This source file includes following definitions.
- wlc_phyreg_enter
- wlc_phyreg_exit
- wlc_radioreg_enter
- wlc_radioreg_exit
- read_radio_reg
- write_radio_reg
- read_radio_id
- and_radio_reg
- or_radio_reg
- xor_radio_reg
- mod_radio_reg
- write_phy_channel_reg
- read_phy_reg
- write_phy_reg
- and_phy_reg
- or_phy_reg
- mod_phy_reg
- wlc_set_phy_uninitted
- wlc_phy_shared_attach
- wlc_phy_timercb_phycal
- wlc_phy_get_radio_ver
- wlc_phy_attach
- wlc_phy_detach
- wlc_phy_get_phyversion
- wlc_phy_get_encore
- wlc_phy_get_coreflags
- wlc_phy_anacore
- wlc_phy_clk_bwbits
- wlc_phy_por_inform
- wlc_phy_edcrs_lock
- wlc_phy_initcal_enable
- wlc_phy_hw_clk_state_upd
- wlc_phy_hw_state_upd
- wlc_phy_init
- wlc_phy_cal_init
- wlc_phy_down
- wlc_phy_table_addr
- wlc_phy_table_data_write
- wlc_phy_write_table
- wlc_phy_read_table
- wlc_phy_init_radio_regs_allbands
- wlc_phy_init_radio_regs
- wlc_phy_do_dummy_tx
- wlc_phy_hold_upd
- wlc_phy_mute_upd
- wlc_phy_clear_tssi
- wlc_phy_cal_txpower_recalc_sw
- wlc_phy_switch_radio
- wlc_phy_bw_state_get
- wlc_phy_bw_state_set
- wlc_phy_chanspec_radio_set
- wlc_phy_chanspec_get
- wlc_phy_chanspec_set
- wlc_phy_chanspec_freq2bandrange_lpssn
- wlc_phy_chanspec_bandrange_get
- wlc_phy_chanspec_ch14_widefilter_set
- wlc_phy_channel2freq
- wlc_phy_chanspec_band_validch
- wlc_phy_chanspec_band_firstch
- wlc_phy_txpower_get
- wlc_phy_txpower_target_set
- wlc_phy_txpower_set
- wlc_phy_txpower_sromlimit
- wlc_phy_txpower_sromlimit_max_get
- wlc_phy_txpower_boardlimit_band
- wlc_phy_txpower_get_target_min
- wlc_phy_txpower_get_target_max
- wlc_phy_env_measure_vbat
- wlc_phy_env_measure_temperature
- wlc_phy_upd_env_txpwr_rate_limits
- wlc_user_txpwr_antport_to_rfport
- wlc_phy_txpower_recalc_target
- wlc_phy_txpower_reg_limit_calc
- wlc_phy_txpwr_percent_set
- wlc_phy_machwcap_set
- wlc_phy_runbist_config
- wlc_phy_txpower_limit_set
- wlc_phy_ofdm_rateset_war
- wlc_phy_bf_preempt_enable
- wlc_phy_txpower_update_shm
- wlc_phy_txpower_hw_ctrl_get
- wlc_phy_txpower_hw_ctrl_set
- wlc_phy_txpower_ipa_upd
- wlc_phy_txpower_est_power_nphy
- wlc_phy_txpower_get_current
- wlc_phy_antsel_type_set
- wlc_phy_test_ison
- wlc_phy_ant_rxdiv_set
- wlc_phy_noise_calc_phy
- wlc_phy_noise_cb
- wlc_phy_noise_read_shmem
- wlc_phy_noise_sample_intr
- wlc_phy_noise_sample_request
- wlc_phy_noise_sample_request_external
- wlc_phy_compute_dB
- wlc_phy_rssi_compute
- wlc_phy_freqtrack_start
- wlc_phy_freqtrack_end
- wlc_phy_set_deaf
- wlc_phy_watchdog
- wlc_phy_BSSinit
- wlc_phy_papd_decode_epsilon
- wlc_phy_cal_perical_mphase_reset
- wlc_phy_cal_perical_mphase_schedule
- wlc_phy_cal_perical
- wlc_phy_cal_perical_mphase_restart
- wlc_phy_nbits
- wlc_phy_stf_chain_init
- wlc_phy_stf_chain_set
- wlc_phy_stf_chain_get
- wlc_phy_stf_chain_active_get
- wlc_phy_stf_ssmode_get
- wlc_phy_get_ofdm_rate_lookup
- wlc_lcnphy_epa_switch
- wlc_phy_ldpc_override_set
- wlc_phy_get_pwrdet_offsets
- wlc_phy_upd_rssi_offset
- wlc_phy_txpower_ipa_ison
1
2
3
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
31 #define MUX(pred, true, false) ((pred) ? (true) : (false))
32
33
34 #define MODINC(x, bound) MUX((x) == (bound) - 1, 0, (x) + 1)
35
36
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
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
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
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
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
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
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
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
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
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
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
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
266 void write_phy_channel_reg(struct brcms_phy *pi, uint val)
267 {
268 bcma_write16(pi->d11core, D11REGOFFS(phychannel), val);
269 }
270
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
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
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
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
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
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
354 struct shared_phy *wlc_phy_shared_attach(struct shared_phy_params *shp)
355 {
356 struct shared_phy *sh;
357
358 sh = kzalloc(sizeof(struct shared_phy), GFP_ATOMIC);
359 if (sh == NULL)
360 return NULL;
361
362 sh->physhim = shp->physhim;
363 sh->unit = shp->unit;
364 sh->corerev = shp->corerev;
365
366 sh->vid = shp->vid;
367 sh->did = shp->did;
368 sh->chip = shp->chip;
369 sh->chiprev = shp->chiprev;
370 sh->chippkg = shp->chippkg;
371 sh->sromrev = shp->sromrev;
372 sh->boardtype = shp->boardtype;
373 sh->boardrev = shp->boardrev;
374 sh->boardflags = shp->boardflags;
375 sh->boardflags2 = shp->boardflags2;
376
377 sh->fast_timer = PHY_SW_TIMER_FAST;
378 sh->slow_timer = PHY_SW_TIMER_SLOW;
379 sh->glacial_timer = PHY_SW_TIMER_GLACIAL;
380
381 sh->rssi_mode = RSSI_ANT_MERGE_MAX;
382
383 return sh;
384 }
385
386 static void wlc_phy_timercb_phycal(struct brcms_phy *pi)
387 {
388 uint delay = 5;
389
390 if (PHY_PERICAL_MPHASE_PENDING(pi)) {
391 if (!pi->sh->up) {
392 wlc_phy_cal_perical_mphase_reset(pi);
393 return;
394 }
395
396 if (SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)) {
397
398 delay = 1000;
399 wlc_phy_cal_perical_mphase_restart(pi);
400 } else
401 wlc_phy_cal_perical_nphy_run(pi, PHY_PERICAL_AUTO);
402 wlapi_add_timer(pi->phycal_timer, delay, 0);
403 return;
404 }
405
406 }
407
408 static u32 wlc_phy_get_radio_ver(struct brcms_phy *pi)
409 {
410 u32 ver;
411
412 ver = read_radio_id(pi);
413
414 return ver;
415 }
416
417 struct brcms_phy_pub *
418 wlc_phy_attach(struct shared_phy *sh, struct bcma_device *d11core,
419 int bandtype, struct wiphy *wiphy)
420 {
421 struct brcms_phy *pi;
422 u32 sflags = 0;
423 uint phyversion;
424 u32 idcode;
425 int i;
426
427 if (D11REV_IS(sh->corerev, 4))
428 sflags = SISF_2G_PHY | SISF_5G_PHY;
429 else
430 sflags = bcma_aread32(d11core, BCMA_IOST);
431
432 if (bandtype == BRCM_BAND_5G) {
433 if ((sflags & (SISF_5G_PHY | SISF_DB_PHY)) == 0)
434 return NULL;
435 }
436
437 pi = sh->phy_head;
438 if ((sflags & SISF_DB_PHY) && pi) {
439 wlapi_bmac_corereset(pi->sh->physhim, pi->pubpi.coreflags);
440 pi->refcnt++;
441 return &pi->pubpi_ro;
442 }
443
444 pi = kzalloc(sizeof(struct brcms_phy), GFP_ATOMIC);
445 if (pi == NULL)
446 return NULL;
447 pi->wiphy = wiphy;
448 pi->d11core = d11core;
449 pi->sh = sh;
450 pi->phy_init_por = true;
451 pi->phy_wreg_limit = PHY_WREG_LIMIT;
452
453 pi->txpwr_percent = 100;
454
455 pi->do_initcal = true;
456
457 pi->phycal_tempdelta = 0;
458
459 if (bandtype == BRCM_BAND_2G && (sflags & SISF_2G_PHY))
460 pi->pubpi.coreflags = SICF_GMODE;
461
462 wlapi_bmac_corereset(pi->sh->physhim, pi->pubpi.coreflags);
463 phyversion = bcma_read16(pi->d11core, D11REGOFFS(phyversion));
464
465 pi->pubpi.phy_type = PHY_TYPE(phyversion);
466 pi->pubpi.phy_rev = phyversion & PV_PV_MASK;
467
468 if (pi->pubpi.phy_type == PHY_TYPE_LCNXN) {
469 pi->pubpi.phy_type = PHY_TYPE_N;
470 pi->pubpi.phy_rev += LCNXN_BASEREV;
471 }
472 pi->pubpi.phy_corenum = PHY_CORE_NUM_2;
473 pi->pubpi.ana_rev = (phyversion & PV_AV_MASK) >> PV_AV_SHIFT;
474
475 if (pi->pubpi.phy_type != PHY_TYPE_N &&
476 pi->pubpi.phy_type != PHY_TYPE_LCN)
477 goto err;
478
479 if (bandtype == BRCM_BAND_5G) {
480 if (!ISNPHY(pi))
481 goto err;
482 } else if (!ISNPHY(pi) && !ISLCNPHY(pi)) {
483 goto err;
484 }
485
486 wlc_phy_anacore((struct brcms_phy_pub *) pi, ON);
487
488 idcode = wlc_phy_get_radio_ver(pi);
489 pi->pubpi.radioid =
490 (idcode & IDCODE_ID_MASK) >> IDCODE_ID_SHIFT;
491 pi->pubpi.radiorev =
492 (idcode & IDCODE_REV_MASK) >> IDCODE_REV_SHIFT;
493 pi->pubpi.radiover =
494 (idcode & IDCODE_VER_MASK) >> IDCODE_VER_SHIFT;
495 if (!VALID_RADIO(pi, pi->pubpi.radioid))
496 goto err;
497
498 wlc_phy_switch_radio((struct brcms_phy_pub *) pi, OFF);
499
500 wlc_set_phy_uninitted(pi);
501
502 pi->bw = WL_CHANSPEC_BW_20;
503 pi->radio_chanspec = (bandtype == BRCM_BAND_2G) ?
504 ch20mhz_chspec(1) : ch20mhz_chspec(36);
505
506 pi->rxiq_samps = PHY_NOISE_SAMPLE_LOG_NUM_NPHY;
507 pi->rxiq_antsel = ANT_RX_DIV_DEF;
508
509 pi->watchdog_override = true;
510
511 pi->cal_type_override = PHY_PERICAL_AUTO;
512
513 pi->nphy_saved_noisevars.bufcount = 0;
514
515 if (ISNPHY(pi))
516 pi->min_txpower = PHY_TXPWR_MIN_NPHY;
517 else
518 pi->min_txpower = PHY_TXPWR_MIN;
519
520 pi->sh->phyrxchain = 0x3;
521
522 pi->rx2tx_biasentry = -1;
523
524 pi->phy_txcore_disable_temp = PHY_CHAIN_TX_DISABLE_TEMP;
525 pi->phy_txcore_enable_temp =
526 PHY_CHAIN_TX_DISABLE_TEMP - PHY_HYSTERESIS_DELTATEMP;
527 pi->phy_tempsense_offset = 0;
528 pi->phy_txcore_heatedup = false;
529
530 pi->nphy_lastcal_temp = -50;
531
532 pi->phynoise_polling = true;
533 if (ISNPHY(pi) || ISLCNPHY(pi))
534 pi->phynoise_polling = false;
535
536 for (i = 0; i < TXP_NUM_RATES; i++) {
537 pi->txpwr_limit[i] = BRCMS_TXPWR_MAX;
538 pi->txpwr_env_limit[i] = BRCMS_TXPWR_MAX;
539 pi->tx_user_target[i] = BRCMS_TXPWR_MAX;
540 }
541
542 pi->radiopwr_override = RADIOPWR_OVERRIDE_DEF;
543
544 pi->user_txpwr_at_rfport = false;
545
546 if (ISNPHY(pi)) {
547
548 pi->phycal_timer = wlapi_init_timer(pi->sh->physhim,
549 wlc_phy_timercb_phycal,
550 pi, "phycal");
551 if (!pi->phycal_timer)
552 goto err;
553
554 if (!wlc_phy_attach_nphy(pi))
555 goto err;
556
557 } else if (ISLCNPHY(pi)) {
558 if (!wlc_phy_attach_lcnphy(pi))
559 goto err;
560
561 }
562
563 pi->refcnt++;
564 pi->next = pi->sh->phy_head;
565 sh->phy_head = pi;
566
567 memcpy(&pi->pubpi_ro, &pi->pubpi, sizeof(struct brcms_phy_pub));
568
569 return &pi->pubpi_ro;
570
571 err:
572 kfree(pi);
573 return NULL;
574 }
575
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
1100 static bool wlc_phy_cal_txpower_recalc_sw(struct brcms_phy *pi)
1101 {
1102 return false;
1103 }
1104
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
1513 static void wlc_phy_upd_env_txpwr_rate_limits(struct brcms_phy *pi, u32 band)
1514 {
1515 u8 i;
1516 s8 temp, vbat;
1517
1518 for (i = 0; i < TXP_NUM_RATES; i++)
1519 pi->txpwr_env_limit[i] = BRCMS_TXPWR_MAX;
1520
1521 vbat = wlc_phy_env_measure_vbat(pi);
1522 temp = wlc_phy_env_measure_temperature(pi);
1523
1524 }
1525
1526 static s8
1527 wlc_user_txpwr_antport_to_rfport(struct brcms_phy *pi, uint chan, u32 band,
1528 u8 rate)
1529 {
1530 return 0;
1531 }
1532
1533 void wlc_phy_txpower_recalc_target(struct brcms_phy *pi)
1534 {
1535 u8 maxtxpwr, mintxpwr, rate, pactrl;
1536 uint target_chan;
1537 u8 tx_pwr_target[TXP_NUM_RATES];
1538 u8 tx_pwr_max = 0;
1539 u8 tx_pwr_min = 255;
1540 u8 tx_pwr_max_rate_ind = 0;
1541 u8 max_num_rate;
1542 u8 start_rate = 0;
1543 u16 chspec;
1544 u32 band = CHSPEC2BAND(pi->radio_chanspec);
1545 void (*txpwr_recalc_fn)(struct brcms_phy *) = NULL;
1546
1547 chspec = pi->radio_chanspec;
1548 if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_NONE)
1549 target_chan = CHSPEC_CHANNEL(chspec);
1550 else if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_UPPER)
1551 target_chan = upper_20_sb(CHSPEC_CHANNEL(chspec));
1552 else
1553 target_chan = lower_20_sb(CHSPEC_CHANNEL(chspec));
1554
1555 pactrl = 0;
1556 if (ISLCNPHY(pi)) {
1557 u32 offset_mcs, i;
1558
1559 if (CHSPEC_IS40(pi->radio_chanspec)) {
1560 offset_mcs = pi->mcs40_po;
1561 for (i = TXP_FIRST_SISO_MCS_20;
1562 i <= TXP_LAST_SISO_MCS_20; i++) {
1563 pi->tx_srom_max_rate_2g[i - 8] =
1564 pi->tx_srom_max_2g -
1565 ((offset_mcs & 0xf) * 2);
1566 offset_mcs >>= 4;
1567 }
1568 } else {
1569 offset_mcs = pi->mcs20_po;
1570 for (i = TXP_FIRST_SISO_MCS_20;
1571 i <= TXP_LAST_SISO_MCS_20; i++) {
1572 pi->tx_srom_max_rate_2g[i - 8] =
1573 pi->tx_srom_max_2g -
1574 ((offset_mcs & 0xf) * 2);
1575 offset_mcs >>= 4;
1576 }
1577 }
1578 }
1579
1580 max_num_rate = ((ISNPHY(pi)) ? (TXP_NUM_RATES) :
1581 ((ISLCNPHY(pi)) ?
1582 (TXP_LAST_SISO_MCS_20 + 1) : (TXP_LAST_OFDM + 1)));
1583
1584 wlc_phy_upd_env_txpwr_rate_limits(pi, band);
1585
1586 for (rate = start_rate; rate < max_num_rate; rate++) {
1587
1588 tx_pwr_target[rate] = pi->tx_user_target[rate];
1589
1590 if (pi->user_txpwr_at_rfport)
1591 tx_pwr_target[rate] +=
1592 wlc_user_txpwr_antport_to_rfport(pi,
1593 target_chan,
1594 band,
1595 rate);
1596
1597 wlc_phy_txpower_sromlimit((struct brcms_phy_pub *) pi,
1598 target_chan,
1599 &mintxpwr, &maxtxpwr, rate);
1600
1601 maxtxpwr = min(maxtxpwr, pi->txpwr_limit[rate]);
1602
1603 maxtxpwr = (maxtxpwr > pactrl) ? (maxtxpwr - pactrl) : 0;
1604
1605 maxtxpwr = (maxtxpwr > 6) ? (maxtxpwr - 6) : 0;
1606
1607 maxtxpwr = min(maxtxpwr, tx_pwr_target[rate]);
1608
1609 if (pi->txpwr_percent <= 100)
1610 maxtxpwr = (maxtxpwr * pi->txpwr_percent) / 100;
1611
1612 tx_pwr_target[rate] = max(maxtxpwr, mintxpwr);
1613
1614 tx_pwr_target[rate] =
1615 min(tx_pwr_target[rate], pi->txpwr_env_limit[rate]);
1616
1617 if (tx_pwr_target[rate] > tx_pwr_max)
1618 tx_pwr_max_rate_ind = rate;
1619
1620 tx_pwr_max = max(tx_pwr_max, tx_pwr_target[rate]);
1621 tx_pwr_min = min(tx_pwr_min, tx_pwr_target[rate]);
1622 }
1623
1624 memset(pi->tx_power_offset, 0, sizeof(pi->tx_power_offset));
1625 pi->tx_power_max = tx_pwr_max;
1626 pi->tx_power_min = tx_pwr_min;
1627 pi->tx_power_max_rate_ind = tx_pwr_max_rate_ind;
1628 for (rate = 0; rate < max_num_rate; rate++) {
1629
1630 pi->tx_power_target[rate] = tx_pwr_target[rate];
1631
1632 if (!pi->hwpwrctrl || ISNPHY(pi))
1633 pi->tx_power_offset[rate] =
1634 pi->tx_power_max - pi->tx_power_target[rate];
1635 else
1636 pi->tx_power_offset[rate] =
1637 pi->tx_power_target[rate] - pi->tx_power_min;
1638 }
1639
1640 txpwr_recalc_fn = pi->pi_fptr.txpwrrecalc;
1641 if (txpwr_recalc_fn)
1642 (*txpwr_recalc_fn)(pi);
1643 }
1644
1645 static void
1646 wlc_phy_txpower_reg_limit_calc(struct brcms_phy *pi, struct txpwr_limits *txpwr,
1647 u16 chanspec)
1648 {
1649 u8 tmp_txpwr_limit[2 * BRCMS_NUM_RATES_OFDM];
1650 u8 *txpwr_ptr1 = NULL, *txpwr_ptr2 = NULL;
1651 int rate_start_index = 0, rate1, rate2, k;
1652
1653 for (rate1 = WL_TX_POWER_CCK_FIRST, rate2 = 0;
1654 rate2 < WL_TX_POWER_CCK_NUM; rate1++, rate2++)
1655 pi->txpwr_limit[rate1] = txpwr->cck[rate2];
1656
1657 for (rate1 = WL_TX_POWER_OFDM_FIRST, rate2 = 0;
1658 rate2 < WL_TX_POWER_OFDM_NUM; rate1++, rate2++)
1659 pi->txpwr_limit[rate1] = txpwr->ofdm[rate2];
1660
1661 if (ISNPHY(pi)) {
1662
1663 for (k = 0; k < 4; k++) {
1664 switch (k) {
1665 case 0:
1666
1667 txpwr_ptr1 = txpwr->mcs_20_siso;
1668 txpwr_ptr2 = txpwr->ofdm;
1669 rate_start_index = WL_TX_POWER_OFDM_FIRST;
1670 break;
1671 case 1:
1672
1673 txpwr_ptr1 = txpwr->mcs_20_cdd;
1674 txpwr_ptr2 = txpwr->ofdm_cdd;
1675 rate_start_index = WL_TX_POWER_OFDM20_CDD_FIRST;
1676 break;
1677 case 2:
1678
1679 txpwr_ptr1 = txpwr->mcs_40_siso;
1680 txpwr_ptr2 = txpwr->ofdm_40_siso;
1681 rate_start_index =
1682 WL_TX_POWER_OFDM40_SISO_FIRST;
1683 break;
1684 case 3:
1685
1686 txpwr_ptr1 = txpwr->mcs_40_cdd;
1687 txpwr_ptr2 = txpwr->ofdm_40_cdd;
1688 rate_start_index = WL_TX_POWER_OFDM40_CDD_FIRST;
1689 break;
1690 }
1691
1692 for (rate2 = 0; rate2 < BRCMS_NUM_RATES_OFDM;
1693 rate2++) {
1694 tmp_txpwr_limit[rate2] = 0;
1695 tmp_txpwr_limit[BRCMS_NUM_RATES_OFDM + rate2] =
1696 txpwr_ptr1[rate2];
1697 }
1698 wlc_phy_mcs_to_ofdm_powers_nphy(
1699 tmp_txpwr_limit, 0,
1700 BRCMS_NUM_RATES_OFDM -
1701 1, BRCMS_NUM_RATES_OFDM);
1702 for (rate1 = rate_start_index, rate2 = 0;
1703 rate2 < BRCMS_NUM_RATES_OFDM; rate1++, rate2++)
1704 pi->txpwr_limit[rate1] =
1705 min(txpwr_ptr2[rate2],
1706 tmp_txpwr_limit[rate2]);
1707 }
1708
1709 for (k = 0; k < 4; k++) {
1710 switch (k) {
1711 case 0:
1712
1713 txpwr_ptr1 = txpwr->ofdm;
1714 txpwr_ptr2 = txpwr->mcs_20_siso;
1715 rate_start_index = WL_TX_POWER_MCS20_SISO_FIRST;
1716 break;
1717 case 1:
1718
1719 txpwr_ptr1 = txpwr->ofdm_cdd;
1720 txpwr_ptr2 = txpwr->mcs_20_cdd;
1721 rate_start_index = WL_TX_POWER_MCS20_CDD_FIRST;
1722 break;
1723 case 2:
1724
1725 txpwr_ptr1 = txpwr->ofdm_40_siso;
1726 txpwr_ptr2 = txpwr->mcs_40_siso;
1727 rate_start_index = WL_TX_POWER_MCS40_SISO_FIRST;
1728 break;
1729 case 3:
1730
1731 txpwr_ptr1 = txpwr->ofdm_40_cdd;
1732 txpwr_ptr2 = txpwr->mcs_40_cdd;
1733 rate_start_index = WL_TX_POWER_MCS40_CDD_FIRST;
1734 break;
1735 }
1736 for (rate2 = 0; rate2 < BRCMS_NUM_RATES_OFDM;
1737 rate2++) {
1738 tmp_txpwr_limit[rate2] = 0;
1739 tmp_txpwr_limit[BRCMS_NUM_RATES_OFDM + rate2] =
1740 txpwr_ptr1[rate2];
1741 }
1742 wlc_phy_ofdm_to_mcs_powers_nphy(
1743 tmp_txpwr_limit, 0,
1744 BRCMS_NUM_RATES_OFDM -
1745 1, BRCMS_NUM_RATES_OFDM);
1746 for (rate1 = rate_start_index, rate2 = 0;
1747 rate2 < BRCMS_NUM_RATES_MCS_1_STREAM;
1748 rate1++, rate2++)
1749 pi->txpwr_limit[rate1] =
1750 min(txpwr_ptr2[rate2],
1751 tmp_txpwr_limit[rate2]);
1752 }
1753
1754 for (k = 0; k < 2; k++) {
1755 switch (k) {
1756 case 0:
1757
1758 rate_start_index = WL_TX_POWER_MCS20_STBC_FIRST;
1759 txpwr_ptr1 = txpwr->mcs_20_stbc;
1760 break;
1761 case 1:
1762
1763 rate_start_index = WL_TX_POWER_MCS40_STBC_FIRST;
1764 txpwr_ptr1 = txpwr->mcs_40_stbc;
1765 break;
1766 }
1767 for (rate1 = rate_start_index, rate2 = 0;
1768 rate2 < BRCMS_NUM_RATES_MCS_1_STREAM;
1769 rate1++, rate2++)
1770 pi->txpwr_limit[rate1] = txpwr_ptr1[rate2];
1771 }
1772
1773 for (k = 0; k < 2; k++) {
1774 switch (k) {
1775 case 0:
1776
1777 rate_start_index = WL_TX_POWER_MCS20_SDM_FIRST;
1778 txpwr_ptr1 = txpwr->mcs_20_mimo;
1779 break;
1780 case 1:
1781
1782 rate_start_index = WL_TX_POWER_MCS40_SDM_FIRST;
1783 txpwr_ptr1 = txpwr->mcs_40_mimo;
1784 break;
1785 }
1786 for (rate1 = rate_start_index, rate2 = 0;
1787 rate2 < BRCMS_NUM_RATES_MCS_2_STREAM;
1788 rate1++, rate2++)
1789 pi->txpwr_limit[rate1] = txpwr_ptr1[rate2];
1790 }
1791
1792 pi->txpwr_limit[WL_TX_POWER_MCS_32] = txpwr->mcs32;
1793
1794 pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST] =
1795 min(pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST],
1796 pi->txpwr_limit[WL_TX_POWER_MCS_32]);
1797 pi->txpwr_limit[WL_TX_POWER_MCS_32] =
1798 pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST];
1799 }
1800 }
1801
1802 void wlc_phy_txpwr_percent_set(struct brcms_phy_pub *ppi, u8 txpwr_percent)
1803 {
1804 struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
1805
1806 pi->txpwr_percent = txpwr_percent;
1807 }
1808
1809 void wlc_phy_machwcap_set(struct brcms_phy_pub *ppi, u32 machwcap)
1810 {
1811 struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
1812
1813 pi->sh->machwcap = machwcap;
1814 }
1815
1816 void wlc_phy_runbist_config(struct brcms_phy_pub *ppi, bool start_end)
1817 {
1818 struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
1819 u16 rxc;
1820 rxc = 0;
1821
1822 if (start_end == ON) {
1823 if (!ISNPHY(pi))
1824 return;
1825
1826 if (NREV_IS(pi->pubpi.phy_rev, 3)
1827 || NREV_IS(pi->pubpi.phy_rev, 4)) {
1828 bcma_wflush16(pi->d11core, D11REGOFFS(phyregaddr),
1829 0xa0);
1830 bcma_set16(pi->d11core, D11REGOFFS(phyregdata),
1831 0x1 << 15);
1832 }
1833 } else {
1834 if (NREV_IS(pi->pubpi.phy_rev, 3)
1835 || NREV_IS(pi->pubpi.phy_rev, 4)) {
1836 bcma_wflush16(pi->d11core, D11REGOFFS(phyregaddr),
1837 0xa0);
1838 bcma_write16(pi->d11core, D11REGOFFS(phyregdata), rxc);
1839 }
1840
1841 wlc_phy_por_inform(ppi);
1842 }
1843 }
1844
1845 void
1846 wlc_phy_txpower_limit_set(struct brcms_phy_pub *ppi, struct txpwr_limits *txpwr,
1847 u16 chanspec)
1848 {
1849 struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
1850
1851 wlc_phy_txpower_reg_limit_calc(pi, txpwr, chanspec);
1852
1853 if (ISLCNPHY(pi)) {
1854 int i, j;
1855 for (i = TXP_FIRST_OFDM_20_CDD, j = 0;
1856 j < BRCMS_NUM_RATES_MCS_1_STREAM; i++, j++) {
1857 if (txpwr->mcs_20_siso[j])
1858 pi->txpwr_limit[i] = txpwr->mcs_20_siso[j];
1859 else
1860 pi->txpwr_limit[i] = txpwr->ofdm[j];
1861 }
1862 }
1863
1864 wlapi_suspend_mac_and_wait(pi->sh->physhim);
1865
1866 wlc_phy_txpower_recalc_target(pi);
1867 wlc_phy_cal_txpower_recalc_sw(pi);
1868 wlapi_enable_mac(pi->sh->physhim);
1869 }
1870
1871 void wlc_phy_ofdm_rateset_war(struct brcms_phy_pub *pih, bool war)
1872 {
1873 struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
1874
1875 pi->ofdm_rateset_war = war;
1876 }
1877
1878 void wlc_phy_bf_preempt_enable(struct brcms_phy_pub *pih, bool bf_preempt)
1879 {
1880 struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
1881
1882 pi->bf_preempt_4306 = bf_preempt;
1883 }
1884
1885 void wlc_phy_txpower_update_shm(struct brcms_phy *pi)
1886 {
1887 int j;
1888 if (ISNPHY(pi))
1889 return;
1890
1891 if (!pi->sh->clk)
1892 return;
1893
1894 if (pi->hwpwrctrl) {
1895 u16 offset;
1896
1897 wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_MAX, 63);
1898 wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_N,
1899 1 << NUM_TSSI_FRAMES);
1900
1901 wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_TARGET,
1902 pi->tx_power_min << NUM_TSSI_FRAMES);
1903
1904 wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_CUR,
1905 pi->hwpwr_txcur);
1906
1907 for (j = TXP_FIRST_OFDM; j <= TXP_LAST_OFDM; j++) {
1908 static const u8 ucode_ofdm_rates[] = {
1909 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c
1910 };
1911 offset = wlapi_bmac_rate_shm_offset(
1912 pi->sh->physhim,
1913 ucode_ofdm_rates[j - TXP_FIRST_OFDM]);
1914 wlapi_bmac_write_shm(pi->sh->physhim, offset + 6,
1915 pi->tx_power_offset[j]);
1916 wlapi_bmac_write_shm(pi->sh->physhim, offset + 14,
1917 -(pi->tx_power_offset[j] / 2));
1918 }
1919
1920 wlapi_bmac_mhf(pi->sh->physhim, MHF2, MHF2_HWPWRCTL,
1921 MHF2_HWPWRCTL, BRCM_BAND_ALL);
1922 } else {
1923 int i;
1924
1925 for (i = TXP_FIRST_OFDM; i <= TXP_LAST_OFDM; i++)
1926 pi->tx_power_offset[i] =
1927 (u8) roundup(pi->tx_power_offset[i], 8);
1928 wlapi_bmac_write_shm(pi->sh->physhim, M_OFDM_OFFSET,
1929 (u16)
1930 ((pi->tx_power_offset[TXP_FIRST_OFDM]
1931 + 7) >> 3));
1932 }
1933 }
1934
1935 bool wlc_phy_txpower_hw_ctrl_get(struct brcms_phy_pub *ppi)
1936 {
1937 struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
1938
1939 if (ISNPHY(pi))
1940 return pi->nphy_txpwrctrl;
1941 else
1942 return pi->hwpwrctrl;
1943 }
1944
1945 void wlc_phy_txpower_hw_ctrl_set(struct brcms_phy_pub *ppi, bool hwpwrctrl)
1946 {
1947 struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
1948 bool suspend;
1949
1950 if (!pi->hwpwrctrl_capable)
1951 return;
1952
1953 pi->hwpwrctrl = hwpwrctrl;
1954 pi->nphy_txpwrctrl = hwpwrctrl;
1955 pi->txpwrctrl = hwpwrctrl;
1956
1957 if (ISNPHY(pi)) {
1958 suspend = (0 == (bcma_read32(pi->d11core,
1959 D11REGOFFS(maccontrol)) &
1960 MCTL_EN_MAC));
1961 if (!suspend)
1962 wlapi_suspend_mac_and_wait(pi->sh->physhim);
1963
1964 wlc_phy_txpwrctrl_enable_nphy(pi, pi->nphy_txpwrctrl);
1965 if (pi->nphy_txpwrctrl == PHY_TPC_HW_OFF)
1966 wlc_phy_txpwr_fixpower_nphy(pi);
1967 else
1968 mod_phy_reg(pi, 0x1e7, (0x7f << 0),
1969 pi->saved_txpwr_idx);
1970
1971 if (!suspend)
1972 wlapi_enable_mac(pi->sh->physhim);
1973 }
1974 }
1975
1976 void wlc_phy_txpower_ipa_upd(struct brcms_phy *pi)
1977 {
1978
1979 if (NREV_GE(pi->pubpi.phy_rev, 3)) {
1980 pi->ipa2g_on = (pi->srom_fem2g.extpagain == 2);
1981 pi->ipa5g_on = (pi->srom_fem5g.extpagain == 2);
1982 } else {
1983 pi->ipa2g_on = false;
1984 pi->ipa5g_on = false;
1985 }
1986 }
1987
1988 static u32 wlc_phy_txpower_est_power_nphy(struct brcms_phy *pi)
1989 {
1990 s16 tx0_status, tx1_status;
1991 u16 estPower1, estPower2;
1992 u8 pwr0, pwr1, adj_pwr0, adj_pwr1;
1993 u32 est_pwr;
1994
1995 estPower1 = read_phy_reg(pi, 0x118);
1996 estPower2 = read_phy_reg(pi, 0x119);
1997
1998 if ((estPower1 & (0x1 << 8)) == (0x1 << 8))
1999 pwr0 = (u8) (estPower1 & (0xff << 0)) >> 0;
2000 else
2001 pwr0 = 0x80;
2002
2003 if ((estPower2 & (0x1 << 8)) == (0x1 << 8))
2004 pwr1 = (u8) (estPower2 & (0xff << 0)) >> 0;
2005 else
2006 pwr1 = 0x80;
2007
2008 tx0_status = read_phy_reg(pi, 0x1ed);
2009 tx1_status = read_phy_reg(pi, 0x1ee);
2010
2011 if ((tx0_status & (0x1 << 15)) == (0x1 << 15))
2012 adj_pwr0 = (u8) (tx0_status & (0xff << 0)) >> 0;
2013 else
2014 adj_pwr0 = 0x80;
2015 if ((tx1_status & (0x1 << 15)) == (0x1 << 15))
2016 adj_pwr1 = (u8) (tx1_status & (0xff << 0)) >> 0;
2017 else
2018 adj_pwr1 = 0x80;
2019
2020 est_pwr = (u32) ((pwr0 << 24) | (pwr1 << 16) | (adj_pwr0 << 8) |
2021 adj_pwr1);
2022
2023 return est_pwr;
2024 }
2025
2026 void
2027 wlc_phy_txpower_get_current(struct brcms_phy_pub *ppi, struct tx_power *power,
2028 uint channel)
2029 {
2030 struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
2031 uint rate, num_rates;
2032 u8 min_pwr, max_pwr;
2033
2034 #if WL_TX_POWER_RATES != TXP_NUM_RATES
2035 #error "struct tx_power out of sync with this fn"
2036 #endif
2037
2038 if (ISNPHY(pi)) {
2039 power->rf_cores = 2;
2040 power->flags |= (WL_TX_POWER_F_MIMO);
2041 if (pi->nphy_txpwrctrl == PHY_TPC_HW_ON)
2042 power->flags |=
2043 (WL_TX_POWER_F_ENABLED | WL_TX_POWER_F_HW);
2044 } else if (ISLCNPHY(pi)) {
2045 power->rf_cores = 1;
2046 power->flags |= (WL_TX_POWER_F_SISO);
2047 if (pi->radiopwr_override == RADIOPWR_OVERRIDE_DEF)
2048 power->flags |= WL_TX_POWER_F_ENABLED;
2049 if (pi->hwpwrctrl)
2050 power->flags |= WL_TX_POWER_F_HW;
2051 }
2052
2053 num_rates = ((ISNPHY(pi)) ? (TXP_NUM_RATES) :
2054 ((ISLCNPHY(pi)) ?
2055 (TXP_LAST_OFDM_20_CDD + 1) : (TXP_LAST_OFDM + 1)));
2056
2057 for (rate = 0; rate < num_rates; rate++) {
2058 power->user_limit[rate] = pi->tx_user_target[rate];
2059 wlc_phy_txpower_sromlimit(ppi, channel, &min_pwr, &max_pwr,
2060 rate);
2061 power->board_limit[rate] = (u8) max_pwr;
2062 power->target[rate] = pi->tx_power_target[rate];
2063 }
2064
2065 if (ISNPHY(pi)) {
2066 u32 est_pout;
2067
2068 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2069 wlc_phyreg_enter((struct brcms_phy_pub *) pi);
2070 est_pout = wlc_phy_txpower_est_power_nphy(pi);
2071 wlc_phyreg_exit((struct brcms_phy_pub *) pi);
2072 wlapi_enable_mac(pi->sh->physhim);
2073
2074 power->est_Pout[0] = (est_pout >> 8) & 0xff;
2075 power->est_Pout[1] = est_pout & 0xff;
2076
2077 power->est_Pout_act[0] = est_pout >> 24;
2078 power->est_Pout_act[1] = (est_pout >> 16) & 0xff;
2079
2080 if (power->est_Pout[0] == 0x80)
2081 power->est_Pout[0] = 0;
2082 if (power->est_Pout[1] == 0x80)
2083 power->est_Pout[1] = 0;
2084
2085 if (power->est_Pout_act[0] == 0x80)
2086 power->est_Pout_act[0] = 0;
2087 if (power->est_Pout_act[1] == 0x80)
2088 power->est_Pout_act[1] = 0;
2089
2090 power->est_Pout_cck = 0;
2091
2092 power->tx_power_max[0] = pi->tx_power_max;
2093 power->tx_power_max[1] = pi->tx_power_max;
2094
2095 power->tx_power_max_rate_ind[0] = pi->tx_power_max_rate_ind;
2096 power->tx_power_max_rate_ind[1] = pi->tx_power_max_rate_ind;
2097 } else if (pi->hwpwrctrl && pi->sh->up) {
2098
2099 wlc_phyreg_enter(ppi);
2100 if (ISLCNPHY(pi)) {
2101
2102 power->tx_power_max[0] = pi->tx_power_max;
2103 power->tx_power_max[1] = pi->tx_power_max;
2104
2105 power->tx_power_max_rate_ind[0] =
2106 pi->tx_power_max_rate_ind;
2107 power->tx_power_max_rate_ind[1] =
2108 pi->tx_power_max_rate_ind;
2109
2110 if (wlc_phy_tpc_isenabled_lcnphy(pi))
2111 power->flags |=
2112 (WL_TX_POWER_F_HW |
2113 WL_TX_POWER_F_ENABLED);
2114 else
2115 power->flags &=
2116 ~(WL_TX_POWER_F_HW |
2117 WL_TX_POWER_F_ENABLED);
2118
2119 wlc_lcnphy_get_tssi(pi, (s8 *) &power->est_Pout[0],
2120 (s8 *) &power->est_Pout_cck);
2121 }
2122 wlc_phyreg_exit(ppi);
2123 }
2124 }
2125
2126 void wlc_phy_antsel_type_set(struct brcms_phy_pub *ppi, u8 antsel_type)
2127 {
2128 struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
2129
2130 pi->antsel_type = antsel_type;
2131 }
2132
2133 bool wlc_phy_test_ison(struct brcms_phy_pub *ppi)
2134 {
2135 struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
2136
2137 return pi->phytest_on;
2138 }
2139
2140 void wlc_phy_ant_rxdiv_set(struct brcms_phy_pub *ppi, u8 val)
2141 {
2142 struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
2143 bool suspend;
2144
2145 pi->sh->rx_antdiv = val;
2146
2147 if (!(ISNPHY(pi) && D11REV_IS(pi->sh->corerev, 16))) {
2148 if (val > ANT_RX_DIV_FORCE_1)
2149 wlapi_bmac_mhf(pi->sh->physhim, MHF1, MHF1_ANTDIV,
2150 MHF1_ANTDIV, BRCM_BAND_ALL);
2151 else
2152 wlapi_bmac_mhf(pi->sh->physhim, MHF1, MHF1_ANTDIV, 0,
2153 BRCM_BAND_ALL);
2154 }
2155
2156 if (ISNPHY(pi))
2157 return;
2158
2159 if (!pi->sh->clk)
2160 return;
2161
2162 suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) &
2163 MCTL_EN_MAC));
2164 if (!suspend)
2165 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2166
2167 if (ISLCNPHY(pi)) {
2168 if (val > ANT_RX_DIV_FORCE_1) {
2169 mod_phy_reg(pi, 0x410, (0x1 << 1), 0x01 << 1);
2170 mod_phy_reg(pi, 0x410,
2171 (0x1 << 0),
2172 ((ANT_RX_DIV_START_1 == val) ? 1 : 0) << 0);
2173 } else {
2174 mod_phy_reg(pi, 0x410, (0x1 << 1), 0x00 << 1);
2175 mod_phy_reg(pi, 0x410, (0x1 << 0), (u16) val << 0);
2176 }
2177 }
2178
2179 if (!suspend)
2180 wlapi_enable_mac(pi->sh->physhim);
2181
2182 return;
2183 }
2184
2185 static bool
2186 wlc_phy_noise_calc_phy(struct brcms_phy *pi, u32 *cmplx_pwr, s8 *pwr_ant)
2187 {
2188 s8 cmplx_pwr_dbm[PHY_CORE_MAX];
2189 u8 i;
2190
2191 memset((u8 *) cmplx_pwr_dbm, 0, sizeof(cmplx_pwr_dbm));
2192 wlc_phy_compute_dB(cmplx_pwr, cmplx_pwr_dbm, pi->pubpi.phy_corenum);
2193
2194 for (i = 0; i < pi->pubpi.phy_corenum; i++) {
2195 if (NREV_GE(pi->pubpi.phy_rev, 3))
2196 cmplx_pwr_dbm[i] += (s8) PHY_NOISE_OFFSETFACT_4322;
2197 else
2198
2199 cmplx_pwr_dbm[i] += (s8) (16 - (15) * 3 - 70);
2200 }
2201
2202 for (i = 0; i < pi->pubpi.phy_corenum; i++) {
2203 pi->nphy_noise_win[i][pi->nphy_noise_index] = cmplx_pwr_dbm[i];
2204 pwr_ant[i] = cmplx_pwr_dbm[i];
2205 }
2206 pi->nphy_noise_index =
2207 MODINC_POW2(pi->nphy_noise_index, PHY_NOISE_WINDOW_SZ);
2208 return true;
2209 }
2210
2211 static void wlc_phy_noise_cb(struct brcms_phy *pi, u8 channel, s8 noise_dbm)
2212 {
2213 if (!pi->phynoise_state)
2214 return;
2215
2216 if (pi->phynoise_state & PHY_NOISE_STATE_MON) {
2217 if (pi->phynoise_chan_watchdog == channel) {
2218 pi->sh->phy_noise_window[pi->sh->phy_noise_index] =
2219 noise_dbm;
2220 pi->sh->phy_noise_index =
2221 MODINC(pi->sh->phy_noise_index, MA_WINDOW_SZ);
2222 }
2223 pi->phynoise_state &= ~PHY_NOISE_STATE_MON;
2224 }
2225
2226 if (pi->phynoise_state & PHY_NOISE_STATE_EXTERNAL)
2227 pi->phynoise_state &= ~PHY_NOISE_STATE_EXTERNAL;
2228
2229 }
2230
2231 static s8 wlc_phy_noise_read_shmem(struct brcms_phy *pi)
2232 {
2233 u32 cmplx_pwr[PHY_CORE_MAX];
2234 s8 noise_dbm_ant[PHY_CORE_MAX];
2235 u16 lo, hi;
2236 u32 cmplx_pwr_tot = 0;
2237 s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
2238 u8 idx, core;
2239
2240 memset((u8 *) cmplx_pwr, 0, sizeof(cmplx_pwr));
2241 memset((u8 *) noise_dbm_ant, 0, sizeof(noise_dbm_ant));
2242
2243 for (idx = 0, core = 0; core < pi->pubpi.phy_corenum; idx += 2,
2244 core++) {
2245 lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP(idx));
2246 hi = wlapi_bmac_read_shm(pi->sh->physhim,
2247 M_PWRIND_MAP(idx + 1));
2248 cmplx_pwr[core] = (hi << 16) + lo;
2249 cmplx_pwr_tot += cmplx_pwr[core];
2250 if (cmplx_pwr[core] == 0)
2251 noise_dbm_ant[core] = PHY_NOISE_FIXED_VAL_NPHY;
2252 else
2253 cmplx_pwr[core] >>= PHY_NOISE_SAMPLE_LOG_NUM_UCODE;
2254 }
2255
2256 if (cmplx_pwr_tot != 0)
2257 wlc_phy_noise_calc_phy(pi, cmplx_pwr, noise_dbm_ant);
2258
2259 for (core = 0; core < pi->pubpi.phy_corenum; core++) {
2260 pi->nphy_noise_win[core][pi->nphy_noise_index] =
2261 noise_dbm_ant[core];
2262
2263 if (noise_dbm_ant[core] > noise_dbm)
2264 noise_dbm = noise_dbm_ant[core];
2265 }
2266 pi->nphy_noise_index =
2267 MODINC_POW2(pi->nphy_noise_index, PHY_NOISE_WINDOW_SZ);
2268
2269 return noise_dbm;
2270
2271 }
2272
2273 void wlc_phy_noise_sample_intr(struct brcms_phy_pub *pih)
2274 {
2275 struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
2276 u16 jssi_aux;
2277 u8 channel = 0;
2278 s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
2279
2280 if (ISLCNPHY(pi)) {
2281 u32 cmplx_pwr, cmplx_pwr0, cmplx_pwr1;
2282 u16 lo, hi;
2283 s32 pwr_offset_dB, gain_dB;
2284 u16 status_0, status_1;
2285
2286 jssi_aux = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_AUX);
2287 channel = jssi_aux & D11_CURCHANNEL_MAX;
2288
2289 lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP0);
2290 hi = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP1);
2291 cmplx_pwr0 = (hi << 16) + lo;
2292
2293 lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP2);
2294 hi = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP3);
2295 cmplx_pwr1 = (hi << 16) + lo;
2296 cmplx_pwr = (cmplx_pwr0 + cmplx_pwr1) >> 6;
2297
2298 status_0 = 0x44;
2299 status_1 = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_0);
2300 if ((cmplx_pwr > 0 && cmplx_pwr < 500)
2301 && ((status_1 & 0xc000) == 0x4000)) {
2302
2303 wlc_phy_compute_dB(&cmplx_pwr, &noise_dbm,
2304 pi->pubpi.phy_corenum);
2305 pwr_offset_dB = (read_phy_reg(pi, 0x434) & 0xFF);
2306 if (pwr_offset_dB > 127)
2307 pwr_offset_dB -= 256;
2308
2309 noise_dbm += (s8) (pwr_offset_dB - 30);
2310
2311 gain_dB = (status_0 & 0x1ff);
2312 noise_dbm -= (s8) (gain_dB);
2313 } else {
2314 noise_dbm = PHY_NOISE_FIXED_VAL_LCNPHY;
2315 }
2316 } else if (ISNPHY(pi)) {
2317
2318 jssi_aux = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_AUX);
2319 channel = jssi_aux & D11_CURCHANNEL_MAX;
2320
2321 noise_dbm = wlc_phy_noise_read_shmem(pi);
2322 }
2323
2324 wlc_phy_noise_cb(pi, channel, noise_dbm);
2325
2326 }
2327
2328 static void
2329 wlc_phy_noise_sample_request(struct brcms_phy_pub *pih, u8 reason, u8 ch)
2330 {
2331 struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
2332 s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
2333 bool sampling_in_progress = (pi->phynoise_state != 0);
2334 bool wait_for_intr = true;
2335
2336 switch (reason) {
2337 case PHY_NOISE_SAMPLE_MON:
2338 pi->phynoise_chan_watchdog = ch;
2339 pi->phynoise_state |= PHY_NOISE_STATE_MON;
2340 break;
2341
2342 case PHY_NOISE_SAMPLE_EXTERNAL:
2343 pi->phynoise_state |= PHY_NOISE_STATE_EXTERNAL;
2344 break;
2345
2346 default:
2347 break;
2348 }
2349
2350 if (sampling_in_progress)
2351 return;
2352
2353 pi->phynoise_now = pi->sh->now;
2354
2355 if (pi->phy_fixed_noise) {
2356 if (ISNPHY(pi)) {
2357 pi->nphy_noise_win[WL_ANT_IDX_1][pi->nphy_noise_index] =
2358 PHY_NOISE_FIXED_VAL_NPHY;
2359 pi->nphy_noise_win[WL_ANT_IDX_2][pi->nphy_noise_index] =
2360 PHY_NOISE_FIXED_VAL_NPHY;
2361 pi->nphy_noise_index = MODINC_POW2(pi->nphy_noise_index,
2362 PHY_NOISE_WINDOW_SZ);
2363 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
2364 } else {
2365 noise_dbm = PHY_NOISE_FIXED_VAL;
2366 }
2367
2368 wait_for_intr = false;
2369 goto done;
2370 }
2371
2372 if (ISLCNPHY(pi)) {
2373 if (!pi->phynoise_polling
2374 || (reason == PHY_NOISE_SAMPLE_EXTERNAL)) {
2375 wlapi_bmac_write_shm(pi->sh->physhim, M_JSSI_0, 0);
2376 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP0, 0);
2377 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP1, 0);
2378 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP2, 0);
2379 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP3, 0);
2380
2381 bcma_set32(pi->d11core, D11REGOFFS(maccommand),
2382 MCMD_BG_NOISE);
2383 } else {
2384 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2385 wlc_lcnphy_deaf_mode(pi, (bool) 0);
2386 noise_dbm = (s8) wlc_lcnphy_rx_signal_power(pi, 20);
2387 wlc_lcnphy_deaf_mode(pi, (bool) 1);
2388 wlapi_enable_mac(pi->sh->physhim);
2389 wait_for_intr = false;
2390 }
2391 } else if (ISNPHY(pi)) {
2392 if (!pi->phynoise_polling
2393 || (reason == PHY_NOISE_SAMPLE_EXTERNAL)) {
2394
2395 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP0, 0);
2396 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP1, 0);
2397 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP2, 0);
2398 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP3, 0);
2399
2400 bcma_set32(pi->d11core, D11REGOFFS(maccommand),
2401 MCMD_BG_NOISE);
2402 } else {
2403 struct phy_iq_est est[PHY_CORE_MAX];
2404 u32 cmplx_pwr[PHY_CORE_MAX];
2405 s8 noise_dbm_ant[PHY_CORE_MAX];
2406 u16 log_num_samps, num_samps, classif_state = 0;
2407 u8 wait_time = 32;
2408 u8 wait_crs = 0;
2409 u8 i;
2410
2411 memset((u8 *) est, 0, sizeof(est));
2412 memset((u8 *) cmplx_pwr, 0, sizeof(cmplx_pwr));
2413 memset((u8 *) noise_dbm_ant, 0, sizeof(noise_dbm_ant));
2414
2415 log_num_samps = PHY_NOISE_SAMPLE_LOG_NUM_NPHY;
2416 num_samps = 1 << log_num_samps;
2417
2418 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2419 classif_state = wlc_phy_classifier_nphy(pi, 0, 0);
2420 wlc_phy_classifier_nphy(pi, 3, 0);
2421 wlc_phy_rx_iq_est_nphy(pi, est, num_samps, wait_time,
2422 wait_crs);
2423 wlc_phy_classifier_nphy(pi, (0x7 << 0), classif_state);
2424 wlapi_enable_mac(pi->sh->physhim);
2425
2426 for (i = 0; i < pi->pubpi.phy_corenum; i++)
2427 cmplx_pwr[i] = (est[i].i_pwr + est[i].q_pwr) >>
2428 log_num_samps;
2429
2430 wlc_phy_noise_calc_phy(pi, cmplx_pwr, noise_dbm_ant);
2431
2432 for (i = 0; i < pi->pubpi.phy_corenum; i++) {
2433 pi->nphy_noise_win[i][pi->nphy_noise_index] =
2434 noise_dbm_ant[i];
2435
2436 if (noise_dbm_ant[i] > noise_dbm)
2437 noise_dbm = noise_dbm_ant[i];
2438 }
2439 pi->nphy_noise_index = MODINC_POW2(pi->nphy_noise_index,
2440 PHY_NOISE_WINDOW_SZ);
2441
2442 wait_for_intr = false;
2443 }
2444 }
2445
2446 done:
2447
2448 if (!wait_for_intr)
2449 wlc_phy_noise_cb(pi, ch, noise_dbm);
2450
2451 }
2452
2453 void wlc_phy_noise_sample_request_external(struct brcms_phy_pub *pih)
2454 {
2455 u8 channel;
2456
2457 channel = CHSPEC_CHANNEL(wlc_phy_chanspec_get(pih));
2458
2459 wlc_phy_noise_sample_request(pih, PHY_NOISE_SAMPLE_EXTERNAL, channel);
2460 }
2461
2462 static const s8 lcnphy_gain_index_offset_for_pkt_rssi[] = {
2463 8,
2464 8,
2465 8,
2466 8,
2467 8,
2468 8,
2469 8,
2470 9,
2471 10,
2472 8,
2473 8,
2474 7,
2475 7,
2476 1,
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 2,
2494 2,
2495 1,
2496 1,
2497 0,
2498 0,
2499 0,
2500 0
2501 };
2502
2503 void wlc_phy_compute_dB(u32 *cmplx_pwr, s8 *p_cmplx_pwr_dB, u8 core)
2504 {
2505 u8 msb, secondmsb, i;
2506 u32 tmp;
2507
2508 for (i = 0; i < core; i++) {
2509 secondmsb = 0;
2510 tmp = cmplx_pwr[i];
2511 msb = fls(tmp);
2512 if (msb)
2513 secondmsb = (u8) ((tmp >> (--msb - 1)) & 1);
2514 p_cmplx_pwr_dB[i] = (s8) (3 * msb + 2 * secondmsb);
2515 }
2516 }
2517
2518 int wlc_phy_rssi_compute(struct brcms_phy_pub *pih,
2519 struct d11rxhdr *rxh)
2520 {
2521 int rssi = rxh->PhyRxStatus_1 & PRXS1_JSSI_MASK;
2522 uint radioid = pih->radioid;
2523 struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
2524
2525 if ((pi->sh->corerev >= 11)
2526 && !(rxh->RxStatus2 & RXS_PHYRXST_VALID)) {
2527 rssi = BRCMS_RSSI_INVALID;
2528 goto end;
2529 }
2530
2531 if (ISLCNPHY(pi)) {
2532 u8 gidx = (rxh->PhyRxStatus_2 & 0xFC00) >> 10;
2533 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
2534
2535 if (rssi > 127)
2536 rssi -= 256;
2537
2538 rssi = rssi + lcnphy_gain_index_offset_for_pkt_rssi[gidx];
2539 if ((rssi > -46) && (gidx > 18))
2540 rssi = rssi + 7;
2541
2542 rssi = rssi + pi_lcn->lcnphy_pkteng_rssi_slope;
2543
2544 rssi = rssi + 2;
2545
2546 }
2547
2548 if (ISLCNPHY(pi)) {
2549 if (rssi > 127)
2550 rssi -= 256;
2551 } else if (radioid == BCM2055_ID || radioid == BCM2056_ID
2552 || radioid == BCM2057_ID) {
2553 rssi = wlc_phy_rssi_compute_nphy(pi, rxh);
2554 }
2555
2556 end:
2557 return rssi;
2558 }
2559
2560 void wlc_phy_freqtrack_start(struct brcms_phy_pub *pih)
2561 {
2562 return;
2563 }
2564
2565 void wlc_phy_freqtrack_end(struct brcms_phy_pub *pih)
2566 {
2567 return;
2568 }
2569
2570 void wlc_phy_set_deaf(struct brcms_phy_pub *ppi, bool user_flag)
2571 {
2572 struct brcms_phy *pi;
2573 pi = (struct brcms_phy *) ppi;
2574
2575 if (ISLCNPHY(pi))
2576 wlc_lcnphy_deaf_mode(pi, true);
2577 else if (ISNPHY(pi))
2578 wlc_nphy_deaf_mode(pi, true);
2579 }
2580
2581 void wlc_phy_watchdog(struct brcms_phy_pub *pih)
2582 {
2583 struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
2584 bool delay_phy_cal = false;
2585 pi->sh->now++;
2586
2587 if (!pi->watchdog_override)
2588 return;
2589
2590 if (!(SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)))
2591 wlc_phy_noise_sample_request((struct brcms_phy_pub *) pi,
2592 PHY_NOISE_SAMPLE_MON,
2593 CHSPEC_CHANNEL(pi->
2594 radio_chanspec));
2595
2596 if (pi->phynoise_state && (pi->sh->now - pi->phynoise_now) > 5)
2597 pi->phynoise_state = 0;
2598
2599 if ((!pi->phycal_txpower) ||
2600 ((pi->sh->now - pi->phycal_txpower) >= pi->sh->fast_timer)) {
2601
2602 if (!SCAN_INPROG_PHY(pi) && wlc_phy_cal_txpower_recalc_sw(pi))
2603 pi->phycal_txpower = pi->sh->now;
2604 }
2605
2606 if ((SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)
2607 || ASSOC_INPROG_PHY(pi)))
2608 return;
2609
2610 if (ISNPHY(pi) && !pi->disable_percal && !delay_phy_cal) {
2611
2612 if ((pi->nphy_perical != PHY_PERICAL_DISABLE) &&
2613 (pi->nphy_perical != PHY_PERICAL_MANUAL) &&
2614 ((pi->sh->now - pi->nphy_perical_last) >=
2615 pi->sh->glacial_timer))
2616 wlc_phy_cal_perical((struct brcms_phy_pub *) pi,
2617 PHY_PERICAL_WATCHDOG);
2618
2619 wlc_phy_txpwr_papd_cal_nphy(pi);
2620 }
2621
2622 if (ISLCNPHY(pi)) {
2623 if (pi->phy_forcecal ||
2624 ((pi->sh->now - pi->phy_lastcal) >=
2625 pi->sh->glacial_timer)) {
2626 if (!(SCAN_RM_IN_PROGRESS(pi) || ASSOC_INPROG_PHY(pi)))
2627 wlc_lcnphy_calib_modes(
2628 pi,
2629 LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL);
2630 if (!
2631 (SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)
2632 || ASSOC_INPROG_PHY(pi)
2633 || pi->carrier_suppr_disable
2634 || pi->disable_percal))
2635 wlc_lcnphy_calib_modes(pi,
2636 PHY_PERICAL_WATCHDOG);
2637 }
2638 }
2639 }
2640
2641 void wlc_phy_BSSinit(struct brcms_phy_pub *pih, bool bonlyap, int rssi)
2642 {
2643 struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
2644 uint i;
2645 uint k;
2646
2647 for (i = 0; i < MA_WINDOW_SZ; i++)
2648 pi->sh->phy_noise_window[i] = (s8) (rssi & 0xff);
2649 if (ISLCNPHY(pi)) {
2650 for (i = 0; i < MA_WINDOW_SZ; i++)
2651 pi->sh->phy_noise_window[i] =
2652 PHY_NOISE_FIXED_VAL_LCNPHY;
2653 }
2654 pi->sh->phy_noise_index = 0;
2655
2656 for (i = 0; i < PHY_NOISE_WINDOW_SZ; i++) {
2657 for (k = WL_ANT_IDX_1; k < WL_ANT_RX_MAX; k++)
2658 pi->nphy_noise_win[k][i] = PHY_NOISE_FIXED_VAL_NPHY;
2659 }
2660 pi->nphy_noise_index = 0;
2661 }
2662
2663 void
2664 wlc_phy_papd_decode_epsilon(u32 epsilon, s32 *eps_real, s32 *eps_imag)
2665 {
2666 *eps_imag = (epsilon >> 13);
2667 if (*eps_imag > 0xfff)
2668 *eps_imag -= 0x2000;
2669
2670 *eps_real = (epsilon & 0x1fff);
2671 if (*eps_real > 0xfff)
2672 *eps_real -= 0x2000;
2673 }
2674
2675 void wlc_phy_cal_perical_mphase_reset(struct brcms_phy *pi)
2676 {
2677 wlapi_del_timer(pi->phycal_timer);
2678
2679 pi->cal_type_override = PHY_PERICAL_AUTO;
2680 pi->mphase_cal_phase_id = MPHASE_CAL_STATE_IDLE;
2681 pi->mphase_txcal_cmdidx = 0;
2682 }
2683
2684 static void
2685 wlc_phy_cal_perical_mphase_schedule(struct brcms_phy *pi, uint delay)
2686 {
2687
2688 if ((pi->nphy_perical != PHY_PERICAL_MPHASE) &&
2689 (pi->nphy_perical != PHY_PERICAL_MANUAL))
2690 return;
2691
2692 wlapi_del_timer(pi->phycal_timer);
2693
2694 pi->mphase_cal_phase_id = MPHASE_CAL_STATE_INIT;
2695 wlapi_add_timer(pi->phycal_timer, delay, 0);
2696 }
2697
2698 void wlc_phy_cal_perical(struct brcms_phy_pub *pih, u8 reason)
2699 {
2700 s16 nphy_currtemp = 0;
2701 s16 delta_temp = 0;
2702 bool do_periodic_cal = true;
2703 struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
2704
2705 if (!ISNPHY(pi))
2706 return;
2707
2708 if ((pi->nphy_perical == PHY_PERICAL_DISABLE) ||
2709 (pi->nphy_perical == PHY_PERICAL_MANUAL))
2710 return;
2711
2712 switch (reason) {
2713 case PHY_PERICAL_DRIVERUP:
2714 break;
2715
2716 case PHY_PERICAL_PHYINIT:
2717 if (pi->nphy_perical == PHY_PERICAL_MPHASE) {
2718 if (PHY_PERICAL_MPHASE_PENDING(pi))
2719 wlc_phy_cal_perical_mphase_reset(pi);
2720
2721 wlc_phy_cal_perical_mphase_schedule(
2722 pi,
2723 PHY_PERICAL_INIT_DELAY);
2724 }
2725 break;
2726
2727 case PHY_PERICAL_JOIN_BSS:
2728 case PHY_PERICAL_START_IBSS:
2729 case PHY_PERICAL_UP_BSS:
2730 if ((pi->nphy_perical == PHY_PERICAL_MPHASE) &&
2731 PHY_PERICAL_MPHASE_PENDING(pi))
2732 wlc_phy_cal_perical_mphase_reset(pi);
2733
2734 pi->first_cal_after_assoc = true;
2735
2736 pi->cal_type_override = PHY_PERICAL_FULL;
2737
2738 if (pi->phycal_tempdelta)
2739 pi->nphy_lastcal_temp = wlc_phy_tempsense_nphy(pi);
2740
2741 wlc_phy_cal_perical_nphy_run(pi, PHY_PERICAL_FULL);
2742 break;
2743
2744 case PHY_PERICAL_WATCHDOG:
2745 if (pi->phycal_tempdelta) {
2746 nphy_currtemp = wlc_phy_tempsense_nphy(pi);
2747 delta_temp =
2748 (nphy_currtemp > pi->nphy_lastcal_temp) ?
2749 nphy_currtemp - pi->nphy_lastcal_temp :
2750 pi->nphy_lastcal_temp - nphy_currtemp;
2751
2752 if ((delta_temp < (s16) pi->phycal_tempdelta) &&
2753 (pi->nphy_txiqlocal_chanspec ==
2754 pi->radio_chanspec))
2755 do_periodic_cal = false;
2756 else
2757 pi->nphy_lastcal_temp = nphy_currtemp;
2758 }
2759
2760 if (do_periodic_cal) {
2761 if (pi->nphy_perical == PHY_PERICAL_MPHASE) {
2762 if (!PHY_PERICAL_MPHASE_PENDING(pi))
2763 wlc_phy_cal_perical_mphase_schedule(
2764 pi,
2765 PHY_PERICAL_WDOG_DELAY);
2766 } else if (pi->nphy_perical == PHY_PERICAL_SPHASE)
2767 wlc_phy_cal_perical_nphy_run(pi,
2768 PHY_PERICAL_AUTO);
2769 }
2770 break;
2771 default:
2772 break;
2773 }
2774 }
2775
2776 void wlc_phy_cal_perical_mphase_restart(struct brcms_phy *pi)
2777 {
2778 pi->mphase_cal_phase_id = MPHASE_CAL_STATE_INIT;
2779 pi->mphase_txcal_cmdidx = 0;
2780 }
2781
2782 u8 wlc_phy_nbits(s32 value)
2783 {
2784 s32 abs_val;
2785 u8 nbits = 0;
2786
2787 abs_val = abs(value);
2788 while ((abs_val >> nbits) > 0)
2789 nbits++;
2790
2791 return nbits;
2792 }
2793
2794 void wlc_phy_stf_chain_init(struct brcms_phy_pub *pih, u8 txchain, u8 rxchain)
2795 {
2796 struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
2797
2798 pi->sh->hw_phytxchain = txchain;
2799 pi->sh->hw_phyrxchain = rxchain;
2800 pi->sh->phytxchain = txchain;
2801 pi->sh->phyrxchain = rxchain;
2802 pi->pubpi.phy_corenum = (u8)hweight8(pi->sh->phyrxchain);
2803 }
2804
2805 void wlc_phy_stf_chain_set(struct brcms_phy_pub *pih, u8 txchain, u8 rxchain)
2806 {
2807 struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
2808
2809 pi->sh->phytxchain = txchain;
2810
2811 if (ISNPHY(pi))
2812 wlc_phy_rxcore_setstate_nphy(pih, rxchain);
2813
2814 pi->pubpi.phy_corenum = (u8)hweight8(pi->sh->phyrxchain);
2815 }
2816
2817 void wlc_phy_stf_chain_get(struct brcms_phy_pub *pih, u8 *txchain, u8 *rxchain)
2818 {
2819 struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
2820
2821 *txchain = pi->sh->phytxchain;
2822 *rxchain = pi->sh->phyrxchain;
2823 }
2824
2825 u8 wlc_phy_stf_chain_active_get(struct brcms_phy_pub *pih)
2826 {
2827 s16 nphy_currtemp;
2828 u8 active_bitmap;
2829 struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
2830
2831 active_bitmap = (pi->phy_txcore_heatedup) ? 0x31 : 0x33;
2832
2833 if (!pi->watchdog_override)
2834 return active_bitmap;
2835
2836 if (NREV_GE(pi->pubpi.phy_rev, 6)) {
2837 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2838 nphy_currtemp = wlc_phy_tempsense_nphy(pi);
2839 wlapi_enable_mac(pi->sh->physhim);
2840
2841 if (!pi->phy_txcore_heatedup) {
2842 if (nphy_currtemp >= pi->phy_txcore_disable_temp) {
2843 active_bitmap &= 0xFD;
2844 pi->phy_txcore_heatedup = true;
2845 }
2846 } else {
2847 if (nphy_currtemp <= pi->phy_txcore_enable_temp) {
2848 active_bitmap |= 0x2;
2849 pi->phy_txcore_heatedup = false;
2850 }
2851 }
2852 }
2853
2854 return active_bitmap;
2855 }
2856
2857 s8 wlc_phy_stf_ssmode_get(struct brcms_phy_pub *pih, u16 chanspec)
2858 {
2859 struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
2860 u8 siso_mcs_id, cdd_mcs_id;
2861
2862 siso_mcs_id =
2863 (CHSPEC_IS40(chanspec)) ? TXP_FIRST_MCS_40_SISO :
2864 TXP_FIRST_MCS_20_SISO;
2865 cdd_mcs_id =
2866 (CHSPEC_IS40(chanspec)) ? TXP_FIRST_MCS_40_CDD :
2867 TXP_FIRST_MCS_20_CDD;
2868
2869 if (pi->tx_power_target[siso_mcs_id] >
2870 (pi->tx_power_target[cdd_mcs_id] + 12))
2871 return PHY_TXC1_MODE_SISO;
2872 else
2873 return PHY_TXC1_MODE_CDD;
2874 }
2875
2876 const u8 *wlc_phy_get_ofdm_rate_lookup(void)
2877 {
2878 return ofdm_rate_lookup;
2879 }
2880
2881 void wlc_lcnphy_epa_switch(struct brcms_phy *pi, bool mode)
2882 {
2883 if ((pi->sh->chip == BCMA_CHIP_ID_BCM4313) &&
2884 (pi->sh->boardflags & BFL_FEM)) {
2885 if (mode) {
2886 u16 txant = 0;
2887 txant = wlapi_bmac_get_txant(pi->sh->physhim);
2888 if (txant == 1) {
2889 mod_phy_reg(pi, 0x44d, (0x1 << 2), (1) << 2);
2890
2891 mod_phy_reg(pi, 0x44c, (0x1 << 2), (1) << 2);
2892
2893 }
2894
2895 bcma_chipco_gpio_control(&pi->d11core->bus->drv_cc,
2896 0x0, 0x0);
2897 bcma_chipco_gpio_out(&pi->d11core->bus->drv_cc,
2898 ~0x40, 0x40);
2899 bcma_chipco_gpio_outen(&pi->d11core->bus->drv_cc,
2900 ~0x40, 0x40);
2901 } else {
2902 mod_phy_reg(pi, 0x44c, (0x1 << 2), (0) << 2);
2903
2904 mod_phy_reg(pi, 0x44d, (0x1 << 2), (0) << 2);
2905
2906 bcma_chipco_gpio_out(&pi->d11core->bus->drv_cc,
2907 ~0x40, 0x00);
2908 bcma_chipco_gpio_outen(&pi->d11core->bus->drv_cc,
2909 ~0x40, 0x00);
2910 bcma_chipco_gpio_control(&pi->d11core->bus->drv_cc,
2911 0x0, 0x40);
2912 }
2913 }
2914 }
2915
2916 void wlc_phy_ldpc_override_set(struct brcms_phy_pub *ppi, bool ldpc)
2917 {
2918 return;
2919 }
2920
2921 void
2922 wlc_phy_get_pwrdet_offsets(struct brcms_phy *pi, s8 *cckoffset, s8 *ofdmoffset)
2923 {
2924 *cckoffset = 0;
2925 *ofdmoffset = 0;
2926 }
2927
2928 s8 wlc_phy_upd_rssi_offset(struct brcms_phy *pi, s8 rssi, u16 chanspec)
2929 {
2930
2931 return rssi;
2932 }
2933
2934 bool wlc_phy_txpower_ipa_ison(struct brcms_phy_pub *ppi)
2935 {
2936 struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
2937
2938 if (ISNPHY(pi))
2939 return wlc_phy_n_txpower_ipa_ison(pi);
2940 else
2941 return false;
2942 }