File Index
Files and directories
Sign in
FILE

phy_cmn.c

File preview with syntax highlighting.

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