cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

phy_cmn.c (72188B)


      1// SPDX-License-Identifier: ISC
      2/*
      3 * Copyright (c) 2010 Broadcom Corporation
      4 */
      5#include <linux/kernel.h>
      6#include <linux/delay.h>
      7#include <linux/bitops.h>
      8
      9#include <brcm_hw_ids.h>
     10#include <chipcommon.h>
     11#include <aiutils.h>
     12#include <d11.h>
     13#include <phy_shim.h>
     14#include "phy_hal.h"
     15#include "phy_int.h"
     16#include "phy_radio.h"
     17#include "phy_lcn.h"
     18#include "phyreg_n.h"
     19
     20#define VALID_N_RADIO(radioid) ((radioid == BCM2055_ID) || \
     21				 (radioid == BCM2056_ID) || \
     22				 (radioid == BCM2057_ID))
     23
     24#define VALID_LCN_RADIO(radioid)	(radioid == BCM2064_ID)
     25
     26#define VALID_RADIO(pi, radioid)        ( \
     27		(ISNPHY(pi) ? VALID_N_RADIO(radioid) : false) || \
     28		(ISLCNPHY(pi) ? VALID_LCN_RADIO(radioid) : false))
     29
     30/* basic mux operation - can be optimized on several architectures */
     31#define MUX(pred, true, false) ((pred) ? (true) : (false))
     32
     33/* modulo inc/dec - assumes x E [0, bound - 1] */
     34#define MODINC(x, bound) MUX((x) == (bound) - 1, 0, (x) + 1)
     35
     36/* modulo inc/dec, bound = 2^k */
     37#define MODDEC_POW2(x, bound) (((x) - 1) & ((bound) - 1))
     38#define MODINC_POW2(x, bound) (((x) + 1) & ((bound) - 1))
     39
     40struct chan_info_basic {
     41	u16 chan;
     42	u16 freq;
     43};
     44
     45static const struct chan_info_basic chan_info_all[] = {
     46	{1, 2412},
     47	{2, 2417},
     48	{3, 2422},
     49	{4, 2427},
     50	{5, 2432},
     51	{6, 2437},
     52	{7, 2442},
     53	{8, 2447},
     54	{9, 2452},
     55	{10, 2457},
     56	{11, 2462},
     57	{12, 2467},
     58	{13, 2472},
     59	{14, 2484},
     60
     61	{34, 5170},
     62	{38, 5190},
     63	{42, 5210},
     64	{46, 5230},
     65
     66	{36, 5180},
     67	{40, 5200},
     68	{44, 5220},
     69	{48, 5240},
     70	{52, 5260},
     71	{56, 5280},
     72	{60, 5300},
     73	{64, 5320},
     74
     75	{100, 5500},
     76	{104, 5520},
     77	{108, 5540},
     78	{112, 5560},
     79	{116, 5580},
     80	{120, 5600},
     81	{124, 5620},
     82	{128, 5640},
     83	{132, 5660},
     84	{136, 5680},
     85	{140, 5700},
     86
     87	{149, 5745},
     88	{153, 5765},
     89	{157, 5785},
     90	{161, 5805},
     91	{165, 5825},
     92
     93	{184, 4920},
     94	{188, 4940},
     95	{192, 4960},
     96	{196, 4980},
     97	{200, 5000},
     98	{204, 5020},
     99	{208, 5040},
    100	{212, 5060},
    101	{216, 5080}
    102};
    103
    104static const u8 ofdm_rate_lookup[] = {
    105
    106	BRCM_RATE_48M,
    107	BRCM_RATE_24M,
    108	BRCM_RATE_12M,
    109	BRCM_RATE_6M,
    110	BRCM_RATE_54M,
    111	BRCM_RATE_36M,
    112	BRCM_RATE_18M,
    113	BRCM_RATE_9M
    114};
    115
    116#define PHY_WREG_LIMIT  24
    117
    118void wlc_phyreg_enter(struct brcms_phy_pub *pih)
    119{
    120	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
    121	wlapi_bmac_ucode_wake_override_phyreg_set(pi->sh->physhim);
    122}
    123
    124void wlc_phyreg_exit(struct brcms_phy_pub *pih)
    125{
    126	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
    127	wlapi_bmac_ucode_wake_override_phyreg_clear(pi->sh->physhim);
    128}
    129
    130void wlc_radioreg_enter(struct brcms_phy_pub *pih)
    131{
    132	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
    133	wlapi_bmac_mctrl(pi->sh->physhim, MCTL_LOCK_RADIO, MCTL_LOCK_RADIO);
    134
    135	udelay(10);
    136}
    137
    138void wlc_radioreg_exit(struct brcms_phy_pub *pih)
    139{
    140	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
    141
    142	(void)bcma_read16(pi->d11core, D11REGOFFS(phyversion));
    143	pi->phy_wreg = 0;
    144	wlapi_bmac_mctrl(pi->sh->physhim, MCTL_LOCK_RADIO, 0);
    145}
    146
    147u16 read_radio_reg(struct brcms_phy *pi, u16 addr)
    148{
    149	u16 data;
    150
    151	if (addr == RADIO_IDCODE)
    152		return 0xffff;
    153
    154	switch (pi->pubpi.phy_type) {
    155	case PHY_TYPE_N:
    156		if (!CONF_HAS(PHYTYPE, PHY_TYPE_N))
    157			break;
    158		if (NREV_GE(pi->pubpi.phy_rev, 7))
    159			addr |= RADIO_2057_READ_OFF;
    160		else
    161			addr |= RADIO_2055_READ_OFF;
    162		break;
    163
    164	case PHY_TYPE_LCN:
    165		if (!CONF_HAS(PHYTYPE, PHY_TYPE_LCN))
    166			break;
    167		addr |= RADIO_2064_READ_OFF;
    168		break;
    169
    170	default:
    171		break;
    172	}
    173
    174	if ((D11REV_GE(pi->sh->corerev, 24)) ||
    175	    (D11REV_IS(pi->sh->corerev, 22)
    176	     && (pi->pubpi.phy_type != PHY_TYPE_SSN))) {
    177		bcma_wflush16(pi->d11core, D11REGOFFS(radioregaddr), addr);
    178		data = bcma_read16(pi->d11core, D11REGOFFS(radioregdata));
    179	} else {
    180		bcma_wflush16(pi->d11core, D11REGOFFS(phy4waddr), addr);
    181		data = bcma_read16(pi->d11core, D11REGOFFS(phy4wdatalo));
    182	}
    183	pi->phy_wreg = 0;
    184
    185	return data;
    186}
    187
    188void write_radio_reg(struct brcms_phy *pi, u16 addr, u16 val)
    189{
    190	if ((D11REV_GE(pi->sh->corerev, 24)) ||
    191	    (D11REV_IS(pi->sh->corerev, 22)
    192	     && (pi->pubpi.phy_type != PHY_TYPE_SSN))) {
    193
    194		bcma_wflush16(pi->d11core, D11REGOFFS(radioregaddr), addr);
    195		bcma_write16(pi->d11core, D11REGOFFS(radioregdata), val);
    196	} else {
    197		bcma_wflush16(pi->d11core, D11REGOFFS(phy4waddr), addr);
    198		bcma_write16(pi->d11core, D11REGOFFS(phy4wdatalo), val);
    199	}
    200
    201	if ((pi->d11core->bus->hosttype == BCMA_HOSTTYPE_PCI) &&
    202	    (++pi->phy_wreg >= pi->phy_wreg_limit)) {
    203		(void)bcma_read32(pi->d11core, D11REGOFFS(maccontrol));
    204		pi->phy_wreg = 0;
    205	}
    206}
    207
    208static u32 read_radio_id(struct brcms_phy *pi)
    209{
    210	u32 id;
    211
    212	if (D11REV_GE(pi->sh->corerev, 24)) {
    213		u32 b0, b1, b2;
    214
    215		bcma_wflush16(pi->d11core, D11REGOFFS(radioregaddr), 0);
    216		b0 = (u32) bcma_read16(pi->d11core, D11REGOFFS(radioregdata));
    217		bcma_wflush16(pi->d11core, D11REGOFFS(radioregaddr), 1);
    218		b1 = (u32) bcma_read16(pi->d11core, D11REGOFFS(radioregdata));
    219		bcma_wflush16(pi->d11core, D11REGOFFS(radioregaddr), 2);
    220		b2 = (u32) bcma_read16(pi->d11core, D11REGOFFS(radioregdata));
    221
    222		id = ((b0 & 0xf) << 28) | (((b2 << 8) | b1) << 12) | ((b0 >> 4)
    223								      & 0xf);
    224	} else {
    225		bcma_wflush16(pi->d11core, D11REGOFFS(phy4waddr), RADIO_IDCODE);
    226		id = (u32) bcma_read16(pi->d11core, D11REGOFFS(phy4wdatalo));
    227		id |= (u32) bcma_read16(pi->d11core,
    228					D11REGOFFS(phy4wdatahi)) << 16;
    229	}
    230	pi->phy_wreg = 0;
    231	return id;
    232}
    233
    234void and_radio_reg(struct brcms_phy *pi, u16 addr, u16 val)
    235{
    236	u16 rval;
    237
    238	rval = read_radio_reg(pi, addr);
    239	write_radio_reg(pi, addr, (rval & val));
    240}
    241
    242void or_radio_reg(struct brcms_phy *pi, u16 addr, u16 val)
    243{
    244	u16 rval;
    245
    246	rval = read_radio_reg(pi, addr);
    247	write_radio_reg(pi, addr, (rval | val));
    248}
    249
    250void xor_radio_reg(struct brcms_phy *pi, u16 addr, u16 mask)
    251{
    252	u16 rval;
    253
    254	rval = read_radio_reg(pi, addr);
    255	write_radio_reg(pi, addr, (rval ^ mask));
    256}
    257
    258void mod_radio_reg(struct brcms_phy *pi, u16 addr, u16 mask, u16 val)
    259{
    260	u16 rval;
    261
    262	rval = read_radio_reg(pi, addr);
    263	write_radio_reg(pi, addr, (rval & ~mask) | (val & mask));
    264}
    265
    266void write_phy_channel_reg(struct brcms_phy *pi, uint val)
    267{
    268	bcma_write16(pi->d11core, D11REGOFFS(phychannel), val);
    269}
    270
    271u16 read_phy_reg(struct brcms_phy *pi, u16 addr)
    272{
    273	bcma_wflush16(pi->d11core, D11REGOFFS(phyregaddr), addr);
    274
    275	pi->phy_wreg = 0;
    276	return bcma_read16(pi->d11core, D11REGOFFS(phyregdata));
    277}
    278
    279void write_phy_reg(struct brcms_phy *pi, u16 addr, u16 val)
    280{
    281#ifdef CONFIG_BCM47XX
    282	bcma_wflush16(pi->d11core, D11REGOFFS(phyregaddr), addr);
    283	bcma_write16(pi->d11core, D11REGOFFS(phyregdata), val);
    284	if (addr == 0x72)
    285		(void)bcma_read16(pi->d11core, D11REGOFFS(phyregdata));
    286#else
    287	bcma_write32(pi->d11core, D11REGOFFS(phyregaddr), addr | (val << 16));
    288	if ((pi->d11core->bus->hosttype == BCMA_HOSTTYPE_PCI) &&
    289	    (++pi->phy_wreg >= pi->phy_wreg_limit)) {
    290		pi->phy_wreg = 0;
    291		(void)bcma_read16(pi->d11core, D11REGOFFS(phyversion));
    292	}
    293#endif
    294}
    295
    296void and_phy_reg(struct brcms_phy *pi, u16 addr, u16 val)
    297{
    298	bcma_wflush16(pi->d11core, D11REGOFFS(phyregaddr), addr);
    299	bcma_mask16(pi->d11core, D11REGOFFS(phyregdata), val);
    300	pi->phy_wreg = 0;
    301}
    302
    303void or_phy_reg(struct brcms_phy *pi, u16 addr, u16 val)
    304{
    305	bcma_wflush16(pi->d11core, D11REGOFFS(phyregaddr), addr);
    306	bcma_set16(pi->d11core, D11REGOFFS(phyregdata), val);
    307	pi->phy_wreg = 0;
    308}
    309
    310void mod_phy_reg(struct brcms_phy *pi, u16 addr, u16 mask, u16 val)
    311{
    312	val &= mask;
    313	bcma_wflush16(pi->d11core, D11REGOFFS(phyregaddr), addr);
    314	bcma_maskset16(pi->d11core, D11REGOFFS(phyregdata), ~mask, val);
    315	pi->phy_wreg = 0;
    316}
    317
    318static void wlc_set_phy_uninitted(struct brcms_phy *pi)
    319{
    320	int i, j;
    321
    322	pi->initialized = false;
    323
    324	pi->tx_vos = 0xffff;
    325	pi->nrssi_table_delta = 0x7fffffff;
    326	pi->rc_cal = 0xffff;
    327	pi->mintxbias = 0xffff;
    328	pi->txpwridx = -1;
    329	if (ISNPHY(pi)) {
    330		pi->phy_spuravoid = SPURAVOID_DISABLE;
    331
    332		if (NREV_GE(pi->pubpi.phy_rev, 3)
    333		    && NREV_LT(pi->pubpi.phy_rev, 7))
    334			pi->phy_spuravoid = SPURAVOID_AUTO;
    335
    336		pi->nphy_papd_skip = 0;
    337		pi->nphy_papd_epsilon_offset[0] = 0xf588;
    338		pi->nphy_papd_epsilon_offset[1] = 0xf588;
    339		pi->nphy_txpwr_idx[0] = 128;
    340		pi->nphy_txpwr_idx[1] = 128;
    341		pi->nphy_txpwrindex[0].index_internal = 40;
    342		pi->nphy_txpwrindex[1].index_internal = 40;
    343		pi->phy_pabias = 0;
    344	} else {
    345		pi->phy_spuravoid = SPURAVOID_AUTO;
    346	}
    347	pi->radiopwr = 0xffff;
    348	for (i = 0; i < STATIC_NUM_RF; i++) {
    349		for (j = 0; j < STATIC_NUM_BB; j++)
    350			pi->stats_11b_txpower[i][j] = -1;
    351	}
    352}
    353
    354struct shared_phy *wlc_phy_shared_attach(struct shared_phy_params *shp)
    355{
    356	struct shared_phy *sh;
    357
    358	sh = kzalloc(sizeof(struct shared_phy), GFP_ATOMIC);
    359	if (sh == NULL)
    360		return NULL;
    361
    362	sh->physhim = shp->physhim;
    363	sh->unit = shp->unit;
    364	sh->corerev = shp->corerev;
    365
    366	sh->vid = shp->vid;
    367	sh->did = shp->did;
    368	sh->chip = shp->chip;
    369	sh->chiprev = shp->chiprev;
    370	sh->chippkg = shp->chippkg;
    371	sh->sromrev = shp->sromrev;
    372	sh->boardtype = shp->boardtype;
    373	sh->boardrev = shp->boardrev;
    374	sh->boardflags = shp->boardflags;
    375	sh->boardflags2 = shp->boardflags2;
    376
    377	sh->fast_timer = PHY_SW_TIMER_FAST;
    378	sh->slow_timer = PHY_SW_TIMER_SLOW;
    379	sh->glacial_timer = PHY_SW_TIMER_GLACIAL;
    380
    381	sh->rssi_mode = RSSI_ANT_MERGE_MAX;
    382
    383	return sh;
    384}
    385
    386static void wlc_phy_timercb_phycal(struct brcms_phy *pi)
    387{
    388	uint delay = 5;
    389
    390	if (PHY_PERICAL_MPHASE_PENDING(pi)) {
    391		if (!pi->sh->up) {
    392			wlc_phy_cal_perical_mphase_reset(pi);
    393			return;
    394		}
    395
    396		if (SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)) {
    397
    398			delay = 1000;
    399			wlc_phy_cal_perical_mphase_restart(pi);
    400		} else
    401			wlc_phy_cal_perical_nphy_run(pi, PHY_PERICAL_AUTO);
    402		wlapi_add_timer(pi->phycal_timer, delay, 0);
    403		return;
    404	}
    405
    406}
    407
    408static u32 wlc_phy_get_radio_ver(struct brcms_phy *pi)
    409{
    410	u32 ver;
    411
    412	ver = read_radio_id(pi);
    413
    414	return ver;
    415}
    416
    417struct brcms_phy_pub *
    418wlc_phy_attach(struct shared_phy *sh, struct bcma_device *d11core,
    419	       int bandtype, struct wiphy *wiphy)
    420{
    421	struct brcms_phy *pi;
    422	u32 sflags = 0;
    423	uint phyversion;
    424	u32 idcode;
    425	int i;
    426
    427	if (D11REV_IS(sh->corerev, 4))
    428		sflags = SISF_2G_PHY | SISF_5G_PHY;
    429	else
    430		sflags = bcma_aread32(d11core, BCMA_IOST);
    431
    432	if (bandtype == BRCM_BAND_5G) {
    433		if ((sflags & (SISF_5G_PHY | SISF_DB_PHY)) == 0)
    434			return NULL;
    435	}
    436
    437	pi = sh->phy_head;
    438	if ((sflags & SISF_DB_PHY) && pi) {
    439		wlapi_bmac_corereset(pi->sh->physhim, pi->pubpi.coreflags);
    440		pi->refcnt++;
    441		return &pi->pubpi_ro;
    442	}
    443
    444	pi = kzalloc(sizeof(struct brcms_phy), GFP_ATOMIC);
    445	if (pi == NULL)
    446		return NULL;
    447	pi->wiphy = wiphy;
    448	pi->d11core = d11core;
    449	pi->sh = sh;
    450	pi->phy_init_por = true;
    451	pi->phy_wreg_limit = PHY_WREG_LIMIT;
    452
    453	pi->txpwr_percent = 100;
    454
    455	pi->do_initcal = true;
    456
    457	pi->phycal_tempdelta = 0;
    458
    459	if (bandtype == BRCM_BAND_2G && (sflags & SISF_2G_PHY))
    460		pi->pubpi.coreflags = SICF_GMODE;
    461
    462	wlapi_bmac_corereset(pi->sh->physhim, pi->pubpi.coreflags);
    463	phyversion = bcma_read16(pi->d11core, D11REGOFFS(phyversion));
    464
    465	pi->pubpi.phy_type = PHY_TYPE(phyversion);
    466	pi->pubpi.phy_rev = phyversion & PV_PV_MASK;
    467
    468	if (pi->pubpi.phy_type == PHY_TYPE_LCNXN) {
    469		pi->pubpi.phy_type = PHY_TYPE_N;
    470		pi->pubpi.phy_rev += LCNXN_BASEREV;
    471	}
    472	pi->pubpi.phy_corenum = PHY_CORE_NUM_2;
    473	pi->pubpi.ana_rev = (phyversion & PV_AV_MASK) >> PV_AV_SHIFT;
    474
    475	if (pi->pubpi.phy_type != PHY_TYPE_N &&
    476	    pi->pubpi.phy_type != PHY_TYPE_LCN)
    477		goto err;
    478
    479	if (bandtype == BRCM_BAND_5G) {
    480		if (!ISNPHY(pi))
    481			goto err;
    482	} else if (!ISNPHY(pi) && !ISLCNPHY(pi)) {
    483		goto err;
    484	}
    485
    486	wlc_phy_anacore((struct brcms_phy_pub *) pi, ON);
    487
    488	idcode = wlc_phy_get_radio_ver(pi);
    489	pi->pubpi.radioid =
    490		(idcode & IDCODE_ID_MASK) >> IDCODE_ID_SHIFT;
    491	pi->pubpi.radiorev =
    492		(idcode & IDCODE_REV_MASK) >> IDCODE_REV_SHIFT;
    493	pi->pubpi.radiover =
    494		(idcode & IDCODE_VER_MASK) >> IDCODE_VER_SHIFT;
    495	if (!VALID_RADIO(pi, pi->pubpi.radioid))
    496		goto err;
    497
    498	wlc_phy_switch_radio((struct brcms_phy_pub *) pi, OFF);
    499
    500	wlc_set_phy_uninitted(pi);
    501
    502	pi->bw = WL_CHANSPEC_BW_20;
    503	pi->radio_chanspec = (bandtype == BRCM_BAND_2G) ?
    504			     ch20mhz_chspec(1) : ch20mhz_chspec(36);
    505
    506	pi->rxiq_samps = PHY_NOISE_SAMPLE_LOG_NUM_NPHY;
    507	pi->rxiq_antsel = ANT_RX_DIV_DEF;
    508
    509	pi->watchdog_override = true;
    510
    511	pi->cal_type_override = PHY_PERICAL_AUTO;
    512
    513	pi->nphy_saved_noisevars.bufcount = 0;
    514
    515	if (ISNPHY(pi))
    516		pi->min_txpower = PHY_TXPWR_MIN_NPHY;
    517	else
    518		pi->min_txpower = PHY_TXPWR_MIN;
    519
    520	pi->sh->phyrxchain = 0x3;
    521
    522	pi->rx2tx_biasentry = -1;
    523
    524	pi->phy_txcore_disable_temp = PHY_CHAIN_TX_DISABLE_TEMP;
    525	pi->phy_txcore_enable_temp =
    526		PHY_CHAIN_TX_DISABLE_TEMP - PHY_HYSTERESIS_DELTATEMP;
    527	pi->phy_tempsense_offset = 0;
    528	pi->phy_txcore_heatedup = false;
    529
    530	pi->nphy_lastcal_temp = -50;
    531
    532	pi->phynoise_polling = true;
    533	if (ISNPHY(pi) || ISLCNPHY(pi))
    534		pi->phynoise_polling = false;
    535
    536	for (i = 0; i < TXP_NUM_RATES; i++) {
    537		pi->txpwr_limit[i] = BRCMS_TXPWR_MAX;
    538		pi->txpwr_env_limit[i] = BRCMS_TXPWR_MAX;
    539		pi->tx_user_target[i] = BRCMS_TXPWR_MAX;
    540	}
    541
    542	pi->radiopwr_override = RADIOPWR_OVERRIDE_DEF;
    543
    544	pi->user_txpwr_at_rfport = false;
    545
    546	if (ISNPHY(pi)) {
    547
    548		pi->phycal_timer = wlapi_init_timer(pi->sh->physhim,
    549						    wlc_phy_timercb_phycal,
    550						    pi, "phycal");
    551		if (!pi->phycal_timer)
    552			goto err;
    553
    554		if (!wlc_phy_attach_nphy(pi))
    555			goto err;
    556
    557	} else if (ISLCNPHY(pi)) {
    558		if (!wlc_phy_attach_lcnphy(pi))
    559			goto err;
    560
    561	}
    562
    563	pi->refcnt++;
    564	pi->next = pi->sh->phy_head;
    565	sh->phy_head = pi;
    566
    567	memcpy(&pi->pubpi_ro, &pi->pubpi, sizeof(struct brcms_phy_pub));
    568
    569	return &pi->pubpi_ro;
    570
    571err:
    572	kfree(pi);
    573	return NULL;
    574}
    575
    576void wlc_phy_detach(struct brcms_phy_pub *pih)
    577{
    578	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
    579
    580	if (pih) {
    581		if (--pi->refcnt)
    582			return;
    583
    584		if (pi->phycal_timer) {
    585			wlapi_free_timer(pi->phycal_timer);
    586			pi->phycal_timer = NULL;
    587		}
    588
    589		if (pi->sh->phy_head == pi)
    590			pi->sh->phy_head = pi->next;
    591		else if (pi->sh->phy_head->next == pi)
    592			pi->sh->phy_head->next = NULL;
    593
    594		if (pi->pi_fptr.detach)
    595			(pi->pi_fptr.detach)(pi);
    596
    597		kfree(pi);
    598	}
    599}
    600
    601bool
    602wlc_phy_get_phyversion(struct brcms_phy_pub *pih, u16 *phytype, u16 *phyrev,
    603		       u16 *radioid, u16 *radiover)
    604{
    605	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
    606	*phytype = (u16) pi->pubpi.phy_type;
    607	*phyrev = (u16) pi->pubpi.phy_rev;
    608	*radioid = pi->pubpi.radioid;
    609	*radiover = pi->pubpi.radiorev;
    610
    611	return true;
    612}
    613
    614bool wlc_phy_get_encore(struct brcms_phy_pub *pih)
    615{
    616	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
    617	return pi->pubpi.abgphy_encore;
    618}
    619
    620u32 wlc_phy_get_coreflags(struct brcms_phy_pub *pih)
    621{
    622	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
    623	return pi->pubpi.coreflags;
    624}
    625
    626void wlc_phy_anacore(struct brcms_phy_pub *pih, bool on)
    627{
    628	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
    629
    630	if (ISNPHY(pi)) {
    631		if (on) {
    632			if (NREV_GE(pi->pubpi.phy_rev, 3)) {
    633				write_phy_reg(pi, 0xa6, 0x0d);
    634				write_phy_reg(pi, 0x8f, 0x0);
    635				write_phy_reg(pi, 0xa7, 0x0d);
    636				write_phy_reg(pi, 0xa5, 0x0);
    637			} else {
    638				write_phy_reg(pi, 0xa5, 0x0);
    639			}
    640		} else {
    641			if (NREV_GE(pi->pubpi.phy_rev, 3)) {
    642				write_phy_reg(pi, 0x8f, 0x07ff);
    643				write_phy_reg(pi, 0xa6, 0x0fd);
    644				write_phy_reg(pi, 0xa5, 0x07ff);
    645				write_phy_reg(pi, 0xa7, 0x0fd);
    646			} else {
    647				write_phy_reg(pi, 0xa5, 0x7fff);
    648			}
    649		}
    650	} else if (ISLCNPHY(pi)) {
    651		if (on) {
    652			and_phy_reg(pi, 0x43b,
    653				    ~((0x1 << 0) | (0x1 << 1) | (0x1 << 2)));
    654		} else {
    655			or_phy_reg(pi, 0x43c,
    656				   (0x1 << 0) | (0x1 << 1) | (0x1 << 2));
    657			or_phy_reg(pi, 0x43b,
    658				   (0x1 << 0) | (0x1 << 1) | (0x1 << 2));
    659		}
    660	}
    661}
    662
    663u32 wlc_phy_clk_bwbits(struct brcms_phy_pub *pih)
    664{
    665	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
    666
    667	u32 phy_bw_clkbits = 0;
    668
    669	if (pi && (ISNPHY(pi) || ISLCNPHY(pi))) {
    670		switch (pi->bw) {
    671		case WL_CHANSPEC_BW_10:
    672			phy_bw_clkbits = SICF_BW10;
    673			break;
    674		case WL_CHANSPEC_BW_20:
    675			phy_bw_clkbits = SICF_BW20;
    676			break;
    677		case WL_CHANSPEC_BW_40:
    678			phy_bw_clkbits = SICF_BW40;
    679			break;
    680		default:
    681			break;
    682		}
    683	}
    684
    685	return phy_bw_clkbits;
    686}
    687
    688void wlc_phy_por_inform(struct brcms_phy_pub *ppi)
    689{
    690	struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
    691
    692	pi->phy_init_por = true;
    693}
    694
    695void wlc_phy_edcrs_lock(struct brcms_phy_pub *pih, bool lock)
    696{
    697	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
    698
    699	pi->edcrs_threshold_lock = lock;
    700
    701	write_phy_reg(pi, 0x22c, 0x46b);
    702	write_phy_reg(pi, 0x22d, 0x46b);
    703	write_phy_reg(pi, 0x22e, 0x3c0);
    704	write_phy_reg(pi, 0x22f, 0x3c0);
    705}
    706
    707void wlc_phy_initcal_enable(struct brcms_phy_pub *pih, bool initcal)
    708{
    709	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
    710
    711	pi->do_initcal = initcal;
    712}
    713
    714void wlc_phy_hw_clk_state_upd(struct brcms_phy_pub *pih, bool newstate)
    715{
    716	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
    717
    718	if (!pi || !pi->sh)
    719		return;
    720
    721	pi->sh->clk = newstate;
    722}
    723
    724void wlc_phy_hw_state_upd(struct brcms_phy_pub *pih, bool newstate)
    725{
    726	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
    727
    728	if (!pi || !pi->sh)
    729		return;
    730
    731	pi->sh->up = newstate;
    732}
    733
    734void wlc_phy_init(struct brcms_phy_pub *pih, u16 chanspec)
    735{
    736	u32 mc;
    737	void (*phy_init)(struct brcms_phy *) = NULL;
    738	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
    739
    740	if (pi->init_in_progress)
    741		return;
    742
    743	pi->init_in_progress = true;
    744
    745	pi->radio_chanspec = chanspec;
    746
    747	mc = bcma_read32(pi->d11core, D11REGOFFS(maccontrol));
    748	if (WARN(mc & MCTL_EN_MAC, "HW error MAC running on init"))
    749		return;
    750
    751	if (!(pi->measure_hold & PHY_HOLD_FOR_SCAN))
    752		pi->measure_hold |= PHY_HOLD_FOR_NOT_ASSOC;
    753
    754	if (WARN(!(bcma_aread32(pi->d11core, BCMA_IOST) & SISF_FCLKA),
    755		 "HW error SISF_FCLKA\n"))
    756		return;
    757
    758	phy_init = pi->pi_fptr.init;
    759
    760	if (phy_init == NULL)
    761		return;
    762
    763	wlc_phy_anacore(pih, ON);
    764
    765	if (CHSPEC_BW(pi->radio_chanspec) != pi->bw)
    766		wlapi_bmac_bw_set(pi->sh->physhim,
    767				  CHSPEC_BW(pi->radio_chanspec));
    768
    769	pi->nphy_gain_boost = true;
    770
    771	wlc_phy_switch_radio((struct brcms_phy_pub *) pi, ON);
    772
    773	(*phy_init)(pi);
    774
    775	pi->phy_init_por = false;
    776
    777	if (D11REV_IS(pi->sh->corerev, 11) || D11REV_IS(pi->sh->corerev, 12))
    778		wlc_phy_do_dummy_tx(pi, true, OFF);
    779
    780	if (!(ISNPHY(pi)))
    781		wlc_phy_txpower_update_shm(pi);
    782
    783	wlc_phy_ant_rxdiv_set((struct brcms_phy_pub *) pi, pi->sh->rx_antdiv);
    784
    785	pi->init_in_progress = false;
    786}
    787
    788void wlc_phy_cal_init(struct brcms_phy_pub *pih)
    789{
    790	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
    791	void (*cal_init)(struct brcms_phy *) = NULL;
    792
    793	if (WARN((bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) &
    794		  MCTL_EN_MAC) != 0, "HW error: MAC enabled during phy cal\n"))
    795		return;
    796
    797	if (!pi->initialized) {
    798		cal_init = pi->pi_fptr.calinit;
    799		if (cal_init)
    800			(*cal_init)(pi);
    801
    802		pi->initialized = true;
    803	}
    804}
    805
    806int wlc_phy_down(struct brcms_phy_pub *pih)
    807{
    808	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
    809	int callbacks = 0;
    810
    811	if (pi->phycal_timer
    812	    && !wlapi_del_timer(pi->phycal_timer))
    813		callbacks++;
    814
    815	pi->nphy_iqcal_chanspec_2G = 0;
    816	pi->nphy_iqcal_chanspec_5G = 0;
    817
    818	return callbacks;
    819}
    820
    821void
    822wlc_phy_table_addr(struct brcms_phy *pi, uint tbl_id, uint tbl_offset,
    823		   u16 tblAddr, u16 tblDataHi, u16 tblDataLo)
    824{
    825	write_phy_reg(pi, tblAddr, (tbl_id << 10) | tbl_offset);
    826
    827	pi->tbl_data_hi = tblDataHi;
    828	pi->tbl_data_lo = tblDataLo;
    829
    830	if (pi->sh->chip == BCMA_CHIP_ID_BCM43224 &&
    831	    pi->sh->chiprev == 1) {
    832		pi->tbl_addr = tblAddr;
    833		pi->tbl_save_id = tbl_id;
    834		pi->tbl_save_offset = tbl_offset;
    835	}
    836}
    837
    838void wlc_phy_table_data_write(struct brcms_phy *pi, uint width, u32 val)
    839{
    840	if ((pi->sh->chip == BCMA_CHIP_ID_BCM43224) &&
    841	    (pi->sh->chiprev == 1) &&
    842	    (pi->tbl_save_id == NPHY_TBL_ID_ANTSWCTRLLUT)) {
    843		read_phy_reg(pi, pi->tbl_data_lo);
    844
    845		write_phy_reg(pi, pi->tbl_addr,
    846			      (pi->tbl_save_id << 10) | pi->tbl_save_offset);
    847		pi->tbl_save_offset++;
    848	}
    849
    850	if (width == 32) {
    851		write_phy_reg(pi, pi->tbl_data_hi, (u16) (val >> 16));
    852		write_phy_reg(pi, pi->tbl_data_lo, (u16) val);
    853	} else {
    854		write_phy_reg(pi, pi->tbl_data_lo, (u16) val);
    855	}
    856}
    857
    858void
    859wlc_phy_write_table(struct brcms_phy *pi, const struct phytbl_info *ptbl_info,
    860		    u16 tblAddr, u16 tblDataHi, u16 tblDataLo)
    861{
    862	uint idx;
    863	uint tbl_id = ptbl_info->tbl_id;
    864	uint tbl_offset = ptbl_info->tbl_offset;
    865	uint tbl_width = ptbl_info->tbl_width;
    866	const u8 *ptbl_8b = (const u8 *)ptbl_info->tbl_ptr;
    867	const u16 *ptbl_16b = (const u16 *)ptbl_info->tbl_ptr;
    868	const u32 *ptbl_32b = (const u32 *)ptbl_info->tbl_ptr;
    869
    870	write_phy_reg(pi, tblAddr, (tbl_id << 10) | tbl_offset);
    871
    872	for (idx = 0; idx < ptbl_info->tbl_len; idx++) {
    873
    874		if ((pi->sh->chip == BCMA_CHIP_ID_BCM43224) &&
    875		    (pi->sh->chiprev == 1) &&
    876		    (tbl_id == NPHY_TBL_ID_ANTSWCTRLLUT)) {
    877			read_phy_reg(pi, tblDataLo);
    878
    879			write_phy_reg(pi, tblAddr,
    880				      (tbl_id << 10) | (tbl_offset + idx));
    881		}
    882
    883		if (tbl_width == 32) {
    884			write_phy_reg(pi, tblDataHi,
    885				      (u16) (ptbl_32b[idx] >> 16));
    886			write_phy_reg(pi, tblDataLo, (u16) ptbl_32b[idx]);
    887		} else if (tbl_width == 16) {
    888			write_phy_reg(pi, tblDataLo, ptbl_16b[idx]);
    889		} else {
    890			write_phy_reg(pi, tblDataLo, ptbl_8b[idx]);
    891		}
    892	}
    893}
    894
    895void
    896wlc_phy_read_table(struct brcms_phy *pi, const struct phytbl_info *ptbl_info,
    897		   u16 tblAddr, u16 tblDataHi, u16 tblDataLo)
    898{
    899	uint idx;
    900	uint tbl_id = ptbl_info->tbl_id;
    901	uint tbl_offset = ptbl_info->tbl_offset;
    902	uint tbl_width = ptbl_info->tbl_width;
    903	u8 *ptbl_8b = (u8 *)ptbl_info->tbl_ptr;
    904	u16 *ptbl_16b = (u16 *)ptbl_info->tbl_ptr;
    905	u32 *ptbl_32b = (u32 *)ptbl_info->tbl_ptr;
    906
    907	write_phy_reg(pi, tblAddr, (tbl_id << 10) | tbl_offset);
    908
    909	for (idx = 0; idx < ptbl_info->tbl_len; idx++) {
    910
    911		if ((pi->sh->chip == BCMA_CHIP_ID_BCM43224) &&
    912		    (pi->sh->chiprev == 1)) {
    913			(void)read_phy_reg(pi, tblDataLo);
    914
    915			write_phy_reg(pi, tblAddr,
    916				      (tbl_id << 10) | (tbl_offset + idx));
    917		}
    918
    919		if (tbl_width == 32) {
    920			ptbl_32b[idx] = read_phy_reg(pi, tblDataLo);
    921			ptbl_32b[idx] |= (read_phy_reg(pi, tblDataHi) << 16);
    922		} else if (tbl_width == 16) {
    923			ptbl_16b[idx] = read_phy_reg(pi, tblDataLo);
    924		} else {
    925			ptbl_8b[idx] = (u8) read_phy_reg(pi, tblDataLo);
    926		}
    927	}
    928}
    929
    930uint
    931wlc_phy_init_radio_regs_allbands(struct brcms_phy *pi,
    932				 struct radio_20xx_regs *radioregs)
    933{
    934	uint i = 0;
    935
    936	do {
    937		if (radioregs[i].do_init)
    938			write_radio_reg(pi, radioregs[i].address,
    939					(u16) radioregs[i].init);
    940
    941		i++;
    942	} while (radioregs[i].address != 0xffff);
    943
    944	return i;
    945}
    946
    947uint
    948wlc_phy_init_radio_regs(struct brcms_phy *pi,
    949			const struct radio_regs *radioregs,
    950			u16 core_offset)
    951{
    952	uint i = 0;
    953	uint count = 0;
    954
    955	do {
    956		if (CHSPEC_IS5G(pi->radio_chanspec)) {
    957			if (radioregs[i].do_init_a) {
    958				write_radio_reg(pi,
    959						radioregs[i].
    960						address | core_offset,
    961						(u16) radioregs[i].init_a);
    962				if (ISNPHY(pi) && (++count % 4 == 0))
    963					BRCMS_PHY_WAR_PR51571(pi);
    964			}
    965		} else {
    966			if (radioregs[i].do_init_g) {
    967				write_radio_reg(pi,
    968						radioregs[i].
    969						address | core_offset,
    970						(u16) radioregs[i].init_g);
    971				if (ISNPHY(pi) && (++count % 4 == 0))
    972					BRCMS_PHY_WAR_PR51571(pi);
    973			}
    974		}
    975
    976		i++;
    977	} while (radioregs[i].address != 0xffff);
    978
    979	return i;
    980}
    981
    982void wlc_phy_do_dummy_tx(struct brcms_phy *pi, bool ofdm, bool pa_on)
    983{
    984#define DUMMY_PKT_LEN   20
    985	struct bcma_device *core = pi->d11core;
    986	int i, count;
    987	u8 ofdmpkt[DUMMY_PKT_LEN] = {
    988		0xcc, 0x01, 0x02, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00,
    989		0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00
    990	};
    991	u8 cckpkt[DUMMY_PKT_LEN] = {
    992		0x6e, 0x84, 0x0b, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00,
    993		0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00
    994	};
    995	u32 *dummypkt;
    996
    997	dummypkt = (u32 *) (ofdm ? ofdmpkt : cckpkt);
    998	wlapi_bmac_write_template_ram(pi->sh->physhim, 0, DUMMY_PKT_LEN,
    999				      dummypkt);
   1000
   1001	bcma_write16(core, D11REGOFFS(xmtsel), 0);
   1002
   1003	if (D11REV_GE(pi->sh->corerev, 11))
   1004		bcma_write16(core, D11REGOFFS(wepctl), 0x100);
   1005	else
   1006		bcma_write16(core, D11REGOFFS(wepctl), 0);
   1007
   1008	bcma_write16(core, D11REGOFFS(txe_phyctl),
   1009		     (ofdm ? 1 : 0) | PHY_TXC_ANT_0);
   1010	if (ISNPHY(pi) || ISLCNPHY(pi))
   1011		bcma_write16(core, D11REGOFFS(txe_phyctl1), 0x1A02);
   1012
   1013	bcma_write16(core, D11REGOFFS(txe_wm_0), 0);
   1014	bcma_write16(core, D11REGOFFS(txe_wm_1), 0);
   1015
   1016	bcma_write16(core, D11REGOFFS(xmttplatetxptr), 0);
   1017	bcma_write16(core, D11REGOFFS(xmttxcnt), DUMMY_PKT_LEN);
   1018
   1019	bcma_write16(core, D11REGOFFS(xmtsel),
   1020		     ((8 << 8) | (1 << 5) | (1 << 2) | 2));
   1021
   1022	bcma_write16(core, D11REGOFFS(txe_ctl), 0);
   1023
   1024	if (!pa_on) {
   1025		if (ISNPHY(pi))
   1026			wlc_phy_pa_override_nphy(pi, OFF);
   1027	}
   1028
   1029	if (ISNPHY(pi) || ISLCNPHY(pi))
   1030		bcma_write16(core, D11REGOFFS(txe_aux), 0xD0);
   1031	else
   1032		bcma_write16(core, D11REGOFFS(txe_aux), ((1 << 5) | (1 << 4)));
   1033
   1034	(void)bcma_read16(core, D11REGOFFS(txe_aux));
   1035
   1036	i = 0;
   1037	count = ofdm ? 30 : 250;
   1038	while ((i++ < count)
   1039	       && (bcma_read16(core, D11REGOFFS(txe_status)) & (1 << 7)))
   1040		udelay(10);
   1041
   1042	i = 0;
   1043
   1044	while ((i++ < 10) &&
   1045	       ((bcma_read16(core, D11REGOFFS(txe_status)) & (1 << 10)) == 0))
   1046		udelay(10);
   1047
   1048	i = 0;
   1049
   1050	while ((i++ < 10) &&
   1051	       ((bcma_read16(core, D11REGOFFS(ifsstat)) & (1 << 8))))
   1052		udelay(10);
   1053
   1054	if (!pa_on) {
   1055		if (ISNPHY(pi))
   1056			wlc_phy_pa_override_nphy(pi, ON);
   1057	}
   1058}
   1059
   1060void wlc_phy_hold_upd(struct brcms_phy_pub *pih, u32 id, bool set)
   1061{
   1062	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
   1063
   1064	if (set)
   1065		mboolset(pi->measure_hold, id);
   1066	else
   1067		mboolclr(pi->measure_hold, id);
   1068
   1069	return;
   1070}
   1071
   1072void wlc_phy_mute_upd(struct brcms_phy_pub *pih, bool mute, u32 flags)
   1073{
   1074	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
   1075
   1076	if (mute)
   1077		mboolset(pi->measure_hold, PHY_HOLD_FOR_MUTE);
   1078	else
   1079		mboolclr(pi->measure_hold, PHY_HOLD_FOR_MUTE);
   1080
   1081	if (!mute && (flags & PHY_MUTE_FOR_PREISM))
   1082		pi->nphy_perical_last = pi->sh->now - pi->sh->glacial_timer;
   1083	return;
   1084}
   1085
   1086void wlc_phy_clear_tssi(struct brcms_phy_pub *pih)
   1087{
   1088	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
   1089
   1090	if (ISNPHY(pi)) {
   1091		return;
   1092	} else {
   1093		wlapi_bmac_write_shm(pi->sh->physhim, M_B_TSSI_0, NULL_TSSI_W);
   1094		wlapi_bmac_write_shm(pi->sh->physhim, M_B_TSSI_1, NULL_TSSI_W);
   1095		wlapi_bmac_write_shm(pi->sh->physhim, M_G_TSSI_0, NULL_TSSI_W);
   1096		wlapi_bmac_write_shm(pi->sh->physhim, M_G_TSSI_1, NULL_TSSI_W);
   1097	}
   1098}
   1099
   1100static bool wlc_phy_cal_txpower_recalc_sw(struct brcms_phy *pi)
   1101{
   1102	return false;
   1103}
   1104
   1105void wlc_phy_switch_radio(struct brcms_phy_pub *pih, bool on)
   1106{
   1107	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
   1108	(void)bcma_read32(pi->d11core, D11REGOFFS(maccontrol));
   1109
   1110	if (ISNPHY(pi)) {
   1111		wlc_phy_switch_radio_nphy(pi, on);
   1112	} else if (ISLCNPHY(pi)) {
   1113		if (on) {
   1114			and_phy_reg(pi, 0x44c,
   1115				    ~((0x1 << 8) |
   1116				      (0x1 << 9) |
   1117				      (0x1 << 10) | (0x1 << 11) | (0x1 << 12)));
   1118			and_phy_reg(pi, 0x4b0, ~((0x1 << 3) | (0x1 << 11)));
   1119			and_phy_reg(pi, 0x4f9, ~(0x1 << 3));
   1120		} else {
   1121			and_phy_reg(pi, 0x44d,
   1122				    ~((0x1 << 10) |
   1123				      (0x1 << 11) |
   1124				      (0x1 << 12) | (0x1 << 13) | (0x1 << 14)));
   1125			or_phy_reg(pi, 0x44c,
   1126				   (0x1 << 8) |
   1127				   (0x1 << 9) |
   1128				   (0x1 << 10) | (0x1 << 11) | (0x1 << 12));
   1129
   1130			and_phy_reg(pi, 0x4b7, ~((0x7f << 8)));
   1131			and_phy_reg(pi, 0x4b1, ~((0x1 << 13)));
   1132			or_phy_reg(pi, 0x4b0, (0x1 << 3) | (0x1 << 11));
   1133			and_phy_reg(pi, 0x4fa, ~((0x1 << 3)));
   1134			or_phy_reg(pi, 0x4f9, (0x1 << 3));
   1135		}
   1136	}
   1137}
   1138
   1139u16 wlc_phy_bw_state_get(struct brcms_phy_pub *ppi)
   1140{
   1141	struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
   1142
   1143	return pi->bw;
   1144}
   1145
   1146void wlc_phy_bw_state_set(struct brcms_phy_pub *ppi, u16 bw)
   1147{
   1148	struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
   1149
   1150	pi->bw = bw;
   1151}
   1152
   1153void wlc_phy_chanspec_radio_set(struct brcms_phy_pub *ppi, u16 newch)
   1154{
   1155	struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
   1156	pi->radio_chanspec = newch;
   1157
   1158}
   1159
   1160u16 wlc_phy_chanspec_get(struct brcms_phy_pub *ppi)
   1161{
   1162	struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
   1163
   1164	return pi->radio_chanspec;
   1165}
   1166
   1167void wlc_phy_chanspec_set(struct brcms_phy_pub *ppi, u16 chanspec)
   1168{
   1169	struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
   1170	u16 m_cur_channel;
   1171	void (*chanspec_set)(struct brcms_phy *, u16) = NULL;
   1172	m_cur_channel = CHSPEC_CHANNEL(chanspec);
   1173	if (CHSPEC_IS5G(chanspec))
   1174		m_cur_channel |= D11_CURCHANNEL_5G;
   1175	if (CHSPEC_IS40(chanspec))
   1176		m_cur_channel |= D11_CURCHANNEL_40;
   1177	wlapi_bmac_write_shm(pi->sh->physhim, M_CURCHANNEL, m_cur_channel);
   1178
   1179	chanspec_set = pi->pi_fptr.chanset;
   1180	if (chanspec_set)
   1181		(*chanspec_set)(pi, chanspec);
   1182
   1183}
   1184
   1185int wlc_phy_chanspec_freq2bandrange_lpssn(uint freq)
   1186{
   1187	int range = -1;
   1188
   1189	if (freq < 2500)
   1190		range = WL_CHAN_FREQ_RANGE_2G;
   1191	else if (freq <= 5320)
   1192		range = WL_CHAN_FREQ_RANGE_5GL;
   1193	else if (freq <= 5700)
   1194		range = WL_CHAN_FREQ_RANGE_5GM;
   1195	else
   1196		range = WL_CHAN_FREQ_RANGE_5GH;
   1197
   1198	return range;
   1199}
   1200
   1201int wlc_phy_chanspec_bandrange_get(struct brcms_phy *pi, u16 chanspec)
   1202{
   1203	int range = -1;
   1204	uint channel = CHSPEC_CHANNEL(chanspec);
   1205	uint freq = wlc_phy_channel2freq(channel);
   1206
   1207	if (ISNPHY(pi))
   1208		range = wlc_phy_get_chan_freq_range_nphy(pi, channel);
   1209	else if (ISLCNPHY(pi))
   1210		range = wlc_phy_chanspec_freq2bandrange_lpssn(freq);
   1211
   1212	return range;
   1213}
   1214
   1215void wlc_phy_chanspec_ch14_widefilter_set(struct brcms_phy_pub *ppi,
   1216					  bool wide_filter)
   1217{
   1218	struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
   1219
   1220	pi->channel_14_wide_filter = wide_filter;
   1221
   1222}
   1223
   1224int wlc_phy_channel2freq(uint channel)
   1225{
   1226	uint i;
   1227
   1228	for (i = 0; i < ARRAY_SIZE(chan_info_all); i++)
   1229		if (chan_info_all[i].chan == channel)
   1230			return chan_info_all[i].freq;
   1231	return 0;
   1232}
   1233
   1234void
   1235wlc_phy_chanspec_band_validch(struct brcms_phy_pub *ppi, uint band,
   1236			      struct brcms_chanvec *channels)
   1237{
   1238	struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
   1239	uint i;
   1240	uint channel;
   1241
   1242	memset(channels, 0, sizeof(struct brcms_chanvec));
   1243
   1244	for (i = 0; i < ARRAY_SIZE(chan_info_all); i++) {
   1245		channel = chan_info_all[i].chan;
   1246
   1247		if ((pi->a_band_high_disable) && (channel >= FIRST_REF5_CHANNUM)
   1248		    && (channel <= LAST_REF5_CHANNUM))
   1249			continue;
   1250
   1251		if ((band == BRCM_BAND_2G && channel <= CH_MAX_2G_CHANNEL) ||
   1252		    (band == BRCM_BAND_5G && channel > CH_MAX_2G_CHANNEL))
   1253			setbit(channels->vec, channel);
   1254	}
   1255}
   1256
   1257u16 wlc_phy_chanspec_band_firstch(struct brcms_phy_pub *ppi, uint band)
   1258{
   1259	struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
   1260	uint i;
   1261	uint channel;
   1262	u16 chspec;
   1263
   1264	for (i = 0; i < ARRAY_SIZE(chan_info_all); i++) {
   1265		channel = chan_info_all[i].chan;
   1266
   1267		if (ISNPHY(pi) && pi->bw == WL_CHANSPEC_BW_40) {
   1268			uint j;
   1269
   1270			for (j = 0; j < ARRAY_SIZE(chan_info_all); j++) {
   1271				if (chan_info_all[j].chan ==
   1272				    channel + CH_10MHZ_APART)
   1273					break;
   1274			}
   1275
   1276			if (j == ARRAY_SIZE(chan_info_all))
   1277				continue;
   1278
   1279			channel = upper_20_sb(channel);
   1280			chspec =  channel | WL_CHANSPEC_BW_40 |
   1281				  WL_CHANSPEC_CTL_SB_LOWER;
   1282			if (band == BRCM_BAND_2G)
   1283				chspec |= WL_CHANSPEC_BAND_2G;
   1284			else
   1285				chspec |= WL_CHANSPEC_BAND_5G;
   1286		} else
   1287			chspec = ch20mhz_chspec(channel);
   1288
   1289		if ((pi->a_band_high_disable) && (channel >= FIRST_REF5_CHANNUM)
   1290		    && (channel <= LAST_REF5_CHANNUM))
   1291			continue;
   1292
   1293		if ((band == BRCM_BAND_2G && channel <= CH_MAX_2G_CHANNEL) ||
   1294		    (band == BRCM_BAND_5G && channel > CH_MAX_2G_CHANNEL))
   1295			return chspec;
   1296	}
   1297
   1298	return (u16) INVCHANSPEC;
   1299}
   1300
   1301int wlc_phy_txpower_get(struct brcms_phy_pub *ppi, uint *qdbm, bool *override)
   1302{
   1303	struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
   1304
   1305	*qdbm = pi->tx_user_target[0];
   1306	if (override != NULL)
   1307		*override = pi->txpwroverride;
   1308	return 0;
   1309}
   1310
   1311void wlc_phy_txpower_target_set(struct brcms_phy_pub *ppi,
   1312				struct txpwr_limits *txpwr)
   1313{
   1314	bool mac_enabled = false;
   1315	struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
   1316
   1317	memcpy(&pi->tx_user_target[TXP_FIRST_CCK],
   1318	       &txpwr->cck[0], BRCMS_NUM_RATES_CCK);
   1319
   1320	memcpy(&pi->tx_user_target[TXP_FIRST_OFDM],
   1321	       &txpwr->ofdm[0], BRCMS_NUM_RATES_OFDM);
   1322	memcpy(&pi->tx_user_target[TXP_FIRST_OFDM_20_CDD],
   1323	       &txpwr->ofdm_cdd[0], BRCMS_NUM_RATES_OFDM);
   1324
   1325	memcpy(&pi->tx_user_target[TXP_FIRST_OFDM_40_SISO],
   1326	       &txpwr->ofdm_40_siso[0], BRCMS_NUM_RATES_OFDM);
   1327	memcpy(&pi->tx_user_target[TXP_FIRST_OFDM_40_CDD],
   1328	       &txpwr->ofdm_40_cdd[0], BRCMS_NUM_RATES_OFDM);
   1329
   1330	memcpy(&pi->tx_user_target[TXP_FIRST_MCS_20_SISO],
   1331	       &txpwr->mcs_20_siso[0], BRCMS_NUM_RATES_MCS_1_STREAM);
   1332	memcpy(&pi->tx_user_target[TXP_FIRST_MCS_20_CDD],
   1333	       &txpwr->mcs_20_cdd[0], BRCMS_NUM_RATES_MCS_1_STREAM);
   1334	memcpy(&pi->tx_user_target[TXP_FIRST_MCS_20_STBC],
   1335	       &txpwr->mcs_20_stbc[0], BRCMS_NUM_RATES_MCS_1_STREAM);
   1336	memcpy(&pi->tx_user_target[TXP_FIRST_MCS_20_SDM],
   1337	       &txpwr->mcs_20_mimo[0], BRCMS_NUM_RATES_MCS_2_STREAM);
   1338
   1339	memcpy(&pi->tx_user_target[TXP_FIRST_MCS_40_SISO],
   1340	       &txpwr->mcs_40_siso[0], BRCMS_NUM_RATES_MCS_1_STREAM);
   1341	memcpy(&pi->tx_user_target[TXP_FIRST_MCS_40_CDD],
   1342	       &txpwr->mcs_40_cdd[0], BRCMS_NUM_RATES_MCS_1_STREAM);
   1343	memcpy(&pi->tx_user_target[TXP_FIRST_MCS_40_STBC],
   1344	       &txpwr->mcs_40_stbc[0], BRCMS_NUM_RATES_MCS_1_STREAM);
   1345	memcpy(&pi->tx_user_target[TXP_FIRST_MCS_40_SDM],
   1346	       &txpwr->mcs_40_mimo[0], BRCMS_NUM_RATES_MCS_2_STREAM);
   1347
   1348	if (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) & MCTL_EN_MAC)
   1349		mac_enabled = true;
   1350
   1351	if (mac_enabled)
   1352		wlapi_suspend_mac_and_wait(pi->sh->physhim);
   1353
   1354	wlc_phy_txpower_recalc_target(pi);
   1355	wlc_phy_cal_txpower_recalc_sw(pi);
   1356
   1357	if (mac_enabled)
   1358		wlapi_enable_mac(pi->sh->physhim);
   1359}
   1360
   1361int wlc_phy_txpower_set(struct brcms_phy_pub *ppi, uint qdbm, bool override)
   1362{
   1363	struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
   1364	int i;
   1365
   1366	if (qdbm > 127)
   1367		return -EINVAL;
   1368
   1369	for (i = 0; i < TXP_NUM_RATES; i++)
   1370		pi->tx_user_target[i] = (u8) qdbm;
   1371
   1372	pi->txpwroverride = false;
   1373
   1374	if (pi->sh->up) {
   1375		if (!SCAN_INPROG_PHY(pi)) {
   1376			bool suspend;
   1377
   1378			suspend = (0 == (bcma_read32(pi->d11core,
   1379						     D11REGOFFS(maccontrol)) &
   1380					 MCTL_EN_MAC));
   1381
   1382			if (!suspend)
   1383				wlapi_suspend_mac_and_wait(pi->sh->physhim);
   1384
   1385			wlc_phy_txpower_recalc_target(pi);
   1386			wlc_phy_cal_txpower_recalc_sw(pi);
   1387
   1388			if (!suspend)
   1389				wlapi_enable_mac(pi->sh->physhim);
   1390		}
   1391	}
   1392	return 0;
   1393}
   1394
   1395void
   1396wlc_phy_txpower_sromlimit(struct brcms_phy_pub *ppi, uint channel, u8 *min_pwr,
   1397			  u8 *max_pwr, int txp_rate_idx)
   1398{
   1399	struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
   1400	uint i;
   1401
   1402	*min_pwr = pi->min_txpower * BRCMS_TXPWR_DB_FACTOR;
   1403
   1404	if (ISNPHY(pi)) {
   1405		if (txp_rate_idx < 0)
   1406			txp_rate_idx = TXP_FIRST_CCK;
   1407		wlc_phy_txpower_sromlimit_get_nphy(pi, channel, max_pwr,
   1408						   (u8) txp_rate_idx);
   1409
   1410	} else if ((channel <= CH_MAX_2G_CHANNEL)) {
   1411		if (txp_rate_idx < 0)
   1412			txp_rate_idx = TXP_FIRST_CCK;
   1413		*max_pwr = pi->tx_srom_max_rate_2g[txp_rate_idx];
   1414	} else {
   1415
   1416		*max_pwr = BRCMS_TXPWR_MAX;
   1417
   1418		if (txp_rate_idx < 0)
   1419			txp_rate_idx = TXP_FIRST_OFDM;
   1420
   1421		for (i = 0; i < ARRAY_SIZE(chan_info_all); i++) {
   1422			if (channel == chan_info_all[i].chan)
   1423				break;
   1424		}
   1425
   1426		if (pi->hwtxpwr) {
   1427			*max_pwr = pi->hwtxpwr[i];
   1428		} else {
   1429
   1430			if ((i >= FIRST_MID_5G_CHAN) && (i <= LAST_MID_5G_CHAN))
   1431				*max_pwr =
   1432				    pi->tx_srom_max_rate_5g_mid[txp_rate_idx];
   1433			if ((i >= FIRST_HIGH_5G_CHAN)
   1434			    && (i <= LAST_HIGH_5G_CHAN))
   1435				*max_pwr =
   1436				    pi->tx_srom_max_rate_5g_hi[txp_rate_idx];
   1437			if ((i >= FIRST_LOW_5G_CHAN) && (i <= LAST_LOW_5G_CHAN))
   1438				*max_pwr =
   1439				    pi->tx_srom_max_rate_5g_low[txp_rate_idx];
   1440		}
   1441	}
   1442}
   1443
   1444void
   1445wlc_phy_txpower_sromlimit_max_get(struct brcms_phy_pub *ppi, uint chan,
   1446				  u8 *max_txpwr, u8 *min_txpwr)
   1447{
   1448	struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
   1449	u8 tx_pwr_max = 0;
   1450	u8 tx_pwr_min = 255;
   1451	u8 max_num_rate;
   1452	u8 maxtxpwr, mintxpwr, rate, pactrl;
   1453
   1454	pactrl = 0;
   1455
   1456	max_num_rate = ISNPHY(pi) ? TXP_NUM_RATES :
   1457		       ISLCNPHY(pi) ? (TXP_LAST_SISO_MCS_20 +
   1458				       1) : (TXP_LAST_OFDM + 1);
   1459
   1460	for (rate = 0; rate < max_num_rate; rate++) {
   1461
   1462		wlc_phy_txpower_sromlimit(ppi, chan, &mintxpwr, &maxtxpwr,
   1463					  rate);
   1464
   1465		maxtxpwr = (maxtxpwr > pactrl) ? (maxtxpwr - pactrl) : 0;
   1466
   1467		maxtxpwr = (maxtxpwr > 6) ? (maxtxpwr - 6) : 0;
   1468
   1469		tx_pwr_max = max(tx_pwr_max, maxtxpwr);
   1470		tx_pwr_min = min(tx_pwr_min, maxtxpwr);
   1471	}
   1472	*max_txpwr = tx_pwr_max;
   1473	*min_txpwr = tx_pwr_min;
   1474}
   1475
   1476void
   1477wlc_phy_txpower_boardlimit_band(struct brcms_phy_pub *ppi, uint bandunit,
   1478				s32 *max_pwr, s32 *min_pwr, u32 *step_pwr)
   1479{
   1480	return;
   1481}
   1482
   1483u8 wlc_phy_txpower_get_target_min(struct brcms_phy_pub *ppi)
   1484{
   1485	struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
   1486
   1487	return pi->tx_power_min;
   1488}
   1489
   1490u8 wlc_phy_txpower_get_target_max(struct brcms_phy_pub *ppi)
   1491{
   1492	struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
   1493
   1494	return pi->tx_power_max;
   1495}
   1496
   1497static s8 wlc_phy_env_measure_vbat(struct brcms_phy *pi)
   1498{
   1499	if (ISLCNPHY(pi))
   1500		return wlc_lcnphy_vbatsense(pi, 0);
   1501	else
   1502		return 0;
   1503}
   1504
   1505static s8 wlc_phy_env_measure_temperature(struct brcms_phy *pi)
   1506{
   1507	if (ISLCNPHY(pi))
   1508		return wlc_lcnphy_tempsense_degree(pi, 0);
   1509	else
   1510		return 0;
   1511}
   1512
   1513static void wlc_phy_upd_env_txpwr_rate_limits(struct brcms_phy *pi, u32 band)
   1514{
   1515	u8 i;
   1516
   1517	for (i = 0; i < TXP_NUM_RATES; i++)
   1518		pi->txpwr_env_limit[i] = BRCMS_TXPWR_MAX;
   1519
   1520	wlc_phy_env_measure_vbat(pi);
   1521	wlc_phy_env_measure_temperature(pi);
   1522}
   1523
   1524static s8
   1525wlc_user_txpwr_antport_to_rfport(struct brcms_phy *pi, uint chan, u32 band,
   1526				 u8 rate)
   1527{
   1528	return 0;
   1529}
   1530
   1531void wlc_phy_txpower_recalc_target(struct brcms_phy *pi)
   1532{
   1533	u8 maxtxpwr, mintxpwr, rate, pactrl;
   1534	uint target_chan;
   1535	u8 tx_pwr_target[TXP_NUM_RATES];
   1536	u8 tx_pwr_max = 0;
   1537	u8 tx_pwr_min = 255;
   1538	u8 tx_pwr_max_rate_ind = 0;
   1539	u8 max_num_rate;
   1540	u8 start_rate = 0;
   1541	u16 chspec;
   1542	u32 band = CHSPEC2BAND(pi->radio_chanspec);
   1543	void (*txpwr_recalc_fn)(struct brcms_phy *) = NULL;
   1544
   1545	chspec = pi->radio_chanspec;
   1546	if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_NONE)
   1547		target_chan = CHSPEC_CHANNEL(chspec);
   1548	else if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_UPPER)
   1549		target_chan = upper_20_sb(CHSPEC_CHANNEL(chspec));
   1550	else
   1551		target_chan = lower_20_sb(CHSPEC_CHANNEL(chspec));
   1552
   1553	pactrl = 0;
   1554	if (ISLCNPHY(pi)) {
   1555		u32 offset_mcs, i;
   1556
   1557		if (CHSPEC_IS40(pi->radio_chanspec)) {
   1558			offset_mcs = pi->mcs40_po;
   1559			for (i = TXP_FIRST_SISO_MCS_20;
   1560			     i <= TXP_LAST_SISO_MCS_20; i++) {
   1561				pi->tx_srom_max_rate_2g[i - 8] =
   1562					pi->tx_srom_max_2g -
   1563					((offset_mcs & 0xf) * 2);
   1564				offset_mcs >>= 4;
   1565			}
   1566		} else {
   1567			offset_mcs = pi->mcs20_po;
   1568			for (i = TXP_FIRST_SISO_MCS_20;
   1569			     i <= TXP_LAST_SISO_MCS_20; i++) {
   1570				pi->tx_srom_max_rate_2g[i - 8] =
   1571					pi->tx_srom_max_2g -
   1572					((offset_mcs & 0xf) * 2);
   1573				offset_mcs >>= 4;
   1574			}
   1575		}
   1576	}
   1577
   1578	max_num_rate = ((ISNPHY(pi)) ? (TXP_NUM_RATES) :
   1579			((ISLCNPHY(pi)) ?
   1580			 (TXP_LAST_SISO_MCS_20 + 1) : (TXP_LAST_OFDM + 1)));
   1581
   1582	wlc_phy_upd_env_txpwr_rate_limits(pi, band);
   1583
   1584	for (rate = start_rate; rate < max_num_rate; rate++) {
   1585
   1586		tx_pwr_target[rate] = pi->tx_user_target[rate];
   1587
   1588		if (pi->user_txpwr_at_rfport)
   1589			tx_pwr_target[rate] +=
   1590				wlc_user_txpwr_antport_to_rfport(pi,
   1591								 target_chan,
   1592								 band,
   1593								 rate);
   1594
   1595		wlc_phy_txpower_sromlimit((struct brcms_phy_pub *) pi,
   1596					  target_chan,
   1597					  &mintxpwr, &maxtxpwr, rate);
   1598
   1599		maxtxpwr = min(maxtxpwr, pi->txpwr_limit[rate]);
   1600
   1601		maxtxpwr = (maxtxpwr > pactrl) ? (maxtxpwr - pactrl) : 0;
   1602
   1603		maxtxpwr = (maxtxpwr > 6) ? (maxtxpwr - 6) : 0;
   1604
   1605		maxtxpwr = min(maxtxpwr, tx_pwr_target[rate]);
   1606
   1607		if (pi->txpwr_percent <= 100)
   1608			maxtxpwr = (maxtxpwr * pi->txpwr_percent) / 100;
   1609
   1610		tx_pwr_target[rate] = max(maxtxpwr, mintxpwr);
   1611
   1612		tx_pwr_target[rate] =
   1613			min(tx_pwr_target[rate], pi->txpwr_env_limit[rate]);
   1614
   1615		if (tx_pwr_target[rate] > tx_pwr_max)
   1616			tx_pwr_max_rate_ind = rate;
   1617
   1618		tx_pwr_max = max(tx_pwr_max, tx_pwr_target[rate]);
   1619		tx_pwr_min = min(tx_pwr_min, tx_pwr_target[rate]);
   1620	}
   1621
   1622	memset(pi->tx_power_offset, 0, sizeof(pi->tx_power_offset));
   1623	pi->tx_power_max = tx_pwr_max;
   1624	pi->tx_power_min = tx_pwr_min;
   1625	pi->tx_power_max_rate_ind = tx_pwr_max_rate_ind;
   1626	for (rate = 0; rate < max_num_rate; rate++) {
   1627
   1628		pi->tx_power_target[rate] = tx_pwr_target[rate];
   1629
   1630		if (!pi->hwpwrctrl || ISNPHY(pi))
   1631			pi->tx_power_offset[rate] =
   1632				pi->tx_power_max - pi->tx_power_target[rate];
   1633		else
   1634			pi->tx_power_offset[rate] =
   1635				pi->tx_power_target[rate] - pi->tx_power_min;
   1636	}
   1637
   1638	txpwr_recalc_fn = pi->pi_fptr.txpwrrecalc;
   1639	if (txpwr_recalc_fn)
   1640		(*txpwr_recalc_fn)(pi);
   1641}
   1642
   1643static void
   1644wlc_phy_txpower_reg_limit_calc(struct brcms_phy *pi, struct txpwr_limits *txpwr,
   1645			       u16 chanspec)
   1646{
   1647	u8 tmp_txpwr_limit[2 * BRCMS_NUM_RATES_OFDM];
   1648	u8 *txpwr_ptr1 = NULL, *txpwr_ptr2 = NULL;
   1649	int rate_start_index = 0, rate1, rate2, k;
   1650
   1651	for (rate1 = WL_TX_POWER_CCK_FIRST, rate2 = 0;
   1652	     rate2 < WL_TX_POWER_CCK_NUM; rate1++, rate2++)
   1653		pi->txpwr_limit[rate1] = txpwr->cck[rate2];
   1654
   1655	for (rate1 = WL_TX_POWER_OFDM_FIRST, rate2 = 0;
   1656	     rate2 < WL_TX_POWER_OFDM_NUM; rate1++, rate2++)
   1657		pi->txpwr_limit[rate1] = txpwr->ofdm[rate2];
   1658
   1659	if (ISNPHY(pi)) {
   1660
   1661		for (k = 0; k < 4; k++) {
   1662			switch (k) {
   1663			case 0:
   1664
   1665				txpwr_ptr1 = txpwr->mcs_20_siso;
   1666				txpwr_ptr2 = txpwr->ofdm;
   1667				rate_start_index = WL_TX_POWER_OFDM_FIRST;
   1668				break;
   1669			case 1:
   1670
   1671				txpwr_ptr1 = txpwr->mcs_20_cdd;
   1672				txpwr_ptr2 = txpwr->ofdm_cdd;
   1673				rate_start_index = WL_TX_POWER_OFDM20_CDD_FIRST;
   1674				break;
   1675			case 2:
   1676
   1677				txpwr_ptr1 = txpwr->mcs_40_siso;
   1678				txpwr_ptr2 = txpwr->ofdm_40_siso;
   1679				rate_start_index =
   1680					WL_TX_POWER_OFDM40_SISO_FIRST;
   1681				break;
   1682			case 3:
   1683
   1684				txpwr_ptr1 = txpwr->mcs_40_cdd;
   1685				txpwr_ptr2 = txpwr->ofdm_40_cdd;
   1686				rate_start_index = WL_TX_POWER_OFDM40_CDD_FIRST;
   1687				break;
   1688			}
   1689
   1690			for (rate2 = 0; rate2 < BRCMS_NUM_RATES_OFDM;
   1691			     rate2++) {
   1692				tmp_txpwr_limit[rate2] = 0;
   1693				tmp_txpwr_limit[BRCMS_NUM_RATES_OFDM + rate2] =
   1694					txpwr_ptr1[rate2];
   1695			}
   1696			wlc_phy_mcs_to_ofdm_powers_nphy(
   1697				tmp_txpwr_limit, 0,
   1698				BRCMS_NUM_RATES_OFDM -
   1699				1, BRCMS_NUM_RATES_OFDM);
   1700			for (rate1 = rate_start_index, rate2 = 0;
   1701			     rate2 < BRCMS_NUM_RATES_OFDM; rate1++, rate2++)
   1702				pi->txpwr_limit[rate1] =
   1703					min(txpwr_ptr2[rate2],
   1704					    tmp_txpwr_limit[rate2]);
   1705		}
   1706
   1707		for (k = 0; k < 4; k++) {
   1708			switch (k) {
   1709			case 0:
   1710
   1711				txpwr_ptr1 = txpwr->ofdm;
   1712				txpwr_ptr2 = txpwr->mcs_20_siso;
   1713				rate_start_index = WL_TX_POWER_MCS20_SISO_FIRST;
   1714				break;
   1715			case 1:
   1716
   1717				txpwr_ptr1 = txpwr->ofdm_cdd;
   1718				txpwr_ptr2 = txpwr->mcs_20_cdd;
   1719				rate_start_index = WL_TX_POWER_MCS20_CDD_FIRST;
   1720				break;
   1721			case 2:
   1722
   1723				txpwr_ptr1 = txpwr->ofdm_40_siso;
   1724				txpwr_ptr2 = txpwr->mcs_40_siso;
   1725				rate_start_index = WL_TX_POWER_MCS40_SISO_FIRST;
   1726				break;
   1727			case 3:
   1728
   1729				txpwr_ptr1 = txpwr->ofdm_40_cdd;
   1730				txpwr_ptr2 = txpwr->mcs_40_cdd;
   1731				rate_start_index = WL_TX_POWER_MCS40_CDD_FIRST;
   1732				break;
   1733			}
   1734			for (rate2 = 0; rate2 < BRCMS_NUM_RATES_OFDM;
   1735			     rate2++) {
   1736				tmp_txpwr_limit[rate2] = 0;
   1737				tmp_txpwr_limit[BRCMS_NUM_RATES_OFDM + rate2] =
   1738					txpwr_ptr1[rate2];
   1739			}
   1740			wlc_phy_ofdm_to_mcs_powers_nphy(
   1741				tmp_txpwr_limit, 0,
   1742				BRCMS_NUM_RATES_OFDM -
   1743				1, BRCMS_NUM_RATES_OFDM);
   1744			for (rate1 = rate_start_index, rate2 = 0;
   1745			     rate2 < BRCMS_NUM_RATES_MCS_1_STREAM;
   1746			     rate1++, rate2++)
   1747				pi->txpwr_limit[rate1] =
   1748					min(txpwr_ptr2[rate2],
   1749					    tmp_txpwr_limit[rate2]);
   1750		}
   1751
   1752		for (k = 0; k < 2; k++) {
   1753			switch (k) {
   1754			case 0:
   1755
   1756				rate_start_index = WL_TX_POWER_MCS20_STBC_FIRST;
   1757				txpwr_ptr1 = txpwr->mcs_20_stbc;
   1758				break;
   1759			case 1:
   1760
   1761				rate_start_index = WL_TX_POWER_MCS40_STBC_FIRST;
   1762				txpwr_ptr1 = txpwr->mcs_40_stbc;
   1763				break;
   1764			}
   1765			for (rate1 = rate_start_index, rate2 = 0;
   1766			     rate2 < BRCMS_NUM_RATES_MCS_1_STREAM;
   1767			     rate1++, rate2++)
   1768				pi->txpwr_limit[rate1] = txpwr_ptr1[rate2];
   1769		}
   1770
   1771		for (k = 0; k < 2; k++) {
   1772			switch (k) {
   1773			case 0:
   1774
   1775				rate_start_index = WL_TX_POWER_MCS20_SDM_FIRST;
   1776				txpwr_ptr1 = txpwr->mcs_20_mimo;
   1777				break;
   1778			case 1:
   1779
   1780				rate_start_index = WL_TX_POWER_MCS40_SDM_FIRST;
   1781				txpwr_ptr1 = txpwr->mcs_40_mimo;
   1782				break;
   1783			}
   1784			for (rate1 = rate_start_index, rate2 = 0;
   1785			     rate2 < BRCMS_NUM_RATES_MCS_2_STREAM;
   1786			     rate1++, rate2++)
   1787				pi->txpwr_limit[rate1] = txpwr_ptr1[rate2];
   1788		}
   1789
   1790		pi->txpwr_limit[WL_TX_POWER_MCS_32] = txpwr->mcs32;
   1791
   1792		pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST] =
   1793			min(pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST],
   1794			    pi->txpwr_limit[WL_TX_POWER_MCS_32]);
   1795		pi->txpwr_limit[WL_TX_POWER_MCS_32] =
   1796			pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST];
   1797	}
   1798}
   1799
   1800void wlc_phy_txpwr_percent_set(struct brcms_phy_pub *ppi, u8 txpwr_percent)
   1801{
   1802	struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
   1803
   1804	pi->txpwr_percent = txpwr_percent;
   1805}
   1806
   1807void wlc_phy_machwcap_set(struct brcms_phy_pub *ppi, u32 machwcap)
   1808{
   1809	struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
   1810
   1811	pi->sh->machwcap = machwcap;
   1812}
   1813
   1814void wlc_phy_runbist_config(struct brcms_phy_pub *ppi, bool start_end)
   1815{
   1816	struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
   1817	u16 rxc;
   1818	rxc = 0;
   1819
   1820	if (start_end == ON) {
   1821		if (!ISNPHY(pi))
   1822			return;
   1823
   1824		if (NREV_IS(pi->pubpi.phy_rev, 3)
   1825		    || NREV_IS(pi->pubpi.phy_rev, 4)) {
   1826			bcma_wflush16(pi->d11core, D11REGOFFS(phyregaddr),
   1827				      0xa0);
   1828			bcma_set16(pi->d11core, D11REGOFFS(phyregdata),
   1829				   0x1 << 15);
   1830		}
   1831	} else {
   1832		if (NREV_IS(pi->pubpi.phy_rev, 3)
   1833		    || NREV_IS(pi->pubpi.phy_rev, 4)) {
   1834			bcma_wflush16(pi->d11core, D11REGOFFS(phyregaddr),
   1835				      0xa0);
   1836			bcma_write16(pi->d11core, D11REGOFFS(phyregdata), rxc);
   1837		}
   1838
   1839		wlc_phy_por_inform(ppi);
   1840	}
   1841}
   1842
   1843void
   1844wlc_phy_txpower_limit_set(struct brcms_phy_pub *ppi, struct txpwr_limits *txpwr,
   1845			  u16 chanspec)
   1846{
   1847	struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
   1848
   1849	wlc_phy_txpower_reg_limit_calc(pi, txpwr, chanspec);
   1850
   1851	if (ISLCNPHY(pi)) {
   1852		int i, j;
   1853		for (i = TXP_FIRST_OFDM_20_CDD, j = 0;
   1854		     j < BRCMS_NUM_RATES_MCS_1_STREAM; i++, j++) {
   1855			if (txpwr->mcs_20_siso[j])
   1856				pi->txpwr_limit[i] = txpwr->mcs_20_siso[j];
   1857			else
   1858				pi->txpwr_limit[i] = txpwr->ofdm[j];
   1859		}
   1860	}
   1861
   1862	wlapi_suspend_mac_and_wait(pi->sh->physhim);
   1863
   1864	wlc_phy_txpower_recalc_target(pi);
   1865	wlc_phy_cal_txpower_recalc_sw(pi);
   1866	wlapi_enable_mac(pi->sh->physhim);
   1867}
   1868
   1869void wlc_phy_ofdm_rateset_war(struct brcms_phy_pub *pih, bool war)
   1870{
   1871	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
   1872
   1873	pi->ofdm_rateset_war = war;
   1874}
   1875
   1876void wlc_phy_bf_preempt_enable(struct brcms_phy_pub *pih, bool bf_preempt)
   1877{
   1878	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
   1879
   1880	pi->bf_preempt_4306 = bf_preempt;
   1881}
   1882
   1883void wlc_phy_txpower_update_shm(struct brcms_phy *pi)
   1884{
   1885	int j;
   1886	if (ISNPHY(pi))
   1887		return;
   1888
   1889	if (!pi->sh->clk)
   1890		return;
   1891
   1892	if (pi->hwpwrctrl) {
   1893		u16 offset;
   1894
   1895		wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_MAX, 63);
   1896		wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_N,
   1897				     1 << NUM_TSSI_FRAMES);
   1898
   1899		wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_TARGET,
   1900				     pi->tx_power_min << NUM_TSSI_FRAMES);
   1901
   1902		wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_CUR,
   1903				     pi->hwpwr_txcur);
   1904
   1905		for (j = TXP_FIRST_OFDM; j <= TXP_LAST_OFDM; j++) {
   1906			static const u8 ucode_ofdm_rates[] = {
   1907				0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c
   1908			};
   1909			offset = wlapi_bmac_rate_shm_offset(
   1910				pi->sh->physhim,
   1911				ucode_ofdm_rates[j - TXP_FIRST_OFDM]);
   1912			wlapi_bmac_write_shm(pi->sh->physhim, offset + 6,
   1913					     pi->tx_power_offset[j]);
   1914			wlapi_bmac_write_shm(pi->sh->physhim, offset + 14,
   1915					     -(pi->tx_power_offset[j] / 2));
   1916		}
   1917
   1918		wlapi_bmac_mhf(pi->sh->physhim, MHF2, MHF2_HWPWRCTL,
   1919			       MHF2_HWPWRCTL, BRCM_BAND_ALL);
   1920	} else {
   1921		int i;
   1922
   1923		for (i = TXP_FIRST_OFDM; i <= TXP_LAST_OFDM; i++)
   1924			pi->tx_power_offset[i] =
   1925				(u8) roundup(pi->tx_power_offset[i], 8);
   1926		wlapi_bmac_write_shm(pi->sh->physhim, M_OFDM_OFFSET,
   1927				     (u16)
   1928				     ((pi->tx_power_offset[TXP_FIRST_OFDM]
   1929				       + 7) >> 3));
   1930	}
   1931}
   1932
   1933bool wlc_phy_txpower_hw_ctrl_get(struct brcms_phy_pub *ppi)
   1934{
   1935	struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
   1936
   1937	if (ISNPHY(pi))
   1938		return pi->nphy_txpwrctrl;
   1939	else
   1940		return pi->hwpwrctrl;
   1941}
   1942
   1943void wlc_phy_txpower_hw_ctrl_set(struct brcms_phy_pub *ppi, bool hwpwrctrl)
   1944{
   1945	struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
   1946	bool suspend;
   1947
   1948	if (!pi->hwpwrctrl_capable)
   1949		return;
   1950
   1951	pi->hwpwrctrl = hwpwrctrl;
   1952	pi->nphy_txpwrctrl = hwpwrctrl;
   1953	pi->txpwrctrl = hwpwrctrl;
   1954
   1955	if (ISNPHY(pi)) {
   1956		suspend = (0 == (bcma_read32(pi->d11core,
   1957					     D11REGOFFS(maccontrol)) &
   1958				 MCTL_EN_MAC));
   1959		if (!suspend)
   1960			wlapi_suspend_mac_and_wait(pi->sh->physhim);
   1961
   1962		wlc_phy_txpwrctrl_enable_nphy(pi, pi->nphy_txpwrctrl);
   1963		if (pi->nphy_txpwrctrl == PHY_TPC_HW_OFF)
   1964			wlc_phy_txpwr_fixpower_nphy(pi);
   1965		else
   1966			mod_phy_reg(pi, 0x1e7, (0x7f << 0),
   1967				    pi->saved_txpwr_idx);
   1968
   1969		if (!suspend)
   1970			wlapi_enable_mac(pi->sh->physhim);
   1971	}
   1972}
   1973
   1974void wlc_phy_txpower_ipa_upd(struct brcms_phy *pi)
   1975{
   1976
   1977	if (NREV_GE(pi->pubpi.phy_rev, 3)) {
   1978		pi->ipa2g_on = (pi->srom_fem2g.extpagain == 2);
   1979		pi->ipa5g_on = (pi->srom_fem5g.extpagain == 2);
   1980	} else {
   1981		pi->ipa2g_on = false;
   1982		pi->ipa5g_on = false;
   1983	}
   1984}
   1985
   1986static u32 wlc_phy_txpower_est_power_nphy(struct brcms_phy *pi)
   1987{
   1988	s16 tx0_status, tx1_status;
   1989	u16 estPower1, estPower2;
   1990	u8 pwr0, pwr1, adj_pwr0, adj_pwr1;
   1991	u32 est_pwr;
   1992
   1993	estPower1 = read_phy_reg(pi, 0x118);
   1994	estPower2 = read_phy_reg(pi, 0x119);
   1995
   1996	if ((estPower1 & (0x1 << 8)) == (0x1 << 8))
   1997		pwr0 = (u8) (estPower1 & (0xff << 0)) >> 0;
   1998	else
   1999		pwr0 = 0x80;
   2000
   2001	if ((estPower2 & (0x1 << 8)) == (0x1 << 8))
   2002		pwr1 = (u8) (estPower2 & (0xff << 0)) >> 0;
   2003	else
   2004		pwr1 = 0x80;
   2005
   2006	tx0_status = read_phy_reg(pi, 0x1ed);
   2007	tx1_status = read_phy_reg(pi, 0x1ee);
   2008
   2009	if ((tx0_status & (0x1 << 15)) == (0x1 << 15))
   2010		adj_pwr0 = (u8) (tx0_status & (0xff << 0)) >> 0;
   2011	else
   2012		adj_pwr0 = 0x80;
   2013	if ((tx1_status & (0x1 << 15)) == (0x1 << 15))
   2014		adj_pwr1 = (u8) (tx1_status & (0xff << 0)) >> 0;
   2015	else
   2016		adj_pwr1 = 0x80;
   2017
   2018	est_pwr = (u32) ((pwr0 << 24) | (pwr1 << 16) | (adj_pwr0 << 8) |
   2019			 adj_pwr1);
   2020
   2021	return est_pwr;
   2022}
   2023
   2024void
   2025wlc_phy_txpower_get_current(struct brcms_phy_pub *ppi, struct tx_power *power,
   2026			    uint channel)
   2027{
   2028	struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
   2029	uint rate, num_rates;
   2030	u8 min_pwr, max_pwr;
   2031
   2032#if WL_TX_POWER_RATES != TXP_NUM_RATES
   2033#error "struct tx_power out of sync with this fn"
   2034#endif
   2035
   2036	if (ISNPHY(pi)) {
   2037		power->rf_cores = 2;
   2038		power->flags |= (WL_TX_POWER_F_MIMO);
   2039		if (pi->nphy_txpwrctrl == PHY_TPC_HW_ON)
   2040			power->flags |=
   2041				(WL_TX_POWER_F_ENABLED | WL_TX_POWER_F_HW);
   2042	} else if (ISLCNPHY(pi)) {
   2043		power->rf_cores = 1;
   2044		power->flags |= (WL_TX_POWER_F_SISO);
   2045		if (pi->radiopwr_override == RADIOPWR_OVERRIDE_DEF)
   2046			power->flags |= WL_TX_POWER_F_ENABLED;
   2047		if (pi->hwpwrctrl)
   2048			power->flags |= WL_TX_POWER_F_HW;
   2049	}
   2050
   2051	num_rates = ((ISNPHY(pi)) ? (TXP_NUM_RATES) :
   2052		     ((ISLCNPHY(pi)) ?
   2053		      (TXP_LAST_OFDM_20_CDD + 1) : (TXP_LAST_OFDM + 1)));
   2054
   2055	for (rate = 0; rate < num_rates; rate++) {
   2056		power->user_limit[rate] = pi->tx_user_target[rate];
   2057		wlc_phy_txpower_sromlimit(ppi, channel, &min_pwr, &max_pwr,
   2058					  rate);
   2059		power->board_limit[rate] = (u8) max_pwr;
   2060		power->target[rate] = pi->tx_power_target[rate];
   2061	}
   2062
   2063	if (ISNPHY(pi)) {
   2064		u32 est_pout;
   2065
   2066		wlapi_suspend_mac_and_wait(pi->sh->physhim);
   2067		wlc_phyreg_enter((struct brcms_phy_pub *) pi);
   2068		est_pout = wlc_phy_txpower_est_power_nphy(pi);
   2069		wlc_phyreg_exit((struct brcms_phy_pub *) pi);
   2070		wlapi_enable_mac(pi->sh->physhim);
   2071
   2072		power->est_Pout[0] = (est_pout >> 8) & 0xff;
   2073		power->est_Pout[1] = est_pout & 0xff;
   2074
   2075		power->est_Pout_act[0] = est_pout >> 24;
   2076		power->est_Pout_act[1] = (est_pout >> 16) & 0xff;
   2077
   2078		if (power->est_Pout[0] == 0x80)
   2079			power->est_Pout[0] = 0;
   2080		if (power->est_Pout[1] == 0x80)
   2081			power->est_Pout[1] = 0;
   2082
   2083		if (power->est_Pout_act[0] == 0x80)
   2084			power->est_Pout_act[0] = 0;
   2085		if (power->est_Pout_act[1] == 0x80)
   2086			power->est_Pout_act[1] = 0;
   2087
   2088		power->est_Pout_cck = 0;
   2089
   2090		power->tx_power_max[0] = pi->tx_power_max;
   2091		power->tx_power_max[1] = pi->tx_power_max;
   2092
   2093		power->tx_power_max_rate_ind[0] = pi->tx_power_max_rate_ind;
   2094		power->tx_power_max_rate_ind[1] = pi->tx_power_max_rate_ind;
   2095	} else if (pi->hwpwrctrl && pi->sh->up) {
   2096
   2097		wlc_phyreg_enter(ppi);
   2098		if (ISLCNPHY(pi)) {
   2099
   2100			power->tx_power_max[0] = pi->tx_power_max;
   2101			power->tx_power_max[1] = pi->tx_power_max;
   2102
   2103			power->tx_power_max_rate_ind[0] =
   2104				pi->tx_power_max_rate_ind;
   2105			power->tx_power_max_rate_ind[1] =
   2106				pi->tx_power_max_rate_ind;
   2107
   2108			if (wlc_phy_tpc_isenabled_lcnphy(pi))
   2109				power->flags |=
   2110					(WL_TX_POWER_F_HW |
   2111					 WL_TX_POWER_F_ENABLED);
   2112			else
   2113				power->flags &=
   2114					~(WL_TX_POWER_F_HW |
   2115					  WL_TX_POWER_F_ENABLED);
   2116
   2117			wlc_lcnphy_get_tssi(pi, (s8 *) &power->est_Pout[0],
   2118					    (s8 *) &power->est_Pout_cck);
   2119		}
   2120		wlc_phyreg_exit(ppi);
   2121	}
   2122}
   2123
   2124void wlc_phy_antsel_type_set(struct brcms_phy_pub *ppi, u8 antsel_type)
   2125{
   2126	struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
   2127
   2128	pi->antsel_type = antsel_type;
   2129}
   2130
   2131bool wlc_phy_test_ison(struct brcms_phy_pub *ppi)
   2132{
   2133	struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
   2134
   2135	return pi->phytest_on;
   2136}
   2137
   2138void wlc_phy_ant_rxdiv_set(struct brcms_phy_pub *ppi, u8 val)
   2139{
   2140	struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
   2141	bool suspend;
   2142
   2143	pi->sh->rx_antdiv = val;
   2144
   2145	if (!(ISNPHY(pi) && D11REV_IS(pi->sh->corerev, 16))) {
   2146		if (val > ANT_RX_DIV_FORCE_1)
   2147			wlapi_bmac_mhf(pi->sh->physhim, MHF1, MHF1_ANTDIV,
   2148				       MHF1_ANTDIV, BRCM_BAND_ALL);
   2149		else
   2150			wlapi_bmac_mhf(pi->sh->physhim, MHF1, MHF1_ANTDIV, 0,
   2151				       BRCM_BAND_ALL);
   2152	}
   2153
   2154	if (ISNPHY(pi))
   2155		return;
   2156
   2157	if (!pi->sh->clk)
   2158		return;
   2159
   2160	suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) &
   2161			 MCTL_EN_MAC));
   2162	if (!suspend)
   2163		wlapi_suspend_mac_and_wait(pi->sh->physhim);
   2164
   2165	if (ISLCNPHY(pi)) {
   2166		if (val > ANT_RX_DIV_FORCE_1) {
   2167			mod_phy_reg(pi, 0x410, (0x1 << 1), 0x01 << 1);
   2168			mod_phy_reg(pi, 0x410,
   2169				    (0x1 << 0),
   2170				    ((ANT_RX_DIV_START_1 == val) ? 1 : 0) << 0);
   2171		} else {
   2172			mod_phy_reg(pi, 0x410, (0x1 << 1), 0x00 << 1);
   2173			mod_phy_reg(pi, 0x410, (0x1 << 0), (u16) val << 0);
   2174		}
   2175	}
   2176
   2177	if (!suspend)
   2178		wlapi_enable_mac(pi->sh->physhim);
   2179
   2180	return;
   2181}
   2182
   2183static bool
   2184wlc_phy_noise_calc_phy(struct brcms_phy *pi, u32 *cmplx_pwr, s8 *pwr_ant)
   2185{
   2186	s8 cmplx_pwr_dbm[PHY_CORE_MAX];
   2187	u8 i;
   2188
   2189	memset((u8 *) cmplx_pwr_dbm, 0, sizeof(cmplx_pwr_dbm));
   2190	wlc_phy_compute_dB(cmplx_pwr, cmplx_pwr_dbm, pi->pubpi.phy_corenum);
   2191
   2192	for (i = 0; i < pi->pubpi.phy_corenum; i++) {
   2193		if (NREV_GE(pi->pubpi.phy_rev, 3))
   2194			cmplx_pwr_dbm[i] += (s8) PHY_NOISE_OFFSETFACT_4322;
   2195		else
   2196
   2197			cmplx_pwr_dbm[i] += (s8) (16 - (15) * 3 - 70);
   2198	}
   2199
   2200	for (i = 0; i < pi->pubpi.phy_corenum; i++) {
   2201		pi->nphy_noise_win[i][pi->nphy_noise_index] = cmplx_pwr_dbm[i];
   2202		pwr_ant[i] = cmplx_pwr_dbm[i];
   2203	}
   2204	pi->nphy_noise_index =
   2205		MODINC_POW2(pi->nphy_noise_index, PHY_NOISE_WINDOW_SZ);
   2206	return true;
   2207}
   2208
   2209static void wlc_phy_noise_cb(struct brcms_phy *pi, u8 channel, s8 noise_dbm)
   2210{
   2211	if (!pi->phynoise_state)
   2212		return;
   2213
   2214	if (pi->phynoise_state & PHY_NOISE_STATE_MON) {
   2215		if (pi->phynoise_chan_watchdog == channel) {
   2216			pi->sh->phy_noise_window[pi->sh->phy_noise_index] =
   2217				noise_dbm;
   2218			pi->sh->phy_noise_index =
   2219				MODINC(pi->sh->phy_noise_index, MA_WINDOW_SZ);
   2220		}
   2221		pi->phynoise_state &= ~PHY_NOISE_STATE_MON;
   2222	}
   2223
   2224	if (pi->phynoise_state & PHY_NOISE_STATE_EXTERNAL)
   2225		pi->phynoise_state &= ~PHY_NOISE_STATE_EXTERNAL;
   2226
   2227}
   2228
   2229static s8 wlc_phy_noise_read_shmem(struct brcms_phy *pi)
   2230{
   2231	u32 cmplx_pwr[PHY_CORE_MAX];
   2232	s8 noise_dbm_ant[PHY_CORE_MAX];
   2233	u16 lo, hi;
   2234	u32 cmplx_pwr_tot = 0;
   2235	s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
   2236	u8 idx, core;
   2237
   2238	memset((u8 *) cmplx_pwr, 0, sizeof(cmplx_pwr));
   2239	memset((u8 *) noise_dbm_ant, 0, sizeof(noise_dbm_ant));
   2240
   2241	for (idx = 0, core = 0; core < pi->pubpi.phy_corenum; idx += 2,
   2242	     core++) {
   2243		lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP(idx));
   2244		hi = wlapi_bmac_read_shm(pi->sh->physhim,
   2245					 M_PWRIND_MAP(idx + 1));
   2246		cmplx_pwr[core] = (hi << 16) + lo;
   2247		cmplx_pwr_tot += cmplx_pwr[core];
   2248		if (cmplx_pwr[core] == 0)
   2249			noise_dbm_ant[core] = PHY_NOISE_FIXED_VAL_NPHY;
   2250		else
   2251			cmplx_pwr[core] >>= PHY_NOISE_SAMPLE_LOG_NUM_UCODE;
   2252	}
   2253
   2254	if (cmplx_pwr_tot != 0)
   2255		wlc_phy_noise_calc_phy(pi, cmplx_pwr, noise_dbm_ant);
   2256
   2257	for (core = 0; core < pi->pubpi.phy_corenum; core++) {
   2258		pi->nphy_noise_win[core][pi->nphy_noise_index] =
   2259			noise_dbm_ant[core];
   2260
   2261		if (noise_dbm_ant[core] > noise_dbm)
   2262			noise_dbm = noise_dbm_ant[core];
   2263	}
   2264	pi->nphy_noise_index =
   2265		MODINC_POW2(pi->nphy_noise_index, PHY_NOISE_WINDOW_SZ);
   2266
   2267	return noise_dbm;
   2268
   2269}
   2270
   2271void wlc_phy_noise_sample_intr(struct brcms_phy_pub *pih)
   2272{
   2273	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
   2274	u16 jssi_aux;
   2275	u8 channel = 0;
   2276	s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
   2277
   2278	if (ISLCNPHY(pi)) {
   2279		u32 cmplx_pwr, cmplx_pwr0, cmplx_pwr1;
   2280		u16 lo, hi;
   2281		s32 pwr_offset_dB, gain_dB;
   2282		u16 status_0, status_1;
   2283
   2284		jssi_aux = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_AUX);
   2285		channel = jssi_aux & D11_CURCHANNEL_MAX;
   2286
   2287		lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP0);
   2288		hi = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP1);
   2289		cmplx_pwr0 = (hi << 16) + lo;
   2290
   2291		lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP2);
   2292		hi = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP3);
   2293		cmplx_pwr1 = (hi << 16) + lo;
   2294		cmplx_pwr = (cmplx_pwr0 + cmplx_pwr1) >> 6;
   2295
   2296		status_0 = 0x44;
   2297		status_1 = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_0);
   2298		if ((cmplx_pwr > 0 && cmplx_pwr < 500)
   2299		    && ((status_1 & 0xc000) == 0x4000)) {
   2300
   2301			wlc_phy_compute_dB(&cmplx_pwr, &noise_dbm,
   2302					   pi->pubpi.phy_corenum);
   2303			pwr_offset_dB = (read_phy_reg(pi, 0x434) & 0xFF);
   2304			if (pwr_offset_dB > 127)
   2305				pwr_offset_dB -= 256;
   2306
   2307			noise_dbm += (s8) (pwr_offset_dB - 30);
   2308
   2309			gain_dB = (status_0 & 0x1ff);
   2310			noise_dbm -= (s8) (gain_dB);
   2311		} else {
   2312			noise_dbm = PHY_NOISE_FIXED_VAL_LCNPHY;
   2313		}
   2314	} else if (ISNPHY(pi)) {
   2315
   2316		jssi_aux = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_AUX);
   2317		channel = jssi_aux & D11_CURCHANNEL_MAX;
   2318
   2319		noise_dbm = wlc_phy_noise_read_shmem(pi);
   2320	}
   2321
   2322	wlc_phy_noise_cb(pi, channel, noise_dbm);
   2323
   2324}
   2325
   2326static void
   2327wlc_phy_noise_sample_request(struct brcms_phy_pub *pih, u8 reason, u8 ch)
   2328{
   2329	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
   2330	s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
   2331	bool sampling_in_progress = (pi->phynoise_state != 0);
   2332	bool wait_for_intr = true;
   2333
   2334	switch (reason) {
   2335	case PHY_NOISE_SAMPLE_MON:
   2336		pi->phynoise_chan_watchdog = ch;
   2337		pi->phynoise_state |= PHY_NOISE_STATE_MON;
   2338		break;
   2339
   2340	case PHY_NOISE_SAMPLE_EXTERNAL:
   2341		pi->phynoise_state |= PHY_NOISE_STATE_EXTERNAL;
   2342		break;
   2343
   2344	default:
   2345		break;
   2346	}
   2347
   2348	if (sampling_in_progress)
   2349		return;
   2350
   2351	pi->phynoise_now = pi->sh->now;
   2352
   2353	if (pi->phy_fixed_noise) {
   2354		if (ISNPHY(pi)) {
   2355			pi->nphy_noise_win[WL_ANT_IDX_1][pi->nphy_noise_index] =
   2356				PHY_NOISE_FIXED_VAL_NPHY;
   2357			pi->nphy_noise_win[WL_ANT_IDX_2][pi->nphy_noise_index] =
   2358				PHY_NOISE_FIXED_VAL_NPHY;
   2359			pi->nphy_noise_index = MODINC_POW2(pi->nphy_noise_index,
   2360							   PHY_NOISE_WINDOW_SZ);
   2361			noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
   2362		} else {
   2363			noise_dbm = PHY_NOISE_FIXED_VAL;
   2364		}
   2365
   2366		wait_for_intr = false;
   2367		goto done;
   2368	}
   2369
   2370	if (ISLCNPHY(pi)) {
   2371		if (!pi->phynoise_polling
   2372		    || (reason == PHY_NOISE_SAMPLE_EXTERNAL)) {
   2373			wlapi_bmac_write_shm(pi->sh->physhim, M_JSSI_0, 0);
   2374			wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP0, 0);
   2375			wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP1, 0);
   2376			wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP2, 0);
   2377			wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP3, 0);
   2378
   2379			bcma_set32(pi->d11core, D11REGOFFS(maccommand),
   2380				   MCMD_BG_NOISE);
   2381		} else {
   2382			wlapi_suspend_mac_and_wait(pi->sh->physhim);
   2383			wlc_lcnphy_deaf_mode(pi, (bool) 0);
   2384			noise_dbm = (s8) wlc_lcnphy_rx_signal_power(pi, 20);
   2385			wlc_lcnphy_deaf_mode(pi, (bool) 1);
   2386			wlapi_enable_mac(pi->sh->physhim);
   2387			wait_for_intr = false;
   2388		}
   2389	} else if (ISNPHY(pi)) {
   2390		if (!pi->phynoise_polling
   2391		    || (reason == PHY_NOISE_SAMPLE_EXTERNAL)) {
   2392
   2393			wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP0, 0);
   2394			wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP1, 0);
   2395			wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP2, 0);
   2396			wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP3, 0);
   2397
   2398			bcma_set32(pi->d11core, D11REGOFFS(maccommand),
   2399				   MCMD_BG_NOISE);
   2400		} else {
   2401			struct phy_iq_est est[PHY_CORE_MAX];
   2402			u32 cmplx_pwr[PHY_CORE_MAX];
   2403			s8 noise_dbm_ant[PHY_CORE_MAX];
   2404			u16 log_num_samps, num_samps, classif_state = 0;
   2405			u8 wait_time = 32;
   2406			u8 wait_crs = 0;
   2407			u8 i;
   2408
   2409			memset((u8 *) est, 0, sizeof(est));
   2410			memset((u8 *) cmplx_pwr, 0, sizeof(cmplx_pwr));
   2411			memset((u8 *) noise_dbm_ant, 0, sizeof(noise_dbm_ant));
   2412
   2413			log_num_samps = PHY_NOISE_SAMPLE_LOG_NUM_NPHY;
   2414			num_samps = 1 << log_num_samps;
   2415
   2416			wlapi_suspend_mac_and_wait(pi->sh->physhim);
   2417			classif_state = wlc_phy_classifier_nphy(pi, 0, 0);
   2418			wlc_phy_classifier_nphy(pi, 3, 0);
   2419			wlc_phy_rx_iq_est_nphy(pi, est, num_samps, wait_time,
   2420					       wait_crs);
   2421			wlc_phy_classifier_nphy(pi, (0x7 << 0), classif_state);
   2422			wlapi_enable_mac(pi->sh->physhim);
   2423
   2424			for (i = 0; i < pi->pubpi.phy_corenum; i++)
   2425				cmplx_pwr[i] = (est[i].i_pwr + est[i].q_pwr) >>
   2426					       log_num_samps;
   2427
   2428			wlc_phy_noise_calc_phy(pi, cmplx_pwr, noise_dbm_ant);
   2429
   2430			for (i = 0; i < pi->pubpi.phy_corenum; i++) {
   2431				pi->nphy_noise_win[i][pi->nphy_noise_index] =
   2432					noise_dbm_ant[i];
   2433
   2434				if (noise_dbm_ant[i] > noise_dbm)
   2435					noise_dbm = noise_dbm_ant[i];
   2436			}
   2437			pi->nphy_noise_index = MODINC_POW2(pi->nphy_noise_index,
   2438							   PHY_NOISE_WINDOW_SZ);
   2439
   2440			wait_for_intr = false;
   2441		}
   2442	}
   2443
   2444done:
   2445
   2446	if (!wait_for_intr)
   2447		wlc_phy_noise_cb(pi, ch, noise_dbm);
   2448
   2449}
   2450
   2451void wlc_phy_noise_sample_request_external(struct brcms_phy_pub *pih)
   2452{
   2453	u8 channel;
   2454
   2455	channel = CHSPEC_CHANNEL(wlc_phy_chanspec_get(pih));
   2456
   2457	wlc_phy_noise_sample_request(pih, PHY_NOISE_SAMPLE_EXTERNAL, channel);
   2458}
   2459
   2460static const s8 lcnphy_gain_index_offset_for_pkt_rssi[] = {
   2461	8,
   2462	8,
   2463	8,
   2464	8,
   2465	8,
   2466	8,
   2467	8,
   2468	9,
   2469	10,
   2470	8,
   2471	8,
   2472	7,
   2473	7,
   2474	1,
   2475	2,
   2476	2,
   2477	2,
   2478	2,
   2479	2,
   2480	2,
   2481	2,
   2482	2,
   2483	2,
   2484	2,
   2485	2,
   2486	2,
   2487	2,
   2488	2,
   2489	2,
   2490	2,
   2491	2,
   2492	2,
   2493	1,
   2494	1,
   2495	0,
   2496	0,
   2497	0,
   2498	0
   2499};
   2500
   2501void wlc_phy_compute_dB(u32 *cmplx_pwr, s8 *p_cmplx_pwr_dB, u8 core)
   2502{
   2503	u8 msb, secondmsb, i;
   2504	u32 tmp;
   2505
   2506	for (i = 0; i < core; i++) {
   2507		secondmsb = 0;
   2508		tmp = cmplx_pwr[i];
   2509		msb = fls(tmp);
   2510		if (msb)
   2511			secondmsb = (u8) ((tmp >> (--msb - 1)) & 1);
   2512		p_cmplx_pwr_dB[i] = (s8) (3 * msb + 2 * secondmsb);
   2513	}
   2514}
   2515
   2516int wlc_phy_rssi_compute(struct brcms_phy_pub *pih,
   2517			 struct d11rxhdr *rxh)
   2518{
   2519	int rssi = rxh->PhyRxStatus_1 & PRXS1_JSSI_MASK;
   2520	uint radioid = pih->radioid;
   2521	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
   2522
   2523	if ((pi->sh->corerev >= 11)
   2524	    && !(rxh->RxStatus2 & RXS_PHYRXST_VALID)) {
   2525		rssi = BRCMS_RSSI_INVALID;
   2526		goto end;
   2527	}
   2528
   2529	if (ISLCNPHY(pi)) {
   2530		u8 gidx = (rxh->PhyRxStatus_2 & 0xFC00) >> 10;
   2531		struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
   2532
   2533		if (rssi > 127)
   2534			rssi -= 256;
   2535
   2536		rssi = rssi + lcnphy_gain_index_offset_for_pkt_rssi[gidx];
   2537		if ((rssi > -46) && (gidx > 18))
   2538			rssi = rssi + 7;
   2539
   2540		rssi = rssi + pi_lcn->lcnphy_pkteng_rssi_slope;
   2541
   2542		rssi = rssi + 2;
   2543
   2544	}
   2545
   2546	if (ISLCNPHY(pi)) {
   2547		if (rssi > 127)
   2548			rssi -= 256;
   2549	} else if (radioid == BCM2055_ID || radioid == BCM2056_ID
   2550		   || radioid == BCM2057_ID) {
   2551		rssi = wlc_phy_rssi_compute_nphy(pi, rxh);
   2552	}
   2553
   2554end:
   2555	return rssi;
   2556}
   2557
   2558void wlc_phy_freqtrack_start(struct brcms_phy_pub *pih)
   2559{
   2560	return;
   2561}
   2562
   2563void wlc_phy_freqtrack_end(struct brcms_phy_pub *pih)
   2564{
   2565	return;
   2566}
   2567
   2568void wlc_phy_set_deaf(struct brcms_phy_pub *ppi, bool user_flag)
   2569{
   2570	struct brcms_phy *pi;
   2571	pi = (struct brcms_phy *) ppi;
   2572
   2573	if (ISLCNPHY(pi))
   2574		wlc_lcnphy_deaf_mode(pi, true);
   2575	else if (ISNPHY(pi))
   2576		wlc_nphy_deaf_mode(pi, true);
   2577}
   2578
   2579void wlc_phy_watchdog(struct brcms_phy_pub *pih)
   2580{
   2581	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
   2582	bool delay_phy_cal = false;
   2583	pi->sh->now++;
   2584
   2585	if (!pi->watchdog_override)
   2586		return;
   2587
   2588	if (!(SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)))
   2589		wlc_phy_noise_sample_request((struct brcms_phy_pub *) pi,
   2590					     PHY_NOISE_SAMPLE_MON,
   2591					     CHSPEC_CHANNEL(pi->
   2592							    radio_chanspec));
   2593
   2594	if (pi->phynoise_state && (pi->sh->now - pi->phynoise_now) > 5)
   2595		pi->phynoise_state = 0;
   2596
   2597	if ((!pi->phycal_txpower) ||
   2598	    ((pi->sh->now - pi->phycal_txpower) >= pi->sh->fast_timer)) {
   2599
   2600		if (!SCAN_INPROG_PHY(pi) && wlc_phy_cal_txpower_recalc_sw(pi))
   2601			pi->phycal_txpower = pi->sh->now;
   2602	}
   2603
   2604	if ((SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)
   2605	     || ASSOC_INPROG_PHY(pi)))
   2606		return;
   2607
   2608	if (ISNPHY(pi) && !pi->disable_percal && !delay_phy_cal) {
   2609
   2610		if ((pi->nphy_perical != PHY_PERICAL_DISABLE) &&
   2611		    (pi->nphy_perical != PHY_PERICAL_MANUAL) &&
   2612		    ((pi->sh->now - pi->nphy_perical_last) >=
   2613		     pi->sh->glacial_timer))
   2614			wlc_phy_cal_perical((struct brcms_phy_pub *) pi,
   2615					    PHY_PERICAL_WATCHDOG);
   2616
   2617		wlc_phy_txpwr_papd_cal_nphy(pi);
   2618	}
   2619
   2620	if (ISLCNPHY(pi)) {
   2621		if (pi->phy_forcecal ||
   2622		    ((pi->sh->now - pi->phy_lastcal) >=
   2623		     pi->sh->glacial_timer)) {
   2624			if (!(SCAN_RM_IN_PROGRESS(pi) || ASSOC_INPROG_PHY(pi)))
   2625				wlc_lcnphy_calib_modes(
   2626					pi,
   2627					LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL);
   2628			if (!
   2629			    (SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)
   2630			     || ASSOC_INPROG_PHY(pi)
   2631			     || pi->carrier_suppr_disable
   2632			     || pi->disable_percal))
   2633				wlc_lcnphy_calib_modes(pi,
   2634						       PHY_PERICAL_WATCHDOG);
   2635		}
   2636	}
   2637}
   2638
   2639void wlc_phy_BSSinit(struct brcms_phy_pub *pih, bool bonlyap, int rssi)
   2640{
   2641	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
   2642	uint i;
   2643	uint k;
   2644
   2645	for (i = 0; i < MA_WINDOW_SZ; i++)
   2646		pi->sh->phy_noise_window[i] = (s8) (rssi & 0xff);
   2647	if (ISLCNPHY(pi)) {
   2648		for (i = 0; i < MA_WINDOW_SZ; i++)
   2649			pi->sh->phy_noise_window[i] =
   2650				PHY_NOISE_FIXED_VAL_LCNPHY;
   2651	}
   2652	pi->sh->phy_noise_index = 0;
   2653
   2654	for (i = 0; i < PHY_NOISE_WINDOW_SZ; i++) {
   2655		for (k = WL_ANT_IDX_1; k < WL_ANT_RX_MAX; k++)
   2656			pi->nphy_noise_win[k][i] = PHY_NOISE_FIXED_VAL_NPHY;
   2657	}
   2658	pi->nphy_noise_index = 0;
   2659}
   2660
   2661void
   2662wlc_phy_papd_decode_epsilon(u32 epsilon, s32 *eps_real, s32 *eps_imag)
   2663{
   2664	*eps_imag = (epsilon >> 13);
   2665	if (*eps_imag > 0xfff)
   2666		*eps_imag -= 0x2000;
   2667
   2668	*eps_real = (epsilon & 0x1fff);
   2669	if (*eps_real > 0xfff)
   2670		*eps_real -= 0x2000;
   2671}
   2672
   2673void wlc_phy_cal_perical_mphase_reset(struct brcms_phy *pi)
   2674{
   2675	wlapi_del_timer(pi->phycal_timer);
   2676
   2677	pi->cal_type_override = PHY_PERICAL_AUTO;
   2678	pi->mphase_cal_phase_id = MPHASE_CAL_STATE_IDLE;
   2679	pi->mphase_txcal_cmdidx = 0;
   2680}
   2681
   2682static void
   2683wlc_phy_cal_perical_mphase_schedule(struct brcms_phy *pi, uint delay)
   2684{
   2685
   2686	if ((pi->nphy_perical != PHY_PERICAL_MPHASE) &&
   2687	    (pi->nphy_perical != PHY_PERICAL_MANUAL))
   2688		return;
   2689
   2690	wlapi_del_timer(pi->phycal_timer);
   2691
   2692	pi->mphase_cal_phase_id = MPHASE_CAL_STATE_INIT;
   2693	wlapi_add_timer(pi->phycal_timer, delay, 0);
   2694}
   2695
   2696void wlc_phy_cal_perical(struct brcms_phy_pub *pih, u8 reason)
   2697{
   2698	s16 nphy_currtemp = 0;
   2699	s16 delta_temp = 0;
   2700	bool do_periodic_cal = true;
   2701	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
   2702
   2703	if (!ISNPHY(pi))
   2704		return;
   2705
   2706	if ((pi->nphy_perical == PHY_PERICAL_DISABLE) ||
   2707	    (pi->nphy_perical == PHY_PERICAL_MANUAL))
   2708		return;
   2709
   2710	switch (reason) {
   2711	case PHY_PERICAL_DRIVERUP:
   2712		break;
   2713
   2714	case PHY_PERICAL_PHYINIT:
   2715		if (pi->nphy_perical == PHY_PERICAL_MPHASE) {
   2716			if (PHY_PERICAL_MPHASE_PENDING(pi))
   2717				wlc_phy_cal_perical_mphase_reset(pi);
   2718
   2719			wlc_phy_cal_perical_mphase_schedule(
   2720				pi,
   2721				PHY_PERICAL_INIT_DELAY);
   2722		}
   2723		break;
   2724
   2725	case PHY_PERICAL_JOIN_BSS:
   2726	case PHY_PERICAL_START_IBSS:
   2727	case PHY_PERICAL_UP_BSS:
   2728		if ((pi->nphy_perical == PHY_PERICAL_MPHASE) &&
   2729		    PHY_PERICAL_MPHASE_PENDING(pi))
   2730			wlc_phy_cal_perical_mphase_reset(pi);
   2731
   2732		pi->first_cal_after_assoc = true;
   2733
   2734		pi->cal_type_override = PHY_PERICAL_FULL;
   2735
   2736		if (pi->phycal_tempdelta)
   2737			pi->nphy_lastcal_temp = wlc_phy_tempsense_nphy(pi);
   2738
   2739		wlc_phy_cal_perical_nphy_run(pi, PHY_PERICAL_FULL);
   2740		break;
   2741
   2742	case PHY_PERICAL_WATCHDOG:
   2743		if (pi->phycal_tempdelta) {
   2744			nphy_currtemp = wlc_phy_tempsense_nphy(pi);
   2745			delta_temp =
   2746				(nphy_currtemp > pi->nphy_lastcal_temp) ?
   2747				nphy_currtemp - pi->nphy_lastcal_temp :
   2748				pi->nphy_lastcal_temp - nphy_currtemp;
   2749
   2750			if ((delta_temp < (s16) pi->phycal_tempdelta) &&
   2751			    (pi->nphy_txiqlocal_chanspec ==
   2752			     pi->radio_chanspec))
   2753				do_periodic_cal = false;
   2754			else
   2755				pi->nphy_lastcal_temp = nphy_currtemp;
   2756		}
   2757
   2758		if (do_periodic_cal) {
   2759			if (pi->nphy_perical == PHY_PERICAL_MPHASE) {
   2760				if (!PHY_PERICAL_MPHASE_PENDING(pi))
   2761					wlc_phy_cal_perical_mphase_schedule(
   2762						pi,
   2763						PHY_PERICAL_WDOG_DELAY);
   2764			} else if (pi->nphy_perical == PHY_PERICAL_SPHASE)
   2765				wlc_phy_cal_perical_nphy_run(pi,
   2766							     PHY_PERICAL_AUTO);
   2767		}
   2768		break;
   2769	default:
   2770		break;
   2771	}
   2772}
   2773
   2774void wlc_phy_cal_perical_mphase_restart(struct brcms_phy *pi)
   2775{
   2776	pi->mphase_cal_phase_id = MPHASE_CAL_STATE_INIT;
   2777	pi->mphase_txcal_cmdidx = 0;
   2778}
   2779
   2780u8 wlc_phy_nbits(s32 value)
   2781{
   2782	s32 abs_val;
   2783	u8 nbits = 0;
   2784
   2785	abs_val = abs(value);
   2786	while ((abs_val >> nbits) > 0)
   2787		nbits++;
   2788
   2789	return nbits;
   2790}
   2791
   2792void wlc_phy_stf_chain_init(struct brcms_phy_pub *pih, u8 txchain, u8 rxchain)
   2793{
   2794	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
   2795
   2796	pi->sh->hw_phytxchain = txchain;
   2797	pi->sh->hw_phyrxchain = rxchain;
   2798	pi->sh->phytxchain = txchain;
   2799	pi->sh->phyrxchain = rxchain;
   2800	pi->pubpi.phy_corenum = (u8)hweight8(pi->sh->phyrxchain);
   2801}
   2802
   2803void wlc_phy_stf_chain_set(struct brcms_phy_pub *pih, u8 txchain, u8 rxchain)
   2804{
   2805	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
   2806
   2807	pi->sh->phytxchain = txchain;
   2808
   2809	if (ISNPHY(pi))
   2810		wlc_phy_rxcore_setstate_nphy(pih, rxchain);
   2811
   2812	pi->pubpi.phy_corenum = (u8)hweight8(pi->sh->phyrxchain);
   2813}
   2814
   2815void wlc_phy_stf_chain_get(struct brcms_phy_pub *pih, u8 *txchain, u8 *rxchain)
   2816{
   2817	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
   2818
   2819	*txchain = pi->sh->phytxchain;
   2820	*rxchain = pi->sh->phyrxchain;
   2821}
   2822
   2823u8 wlc_phy_stf_chain_active_get(struct brcms_phy_pub *pih)
   2824{
   2825	s16 nphy_currtemp;
   2826	u8 active_bitmap;
   2827	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
   2828
   2829	active_bitmap = (pi->phy_txcore_heatedup) ? 0x31 : 0x33;
   2830
   2831	if (!pi->watchdog_override)
   2832		return active_bitmap;
   2833
   2834	if (NREV_GE(pi->pubpi.phy_rev, 6)) {
   2835		wlapi_suspend_mac_and_wait(pi->sh->physhim);
   2836		nphy_currtemp = wlc_phy_tempsense_nphy(pi);
   2837		wlapi_enable_mac(pi->sh->physhim);
   2838
   2839		if (!pi->phy_txcore_heatedup) {
   2840			if (nphy_currtemp >= pi->phy_txcore_disable_temp) {
   2841				active_bitmap &= 0xFD;
   2842				pi->phy_txcore_heatedup = true;
   2843			}
   2844		} else {
   2845			if (nphy_currtemp <= pi->phy_txcore_enable_temp) {
   2846				active_bitmap |= 0x2;
   2847				pi->phy_txcore_heatedup = false;
   2848			}
   2849		}
   2850	}
   2851
   2852	return active_bitmap;
   2853}
   2854
   2855s8 wlc_phy_stf_ssmode_get(struct brcms_phy_pub *pih, u16 chanspec)
   2856{
   2857	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
   2858	u8 siso_mcs_id, cdd_mcs_id;
   2859
   2860	siso_mcs_id =
   2861		(CHSPEC_IS40(chanspec)) ? TXP_FIRST_MCS_40_SISO :
   2862		TXP_FIRST_MCS_20_SISO;
   2863	cdd_mcs_id =
   2864		(CHSPEC_IS40(chanspec)) ? TXP_FIRST_MCS_40_CDD :
   2865		TXP_FIRST_MCS_20_CDD;
   2866
   2867	if (pi->tx_power_target[siso_mcs_id] >
   2868	    (pi->tx_power_target[cdd_mcs_id] + 12))
   2869		return PHY_TXC1_MODE_SISO;
   2870	else
   2871		return PHY_TXC1_MODE_CDD;
   2872}
   2873
   2874const u8 *wlc_phy_get_ofdm_rate_lookup(void)
   2875{
   2876	return ofdm_rate_lookup;
   2877}
   2878
   2879void wlc_lcnphy_epa_switch(struct brcms_phy *pi, bool mode)
   2880{
   2881	if ((pi->sh->chip == BCMA_CHIP_ID_BCM4313) &&
   2882	    (pi->sh->boardflags & BFL_FEM)) {
   2883		if (mode) {
   2884			u16 txant = 0;
   2885			txant = wlapi_bmac_get_txant(pi->sh->physhim);
   2886			if (txant == 1) {
   2887				mod_phy_reg(pi, 0x44d, (0x1 << 2), (1) << 2);
   2888
   2889				mod_phy_reg(pi, 0x44c, (0x1 << 2), (1) << 2);
   2890
   2891			}
   2892
   2893			bcma_chipco_gpio_control(&pi->d11core->bus->drv_cc,
   2894						 0x0, 0x0);
   2895			bcma_chipco_gpio_out(&pi->d11core->bus->drv_cc,
   2896					     ~0x40, 0x40);
   2897			bcma_chipco_gpio_outen(&pi->d11core->bus->drv_cc,
   2898					       ~0x40, 0x40);
   2899		} else {
   2900			mod_phy_reg(pi, 0x44c, (0x1 << 2), (0) << 2);
   2901
   2902			mod_phy_reg(pi, 0x44d, (0x1 << 2), (0) << 2);
   2903
   2904			bcma_chipco_gpio_out(&pi->d11core->bus->drv_cc,
   2905					     ~0x40, 0x00);
   2906			bcma_chipco_gpio_outen(&pi->d11core->bus->drv_cc,
   2907					       ~0x40, 0x00);
   2908			bcma_chipco_gpio_control(&pi->d11core->bus->drv_cc,
   2909						 0x0, 0x40);
   2910		}
   2911	}
   2912}
   2913
   2914void wlc_phy_ldpc_override_set(struct brcms_phy_pub *ppi, bool ldpc)
   2915{
   2916	return;
   2917}
   2918
   2919void
   2920wlc_phy_get_pwrdet_offsets(struct brcms_phy *pi, s8 *cckoffset, s8 *ofdmoffset)
   2921{
   2922	*cckoffset = 0;
   2923	*ofdmoffset = 0;
   2924}
   2925
   2926s8 wlc_phy_upd_rssi_offset(struct brcms_phy *pi, s8 rssi, u16 chanspec)
   2927{
   2928
   2929	return rssi;
   2930}
   2931
   2932bool wlc_phy_txpower_ipa_ison(struct brcms_phy_pub *ppi)
   2933{
   2934	struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
   2935
   2936	if (ISNPHY(pi))
   2937		return wlc_phy_n_txpower_ipa_ison(pi);
   2938	else
   2939		return false;
   2940}