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