2 * Copyright (c) 2010 Broadcom Corporation
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 #include <linux/kernel.h>
19 #include <linux/module.h>
20 #include <linux/pci.h>
21 #include <linux/netdevice.h>
22 #include <linux/etherdevice.h>
24 #include <proto/802.11.h>
40 #include "wlc_types.h"
47 #include "wlc_phy_shim.h"
48 #include "phy/wlc_phy_hal.h"
49 #include "wlc_channel.h"
51 #include "wl_export.h"
53 #include "wlc_antsel.h"
54 #include "pcie_core.h"
55 #include "wlc_alloc.h"
59 #define TIMER_INTERVAL_WATCHDOG_BMAC 1000 /* watchdog timer, in unit of ms */
61 #define SYNTHPU_DLY_APHY_US 3700 /* a phy synthpu_dly time in us */
62 #define SYNTHPU_DLY_BPHY_US 1050 /* b/g phy synthpu_dly time in us, default */
63 #define SYNTHPU_DLY_NPHY_US 2048 /* n phy REV3 synthpu_dly time in us, default */
64 #define SYNTHPU_DLY_LPPHY_US 300 /* lpphy synthpu_dly time in us */
66 #define SYNTHPU_DLY_PHY_US_QT 100 /* QT synthpu_dly time in us */
68 #ifndef BMAC_DUP_TO_REMOVE
69 #define WLC_RM_WAIT_TX_SUSPEND 4 /* Wait Tx Suspend */
71 #define ANTCNT 10 /* vanilla M_MAX_ANTCNT value */
73 #endif /* BMAC_DUP_TO_REMOVE */
75 #define DMAREG(wlc_hw, direction, fifonum) \
76 ((direction == DMA_TX) ? \
77 (void *)&(wlc_hw->regs->fifo64regs[fifonum].dmaxmt) : \
78 (void *)&(wlc_hw->regs->fifo64regs[fifonum].dmarcv))
81 * The following table lists the buffer memory allocated to xmt fifos in HW.
82 * the size is in units of 256bytes(one block), total size is HW dependent
83 * ucode has default fifo partition, sw can overwrite if necessary
85 * This is documented in twiki under the topic UcodeTxFifo. Please ensure
86 * the twiki is updated before making changes.
89 #define XMTFIFOTBL_STARTREV 20 /* Starting corerev for the fifo size table */
91 static u16 xmtfifo_sz
[][NFIFO
] = {
92 {20, 192, 192, 21, 17, 5}, /* corerev 20: 5120, 49152, 49152, 5376, 4352, 1280 */
93 {9, 58, 22, 14, 14, 5}, /* corerev 21: 2304, 14848, 5632, 3584, 3584, 1280 */
94 {20, 192, 192, 21, 17, 5}, /* corerev 22: 5120, 49152, 49152, 5376, 4352, 1280 */
95 {20, 192, 192, 21, 17, 5}, /* corerev 23: 5120, 49152, 49152, 5376, 4352, 1280 */
96 {9, 58, 22, 14, 14, 5}, /* corerev 24: 2304, 14848, 5632, 3584, 3584, 1280 */
99 static void wlc_clkctl_clk(struct wlc_hw_info
*wlc
, uint mode
);
100 static void wlc_coreinit(struct wlc_info
*wlc
);
102 /* used by wlc_wakeucode_init() */
103 static void wlc_write_inits(struct wlc_hw_info
*wlc_hw
,
104 const struct d11init
*inits
);
105 static void wlc_ucode_write(struct wlc_hw_info
*wlc_hw
, const u32 ucode
[],
107 static void wlc_ucode_download(struct wlc_hw_info
*wlc
);
108 static void wlc_ucode_txant_set(struct wlc_hw_info
*wlc_hw
);
110 /* used by wlc_dpc() */
111 static bool wlc_bmac_dotxstatus(struct wlc_hw_info
*wlc
, tx_status_t
*txs
,
113 static bool wlc_bmac_txstatus(struct wlc_hw_info
*wlc
, bool bound
, bool *fatal
);
114 static bool wlc_bmac_recv(struct wlc_hw_info
*wlc_hw
, uint fifo
, bool bound
);
116 /* used by wlc_down() */
117 static void wlc_flushqueues(struct wlc_info
*wlc
);
119 static void wlc_write_mhf(struct wlc_hw_info
*wlc_hw
, u16
*mhfs
);
120 static void wlc_mctrl_reset(struct wlc_hw_info
*wlc_hw
);
121 static void wlc_corerev_fifofixup(struct wlc_hw_info
*wlc_hw
);
122 static bool wlc_bmac_tx_fifo_suspended(struct wlc_hw_info
*wlc_hw
,
124 static void wlc_bmac_tx_fifo_suspend(struct wlc_hw_info
*wlc_hw
, uint tx_fifo
);
125 static void wlc_bmac_tx_fifo_resume(struct wlc_hw_info
*wlc_hw
, uint tx_fifo
);
127 /* Low Level Prototypes */
128 static int wlc_bmac_bandtype(struct wlc_hw_info
*wlc_hw
);
129 static void wlc_bmac_info_init(struct wlc_hw_info
*wlc_hw
);
130 static void wlc_bmac_xtal(struct wlc_hw_info
*wlc_hw
, bool want
);
131 static u16
wlc_bmac_read_objmem(struct wlc_hw_info
*wlc_hw
, uint offset
,
133 static void wlc_bmac_write_objmem(struct wlc_hw_info
*wlc_hw
, uint offset
,
135 static void wlc_bmac_core_phy_clk(struct wlc_hw_info
*wlc_hw
, bool clk
);
136 static bool wlc_bmac_attach_dmapio(struct wlc_info
*wlc
, uint j
, bool wme
);
137 static void wlc_bmac_detach_dmapio(struct wlc_hw_info
*wlc_hw
);
138 static void wlc_ucode_bsinit(struct wlc_hw_info
*wlc_hw
);
139 static bool wlc_validboardtype(struct wlc_hw_info
*wlc
);
140 static bool wlc_isgoodchip(struct wlc_hw_info
*wlc_hw
);
141 static bool wlc_bmac_validate_chip_access(struct wlc_hw_info
*wlc_hw
);
142 static char *wlc_get_macaddr(struct wlc_hw_info
*wlc_hw
);
143 static void wlc_mhfdef(struct wlc_info
*wlc
, u16
*mhfs
, u16 mhf2_init
);
144 static void wlc_mctrl_write(struct wlc_hw_info
*wlc_hw
);
145 static void wlc_bmac_mute(struct wlc_hw_info
*wlc_hw
, bool want
, mbool flags
);
146 static void wlc_ucode_mute_override_set(struct wlc_hw_info
*wlc_hw
);
147 static void wlc_ucode_mute_override_clear(struct wlc_hw_info
*wlc_hw
);
148 static u32
wlc_wlintrsoff(struct wlc_info
*wlc
);
149 static void wlc_wlintrsrestore(struct wlc_info
*wlc
, u32 macintmask
);
150 static void wlc_gpio_init(struct wlc_info
*wlc
);
151 static void wlc_write_hw_bcntemplate0(struct wlc_hw_info
*wlc_hw
, void *bcn
,
153 static void wlc_write_hw_bcntemplate1(struct wlc_hw_info
*wlc_hw
, void *bcn
,
155 static void wlc_bmac_bsinit(struct wlc_info
*wlc
, chanspec_t chanspec
);
156 static u32
wlc_setband_inact(struct wlc_info
*wlc
, uint bandunit
);
157 static void wlc_bmac_setband(struct wlc_hw_info
*wlc_hw
, uint bandunit
,
158 chanspec_t chanspec
);
159 static void wlc_bmac_update_slot_timing(struct wlc_hw_info
*wlc_hw
,
161 static void wlc_upd_ofdm_pctl1_table(struct wlc_hw_info
*wlc_hw
);
162 static u16
wlc_bmac_ofdm_ratetable_offset(struct wlc_hw_info
*wlc_hw
,
165 /* === Low Level functions === */
167 void wlc_bmac_set_shortslot(struct wlc_hw_info
*wlc_hw
, bool shortslot
)
169 wlc_hw
->shortslot
= shortslot
;
171 if (BAND_2G(wlc_bmac_bandtype(wlc_hw
)) && wlc_hw
->up
) {
172 wlc_suspend_mac_and_wait(wlc_hw
->wlc
);
173 wlc_bmac_update_slot_timing(wlc_hw
, shortslot
);
174 wlc_enable_mac(wlc_hw
->wlc
);
179 * Update the slot timing for standard 11b/g (20us slots)
180 * or shortslot 11g (9us slots)
181 * The PSM needs to be suspended for this call.
183 static void wlc_bmac_update_slot_timing(struct wlc_hw_info
*wlc_hw
,
191 /* 11g short slot: 11a timing */
192 W_REG(®s
->ifs_slot
, 0x0207); /* APHY_SLOT_TIME */
193 wlc_bmac_write_shm(wlc_hw
, M_DOT11_SLOT
, APHY_SLOT_TIME
);
195 /* 11g long slot: 11b timing */
196 W_REG(®s
->ifs_slot
, 0x0212); /* BPHY_SLOT_TIME */
197 wlc_bmac_write_shm(wlc_hw
, M_DOT11_SLOT
, BPHY_SLOT_TIME
);
201 static void WLBANDINITFN(wlc_ucode_bsinit
) (struct wlc_hw_info
*wlc_hw
)
203 /* init microcode host flags */
204 wlc_write_mhf(wlc_hw
, wlc_hw
->band
->mhfs
);
206 /* do band-specific ucode IHR, SHM, and SCR inits */
207 if (D11REV_IS(wlc_hw
->corerev
, 23)) {
208 if (WLCISNPHY(wlc_hw
->band
)) {
209 wlc_write_inits(wlc_hw
, d11n0bsinitvals16
);
211 WL_ERROR("%s: wl%d: unsupported phy in corerev %d\n",
212 __func__
, wlc_hw
->unit
, wlc_hw
->corerev
);
215 if (D11REV_IS(wlc_hw
->corerev
, 24)) {
216 if (WLCISLCNPHY(wlc_hw
->band
)) {
217 wlc_write_inits(wlc_hw
, d11lcn0bsinitvals24
);
219 WL_ERROR("%s: wl%d: unsupported phy in corerev %d\n",
220 __func__
, wlc_hw
->unit
,
223 WL_ERROR("%s: wl%d: unsupported corerev %d\n",
224 __func__
, wlc_hw
->unit
, wlc_hw
->corerev
);
229 /* switch to new band but leave it inactive */
230 static u32
WLBANDINITFN(wlc_setband_inact
) (struct wlc_info
*wlc
, uint bandunit
)
232 struct wlc_hw_info
*wlc_hw
= wlc
->hw
;
235 WL_TRACE("wl%d: wlc_setband_inact\n", wlc_hw
->unit
);
237 ASSERT(bandunit
!= wlc_hw
->band
->bandunit
);
238 ASSERT(si_iscoreup(wlc_hw
->sih
));
239 ASSERT((R_REG(&wlc_hw
->regs
->maccontrol
) & MCTL_EN_MAC
) ==
242 /* disable interrupts */
243 macintmask
= wl_intrsoff(wlc
->wl
);
246 wlc_phy_switch_radio(wlc_hw
->band
->pi
, OFF
);
250 wlc_bmac_core_phy_clk(wlc_hw
, OFF
);
252 wlc_setxband(wlc_hw
, bandunit
);
257 /* Process received frames */
259 * Return true if more frames need to be processed. false otherwise.
260 * Param 'bound' indicates max. # frames to process before break out.
262 static bool BCMFASTPATH
263 wlc_bmac_recv(struct wlc_hw_info
*wlc_hw
, uint fifo
, bool bound
)
266 struct sk_buff
*head
= NULL
;
267 struct sk_buff
*tail
= NULL
;
269 uint bound_limit
= bound
? wlc_hw
->wlc
->pub
->tunables
->rxbnd
: -1;
271 wlc_d11rxhdr_t
*wlc_rxhdr
= NULL
;
273 WL_TRACE("wl%d: %s\n", wlc_hw
->unit
, __func__
);
274 /* gather received frames */
275 while ((p
= dma_rx(wlc_hw
->di
[fifo
]))) {
284 /* !give others some time to run! */
285 if (++n
>= bound_limit
)
289 /* get the TSF REG reading */
290 wlc_bmac_read_tsf(wlc_hw
, &tsf_l
, &tsf_h
);
292 /* post more rbufs */
293 dma_rxfill(wlc_hw
->di
[fifo
]);
295 /* process each frame */
296 while ((p
= head
) != NULL
) {
300 /* record the tsf_l in wlc_rxd11hdr */
301 wlc_rxhdr
= (wlc_d11rxhdr_t
*) p
->data
;
302 wlc_rxhdr
->tsf_l
= cpu_to_le32(tsf_l
);
304 /* compute the RSSI from d11rxhdr and record it in wlc_rxd11hr */
305 wlc_phy_rssi_compute(wlc_hw
->band
->pi
, wlc_rxhdr
);
307 wlc_recv(wlc_hw
->wlc
, p
);
310 return n
>= bound_limit
;
313 /* second-level interrupt processing
314 * Return true if another dpc needs to be re-scheduled. false otherwise.
315 * Param 'bounded' indicates if applicable loops should be bounded.
317 bool BCMFASTPATH
wlc_dpc(struct wlc_info
*wlc
, bool bounded
)
320 struct wlc_hw_info
*wlc_hw
= wlc
->hw
;
321 d11regs_t
*regs
= wlc_hw
->regs
;
324 if (DEVICEREMOVED(wlc
)) {
325 WL_ERROR("wl%d: %s: dead chip\n", wlc_hw
->unit
, __func__
);
330 /* grab and clear the saved software intstatus bits */
331 macintstatus
= wlc
->macintstatus
;
332 wlc
->macintstatus
= 0;
334 WL_TRACE("wl%d: wlc_dpc: macintstatus 0x%x\n",
335 wlc_hw
->unit
, macintstatus
);
337 if (macintstatus
& MI_PRQ
) {
338 /* Process probe request FIFO */
339 ASSERT(0 && "PRQ Interrupt in non-MBSS");
342 /* BCN template is available */
343 /* ZZZ: Use AP_ACTIVE ? */
344 if (AP_ENAB(wlc
->pub
) && (!APSTA_ENAB(wlc
->pub
) || wlc
->aps_associated
)
345 && (macintstatus
& MI_BCNTPL
)) {
346 wlc_update_beacon(wlc
);
349 /* PMQ entry addition */
350 if (macintstatus
& MI_PMQ
) {
354 if (macintstatus
& MI_TFS
) {
355 if (wlc_bmac_txstatus(wlc
->hw
, bounded
, &fatal
))
356 wlc
->macintstatus
|= MI_TFS
;
358 WL_ERROR("MI_TFS: fatal\n");
363 if (macintstatus
& (MI_TBTT
| MI_DTIM_TBTT
))
366 /* ATIM window end */
367 if (macintstatus
& MI_ATIMWINEND
) {
368 WL_TRACE("wlc_isr: end of ATIM window\n");
370 OR_REG(®s
->maccommand
, wlc
->qvalid
);
375 if (macintstatus
& MI_PHYTXERR
) {
376 wlc
->pub
->_cnt
->txphyerr
++;
379 /* received data or control frame, MI_DMAINT is indication of RX_FIFO interrupt */
380 if (macintstatus
& MI_DMAINT
) {
381 if (wlc_bmac_recv(wlc_hw
, RX_FIFO
, bounded
)) {
382 wlc
->macintstatus
|= MI_DMAINT
;
386 /* TX FIFO suspend/flush completion */
387 if (macintstatus
& MI_TXSTOP
) {
388 if (wlc_bmac_tx_fifo_suspended(wlc_hw
, TX_DATA_FIFO
)) {
389 /* WL_ERROR("dpc: fifo_suspend_comlete\n"); */
393 /* noise sample collected */
394 if (macintstatus
& MI_BG_NOISE
) {
395 wlc_phy_noise_sample_intr(wlc_hw
->band
->pi
);
398 if (macintstatus
& MI_GP0
) {
399 WL_ERROR("wl%d: PSM microcode watchdog fired at %d (seconds). Resetting.\n",
400 wlc_hw
->unit
, wlc_hw
->now
);
402 printk_once("%s : PSM Watchdog, chipid 0x%x, chiprev 0x%x\n",
403 __func__
, wlc_hw
->sih
->chip
,
404 wlc_hw
->sih
->chiprev
);
406 wlc
->pub
->_cnt
->psmwds
++;
412 /* gptimer timeout */
413 if (macintstatus
& MI_TO
) {
414 W_REG(®s
->gptimer
, 0);
417 if (macintstatus
& MI_RFDISABLE
) {
418 WL_TRACE("wl%d: BMAC Detected a change on the RF Disable Input\n", wlc_hw
->unit
);
420 wlc
->pub
->_cnt
->rfdisable
++;
421 wl_rfkill_set_hw_state(wlc
->wl
);
424 /* send any enq'd tx packets. Just makes sure to jump start tx */
425 if (!pktq_empty(&wlc
->active_queue
->q
))
426 wlc_send_q(wlc
, wlc
->active_queue
);
428 ASSERT(wlc_ps_check(wlc
));
430 /* make sure the bound indication and the implementation are in sync */
431 ASSERT(bounded
== true || wlc
->macintstatus
== 0);
433 /* it isn't done and needs to be resched if macintstatus is non-zero */
434 return wlc
->macintstatus
!= 0;
438 return wlc
->macintstatus
!= 0;
441 /* common low-level watchdog code */
442 void wlc_bmac_watchdog(void *arg
)
444 struct wlc_info
*wlc
= (struct wlc_info
*) arg
;
445 struct wlc_hw_info
*wlc_hw
= wlc
->hw
;
447 WL_TRACE("wl%d: wlc_bmac_watchdog\n", wlc_hw
->unit
);
452 /* increment second count */
455 /* Check for FIFO error interrupts */
456 wlc_bmac_fifoerrors(wlc_hw
);
458 /* make sure RX dma has buffers */
459 dma_rxfill(wlc
->hw
->di
[RX_FIFO
]);
461 wlc_phy_watchdog(wlc_hw
->band
->pi
);
465 wlc_bmac_set_chanspec(struct wlc_hw_info
*wlc_hw
, chanspec_t chanspec
,
466 bool mute
, struct txpwr_limits
*txpwr
)
470 WL_TRACE("wl%d: wlc_bmac_set_chanspec 0x%x\n",
471 wlc_hw
->unit
, chanspec
);
473 wlc_hw
->chanspec
= chanspec
;
475 /* Switch bands if necessary */
476 if (NBANDS_HW(wlc_hw
) > 1) {
477 bandunit
= CHSPEC_WLCBANDUNIT(chanspec
);
478 if (wlc_hw
->band
->bandunit
!= bandunit
) {
479 /* wlc_bmac_setband disables other bandunit,
480 * use light band switch if not up yet
483 wlc_phy_chanspec_radio_set(wlc_hw
->
484 bandstate
[bandunit
]->
486 wlc_bmac_setband(wlc_hw
, bandunit
, chanspec
);
488 wlc_setxband(wlc_hw
, bandunit
);
493 wlc_phy_initcal_enable(wlc_hw
->band
->pi
, !mute
);
497 wlc_phy_txpower_limit_set(wlc_hw
->band
->pi
, txpwr
,
499 wlc_phy_chanspec_radio_set(wlc_hw
->band
->pi
, chanspec
);
501 wlc_phy_chanspec_set(wlc_hw
->band
->pi
, chanspec
);
502 wlc_phy_txpower_limit_set(wlc_hw
->band
->pi
, txpwr
, chanspec
);
504 /* Update muting of the channel */
505 wlc_bmac_mute(wlc_hw
, mute
, 0);
509 int wlc_bmac_state_get(struct wlc_hw_info
*wlc_hw
, wlc_bmac_state_t
*state
)
511 state
->machwcap
= wlc_hw
->machwcap
;
516 static bool wlc_bmac_attach_dmapio(struct wlc_info
*wlc
, uint j
, bool wme
)
520 /* ucode host flag 2 needed for pio mode, independent of band and fifo */
522 struct wlc_hw_info
*wlc_hw
= wlc
->hw
;
523 uint unit
= wlc_hw
->unit
;
524 wlc_tunables_t
*tune
= wlc
->pub
->tunables
;
526 /* name and offsets for dma_attach */
527 snprintf(name
, sizeof(name
), "wl%d", unit
);
529 if (wlc_hw
->di
[0] == 0) { /* Init FIFOs */
531 int dma_attach_err
= 0;
532 /* Find out the DMA addressing capability and let OS know
533 * All the channels within one DMA core have 'common-minimum' same
537 dma_addrwidth(wlc_hw
->sih
, DMAREG(wlc_hw
, DMA_TX
, 0));
539 if (!wl_alloc_dma_resources(wlc_hw
->wlc
->wl
, addrwidth
)) {
540 WL_ERROR("wl%d: wlc_attach: alloc_dma_resources failed\n",
547 * TX: TX_AC_BK_FIFO (TX AC Background data packets)
548 * RX: RX_FIFO (RX data packets)
550 ASSERT(TX_AC_BK_FIFO
== 0);
551 ASSERT(RX_FIFO
== 0);
552 wlc_hw
->di
[0] = dma_attach(name
, wlc_hw
->sih
,
553 (wme
? DMAREG(wlc_hw
, DMA_TX
, 0) :
554 NULL
), DMAREG(wlc_hw
, DMA_RX
, 0),
555 (wme
? tune
->ntxd
: 0), tune
->nrxd
,
556 tune
->rxbufsz
, -1, tune
->nrxbufpost
,
557 WL_HWRXOFF
, &wl_msg_level
);
558 dma_attach_err
|= (NULL
== wlc_hw
->di
[0]);
562 * TX: TX_AC_BE_FIFO (TX AC Best-Effort data packets)
563 * (legacy) TX_DATA_FIFO (TX data packets)
566 ASSERT(TX_AC_BE_FIFO
== 1);
567 ASSERT(TX_DATA_FIFO
== 1);
568 wlc_hw
->di
[1] = dma_attach(name
, wlc_hw
->sih
,
569 DMAREG(wlc_hw
, DMA_TX
, 1), NULL
,
570 tune
->ntxd
, 0, 0, -1, 0, 0,
572 dma_attach_err
|= (NULL
== wlc_hw
->di
[1]);
576 * TX: TX_AC_VI_FIFO (TX AC Video data packets)
579 ASSERT(TX_AC_VI_FIFO
== 2);
580 wlc_hw
->di
[2] = dma_attach(name
, wlc_hw
->sih
,
581 DMAREG(wlc_hw
, DMA_TX
, 2), NULL
,
582 tune
->ntxd
, 0, 0, -1, 0, 0,
584 dma_attach_err
|= (NULL
== wlc_hw
->di
[2]);
587 * TX: TX_AC_VO_FIFO (TX AC Voice data packets)
588 * (legacy) TX_CTL_FIFO (TX control & mgmt packets)
590 ASSERT(TX_AC_VO_FIFO
== 3);
591 ASSERT(TX_CTL_FIFO
== 3);
592 wlc_hw
->di
[3] = dma_attach(name
, wlc_hw
->sih
,
593 DMAREG(wlc_hw
, DMA_TX
, 3),
594 NULL
, tune
->ntxd
, 0, 0, -1,
595 0, 0, &wl_msg_level
);
596 dma_attach_err
|= (NULL
== wlc_hw
->di
[3]);
597 /* Cleaner to leave this as if with AP defined */
599 if (dma_attach_err
) {
600 WL_ERROR("wl%d: wlc_attach: dma_attach failed\n", unit
);
604 /* get pointer to dma engine tx flow control variable */
605 for (i
= 0; i
< NFIFO
; i
++)
608 (uint
*) dma_getvar(wlc_hw
->di
[i
],
612 /* initial ucode host flags */
613 wlc_mhfdef(wlc
, wlc_hw
->band
->mhfs
, pio_mhf2
);
618 static void wlc_bmac_detach_dmapio(struct wlc_hw_info
*wlc_hw
)
622 for (j
= 0; j
< NFIFO
; j
++) {
624 dma_detach(wlc_hw
->di
[j
]);
625 wlc_hw
->di
[j
] = NULL
;
631 * run backplane attach, init nvram
633 * initialize software state for each core and band
634 * put the whole chip in reset(driver down state), no clock
636 int wlc_bmac_attach(struct wlc_info
*wlc
, u16 vendor
, u16 device
, uint unit
,
637 bool piomode
, void *regsva
, uint bustype
, void *btparam
)
639 struct wlc_hw_info
*wlc_hw
;
641 char *macaddr
= NULL
;
646 shared_phy_params_t sha_params
;
648 WL_TRACE("wl%d: wlc_bmac_attach: vendor 0x%x device 0x%x\n",
649 unit
, vendor
, device
);
651 ASSERT(sizeof(wlc_d11rxhdr_t
) <= WL_HWRXOFF
);
658 wlc_hw
->band
= wlc_hw
->bandstate
[0];
659 wlc_hw
->_piomode
= piomode
;
661 /* populate struct wlc_hw_info with default values */
662 wlc_bmac_info_init(wlc_hw
);
665 * Do the hardware portion of the attach.
666 * Also initialize software state that depends on the particular hardware
669 wlc_hw
->sih
= si_attach((uint
) device
, regsva
, bustype
, btparam
,
670 &wlc_hw
->vars
, &wlc_hw
->vars_size
);
671 if (wlc_hw
->sih
== NULL
) {
672 WL_ERROR("wl%d: wlc_bmac_attach: si_attach failed\n", unit
);
679 * Get vendid/devid nvram overwrites, which could be different
680 * than those the BIOS recognizes for devices on PCMCIA_BUS,
681 * SDIO_BUS, and SROMless devices on PCI_BUS.
684 bustype
= BCMBUSTYPE
;
686 if (bustype
!= SI_BUS
) {
689 var
= getvar(vars
, "vendid");
691 vendor
= (u16
) simple_strtoul(var
, NULL
, 0);
692 WL_ERROR("Overriding vendor id = 0x%x\n", vendor
);
694 var
= getvar(vars
, "devid");
696 u16 devid
= (u16
) simple_strtoul(var
, NULL
, 0);
697 if (devid
!= 0xffff) {
699 WL_ERROR("Overriding device id = 0x%x\n",
704 /* verify again the device is supported */
705 if (!wlc_chipmatch(vendor
, device
)) {
706 WL_ERROR("wl%d: wlc_bmac_attach: Unsupported vendor/device (0x%x/0x%x)\n",
707 unit
, vendor
, device
);
713 wlc_hw
->vendorid
= vendor
;
714 wlc_hw
->deviceid
= device
;
716 /* set bar0 window to point at D11 core */
717 wlc_hw
->regs
= (d11regs_t
*) si_setcore(wlc_hw
->sih
, D11_CORE_ID
, 0);
718 wlc_hw
->corerev
= si_corerev(wlc_hw
->sih
);
722 wlc
->regs
= wlc_hw
->regs
;
724 /* validate chip, chiprev and corerev */
725 if (!wlc_isgoodchip(wlc_hw
)) {
730 /* initialize power control registers */
731 si_clkctl_init(wlc_hw
->sih
);
733 /* request fastclock and force fastclock for the rest of attach
734 * bring the d11 core out of reset.
735 * For PMU chips, the first wlc_clkctl_clk is no-op since core-clk is still false;
736 * But it will be called again inside wlc_corereset, after d11 is out of reset.
738 wlc_clkctl_clk(wlc_hw
, CLK_FAST
);
739 wlc_bmac_corereset(wlc_hw
, WLC_USE_COREFLAGS
);
741 if (!wlc_bmac_validate_chip_access(wlc_hw
)) {
742 WL_ERROR("wl%d: wlc_bmac_attach: validate_chip_access failed\n",
748 /* get the board rev, used just below */
749 j
= getintvar(vars
, "boardrev");
750 /* promote srom boardrev of 0xFF to 1 */
751 if (j
== BOARDREV_PROMOTABLE
)
752 j
= BOARDREV_PROMOTED
;
753 wlc_hw
->boardrev
= (u16
) j
;
754 if (!wlc_validboardtype(wlc_hw
)) {
755 WL_ERROR("wl%d: wlc_bmac_attach: Unsupported Broadcom board type (0x%x)" " or revision level (0x%x)\n",
756 unit
, wlc_hw
->sih
->boardtype
, wlc_hw
->boardrev
);
760 wlc_hw
->sromrev
= (u8
) getintvar(vars
, "sromrev");
761 wlc_hw
->boardflags
= (u32
) getintvar(vars
, "boardflags");
762 wlc_hw
->boardflags2
= (u32
) getintvar(vars
, "boardflags2");
764 if (wlc_hw
->boardflags
& BFL_NOPLLDOWN
)
765 wlc_bmac_pllreq(wlc_hw
, true, WLC_PLLREQ_SHARED
);
767 if ((wlc_hw
->sih
->bustype
== PCI_BUS
)
768 && (si_pci_war16165(wlc_hw
->sih
)))
769 wlc
->war16165
= true;
771 /* check device id(srom, nvram etc.) to set bands */
772 if (wlc_hw
->deviceid
== BCM43224_D11N_ID
) {
773 /* Dualband boards */
778 if ((wlc_hw
->sih
->chip
== BCM43225_CHIP_ID
))
781 /* BMAC_NOTE: remove init of pub values when wlc_attach() unconditionally does the
782 * init of these values
784 wlc
->vendorid
= wlc_hw
->vendorid
;
785 wlc
->deviceid
= wlc_hw
->deviceid
;
786 wlc
->pub
->sih
= wlc_hw
->sih
;
787 wlc
->pub
->corerev
= wlc_hw
->corerev
;
788 wlc
->pub
->sromrev
= wlc_hw
->sromrev
;
789 wlc
->pub
->boardrev
= wlc_hw
->boardrev
;
790 wlc
->pub
->boardflags
= wlc_hw
->boardflags
;
791 wlc
->pub
->boardflags2
= wlc_hw
->boardflags2
;
792 wlc
->pub
->_nbands
= wlc_hw
->_nbands
;
794 wlc_hw
->physhim
= wlc_phy_shim_attach(wlc_hw
, wlc
->wl
, wlc
);
796 if (wlc_hw
->physhim
== NULL
) {
797 WL_ERROR("wl%d: wlc_bmac_attach: wlc_phy_shim_attach failed\n",
803 /* pass all the parameters to wlc_phy_shared_attach in one struct */
804 sha_params
.sih
= wlc_hw
->sih
;
805 sha_params
.physhim
= wlc_hw
->physhim
;
806 sha_params
.unit
= unit
;
807 sha_params
.corerev
= wlc_hw
->corerev
;
808 sha_params
.vars
= vars
;
809 sha_params
.vid
= wlc_hw
->vendorid
;
810 sha_params
.did
= wlc_hw
->deviceid
;
811 sha_params
.chip
= wlc_hw
->sih
->chip
;
812 sha_params
.chiprev
= wlc_hw
->sih
->chiprev
;
813 sha_params
.chippkg
= wlc_hw
->sih
->chippkg
;
814 sha_params
.sromrev
= wlc_hw
->sromrev
;
815 sha_params
.boardtype
= wlc_hw
->sih
->boardtype
;
816 sha_params
.boardrev
= wlc_hw
->boardrev
;
817 sha_params
.boardvendor
= wlc_hw
->sih
->boardvendor
;
818 sha_params
.boardflags
= wlc_hw
->boardflags
;
819 sha_params
.boardflags2
= wlc_hw
->boardflags2
;
820 sha_params
.bustype
= wlc_hw
->sih
->bustype
;
821 sha_params
.buscorerev
= wlc_hw
->sih
->buscorerev
;
823 /* alloc and save pointer to shared phy state area */
824 wlc_hw
->phy_sh
= wlc_phy_shared_attach(&sha_params
);
825 if (!wlc_hw
->phy_sh
) {
830 /* initialize software state for each core and band */
831 for (j
= 0; j
< NBANDS_HW(wlc_hw
); j
++) {
833 * band0 is always 2.4Ghz
834 * band1, if present, is 5Ghz
837 /* So if this is a single band 11a card, use band 1 */
838 if (IS_SINGLEBAND_5G(wlc_hw
->deviceid
))
841 wlc_setxband(wlc_hw
, j
);
843 wlc_hw
->band
->bandunit
= j
;
844 wlc_hw
->band
->bandtype
= j
? WLC_BAND_5G
: WLC_BAND_2G
;
845 wlc
->band
->bandunit
= j
;
846 wlc
->band
->bandtype
= j
? WLC_BAND_5G
: WLC_BAND_2G
;
847 wlc
->core
->coreidx
= si_coreidx(wlc_hw
->sih
);
849 wlc_hw
->machwcap
= R_REG(®s
->machwcap
);
850 wlc_hw
->machwcap_backup
= wlc_hw
->machwcap
;
852 /* init tx fifo size */
853 ASSERT((wlc_hw
->corerev
- XMTFIFOTBL_STARTREV
) <
854 ARRAY_SIZE(xmtfifo_sz
));
856 xmtfifo_sz
[(wlc_hw
->corerev
- XMTFIFOTBL_STARTREV
)];
858 /* Get a phy for this band */
859 wlc_hw
->band
->pi
= wlc_phy_attach(wlc_hw
->phy_sh
,
860 (void *)regs
, wlc_bmac_bandtype(wlc_hw
), vars
);
861 if (wlc_hw
->band
->pi
== NULL
) {
862 WL_ERROR("wl%d: wlc_bmac_attach: wlc_phy_attach failed\n",
868 wlc_phy_machwcap_set(wlc_hw
->band
->pi
, wlc_hw
->machwcap
);
870 wlc_phy_get_phyversion(wlc_hw
->band
->pi
, &wlc_hw
->band
->phytype
,
871 &wlc_hw
->band
->phyrev
,
872 &wlc_hw
->band
->radioid
,
873 &wlc_hw
->band
->radiorev
);
874 wlc_hw
->band
->abgphy_encore
=
875 wlc_phy_get_encore(wlc_hw
->band
->pi
);
876 wlc
->band
->abgphy_encore
= wlc_phy_get_encore(wlc_hw
->band
->pi
);
877 wlc_hw
->band
->core_flags
=
878 wlc_phy_get_coreflags(wlc_hw
->band
->pi
);
880 /* verify good phy_type & supported phy revision */
881 if (WLCISNPHY(wlc_hw
->band
)) {
882 if (NCONF_HAS(wlc_hw
->band
->phyrev
))
886 } else if (WLCISLCNPHY(wlc_hw
->band
)) {
887 if (LCNCONF_HAS(wlc_hw
->band
->phyrev
))
893 WL_ERROR("wl%d: wlc_bmac_attach: unsupported phy type/rev (%d/%d)\n",
895 wlc_hw
->band
->phytype
, wlc_hw
->band
->phyrev
);
901 /* BMAC_NOTE: wlc->band->pi should not be set below and should be done in the
902 * high level attach. However we can not make that change until all low level access
903 * is changed to wlc_hw->band->pi. Instead do the wlc->band->pi init below, keeping
904 * wlc_hw->band->pi as well for incremental update of low level fns, and cut over
905 * low only init when all fns updated.
907 wlc
->band
->pi
= wlc_hw
->band
->pi
;
908 wlc
->band
->phytype
= wlc_hw
->band
->phytype
;
909 wlc
->band
->phyrev
= wlc_hw
->band
->phyrev
;
910 wlc
->band
->radioid
= wlc_hw
->band
->radioid
;
911 wlc
->band
->radiorev
= wlc_hw
->band
->radiorev
;
913 /* default contention windows size limits */
914 wlc_hw
->band
->CWmin
= APHY_CWMIN
;
915 wlc_hw
->band
->CWmax
= PHY_CWMAX
;
917 if (!wlc_bmac_attach_dmapio(wlc
, j
, wme
)) {
923 /* disable core to match driver "down" state */
924 wlc_coredisable(wlc_hw
);
926 /* Match driver "down" state */
927 if (wlc_hw
->sih
->bustype
== PCI_BUS
)
928 si_pci_down(wlc_hw
->sih
);
930 /* register sb interrupt callback functions */
931 si_register_intr_callback(wlc_hw
->sih
, (void *)wlc_wlintrsoff
,
932 (void *)wlc_wlintrsrestore
, NULL
, wlc
);
934 /* turn off pll and xtal to match driver "down" state */
935 wlc_bmac_xtal(wlc_hw
, OFF
);
937 /* *********************************************************************
938 * The hardware is in the DOWN state at this point. D11 core
939 * or cores are in reset with clocks off, and the board PLLs
940 * are off if possible.
942 * Beyond this point, wlc->sbclk == false and chip registers
943 * should not be touched.
944 *********************************************************************
947 /* init etheraddr state variables */
948 macaddr
= wlc_get_macaddr(wlc_hw
);
949 if (macaddr
== NULL
) {
950 WL_ERROR("wl%d: wlc_bmac_attach: macaddr not found\n", unit
);
954 bcm_ether_atoe(macaddr
, wlc_hw
->etheraddr
);
955 if (is_broadcast_ether_addr(wlc_hw
->etheraddr
) ||
956 is_zero_ether_addr(wlc_hw
->etheraddr
)) {
957 WL_ERROR("wl%d: wlc_bmac_attach: bad macaddr %s\n",
963 WL_TRACE("%s:: deviceid 0x%x nbands %d board 0x%x macaddr: %s\n",
964 __func__
, wlc_hw
->deviceid
, wlc_hw
->_nbands
,
965 wlc_hw
->sih
->boardtype
, macaddr
);
970 WL_ERROR("wl%d: wlc_bmac_attach: failed with err %d\n", unit
, err
);
975 * Initialize wlc_info default values ...
976 * may get overrides later in this function
977 * BMAC_NOTES, move low out and resolve the dangling ones
979 static void wlc_bmac_info_init(struct wlc_hw_info
*wlc_hw
)
981 struct wlc_info
*wlc
= wlc_hw
->wlc
;
983 /* set default sw macintmask value */
984 wlc
->defmacintmask
= DEF_MACINTMASK
;
986 /* various 802.11g modes */
987 wlc_hw
->shortslot
= false;
989 wlc_hw
->SFBL
= RETRY_SHORT_FB
;
990 wlc_hw
->LFBL
= RETRY_LONG_FB
;
992 /* default mac retry limits */
993 wlc_hw
->SRL
= RETRY_SHORT_DEF
;
994 wlc_hw
->LRL
= RETRY_LONG_DEF
;
995 wlc_hw
->chanspec
= CH20MHZ_CHSPEC(1);
1001 int wlc_bmac_detach(struct wlc_info
*wlc
)
1004 struct wlc_hwband
*band
;
1005 struct wlc_hw_info
*wlc_hw
= wlc
->hw
;
1011 /* detach interrupt sync mechanism since interrupt is disabled and per-port
1012 * interrupt object may has been freed. this must be done before sb core switch
1014 si_deregister_intr_callback(wlc_hw
->sih
);
1016 if (wlc_hw
->sih
->bustype
== PCI_BUS
)
1017 si_pci_sleep(wlc_hw
->sih
);
1020 wlc_bmac_detach_dmapio(wlc_hw
);
1022 band
= wlc_hw
->band
;
1023 for (i
= 0; i
< NBANDS_HW(wlc_hw
); i
++) {
1025 /* Detach this band's phy */
1026 wlc_phy_detach(band
->pi
);
1029 band
= wlc_hw
->bandstate
[OTHERBANDUNIT(wlc
)];
1032 /* Free shared phy state */
1033 wlc_phy_shared_detach(wlc_hw
->phy_sh
);
1035 wlc_phy_shim_detach(wlc_hw
->physhim
);
1038 kfree(wlc_hw
->vars
);
1039 wlc_hw
->vars
= NULL
;
1042 si_detach(wlc_hw
->sih
);
1050 void wlc_bmac_reset(struct wlc_hw_info
*wlc_hw
)
1052 WL_TRACE("wl%d: wlc_bmac_reset\n", wlc_hw
->unit
);
1054 wlc_hw
->wlc
->pub
->_cnt
->reset
++;
1056 /* reset the core */
1057 if (!DEVICEREMOVED(wlc_hw
->wlc
))
1058 wlc_bmac_corereset(wlc_hw
, WLC_USE_COREFLAGS
);
1060 /* purge the dma rings */
1061 wlc_flushqueues(wlc_hw
->wlc
);
1063 wlc_reset_bmac_done(wlc_hw
->wlc
);
1067 wlc_bmac_init(struct wlc_hw_info
*wlc_hw
, chanspec_t chanspec
,
1071 struct wlc_info
*wlc
= wlc_hw
->wlc
;
1073 WL_TRACE("wl%d: wlc_bmac_init\n", wlc_hw
->unit
);
1075 /* request FAST clock if not on */
1076 fastclk
= wlc_hw
->forcefastclk
;
1078 wlc_clkctl_clk(wlc_hw
, CLK_FAST
);
1080 /* disable interrupts */
1081 macintmask
= wl_intrsoff(wlc
->wl
);
1083 /* set up the specified band and chanspec */
1084 wlc_setxband(wlc_hw
, CHSPEC_WLCBANDUNIT(chanspec
));
1085 wlc_phy_chanspec_radio_set(wlc_hw
->band
->pi
, chanspec
);
1087 /* do one-time phy inits and calibration */
1088 wlc_phy_cal_init(wlc_hw
->band
->pi
);
1090 /* core-specific initialization */
1093 /* suspend the tx fifos and mute the phy for preism cac time */
1095 wlc_bmac_mute(wlc_hw
, ON
, PHY_MUTE_FOR_PREISM
);
1097 /* band-specific inits */
1098 wlc_bmac_bsinit(wlc
, chanspec
);
1100 /* restore macintmask */
1101 wl_intrsrestore(wlc
->wl
, macintmask
);
1103 /* seed wake_override with WLC_WAKE_OVERRIDE_MACSUSPEND since the mac is suspended
1104 * and wlc_enable_mac() will clear this override bit.
1106 mboolset(wlc_hw
->wake_override
, WLC_WAKE_OVERRIDE_MACSUSPEND
);
1109 * initialize mac_suspend_depth to 1 to match ucode initial suspended state
1111 wlc_hw
->mac_suspend_depth
= 1;
1113 /* restore the clk */
1115 wlc_clkctl_clk(wlc_hw
, CLK_DYNAMIC
);
1118 int wlc_bmac_up_prep(struct wlc_hw_info
*wlc_hw
)
1122 WL_TRACE("wl%d: %s:\n", wlc_hw
->unit
, __func__
);
1124 ASSERT(wlc_hw
->wlc
->pub
->hw_up
&& wlc_hw
->wlc
->macintmask
== 0);
1127 * Enable pll and xtal, initialize the power control registers,
1128 * and force fastclock for the remainder of wlc_up().
1130 wlc_bmac_xtal(wlc_hw
, ON
);
1131 si_clkctl_init(wlc_hw
->sih
);
1132 wlc_clkctl_clk(wlc_hw
, CLK_FAST
);
1135 * Configure pci/pcmcia here instead of in wlc_attach()
1136 * to allow mfg hotswap: down, hotswap (chip power cycle), up.
1138 coremask
= (1 << wlc_hw
->wlc
->core
->coreidx
);
1140 if (wlc_hw
->sih
->bustype
== PCI_BUS
)
1141 si_pci_setup(wlc_hw
->sih
, coremask
);
1143 ASSERT(si_coreid(wlc_hw
->sih
) == D11_CORE_ID
);
1146 * Need to read the hwradio status here to cover the case where the system
1147 * is loaded with the hw radio disabled. We do not want to bring the driver up in this case.
1149 if (wlc_bmac_radio_read_hwdisabled(wlc_hw
)) {
1150 /* put SB PCI in down state again */
1151 if (wlc_hw
->sih
->bustype
== PCI_BUS
)
1152 si_pci_down(wlc_hw
->sih
);
1153 wlc_bmac_xtal(wlc_hw
, OFF
);
1154 return BCME_RADIOOFF
;
1157 if (wlc_hw
->sih
->bustype
== PCI_BUS
)
1158 si_pci_up(wlc_hw
->sih
);
1160 /* reset the d11 core */
1161 wlc_bmac_corereset(wlc_hw
, WLC_USE_COREFLAGS
);
1166 int wlc_bmac_up_finish(struct wlc_hw_info
*wlc_hw
)
1168 WL_TRACE("wl%d: %s:\n", wlc_hw
->unit
, __func__
);
1171 wlc_phy_hw_state_upd(wlc_hw
->band
->pi
, true);
1173 /* FULLY enable dynamic power control and d11 core interrupt */
1174 wlc_clkctl_clk(wlc_hw
, CLK_DYNAMIC
);
1175 ASSERT(wlc_hw
->wlc
->macintmask
== 0);
1176 wl_intrson(wlc_hw
->wlc
->wl
);
1180 int wlc_bmac_down_prep(struct wlc_hw_info
*wlc_hw
)
1185 WL_TRACE("wl%d: %s:\n", wlc_hw
->unit
, __func__
);
1190 dev_gone
= DEVICEREMOVED(wlc_hw
->wlc
);
1192 /* disable interrupts */
1194 wlc_hw
->wlc
->macintmask
= 0;
1196 /* now disable interrupts */
1197 wl_intrsoff(wlc_hw
->wlc
->wl
);
1199 /* ensure we're running on the pll clock again */
1200 wlc_clkctl_clk(wlc_hw
, CLK_FAST
);
1202 /* down phy at the last of this stage */
1203 callbacks
+= wlc_phy_down(wlc_hw
->band
->pi
);
1208 int wlc_bmac_down_finish(struct wlc_hw_info
*wlc_hw
)
1213 WL_TRACE("wl%d: %s:\n", wlc_hw
->unit
, __func__
);
1219 wlc_phy_hw_state_upd(wlc_hw
->band
->pi
, false);
1221 dev_gone
= DEVICEREMOVED(wlc_hw
->wlc
);
1224 wlc_hw
->sbclk
= false;
1225 wlc_hw
->clk
= false;
1226 wlc_phy_hw_clk_state_upd(wlc_hw
->band
->pi
, false);
1228 /* reclaim any posted packets */
1229 wlc_flushqueues(wlc_hw
->wlc
);
1232 /* Reset and disable the core */
1233 if (si_iscoreup(wlc_hw
->sih
)) {
1234 if (R_REG(&wlc_hw
->regs
->maccontrol
) &
1236 wlc_suspend_mac_and_wait(wlc_hw
->wlc
);
1237 callbacks
+= wl_reset(wlc_hw
->wlc
->wl
);
1238 wlc_coredisable(wlc_hw
);
1241 /* turn off primary xtal and pll */
1242 if (!wlc_hw
->noreset
) {
1243 if (wlc_hw
->sih
->bustype
== PCI_BUS
)
1244 si_pci_down(wlc_hw
->sih
);
1245 wlc_bmac_xtal(wlc_hw
, OFF
);
1252 void wlc_bmac_wait_for_wake(struct wlc_hw_info
*wlc_hw
)
1254 /* delay before first read of ucode state */
1257 /* wait until ucode is no longer asleep */
1258 SPINWAIT((wlc_bmac_read_shm(wlc_hw
, M_UCODE_DBGST
) ==
1259 DBGST_ASLEEP
), wlc_hw
->wlc
->fastpwrup_dly
);
1261 ASSERT(wlc_bmac_read_shm(wlc_hw
, M_UCODE_DBGST
) != DBGST_ASLEEP
);
1264 void wlc_bmac_hw_etheraddr(struct wlc_hw_info
*wlc_hw
, u8
*ea
)
1266 memcpy(ea
, wlc_hw
->etheraddr
, ETH_ALEN
);
1269 static int wlc_bmac_bandtype(struct wlc_hw_info
*wlc_hw
)
1271 return wlc_hw
->band
->bandtype
;
1274 /* control chip clock to save power, enable dynamic clock or force fast clock */
1275 static void wlc_clkctl_clk(struct wlc_hw_info
*wlc_hw
, uint mode
)
1277 if (PMUCTL_ENAB(wlc_hw
->sih
)) {
1278 /* new chips with PMU, CCS_FORCEHT will distribute the HT clock on backplane,
1279 * but mac core will still run on ALP(not HT) when it enters powersave mode,
1280 * which means the FCA bit may not be set.
1281 * should wakeup mac if driver wants it to run on HT.
1285 if (mode
== CLK_FAST
) {
1286 OR_REG(&wlc_hw
->regs
->clk_ctl_st
,
1293 clk_ctl_st
) & CCS_HTAVAIL
) == 0),
1294 PMU_MAX_TRANSITION_DLY
);
1297 clk_ctl_st
) & CCS_HTAVAIL
);
1299 if ((wlc_hw
->sih
->pmurev
== 0) &&
1302 clk_ctl_st
) & (CCS_FORCEHT
| CCS_HTAREQ
)))
1305 clk_ctl_st
) & CCS_HTAVAIL
)
1307 PMU_MAX_TRANSITION_DLY
);
1308 AND_REG(&wlc_hw
->regs
->clk_ctl_st
,
1312 wlc_hw
->forcefastclk
= (mode
== CLK_FAST
);
1315 /* old chips w/o PMU, force HT through cc,
1316 * then use FCA to verify mac is running fast clock
1319 wlc_hw
->forcefastclk
= si_clkctl_cc(wlc_hw
->sih
, mode
);
1321 /* check fast clock is available (if core is not in reset) */
1322 if (wlc_hw
->forcefastclk
&& wlc_hw
->clk
)
1323 ASSERT(si_core_sflags(wlc_hw
->sih
, 0, 0) & SISF_FCLKA
);
1325 /* keep the ucode wake bit on if forcefastclk is on
1326 * since we do not want ucode to put us back to slow clock
1327 * when it dozes for PM mode.
1328 * Code below matches the wake override bit with current forcefastclk state
1329 * Only setting bit in wake_override instead of waking ucode immediately
1330 * since old code (wlc.c 1.4499) had this behavior. Older code set
1331 * wlc->forcefastclk but only had the wake happen if the wakup_ucode work
1332 * (protected by an up check) was executed just below.
1334 if (wlc_hw
->forcefastclk
)
1335 mboolset(wlc_hw
->wake_override
,
1336 WLC_WAKE_OVERRIDE_FORCEFAST
);
1338 mboolclr(wlc_hw
->wake_override
,
1339 WLC_WAKE_OVERRIDE_FORCEFAST
);
1343 /* set initial host flags value */
1345 wlc_mhfdef(struct wlc_info
*wlc
, u16
*mhfs
, u16 mhf2_init
)
1347 struct wlc_hw_info
*wlc_hw
= wlc
->hw
;
1349 memset(mhfs
, 0, MHFMAX
* sizeof(u16
));
1351 mhfs
[MHF2
] |= mhf2_init
;
1353 /* prohibit use of slowclock on multifunction boards */
1354 if (wlc_hw
->boardflags
& BFL_NOPLLDOWN
)
1355 mhfs
[MHF1
] |= MHF1_FORCEFASTCLK
;
1357 if (WLCISNPHY(wlc_hw
->band
) && NREV_LT(wlc_hw
->band
->phyrev
, 2)) {
1358 mhfs
[MHF2
] |= MHF2_NPHY40MHZ_WAR
;
1359 mhfs
[MHF1
] |= MHF1_IQSWAP_WAR
;
1363 /* set or clear ucode host flag bits
1364 * it has an optimization for no-change write
1365 * it only writes through shared memory when the core has clock;
1366 * pre-CLK changes should use wlc_write_mhf to get around the optimization
1369 * bands values are: WLC_BAND_AUTO <--- Current band only
1370 * WLC_BAND_5G <--- 5G band only
1371 * WLC_BAND_2G <--- 2G band only
1372 * WLC_BAND_ALL <--- All bands
1375 wlc_bmac_mhf(struct wlc_hw_info
*wlc_hw
, u8 idx
, u16 mask
, u16 val
,
1379 u16 addr
[MHFMAX
] = {
1380 M_HOST_FLAGS1
, M_HOST_FLAGS2
, M_HOST_FLAGS3
, M_HOST_FLAGS4
,
1383 struct wlc_hwband
*band
;
1385 ASSERT((val
& ~mask
) == 0);
1386 ASSERT(idx
< MHFMAX
);
1387 ASSERT(ARRAY_SIZE(addr
) == MHFMAX
);
1390 /* Current band only or all bands,
1391 * then set the band to current band
1395 band
= wlc_hw
->band
;
1398 band
= wlc_hw
->bandstate
[BAND_5G_INDEX
];
1401 band
= wlc_hw
->bandstate
[BAND_2G_INDEX
];
1409 save
= band
->mhfs
[idx
];
1410 band
->mhfs
[idx
] = (band
->mhfs
[idx
] & ~mask
) | val
;
1412 /* optimization: only write through if changed, and
1413 * changed band is the current band
1415 if (wlc_hw
->clk
&& (band
->mhfs
[idx
] != save
)
1416 && (band
== wlc_hw
->band
))
1417 wlc_bmac_write_shm(wlc_hw
, addr
[idx
],
1418 (u16
) band
->mhfs
[idx
]);
1421 if (bands
== WLC_BAND_ALL
) {
1422 wlc_hw
->bandstate
[0]->mhfs
[idx
] =
1423 (wlc_hw
->bandstate
[0]->mhfs
[idx
] & ~mask
) | val
;
1424 wlc_hw
->bandstate
[1]->mhfs
[idx
] =
1425 (wlc_hw
->bandstate
[1]->mhfs
[idx
] & ~mask
) | val
;
1429 u16
wlc_bmac_mhf_get(struct wlc_hw_info
*wlc_hw
, u8 idx
, int bands
)
1431 struct wlc_hwband
*band
;
1432 ASSERT(idx
< MHFMAX
);
1436 band
= wlc_hw
->band
;
1439 band
= wlc_hw
->bandstate
[BAND_5G_INDEX
];
1442 band
= wlc_hw
->bandstate
[BAND_2G_INDEX
];
1452 return band
->mhfs
[idx
];
1455 static void wlc_write_mhf(struct wlc_hw_info
*wlc_hw
, u16
*mhfs
)
1459 M_HOST_FLAGS1
, M_HOST_FLAGS2
, M_HOST_FLAGS3
, M_HOST_FLAGS4
,
1463 ASSERT(ARRAY_SIZE(addr
) == MHFMAX
);
1465 for (idx
= 0; idx
< MHFMAX
; idx
++) {
1466 wlc_bmac_write_shm(wlc_hw
, addr
[idx
], mhfs
[idx
]);
1470 /* set the maccontrol register to desired reset state and
1471 * initialize the sw cache of the register
1473 static void wlc_mctrl_reset(struct wlc_hw_info
*wlc_hw
)
1475 /* IHR accesses are always enabled, PSM disabled, HPS off and WAKE on */
1476 wlc_hw
->maccontrol
= 0;
1477 wlc_hw
->suspended_fifos
= 0;
1478 wlc_hw
->wake_override
= 0;
1479 wlc_hw
->mute_override
= 0;
1480 wlc_bmac_mctrl(wlc_hw
, ~0, MCTL_IHR_EN
| MCTL_WAKE
);
1483 /* set or clear maccontrol bits */
1484 void wlc_bmac_mctrl(struct wlc_hw_info
*wlc_hw
, u32 mask
, u32 val
)
1489 ASSERT((val
& ~mask
) == 0);
1491 maccontrol
= wlc_hw
->maccontrol
;
1492 new_maccontrol
= (maccontrol
& ~mask
) | val
;
1494 /* if the new maccontrol value is the same as the old, nothing to do */
1495 if (new_maccontrol
== maccontrol
)
1498 /* something changed, cache the new value */
1499 wlc_hw
->maccontrol
= new_maccontrol
;
1501 /* write the new values with overrides applied */
1502 wlc_mctrl_write(wlc_hw
);
1505 /* write the software state of maccontrol and overrides to the maccontrol register */
1506 static void wlc_mctrl_write(struct wlc_hw_info
*wlc_hw
)
1508 u32 maccontrol
= wlc_hw
->maccontrol
;
1510 /* OR in the wake bit if overridden */
1511 if (wlc_hw
->wake_override
)
1512 maccontrol
|= MCTL_WAKE
;
1514 /* set AP and INFRA bits for mute if needed */
1515 if (wlc_hw
->mute_override
) {
1516 maccontrol
&= ~(MCTL_AP
);
1517 maccontrol
|= MCTL_INFRA
;
1520 W_REG(&wlc_hw
->regs
->maccontrol
, maccontrol
);
1523 void wlc_ucode_wake_override_set(struct wlc_hw_info
*wlc_hw
, u32 override_bit
)
1525 ASSERT((wlc_hw
->wake_override
& override_bit
) == 0);
1527 if (wlc_hw
->wake_override
|| (wlc_hw
->maccontrol
& MCTL_WAKE
)) {
1528 mboolset(wlc_hw
->wake_override
, override_bit
);
1532 mboolset(wlc_hw
->wake_override
, override_bit
);
1534 wlc_mctrl_write(wlc_hw
);
1535 wlc_bmac_wait_for_wake(wlc_hw
);
1540 void wlc_ucode_wake_override_clear(struct wlc_hw_info
*wlc_hw
, u32 override_bit
)
1542 ASSERT(wlc_hw
->wake_override
& override_bit
);
1544 mboolclr(wlc_hw
->wake_override
, override_bit
);
1546 if (wlc_hw
->wake_override
|| (wlc_hw
->maccontrol
& MCTL_WAKE
))
1549 wlc_mctrl_write(wlc_hw
);
1554 /* When driver needs ucode to stop beaconing, it has to make sure that
1555 * MCTL_AP is clear and MCTL_INFRA is set
1556 * Mode MCTL_AP MCTL_INFRA
1558 * STA 0 1 <--- This will ensure no beacons
1561 static void wlc_ucode_mute_override_set(struct wlc_hw_info
*wlc_hw
)
1563 wlc_hw
->mute_override
= 1;
1565 /* if maccontrol already has AP == 0 and INFRA == 1 without this
1566 * override, then there is no change to write
1568 if ((wlc_hw
->maccontrol
& (MCTL_AP
| MCTL_INFRA
)) == MCTL_INFRA
)
1571 wlc_mctrl_write(wlc_hw
);
1576 /* Clear the override on AP and INFRA bits */
1577 static void wlc_ucode_mute_override_clear(struct wlc_hw_info
*wlc_hw
)
1579 if (wlc_hw
->mute_override
== 0)
1582 wlc_hw
->mute_override
= 0;
1584 /* if maccontrol already has AP == 0 and INFRA == 1 without this
1585 * override, then there is no change to write
1587 if ((wlc_hw
->maccontrol
& (MCTL_AP
| MCTL_INFRA
)) == MCTL_INFRA
)
1590 wlc_mctrl_write(wlc_hw
);
1594 * Write a MAC address to the rcmta structure
1597 wlc_bmac_set_rcmta(struct wlc_hw_info
*wlc_hw
, int idx
,
1600 d11regs_t
*regs
= wlc_hw
->regs
;
1601 volatile u16
*objdata16
= (volatile u16
*)®s
->objdata
;
1605 WL_TRACE("wl%d: %s\n", wlc_hw
->unit
, __func__
);
1608 (addr
[3] << 24) | (addr
[2] << 16) |
1609 (addr
[1] << 8) | addr
[0];
1610 mac_l
= (addr
[5] << 8) | addr
[4];
1612 W_REG(®s
->objaddr
, (OBJADDR_RCMTA_SEL
| (idx
* 2)));
1613 (void)R_REG(®s
->objaddr
);
1614 W_REG(®s
->objdata
, mac_hm
);
1615 W_REG(®s
->objaddr
, (OBJADDR_RCMTA_SEL
| ((idx
* 2) + 1)));
1616 (void)R_REG(®s
->objaddr
);
1617 W_REG(objdata16
, mac_l
);
1621 * Write a MAC address to the given match reg offset in the RXE match engine.
1624 wlc_bmac_set_addrmatch(struct wlc_hw_info
*wlc_hw
, int match_reg_offset
,
1632 WL_TRACE("wl%d: wlc_bmac_set_addrmatch\n", wlc_hw
->unit
);
1634 ASSERT(match_reg_offset
< RCM_SIZE
);
1636 regs
= wlc_hw
->regs
;
1637 mac_l
= addr
[0] | (addr
[1] << 8);
1638 mac_m
= addr
[2] | (addr
[3] << 8);
1639 mac_h
= addr
[4] | (addr
[5] << 8);
1641 /* enter the MAC addr into the RXE match registers */
1642 W_REG(®s
->rcm_ctl
, RCM_INC_DATA
| match_reg_offset
);
1643 W_REG(®s
->rcm_mat_data
, mac_l
);
1644 W_REG(®s
->rcm_mat_data
, mac_m
);
1645 W_REG(®s
->rcm_mat_data
, mac_h
);
1650 wlc_bmac_write_template_ram(struct wlc_hw_info
*wlc_hw
, int offset
, int len
,
1657 volatile u16
*dptr
= NULL
;
1658 #endif /* IL_BIGENDIAN */
1659 WL_TRACE("wl%d: wlc_bmac_write_template_ram\n", wlc_hw
->unit
);
1661 regs
= wlc_hw
->regs
;
1663 ASSERT(IS_ALIGNED(offset
, sizeof(u32
)));
1664 ASSERT(IS_ALIGNED(len
, sizeof(u32
)));
1665 ASSERT((offset
& ~0xffff) == 0);
1667 W_REG(®s
->tplatewrptr
, offset
);
1669 /* if MCTL_BIGEND bit set in mac control register,
1670 * the chip swaps data in fifo, as well as data in
1673 be_bit
= (R_REG(®s
->maccontrol
) & MCTL_BIGEND
) != 0;
1676 memcpy(&word
, buf
, sizeof(u32
));
1679 word
= cpu_to_be32(word
);
1681 word
= cpu_to_le32(word
);
1683 W_REG(®s
->tplatewrdata
, word
);
1685 buf
= (u8
*) buf
+ sizeof(u32
);
1690 void wlc_bmac_set_cwmin(struct wlc_hw_info
*wlc_hw
, u16 newmin
)
1692 wlc_hw
->band
->CWmin
= newmin
;
1694 W_REG(&wlc_hw
->regs
->objaddr
, OBJADDR_SCR_SEL
| S_DOT11_CWMIN
);
1695 (void)R_REG(&wlc_hw
->regs
->objaddr
);
1696 W_REG(&wlc_hw
->regs
->objdata
, newmin
);
1699 void wlc_bmac_set_cwmax(struct wlc_hw_info
*wlc_hw
, u16 newmax
)
1701 wlc_hw
->band
->CWmax
= newmax
;
1703 W_REG(&wlc_hw
->regs
->objaddr
, OBJADDR_SCR_SEL
| S_DOT11_CWMAX
);
1704 (void)R_REG(&wlc_hw
->regs
->objaddr
);
1705 W_REG(&wlc_hw
->regs
->objdata
, newmax
);
1708 void wlc_bmac_bw_set(struct wlc_hw_info
*wlc_hw
, u16 bw
)
1712 /* request FAST clock if not on */
1713 fastclk
= wlc_hw
->forcefastclk
;
1715 wlc_clkctl_clk(wlc_hw
, CLK_FAST
);
1717 wlc_phy_bw_state_set(wlc_hw
->band
->pi
, bw
);
1719 ASSERT(wlc_hw
->clk
);
1721 wlc_bmac_phy_reset(wlc_hw
);
1722 wlc_phy_init(wlc_hw
->band
->pi
, wlc_phy_chanspec_get(wlc_hw
->band
->pi
));
1724 /* restore the clk */
1726 wlc_clkctl_clk(wlc_hw
, CLK_DYNAMIC
);
1730 wlc_write_hw_bcntemplate0(struct wlc_hw_info
*wlc_hw
, void *bcn
, int len
)
1732 d11regs_t
*regs
= wlc_hw
->regs
;
1734 wlc_bmac_write_template_ram(wlc_hw
, T_BCN0_TPL_BASE
, (len
+ 3) & ~3,
1736 /* write beacon length to SCR */
1737 ASSERT(len
< 65536);
1738 wlc_bmac_write_shm(wlc_hw
, M_BCN0_FRM_BYTESZ
, (u16
) len
);
1739 /* mark beacon0 valid */
1740 OR_REG(®s
->maccommand
, MCMD_BCN0VLD
);
1744 wlc_write_hw_bcntemplate1(struct wlc_hw_info
*wlc_hw
, void *bcn
, int len
)
1746 d11regs_t
*regs
= wlc_hw
->regs
;
1748 wlc_bmac_write_template_ram(wlc_hw
, T_BCN1_TPL_BASE
, (len
+ 3) & ~3,
1750 /* write beacon length to SCR */
1751 ASSERT(len
< 65536);
1752 wlc_bmac_write_shm(wlc_hw
, M_BCN1_FRM_BYTESZ
, (u16
) len
);
1753 /* mark beacon1 valid */
1754 OR_REG(®s
->maccommand
, MCMD_BCN1VLD
);
1757 /* mac is assumed to be suspended at this point */
1759 wlc_bmac_write_hw_bcntemplates(struct wlc_hw_info
*wlc_hw
, void *bcn
, int len
,
1762 d11regs_t
*regs
= wlc_hw
->regs
;
1765 wlc_write_hw_bcntemplate0(wlc_hw
, bcn
, len
);
1766 wlc_write_hw_bcntemplate1(wlc_hw
, bcn
, len
);
1769 if (!(R_REG(®s
->maccommand
) & MCMD_BCN0VLD
))
1770 wlc_write_hw_bcntemplate0(wlc_hw
, bcn
, len
);
1773 (R_REG(®s
->maccommand
) & MCMD_BCN1VLD
))
1774 wlc_write_hw_bcntemplate1(wlc_hw
, bcn
, len
);
1775 else /* one template should always have been available */
1780 static void WLBANDINITFN(wlc_bmac_upd_synthpu
) (struct wlc_hw_info
*wlc_hw
)
1783 struct wlc_info
*wlc
= wlc_hw
->wlc
;
1784 /* update SYNTHPU_DLY */
1786 if (WLCISLCNPHY(wlc
->band
)) {
1787 v
= SYNTHPU_DLY_LPPHY_US
;
1788 } else if (WLCISNPHY(wlc
->band
) && (NREV_GE(wlc
->band
->phyrev
, 3))) {
1789 v
= SYNTHPU_DLY_NPHY_US
;
1791 v
= SYNTHPU_DLY_BPHY_US
;
1794 wlc_bmac_write_shm(wlc_hw
, M_SYNTHPU_DLY
, v
);
1797 /* band-specific init */
1799 WLBANDINITFN(wlc_bmac_bsinit
) (struct wlc_info
*wlc
, chanspec_t chanspec
)
1801 struct wlc_hw_info
*wlc_hw
= wlc
->hw
;
1803 WL_TRACE("wl%d: wlc_bmac_bsinit: bandunit %d\n",
1804 wlc_hw
->unit
, wlc_hw
->band
->bandunit
);
1807 if (PHY_TYPE(R_REG(&wlc_hw
->regs
->phyversion
)) !=
1810 PHY_TYPE(R_REG(&wlc_hw
->regs
->phyversion
))
1811 == wlc_hw
->band
->phytype
);
1813 wlc_ucode_bsinit(wlc_hw
);
1815 wlc_phy_init(wlc_hw
->band
->pi
, chanspec
);
1817 wlc_ucode_txant_set(wlc_hw
);
1819 /* cwmin is band-specific, update hardware with value for current band */
1820 wlc_bmac_set_cwmin(wlc_hw
, wlc_hw
->band
->CWmin
);
1821 wlc_bmac_set_cwmax(wlc_hw
, wlc_hw
->band
->CWmax
);
1823 wlc_bmac_update_slot_timing(wlc_hw
,
1824 BAND_5G(wlc_hw
->band
->
1825 bandtype
) ? true : wlc_hw
->
1828 /* write phytype and phyvers */
1829 wlc_bmac_write_shm(wlc_hw
, M_PHYTYPE
, (u16
) wlc_hw
->band
->phytype
);
1830 wlc_bmac_write_shm(wlc_hw
, M_PHYVER
, (u16
) wlc_hw
->band
->phyrev
);
1832 /* initialize the txphyctl1 rate table since shmem is shared between bands */
1833 wlc_upd_ofdm_pctl1_table(wlc_hw
);
1835 wlc_bmac_upd_synthpu(wlc_hw
);
1838 static void wlc_bmac_core_phy_clk(struct wlc_hw_info
*wlc_hw
, bool clk
)
1840 WL_TRACE("wl%d: wlc_bmac_core_phy_clk: clk %d\n", wlc_hw
->unit
, clk
);
1842 wlc_hw
->phyclk
= clk
;
1844 if (OFF
== clk
) { /* clear gmode bit, put phy into reset */
1846 si_core_cflags(wlc_hw
->sih
, (SICF_PRST
| SICF_FGC
| SICF_GMODE
),
1847 (SICF_PRST
| SICF_FGC
));
1849 si_core_cflags(wlc_hw
->sih
, (SICF_PRST
| SICF_FGC
), SICF_PRST
);
1852 } else { /* take phy out of reset */
1854 si_core_cflags(wlc_hw
->sih
, (SICF_PRST
| SICF_FGC
), SICF_FGC
);
1856 si_core_cflags(wlc_hw
->sih
, (SICF_FGC
), 0);
1862 /* Perform a soft reset of the PHY PLL */
1863 void wlc_bmac_core_phypll_reset(struct wlc_hw_info
*wlc_hw
)
1865 WL_TRACE("wl%d: wlc_bmac_core_phypll_reset\n", wlc_hw
->unit
);
1867 si_corereg(wlc_hw
->sih
, SI_CC_IDX
,
1868 offsetof(chipcregs_t
, chipcontrol_addr
), ~0, 0);
1870 si_corereg(wlc_hw
->sih
, SI_CC_IDX
,
1871 offsetof(chipcregs_t
, chipcontrol_data
), 0x4, 0);
1873 si_corereg(wlc_hw
->sih
, SI_CC_IDX
,
1874 offsetof(chipcregs_t
, chipcontrol_data
), 0x4, 4);
1876 si_corereg(wlc_hw
->sih
, SI_CC_IDX
,
1877 offsetof(chipcregs_t
, chipcontrol_data
), 0x4, 0);
1881 /* light way to turn on phy clock without reset for NPHY only
1882 * refer to wlc_bmac_core_phy_clk for full version
1884 void wlc_bmac_phyclk_fgc(struct wlc_hw_info
*wlc_hw
, bool clk
)
1886 /* support(necessary for NPHY and HYPHY) only */
1887 if (!WLCISNPHY(wlc_hw
->band
))
1891 si_core_cflags(wlc_hw
->sih
, SICF_FGC
, SICF_FGC
);
1893 si_core_cflags(wlc_hw
->sih
, SICF_FGC
, 0);
1897 void wlc_bmac_macphyclk_set(struct wlc_hw_info
*wlc_hw
, bool clk
)
1900 si_core_cflags(wlc_hw
->sih
, SICF_MPCLKE
, SICF_MPCLKE
);
1902 si_core_cflags(wlc_hw
->sih
, SICF_MPCLKE
, 0);
1905 void wlc_bmac_phy_reset(struct wlc_hw_info
*wlc_hw
)
1907 wlc_phy_t
*pih
= wlc_hw
->band
->pi
;
1909 bool phy_in_reset
= false;
1911 WL_TRACE("wl%d: wlc_bmac_phy_reset\n", wlc_hw
->unit
);
1916 phy_bw_clkbits
= wlc_phy_clk_bwbits(wlc_hw
->band
->pi
);
1918 /* Specific reset sequence required for NPHY rev 3 and 4 */
1919 if (WLCISNPHY(wlc_hw
->band
) && NREV_GE(wlc_hw
->band
->phyrev
, 3) &&
1920 NREV_LE(wlc_hw
->band
->phyrev
, 4)) {
1921 /* Set the PHY bandwidth */
1922 si_core_cflags(wlc_hw
->sih
, SICF_BWMASK
, phy_bw_clkbits
);
1926 /* Perform a soft reset of the PHY PLL */
1927 wlc_bmac_core_phypll_reset(wlc_hw
);
1930 si_core_cflags(wlc_hw
->sih
, (SICF_PRST
| SICF_PCLKE
),
1931 (SICF_PRST
| SICF_PCLKE
));
1932 phy_in_reset
= true;
1935 si_core_cflags(wlc_hw
->sih
,
1936 (SICF_PRST
| SICF_PCLKE
| SICF_BWMASK
),
1937 (SICF_PRST
| SICF_PCLKE
| phy_bw_clkbits
));
1941 wlc_bmac_core_phy_clk(wlc_hw
, ON
);
1944 wlc_phy_anacore(pih
, ON
);
1947 /* switch to and initialize new band */
1949 WLBANDINITFN(wlc_bmac_setband
) (struct wlc_hw_info
*wlc_hw
, uint bandunit
,
1950 chanspec_t chanspec
) {
1951 struct wlc_info
*wlc
= wlc_hw
->wlc
;
1954 ASSERT(NBANDS_HW(wlc_hw
) > 1);
1955 ASSERT(bandunit
!= wlc_hw
->band
->bandunit
);
1957 /* Enable the d11 core before accessing it */
1958 if (!si_iscoreup(wlc_hw
->sih
)) {
1959 si_core_reset(wlc_hw
->sih
, 0, 0);
1960 ASSERT(si_iscoreup(wlc_hw
->sih
));
1961 wlc_mctrl_reset(wlc_hw
);
1964 macintmask
= wlc_setband_inact(wlc
, bandunit
);
1969 wlc_bmac_core_phy_clk(wlc_hw
, ON
);
1971 /* band-specific initializations */
1972 wlc_bmac_bsinit(wlc
, chanspec
);
1975 * If there are any pending software interrupt bits,
1976 * then replace these with a harmless nonzero value
1977 * so wlc_dpc() will re-enable interrupts when done.
1979 if (wlc
->macintstatus
)
1980 wlc
->macintstatus
= MI_DMAINT
;
1982 /* restore macintmask */
1983 wl_intrsrestore(wlc
->wl
, macintmask
);
1985 /* ucode should still be suspended.. */
1986 ASSERT((R_REG(&wlc_hw
->regs
->maccontrol
) & MCTL_EN_MAC
) ==
1990 /* low-level band switch utility routine */
1991 void WLBANDINITFN(wlc_setxband
) (struct wlc_hw_info
*wlc_hw
, uint bandunit
)
1993 WL_TRACE("wl%d: wlc_setxband: bandunit %d\n", wlc_hw
->unit
, bandunit
);
1995 wlc_hw
->band
= wlc_hw
->bandstate
[bandunit
];
1997 /* BMAC_NOTE: until we eliminate need for wlc->band refs in low level code */
1998 wlc_hw
->wlc
->band
= wlc_hw
->wlc
->bandstate
[bandunit
];
2000 /* set gmode core flag */
2001 if (wlc_hw
->sbclk
&& !wlc_hw
->noreset
) {
2002 si_core_cflags(wlc_hw
->sih
, SICF_GMODE
,
2003 ((bandunit
== 0) ? SICF_GMODE
: 0));
2007 static bool wlc_isgoodchip(struct wlc_hw_info
*wlc_hw
)
2010 /* reject unsupported corerev */
2011 if (!VALID_COREREV(wlc_hw
->corerev
)) {
2012 WL_ERROR("unsupported core rev %d\n", wlc_hw
->corerev
);
2019 static bool wlc_validboardtype(struct wlc_hw_info
*wlc_hw
)
2021 bool goodboard
= true;
2022 uint boardrev
= wlc_hw
->boardrev
;
2026 else if (boardrev
> 0xff) {
2027 uint brt
= (boardrev
& 0xf000) >> 12;
2028 uint b0
= (boardrev
& 0xf00) >> 8;
2029 uint b1
= (boardrev
& 0xf0) >> 4;
2030 uint b2
= boardrev
& 0xf;
2032 if ((brt
> 2) || (brt
== 0) || (b0
> 9) || (b0
== 0) || (b1
> 9)
2037 if (wlc_hw
->sih
->boardvendor
!= VENDOR_BROADCOM
)
2043 static char *wlc_get_macaddr(struct wlc_hw_info
*wlc_hw
)
2045 const char *varname
= "macaddr";
2048 /* If macaddr exists, use it (Sromrev4, CIS, ...). */
2049 macaddr
= getvar(wlc_hw
->vars
, varname
);
2050 if (macaddr
!= NULL
)
2053 if (NBANDS_HW(wlc_hw
) > 1)
2054 varname
= "et1macaddr";
2056 varname
= "il0macaddr";
2058 macaddr
= getvar(wlc_hw
->vars
, varname
);
2059 if (macaddr
== NULL
) {
2060 WL_ERROR("wl%d: wlc_get_macaddr: macaddr getvar(%s) not found\n",
2061 wlc_hw
->unit
, varname
);
2068 * Return true if radio is disabled, otherwise false.
2069 * hw radio disable signal is an external pin, users activate it asynchronously
2070 * this function could be called when driver is down and w/o clock
2071 * it operates on different registers depending on corerev and boardflag.
2073 bool wlc_bmac_radio_read_hwdisabled(struct wlc_hw_info
*wlc_hw
)
2076 u32 resetbits
= 0, flags
= 0;
2078 xtal
= wlc_hw
->sbclk
;
2080 wlc_bmac_xtal(wlc_hw
, ON
);
2082 /* may need to take core out of reset first */
2086 * mac no longer enables phyclk automatically when driver
2087 * accesses phyreg throughput mac. This can be skipped since
2088 * only mac reg is accessed below
2090 flags
|= SICF_PCLKE
;
2092 /* AI chip doesn't restore bar0win2 on hibernation/resume, need sw fixup */
2093 if ((wlc_hw
->sih
->chip
== BCM43224_CHIP_ID
) ||
2094 (wlc_hw
->sih
->chip
== BCM43225_CHIP_ID
) ||
2095 (wlc_hw
->sih
->chip
== BCM43421_CHIP_ID
))
2097 (d11regs_t
*) si_setcore(wlc_hw
->sih
, D11_CORE_ID
,
2099 si_core_reset(wlc_hw
->sih
, flags
, resetbits
);
2100 wlc_mctrl_reset(wlc_hw
);
2103 v
= ((R_REG(&wlc_hw
->regs
->phydebug
) & PDBG_RFD
) != 0);
2105 /* put core back into reset */
2107 si_core_disable(wlc_hw
->sih
, 0);
2110 wlc_bmac_xtal(wlc_hw
, OFF
);
2115 /* Initialize just the hardware when coming out of POR or S3/S5 system states */
2116 void wlc_bmac_hw_up(struct wlc_hw_info
*wlc_hw
)
2118 if (wlc_hw
->wlc
->pub
->hw_up
)
2121 WL_TRACE("wl%d: %s:\n", wlc_hw
->unit
, __func__
);
2124 * Enable pll and xtal, initialize the power control registers,
2125 * and force fastclock for the remainder of wlc_up().
2127 wlc_bmac_xtal(wlc_hw
, ON
);
2128 si_clkctl_init(wlc_hw
->sih
);
2129 wlc_clkctl_clk(wlc_hw
, CLK_FAST
);
2131 if (wlc_hw
->sih
->bustype
== PCI_BUS
) {
2132 si_pci_fixcfg(wlc_hw
->sih
);
2134 /* AI chip doesn't restore bar0win2 on hibernation/resume, need sw fixup */
2135 if ((wlc_hw
->sih
->chip
== BCM43224_CHIP_ID
) ||
2136 (wlc_hw
->sih
->chip
== BCM43225_CHIP_ID
) ||
2137 (wlc_hw
->sih
->chip
== BCM43421_CHIP_ID
))
2139 (d11regs_t
*) si_setcore(wlc_hw
->sih
, D11_CORE_ID
,
2143 /* Inform phy that a POR reset has occurred so it does a complete phy init */
2144 wlc_phy_por_inform(wlc_hw
->band
->pi
);
2146 wlc_hw
->ucode_loaded
= false;
2147 wlc_hw
->wlc
->pub
->hw_up
= true;
2149 if ((wlc_hw
->boardflags
& BFL_FEM
)
2150 && (wlc_hw
->sih
->chip
== BCM4313_CHIP_ID
)) {
2152 (wlc_hw
->boardrev
>= 0x1250
2153 && (wlc_hw
->boardflags
& BFL_FEM_BT
)))
2154 si_epa_4313war(wlc_hw
->sih
);
2158 static bool wlc_dma_rxreset(struct wlc_hw_info
*wlc_hw
, uint fifo
)
2160 struct hnddma_pub
*di
= wlc_hw
->di
[fifo
];
2161 return dma_rxreset(di
);
2165 * ensure fask clock during reset
2167 * reset d11(out of reset)
2168 * reset phy(out of reset)
2169 * clear software macintstatus for fresh new start
2170 * one testing hack wlc_hw->noreset will bypass the d11/phy reset
2172 void wlc_bmac_corereset(struct wlc_hw_info
*wlc_hw
, u32 flags
)
2179 if (flags
== WLC_USE_COREFLAGS
)
2180 flags
= (wlc_hw
->band
->pi
? wlc_hw
->band
->core_flags
: 0);
2182 WL_TRACE("wl%d: %s\n", wlc_hw
->unit
, __func__
);
2184 regs
= wlc_hw
->regs
;
2186 /* request FAST clock if not on */
2187 fastclk
= wlc_hw
->forcefastclk
;
2189 wlc_clkctl_clk(wlc_hw
, CLK_FAST
);
2191 /* reset the dma engines except first time thru */
2192 if (si_iscoreup(wlc_hw
->sih
)) {
2193 for (i
= 0; i
< NFIFO
; i
++)
2194 if ((wlc_hw
->di
[i
]) && (!dma_txreset(wlc_hw
->di
[i
]))) {
2195 WL_ERROR("wl%d: %s: dma_txreset[%d]: cannot stop dma\n",
2196 wlc_hw
->unit
, __func__
, i
);
2199 if ((wlc_hw
->di
[RX_FIFO
])
2200 && (!wlc_dma_rxreset(wlc_hw
, RX_FIFO
))) {
2201 WL_ERROR("wl%d: %s: dma_rxreset[%d]: cannot stop dma\n",
2202 wlc_hw
->unit
, __func__
, RX_FIFO
);
2205 /* if noreset, just stop the psm and return */
2206 if (wlc_hw
->noreset
) {
2207 wlc_hw
->wlc
->macintstatus
= 0; /* skip wl_dpc after down */
2208 wlc_bmac_mctrl(wlc_hw
, MCTL_PSM_RUN
| MCTL_EN_MAC
, 0);
2213 * mac no longer enables phyclk automatically when driver accesses
2214 * phyreg throughput mac, AND phy_reset is skipped at early stage when
2215 * band->pi is invalid. need to enable PHY CLK
2217 flags
|= SICF_PCLKE
;
2220 * In chips with PMU, the fastclk request goes through d11 core reg 0x1e0, which
2221 * is cleared by the core_reset. have to re-request it.
2222 * This adds some delay and we can optimize it by also requesting fastclk through
2223 * chipcommon during this period if necessary. But that has to work coordinate
2224 * with other driver like mips/arm since they may touch chipcommon as well.
2226 wlc_hw
->clk
= false;
2227 si_core_reset(wlc_hw
->sih
, flags
, resetbits
);
2229 if (wlc_hw
->band
&& wlc_hw
->band
->pi
)
2230 wlc_phy_hw_clk_state_upd(wlc_hw
->band
->pi
, true);
2232 wlc_mctrl_reset(wlc_hw
);
2234 if (PMUCTL_ENAB(wlc_hw
->sih
))
2235 wlc_clkctl_clk(wlc_hw
, CLK_FAST
);
2237 wlc_bmac_phy_reset(wlc_hw
);
2239 /* turn on PHY_PLL */
2240 wlc_bmac_core_phypll_ctl(wlc_hw
, true);
2242 /* clear sw intstatus */
2243 wlc_hw
->wlc
->macintstatus
= 0;
2245 /* restore the clk setting */
2247 wlc_clkctl_clk(wlc_hw
, CLK_DYNAMIC
);
2250 /* txfifo sizes needs to be modified(increased) since the newer cores
2253 static void wlc_corerev_fifofixup(struct wlc_hw_info
*wlc_hw
)
2255 d11regs_t
*regs
= wlc_hw
->regs
;
2257 u16 txfifo_startblk
= TXFIFO_START_BLK
, txfifo_endblk
;
2258 u16 txfifo_def
, txfifo_def1
;
2261 /* tx fifos start at TXFIFO_START_BLK from the Base address */
2262 txfifo_startblk
= TXFIFO_START_BLK
;
2264 /* sequence of operations: reset fifo, set fifo size, reset fifo */
2265 for (fifo_nu
= 0; fifo_nu
< NFIFO
; fifo_nu
++) {
2267 txfifo_endblk
= txfifo_startblk
+ wlc_hw
->xmtfifo_sz
[fifo_nu
];
2268 txfifo_def
= (txfifo_startblk
& 0xff) |
2269 (((txfifo_endblk
- 1) & 0xff) << TXFIFO_FIFOTOP_SHIFT
);
2270 txfifo_def1
= ((txfifo_startblk
>> 8) & 0x1) |
2272 1) >> 8) & 0x1) << TXFIFO_FIFOTOP_SHIFT
);
2274 TXFIFOCMD_RESET_MASK
| (fifo_nu
<< TXFIFOCMD_FIFOSEL_SHIFT
);
2276 W_REG(®s
->xmtfifocmd
, txfifo_cmd
);
2277 W_REG(®s
->xmtfifodef
, txfifo_def
);
2278 W_REG(®s
->xmtfifodef1
, txfifo_def1
);
2280 W_REG(®s
->xmtfifocmd
, txfifo_cmd
);
2282 txfifo_startblk
+= wlc_hw
->xmtfifo_sz
[fifo_nu
];
2285 * need to propagate to shm location to be in sync since ucode/hw won't
2288 wlc_bmac_write_shm(wlc_hw
, M_FIFOSIZE0
,
2289 wlc_hw
->xmtfifo_sz
[TX_AC_BE_FIFO
]);
2290 wlc_bmac_write_shm(wlc_hw
, M_FIFOSIZE1
,
2291 wlc_hw
->xmtfifo_sz
[TX_AC_VI_FIFO
]);
2292 wlc_bmac_write_shm(wlc_hw
, M_FIFOSIZE2
,
2293 ((wlc_hw
->xmtfifo_sz
[TX_AC_VO_FIFO
] << 8) | wlc_hw
->
2294 xmtfifo_sz
[TX_AC_BK_FIFO
]));
2295 wlc_bmac_write_shm(wlc_hw
, M_FIFOSIZE3
,
2296 ((wlc_hw
->xmtfifo_sz
[TX_ATIM_FIFO
] << 8) | wlc_hw
->
2297 xmtfifo_sz
[TX_BCMC_FIFO
]));
2302 * download ucode/PCM
2303 * let ucode run to suspended
2304 * download ucode inits
2305 * config other core registers
2308 static void wlc_coreinit(struct wlc_info
*wlc
)
2310 struct wlc_hw_info
*wlc_hw
= wlc
->hw
;
2315 bool fifosz_fixup
= false;
2319 regs
= wlc_hw
->regs
;
2321 WL_TRACE("wl%d: wlc_coreinit\n", wlc_hw
->unit
);
2324 wlc_bmac_mctrl(wlc_hw
, ~0, (MCTL_IHR_EN
| MCTL_PSM_JMP_0
| MCTL_WAKE
));
2326 wlc_ucode_download(wlc_hw
);
2328 * FIFOSZ fixup. driver wants to controls the fifo allocation.
2330 fifosz_fixup
= true;
2332 /* let the PSM run to the suspended state, set mode to BSS STA */
2333 W_REG(®s
->macintstatus
, -1);
2334 wlc_bmac_mctrl(wlc_hw
, ~0,
2335 (MCTL_IHR_EN
| MCTL_INFRA
| MCTL_PSM_RUN
| MCTL_WAKE
));
2337 /* wait for ucode to self-suspend after auto-init */
2338 SPINWAIT(((R_REG(®s
->macintstatus
) & MI_MACSSPNDD
) == 0),
2340 if ((R_REG(®s
->macintstatus
) & MI_MACSSPNDD
) == 0)
2341 WL_ERROR("wl%d: wlc_coreinit: ucode did not self-suspend!\n",
2346 sflags
= si_core_sflags(wlc_hw
->sih
, 0, 0);
2348 if (D11REV_IS(wlc_hw
->corerev
, 23)) {
2349 if (WLCISNPHY(wlc_hw
->band
))
2350 wlc_write_inits(wlc_hw
, d11n0initvals16
);
2352 WL_ERROR("%s: wl%d: unsupported phy in corerev %d\n",
2353 __func__
, wlc_hw
->unit
, wlc_hw
->corerev
);
2354 } else if (D11REV_IS(wlc_hw
->corerev
, 24)) {
2355 if (WLCISLCNPHY(wlc_hw
->band
)) {
2356 wlc_write_inits(wlc_hw
, d11lcn0initvals24
);
2358 WL_ERROR("%s: wl%d: unsupported phy in corerev %d\n",
2359 __func__
, wlc_hw
->unit
, wlc_hw
->corerev
);
2362 WL_ERROR("%s: wl%d: unsupported corerev %d\n",
2363 __func__
, wlc_hw
->unit
, wlc_hw
->corerev
);
2366 /* For old ucode, txfifo sizes needs to be modified(increased) */
2367 if (fifosz_fixup
== true) {
2368 wlc_corerev_fifofixup(wlc_hw
);
2371 /* check txfifo allocations match between ucode and driver */
2372 buf
[TX_AC_BE_FIFO
] = wlc_bmac_read_shm(wlc_hw
, M_FIFOSIZE0
);
2373 if (buf
[TX_AC_BE_FIFO
] != wlc_hw
->xmtfifo_sz
[TX_AC_BE_FIFO
]) {
2377 buf
[TX_AC_VI_FIFO
] = wlc_bmac_read_shm(wlc_hw
, M_FIFOSIZE1
);
2378 if (buf
[TX_AC_VI_FIFO
] != wlc_hw
->xmtfifo_sz
[TX_AC_VI_FIFO
]) {
2382 buf
[TX_AC_BK_FIFO
] = wlc_bmac_read_shm(wlc_hw
, M_FIFOSIZE2
);
2383 buf
[TX_AC_VO_FIFO
] = (buf
[TX_AC_BK_FIFO
] >> 8) & 0xff;
2384 buf
[TX_AC_BK_FIFO
] &= 0xff;
2385 if (buf
[TX_AC_BK_FIFO
] != wlc_hw
->xmtfifo_sz
[TX_AC_BK_FIFO
]) {
2389 if (buf
[TX_AC_VO_FIFO
] != wlc_hw
->xmtfifo_sz
[TX_AC_VO_FIFO
]) {
2393 buf
[TX_BCMC_FIFO
] = wlc_bmac_read_shm(wlc_hw
, M_FIFOSIZE3
);
2394 buf
[TX_ATIM_FIFO
] = (buf
[TX_BCMC_FIFO
] >> 8) & 0xff;
2395 buf
[TX_BCMC_FIFO
] &= 0xff;
2396 if (buf
[TX_BCMC_FIFO
] != wlc_hw
->xmtfifo_sz
[TX_BCMC_FIFO
]) {
2400 if (buf
[TX_ATIM_FIFO
] != wlc_hw
->xmtfifo_sz
[TX_ATIM_FIFO
]) {
2405 WL_ERROR("wlc_coreinit: txfifo mismatch: ucode size %d driver size %d index %d\n",
2406 buf
[i
], wlc_hw
->xmtfifo_sz
[i
], i
);
2410 /* make sure we can still talk to the mac */
2411 ASSERT(R_REG(®s
->maccontrol
) != 0xffffffff);
2413 /* band-specific inits done by wlc_bsinit() */
2415 /* Set up frame burst size and antenna swap threshold init values */
2416 wlc_bmac_write_shm(wlc_hw
, M_MBURST_SIZE
, MAXTXFRAMEBURST
);
2417 wlc_bmac_write_shm(wlc_hw
, M_MAX_ANTCNT
, ANTCNT
);
2419 /* enable one rx interrupt per received frame */
2420 W_REG(®s
->intrcvlazy
[0], (1 << IRL_FC_SHIFT
));
2422 /* set the station mode (BSS STA) */
2423 wlc_bmac_mctrl(wlc_hw
,
2424 (MCTL_INFRA
| MCTL_DISCARD_PMQ
| MCTL_AP
),
2425 (MCTL_INFRA
| MCTL_DISCARD_PMQ
));
2427 /* set up Beacon interval */
2428 bcnint_us
= 0x8000 << 10;
2429 W_REG(®s
->tsf_cfprep
, (bcnint_us
<< CFPREP_CBI_SHIFT
));
2430 W_REG(®s
->tsf_cfpstart
, bcnint_us
);
2431 W_REG(®s
->macintstatus
, MI_GP1
);
2433 /* write interrupt mask */
2434 W_REG(®s
->intctrlregs
[RX_FIFO
].intmask
, DEF_RXINTMASK
);
2436 /* allow the MAC to control the PHY clock (dynamic on/off) */
2437 wlc_bmac_macphyclk_set(wlc_hw
, ON
);
2439 /* program dynamic clock control fast powerup delay register */
2440 wlc
->fastpwrup_dly
= si_clkctl_fast_pwrup_delay(wlc_hw
->sih
);
2441 W_REG(®s
->scc_fastpwrup_dly
, wlc
->fastpwrup_dly
);
2443 /* tell the ucode the corerev */
2444 wlc_bmac_write_shm(wlc_hw
, M_MACHW_VER
, (u16
) wlc_hw
->corerev
);
2446 /* tell the ucode MAC capabilities */
2447 wlc_bmac_write_shm(wlc_hw
, M_MACHW_CAP_L
,
2448 (u16
) (wlc_hw
->machwcap
& 0xffff));
2449 wlc_bmac_write_shm(wlc_hw
, M_MACHW_CAP_H
,
2451 machwcap
>> 16) & 0xffff));
2453 /* write retry limits to SCR, this done after PSM init */
2454 W_REG(®s
->objaddr
, OBJADDR_SCR_SEL
| S_DOT11_SRC_LMT
);
2455 (void)R_REG(®s
->objaddr
);
2456 W_REG(®s
->objdata
, wlc_hw
->SRL
);
2457 W_REG(®s
->objaddr
, OBJADDR_SCR_SEL
| S_DOT11_LRC_LMT
);
2458 (void)R_REG(®s
->objaddr
);
2459 W_REG(®s
->objdata
, wlc_hw
->LRL
);
2461 /* write rate fallback retry limits */
2462 wlc_bmac_write_shm(wlc_hw
, M_SFRMTXCNTFBRTHSD
, wlc_hw
->SFBL
);
2463 wlc_bmac_write_shm(wlc_hw
, M_LFRMTXCNTFBRTHSD
, wlc_hw
->LFBL
);
2465 AND_REG(®s
->ifs_ctl
, 0x0FFF);
2466 W_REG(®s
->ifs_aifsn
, EDCF_AIFSN_MIN
);
2468 /* dma initializations */
2469 wlc
->txpend16165war
= 0;
2471 /* init the tx dma engines */
2472 for (i
= 0; i
< NFIFO
; i
++) {
2474 dma_txinit(wlc_hw
->di
[i
]);
2477 /* init the rx dma engine(s) and post receive buffers */
2478 dma_rxinit(wlc_hw
->di
[RX_FIFO
]);
2479 dma_rxfill(wlc_hw
->di
[RX_FIFO
]);
2482 /* This function is used for changing the tsf frac register
2483 * If spur avoidance mode is off, the mac freq will be 80/120/160Mhz
2484 * If spur avoidance mode is on1, the mac freq will be 82/123/164Mhz
2485 * If spur avoidance mode is on2, the mac freq will be 84/126/168Mhz
2486 * HTPHY Formula is 2^26/freq(MHz) e.g.
2487 * For spuron2 - 126MHz -> 2^26/126 = 532610.0
2488 * - 532610 = 0x82082 => tsf_clk_frac_h = 0x8, tsf_clk_frac_l = 0x2082
2489 * For spuron: 123MHz -> 2^26/123 = 545600.5
2490 * - 545601 = 0x85341 => tsf_clk_frac_h = 0x8, tsf_clk_frac_l = 0x5341
2491 * For spur off: 120MHz -> 2^26/120 = 559240.5
2492 * - 559241 = 0x88889 => tsf_clk_frac_h = 0x8, tsf_clk_frac_l = 0x8889
2495 void wlc_bmac_switch_macfreq(struct wlc_hw_info
*wlc_hw
, u8 spurmode
)
2498 regs
= wlc_hw
->regs
;
2500 if ((wlc_hw
->sih
->chip
== BCM43224_CHIP_ID
) ||
2501 (wlc_hw
->sih
->chip
== BCM43225_CHIP_ID
)) {
2502 if (spurmode
== WL_SPURAVOID_ON2
) { /* 126Mhz */
2503 W_REG(®s
->tsf_clk_frac_l
, 0x2082);
2504 W_REG(®s
->tsf_clk_frac_h
, 0x8);
2505 } else if (spurmode
== WL_SPURAVOID_ON1
) { /* 123Mhz */
2506 W_REG(®s
->tsf_clk_frac_l
, 0x5341);
2507 W_REG(®s
->tsf_clk_frac_h
, 0x8);
2508 } else { /* 120Mhz */
2509 W_REG(®s
->tsf_clk_frac_l
, 0x8889);
2510 W_REG(®s
->tsf_clk_frac_h
, 0x8);
2512 } else if (WLCISLCNPHY(wlc_hw
->band
)) {
2513 if (spurmode
== WL_SPURAVOID_ON1
) { /* 82Mhz */
2514 W_REG(®s
->tsf_clk_frac_l
, 0x7CE0);
2515 W_REG(®s
->tsf_clk_frac_h
, 0xC);
2516 } else { /* 80Mhz */
2517 W_REG(®s
->tsf_clk_frac_l
, 0xCCCD);
2518 W_REG(®s
->tsf_clk_frac_h
, 0xC);
2523 /* Initialize GPIOs that are controlled by D11 core */
2524 static void wlc_gpio_init(struct wlc_info
*wlc
)
2526 struct wlc_hw_info
*wlc_hw
= wlc
->hw
;
2530 regs
= wlc_hw
->regs
;
2532 /* use GPIO select 0 to get all gpio signals from the gpio out reg */
2533 wlc_bmac_mctrl(wlc_hw
, MCTL_GPOUT_SEL_MASK
, 0);
2536 * Common GPIO setup:
2537 * G0 = LED 0 = WLAN Activity
2538 * G1 = LED 1 = WLAN 2.4 GHz Radio State
2539 * G2 = LED 2 = WLAN 5 GHz Radio State
2540 * G4 = radio disable input (HI enabled, LO disabled)
2545 /* Allocate GPIOs for mimo antenna diversity feature */
2546 if (wlc_hw
->antsel_type
== ANTSEL_2x3
) {
2547 /* Enable antenna diversity, use 2x3 mode */
2548 wlc_bmac_mhf(wlc_hw
, MHF3
, MHF3_ANTSEL_EN
,
2549 MHF3_ANTSEL_EN
, WLC_BAND_ALL
);
2550 wlc_bmac_mhf(wlc_hw
, MHF3
, MHF3_ANTSEL_MODE
,
2551 MHF3_ANTSEL_MODE
, WLC_BAND_ALL
);
2553 /* init superswitch control */
2554 wlc_phy_antsel_init(wlc_hw
->band
->pi
, false);
2556 } else if (wlc_hw
->antsel_type
== ANTSEL_2x4
) {
2557 ASSERT((gm
& BOARD_GPIO_12
) == 0);
2558 gm
|= gc
|= (BOARD_GPIO_12
| BOARD_GPIO_13
);
2560 * The board itself is powered by these GPIOs
2561 * (when not sending pattern) so set them high
2563 OR_REG(®s
->psm_gpio_oe
,
2564 (BOARD_GPIO_12
| BOARD_GPIO_13
));
2565 OR_REG(®s
->psm_gpio_out
,
2566 (BOARD_GPIO_12
| BOARD_GPIO_13
));
2568 /* Enable antenna diversity, use 2x4 mode */
2569 wlc_bmac_mhf(wlc_hw
, MHF3
, MHF3_ANTSEL_EN
,
2570 MHF3_ANTSEL_EN
, WLC_BAND_ALL
);
2571 wlc_bmac_mhf(wlc_hw
, MHF3
, MHF3_ANTSEL_MODE
, 0,
2574 /* Configure the desired clock to be 4Mhz */
2575 wlc_bmac_write_shm(wlc_hw
, M_ANTSEL_CLKDIV
,
2576 ANTSEL_CLKDIV_4MHZ
);
2579 /* gpio 9 controls the PA. ucode is responsible for wiggling out and oe */
2580 if (wlc_hw
->boardflags
& BFL_PACTRL
)
2581 gm
|= gc
|= BOARD_GPIO_PACTRL
;
2583 /* apply to gpiocontrol register */
2584 si_gpiocontrol(wlc_hw
->sih
, gm
, gc
, GPIO_DRV_PRIORITY
);
2587 static void wlc_ucode_download(struct wlc_hw_info
*wlc_hw
)
2589 struct wlc_info
*wlc
;
2592 if (wlc_hw
->ucode_loaded
)
2595 if (D11REV_IS(wlc_hw
->corerev
, 23)) {
2596 if (WLCISNPHY(wlc_hw
->band
)) {
2597 wlc_ucode_write(wlc_hw
, bcm43xx_16_mimo
,
2599 wlc_hw
->ucode_loaded
= true;
2601 WL_ERROR("%s: wl%d: unsupported phy in corerev %d\n",
2602 __func__
, wlc_hw
->unit
, wlc_hw
->corerev
);
2603 } else if (D11REV_IS(wlc_hw
->corerev
, 24)) {
2604 if (WLCISLCNPHY(wlc_hw
->band
)) {
2605 wlc_ucode_write(wlc_hw
, bcm43xx_24_lcn
,
2607 wlc_hw
->ucode_loaded
= true;
2609 WL_ERROR("%s: wl%d: unsupported phy in corerev %d\n",
2610 __func__
, wlc_hw
->unit
, wlc_hw
->corerev
);
2615 static void wlc_ucode_write(struct wlc_hw_info
*wlc_hw
, const u32 ucode
[],
2616 const uint nbytes
) {
2617 d11regs_t
*regs
= wlc_hw
->regs
;
2621 WL_TRACE("wl%d: wlc_ucode_write\n", wlc_hw
->unit
);
2623 ASSERT(IS_ALIGNED(nbytes
, sizeof(u32
)));
2625 count
= (nbytes
/ sizeof(u32
));
2627 W_REG(®s
->objaddr
, (OBJADDR_AUTO_INC
| OBJADDR_UCM_SEL
));
2628 (void)R_REG(®s
->objaddr
);
2629 for (i
= 0; i
< count
; i
++)
2630 W_REG(®s
->objdata
, ucode
[i
]);
2633 static void wlc_write_inits(struct wlc_hw_info
*wlc_hw
,
2634 const struct d11init
*inits
)
2639 WL_TRACE("wl%d: wlc_write_inits\n", wlc_hw
->unit
);
2641 base
= (volatile u8
*)wlc_hw
->regs
;
2643 for (i
= 0; inits
[i
].addr
!= 0xffff; i
++) {
2644 ASSERT((inits
[i
].size
== 2) || (inits
[i
].size
== 4));
2646 if (inits
[i
].size
== 2)
2647 W_REG((u16
*)(base
+ inits
[i
].addr
),
2649 else if (inits
[i
].size
== 4)
2650 W_REG((u32
*)(base
+ inits
[i
].addr
),
2655 static void wlc_ucode_txant_set(struct wlc_hw_info
*wlc_hw
)
2658 u16 phytxant
= wlc_hw
->bmac_phytxant
;
2659 u16 mask
= PHY_TXC_ANT_MASK
;
2661 /* set the Probe Response frame phy control word */
2662 phyctl
= wlc_bmac_read_shm(wlc_hw
, M_CTXPRS_BLK
+ C_CTX_PCTLWD_POS
);
2663 phyctl
= (phyctl
& ~mask
) | phytxant
;
2664 wlc_bmac_write_shm(wlc_hw
, M_CTXPRS_BLK
+ C_CTX_PCTLWD_POS
, phyctl
);
2666 /* set the Response (ACK/CTS) frame phy control word */
2667 phyctl
= wlc_bmac_read_shm(wlc_hw
, M_RSP_PCTLWD
);
2668 phyctl
= (phyctl
& ~mask
) | phytxant
;
2669 wlc_bmac_write_shm(wlc_hw
, M_RSP_PCTLWD
, phyctl
);
2672 void wlc_bmac_txant_set(struct wlc_hw_info
*wlc_hw
, u16 phytxant
)
2674 /* update sw state */
2675 wlc_hw
->bmac_phytxant
= phytxant
;
2677 /* push to ucode if up */
2680 wlc_ucode_txant_set(wlc_hw
);
2684 u16
wlc_bmac_get_txant(struct wlc_hw_info
*wlc_hw
)
2686 return (u16
) wlc_hw
->wlc
->stf
->txant
;
2689 void wlc_bmac_antsel_type_set(struct wlc_hw_info
*wlc_hw
, u8 antsel_type
)
2691 wlc_hw
->antsel_type
= antsel_type
;
2693 /* Update the antsel type for phy module to use */
2694 wlc_phy_antsel_type_set(wlc_hw
->band
->pi
, antsel_type
);
2697 void wlc_bmac_fifoerrors(struct wlc_hw_info
*wlc_hw
)
2701 uint intstatus
, idx
;
2702 d11regs_t
*regs
= wlc_hw
->regs
;
2704 unit
= wlc_hw
->unit
;
2706 for (idx
= 0; idx
< NFIFO
; idx
++) {
2707 /* read intstatus register and ignore any non-error bits */
2709 R_REG(®s
->intctrlregs
[idx
].intstatus
) & I_ERRORS
;
2713 WL_TRACE("wl%d: wlc_bmac_fifoerrors: intstatus%d 0x%x\n",
2714 unit
, idx
, intstatus
);
2716 if (intstatus
& I_RO
) {
2717 WL_ERROR("wl%d: fifo %d: receive fifo overflow\n",
2719 wlc_hw
->wlc
->pub
->_cnt
->rxoflo
++;
2723 if (intstatus
& I_PC
) {
2724 WL_ERROR("wl%d: fifo %d: descriptor error\n",
2726 wlc_hw
->wlc
->pub
->_cnt
->dmade
++;
2730 if (intstatus
& I_PD
) {
2731 WL_ERROR("wl%d: fifo %d: data error\n", unit
, idx
);
2732 wlc_hw
->wlc
->pub
->_cnt
->dmada
++;
2736 if (intstatus
& I_DE
) {
2737 WL_ERROR("wl%d: fifo %d: descriptor protocol error\n",
2739 wlc_hw
->wlc
->pub
->_cnt
->dmape
++;
2743 if (intstatus
& I_RU
) {
2744 WL_ERROR("wl%d: fifo %d: receive descriptor underflow\n",
2746 wlc_hw
->wlc
->pub
->_cnt
->rxuflo
[idx
]++;
2749 if (intstatus
& I_XU
) {
2750 WL_ERROR("wl%d: fifo %d: transmit fifo underflow\n",
2752 wlc_hw
->wlc
->pub
->_cnt
->txuflo
++;
2757 wlc_fatal_error(wlc_hw
->wlc
); /* big hammer */
2760 W_REG(®s
->intctrlregs
[idx
].intstatus
,
2765 void wlc_intrson(struct wlc_info
*wlc
)
2767 struct wlc_hw_info
*wlc_hw
= wlc
->hw
;
2768 ASSERT(wlc
->defmacintmask
);
2769 wlc
->macintmask
= wlc
->defmacintmask
;
2770 W_REG(&wlc_hw
->regs
->macintmask
, wlc
->macintmask
);
2773 /* callback for siutils.c, which has only wlc handler, no wl
2774 * they both check up, not only because there is no need to off/restore d11 interrupt
2775 * but also because per-port code may require sync with valid interrupt.
2778 static u32
wlc_wlintrsoff(struct wlc_info
*wlc
)
2783 return wl_intrsoff(wlc
->wl
);
2786 static void wlc_wlintrsrestore(struct wlc_info
*wlc
, u32 macintmask
)
2791 wl_intrsrestore(wlc
->wl
, macintmask
);
2794 u32
wlc_intrsoff(struct wlc_info
*wlc
)
2796 struct wlc_hw_info
*wlc_hw
= wlc
->hw
;
2802 macintmask
= wlc
->macintmask
; /* isr can still happen */
2804 W_REG(&wlc_hw
->regs
->macintmask
, 0);
2805 (void)R_REG(&wlc_hw
->regs
->macintmask
); /* sync readback */
2806 udelay(1); /* ensure int line is no longer driven */
2807 wlc
->macintmask
= 0;
2809 /* return previous macintmask; resolve race between us and our isr */
2810 return wlc
->macintstatus
? 0 : macintmask
;
2813 void wlc_intrsrestore(struct wlc_info
*wlc
, u32 macintmask
)
2815 struct wlc_hw_info
*wlc_hw
= wlc
->hw
;
2819 wlc
->macintmask
= macintmask
;
2820 W_REG(&wlc_hw
->regs
->macintmask
, wlc
->macintmask
);
2823 static void wlc_bmac_mute(struct wlc_hw_info
*wlc_hw
, bool on
, mbool flags
)
2825 u8 null_ether_addr
[ETH_ALEN
] = {0, 0, 0, 0, 0, 0};
2828 /* suspend tx fifos */
2829 wlc_bmac_tx_fifo_suspend(wlc_hw
, TX_DATA_FIFO
);
2830 wlc_bmac_tx_fifo_suspend(wlc_hw
, TX_CTL_FIFO
);
2831 wlc_bmac_tx_fifo_suspend(wlc_hw
, TX_AC_BK_FIFO
);
2832 wlc_bmac_tx_fifo_suspend(wlc_hw
, TX_AC_VI_FIFO
);
2834 /* zero the address match register so we do not send ACKs */
2835 wlc_bmac_set_addrmatch(wlc_hw
, RCM_MAC_OFFSET
,
2838 /* resume tx fifos */
2839 if (!wlc_hw
->wlc
->tx_suspended
) {
2840 wlc_bmac_tx_fifo_resume(wlc_hw
, TX_DATA_FIFO
);
2842 wlc_bmac_tx_fifo_resume(wlc_hw
, TX_CTL_FIFO
);
2843 wlc_bmac_tx_fifo_resume(wlc_hw
, TX_AC_BK_FIFO
);
2844 wlc_bmac_tx_fifo_resume(wlc_hw
, TX_AC_VI_FIFO
);
2846 /* Restore address */
2847 wlc_bmac_set_addrmatch(wlc_hw
, RCM_MAC_OFFSET
,
2851 wlc_phy_mute_upd(wlc_hw
->band
->pi
, on
, flags
);
2854 wlc_ucode_mute_override_set(wlc_hw
);
2856 wlc_ucode_mute_override_clear(wlc_hw
);
2859 int wlc_bmac_xmtfifo_sz_get(struct wlc_hw_info
*wlc_hw
, uint fifo
, uint
*blocks
)
2864 *blocks
= wlc_hw
->xmtfifo_sz
[fifo
];
2869 /* wlc_bmac_tx_fifo_suspended:
2870 * Check the MAC's tx suspend status for a tx fifo.
2872 * When the MAC acknowledges a tx suspend, it indicates that no more
2873 * packets will be transmitted out the radio. This is independent of
2874 * DMA channel suspension---the DMA may have finished suspending, or may still
2875 * be pulling data into a tx fifo, by the time the MAC acks the suspend
2878 static bool wlc_bmac_tx_fifo_suspended(struct wlc_hw_info
*wlc_hw
, uint tx_fifo
)
2880 /* check that a suspend has been requested and is no longer pending */
2883 * for DMA mode, the suspend request is set in xmtcontrol of the DMA engine,
2884 * and the tx fifo suspend at the lower end of the MAC is acknowledged in the
2885 * chnstatus register.
2886 * The tx fifo suspend completion is independent of the DMA suspend completion and
2887 * may be acked before or after the DMA is suspended.
2889 if (dma_txsuspended(wlc_hw
->di
[tx_fifo
]) &&
2890 (R_REG(&wlc_hw
->regs
->chnstatus
) &
2891 (1 << tx_fifo
)) == 0)
2897 static void wlc_bmac_tx_fifo_suspend(struct wlc_hw_info
*wlc_hw
, uint tx_fifo
)
2899 u8 fifo
= 1 << tx_fifo
;
2901 /* Two clients of this code, 11h Quiet period and scanning. */
2903 /* only suspend if not already suspended */
2904 if ((wlc_hw
->suspended_fifos
& fifo
) == fifo
)
2907 /* force the core awake only if not already */
2908 if (wlc_hw
->suspended_fifos
== 0)
2909 wlc_ucode_wake_override_set(wlc_hw
, WLC_WAKE_OVERRIDE_TXFIFO
);
2911 wlc_hw
->suspended_fifos
|= fifo
;
2913 if (wlc_hw
->di
[tx_fifo
]) {
2914 /* Suspending AMPDU transmissions in the middle can cause underflow
2915 * which may result in mismatch between ucode and driver
2916 * so suspend the mac before suspending the FIFO
2918 if (WLC_PHY_11N_CAP(wlc_hw
->band
))
2919 wlc_suspend_mac_and_wait(wlc_hw
->wlc
);
2921 dma_txsuspend(wlc_hw
->di
[tx_fifo
]);
2923 if (WLC_PHY_11N_CAP(wlc_hw
->band
))
2924 wlc_enable_mac(wlc_hw
->wlc
);
2928 static void wlc_bmac_tx_fifo_resume(struct wlc_hw_info
*wlc_hw
, uint tx_fifo
)
2930 /* BMAC_NOTE: WLC_TX_FIFO_ENAB is done in wlc_dpc() for DMA case but need to be done
2931 * here for PIO otherwise the watchdog will catch the inconsistency and fire
2933 /* Two clients of this code, 11h Quiet period and scanning. */
2934 if (wlc_hw
->di
[tx_fifo
])
2935 dma_txresume(wlc_hw
->di
[tx_fifo
]);
2937 /* allow core to sleep again */
2938 if (wlc_hw
->suspended_fifos
== 0)
2941 wlc_hw
->suspended_fifos
&= ~(1 << tx_fifo
);
2942 if (wlc_hw
->suspended_fifos
== 0)
2943 wlc_ucode_wake_override_clear(wlc_hw
,
2944 WLC_WAKE_OVERRIDE_TXFIFO
);
2949 * Read and clear macintmask and macintstatus and intstatus registers.
2950 * This routine should be called with interrupts off
2952 * -1 if DEVICEREMOVED(wlc) evaluates to true;
2953 * 0 if the interrupt is not for us, or we are in some special cases;
2954 * device interrupt status bits otherwise.
2956 static inline u32
wlc_intstatus(struct wlc_info
*wlc
, bool in_isr
)
2958 struct wlc_hw_info
*wlc_hw
= wlc
->hw
;
2959 d11regs_t
*regs
= wlc_hw
->regs
;
2962 /* macintstatus includes a DMA interrupt summary bit */
2963 macintstatus
= R_REG(®s
->macintstatus
);
2965 WL_TRACE("wl%d: macintstatus: 0x%x\n", wlc_hw
->unit
, macintstatus
);
2967 /* detect cardbus removed, in power down(suspend) and in reset */
2968 if (DEVICEREMOVED(wlc
))
2971 /* DEVICEREMOVED succeeds even when the core is still resetting,
2972 * handle that case here.
2974 if (macintstatus
== 0xffffffff)
2977 /* defer unsolicited interrupts */
2978 macintstatus
&= (in_isr
? wlc
->macintmask
: wlc
->defmacintmask
);
2981 if (macintstatus
== 0)
2984 /* interrupts are already turned off for CFE build
2985 * Caution: For CFE Turning off the interrupts again has some undesired
2988 /* turn off the interrupts */
2989 W_REG(®s
->macintmask
, 0);
2990 (void)R_REG(®s
->macintmask
); /* sync readback */
2991 wlc
->macintmask
= 0;
2993 /* clear device interrupts */
2994 W_REG(®s
->macintstatus
, macintstatus
);
2996 /* MI_DMAINT is indication of non-zero intstatus */
2997 if (macintstatus
& MI_DMAINT
) {
2999 * only fifo interrupt enabled is I_RI in
3000 * RX_FIFO. If MI_DMAINT is set, assume it
3001 * is set and clear the interrupt.
3003 W_REG(®s
->intctrlregs
[RX_FIFO
].intstatus
,
3007 return macintstatus
;
3010 /* Update wlc->macintstatus and wlc->intstatus[]. */
3011 /* Return true if they are updated successfully. false otherwise */
3012 bool wlc_intrsupd(struct wlc_info
*wlc
)
3016 ASSERT(wlc
->macintstatus
!= 0);
3018 /* read and clear macintstatus and intstatus registers */
3019 macintstatus
= wlc_intstatus(wlc
, false);
3021 /* device is removed */
3022 if (macintstatus
== 0xffffffff)
3025 /* update interrupt status in software */
3026 wlc
->macintstatus
|= macintstatus
;
3032 * First-level interrupt processing.
3033 * Return true if this was our interrupt, false otherwise.
3034 * *wantdpc will be set to true if further wlc_dpc() processing is required,
3037 bool BCMFASTPATH
wlc_isr(struct wlc_info
*wlc
, bool *wantdpc
)
3039 struct wlc_hw_info
*wlc_hw
= wlc
->hw
;
3044 if (!wlc_hw
->up
|| !wlc
->macintmask
)
3047 /* read and clear macintstatus and intstatus registers */
3048 macintstatus
= wlc_intstatus(wlc
, true);
3050 if (macintstatus
== 0xffffffff)
3051 WL_ERROR("DEVICEREMOVED detected in the ISR code path\n");
3053 /* it is not for us */
3054 if (macintstatus
== 0)
3059 /* save interrupt status bits */
3060 ASSERT(wlc
->macintstatus
== 0);
3061 wlc
->macintstatus
= macintstatus
;
3067 static bool BCMFASTPATH
3068 wlc_bmac_dotxstatus(struct wlc_hw_info
*wlc_hw
, tx_status_t
*txs
, u32 s2
)
3070 /* discard intermediate indications for ucode with one legitimate case:
3071 * e.g. if "useRTS" is set. ucode did a successful rts/cts exchange, but the subsequent
3072 * tx of DATA failed. so it will start rts/cts from the beginning (resetting the rts
3073 * transmission count)
3075 if (!(txs
->status
& TX_STATUS_AMPDU
)
3076 && (txs
->status
& TX_STATUS_INTERMEDIATE
)) {
3080 return wlc_dotxstatus(wlc_hw
->wlc
, txs
, s2
);
3083 /* process tx completion events in BMAC
3084 * Return true if more tx status need to be processed. false otherwise.
3086 static bool BCMFASTPATH
3087 wlc_bmac_txstatus(struct wlc_hw_info
*wlc_hw
, bool bound
, bool *fatal
)
3089 bool morepending
= false;
3090 struct wlc_info
*wlc
= wlc_hw
->wlc
;
3092 tx_status_t txstatus
, *txs
;
3096 * Param 'max_tx_num' indicates max. # tx status to process before
3099 uint max_tx_num
= bound
? wlc
->pub
->tunables
->txsbnd
: -1;
3101 WL_TRACE("wl%d: wlc_bmac_txstatus\n", wlc_hw
->unit
);
3104 regs
= wlc_hw
->regs
;
3106 && (s1
= R_REG(®s
->frmtxstatus
)) & TXS_V
) {
3108 if (s1
== 0xffffffff) {
3109 WL_ERROR("wl%d: %s: dead chip\n",
3110 wlc_hw
->unit
, __func__
);
3111 ASSERT(s1
!= 0xffffffff);
3115 s2
= R_REG(®s
->frmtxstatus2
);
3117 txs
->status
= s1
& TXS_STATUS_MASK
;
3118 txs
->frameid
= (s1
& TXS_FID_MASK
) >> TXS_FID_SHIFT
;
3119 txs
->sequence
= s2
& TXS_SEQ_MASK
;
3120 txs
->phyerr
= (s2
& TXS_PTX_MASK
) >> TXS_PTX_SHIFT
;
3121 txs
->lasttxtime
= 0;
3123 *fatal
= wlc_bmac_dotxstatus(wlc_hw
, txs
, s2
);
3125 /* !give others some time to run! */
3126 if (++n
>= max_tx_num
)
3133 if (n
>= max_tx_num
)
3136 if (!pktq_empty(&wlc
->active_queue
->q
))
3137 wlc_send_q(wlc
, wlc
->active_queue
);
3142 void wlc_suspend_mac_and_wait(struct wlc_info
*wlc
)
3144 struct wlc_hw_info
*wlc_hw
= wlc
->hw
;
3145 d11regs_t
*regs
= wlc_hw
->regs
;
3148 WL_TRACE("wl%d: wlc_suspend_mac_and_wait: bandunit %d\n",
3149 wlc_hw
->unit
, wlc_hw
->band
->bandunit
);
3152 * Track overlapping suspend requests
3154 wlc_hw
->mac_suspend_depth
++;
3155 if (wlc_hw
->mac_suspend_depth
> 1)
3158 /* force the core awake */
3159 wlc_ucode_wake_override_set(wlc_hw
, WLC_WAKE_OVERRIDE_MACSUSPEND
);
3161 mc
= R_REG(®s
->maccontrol
);
3163 if (mc
== 0xffffffff) {
3164 WL_ERROR("wl%d: %s: dead chip\n", wlc_hw
->unit
, __func__
);
3168 ASSERT(!(mc
& MCTL_PSM_JMP_0
));
3169 ASSERT(mc
& MCTL_PSM_RUN
);
3170 ASSERT(mc
& MCTL_EN_MAC
);
3172 mi
= R_REG(®s
->macintstatus
);
3173 if (mi
== 0xffffffff) {
3174 WL_ERROR("wl%d: %s: dead chip\n", wlc_hw
->unit
, __func__
);
3178 ASSERT(!(mi
& MI_MACSSPNDD
));
3180 wlc_bmac_mctrl(wlc_hw
, MCTL_EN_MAC
, 0);
3182 SPINWAIT(!(R_REG(®s
->macintstatus
) & MI_MACSSPNDD
),
3183 WLC_MAX_MAC_SUSPEND
);
3185 if (!(R_REG(®s
->macintstatus
) & MI_MACSSPNDD
)) {
3186 WL_ERROR("wl%d: wlc_suspend_mac_and_wait: waited %d uS and MI_MACSSPNDD is still not on.\n",
3187 wlc_hw
->unit
, WLC_MAX_MAC_SUSPEND
);
3188 WL_ERROR("wl%d: psmdebug 0x%08x, phydebug 0x%08x, psm_brc 0x%04x\n",
3190 R_REG(®s
->psmdebug
),
3191 R_REG(®s
->phydebug
),
3192 R_REG(®s
->psm_brc
));
3195 mc
= R_REG(®s
->maccontrol
);
3196 if (mc
== 0xffffffff) {
3197 WL_ERROR("wl%d: %s: dead chip\n", wlc_hw
->unit
, __func__
);
3201 ASSERT(!(mc
& MCTL_PSM_JMP_0
));
3202 ASSERT(mc
& MCTL_PSM_RUN
);
3203 ASSERT(!(mc
& MCTL_EN_MAC
));
3206 void wlc_enable_mac(struct wlc_info
*wlc
)
3208 struct wlc_hw_info
*wlc_hw
= wlc
->hw
;
3209 d11regs_t
*regs
= wlc_hw
->regs
;
3212 WL_TRACE("wl%d: wlc_enable_mac: bandunit %d\n",
3213 wlc_hw
->unit
, wlc
->band
->bandunit
);
3216 * Track overlapping suspend requests
3218 ASSERT(wlc_hw
->mac_suspend_depth
> 0);
3219 wlc_hw
->mac_suspend_depth
--;
3220 if (wlc_hw
->mac_suspend_depth
> 0)
3223 mc
= R_REG(®s
->maccontrol
);
3224 ASSERT(!(mc
& MCTL_PSM_JMP_0
));
3225 ASSERT(!(mc
& MCTL_EN_MAC
));
3226 ASSERT(mc
& MCTL_PSM_RUN
);
3228 wlc_bmac_mctrl(wlc_hw
, MCTL_EN_MAC
, MCTL_EN_MAC
);
3229 W_REG(®s
->macintstatus
, MI_MACSSPNDD
);
3231 mc
= R_REG(®s
->maccontrol
);
3232 ASSERT(!(mc
& MCTL_PSM_JMP_0
));
3233 ASSERT(mc
& MCTL_EN_MAC
);
3234 ASSERT(mc
& MCTL_PSM_RUN
);
3236 mi
= R_REG(®s
->macintstatus
);
3237 ASSERT(!(mi
& MI_MACSSPNDD
));
3239 wlc_ucode_wake_override_clear(wlc_hw
, WLC_WAKE_OVERRIDE_MACSUSPEND
);
3242 static void wlc_upd_ofdm_pctl1_table(struct wlc_hw_info
*wlc_hw
)
3246 WLC_RATE_6M
, WLC_RATE_9M
, WLC_RATE_12M
, WLC_RATE_18M
,
3247 WLC_RATE_24M
, WLC_RATE_36M
, WLC_RATE_48M
, WLC_RATE_54M
3253 if (!WLC_PHY_11N_CAP(wlc_hw
->band
))
3256 /* walk the phy rate table and update the entries */
3257 for (i
= 0; i
< ARRAY_SIZE(rates
); i
++) {
3260 entry_ptr
= wlc_bmac_ofdm_ratetable_offset(wlc_hw
, rate
);
3262 /* read the SHM Rate Table entry OFDM PCTL1 values */
3264 wlc_bmac_read_shm(wlc_hw
, entry_ptr
+ M_RT_OFDM_PCTL1_POS
);
3266 /* modify the value */
3267 pctl1
&= ~PHY_TXC1_MODE_MASK
;
3268 pctl1
|= (wlc_hw
->hw_stf_ss_opmode
<< PHY_TXC1_MODE_SHIFT
);
3270 /* Update the SHM Rate Table entry OFDM PCTL1 values */
3271 wlc_bmac_write_shm(wlc_hw
, entry_ptr
+ M_RT_OFDM_PCTL1_POS
,
3276 static u16
wlc_bmac_ofdm_ratetable_offset(struct wlc_hw_info
*wlc_hw
, u8 rate
)
3280 struct plcp_signal_rate_lookup
{
3284 /* OFDM RATE sub-field of PLCP SIGNAL field, per 802.11 sec 17.3.4.1 */
3285 const struct plcp_signal_rate_lookup rate_lookup
[] = {
3288 {WLC_RATE_12M
, 0xA},
3289 {WLC_RATE_18M
, 0xE},
3290 {WLC_RATE_24M
, 0x9},
3291 {WLC_RATE_36M
, 0xD},
3292 {WLC_RATE_48M
, 0x8},
3296 for (i
= 0; i
< ARRAY_SIZE(rate_lookup
); i
++) {
3297 if (rate
== rate_lookup
[i
].rate
) {
3298 plcp_rate
= rate_lookup
[i
].signal_rate
;
3303 /* Find the SHM pointer to the rate table entry by looking in the
3306 return 2 * wlc_bmac_read_shm(wlc_hw
, M_RT_DIRMAP_A
+ (plcp_rate
* 2));
3309 void wlc_bmac_band_stf_ss_set(struct wlc_hw_info
*wlc_hw
, u8 stf_mode
)
3311 wlc_hw
->hw_stf_ss_opmode
= stf_mode
;
3314 wlc_upd_ofdm_pctl1_table(wlc_hw
);
3318 wlc_bmac_read_tsf(struct wlc_hw_info
*wlc_hw
, u32
*tsf_l_ptr
,
3321 d11regs_t
*regs
= wlc_hw
->regs
;
3323 /* read the tsf timer low, then high to get an atomic read */
3324 *tsf_l_ptr
= R_REG(®s
->tsf_timerlow
);
3325 *tsf_h_ptr
= R_REG(®s
->tsf_timerhigh
);
3330 static bool wlc_bmac_validate_chip_access(struct wlc_hw_info
*wlc_hw
)
3335 WL_TRACE("wl%d: validate_chip_access\n", wlc_hw
->unit
);
3337 regs
= wlc_hw
->regs
;
3339 /* Validate dchip register access */
3341 W_REG(®s
->objaddr
, OBJADDR_SHM_SEL
| 0);
3342 (void)R_REG(®s
->objaddr
);
3343 w
= R_REG(®s
->objdata
);
3345 /* Can we write and read back a 32bit register? */
3346 W_REG(®s
->objaddr
, OBJADDR_SHM_SEL
| 0);
3347 (void)R_REG(®s
->objaddr
);
3348 W_REG(®s
->objdata
, (u32
) 0xaa5555aa);
3350 W_REG(®s
->objaddr
, OBJADDR_SHM_SEL
| 0);
3351 (void)R_REG(®s
->objaddr
);
3352 val
= R_REG(®s
->objdata
);
3353 if (val
!= (u32
) 0xaa5555aa) {
3354 WL_ERROR("wl%d: validate_chip_access: SHM = 0x%x, expected 0xaa5555aa\n",
3359 W_REG(®s
->objaddr
, OBJADDR_SHM_SEL
| 0);
3360 (void)R_REG(®s
->objaddr
);
3361 W_REG(®s
->objdata
, (u32
) 0x55aaaa55);
3363 W_REG(®s
->objaddr
, OBJADDR_SHM_SEL
| 0);
3364 (void)R_REG(®s
->objaddr
);
3365 val
= R_REG(®s
->objdata
);
3366 if (val
!= (u32
) 0x55aaaa55) {
3367 WL_ERROR("wl%d: validate_chip_access: SHM = 0x%x, expected 0x55aaaa55\n",
3372 W_REG(®s
->objaddr
, OBJADDR_SHM_SEL
| 0);
3373 (void)R_REG(®s
->objaddr
);
3374 W_REG(®s
->objdata
, w
);
3376 /* clear CFPStart */
3377 W_REG(®s
->tsf_cfpstart
, 0);
3379 w
= R_REG(®s
->maccontrol
);
3380 if ((w
!= (MCTL_IHR_EN
| MCTL_WAKE
)) &&
3381 (w
!= (MCTL_IHR_EN
| MCTL_GMODE
| MCTL_WAKE
))) {
3382 WL_ERROR("wl%d: validate_chip_access: maccontrol = 0x%x, expected 0x%x or 0x%x\n",
3384 (MCTL_IHR_EN
| MCTL_WAKE
),
3385 (MCTL_IHR_EN
| MCTL_GMODE
| MCTL_WAKE
));
3392 #define PHYPLL_WAIT_US 100000
3394 void wlc_bmac_core_phypll_ctl(struct wlc_hw_info
*wlc_hw
, bool on
)
3399 WL_TRACE("wl%d: wlc_bmac_core_phypll_ctl\n", wlc_hw
->unit
);
3402 regs
= wlc_hw
->regs
;
3405 if ((wlc_hw
->sih
->chip
== BCM4313_CHIP_ID
)) {
3406 OR_REG(®s
->clk_ctl_st
,
3407 (CCS_ERSRC_REQ_HT
| CCS_ERSRC_REQ_D11PLL
|
3408 CCS_ERSRC_REQ_PHYPLL
));
3409 SPINWAIT((R_REG(®s
->clk_ctl_st
) &
3410 (CCS_ERSRC_AVAIL_HT
)) != (CCS_ERSRC_AVAIL_HT
),
3413 tmp
= R_REG(®s
->clk_ctl_st
);
3414 if ((tmp
& (CCS_ERSRC_AVAIL_HT
)) !=
3415 (CCS_ERSRC_AVAIL_HT
)) {
3416 WL_ERROR("%s: turn on PHY PLL failed\n",
3421 OR_REG(®s
->clk_ctl_st
,
3422 (CCS_ERSRC_REQ_D11PLL
| CCS_ERSRC_REQ_PHYPLL
));
3423 SPINWAIT((R_REG(®s
->clk_ctl_st
) &
3424 (CCS_ERSRC_AVAIL_D11PLL
|
3425 CCS_ERSRC_AVAIL_PHYPLL
)) !=
3426 (CCS_ERSRC_AVAIL_D11PLL
|
3427 CCS_ERSRC_AVAIL_PHYPLL
), PHYPLL_WAIT_US
);
3429 tmp
= R_REG(®s
->clk_ctl_st
);
3431 (CCS_ERSRC_AVAIL_D11PLL
| CCS_ERSRC_AVAIL_PHYPLL
))
3433 (CCS_ERSRC_AVAIL_D11PLL
| CCS_ERSRC_AVAIL_PHYPLL
)) {
3434 WL_ERROR("%s: turn on PHY PLL failed\n",
3440 /* Since the PLL may be shared, other cores can still be requesting it;
3441 * so we'll deassert the request but not wait for status to comply.
3443 AND_REG(®s
->clk_ctl_st
, ~CCS_ERSRC_REQ_PHYPLL
);
3444 tmp
= R_REG(®s
->clk_ctl_st
);
3448 void wlc_coredisable(struct wlc_hw_info
*wlc_hw
)
3452 WL_TRACE("wl%d: %s\n", wlc_hw
->unit
, __func__
);
3454 ASSERT(!wlc_hw
->up
);
3456 dev_gone
= DEVICEREMOVED(wlc_hw
->wlc
);
3461 if (wlc_hw
->noreset
)
3465 wlc_phy_switch_radio(wlc_hw
->band
->pi
, OFF
);
3467 /* turn off analog core */
3468 wlc_phy_anacore(wlc_hw
->band
->pi
, OFF
);
3470 /* turn off PHYPLL to save power */
3471 wlc_bmac_core_phypll_ctl(wlc_hw
, false);
3473 /* No need to set wlc->pub->radio_active = OFF
3474 * because this function needs down capability and
3475 * radio_active is designed for BCMNODOWN.
3478 /* remove gpio controls */
3479 if (wlc_hw
->ucode_dbgsel
)
3480 si_gpiocontrol(wlc_hw
->sih
, ~0, 0, GPIO_DRV_PRIORITY
);
3482 wlc_hw
->clk
= false;
3483 si_core_disable(wlc_hw
->sih
, 0);
3484 wlc_phy_hw_clk_state_upd(wlc_hw
->band
->pi
, false);
3487 /* power both the pll and external oscillator on/off */
3488 static void wlc_bmac_xtal(struct wlc_hw_info
*wlc_hw
, bool want
)
3490 WL_TRACE("wl%d: wlc_bmac_xtal: want %d\n", wlc_hw
->unit
, want
);
3492 /* dont power down if plldown is false or we must poll hw radio disable */
3493 if (!want
&& wlc_hw
->pllreq
)
3497 si_clkctl_xtal(wlc_hw
->sih
, XTAL
| PLL
, want
);
3499 wlc_hw
->sbclk
= want
;
3500 if (!wlc_hw
->sbclk
) {
3501 wlc_hw
->clk
= false;
3502 if (wlc_hw
->band
&& wlc_hw
->band
->pi
)
3503 wlc_phy_hw_clk_state_upd(wlc_hw
->band
->pi
, false);
3507 static void wlc_flushqueues(struct wlc_info
*wlc
)
3509 struct wlc_hw_info
*wlc_hw
= wlc
->hw
;
3512 wlc
->txpend16165war
= 0;
3514 /* free any posted tx packets */
3515 for (i
= 0; i
< NFIFO
; i
++)
3516 if (wlc_hw
->di
[i
]) {
3517 dma_txreclaim(wlc_hw
->di
[i
], HNDDMA_RANGE_ALL
);
3518 TXPKTPENDCLR(wlc
, i
);
3519 WL_TRACE("wlc_flushqueues: pktpend fifo %d cleared\n",
3523 /* free any posted rx packets */
3524 dma_rxreclaim(wlc_hw
->di
[RX_FIFO
]);
3527 u16
wlc_bmac_read_shm(struct wlc_hw_info
*wlc_hw
, uint offset
)
3529 return wlc_bmac_read_objmem(wlc_hw
, offset
, OBJADDR_SHM_SEL
);
3532 void wlc_bmac_write_shm(struct wlc_hw_info
*wlc_hw
, uint offset
, u16 v
)
3534 wlc_bmac_write_objmem(wlc_hw
, offset
, v
, OBJADDR_SHM_SEL
);
3537 /* Set a range of shared memory to a value.
3538 * SHM 'offset' needs to be an even address and
3539 * Buffer length 'len' must be an even number of bytes
3541 void wlc_bmac_set_shm(struct wlc_hw_info
*wlc_hw
, uint offset
, u16 v
, int len
)
3545 /* offset and len need to be even */
3546 ASSERT((offset
& 1) == 0);
3547 ASSERT((len
& 1) == 0);
3552 for (i
= 0; i
< len
; i
+= 2) {
3553 wlc_bmac_write_objmem(wlc_hw
, offset
+ i
, v
, OBJADDR_SHM_SEL
);
3558 wlc_bmac_read_objmem(struct wlc_hw_info
*wlc_hw
, uint offset
, u32 sel
)
3560 d11regs_t
*regs
= wlc_hw
->regs
;
3561 volatile u16
*objdata_lo
= (volatile u16
*)®s
->objdata
;
3562 volatile u16
*objdata_hi
= objdata_lo
+ 1;
3565 ASSERT((offset
& 1) == 0);
3567 W_REG(®s
->objaddr
, sel
| (offset
>> 2));
3568 (void)R_REG(®s
->objaddr
);
3570 v
= R_REG(objdata_hi
);
3572 v
= R_REG(objdata_lo
);
3579 wlc_bmac_write_objmem(struct wlc_hw_info
*wlc_hw
, uint offset
, u16 v
, u32 sel
)
3581 d11regs_t
*regs
= wlc_hw
->regs
;
3582 volatile u16
*objdata_lo
= (volatile u16
*)®s
->objdata
;
3583 volatile u16
*objdata_hi
= objdata_lo
+ 1;
3585 ASSERT((offset
& 1) == 0);
3587 W_REG(®s
->objaddr
, sel
| (offset
>> 2));
3588 (void)R_REG(®s
->objaddr
);
3590 W_REG(objdata_hi
, v
);
3592 W_REG(objdata_lo
, v
);
3596 /* Copy a buffer to shared memory of specified type .
3597 * SHM 'offset' needs to be an even address and
3598 * Buffer length 'len' must be an even number of bytes
3599 * 'sel' selects the type of memory
3602 wlc_bmac_copyto_objmem(struct wlc_hw_info
*wlc_hw
, uint offset
, const void *buf
,
3606 const u8
*p
= (const u8
*)buf
;
3609 /* offset and len need to be even */
3610 ASSERT((offset
& 1) == 0);
3611 ASSERT((len
& 1) == 0);
3616 for (i
= 0; i
< len
; i
+= 2) {
3617 v
= p
[i
] | (p
[i
+ 1] << 8);
3618 wlc_bmac_write_objmem(wlc_hw
, offset
+ i
, v
, sel
);
3622 /* Copy a piece of shared memory of specified type to a buffer .
3623 * SHM 'offset' needs to be an even address and
3624 * Buffer length 'len' must be an even number of bytes
3625 * 'sel' selects the type of memory
3628 wlc_bmac_copyfrom_objmem(struct wlc_hw_info
*wlc_hw
, uint offset
, void *buf
,
3635 /* offset and len need to be even */
3636 ASSERT((offset
& 1) == 0);
3637 ASSERT((len
& 1) == 0);
3642 for (i
= 0; i
< len
; i
+= 2) {
3643 v
= wlc_bmac_read_objmem(wlc_hw
, offset
+ i
, sel
);
3645 p
[i
+ 1] = (v
>> 8) & 0xFF;
3649 void wlc_bmac_copyfrom_vars(struct wlc_hw_info
*wlc_hw
, char **buf
, uint
*len
)
3651 WL_TRACE("wlc_bmac_copyfrom_vars, nvram vars totlen=%d\n",
3654 *buf
= wlc_hw
->vars
;
3655 *len
= wlc_hw
->vars_size
;
3658 void wlc_bmac_retrylimit_upd(struct wlc_hw_info
*wlc_hw
, u16 SRL
, u16 LRL
)
3663 /* write retry limit to SCR, shouldn't need to suspend */
3665 W_REG(&wlc_hw
->regs
->objaddr
,
3666 OBJADDR_SCR_SEL
| S_DOT11_SRC_LMT
);
3667 (void)R_REG(&wlc_hw
->regs
->objaddr
);
3668 W_REG(&wlc_hw
->regs
->objdata
, wlc_hw
->SRL
);
3669 W_REG(&wlc_hw
->regs
->objaddr
,
3670 OBJADDR_SCR_SEL
| S_DOT11_LRC_LMT
);
3671 (void)R_REG(&wlc_hw
->regs
->objaddr
);
3672 W_REG(&wlc_hw
->regs
->objdata
, wlc_hw
->LRL
);
3676 void wlc_bmac_set_noreset(struct wlc_hw_info
*wlc_hw
, bool noreset_flag
)
3678 wlc_hw
->noreset
= noreset_flag
;
3681 void wlc_bmac_pllreq(struct wlc_hw_info
*wlc_hw
, bool set
, mbool req_bit
)
3686 if (mboolisset(wlc_hw
->pllreq
, req_bit
))
3689 mboolset(wlc_hw
->pllreq
, req_bit
);
3691 if (mboolisset(wlc_hw
->pllreq
, WLC_PLLREQ_FLIP
)) {
3692 if (!wlc_hw
->sbclk
) {
3693 wlc_bmac_xtal(wlc_hw
, ON
);
3697 if (!mboolisset(wlc_hw
->pllreq
, req_bit
))
3700 mboolclr(wlc_hw
->pllreq
, req_bit
);
3702 if (mboolisset(wlc_hw
->pllreq
, WLC_PLLREQ_FLIP
)) {
3703 if (wlc_hw
->sbclk
) {
3704 wlc_bmac_xtal(wlc_hw
, OFF
);
3712 /* this will be true for all ai chips */
3713 bool wlc_bmac_taclear(struct wlc_hw_info
*wlc_hw
, bool ta_ok
)
3718 u16
wlc_bmac_rate_shm_offset(struct wlc_hw_info
*wlc_hw
, u8 rate
)
3723 /* get the phy specific rate encoding for the PLCP SIGNAL field */
3724 /* XXX4321 fixup needed ? */
3726 table_ptr
= M_RT_DIRMAP_A
;
3728 table_ptr
= M_RT_DIRMAP_B
;
3730 /* for a given rate, the LS-nibble of the PLCP SIGNAL field is
3731 * the index into the rate table.
3733 phy_rate
= rate_info
[rate
] & RATE_MASK
;
3734 index
= phy_rate
& 0xf;
3736 /* Find the SHM pointer to the rate table entry by looking in the
3739 return 2 * wlc_bmac_read_shm(wlc_hw
, table_ptr
+ (index
* 2));
3742 void wlc_bmac_antsel_set(struct wlc_hw_info
*wlc_hw
, u32 antsel_avail
)
3744 wlc_hw
->antsel_avail
= antsel_avail
;