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