Merge branch 'staging-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh...
[pandora-kernel.git] / drivers / staging / brcm80211 / sys / wlc_bmac.c
1 /*
2  * Copyright (c) 2010 Broadcom Corporation
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16
17
18 #include <linux/kernel.h>
19 #include <wlc_cfg.h>
20 #include <linux/module.h>
21 #include <linux/pci.h>
22 #include <linux/netdevice.h>
23 #include <linux/etherdevice.h>
24 #include <bcmdefs.h>
25 #include <osl.h>
26 #include <proto/802.11.h>
27 #include <bcmwifi.h>
28 #include <bcmutils.h>
29 #include <siutils.h>
30 #include <bcmendian.h>
31 #include <wlioctl.h>
32 #include <sbconfig.h>
33 #include <sbchipc.h>
34 #include <pcicfg.h>
35 #include <sbhndpio.h>
36 #include <sbhnddma.h>
37 #include <hnddma.h>
38 #include <hndpmu.h>
39 #include <d11.h>
40 #include <wlc_rate.h>
41 #include <wlc_pub.h>
42 #include <wlc_channel.h>
43 #include <bcmsrom.h>
44 #include <wlc_key.h>
45 #include <bcmdevs.h>
46 /* BMAC_NOTE: a WLC_HIGH compile include of wlc.h adds in more structures and type
47  * dependencies. Need to include these to files to allow a clean include of wlc.h
48  * with WLC_HIGH defined.
49  * At some point we may be able to skip the include of wlc.h and instead just
50  * define a stub wlc_info and band struct to allow rpc calls to get the rpc handle.
51  */
52 #include <wlc_event.h>
53 #include <wlc_mac80211.h>
54 #include <wlc_bmac.h>
55 #include <wlc_phy_shim.h>
56 #include <wlc_phy_hal.h>
57 #include <wl_export.h>
58 #include "wl_ucode.h"
59 #include "d11ucode_ext.h"
60 #include <bcmotp.h>
61
62 /* BMAC_NOTE: With WLC_HIGH defined, some fns in this file make calls to high level
63  * functions defined in the headers below. We should be eliminating those calls and
64  * will be able to delete these include lines.
65  */
66 #include <wlc_antsel.h>
67
68 #include <pcie_core.h>
69
70 #include <wlc_alloc.h>
71 #include <wl_dbg.h>
72
73 #define TIMER_INTERVAL_WATCHDOG_BMAC    1000    /* watchdog timer, in unit of ms */
74
75 #define SYNTHPU_DLY_APHY_US     3700    /* a phy synthpu_dly time in us */
76 #define SYNTHPU_DLY_BPHY_US     1050    /* b/g phy synthpu_dly time in us, default */
77 #define SYNTHPU_DLY_NPHY_US     2048    /* n phy REV3 synthpu_dly time in us, default */
78 #define SYNTHPU_DLY_LPPHY_US    300     /* lpphy synthpu_dly time in us */
79
80 #define SYNTHPU_DLY_PHY_US_QT   100     /* QT synthpu_dly time in us */
81
82 #ifndef BMAC_DUP_TO_REMOVE
83 #define WLC_RM_WAIT_TX_SUSPEND          4       /* Wait Tx Suspend */
84
85 #define ANTCNT                  10      /* vanilla M_MAX_ANTCNT value */
86
87 #endif                          /* BMAC_DUP_TO_REMOVE */
88
89 #define DMAREG(wlc_hw, direction, fifonum)      (D11REV_LT(wlc_hw->corerev, 11) ? \
90         ((direction == DMA_TX) ? \
91                 (void *)&(wlc_hw->regs->fifo.f32regs.dmaregs[fifonum].xmt) : \
92                 (void *)&(wlc_hw->regs->fifo.f32regs.dmaregs[fifonum].rcv)) : \
93         ((direction == DMA_TX) ? \
94                 (void *)&(wlc_hw->regs->fifo.f64regs[fifonum].dmaxmt) : \
95                 (void *)&(wlc_hw->regs->fifo.f64regs[fifonum].dmarcv)))
96
97 /*
98  * The following table lists the buffer memory allocated to xmt fifos in HW.
99  * the size is in units of 256bytes(one block), total size is HW dependent
100  * ucode has default fifo partition, sw can overwrite if necessary
101  *
102  * This is documented in twiki under the topic UcodeTxFifo. Please ensure
103  * the twiki is updated before making changes.
104  */
105
106 #define XMTFIFOTBL_STARTREV     20      /* Starting corerev for the fifo size table */
107
108 static u16 xmtfifo_sz[][NFIFO] = {
109         {20, 192, 192, 21, 17, 5},      /* corerev 20: 5120, 49152, 49152, 5376, 4352, 1280 */
110         {9, 58, 22, 14, 14, 5}, /* corerev 21: 2304, 14848, 5632, 3584, 3584, 1280 */
111         {20, 192, 192, 21, 17, 5},      /* corerev 22: 5120, 49152, 49152, 5376, 4352, 1280 */
112         {20, 192, 192, 21, 17, 5},      /* corerev 23: 5120, 49152, 49152, 5376, 4352, 1280 */
113         {9, 58, 22, 14, 14, 5}, /* corerev 24: 2304, 14848, 5632, 3584, 3584, 1280 */
114 };
115
116 static void wlc_clkctl_clk(struct wlc_hw_info *wlc, uint mode);
117 static void wlc_coreinit(struct wlc_info *wlc);
118
119 /* used by wlc_wakeucode_init() */
120 static void wlc_write_inits(struct wlc_hw_info *wlc_hw, const d11init_t *inits);
121 static void wlc_ucode_write(struct wlc_hw_info *wlc_hw, const u32 ucode[],
122                             const uint nbytes);
123 static void wlc_ucode_download(struct wlc_hw_info *wlc);
124 static void wlc_ucode_txant_set(struct wlc_hw_info *wlc_hw);
125
126 /* used by wlc_dpc() */
127 static bool wlc_bmac_dotxstatus(struct wlc_hw_info *wlc, tx_status_t *txs,
128                                 u32 s2);
129 static bool wlc_bmac_txstatus_corerev4(struct wlc_hw_info *wlc);
130 static bool wlc_bmac_txstatus(struct wlc_hw_info *wlc, bool bound, bool *fatal);
131 static bool wlc_bmac_recv(struct wlc_hw_info *wlc_hw, uint fifo, bool bound);
132
133 /* used by wlc_down() */
134 static void wlc_flushqueues(struct wlc_info *wlc);
135
136 static void wlc_write_mhf(struct wlc_hw_info *wlc_hw, u16 *mhfs);
137 static void wlc_mctrl_reset(struct wlc_hw_info *wlc_hw);
138 static void wlc_corerev_fifofixup(struct wlc_hw_info *wlc_hw);
139
140 /* Low Level Prototypes */
141 static u16 wlc_bmac_read_objmem(struct wlc_hw_info *wlc_hw, uint offset,
142                                    u32 sel);
143 static void wlc_bmac_write_objmem(struct wlc_hw_info *wlc_hw, uint offset,
144                                   u16 v, u32 sel);
145 static bool wlc_bmac_attach_dmapio(struct wlc_info *wlc, uint j, bool wme);
146 static void wlc_bmac_detach_dmapio(struct wlc_hw_info *wlc_hw);
147 static void wlc_ucode_bsinit(struct wlc_hw_info *wlc_hw);
148 static bool wlc_validboardtype(struct wlc_hw_info *wlc);
149 static bool wlc_isgoodchip(struct wlc_hw_info *wlc_hw);
150 static char *wlc_get_macaddr(struct wlc_hw_info *wlc_hw);
151 static void wlc_mhfdef(struct wlc_info *wlc, u16 *mhfs, u16 mhf2_init);
152 static void wlc_mctrl_write(struct wlc_hw_info *wlc_hw);
153 static void wlc_ucode_mute_override_set(struct wlc_hw_info *wlc_hw);
154 static void wlc_ucode_mute_override_clear(struct wlc_hw_info *wlc_hw);
155 static u32 wlc_wlintrsoff(struct wlc_info *wlc);
156 static void wlc_wlintrsrestore(struct wlc_info *wlc, u32 macintmask);
157 static void wlc_gpio_init(struct wlc_info *wlc);
158 static void wlc_write_hw_bcntemplate0(struct wlc_hw_info *wlc_hw, void *bcn,
159                                       int len);
160 static void wlc_write_hw_bcntemplate1(struct wlc_hw_info *wlc_hw, void *bcn,
161                                       int len);
162 static void wlc_bmac_bsinit(struct wlc_info *wlc, chanspec_t chanspec);
163 static u32 wlc_setband_inact(struct wlc_info *wlc, uint bandunit);
164 static void wlc_bmac_setband(struct wlc_hw_info *wlc_hw, uint bandunit,
165                              chanspec_t chanspec);
166 static void wlc_bmac_update_slot_timing(struct wlc_hw_info *wlc_hw,
167                                         bool shortslot);
168 static void wlc_upd_ofdm_pctl1_table(struct wlc_hw_info *wlc_hw);
169 static u16 wlc_bmac_ofdm_ratetable_offset(struct wlc_hw_info *wlc_hw,
170                                              u8 rate);
171
172 /* === Low Level functions === */
173
174 void wlc_bmac_set_shortslot(struct wlc_hw_info *wlc_hw, bool shortslot)
175 {
176         wlc_hw->shortslot = shortslot;
177
178         if (BAND_2G(wlc_hw->band->bandtype) && wlc_hw->up) {
179                 wlc_suspend_mac_and_wait(wlc_hw->wlc);
180                 wlc_bmac_update_slot_timing(wlc_hw, shortslot);
181                 wlc_enable_mac(wlc_hw->wlc);
182         }
183 }
184
185 /*
186  * Update the slot timing for standard 11b/g (20us slots)
187  * or shortslot 11g (9us slots)
188  * The PSM needs to be suspended for this call.
189  */
190 static void wlc_bmac_update_slot_timing(struct wlc_hw_info *wlc_hw,
191                                         bool shortslot)
192 {
193         struct osl_info *osh;
194         d11regs_t *regs;
195
196         osh = wlc_hw->osh;
197         regs = wlc_hw->regs;
198
199         if (shortslot) {
200                 /* 11g short slot: 11a timing */
201                 W_REG(osh, &regs->ifs_slot, 0x0207);    /* APHY_SLOT_TIME */
202                 wlc_bmac_write_shm(wlc_hw, M_DOT11_SLOT, APHY_SLOT_TIME);
203         } else {
204                 /* 11g long slot: 11b timing */
205                 W_REG(osh, &regs->ifs_slot, 0x0212);    /* BPHY_SLOT_TIME */
206                 wlc_bmac_write_shm(wlc_hw, M_DOT11_SLOT, BPHY_SLOT_TIME);
207         }
208 }
209
210 static void WLBANDINITFN(wlc_ucode_bsinit) (struct wlc_hw_info *wlc_hw)
211 {
212         /* init microcode host flags */
213         wlc_write_mhf(wlc_hw, wlc_hw->band->mhfs);
214
215         /* do band-specific ucode IHR, SHM, and SCR inits */
216         if (D11REV_IS(wlc_hw->corerev, 23)) {
217                 if (WLCISNPHY(wlc_hw->band)) {
218                         wlc_write_inits(wlc_hw, d11n0bsinitvals16);
219                 } else {
220                         WL_ERROR("%s: wl%d: unsupported phy in corerev %d\n",
221                                  __func__, wlc_hw->unit, wlc_hw->corerev);
222                 }
223         } else {
224                 if (D11REV_IS(wlc_hw->corerev, 24)) {
225                         if (WLCISLCNPHY(wlc_hw->band)) {
226                                 wlc_write_inits(wlc_hw, d11lcn0bsinitvals24);
227                         } else
228                                 WL_ERROR("%s: wl%d: unsupported phy in corerev %d\n",
229                                          __func__, wlc_hw->unit,
230                                          wlc_hw->corerev);
231                 } else {
232                         WL_ERROR("%s: wl%d: unsupported corerev %d\n",
233                                  __func__, wlc_hw->unit, wlc_hw->corerev);
234                 }
235         }
236 }
237
238 /* switch to new band but leave it inactive */
239 static u32 WLBANDINITFN(wlc_setband_inact) (struct wlc_info *wlc, uint bandunit)
240 {
241         struct wlc_hw_info *wlc_hw = wlc->hw;
242         u32 macintmask;
243         u32 tmp;
244
245         WL_TRACE("wl%d: wlc_setband_inact\n", wlc_hw->unit);
246
247         ASSERT(bandunit != wlc_hw->band->bandunit);
248         ASSERT(si_iscoreup(wlc_hw->sih));
249         ASSERT((R_REG(wlc_hw->osh, &wlc_hw->regs->maccontrol) & MCTL_EN_MAC) ==
250                0);
251
252         /* disable interrupts */
253         macintmask = wl_intrsoff(wlc->wl);
254
255         /* radio off */
256         wlc_phy_switch_radio(wlc_hw->band->pi, OFF);
257
258         ASSERT(wlc_hw->clk);
259
260         if (D11REV_LT(wlc_hw->corerev, 17))
261                 tmp = R_REG(wlc_hw->osh, &wlc_hw->regs->maccontrol);
262
263         wlc_bmac_core_phy_clk(wlc_hw, OFF);
264
265         wlc_setxband(wlc_hw, bandunit);
266
267         return macintmask;
268 }
269
270 /* Process received frames */
271 /*
272  * Return true if more frames need to be processed. false otherwise.
273  * Param 'bound' indicates max. # frames to process before break out.
274  */
275 static bool BCMFASTPATH
276 wlc_bmac_recv(struct wlc_hw_info *wlc_hw, uint fifo, bool bound)
277 {
278         struct sk_buff *p;
279         struct sk_buff *head = NULL;
280         struct sk_buff *tail = NULL;
281         uint n = 0;
282         uint bound_limit = bound ? wlc_hw->wlc->pub->tunables->rxbnd : -1;
283         u32 tsf_h, tsf_l;
284         wlc_d11rxhdr_t *wlc_rxhdr = NULL;
285
286         WL_TRACE("wl%d: %s\n", wlc_hw->unit, __func__);
287         /* gather received frames */
288         while ((p = dma_rx(wlc_hw->di[fifo]))) {
289
290                 if (!tail)
291                         head = tail = p;
292                 else {
293                         tail->prev = p;
294                         tail = p;
295                 }
296
297                 /* !give others some time to run! */
298                 if (++n >= bound_limit)
299                         break;
300         }
301
302         /* get the TSF REG reading */
303         wlc_bmac_read_tsf(wlc_hw, &tsf_l, &tsf_h);
304
305         /* post more rbufs */
306         dma_rxfill(wlc_hw->di[fifo]);
307
308         /* process each frame */
309         while ((p = head) != NULL) {
310                 head = head->prev;
311                 p->prev = NULL;
312
313                 /* record the tsf_l in wlc_rxd11hdr */
314                 wlc_rxhdr = (wlc_d11rxhdr_t *) p->data;
315                 wlc_rxhdr->tsf_l = htol32(tsf_l);
316
317                 /* compute the RSSI from d11rxhdr and record it in wlc_rxd11hr */
318                 wlc_phy_rssi_compute(wlc_hw->band->pi, wlc_rxhdr);
319
320                 wlc_recv(wlc_hw->wlc, p);
321         }
322
323         return n >= bound_limit;
324 }
325
326 /* second-level interrupt processing
327  *   Return true if another dpc needs to be re-scheduled. false otherwise.
328  *   Param 'bounded' indicates if applicable loops should be bounded.
329  */
330 bool BCMFASTPATH wlc_dpc(struct wlc_info *wlc, bool bounded)
331 {
332         u32 macintstatus;
333         struct wlc_hw_info *wlc_hw = wlc->hw;
334         d11regs_t *regs = wlc_hw->regs;
335         bool fatal = false;
336
337         if (DEVICEREMOVED(wlc)) {
338                 WL_ERROR("wl%d: %s: dead chip\n", wlc_hw->unit, __func__);
339                 wl_down(wlc->wl);
340                 return false;
341         }
342
343         /* grab and clear the saved software intstatus bits */
344         macintstatus = wlc->macintstatus;
345         wlc->macintstatus = 0;
346
347         WL_TRACE("wl%d: wlc_dpc: macintstatus 0x%x\n",
348                  wlc_hw->unit, macintstatus);
349
350         if (macintstatus & MI_PRQ) {
351                 /* Process probe request FIFO */
352                 ASSERT(0 && "PRQ Interrupt in non-MBSS");
353         }
354
355         /* BCN template is available */
356         /* ZZZ: Use AP_ACTIVE ? */
357         if (AP_ENAB(wlc->pub) && (!APSTA_ENAB(wlc->pub) || wlc->aps_associated)
358             && (macintstatus & MI_BCNTPL)) {
359                 wlc_update_beacon(wlc);
360         }
361
362         /* PMQ entry addition */
363         if (macintstatus & MI_PMQ) {
364         }
365
366         /* tx status */
367         if (macintstatus & MI_TFS) {
368                 if (wlc_bmac_txstatus(wlc->hw, bounded, &fatal))
369                         wlc->macintstatus |= MI_TFS;
370                 if (fatal) {
371                         WL_ERROR("MI_TFS: fatal\n");
372                         goto fatal;
373                 }
374         }
375
376         if (macintstatus & (MI_TBTT | MI_DTIM_TBTT))
377                 wlc_tbtt(wlc, regs);
378
379         /* ATIM window end */
380         if (macintstatus & MI_ATIMWINEND) {
381                 WL_TRACE("wlc_isr: end of ATIM window\n");
382
383                 OR_REG(wlc_hw->osh, &regs->maccommand, wlc->qvalid);
384                 wlc->qvalid = 0;
385         }
386
387         /* phy tx error */
388         if (macintstatus & MI_PHYTXERR) {
389                 WLCNTINCR(wlc->pub->_cnt->txphyerr);
390         }
391
392         /* received data or control frame, MI_DMAINT is indication of RX_FIFO interrupt */
393         if (macintstatus & MI_DMAINT) {
394                 if (wlc_bmac_recv(wlc_hw, RX_FIFO, bounded)) {
395                         wlc->macintstatus |= MI_DMAINT;
396                 }
397         }
398
399         /* TX FIFO suspend/flush completion */
400         if (macintstatus & MI_TXSTOP) {
401                 if (wlc_bmac_tx_fifo_suspended(wlc_hw, TX_DATA_FIFO)) {
402                         /*      WL_ERROR("dpc: fifo_suspend_comlete\n"); */
403                 }
404         }
405
406         /* noise sample collected */
407         if (macintstatus & MI_BG_NOISE) {
408                 wlc_phy_noise_sample_intr(wlc_hw->band->pi);
409         }
410
411         if (macintstatus & MI_GP0) {
412                 WL_ERROR("wl%d: PSM microcode watchdog fired at %d (seconds). Resetting.\n",
413                          wlc_hw->unit, wlc_hw->now);
414
415                 printk_once("%s : PSM Watchdog, chipid 0x%x, chiprev 0x%x\n",
416                                         __func__, wlc_hw->sih->chip,
417                                         wlc_hw->sih->chiprev);
418
419                 WLCNTINCR(wlc->pub->_cnt->psmwds);
420
421                 /* big hammer */
422                 wl_init(wlc->wl);
423         }
424
425         /* gptimer timeout */
426         if (macintstatus & MI_TO) {
427                 W_REG(wlc_hw->osh, &regs->gptimer, 0);
428         }
429
430         if (macintstatus & MI_RFDISABLE) {
431 #if defined(BCMDBG)
432                 u32 rfd = R_REG(wlc_hw->osh, &regs->phydebug) & PDBG_RFD;
433 #endif
434
435                 WL_ERROR("wl%d: MAC Detected a change on the RF Disable Input 0x%x\n",
436                          wlc_hw->unit, rfd);
437
438                 WLCNTINCR(wlc->pub->_cnt->rfdisable);
439         }
440
441         /* send any enq'd tx packets. Just makes sure to jump start tx */
442         if (!pktq_empty(&wlc->active_queue->q))
443                 wlc_send_q(wlc, wlc->active_queue);
444
445         ASSERT(wlc_ps_check(wlc));
446
447         /* make sure the bound indication and the implementation are in sync */
448         ASSERT(bounded == true || wlc->macintstatus == 0);
449
450         /* it isn't done and needs to be resched if macintstatus is non-zero */
451         return wlc->macintstatus != 0;
452
453  fatal:
454         wl_init(wlc->wl);
455         return wlc->macintstatus != 0;
456 }
457
458 /* common low-level watchdog code */
459 void wlc_bmac_watchdog(void *arg)
460 {
461         struct wlc_info *wlc = (struct wlc_info *) arg;
462         struct wlc_hw_info *wlc_hw = wlc->hw;
463
464         WL_TRACE("wl%d: wlc_bmac_watchdog\n", wlc_hw->unit);
465
466         if (!wlc_hw->up)
467                 return;
468
469         /* increment second count */
470         wlc_hw->now++;
471
472         /* Check for FIFO error interrupts */
473         wlc_bmac_fifoerrors(wlc_hw);
474
475         /* make sure RX dma has buffers */
476         dma_rxfill(wlc->hw->di[RX_FIFO]);
477         if (D11REV_IS(wlc_hw->corerev, 4)) {
478                 dma_rxfill(wlc->hw->di[RX_TXSTATUS_FIFO]);
479         }
480
481         wlc_phy_watchdog(wlc_hw->band->pi);
482 }
483
484 void
485 wlc_bmac_set_chanspec(struct wlc_hw_info *wlc_hw, chanspec_t chanspec,
486                       bool mute, struct txpwr_limits *txpwr)
487 {
488         uint bandunit;
489
490         WL_TRACE("wl%d: wlc_bmac_set_chanspec 0x%x\n",
491                  wlc_hw->unit, chanspec);
492
493         wlc_hw->chanspec = chanspec;
494
495         /* Switch bands if necessary */
496         if (NBANDS_HW(wlc_hw) > 1) {
497                 bandunit = CHSPEC_WLCBANDUNIT(chanspec);
498                 if (wlc_hw->band->bandunit != bandunit) {
499                         /* wlc_bmac_setband disables other bandunit,
500                          *  use light band switch if not up yet
501                          */
502                         if (wlc_hw->up) {
503                                 wlc_phy_chanspec_radio_set(wlc_hw->
504                                                            bandstate[bandunit]->
505                                                            pi, chanspec);
506                                 wlc_bmac_setband(wlc_hw, bandunit, chanspec);
507                         } else {
508                                 wlc_setxband(wlc_hw, bandunit);
509                         }
510                 }
511         }
512
513         wlc_phy_initcal_enable(wlc_hw->band->pi, !mute);
514
515         if (!wlc_hw->up) {
516                 if (wlc_hw->clk)
517                         wlc_phy_txpower_limit_set(wlc_hw->band->pi, txpwr,
518                                                   chanspec);
519                 wlc_phy_chanspec_radio_set(wlc_hw->band->pi, chanspec);
520         } else {
521                 wlc_phy_chanspec_set(wlc_hw->band->pi, chanspec);
522                 wlc_phy_txpower_limit_set(wlc_hw->band->pi, txpwr, chanspec);
523
524                 /* Update muting of the channel */
525                 wlc_bmac_mute(wlc_hw, mute, 0);
526         }
527 }
528
529 int wlc_bmac_revinfo_get(struct wlc_hw_info *wlc_hw,
530                          wlc_bmac_revinfo_t *revinfo)
531 {
532         si_t *sih = wlc_hw->sih;
533         uint idx;
534
535         revinfo->vendorid = wlc_hw->vendorid;
536         revinfo->deviceid = wlc_hw->deviceid;
537
538         revinfo->boardrev = wlc_hw->boardrev;
539         revinfo->corerev = wlc_hw->corerev;
540         revinfo->sromrev = wlc_hw->sromrev;
541         revinfo->chiprev = sih->chiprev;
542         revinfo->chip = sih->chip;
543         revinfo->chippkg = sih->chippkg;
544         revinfo->boardtype = sih->boardtype;
545         revinfo->boardvendor = sih->boardvendor;
546         revinfo->bustype = sih->bustype;
547         revinfo->buscoretype = sih->buscoretype;
548         revinfo->buscorerev = sih->buscorerev;
549         revinfo->issim = sih->issim;
550
551         revinfo->nbands = NBANDS_HW(wlc_hw);
552
553         for (idx = 0; idx < NBANDS_HW(wlc_hw); idx++) {
554                 wlc_hwband_t *band = wlc_hw->bandstate[idx];
555                 revinfo->band[idx].bandunit = band->bandunit;
556                 revinfo->band[idx].bandtype = band->bandtype;
557                 revinfo->band[idx].phytype = band->phytype;
558                 revinfo->band[idx].phyrev = band->phyrev;
559                 revinfo->band[idx].radioid = band->radioid;
560                 revinfo->band[idx].radiorev = band->radiorev;
561                 revinfo->band[idx].abgphy_encore = band->abgphy_encore;
562                 revinfo->band[idx].anarev = 0;
563
564         }
565         return 0;
566 }
567
568 int wlc_bmac_state_get(struct wlc_hw_info *wlc_hw, wlc_bmac_state_t *state)
569 {
570         state->machwcap = wlc_hw->machwcap;
571
572         return 0;
573 }
574
575 static bool wlc_bmac_attach_dmapio(struct wlc_info *wlc, uint j, bool wme)
576 {
577         uint i;
578         char name[8];
579         /* ucode host flag 2 needed for pio mode, independent of band and fifo */
580         u16 pio_mhf2 = 0;
581         struct wlc_hw_info *wlc_hw = wlc->hw;
582         uint unit = wlc_hw->unit;
583         wlc_tunables_t *tune = wlc->pub->tunables;
584
585         /* name and offsets for dma_attach */
586         snprintf(name, sizeof(name), "wl%d", unit);
587
588         if (wlc_hw->di[0] == 0) {       /* Init FIFOs */
589                 uint addrwidth;
590                 int dma_attach_err = 0;
591                 struct osl_info *osh = wlc_hw->osh;
592
593                 /* Find out the DMA addressing capability and let OS know
594                  * All the channels within one DMA core have 'common-minimum' same
595                  * capability
596                  */
597                 addrwidth =
598                     dma_addrwidth(wlc_hw->sih, DMAREG(wlc_hw, DMA_TX, 0));
599
600                 if (!wl_alloc_dma_resources(wlc_hw->wlc->wl, addrwidth)) {
601                         WL_ERROR("wl%d: wlc_attach: alloc_dma_resources failed\n",
602                                  unit);
603                         return false;
604                 }
605
606                 /*
607                  * FIFO 0
608                  * TX: TX_AC_BK_FIFO (TX AC Background data packets)
609                  * RX: RX_FIFO (RX data packets)
610                  */
611                 ASSERT(TX_AC_BK_FIFO == 0);
612                 ASSERT(RX_FIFO == 0);
613                 wlc_hw->di[0] = dma_attach(osh, name, wlc_hw->sih,
614                                            (wme ? DMAREG(wlc_hw, DMA_TX, 0) :
615                                             NULL), DMAREG(wlc_hw, DMA_RX, 0),
616                                            (wme ? tune->ntxd : 0), tune->nrxd,
617                                            tune->rxbufsz, -1, tune->nrxbufpost,
618                                            WL_HWRXOFF, &wl_msg_level);
619                 dma_attach_err |= (NULL == wlc_hw->di[0]);
620
621                 /*
622                  * FIFO 1
623                  * TX: TX_AC_BE_FIFO (TX AC Best-Effort data packets)
624                  *   (legacy) TX_DATA_FIFO (TX data packets)
625                  * RX: UNUSED
626                  */
627                 ASSERT(TX_AC_BE_FIFO == 1);
628                 ASSERT(TX_DATA_FIFO == 1);
629                 wlc_hw->di[1] = dma_attach(osh, name, wlc_hw->sih,
630                                            DMAREG(wlc_hw, DMA_TX, 1), NULL,
631                                            tune->ntxd, 0, 0, -1, 0, 0,
632                                            &wl_msg_level);
633                 dma_attach_err |= (NULL == wlc_hw->di[1]);
634
635                 /*
636                  * FIFO 2
637                  * TX: TX_AC_VI_FIFO (TX AC Video data packets)
638                  * RX: UNUSED
639                  */
640                 ASSERT(TX_AC_VI_FIFO == 2);
641                 wlc_hw->di[2] = dma_attach(osh, name, wlc_hw->sih,
642                                            DMAREG(wlc_hw, DMA_TX, 2), NULL,
643                                            tune->ntxd, 0, 0, -1, 0, 0,
644                                            &wl_msg_level);
645                 dma_attach_err |= (NULL == wlc_hw->di[2]);
646                 /*
647                  * FIFO 3
648                  * TX: TX_AC_VO_FIFO (TX AC Voice data packets)
649                  *   (legacy) TX_CTL_FIFO (TX control & mgmt packets)
650                  * RX: RX_TXSTATUS_FIFO (transmit-status packets)
651                  *      for corerev < 5 only
652                  */
653                 ASSERT(TX_AC_VO_FIFO == 3);
654                 ASSERT(TX_CTL_FIFO == 3);
655                 if (D11REV_IS(wlc_hw->corerev, 4)) {
656                         ASSERT(RX_TXSTATUS_FIFO == 3);
657                         wlc_hw->di[3] = dma_attach(osh, name, wlc_hw->sih,
658                                                    DMAREG(wlc_hw, DMA_TX, 3),
659                                                    DMAREG(wlc_hw, DMA_RX, 3),
660                                                    tune->ntxd, tune->nrxd,
661                                                    sizeof(tx_status_t), -1,
662                                                    tune->nrxbufpost, 0,
663                                                    &wl_msg_level);
664                         dma_attach_err |= (NULL == wlc_hw->di[3]);
665                 } else {
666                         wlc_hw->di[3] = dma_attach(osh, name, wlc_hw->sih,
667                                                    DMAREG(wlc_hw, DMA_TX, 3),
668                                                    NULL, tune->ntxd, 0, 0, -1,
669                                                    0, 0, &wl_msg_level);
670                         dma_attach_err |= (NULL == wlc_hw->di[3]);
671                 }
672 /* Cleaner to leave this as if with AP defined */
673
674                 if (dma_attach_err) {
675                         WL_ERROR("wl%d: wlc_attach: dma_attach failed\n", unit);
676                         return false;
677                 }
678
679                 /* get pointer to dma engine tx flow control variable */
680                 for (i = 0; i < NFIFO; i++)
681                         if (wlc_hw->di[i])
682                                 wlc_hw->txavail[i] =
683                                     (uint *) dma_getvar(wlc_hw->di[i],
684                                                         "&txavail");
685         }
686
687         /* initial ucode host flags */
688         wlc_mhfdef(wlc, wlc_hw->band->mhfs, pio_mhf2);
689
690         return true;
691 }
692
693 static void wlc_bmac_detach_dmapio(struct wlc_hw_info *wlc_hw)
694 {
695         uint j;
696
697         for (j = 0; j < NFIFO; j++) {
698                 if (wlc_hw->di[j]) {
699                         dma_detach(wlc_hw->di[j]);
700                         wlc_hw->di[j] = NULL;
701                 }
702         }
703 }
704
705 /* low level attach
706  *    run backplane attach, init nvram
707  *    run phy attach
708  *    initialize software state for each core and band
709  *    put the whole chip in reset(driver down state), no clock
710  */
711 int wlc_bmac_attach(struct wlc_info *wlc, u16 vendor, u16 device, uint unit,
712                     bool piomode, struct osl_info *osh, void *regsva,
713                     uint bustype, void *btparam)
714 {
715         struct wlc_hw_info *wlc_hw;
716         d11regs_t *regs;
717         char *macaddr = NULL;
718         char *vars;
719         uint err = 0;
720         uint j;
721         bool wme = false;
722         shared_phy_params_t sha_params;
723
724         WL_TRACE("wl%d: wlc_bmac_attach: vendor 0x%x device 0x%x\n",
725                  unit, vendor, device);
726
727         ASSERT(sizeof(wlc_d11rxhdr_t) <= WL_HWRXOFF);
728
729         wme = true;
730
731         wlc_hw = wlc->hw;
732         wlc_hw->wlc = wlc;
733         wlc_hw->unit = unit;
734         wlc_hw->osh = osh;
735         wlc_hw->band = wlc_hw->bandstate[0];
736         wlc_hw->_piomode = piomode;
737
738         /* populate struct wlc_hw_info with default values  */
739         wlc_bmac_info_init(wlc_hw);
740
741         /*
742          * Do the hardware portion of the attach.
743          * Also initialize software state that depends on the particular hardware
744          * we are running.
745          */
746         wlc_hw->sih = si_attach((uint) device, osh, regsva, bustype, btparam,
747                                 &wlc_hw->vars, &wlc_hw->vars_size);
748         if (wlc_hw->sih == NULL) {
749                 WL_ERROR("wl%d: wlc_bmac_attach: si_attach failed\n", unit);
750                 err = 11;
751                 goto fail;
752         }
753         vars = wlc_hw->vars;
754
755         /*
756          * Get vendid/devid nvram overwrites, which could be different
757          * than those the BIOS recognizes for devices on PCMCIA_BUS,
758          * SDIO_BUS, and SROMless devices on PCI_BUS.
759          */
760 #ifdef BCMBUSTYPE
761         bustype = BCMBUSTYPE;
762 #endif
763         if (bustype != SI_BUS) {
764                 char *var;
765
766                 var = getvar(vars, "vendid");
767                 if (var) {
768                         vendor = (u16) simple_strtoul(var, NULL, 0);
769                         WL_ERROR("Overriding vendor id = 0x%x\n", vendor);
770                 }
771                 var = getvar(vars, "devid");
772                 if (var) {
773                         u16 devid = (u16) simple_strtoul(var, NULL, 0);
774                         if (devid != 0xffff) {
775                                 device = devid;
776                                 WL_ERROR("Overriding device id = 0x%x\n",
777                                          device);
778                         }
779                 }
780
781                 /* verify again the device is supported */
782                 if (!wlc_chipmatch(vendor, device)) {
783                         WL_ERROR("wl%d: wlc_bmac_attach: Unsupported vendor/device (0x%x/0x%x)\n",
784                                  unit, vendor, device);
785                         err = 12;
786                         goto fail;
787                 }
788         }
789
790         wlc_hw->vendorid = vendor;
791         wlc_hw->deviceid = device;
792
793         /* set bar0 window to point at D11 core */
794         wlc_hw->regs = (d11regs_t *) si_setcore(wlc_hw->sih, D11_CORE_ID, 0);
795         wlc_hw->corerev = si_corerev(wlc_hw->sih);
796
797         regs = wlc_hw->regs;
798
799         wlc->regs = wlc_hw->regs;
800
801         /* validate chip, chiprev and corerev */
802         if (!wlc_isgoodchip(wlc_hw)) {
803                 err = 13;
804                 goto fail;
805         }
806
807         /* initialize power control registers */
808         si_clkctl_init(wlc_hw->sih);
809
810         /* request fastclock and force fastclock for the rest of attach
811          * bring the d11 core out of reset.
812          *   For PMU chips, the first wlc_clkctl_clk is no-op since core-clk is still false;
813          *   But it will be called again inside wlc_corereset, after d11 is out of reset.
814          */
815         wlc_clkctl_clk(wlc_hw, CLK_FAST);
816         wlc_bmac_corereset(wlc_hw, WLC_USE_COREFLAGS);
817
818         if (!wlc_bmac_validate_chip_access(wlc_hw)) {
819                 WL_ERROR("wl%d: wlc_bmac_attach: validate_chip_access failed\n",
820                          unit);
821                 err = 14;
822                 goto fail;
823         }
824
825         /* get the board rev, used just below */
826         j = getintvar(vars, "boardrev");
827         /* promote srom boardrev of 0xFF to 1 */
828         if (j == BOARDREV_PROMOTABLE)
829                 j = BOARDREV_PROMOTED;
830         wlc_hw->boardrev = (u16) j;
831         if (!wlc_validboardtype(wlc_hw)) {
832                 WL_ERROR("wl%d: wlc_bmac_attach: Unsupported Broadcom board type (0x%x)" " or revision level (0x%x)\n",
833                          unit, wlc_hw->sih->boardtype, wlc_hw->boardrev);
834                 err = 15;
835                 goto fail;
836         }
837         wlc_hw->sromrev = (u8) getintvar(vars, "sromrev");
838         wlc_hw->boardflags = (u32) getintvar(vars, "boardflags");
839         wlc_hw->boardflags2 = (u32) getintvar(vars, "boardflags2");
840
841         if (D11REV_LE(wlc_hw->corerev, 4)
842             || (wlc_hw->boardflags & BFL_NOPLLDOWN))
843                 wlc_bmac_pllreq(wlc_hw, true, WLC_PLLREQ_SHARED);
844
845         if ((wlc_hw->sih->bustype == PCI_BUS)
846             && (si_pci_war16165(wlc_hw->sih)))
847                 wlc->war16165 = true;
848
849         /* check device id(srom, nvram etc.) to set bands */
850         if (wlc_hw->deviceid == BCM43224_D11N_ID) {
851                 /* Dualband boards */
852                 wlc_hw->_nbands = 2;
853         } else
854                 wlc_hw->_nbands = 1;
855
856         if ((wlc_hw->sih->chip == BCM43225_CHIP_ID))
857                 wlc_hw->_nbands = 1;
858
859         /* BMAC_NOTE: remove init of pub values when wlc_attach() unconditionally does the
860          * init of these values
861          */
862         wlc->vendorid = wlc_hw->vendorid;
863         wlc->deviceid = wlc_hw->deviceid;
864         wlc->pub->sih = wlc_hw->sih;
865         wlc->pub->corerev = wlc_hw->corerev;
866         wlc->pub->sromrev = wlc_hw->sromrev;
867         wlc->pub->boardrev = wlc_hw->boardrev;
868         wlc->pub->boardflags = wlc_hw->boardflags;
869         wlc->pub->boardflags2 = wlc_hw->boardflags2;
870         wlc->pub->_nbands = wlc_hw->_nbands;
871
872         wlc_hw->physhim = wlc_phy_shim_attach(wlc_hw, wlc->wl, wlc);
873
874         if (wlc_hw->physhim == NULL) {
875                 WL_ERROR("wl%d: wlc_bmac_attach: wlc_phy_shim_attach failed\n",
876                          unit);
877                 err = 25;
878                 goto fail;
879         }
880
881         /* pass all the parameters to wlc_phy_shared_attach in one struct */
882         sha_params.osh = osh;
883         sha_params.sih = wlc_hw->sih;
884         sha_params.physhim = wlc_hw->physhim;
885         sha_params.unit = unit;
886         sha_params.corerev = wlc_hw->corerev;
887         sha_params.vars = vars;
888         sha_params.vid = wlc_hw->vendorid;
889         sha_params.did = wlc_hw->deviceid;
890         sha_params.chip = wlc_hw->sih->chip;
891         sha_params.chiprev = wlc_hw->sih->chiprev;
892         sha_params.chippkg = wlc_hw->sih->chippkg;
893         sha_params.sromrev = wlc_hw->sromrev;
894         sha_params.boardtype = wlc_hw->sih->boardtype;
895         sha_params.boardrev = wlc_hw->boardrev;
896         sha_params.boardvendor = wlc_hw->sih->boardvendor;
897         sha_params.boardflags = wlc_hw->boardflags;
898         sha_params.boardflags2 = wlc_hw->boardflags2;
899         sha_params.bustype = wlc_hw->sih->bustype;
900         sha_params.buscorerev = wlc_hw->sih->buscorerev;
901
902         /* alloc and save pointer to shared phy state area */
903         wlc_hw->phy_sh = wlc_phy_shared_attach(&sha_params);
904         if (!wlc_hw->phy_sh) {
905                 err = 16;
906                 goto fail;
907         }
908
909         /* initialize software state for each core and band */
910         for (j = 0; j < NBANDS_HW(wlc_hw); j++) {
911                 /*
912                  * band0 is always 2.4Ghz
913                  * band1, if present, is 5Ghz
914                  */
915
916                 /* So if this is a single band 11a card, use band 1 */
917                 if (IS_SINGLEBAND_5G(wlc_hw->deviceid))
918                         j = BAND_5G_INDEX;
919
920                 wlc_setxband(wlc_hw, j);
921
922                 wlc_hw->band->bandunit = j;
923                 wlc_hw->band->bandtype = j ? WLC_BAND_5G : WLC_BAND_2G;
924                 wlc->band->bandunit = j;
925                 wlc->band->bandtype = j ? WLC_BAND_5G : WLC_BAND_2G;
926                 wlc->core->coreidx = si_coreidx(wlc_hw->sih);
927
928                 if (D11REV_GE(wlc_hw->corerev, 13)) {
929                         wlc_hw->machwcap = R_REG(wlc_hw->osh, &regs->machwcap);
930                         wlc_hw->machwcap_backup = wlc_hw->machwcap;
931                 }
932
933                 /* init tx fifo size */
934                 ASSERT((wlc_hw->corerev - XMTFIFOTBL_STARTREV) <
935                        ARRAY_SIZE(xmtfifo_sz));
936                 wlc_hw->xmtfifo_sz =
937                     xmtfifo_sz[(wlc_hw->corerev - XMTFIFOTBL_STARTREV)];
938
939                 /* Get a phy for this band */
940                 wlc_hw->band->pi = wlc_phy_attach(wlc_hw->phy_sh,
941                         (void *)regs, wlc_hw->band->bandtype, vars);
942                 if (wlc_hw->band->pi == NULL) {
943                         WL_ERROR("wl%d: wlc_bmac_attach: wlc_phy_attach failed\n",
944                                  unit);
945                         err = 17;
946                         goto fail;
947                 }
948
949                 wlc_phy_machwcap_set(wlc_hw->band->pi, wlc_hw->machwcap);
950
951                 wlc_phy_get_phyversion(wlc_hw->band->pi, &wlc_hw->band->phytype,
952                                        &wlc_hw->band->phyrev,
953                                        &wlc_hw->band->radioid,
954                                        &wlc_hw->band->radiorev);
955                 wlc_hw->band->abgphy_encore =
956                     wlc_phy_get_encore(wlc_hw->band->pi);
957                 wlc->band->abgphy_encore = wlc_phy_get_encore(wlc_hw->band->pi);
958                 wlc_hw->band->core_flags =
959                     wlc_phy_get_coreflags(wlc_hw->band->pi);
960
961                 /* verify good phy_type & supported phy revision */
962                 if (WLCISNPHY(wlc_hw->band)) {
963                         if (NCONF_HAS(wlc_hw->band->phyrev))
964                                 goto good_phy;
965                         else
966                                 goto bad_phy;
967                 } else if (WLCISLCNPHY(wlc_hw->band)) {
968                         if (LCNCONF_HAS(wlc_hw->band->phyrev))
969                                 goto good_phy;
970                         else
971                                 goto bad_phy;
972                 } else {
973  bad_phy:
974                         WL_ERROR("wl%d: wlc_bmac_attach: unsupported phy type/rev (%d/%d)\n",
975                                  unit,
976                                  wlc_hw->band->phytype, wlc_hw->band->phyrev);
977                         err = 18;
978                         goto fail;
979                 }
980
981  good_phy:
982                 /* BMAC_NOTE: wlc->band->pi should not be set below and should be done in the
983                  * high level attach. However we can not make that change until all low level access
984                  * is changed to wlc_hw->band->pi. Instead do the wlc->band->pi init below, keeping
985                  * wlc_hw->band->pi as well for incremental update of low level fns, and cut over
986                  * low only init when all fns updated.
987                  */
988                 wlc->band->pi = wlc_hw->band->pi;
989                 wlc->band->phytype = wlc_hw->band->phytype;
990                 wlc->band->phyrev = wlc_hw->band->phyrev;
991                 wlc->band->radioid = wlc_hw->band->radioid;
992                 wlc->band->radiorev = wlc_hw->band->radiorev;
993
994                 /* default contention windows size limits */
995                 wlc_hw->band->CWmin = APHY_CWMIN;
996                 wlc_hw->band->CWmax = PHY_CWMAX;
997
998                 if (!wlc_bmac_attach_dmapio(wlc, j, wme)) {
999                         err = 19;
1000                         goto fail;
1001                 }
1002         }
1003
1004         /* disable core to match driver "down" state */
1005         wlc_coredisable(wlc_hw);
1006
1007         /* Match driver "down" state */
1008         if (wlc_hw->sih->bustype == PCI_BUS)
1009                 si_pci_down(wlc_hw->sih);
1010
1011         /* register sb interrupt callback functions */
1012         si_register_intr_callback(wlc_hw->sih, (void *)wlc_wlintrsoff,
1013                                   (void *)wlc_wlintrsrestore, NULL, wlc);
1014
1015         /* turn off pll and xtal to match driver "down" state */
1016         wlc_bmac_xtal(wlc_hw, OFF);
1017
1018         /* *********************************************************************
1019          * The hardware is in the DOWN state at this point. D11 core
1020          * or cores are in reset with clocks off, and the board PLLs
1021          * are off if possible.
1022          *
1023          * Beyond this point, wlc->sbclk == false and chip registers
1024          * should not be touched.
1025          *********************************************************************
1026          */
1027
1028         /* init etheraddr state variables */
1029         macaddr = wlc_get_macaddr(wlc_hw);
1030         if (macaddr == NULL) {
1031                 WL_ERROR("wl%d: wlc_bmac_attach: macaddr not found\n", unit);
1032                 err = 21;
1033                 goto fail;
1034         }
1035         bcm_ether_atoe(macaddr, &wlc_hw->etheraddr);
1036         if (is_broadcast_ether_addr(wlc_hw->etheraddr.octet) ||
1037             is_zero_ether_addr(wlc_hw->etheraddr.octet)) {
1038                 WL_ERROR("wl%d: wlc_bmac_attach: bad macaddr %s\n",
1039                          unit, macaddr);
1040                 err = 22;
1041                 goto fail;
1042         }
1043
1044         WL_ERROR("%s:: deviceid 0x%x nbands %d board 0x%x macaddr: %s\n",
1045                  __func__, wlc_hw->deviceid, wlc_hw->_nbands,
1046                  wlc_hw->sih->boardtype, macaddr);
1047
1048         return err;
1049
1050  fail:
1051         WL_ERROR("wl%d: wlc_bmac_attach: failed with err %d\n", unit, err);
1052         return err;
1053 }
1054
1055 /*
1056  * Initialize wlc_info default values ...
1057  * may get overrides later in this function
1058  *  BMAC_NOTES, move low out and resolve the dangling ones
1059  */
1060 void wlc_bmac_info_init(struct wlc_hw_info *wlc_hw)
1061 {
1062         struct wlc_info *wlc = wlc_hw->wlc;
1063
1064         /* set default sw macintmask value */
1065         wlc->defmacintmask = DEF_MACINTMASK;
1066
1067         /* various 802.11g modes */
1068         wlc_hw->shortslot = false;
1069
1070         wlc_hw->SFBL = RETRY_SHORT_FB;
1071         wlc_hw->LFBL = RETRY_LONG_FB;
1072
1073         /* default mac retry limits */
1074         wlc_hw->SRL = RETRY_SHORT_DEF;
1075         wlc_hw->LRL = RETRY_LONG_DEF;
1076         wlc_hw->chanspec = CH20MHZ_CHSPEC(1);
1077 }
1078
1079 /*
1080  * low level detach
1081  */
1082 int wlc_bmac_detach(struct wlc_info *wlc)
1083 {
1084         uint i;
1085         wlc_hwband_t *band;
1086         struct wlc_hw_info *wlc_hw = wlc->hw;
1087         int callbacks;
1088
1089         callbacks = 0;
1090
1091         if (wlc_hw->sih) {
1092                 /* detach interrupt sync mechanism since interrupt is disabled and per-port
1093                  * interrupt object may has been freed. this must be done before sb core switch
1094                  */
1095                 si_deregister_intr_callback(wlc_hw->sih);
1096
1097                 if (wlc_hw->sih->bustype == PCI_BUS)
1098                         si_pci_sleep(wlc_hw->sih);
1099         }
1100
1101         wlc_bmac_detach_dmapio(wlc_hw);
1102
1103         band = wlc_hw->band;
1104         for (i = 0; i < NBANDS_HW(wlc_hw); i++) {
1105                 if (band->pi) {
1106                         /* Detach this band's phy */
1107                         wlc_phy_detach(band->pi);
1108                         band->pi = NULL;
1109                 }
1110                 band = wlc_hw->bandstate[OTHERBANDUNIT(wlc)];
1111         }
1112
1113         /* Free shared phy state */
1114         wlc_phy_shared_detach(wlc_hw->phy_sh);
1115
1116         wlc_phy_shim_detach(wlc_hw->physhim);
1117
1118         /* free vars */
1119         if (wlc_hw->vars) {
1120                 kfree(wlc_hw->vars);
1121                 wlc_hw->vars = NULL;
1122         }
1123
1124         if (wlc_hw->sih) {
1125                 si_detach(wlc_hw->sih);
1126                 wlc_hw->sih = NULL;
1127         }
1128
1129         return callbacks;
1130
1131 }
1132
1133 void wlc_bmac_reset(struct wlc_hw_info *wlc_hw)
1134 {
1135         WL_TRACE("wl%d: wlc_bmac_reset\n", wlc_hw->unit);
1136
1137         WLCNTINCR(wlc_hw->wlc->pub->_cnt->reset);
1138
1139         /* reset the core */
1140         if (!DEVICEREMOVED(wlc_hw->wlc))
1141                 wlc_bmac_corereset(wlc_hw, WLC_USE_COREFLAGS);
1142
1143         /* purge the dma rings */
1144         wlc_flushqueues(wlc_hw->wlc);
1145
1146         wlc_reset_bmac_done(wlc_hw->wlc);
1147 }
1148
1149 void
1150 wlc_bmac_init(struct wlc_hw_info *wlc_hw, chanspec_t chanspec,
1151                           bool mute) {
1152         u32 macintmask;
1153         bool fastclk;
1154         struct wlc_info *wlc = wlc_hw->wlc;
1155
1156         WL_TRACE("wl%d: wlc_bmac_init\n", wlc_hw->unit);
1157
1158         /* request FAST clock if not on */
1159         fastclk = wlc_hw->forcefastclk;
1160         if (!fastclk)
1161                 wlc_clkctl_clk(wlc_hw, CLK_FAST);
1162
1163         /* disable interrupts */
1164         macintmask = wl_intrsoff(wlc->wl);
1165
1166         /* set up the specified band and chanspec */
1167         wlc_setxband(wlc_hw, CHSPEC_WLCBANDUNIT(chanspec));
1168         wlc_phy_chanspec_radio_set(wlc_hw->band->pi, chanspec);
1169
1170         /* do one-time phy inits and calibration */
1171         wlc_phy_cal_init(wlc_hw->band->pi);
1172
1173         /* core-specific initialization */
1174         wlc_coreinit(wlc);
1175
1176         /* suspend the tx fifos and mute the phy for preism cac time */
1177         if (mute)
1178                 wlc_bmac_mute(wlc_hw, ON, PHY_MUTE_FOR_PREISM);
1179
1180         /* band-specific inits */
1181         wlc_bmac_bsinit(wlc, chanspec);
1182
1183         /* restore macintmask */
1184         wl_intrsrestore(wlc->wl, macintmask);
1185
1186         /* seed wake_override with WLC_WAKE_OVERRIDE_MACSUSPEND since the mac is suspended
1187          * and wlc_enable_mac() will clear this override bit.
1188          */
1189         mboolset(wlc_hw->wake_override, WLC_WAKE_OVERRIDE_MACSUSPEND);
1190
1191         /*
1192          * initialize mac_suspend_depth to 1 to match ucode initial suspended state
1193          */
1194         wlc_hw->mac_suspend_depth = 1;
1195
1196         /* restore the clk */
1197         if (!fastclk)
1198                 wlc_clkctl_clk(wlc_hw, CLK_DYNAMIC);
1199 }
1200
1201 int wlc_bmac_up_prep(struct wlc_hw_info *wlc_hw)
1202 {
1203         uint coremask;
1204
1205         WL_TRACE("wl%d: %s:\n", wlc_hw->unit, __func__);
1206
1207         ASSERT(wlc_hw->wlc->pub->hw_up && wlc_hw->wlc->macintmask == 0);
1208
1209         /*
1210          * Enable pll and xtal, initialize the power control registers,
1211          * and force fastclock for the remainder of wlc_up().
1212          */
1213         wlc_bmac_xtal(wlc_hw, ON);
1214         si_clkctl_init(wlc_hw->sih);
1215         wlc_clkctl_clk(wlc_hw, CLK_FAST);
1216
1217         /*
1218          * Configure pci/pcmcia here instead of in wlc_attach()
1219          * to allow mfg hotswap:  down, hotswap (chip power cycle), up.
1220          */
1221         coremask = (1 << wlc_hw->wlc->core->coreidx);
1222
1223         if (wlc_hw->sih->bustype == PCI_BUS)
1224                 si_pci_setup(wlc_hw->sih, coremask);
1225
1226         ASSERT(si_coreid(wlc_hw->sih) == D11_CORE_ID);
1227
1228         /*
1229          * Need to read the hwradio status here to cover the case where the system
1230          * is loaded with the hw radio disabled. We do not want to bring the driver up in this case.
1231          */
1232         if (wlc_bmac_radio_read_hwdisabled(wlc_hw)) {
1233                 /* put SB PCI in down state again */
1234                 if (wlc_hw->sih->bustype == PCI_BUS)
1235                         si_pci_down(wlc_hw->sih);
1236                 wlc_bmac_xtal(wlc_hw, OFF);
1237                 return BCME_RADIOOFF;
1238         }
1239
1240         if (wlc_hw->sih->bustype == PCI_BUS)
1241                 si_pci_up(wlc_hw->sih);
1242
1243         /* reset the d11 core */
1244         wlc_bmac_corereset(wlc_hw, WLC_USE_COREFLAGS);
1245
1246         return 0;
1247 }
1248
1249 int wlc_bmac_up_finish(struct wlc_hw_info *wlc_hw)
1250 {
1251         WL_TRACE("wl%d: %s:\n", wlc_hw->unit, __func__);
1252
1253         wlc_hw->up = true;
1254         wlc_phy_hw_state_upd(wlc_hw->band->pi, true);
1255
1256         /* FULLY enable dynamic power control and d11 core interrupt */
1257         wlc_clkctl_clk(wlc_hw, CLK_DYNAMIC);
1258         ASSERT(wlc_hw->wlc->macintmask == 0);
1259         wl_intrson(wlc_hw->wlc->wl);
1260         return 0;
1261 }
1262
1263 int wlc_bmac_down_prep(struct wlc_hw_info *wlc_hw)
1264 {
1265         bool dev_gone;
1266         uint callbacks = 0;
1267
1268         WL_TRACE("wl%d: %s:\n", wlc_hw->unit, __func__);
1269
1270         if (!wlc_hw->up)
1271                 return callbacks;
1272
1273         dev_gone = DEVICEREMOVED(wlc_hw->wlc);
1274
1275         /* disable interrupts */
1276         if (dev_gone)
1277                 wlc_hw->wlc->macintmask = 0;
1278         else {
1279                 /* now disable interrupts */
1280                 wl_intrsoff(wlc_hw->wlc->wl);
1281
1282                 /* ensure we're running on the pll clock again */
1283                 wlc_clkctl_clk(wlc_hw, CLK_FAST);
1284         }
1285         /* down phy at the last of this stage */
1286         callbacks += wlc_phy_down(wlc_hw->band->pi);
1287
1288         return callbacks;
1289 }
1290
1291 int wlc_bmac_down_finish(struct wlc_hw_info *wlc_hw)
1292 {
1293         uint callbacks = 0;
1294         bool dev_gone;
1295
1296         WL_TRACE("wl%d: %s:\n", wlc_hw->unit, __func__);
1297
1298         if (!wlc_hw->up)
1299                 return callbacks;
1300
1301         wlc_hw->up = false;
1302         wlc_phy_hw_state_upd(wlc_hw->band->pi, false);
1303
1304         dev_gone = DEVICEREMOVED(wlc_hw->wlc);
1305
1306         if (dev_gone) {
1307                 wlc_hw->sbclk = false;
1308                 wlc_hw->clk = false;
1309                 wlc_phy_hw_clk_state_upd(wlc_hw->band->pi, false);
1310
1311                 /* reclaim any posted packets */
1312                 wlc_flushqueues(wlc_hw->wlc);
1313         } else {
1314
1315                 /* Reset and disable the core */
1316                 if (si_iscoreup(wlc_hw->sih)) {
1317                         if (R_REG(wlc_hw->osh, &wlc_hw->regs->maccontrol) &
1318                             MCTL_EN_MAC)
1319                                 wlc_suspend_mac_and_wait(wlc_hw->wlc);
1320                         callbacks += wl_reset(wlc_hw->wlc->wl);
1321                         wlc_coredisable(wlc_hw);
1322                 }
1323
1324                 /* turn off primary xtal and pll */
1325                 if (!wlc_hw->noreset) {
1326                         if (wlc_hw->sih->bustype == PCI_BUS)
1327                                 si_pci_down(wlc_hw->sih);
1328                         wlc_bmac_xtal(wlc_hw, OFF);
1329                 }
1330         }
1331
1332         return callbacks;
1333 }
1334
1335 void wlc_bmac_wait_for_wake(struct wlc_hw_info *wlc_hw)
1336 {
1337         if (D11REV_IS(wlc_hw->corerev, 4))      /* no slowclock */
1338                 udelay(5);
1339         else {
1340                 /* delay before first read of ucode state */
1341                 udelay(40);
1342
1343                 /* wait until ucode is no longer asleep */
1344                 SPINWAIT((wlc_bmac_read_shm(wlc_hw, M_UCODE_DBGST) ==
1345                           DBGST_ASLEEP), wlc_hw->wlc->fastpwrup_dly);
1346         }
1347
1348         ASSERT(wlc_bmac_read_shm(wlc_hw, M_UCODE_DBGST) != DBGST_ASLEEP);
1349 }
1350
1351 void wlc_bmac_hw_etheraddr(struct wlc_hw_info *wlc_hw, struct ether_addr *ea)
1352 {
1353         bcopy(&wlc_hw->etheraddr, ea, ETH_ALEN);
1354 }
1355
1356 void wlc_bmac_set_hw_etheraddr(struct wlc_hw_info *wlc_hw,
1357                                struct ether_addr *ea)
1358 {
1359         bcopy(ea, &wlc_hw->etheraddr, ETH_ALEN);
1360 }
1361
1362 int wlc_bmac_bandtype(struct wlc_hw_info *wlc_hw)
1363 {
1364         return wlc_hw->band->bandtype;
1365 }
1366
1367 void *wlc_cur_phy(struct wlc_info *wlc)
1368 {
1369         struct wlc_hw_info *wlc_hw = wlc->hw;
1370         return (void *)wlc_hw->band->pi;
1371 }
1372
1373 /* control chip clock to save power, enable dynamic clock or force fast clock */
1374 static void wlc_clkctl_clk(struct wlc_hw_info *wlc_hw, uint mode)
1375 {
1376         if (PMUCTL_ENAB(wlc_hw->sih)) {
1377                 /* new chips with PMU, CCS_FORCEHT will distribute the HT clock on backplane,
1378                  *  but mac core will still run on ALP(not HT) when it enters powersave mode,
1379                  *      which means the FCA bit may not be set.
1380                  *      should wakeup mac if driver wants it to run on HT.
1381                  */
1382
1383                 if (wlc_hw->clk) {
1384                         if (mode == CLK_FAST) {
1385                                 OR_REG(wlc_hw->osh, &wlc_hw->regs->clk_ctl_st,
1386                                        CCS_FORCEHT);
1387
1388                                 udelay(64);
1389
1390                                 SPINWAIT(((R_REG
1391                                            (wlc_hw->osh,
1392                                             &wlc_hw->regs->
1393                                             clk_ctl_st) & CCS_HTAVAIL) == 0),
1394                                          PMU_MAX_TRANSITION_DLY);
1395                                 ASSERT(R_REG
1396                                        (wlc_hw->osh,
1397                                         &wlc_hw->regs->
1398                                         clk_ctl_st) & CCS_HTAVAIL);
1399                         } else {
1400                                 if ((wlc_hw->sih->pmurev == 0) &&
1401                                     (R_REG
1402                                      (wlc_hw->osh,
1403                                       &wlc_hw->regs->
1404                                       clk_ctl_st) & (CCS_FORCEHT | CCS_HTAREQ)))
1405                                         SPINWAIT(((R_REG
1406                                                    (wlc_hw->osh,
1407                                                     &wlc_hw->regs->
1408                                                     clk_ctl_st) & CCS_HTAVAIL)
1409                                                   == 0),
1410                                                  PMU_MAX_TRANSITION_DLY);
1411                                 AND_REG(wlc_hw->osh, &wlc_hw->regs->clk_ctl_st,
1412                                         ~CCS_FORCEHT);
1413                         }
1414                 }
1415                 wlc_hw->forcefastclk = (mode == CLK_FAST);
1416         } else {
1417                 bool wakeup_ucode;
1418
1419                 /* old chips w/o PMU, force HT through cc,
1420                  * then use FCA to verify mac is running fast clock
1421                  */
1422
1423                 wakeup_ucode = D11REV_LT(wlc_hw->corerev, 9);
1424
1425                 if (wlc_hw->up && wakeup_ucode)
1426                         wlc_ucode_wake_override_set(wlc_hw,
1427                                                     WLC_WAKE_OVERRIDE_CLKCTL);
1428
1429                 wlc_hw->forcefastclk = si_clkctl_cc(wlc_hw->sih, mode);
1430
1431                 if (D11REV_LT(wlc_hw->corerev, 11)) {
1432                         /* ucode WAR for old chips */
1433                         if (wlc_hw->forcefastclk)
1434                                 wlc_bmac_mhf(wlc_hw, MHF1, MHF1_FORCEFASTCLK,
1435                                              MHF1_FORCEFASTCLK, WLC_BAND_ALL);
1436                         else
1437                                 wlc_bmac_mhf(wlc_hw, MHF1, MHF1_FORCEFASTCLK, 0,
1438                                              WLC_BAND_ALL);
1439                 }
1440
1441                 /* check fast clock is available (if core is not in reset) */
1442                 if (D11REV_GT(wlc_hw->corerev, 4) && wlc_hw->forcefastclk
1443                     && wlc_hw->clk)
1444                         ASSERT(si_core_sflags(wlc_hw->sih, 0, 0) & SISF_FCLKA);
1445
1446                 /* keep the ucode wake bit on if forcefastclk is on
1447                  * since we do not want ucode to put us back to slow clock
1448                  * when it dozes for PM mode.
1449                  * Code below matches the wake override bit with current forcefastclk state
1450                  * Only setting bit in wake_override instead of waking ucode immediately
1451                  * since old code (wlc.c 1.4499) had this behavior. Older code set
1452                  * wlc->forcefastclk but only had the wake happen if the wakup_ucode work
1453                  * (protected by an up check) was executed just below.
1454                  */
1455                 if (wlc_hw->forcefastclk)
1456                         mboolset(wlc_hw->wake_override,
1457                                  WLC_WAKE_OVERRIDE_FORCEFAST);
1458                 else
1459                         mboolclr(wlc_hw->wake_override,
1460                                  WLC_WAKE_OVERRIDE_FORCEFAST);
1461
1462                 /* ok to clear the wakeup now */
1463                 if (wlc_hw->up && wakeup_ucode)
1464                         wlc_ucode_wake_override_clear(wlc_hw,
1465                                                       WLC_WAKE_OVERRIDE_CLKCTL);
1466         }
1467 }
1468
1469 /* set initial host flags value */
1470 static void
1471 wlc_mhfdef(struct wlc_info *wlc, u16 *mhfs, u16 mhf2_init)
1472 {
1473         struct wlc_hw_info *wlc_hw = wlc->hw;
1474
1475         memset(mhfs, 0, MHFMAX * sizeof(u16));
1476
1477         mhfs[MHF2] |= mhf2_init;
1478
1479         /* prohibit use of slowclock on multifunction boards */
1480         if (wlc_hw->boardflags & BFL_NOPLLDOWN)
1481                 mhfs[MHF1] |= MHF1_FORCEFASTCLK;
1482
1483         if (WLCISNPHY(wlc_hw->band) && NREV_LT(wlc_hw->band->phyrev, 2)) {
1484                 mhfs[MHF2] |= MHF2_NPHY40MHZ_WAR;
1485                 mhfs[MHF1] |= MHF1_IQSWAP_WAR;
1486         }
1487 }
1488
1489 /* set or clear ucode host flag bits
1490  * it has an optimization for no-change write
1491  * it only writes through shared memory when the core has clock;
1492  * pre-CLK changes should use wlc_write_mhf to get around the optimization
1493  *
1494  *
1495  * bands values are: WLC_BAND_AUTO <--- Current band only
1496  *                   WLC_BAND_5G   <--- 5G band only
1497  *                   WLC_BAND_2G   <--- 2G band only
1498  *                   WLC_BAND_ALL  <--- All bands
1499  */
1500 void
1501 wlc_bmac_mhf(struct wlc_hw_info *wlc_hw, u8 idx, u16 mask, u16 val,
1502              int bands)
1503 {
1504         u16 save;
1505         u16 addr[MHFMAX] = {
1506                 M_HOST_FLAGS1, M_HOST_FLAGS2, M_HOST_FLAGS3, M_HOST_FLAGS4,
1507                 M_HOST_FLAGS5
1508         };
1509         wlc_hwband_t *band;
1510
1511         ASSERT((val & ~mask) == 0);
1512         ASSERT(idx < MHFMAX);
1513         ASSERT(ARRAY_SIZE(addr) == MHFMAX);
1514
1515         switch (bands) {
1516                 /* Current band only or all bands,
1517                  * then set the band to current band
1518                  */
1519         case WLC_BAND_AUTO:
1520         case WLC_BAND_ALL:
1521                 band = wlc_hw->band;
1522                 break;
1523         case WLC_BAND_5G:
1524                 band = wlc_hw->bandstate[BAND_5G_INDEX];
1525                 break;
1526         case WLC_BAND_2G:
1527                 band = wlc_hw->bandstate[BAND_2G_INDEX];
1528                 break;
1529         default:
1530                 ASSERT(0);
1531                 band = NULL;
1532         }
1533
1534         if (band) {
1535                 save = band->mhfs[idx];
1536                 band->mhfs[idx] = (band->mhfs[idx] & ~mask) | val;
1537
1538                 /* optimization: only write through if changed, and
1539                  * changed band is the current band
1540                  */
1541                 if (wlc_hw->clk && (band->mhfs[idx] != save)
1542                     && (band == wlc_hw->band))
1543                         wlc_bmac_write_shm(wlc_hw, addr[idx],
1544                                            (u16) band->mhfs[idx]);
1545         }
1546
1547         if (bands == WLC_BAND_ALL) {
1548                 wlc_hw->bandstate[0]->mhfs[idx] =
1549                     (wlc_hw->bandstate[0]->mhfs[idx] & ~mask) | val;
1550                 wlc_hw->bandstate[1]->mhfs[idx] =
1551                     (wlc_hw->bandstate[1]->mhfs[idx] & ~mask) | val;
1552         }
1553 }
1554
1555 u16 wlc_bmac_mhf_get(struct wlc_hw_info *wlc_hw, u8 idx, int bands)
1556 {
1557         wlc_hwband_t *band;
1558         ASSERT(idx < MHFMAX);
1559
1560         switch (bands) {
1561         case WLC_BAND_AUTO:
1562                 band = wlc_hw->band;
1563                 break;
1564         case WLC_BAND_5G:
1565                 band = wlc_hw->bandstate[BAND_5G_INDEX];
1566                 break;
1567         case WLC_BAND_2G:
1568                 band = wlc_hw->bandstate[BAND_2G_INDEX];
1569                 break;
1570         default:
1571                 ASSERT(0);
1572                 band = NULL;
1573         }
1574
1575         if (!band)
1576                 return 0;
1577
1578         return band->mhfs[idx];
1579 }
1580
1581 static void wlc_write_mhf(struct wlc_hw_info *wlc_hw, u16 *mhfs)
1582 {
1583         u8 idx;
1584         u16 addr[] = {
1585                 M_HOST_FLAGS1, M_HOST_FLAGS2, M_HOST_FLAGS3, M_HOST_FLAGS4,
1586                 M_HOST_FLAGS5
1587         };
1588
1589         ASSERT(ARRAY_SIZE(addr) == MHFMAX);
1590
1591         for (idx = 0; idx < MHFMAX; idx++) {
1592                 wlc_bmac_write_shm(wlc_hw, addr[idx], mhfs[idx]);
1593         }
1594 }
1595
1596 /* set the maccontrol register to desired reset state and
1597  * initialize the sw cache of the register
1598  */
1599 static void wlc_mctrl_reset(struct wlc_hw_info *wlc_hw)
1600 {
1601         /* IHR accesses are always enabled, PSM disabled, HPS off and WAKE on */
1602         wlc_hw->maccontrol = 0;
1603         wlc_hw->suspended_fifos = 0;
1604         wlc_hw->wake_override = 0;
1605         wlc_hw->mute_override = 0;
1606         wlc_bmac_mctrl(wlc_hw, ~0, MCTL_IHR_EN | MCTL_WAKE);
1607 }
1608
1609 /* set or clear maccontrol bits */
1610 void wlc_bmac_mctrl(struct wlc_hw_info *wlc_hw, u32 mask, u32 val)
1611 {
1612         u32 maccontrol;
1613         u32 new_maccontrol;
1614
1615         ASSERT((val & ~mask) == 0);
1616
1617         maccontrol = wlc_hw->maccontrol;
1618         new_maccontrol = (maccontrol & ~mask) | val;
1619
1620         /* if the new maccontrol value is the same as the old, nothing to do */
1621         if (new_maccontrol == maccontrol)
1622                 return;
1623
1624         /* something changed, cache the new value */
1625         wlc_hw->maccontrol = new_maccontrol;
1626
1627         /* write the new values with overrides applied */
1628         wlc_mctrl_write(wlc_hw);
1629 }
1630
1631 /* write the software state of maccontrol and overrides to the maccontrol register */
1632 static void wlc_mctrl_write(struct wlc_hw_info *wlc_hw)
1633 {
1634         u32 maccontrol = wlc_hw->maccontrol;
1635
1636         /* OR in the wake bit if overridden */
1637         if (wlc_hw->wake_override)
1638                 maccontrol |= MCTL_WAKE;
1639
1640         /* set AP and INFRA bits for mute if needed */
1641         if (wlc_hw->mute_override) {
1642                 maccontrol &= ~(MCTL_AP);
1643                 maccontrol |= MCTL_INFRA;
1644         }
1645
1646         W_REG(wlc_hw->osh, &wlc_hw->regs->maccontrol, maccontrol);
1647 }
1648
1649 void wlc_ucode_wake_override_set(struct wlc_hw_info *wlc_hw, u32 override_bit)
1650 {
1651         ASSERT((wlc_hw->wake_override & override_bit) == 0);
1652
1653         if (wlc_hw->wake_override || (wlc_hw->maccontrol & MCTL_WAKE)) {
1654                 mboolset(wlc_hw->wake_override, override_bit);
1655                 return;
1656         }
1657
1658         mboolset(wlc_hw->wake_override, override_bit);
1659
1660         wlc_mctrl_write(wlc_hw);
1661         wlc_bmac_wait_for_wake(wlc_hw);
1662
1663         return;
1664 }
1665
1666 void wlc_ucode_wake_override_clear(struct wlc_hw_info *wlc_hw, u32 override_bit)
1667 {
1668         ASSERT(wlc_hw->wake_override & override_bit);
1669
1670         mboolclr(wlc_hw->wake_override, override_bit);
1671
1672         if (wlc_hw->wake_override || (wlc_hw->maccontrol & MCTL_WAKE))
1673                 return;
1674
1675         wlc_mctrl_write(wlc_hw);
1676
1677         return;
1678 }
1679
1680 /* When driver needs ucode to stop beaconing, it has to make sure that
1681  * MCTL_AP is clear and MCTL_INFRA is set
1682  * Mode           MCTL_AP        MCTL_INFRA
1683  * AP                1              1
1684  * STA               0              1 <--- This will ensure no beacons
1685  * IBSS              0              0
1686  */
1687 static void wlc_ucode_mute_override_set(struct wlc_hw_info *wlc_hw)
1688 {
1689         wlc_hw->mute_override = 1;
1690
1691         /* if maccontrol already has AP == 0 and INFRA == 1 without this
1692          * override, then there is no change to write
1693          */
1694         if ((wlc_hw->maccontrol & (MCTL_AP | MCTL_INFRA)) == MCTL_INFRA)
1695                 return;
1696
1697         wlc_mctrl_write(wlc_hw);
1698
1699         return;
1700 }
1701
1702 /* Clear the override on AP and INFRA bits */
1703 static void wlc_ucode_mute_override_clear(struct wlc_hw_info *wlc_hw)
1704 {
1705         if (wlc_hw->mute_override == 0)
1706                 return;
1707
1708         wlc_hw->mute_override = 0;
1709
1710         /* if maccontrol already has AP == 0 and INFRA == 1 without this
1711          * override, then there is no change to write
1712          */
1713         if ((wlc_hw->maccontrol & (MCTL_AP | MCTL_INFRA)) == MCTL_INFRA)
1714                 return;
1715
1716         wlc_mctrl_write(wlc_hw);
1717 }
1718
1719 /*
1720  * Write a MAC address to the rcmta structure
1721  */
1722 void
1723 wlc_bmac_set_rcmta(struct wlc_hw_info *wlc_hw, int idx,
1724                    const struct ether_addr *addr)
1725 {
1726         d11regs_t *regs = wlc_hw->regs;
1727         volatile u16 *objdata16 = (volatile u16 *)&regs->objdata;
1728         u32 mac_hm;
1729         u16 mac_l;
1730         struct osl_info *osh;
1731
1732         WL_TRACE("wl%d: %s\n", wlc_hw->unit, __func__);
1733
1734         ASSERT(wlc_hw->corerev > 4);
1735
1736         mac_hm =
1737             (addr->octet[3] << 24) | (addr->octet[2] << 16) | (addr->
1738                                                                octet[1] << 8) |
1739             addr->octet[0];
1740         mac_l = (addr->octet[5] << 8) | addr->octet[4];
1741
1742         osh = wlc_hw->osh;
1743
1744         W_REG(osh, &regs->objaddr, (OBJADDR_RCMTA_SEL | (idx * 2)));
1745         (void)R_REG(osh, &regs->objaddr);
1746         W_REG(osh, &regs->objdata, mac_hm);
1747         W_REG(osh, &regs->objaddr, (OBJADDR_RCMTA_SEL | ((idx * 2) + 1)));
1748         (void)R_REG(osh, &regs->objaddr);
1749         W_REG(osh, objdata16, mac_l);
1750 }
1751
1752 /*
1753  * Write a MAC address to the given match reg offset in the RXE match engine.
1754  */
1755 void
1756 wlc_bmac_set_addrmatch(struct wlc_hw_info *wlc_hw, int match_reg_offset,
1757                        const struct ether_addr *addr)
1758 {
1759         d11regs_t *regs;
1760         u16 mac_l;
1761         u16 mac_m;
1762         u16 mac_h;
1763         struct osl_info *osh;
1764
1765         WL_TRACE("wl%d: wlc_bmac_set_addrmatch\n", wlc_hw->unit);
1766
1767         ASSERT((match_reg_offset < RCM_SIZE) || (wlc_hw->corerev == 4));
1768
1769         regs = wlc_hw->regs;
1770         mac_l = addr->octet[0] | (addr->octet[1] << 8);
1771         mac_m = addr->octet[2] | (addr->octet[3] << 8);
1772         mac_h = addr->octet[4] | (addr->octet[5] << 8);
1773
1774         osh = wlc_hw->osh;
1775
1776         /* enter the MAC addr into the RXE match registers */
1777         W_REG(osh, &regs->rcm_ctl, RCM_INC_DATA | match_reg_offset);
1778         W_REG(osh, &regs->rcm_mat_data, mac_l);
1779         W_REG(osh, &regs->rcm_mat_data, mac_m);
1780         W_REG(osh, &regs->rcm_mat_data, mac_h);
1781
1782 }
1783
1784 void
1785 wlc_bmac_write_template_ram(struct wlc_hw_info *wlc_hw, int offset, int len,
1786                             void *buf)
1787 {
1788         d11regs_t *regs;
1789         u32 word;
1790         bool be_bit;
1791 #ifdef IL_BIGENDIAN
1792         volatile u16 *dptr = NULL;
1793 #endif                          /* IL_BIGENDIAN */
1794         struct osl_info *osh;
1795
1796         WL_TRACE("wl%d: wlc_bmac_write_template_ram\n", wlc_hw->unit);
1797
1798         regs = wlc_hw->regs;
1799         osh = wlc_hw->osh;
1800
1801         ASSERT(IS_ALIGNED(offset, sizeof(u32)));
1802         ASSERT(IS_ALIGNED(len, sizeof(u32)));
1803         ASSERT((offset & ~0xffff) == 0);
1804
1805         W_REG(osh, &regs->tplatewrptr, offset);
1806
1807         /* if MCTL_BIGEND bit set in mac control register,
1808          * the chip swaps data in fifo, as well as data in
1809          * template ram
1810          */
1811         be_bit = (R_REG(osh, &regs->maccontrol) & MCTL_BIGEND) != 0;
1812
1813         while (len > 0) {
1814                 bcopy((u8 *) buf, &word, sizeof(u32));
1815
1816                 if (be_bit)
1817                         word = hton32(word);
1818                 else
1819                         word = htol32(word);
1820
1821                 W_REG(osh, &regs->tplatewrdata, word);
1822
1823                 buf = (u8 *) buf + sizeof(u32);
1824                 len -= sizeof(u32);
1825         }
1826 }
1827
1828 void wlc_bmac_set_cwmin(struct wlc_hw_info *wlc_hw, u16 newmin)
1829 {
1830         struct osl_info *osh;
1831
1832         osh = wlc_hw->osh;
1833         wlc_hw->band->CWmin = newmin;
1834
1835         W_REG(osh, &wlc_hw->regs->objaddr, OBJADDR_SCR_SEL | S_DOT11_CWMIN);
1836         (void)R_REG(osh, &wlc_hw->regs->objaddr);
1837         W_REG(osh, &wlc_hw->regs->objdata, newmin);
1838 }
1839
1840 void wlc_bmac_set_cwmax(struct wlc_hw_info *wlc_hw, u16 newmax)
1841 {
1842         struct osl_info *osh;
1843
1844         osh = wlc_hw->osh;
1845         wlc_hw->band->CWmax = newmax;
1846
1847         W_REG(osh, &wlc_hw->regs->objaddr, OBJADDR_SCR_SEL | S_DOT11_CWMAX);
1848         (void)R_REG(osh, &wlc_hw->regs->objaddr);
1849         W_REG(osh, &wlc_hw->regs->objdata, newmax);
1850 }
1851
1852 void wlc_bmac_bw_set(struct wlc_hw_info *wlc_hw, u16 bw)
1853 {
1854         bool fastclk;
1855         u32 tmp;
1856
1857         /* request FAST clock if not on */
1858         fastclk = wlc_hw->forcefastclk;
1859         if (!fastclk)
1860                 wlc_clkctl_clk(wlc_hw, CLK_FAST);
1861
1862         wlc_phy_bw_state_set(wlc_hw->band->pi, bw);
1863
1864         ASSERT(wlc_hw->clk);
1865         if (D11REV_LT(wlc_hw->corerev, 17))
1866                 tmp = R_REG(wlc_hw->osh, &wlc_hw->regs->maccontrol);
1867
1868         wlc_bmac_phy_reset(wlc_hw);
1869         wlc_phy_init(wlc_hw->band->pi, wlc_phy_chanspec_get(wlc_hw->band->pi));
1870
1871         /* restore the clk */
1872         if (!fastclk)
1873                 wlc_clkctl_clk(wlc_hw, CLK_DYNAMIC);
1874 }
1875
1876 static void
1877 wlc_write_hw_bcntemplate0(struct wlc_hw_info *wlc_hw, void *bcn, int len)
1878 {
1879         d11regs_t *regs = wlc_hw->regs;
1880
1881         wlc_bmac_write_template_ram(wlc_hw, T_BCN0_TPL_BASE, (len + 3) & ~3,
1882                                     bcn);
1883         /* write beacon length to SCR */
1884         ASSERT(len < 65536);
1885         wlc_bmac_write_shm(wlc_hw, M_BCN0_FRM_BYTESZ, (u16) len);
1886         /* mark beacon0 valid */
1887         OR_REG(wlc_hw->osh, &regs->maccommand, MCMD_BCN0VLD);
1888 }
1889
1890 static void
1891 wlc_write_hw_bcntemplate1(struct wlc_hw_info *wlc_hw, void *bcn, int len)
1892 {
1893         d11regs_t *regs = wlc_hw->regs;
1894
1895         wlc_bmac_write_template_ram(wlc_hw, T_BCN1_TPL_BASE, (len + 3) & ~3,
1896                                     bcn);
1897         /* write beacon length to SCR */
1898         ASSERT(len < 65536);
1899         wlc_bmac_write_shm(wlc_hw, M_BCN1_FRM_BYTESZ, (u16) len);
1900         /* mark beacon1 valid */
1901         OR_REG(wlc_hw->osh, &regs->maccommand, MCMD_BCN1VLD);
1902 }
1903
1904 /* mac is assumed to be suspended at this point */
1905 void
1906 wlc_bmac_write_hw_bcntemplates(struct wlc_hw_info *wlc_hw, void *bcn, int len,
1907                                bool both)
1908 {
1909         d11regs_t *regs = wlc_hw->regs;
1910
1911         if (both) {
1912                 wlc_write_hw_bcntemplate0(wlc_hw, bcn, len);
1913                 wlc_write_hw_bcntemplate1(wlc_hw, bcn, len);
1914         } else {
1915                 /* bcn 0 */
1916                 if (!(R_REG(wlc_hw->osh, &regs->maccommand) & MCMD_BCN0VLD))
1917                         wlc_write_hw_bcntemplate0(wlc_hw, bcn, len);
1918                 /* bcn 1 */
1919                 else if (!
1920                          (R_REG(wlc_hw->osh, &regs->maccommand) & MCMD_BCN1VLD))
1921                         wlc_write_hw_bcntemplate1(wlc_hw, bcn, len);
1922                 else            /* one template should always have been available */
1923                         ASSERT(0);
1924         }
1925 }
1926
1927 static void WLBANDINITFN(wlc_bmac_upd_synthpu) (struct wlc_hw_info *wlc_hw)
1928 {
1929         u16 v;
1930         struct wlc_info *wlc = wlc_hw->wlc;
1931         /* update SYNTHPU_DLY */
1932
1933         if (WLCISLCNPHY(wlc->band)) {
1934                 v = SYNTHPU_DLY_LPPHY_US;
1935         } else if (WLCISNPHY(wlc->band) && (NREV_GE(wlc->band->phyrev, 3))) {
1936                 v = SYNTHPU_DLY_NPHY_US;
1937         } else {
1938                 v = SYNTHPU_DLY_BPHY_US;
1939         }
1940
1941         wlc_bmac_write_shm(wlc_hw, M_SYNTHPU_DLY, v);
1942 }
1943
1944 /* band-specific init */
1945 static void
1946 WLBANDINITFN(wlc_bmac_bsinit) (struct wlc_info *wlc, chanspec_t chanspec)
1947 {
1948         struct wlc_hw_info *wlc_hw = wlc->hw;
1949
1950         WL_TRACE("wl%d: wlc_bmac_bsinit: bandunit %d\n",
1951                  wlc_hw->unit, wlc_hw->band->bandunit);
1952
1953         /* sanity check */
1954         if (PHY_TYPE(R_REG(wlc_hw->osh, &wlc_hw->regs->phyversion)) !=
1955             PHY_TYPE_LCNXN)
1956                 ASSERT((uint)
1957                        PHY_TYPE(R_REG(wlc_hw->osh, &wlc_hw->regs->phyversion))
1958                        == wlc_hw->band->phytype);
1959
1960         wlc_ucode_bsinit(wlc_hw);
1961
1962         wlc_phy_init(wlc_hw->band->pi, chanspec);
1963
1964         wlc_ucode_txant_set(wlc_hw);
1965
1966         /* cwmin is band-specific, update hardware with value for current band */
1967         wlc_bmac_set_cwmin(wlc_hw, wlc_hw->band->CWmin);
1968         wlc_bmac_set_cwmax(wlc_hw, wlc_hw->band->CWmax);
1969
1970         wlc_bmac_update_slot_timing(wlc_hw,
1971                                     BAND_5G(wlc_hw->band->
1972                                             bandtype) ? true : wlc_hw->
1973                                     shortslot);
1974
1975         /* write phytype and phyvers */
1976         wlc_bmac_write_shm(wlc_hw, M_PHYTYPE, (u16) wlc_hw->band->phytype);
1977         wlc_bmac_write_shm(wlc_hw, M_PHYVER, (u16) wlc_hw->band->phyrev);
1978
1979         /* initialize the txphyctl1 rate table since shmem is shared between bands */
1980         wlc_upd_ofdm_pctl1_table(wlc_hw);
1981
1982         wlc_bmac_upd_synthpu(wlc_hw);
1983 }
1984
1985 void wlc_bmac_core_phy_clk(struct wlc_hw_info *wlc_hw, bool clk)
1986 {
1987         WL_TRACE("wl%d: wlc_bmac_core_phy_clk: clk %d\n", wlc_hw->unit, clk);
1988
1989         wlc_hw->phyclk = clk;
1990
1991         if (OFF == clk) {       /* clear gmode bit, put phy into reset */
1992
1993                 si_core_cflags(wlc_hw->sih, (SICF_PRST | SICF_FGC | SICF_GMODE),
1994                                (SICF_PRST | SICF_FGC));
1995                 udelay(1);
1996                 si_core_cflags(wlc_hw->sih, (SICF_PRST | SICF_FGC), SICF_PRST);
1997                 udelay(1);
1998
1999         } else {                /* take phy out of reset */
2000
2001                 si_core_cflags(wlc_hw->sih, (SICF_PRST | SICF_FGC), SICF_FGC);
2002                 udelay(1);
2003                 si_core_cflags(wlc_hw->sih, (SICF_FGC), 0);
2004                 udelay(1);
2005
2006         }
2007 }
2008
2009 /* Perform a soft reset of the PHY PLL */
2010 void wlc_bmac_core_phypll_reset(struct wlc_hw_info *wlc_hw)
2011 {
2012         WL_TRACE("wl%d: wlc_bmac_core_phypll_reset\n", wlc_hw->unit);
2013
2014         si_corereg(wlc_hw->sih, SI_CC_IDX,
2015                    offsetof(chipcregs_t, chipcontrol_addr), ~0, 0);
2016         udelay(1);
2017         si_corereg(wlc_hw->sih, SI_CC_IDX,
2018                    offsetof(chipcregs_t, chipcontrol_data), 0x4, 0);
2019         udelay(1);
2020         si_corereg(wlc_hw->sih, SI_CC_IDX,
2021                    offsetof(chipcregs_t, chipcontrol_data), 0x4, 4);
2022         udelay(1);
2023         si_corereg(wlc_hw->sih, SI_CC_IDX,
2024                    offsetof(chipcregs_t, chipcontrol_data), 0x4, 0);
2025         udelay(1);
2026 }
2027
2028 /* light way to turn on phy clock without reset for NPHY only
2029  *  refer to wlc_bmac_core_phy_clk for full version
2030  */
2031 void wlc_bmac_phyclk_fgc(struct wlc_hw_info *wlc_hw, bool clk)
2032 {
2033         /* support(necessary for NPHY and HYPHY) only */
2034         if (!WLCISNPHY(wlc_hw->band))
2035                 return;
2036
2037         if (ON == clk)
2038                 si_core_cflags(wlc_hw->sih, SICF_FGC, SICF_FGC);
2039         else
2040                 si_core_cflags(wlc_hw->sih, SICF_FGC, 0);
2041
2042 }
2043
2044 void wlc_bmac_macphyclk_set(struct wlc_hw_info *wlc_hw, bool clk)
2045 {
2046         if (ON == clk)
2047                 si_core_cflags(wlc_hw->sih, SICF_MPCLKE, SICF_MPCLKE);
2048         else
2049                 si_core_cflags(wlc_hw->sih, SICF_MPCLKE, 0);
2050 }
2051
2052 void wlc_bmac_phy_reset(struct wlc_hw_info *wlc_hw)
2053 {
2054         wlc_phy_t *pih = wlc_hw->band->pi;
2055         u32 phy_bw_clkbits;
2056         bool phy_in_reset = false;
2057
2058         WL_TRACE("wl%d: wlc_bmac_phy_reset\n", wlc_hw->unit);
2059
2060         if (pih == NULL)
2061                 return;
2062
2063         phy_bw_clkbits = wlc_phy_clk_bwbits(wlc_hw->band->pi);
2064
2065         /* Specfic reset sequence required for NPHY rev 3 and 4 */
2066         if (WLCISNPHY(wlc_hw->band) && NREV_GE(wlc_hw->band->phyrev, 3) &&
2067             NREV_LE(wlc_hw->band->phyrev, 4)) {
2068                 /* Set the PHY bandwidth */
2069                 si_core_cflags(wlc_hw->sih, SICF_BWMASK, phy_bw_clkbits);
2070
2071                 udelay(1);
2072
2073                 /* Perform a soft reset of the PHY PLL */
2074                 wlc_bmac_core_phypll_reset(wlc_hw);
2075
2076                 /* reset the PHY */
2077                 si_core_cflags(wlc_hw->sih, (SICF_PRST | SICF_PCLKE),
2078                                (SICF_PRST | SICF_PCLKE));
2079                 phy_in_reset = true;
2080         } else {
2081
2082                 si_core_cflags(wlc_hw->sih,
2083                                (SICF_PRST | SICF_PCLKE | SICF_BWMASK),
2084                                (SICF_PRST | SICF_PCLKE | phy_bw_clkbits));
2085         }
2086
2087         udelay(2);
2088         wlc_bmac_core_phy_clk(wlc_hw, ON);
2089
2090         if (pih)
2091                 wlc_phy_anacore(pih, ON);
2092 }
2093
2094 /* switch to and initialize new band */
2095 static void
2096 WLBANDINITFN(wlc_bmac_setband) (struct wlc_hw_info *wlc_hw, uint bandunit,
2097                                 chanspec_t chanspec) {
2098         struct wlc_info *wlc = wlc_hw->wlc;
2099         u32 macintmask;
2100
2101         ASSERT(NBANDS_HW(wlc_hw) > 1);
2102         ASSERT(bandunit != wlc_hw->band->bandunit);
2103
2104         /* Enable the d11 core before accessing it */
2105         if (!si_iscoreup(wlc_hw->sih)) {
2106                 si_core_reset(wlc_hw->sih, 0, 0);
2107                 ASSERT(si_iscoreup(wlc_hw->sih));
2108                 wlc_mctrl_reset(wlc_hw);
2109         }
2110
2111         macintmask = wlc_setband_inact(wlc, bandunit);
2112
2113         if (!wlc_hw->up)
2114                 return;
2115
2116         wlc_bmac_core_phy_clk(wlc_hw, ON);
2117
2118         /* band-specific initializations */
2119         wlc_bmac_bsinit(wlc, chanspec);
2120
2121         /*
2122          * If there are any pending software interrupt bits,
2123          * then replace these with a harmless nonzero value
2124          * so wlc_dpc() will re-enable interrupts when done.
2125          */
2126         if (wlc->macintstatus)
2127                 wlc->macintstatus = MI_DMAINT;
2128
2129         /* restore macintmask */
2130         wl_intrsrestore(wlc->wl, macintmask);
2131
2132         /* ucode should still be suspended.. */
2133         ASSERT((R_REG(wlc_hw->osh, &wlc_hw->regs->maccontrol) & MCTL_EN_MAC) ==
2134                0);
2135 }
2136
2137 /* low-level band switch utility routine */
2138 void WLBANDINITFN(wlc_setxband) (struct wlc_hw_info *wlc_hw, uint bandunit)
2139 {
2140         WL_TRACE("wl%d: wlc_setxband: bandunit %d\n", wlc_hw->unit, bandunit);
2141
2142         wlc_hw->band = wlc_hw->bandstate[bandunit];
2143
2144         /* BMAC_NOTE: until we eliminate need for wlc->band refs in low level code */
2145         wlc_hw->wlc->band = wlc_hw->wlc->bandstate[bandunit];
2146
2147         /* set gmode core flag */
2148         if (wlc_hw->sbclk && !wlc_hw->noreset) {
2149                 si_core_cflags(wlc_hw->sih, SICF_GMODE,
2150                                ((bandunit == 0) ? SICF_GMODE : 0));
2151         }
2152 }
2153
2154 static bool wlc_isgoodchip(struct wlc_hw_info *wlc_hw)
2155 {
2156
2157         /* reject unsupported corerev */
2158         if (!VALID_COREREV(wlc_hw->corerev)) {
2159                 WL_ERROR("unsupported core rev %d\n", wlc_hw->corerev);
2160                 return false;
2161         }
2162
2163         return true;
2164 }
2165
2166 static bool wlc_validboardtype(struct wlc_hw_info *wlc_hw)
2167 {
2168         bool goodboard = true;
2169         uint boardrev = wlc_hw->boardrev;
2170
2171         if (boardrev == 0)
2172                 goodboard = false;
2173         else if (boardrev > 0xff) {
2174                 uint brt = (boardrev & 0xf000) >> 12;
2175                 uint b0 = (boardrev & 0xf00) >> 8;
2176                 uint b1 = (boardrev & 0xf0) >> 4;
2177                 uint b2 = boardrev & 0xf;
2178
2179                 if ((brt > 2) || (brt == 0) || (b0 > 9) || (b0 == 0) || (b1 > 9)
2180                     || (b2 > 9))
2181                         goodboard = false;
2182         }
2183
2184         if (wlc_hw->sih->boardvendor != VENDOR_BROADCOM)
2185                 return goodboard;
2186
2187         return goodboard;
2188 }
2189
2190 static char *wlc_get_macaddr(struct wlc_hw_info *wlc_hw)
2191 {
2192         const char *varname = "macaddr";
2193         char *macaddr;
2194
2195         /* If macaddr exists, use it (Sromrev4, CIS, ...). */
2196         macaddr = getvar(wlc_hw->vars, varname);
2197         if (macaddr != NULL)
2198                 return macaddr;
2199
2200         if (NBANDS_HW(wlc_hw) > 1)
2201                 varname = "et1macaddr";
2202         else
2203                 varname = "il0macaddr";
2204
2205         macaddr = getvar(wlc_hw->vars, varname);
2206         if (macaddr == NULL) {
2207                 WL_ERROR("wl%d: wlc_get_macaddr: macaddr getvar(%s) not found\n",
2208                          wlc_hw->unit, varname);
2209         }
2210
2211         return macaddr;
2212 }
2213
2214 /*
2215  * Return true if radio is disabled, otherwise false.
2216  * hw radio disable signal is an external pin, users activate it asynchronously
2217  * this function could be called when driver is down and w/o clock
2218  * it operates on different registers depending on corerev and boardflag.
2219  */
2220 bool wlc_bmac_radio_read_hwdisabled(struct wlc_hw_info *wlc_hw)
2221 {
2222         bool v, clk, xtal;
2223         u32 resetbits = 0, flags = 0;
2224
2225         xtal = wlc_hw->sbclk;
2226         if (!xtal)
2227                 wlc_bmac_xtal(wlc_hw, ON);
2228
2229         /* may need to take core out of reset first */
2230         clk = wlc_hw->clk;
2231         if (!clk) {
2232                 if (D11REV_LE(wlc_hw->corerev, 11))
2233                         resetbits |= SICF_PCLKE;
2234
2235                 /*
2236                  * corerev >= 18, mac no longer enables phyclk automatically when driver accesses
2237                  * phyreg throughput mac. This can be skipped since only mac reg is accessed below
2238                  */
2239                 if (D11REV_GE(wlc_hw->corerev, 18))
2240                         flags |= SICF_PCLKE;
2241
2242                 /* AI chip doesn't restore bar0win2 on hibernation/resume, need sw fixup */
2243                 if ((wlc_hw->sih->chip == BCM43224_CHIP_ID) ||
2244                     (wlc_hw->sih->chip == BCM43225_CHIP_ID) ||
2245                     (wlc_hw->sih->chip == BCM43421_CHIP_ID))
2246                         wlc_hw->regs =
2247                             (d11regs_t *) si_setcore(wlc_hw->sih, D11_CORE_ID,
2248                                                      0);
2249                 si_core_reset(wlc_hw->sih, flags, resetbits);
2250                 wlc_mctrl_reset(wlc_hw);
2251         }
2252
2253         v = ((R_REG(wlc_hw->osh, &wlc_hw->regs->phydebug) & PDBG_RFD) != 0);
2254
2255         /* put core back into reset */
2256         if (!clk)
2257                 si_core_disable(wlc_hw->sih, 0);
2258
2259         if (!xtal)
2260                 wlc_bmac_xtal(wlc_hw, OFF);
2261
2262         return v;
2263 }
2264
2265 /* Initialize just the hardware when coming out of POR or S3/S5 system states */
2266 void wlc_bmac_hw_up(struct wlc_hw_info *wlc_hw)
2267 {
2268         if (wlc_hw->wlc->pub->hw_up)
2269                 return;
2270
2271         WL_TRACE("wl%d: %s:\n", wlc_hw->unit, __func__);
2272
2273         /*
2274          * Enable pll and xtal, initialize the power control registers,
2275          * and force fastclock for the remainder of wlc_up().
2276          */
2277         wlc_bmac_xtal(wlc_hw, ON);
2278         si_clkctl_init(wlc_hw->sih);
2279         wlc_clkctl_clk(wlc_hw, CLK_FAST);
2280
2281         if (wlc_hw->sih->bustype == PCI_BUS) {
2282                 si_pci_fixcfg(wlc_hw->sih);
2283
2284                 /* AI chip doesn't restore bar0win2 on hibernation/resume, need sw fixup */
2285                 if ((wlc_hw->sih->chip == BCM43224_CHIP_ID) ||
2286                     (wlc_hw->sih->chip == BCM43225_CHIP_ID) ||
2287                     (wlc_hw->sih->chip == BCM43421_CHIP_ID))
2288                         wlc_hw->regs =
2289                             (d11regs_t *) si_setcore(wlc_hw->sih, D11_CORE_ID,
2290                                                      0);
2291         }
2292
2293         /* Inform phy that a POR reset has occurred so it does a complete phy init */
2294         wlc_phy_por_inform(wlc_hw->band->pi);
2295
2296         wlc_hw->ucode_loaded = false;
2297         wlc_hw->wlc->pub->hw_up = true;
2298
2299         if ((wlc_hw->boardflags & BFL_FEM)
2300             && (wlc_hw->sih->chip == BCM4313_CHIP_ID)) {
2301                 if (!
2302                     (wlc_hw->boardrev >= 0x1250
2303                      && (wlc_hw->boardflags & BFL_FEM_BT)))
2304                         si_epa_4313war(wlc_hw->sih);
2305         }
2306 }
2307
2308 static bool wlc_dma_rxreset(struct wlc_hw_info *wlc_hw, uint fifo)
2309 {
2310         struct hnddma_pub *di = wlc_hw->di[fifo];
2311         struct osl_info *osh;
2312
2313         if (D11REV_LT(wlc_hw->corerev, 12)) {
2314                 bool rxidle = true;
2315                 u16 rcv_frm_cnt = 0;
2316
2317                 osh = wlc_hw->osh;
2318
2319                 W_REG(osh, &wlc_hw->regs->rcv_fifo_ctl, fifo << 8);
2320                 SPINWAIT((!(rxidle = dma_rxidle(di))) &&
2321                          ((rcv_frm_cnt =
2322                            R_REG(osh, &wlc_hw->regs->rcv_frm_cnt)) != 0),
2323                          50000);
2324
2325                 if (!rxidle && (rcv_frm_cnt != 0))
2326                         WL_ERROR("wl%d: %s: rxdma[%d] not idle && rcv_frm_cnt(%d) not zero\n",
2327                                  wlc_hw->unit, __func__, fifo, rcv_frm_cnt);
2328                 mdelay(2);
2329         }
2330
2331         return dma_rxreset(di);
2332 }
2333
2334 /* d11 core reset
2335  *   ensure fask clock during reset
2336  *   reset dma
2337  *   reset d11(out of reset)
2338  *   reset phy(out of reset)
2339  *   clear software macintstatus for fresh new start
2340  * one testing hack wlc_hw->noreset will bypass the d11/phy reset
2341  */
2342 void wlc_bmac_corereset(struct wlc_hw_info *wlc_hw, u32 flags)
2343 {
2344         d11regs_t *regs;
2345         uint i;
2346         bool fastclk;
2347         u32 resetbits = 0;
2348
2349         if (flags == WLC_USE_COREFLAGS)
2350                 flags = (wlc_hw->band->pi ? wlc_hw->band->core_flags : 0);
2351
2352         WL_TRACE("wl%d: %s\n", wlc_hw->unit, __func__);
2353
2354         regs = wlc_hw->regs;
2355
2356         /* request FAST clock if not on  */
2357         fastclk = wlc_hw->forcefastclk;
2358         if (!fastclk)
2359                 wlc_clkctl_clk(wlc_hw, CLK_FAST);
2360
2361         /* reset the dma engines except first time thru */
2362         if (si_iscoreup(wlc_hw->sih)) {
2363                 for (i = 0; i < NFIFO; i++)
2364                         if ((wlc_hw->di[i]) && (!dma_txreset(wlc_hw->di[i]))) {
2365                                 WL_ERROR("wl%d: %s: dma_txreset[%d]: cannot stop dma\n",
2366                                          wlc_hw->unit, __func__, i);
2367                         }
2368
2369                 if ((wlc_hw->di[RX_FIFO])
2370                     && (!wlc_dma_rxreset(wlc_hw, RX_FIFO))) {
2371                         WL_ERROR("wl%d: %s: dma_rxreset[%d]: cannot stop dma\n",
2372                                  wlc_hw->unit, __func__, RX_FIFO);
2373                 }
2374                 if (D11REV_IS(wlc_hw->corerev, 4)
2375                     && wlc_hw->di[RX_TXSTATUS_FIFO]
2376                     && (!wlc_dma_rxreset(wlc_hw, RX_TXSTATUS_FIFO))) {
2377                         WL_ERROR("wl%d: %s: dma_rxreset[%d]: cannot stop dma\n",
2378                                  wlc_hw->unit, __func__, RX_TXSTATUS_FIFO);
2379                 }
2380         }
2381         /* if noreset, just stop the psm and return */
2382         if (wlc_hw->noreset) {
2383                 wlc_hw->wlc->macintstatus = 0;  /* skip wl_dpc after down */
2384                 wlc_bmac_mctrl(wlc_hw, MCTL_PSM_RUN | MCTL_EN_MAC, 0);
2385                 return;
2386         }
2387
2388         if (D11REV_LE(wlc_hw->corerev, 11))
2389                 resetbits |= SICF_PCLKE;
2390
2391         /*
2392          * corerev >= 18, mac no longer enables phyclk automatically when driver accesses phyreg
2393          * throughput mac, AND phy_reset is skipped at early stage when band->pi is invalid
2394          * need to enable PHY CLK
2395          */
2396         if (D11REV_GE(wlc_hw->corerev, 18))
2397                 flags |= SICF_PCLKE;
2398
2399         /* reset the core
2400          * In chips with PMU, the fastclk request goes through d11 core reg 0x1e0, which
2401          *  is cleared by the core_reset. have to re-request it.
2402          *  This adds some delay and we can optimize it by also requesting fastclk through
2403          *  chipcommon during this period if necessary. But that has to work coordinate
2404          *  with other driver like mips/arm since they may touch chipcommon as well.
2405          */
2406         wlc_hw->clk = false;
2407         si_core_reset(wlc_hw->sih, flags, resetbits);
2408         wlc_hw->clk = true;
2409         if (wlc_hw->band && wlc_hw->band->pi)
2410                 wlc_phy_hw_clk_state_upd(wlc_hw->band->pi, true);
2411
2412         wlc_mctrl_reset(wlc_hw);
2413
2414         if (PMUCTL_ENAB(wlc_hw->sih))
2415                 wlc_clkctl_clk(wlc_hw, CLK_FAST);
2416
2417         wlc_bmac_phy_reset(wlc_hw);
2418
2419         /* turn on PHY_PLL */
2420         wlc_bmac_core_phypll_ctl(wlc_hw, true);
2421
2422         /* clear sw intstatus */
2423         wlc_hw->wlc->macintstatus = 0;
2424
2425         /* restore the clk setting */
2426         if (!fastclk)
2427                 wlc_clkctl_clk(wlc_hw, CLK_DYNAMIC);
2428 }
2429
2430 /* If the ucode that supports corerev 5 is used for corerev 9 and above,
2431  * txfifo sizes needs to be modified(increased) since the newer cores
2432  * have more memory.
2433  */
2434 static void wlc_corerev_fifofixup(struct wlc_hw_info *wlc_hw)
2435 {
2436         d11regs_t *regs = wlc_hw->regs;
2437         u16 fifo_nu;
2438         u16 txfifo_startblk = TXFIFO_START_BLK, txfifo_endblk;
2439         u16 txfifo_def, txfifo_def1;
2440         u16 txfifo_cmd;
2441         struct osl_info *osh;
2442
2443         if (D11REV_LT(wlc_hw->corerev, 9))
2444                 goto exit;
2445
2446         /* tx fifos start at TXFIFO_START_BLK from the Base address */
2447         txfifo_startblk = TXFIFO_START_BLK;
2448
2449         osh = wlc_hw->osh;
2450
2451         /* sequence of operations:  reset fifo, set fifo size, reset fifo */
2452         for (fifo_nu = 0; fifo_nu < NFIFO; fifo_nu++) {
2453
2454                 txfifo_endblk = txfifo_startblk + wlc_hw->xmtfifo_sz[fifo_nu];
2455                 txfifo_def = (txfifo_startblk & 0xff) |
2456                     (((txfifo_endblk - 1) & 0xff) << TXFIFO_FIFOTOP_SHIFT);
2457                 txfifo_def1 = ((txfifo_startblk >> 8) & 0x1) |
2458                     ((((txfifo_endblk -
2459                         1) >> 8) & 0x1) << TXFIFO_FIFOTOP_SHIFT);
2460                 txfifo_cmd =
2461                     TXFIFOCMD_RESET_MASK | (fifo_nu << TXFIFOCMD_FIFOSEL_SHIFT);
2462
2463                 W_REG(osh, &regs->xmtfifocmd, txfifo_cmd);
2464                 W_REG(osh, &regs->xmtfifodef, txfifo_def);
2465                 if (D11REV_GE(wlc_hw->corerev, 16))
2466                         W_REG(osh, &regs->xmtfifodef1, txfifo_def1);
2467
2468                 W_REG(osh, &regs->xmtfifocmd, txfifo_cmd);
2469
2470                 txfifo_startblk += wlc_hw->xmtfifo_sz[fifo_nu];
2471         }
2472  exit:
2473         /* need to propagate to shm location to be in sync since ucode/hw won't do this */
2474         wlc_bmac_write_shm(wlc_hw, M_FIFOSIZE0,
2475                            wlc_hw->xmtfifo_sz[TX_AC_BE_FIFO]);
2476         wlc_bmac_write_shm(wlc_hw, M_FIFOSIZE1,
2477                            wlc_hw->xmtfifo_sz[TX_AC_VI_FIFO]);
2478         wlc_bmac_write_shm(wlc_hw, M_FIFOSIZE2,
2479                            ((wlc_hw->xmtfifo_sz[TX_AC_VO_FIFO] << 8) | wlc_hw->
2480                             xmtfifo_sz[TX_AC_BK_FIFO]));
2481         wlc_bmac_write_shm(wlc_hw, M_FIFOSIZE3,
2482                            ((wlc_hw->xmtfifo_sz[TX_ATIM_FIFO] << 8) | wlc_hw->
2483                             xmtfifo_sz[TX_BCMC_FIFO]));
2484 }
2485
2486 /* d11 core init
2487  *   reset PSM
2488  *   download ucode/PCM
2489  *   let ucode run to suspended
2490  *   download ucode inits
2491  *   config other core registers
2492  *   init dma
2493  */
2494 static void wlc_coreinit(struct wlc_info *wlc)
2495 {
2496         struct wlc_hw_info *wlc_hw = wlc->hw;
2497         d11regs_t *regs;
2498         u32 sflags;
2499         uint bcnint_us;
2500         uint i = 0;
2501         bool fifosz_fixup = false;
2502         struct osl_info *osh;
2503         int err = 0;
2504         u16 buf[NFIFO];
2505
2506         regs = wlc_hw->regs;
2507         osh = wlc_hw->osh;
2508
2509         WL_TRACE("wl%d: wlc_coreinit\n", wlc_hw->unit);
2510
2511         /* reset PSM */
2512         wlc_bmac_mctrl(wlc_hw, ~0, (MCTL_IHR_EN | MCTL_PSM_JMP_0 | MCTL_WAKE));
2513
2514         wlc_ucode_download(wlc_hw);
2515         /*
2516          * FIFOSZ fixup
2517          * 1) core5-9 use ucode 5 to save space since the PSM is the same
2518          * 2) newer chips, driver wants to controls the fifo allocation
2519          */
2520         if (D11REV_GE(wlc_hw->corerev, 4))
2521                 fifosz_fixup = true;
2522
2523         /* let the PSM run to the suspended state, set mode to BSS STA */
2524         W_REG(osh, &regs->macintstatus, -1);
2525         wlc_bmac_mctrl(wlc_hw, ~0,
2526                        (MCTL_IHR_EN | MCTL_INFRA | MCTL_PSM_RUN | MCTL_WAKE));
2527
2528         /* wait for ucode to self-suspend after auto-init */
2529         SPINWAIT(((R_REG(osh, &regs->macintstatus) & MI_MACSSPNDD) == 0),
2530                  1000 * 1000);
2531         if ((R_REG(osh, &regs->macintstatus) & MI_MACSSPNDD) == 0)
2532                 WL_ERROR("wl%d: wlc_coreinit: ucode did not self-suspend!\n",
2533                          wlc_hw->unit);
2534
2535         wlc_gpio_init(wlc);
2536
2537         sflags = si_core_sflags(wlc_hw->sih, 0, 0);
2538
2539         if (D11REV_IS(wlc_hw->corerev, 23)) {
2540                 if (WLCISNPHY(wlc_hw->band))
2541                         wlc_write_inits(wlc_hw, d11n0initvals16);
2542                 else
2543                         WL_ERROR("%s: wl%d: unsupported phy in corerev %d\n",
2544                                  __func__, wlc_hw->unit, wlc_hw->corerev);
2545         } else if (D11REV_IS(wlc_hw->corerev, 24)) {
2546                 if (WLCISLCNPHY(wlc_hw->band)) {
2547                         wlc_write_inits(wlc_hw, d11lcn0initvals24);
2548                 } else {
2549                         WL_ERROR("%s: wl%d: unsupported phy in corerev %d\n",
2550                                  __func__, wlc_hw->unit, wlc_hw->corerev);
2551                 }
2552         } else {
2553                 WL_ERROR("%s: wl%d: unsupported corerev %d\n",
2554                          __func__, wlc_hw->unit, wlc_hw->corerev);
2555         }
2556
2557         /* For old ucode, txfifo sizes needs to be modified(increased) for Corerev >= 9 */
2558         if (fifosz_fixup == true) {
2559                 wlc_corerev_fifofixup(wlc_hw);
2560         }
2561
2562         /* check txfifo allocations match between ucode and driver */
2563         buf[TX_AC_BE_FIFO] = wlc_bmac_read_shm(wlc_hw, M_FIFOSIZE0);
2564         if (buf[TX_AC_BE_FIFO] != wlc_hw->xmtfifo_sz[TX_AC_BE_FIFO]) {
2565                 i = TX_AC_BE_FIFO;
2566                 err = -1;
2567         }
2568         buf[TX_AC_VI_FIFO] = wlc_bmac_read_shm(wlc_hw, M_FIFOSIZE1);
2569         if (buf[TX_AC_VI_FIFO] != wlc_hw->xmtfifo_sz[TX_AC_VI_FIFO]) {
2570                 i = TX_AC_VI_FIFO;
2571                 err = -1;
2572         }
2573         buf[TX_AC_BK_FIFO] = wlc_bmac_read_shm(wlc_hw, M_FIFOSIZE2);
2574         buf[TX_AC_VO_FIFO] = (buf[TX_AC_BK_FIFO] >> 8) & 0xff;
2575         buf[TX_AC_BK_FIFO] &= 0xff;
2576         if (buf[TX_AC_BK_FIFO] != wlc_hw->xmtfifo_sz[TX_AC_BK_FIFO]) {
2577                 i = TX_AC_BK_FIFO;
2578                 err = -1;
2579         }
2580         if (buf[TX_AC_VO_FIFO] != wlc_hw->xmtfifo_sz[TX_AC_VO_FIFO]) {
2581                 i = TX_AC_VO_FIFO;
2582                 err = -1;
2583         }
2584         buf[TX_BCMC_FIFO] = wlc_bmac_read_shm(wlc_hw, M_FIFOSIZE3);
2585         buf[TX_ATIM_FIFO] = (buf[TX_BCMC_FIFO] >> 8) & 0xff;
2586         buf[TX_BCMC_FIFO] &= 0xff;
2587         if (buf[TX_BCMC_FIFO] != wlc_hw->xmtfifo_sz[TX_BCMC_FIFO]) {
2588                 i = TX_BCMC_FIFO;
2589                 err = -1;
2590         }
2591         if (buf[TX_ATIM_FIFO] != wlc_hw->xmtfifo_sz[TX_ATIM_FIFO]) {
2592                 i = TX_ATIM_FIFO;
2593                 err = -1;
2594         }
2595         if (err != 0) {
2596                 WL_ERROR("wlc_coreinit: txfifo mismatch: ucode size %d driver size %d index %d\n",
2597                          buf[i], wlc_hw->xmtfifo_sz[i], i);
2598                 /* DO NOT ASSERT corerev < 4 even there is a mismatch
2599                  * shmem, since driver don't overwrite those chip and
2600                  * ucode initialize data will be used.
2601                  */
2602                 if (D11REV_GE(wlc_hw->corerev, 4))
2603                         ASSERT(0);
2604         }
2605
2606         /* make sure we can still talk to the mac */
2607         ASSERT(R_REG(osh, &regs->maccontrol) != 0xffffffff);
2608
2609         /* band-specific inits done by wlc_bsinit() */
2610
2611         /* Set up frame burst size and antenna swap threshold init values */
2612         wlc_bmac_write_shm(wlc_hw, M_MBURST_SIZE, MAXTXFRAMEBURST);
2613         wlc_bmac_write_shm(wlc_hw, M_MAX_ANTCNT, ANTCNT);
2614
2615         /* enable one rx interrupt per received frame */
2616         W_REG(osh, &regs->intrcvlazy[0], (1 << IRL_FC_SHIFT));
2617         if (D11REV_IS(wlc_hw->corerev, 4))
2618                 W_REG(osh, &regs->intrcvlazy[3], (1 << IRL_FC_SHIFT));
2619
2620         /* set the station mode (BSS STA) */
2621         wlc_bmac_mctrl(wlc_hw,
2622                        (MCTL_INFRA | MCTL_DISCARD_PMQ | MCTL_AP),
2623                        (MCTL_INFRA | MCTL_DISCARD_PMQ));
2624
2625         /* set up Beacon interval */
2626         bcnint_us = 0x8000 << 10;
2627         W_REG(osh, &regs->tsf_cfprep, (bcnint_us << CFPREP_CBI_SHIFT));
2628         W_REG(osh, &regs->tsf_cfpstart, bcnint_us);
2629         W_REG(osh, &regs->macintstatus, MI_GP1);
2630
2631         /* write interrupt mask */
2632         W_REG(osh, &regs->intctrlregs[RX_FIFO].intmask, DEF_RXINTMASK);
2633         if (D11REV_IS(wlc_hw->corerev, 4))
2634                 W_REG(osh, &regs->intctrlregs[RX_TXSTATUS_FIFO].intmask,
2635                       DEF_RXINTMASK);
2636
2637         /* allow the MAC to control the PHY clock (dynamic on/off) */
2638         wlc_bmac_macphyclk_set(wlc_hw, ON);
2639
2640         /* program dynamic clock control fast powerup delay register */
2641         if (D11REV_GT(wlc_hw->corerev, 4)) {
2642                 wlc->fastpwrup_dly = si_clkctl_fast_pwrup_delay(wlc_hw->sih);
2643                 W_REG(osh, &regs->scc_fastpwrup_dly, wlc->fastpwrup_dly);
2644         }
2645
2646         /* tell the ucode the corerev */
2647         wlc_bmac_write_shm(wlc_hw, M_MACHW_VER, (u16) wlc_hw->corerev);
2648
2649         /* tell the ucode MAC capabilities */
2650         if (D11REV_GE(wlc_hw->corerev, 13)) {
2651                 wlc_bmac_write_shm(wlc_hw, M_MACHW_CAP_L,
2652                                    (u16) (wlc_hw->machwcap & 0xffff));
2653                 wlc_bmac_write_shm(wlc_hw, M_MACHW_CAP_H,
2654                                    (u16) ((wlc_hw->
2655                                               machwcap >> 16) & 0xffff));
2656         }
2657
2658         /* write retry limits to SCR, this done after PSM init */
2659         W_REG(osh, &regs->objaddr, OBJADDR_SCR_SEL | S_DOT11_SRC_LMT);
2660         (void)R_REG(osh, &regs->objaddr);
2661         W_REG(osh, &regs->objdata, wlc_hw->SRL);
2662         W_REG(osh, &regs->objaddr, OBJADDR_SCR_SEL | S_DOT11_LRC_LMT);
2663         (void)R_REG(osh, &regs->objaddr);
2664         W_REG(osh, &regs->objdata, wlc_hw->LRL);
2665
2666         /* write rate fallback retry limits */
2667         wlc_bmac_write_shm(wlc_hw, M_SFRMTXCNTFBRTHSD, wlc_hw->SFBL);
2668         wlc_bmac_write_shm(wlc_hw, M_LFRMTXCNTFBRTHSD, wlc_hw->LFBL);
2669
2670         if (D11REV_GE(wlc_hw->corerev, 16)) {
2671                 AND_REG(osh, &regs->ifs_ctl, 0x0FFF);
2672                 W_REG(osh, &regs->ifs_aifsn, EDCF_AIFSN_MIN);
2673         }
2674
2675         /* dma initializations */
2676         wlc->txpend16165war = 0;
2677
2678         /* init the tx dma engines */
2679         for (i = 0; i < NFIFO; i++) {
2680                 if (wlc_hw->di[i])
2681                         dma_txinit(wlc_hw->di[i]);
2682         }
2683
2684         /* init the rx dma engine(s) and post receive buffers */
2685         dma_rxinit(wlc_hw->di[RX_FIFO]);
2686         dma_rxfill(wlc_hw->di[RX_FIFO]);
2687         if (D11REV_IS(wlc_hw->corerev, 4)) {
2688                 dma_rxinit(wlc_hw->di[RX_TXSTATUS_FIFO]);
2689                 dma_rxfill(wlc_hw->di[RX_TXSTATUS_FIFO]);
2690         }
2691 }
2692
2693 /* This function is used for changing the tsf frac register
2694  * If spur avoidance mode is off, the mac freq will be 80/120/160Mhz
2695  * If spur avoidance mode is on1, the mac freq will be 82/123/164Mhz
2696  * If spur avoidance mode is on2, the mac freq will be 84/126/168Mhz
2697  * HTPHY Formula is 2^26/freq(MHz) e.g.
2698  * For spuron2 - 126MHz -> 2^26/126 = 532610.0
2699  *  - 532610 = 0x82082 => tsf_clk_frac_h = 0x8, tsf_clk_frac_l = 0x2082
2700  * For spuron: 123MHz -> 2^26/123    = 545600.5
2701  *  - 545601 = 0x85341 => tsf_clk_frac_h = 0x8, tsf_clk_frac_l = 0x5341
2702  * For spur off: 120MHz -> 2^26/120    = 559240.5
2703  *  - 559241 = 0x88889 => tsf_clk_frac_h = 0x8, tsf_clk_frac_l = 0x8889
2704  */
2705
2706 void wlc_bmac_switch_macfreq(struct wlc_hw_info *wlc_hw, u8 spurmode)
2707 {
2708         d11regs_t *regs;
2709         struct osl_info *osh;
2710         regs = wlc_hw->regs;
2711         osh = wlc_hw->osh;
2712
2713         if ((wlc_hw->sih->chip == BCM43224_CHIP_ID) ||
2714             (wlc_hw->sih->chip == BCM43225_CHIP_ID)) {
2715                 if (spurmode == WL_SPURAVOID_ON2) {     /* 126Mhz */
2716                         W_REG(osh, &regs->tsf_clk_frac_l, 0x2082);
2717                         W_REG(osh, &regs->tsf_clk_frac_h, 0x8);
2718                 } else if (spurmode == WL_SPURAVOID_ON1) {      /* 123Mhz */
2719                         W_REG(osh, &regs->tsf_clk_frac_l, 0x5341);
2720                         W_REG(osh, &regs->tsf_clk_frac_h, 0x8);
2721                 } else {        /* 120Mhz */
2722                         W_REG(osh, &regs->tsf_clk_frac_l, 0x8889);
2723                         W_REG(osh, &regs->tsf_clk_frac_h, 0x8);
2724                 }
2725         } else if (WLCISLCNPHY(wlc_hw->band)) {
2726                 if (spurmode == WL_SPURAVOID_ON1) {     /* 82Mhz */
2727                         W_REG(osh, &regs->tsf_clk_frac_l, 0x7CE0);
2728                         W_REG(osh, &regs->tsf_clk_frac_h, 0xC);
2729                 } else {        /* 80Mhz */
2730                         W_REG(osh, &regs->tsf_clk_frac_l, 0xCCCD);
2731                         W_REG(osh, &regs->tsf_clk_frac_h, 0xC);
2732                 }
2733         }
2734 }
2735
2736 /* Initialize GPIOs that are controlled by D11 core */
2737 static void wlc_gpio_init(struct wlc_info *wlc)
2738 {
2739         struct wlc_hw_info *wlc_hw = wlc->hw;
2740         d11regs_t *regs;
2741         u32 gc, gm;
2742         struct osl_info *osh;
2743
2744         regs = wlc_hw->regs;
2745         osh = wlc_hw->osh;
2746
2747         /* use GPIO select 0 to get all gpio signals from the gpio out reg */
2748         wlc_bmac_mctrl(wlc_hw, MCTL_GPOUT_SEL_MASK, 0);
2749
2750         /*
2751          * Common GPIO setup:
2752          *      G0 = LED 0 = WLAN Activity
2753          *      G1 = LED 1 = WLAN 2.4 GHz Radio State
2754          *      G2 = LED 2 = WLAN 5 GHz Radio State
2755          *      G4 = radio disable input (HI enabled, LO disabled)
2756          */
2757
2758         gc = gm = 0;
2759
2760         /* Allocate GPIOs for mimo antenna diversity feature */
2761         if (WLANTSEL_ENAB(wlc)) {
2762                 if (wlc_hw->antsel_type == ANTSEL_2x3) {
2763                         /* Enable antenna diversity, use 2x3 mode */
2764                         wlc_bmac_mhf(wlc_hw, MHF3, MHF3_ANTSEL_EN,
2765                                      MHF3_ANTSEL_EN, WLC_BAND_ALL);
2766                         wlc_bmac_mhf(wlc_hw, MHF3, MHF3_ANTSEL_MODE,
2767                                      MHF3_ANTSEL_MODE, WLC_BAND_ALL);
2768
2769                         /* init superswitch control */
2770                         wlc_phy_antsel_init(wlc_hw->band->pi, false);
2771
2772                 } else if (wlc_hw->antsel_type == ANTSEL_2x4) {
2773                         ASSERT((gm & BOARD_GPIO_12) == 0);
2774                         gm |= gc |= (BOARD_GPIO_12 | BOARD_GPIO_13);
2775                         /* The board itself is powered by these GPIOs (when not sending pattern)
2776                          * So set them high
2777                          */
2778                         OR_REG(osh, &regs->psm_gpio_oe,
2779                                (BOARD_GPIO_12 | BOARD_GPIO_13));
2780                         OR_REG(osh, &regs->psm_gpio_out,
2781                                (BOARD_GPIO_12 | BOARD_GPIO_13));
2782
2783                         /* Enable antenna diversity, use 2x4 mode */
2784                         wlc_bmac_mhf(wlc_hw, MHF3, MHF3_ANTSEL_EN,
2785                                      MHF3_ANTSEL_EN, WLC_BAND_ALL);
2786                         wlc_bmac_mhf(wlc_hw, MHF3, MHF3_ANTSEL_MODE, 0,
2787                                      WLC_BAND_ALL);
2788
2789                         /* Configure the desired clock to be 4Mhz */
2790                         wlc_bmac_write_shm(wlc_hw, M_ANTSEL_CLKDIV,
2791                                            ANTSEL_CLKDIV_4MHZ);
2792                 }
2793         }
2794         /* gpio 9 controls the PA.  ucode is responsible for wiggling out and oe */
2795         if (wlc_hw->boardflags & BFL_PACTRL)
2796                 gm |= gc |= BOARD_GPIO_PACTRL;
2797
2798         /* apply to gpiocontrol register */
2799         si_gpiocontrol(wlc_hw->sih, gm, gc, GPIO_DRV_PRIORITY);
2800 }
2801
2802 static void wlc_ucode_download(struct wlc_hw_info *wlc_hw)
2803 {
2804         struct wlc_info *wlc;
2805         wlc = wlc_hw->wlc;
2806
2807         if (wlc_hw->ucode_loaded)
2808                 return;
2809
2810         if (D11REV_IS(wlc_hw->corerev, 23)) {
2811                 if (WLCISNPHY(wlc_hw->band)) {
2812                         wlc_ucode_write(wlc_hw, bcm43xx_16_mimo,
2813                                         bcm43xx_16_mimosz);
2814                         wlc_hw->ucode_loaded = true;
2815                 } else
2816                         WL_ERROR("%s: wl%d: unsupported phy in corerev %d\n",
2817                                  __func__, wlc_hw->unit, wlc_hw->corerev);
2818         } else if (D11REV_IS(wlc_hw->corerev, 24)) {
2819                 if (WLCISLCNPHY(wlc_hw->band)) {
2820                         wlc_ucode_write(wlc_hw, bcm43xx_24_lcn,
2821                                         bcm43xx_24_lcnsz);
2822                         wlc_hw->ucode_loaded = true;
2823                 } else {
2824                         WL_ERROR("%s: wl%d: unsupported phy in corerev %d\n",
2825                                  __func__, wlc_hw->unit, wlc_hw->corerev);
2826                 }
2827         }
2828 }
2829
2830 static void wlc_ucode_write(struct wlc_hw_info *wlc_hw, const u32 ucode[],
2831                               const uint nbytes) {
2832         struct osl_info *osh;
2833         d11regs_t *regs = wlc_hw->regs;
2834         uint i;
2835         uint count;
2836
2837         osh = wlc_hw->osh;
2838
2839         WL_TRACE("wl%d: wlc_ucode_write\n", wlc_hw->unit);
2840
2841         ASSERT(IS_ALIGNED(nbytes, sizeof(u32)));
2842
2843         count = (nbytes / sizeof(u32));
2844
2845         W_REG(osh, &regs->objaddr, (OBJADDR_AUTO_INC | OBJADDR_UCM_SEL));
2846         (void)R_REG(osh, &regs->objaddr);
2847         for (i = 0; i < count; i++)
2848                 W_REG(osh, &regs->objdata, ucode[i]);
2849 }
2850
2851 static void wlc_write_inits(struct wlc_hw_info *wlc_hw, const d11init_t *inits)
2852 {
2853         int i;
2854         struct osl_info *osh;
2855         volatile u8 *base;
2856
2857         WL_TRACE("wl%d: wlc_write_inits\n", wlc_hw->unit);
2858
2859         osh = wlc_hw->osh;
2860         base = (volatile u8 *)wlc_hw->regs;
2861
2862         for (i = 0; inits[i].addr != 0xffff; i++) {
2863                 ASSERT((inits[i].size == 2) || (inits[i].size == 4));
2864
2865                 if (inits[i].size == 2)
2866                         W_REG(osh, (u16 *)(base + inits[i].addr),
2867                               inits[i].value);
2868                 else if (inits[i].size == 4)
2869                         W_REG(osh, (u32 *)(base + inits[i].addr),
2870                               inits[i].value);
2871         }
2872 }
2873
2874 static void wlc_ucode_txant_set(struct wlc_hw_info *wlc_hw)
2875 {
2876         u16 phyctl;
2877         u16 phytxant = wlc_hw->bmac_phytxant;
2878         u16 mask = PHY_TXC_ANT_MASK;
2879
2880         /* set the Probe Response frame phy control word */
2881         phyctl = wlc_bmac_read_shm(wlc_hw, M_CTXPRS_BLK + C_CTX_PCTLWD_POS);
2882         phyctl = (phyctl & ~mask) | phytxant;
2883         wlc_bmac_write_shm(wlc_hw, M_CTXPRS_BLK + C_CTX_PCTLWD_POS, phyctl);
2884
2885         /* set the Response (ACK/CTS) frame phy control word */
2886         phyctl = wlc_bmac_read_shm(wlc_hw, M_RSP_PCTLWD);
2887         phyctl = (phyctl & ~mask) | phytxant;
2888         wlc_bmac_write_shm(wlc_hw, M_RSP_PCTLWD, phyctl);
2889 }
2890
2891 void wlc_bmac_txant_set(struct wlc_hw_info *wlc_hw, u16 phytxant)
2892 {
2893         /* update sw state */
2894         wlc_hw->bmac_phytxant = phytxant;
2895
2896         /* push to ucode if up */
2897         if (!wlc_hw->up)
2898                 return;
2899         wlc_ucode_txant_set(wlc_hw);
2900
2901 }
2902
2903 u16 wlc_bmac_get_txant(struct wlc_hw_info *wlc_hw)
2904 {
2905         return (u16) wlc_hw->wlc->stf->txant;
2906 }
2907
2908 void wlc_bmac_antsel_type_set(struct wlc_hw_info *wlc_hw, u8 antsel_type)
2909 {
2910         wlc_hw->antsel_type = antsel_type;
2911
2912         /* Update the antsel type for phy module to use */
2913         wlc_phy_antsel_type_set(wlc_hw->band->pi, antsel_type);
2914 }
2915
2916 void wlc_bmac_fifoerrors(struct wlc_hw_info *wlc_hw)
2917 {
2918         bool fatal = false;
2919         uint unit;
2920         uint intstatus, idx;
2921         d11regs_t *regs = wlc_hw->regs;
2922
2923         unit = wlc_hw->unit;
2924
2925         for (idx = 0; idx < NFIFO; idx++) {
2926                 /* read intstatus register and ignore any non-error bits */
2927                 intstatus =
2928                     R_REG(wlc_hw->osh,
2929                           &regs->intctrlregs[idx].intstatus) & I_ERRORS;
2930                 if (!intstatus)
2931                         continue;
2932
2933                 WL_TRACE("wl%d: wlc_bmac_fifoerrors: intstatus%d 0x%x\n",
2934                          unit, idx, intstatus);
2935
2936                 if (intstatus & I_RO) {
2937                         WL_ERROR("wl%d: fifo %d: receive fifo overflow\n",
2938                                  unit, idx);
2939                         WLCNTINCR(wlc_hw->wlc->pub->_cnt->rxoflo);
2940                         fatal = true;
2941                 }
2942
2943                 if (intstatus & I_PC) {
2944                         WL_ERROR("wl%d: fifo %d: descriptor error\n",
2945                                  unit, idx);
2946                         WLCNTINCR(wlc_hw->wlc->pub->_cnt->dmade);
2947                         fatal = true;
2948                 }
2949
2950                 if (intstatus & I_PD) {
2951                         WL_ERROR("wl%d: fifo %d: data error\n", unit, idx);
2952                         WLCNTINCR(wlc_hw->wlc->pub->_cnt->dmada);
2953                         fatal = true;
2954                 }
2955
2956                 if (intstatus & I_DE) {
2957                         WL_ERROR("wl%d: fifo %d: descriptor protocol error\n",
2958                                  unit, idx);
2959                         WLCNTINCR(wlc_hw->wlc->pub->_cnt->dmape);
2960                         fatal = true;
2961                 }
2962
2963                 if (intstatus & I_RU) {
2964                         WL_ERROR("wl%d: fifo %d: receive descriptor underflow\n",
2965                                  idx, unit);
2966                         WLCNTINCR(wlc_hw->wlc->pub->_cnt->rxuflo[idx]);
2967                 }
2968
2969                 if (intstatus & I_XU) {
2970                         WL_ERROR("wl%d: fifo %d: transmit fifo underflow\n",
2971                                  idx, unit);
2972                         WLCNTINCR(wlc_hw->wlc->pub->_cnt->txuflo);
2973                         fatal = true;
2974                 }
2975
2976                 if (fatal) {
2977                         wlc_fatal_error(wlc_hw->wlc);   /* big hammer */
2978                         break;
2979                 } else
2980                         W_REG(wlc_hw->osh, &regs->intctrlregs[idx].intstatus,
2981                               intstatus);
2982         }
2983 }
2984
2985 void wlc_intrson(struct wlc_info *wlc)
2986 {
2987         struct wlc_hw_info *wlc_hw = wlc->hw;
2988         ASSERT(wlc->defmacintmask);
2989         wlc->macintmask = wlc->defmacintmask;
2990         W_REG(wlc_hw->osh, &wlc_hw->regs->macintmask, wlc->macintmask);
2991 }
2992
2993 /* callback for siutils.c, which has only wlc handler, no wl
2994  * they both check up, not only because there is no need to off/restore d11 interrupt
2995  *  but also because per-port code may require sync with valid interrupt.
2996  */
2997
2998 static u32 wlc_wlintrsoff(struct wlc_info *wlc)
2999 {
3000         if (!wlc->hw->up)
3001                 return 0;
3002
3003         return wl_intrsoff(wlc->wl);
3004 }
3005
3006 static void wlc_wlintrsrestore(struct wlc_info *wlc, u32 macintmask)
3007 {
3008         if (!wlc->hw->up)
3009                 return;
3010
3011         wl_intrsrestore(wlc->wl, macintmask);
3012 }
3013
3014 u32 wlc_intrsoff(struct wlc_info *wlc)
3015 {
3016         struct wlc_hw_info *wlc_hw = wlc->hw;
3017         u32 macintmask;
3018
3019         if (!wlc_hw->clk)
3020                 return 0;
3021
3022         macintmask = wlc->macintmask;   /* isr can still happen */
3023
3024         W_REG(wlc_hw->osh, &wlc_hw->regs->macintmask, 0);
3025         (void)R_REG(wlc_hw->osh, &wlc_hw->regs->macintmask);    /* sync readback */
3026         udelay(1);              /* ensure int line is no longer driven */
3027         wlc->macintmask = 0;
3028
3029         /* return previous macintmask; resolve race between us and our isr */
3030         return wlc->macintstatus ? 0 : macintmask;
3031 }
3032
3033 void wlc_intrsrestore(struct wlc_info *wlc, u32 macintmask)
3034 {
3035         struct wlc_hw_info *wlc_hw = wlc->hw;
3036         if (!wlc_hw->clk)
3037                 return;
3038
3039         wlc->macintmask = macintmask;
3040         W_REG(wlc_hw->osh, &wlc_hw->regs->macintmask, wlc->macintmask);
3041 }
3042
3043 void wlc_bmac_mute(struct wlc_hw_info *wlc_hw, bool on, mbool flags)
3044 {
3045         struct ether_addr null_ether_addr = { {0, 0, 0, 0, 0, 0} };
3046
3047         if (on) {
3048                 /* suspend tx fifos */
3049                 wlc_bmac_tx_fifo_suspend(wlc_hw, TX_DATA_FIFO);
3050                 wlc_bmac_tx_fifo_suspend(wlc_hw, TX_CTL_FIFO);
3051                 wlc_bmac_tx_fifo_suspend(wlc_hw, TX_AC_BK_FIFO);
3052                 wlc_bmac_tx_fifo_suspend(wlc_hw, TX_AC_VI_FIFO);
3053
3054                 /* zero the address match register so we do not send ACKs */
3055                 wlc_bmac_set_addrmatch(wlc_hw, RCM_MAC_OFFSET,
3056                                        &null_ether_addr);
3057         } else {
3058                 /* resume tx fifos */
3059                 if (!wlc_hw->wlc->tx_suspended) {
3060                         wlc_bmac_tx_fifo_resume(wlc_hw, TX_DATA_FIFO);
3061                 }
3062                 wlc_bmac_tx_fifo_resume(wlc_hw, TX_CTL_FIFO);
3063                 wlc_bmac_tx_fifo_resume(wlc_hw, TX_AC_BK_FIFO);
3064                 wlc_bmac_tx_fifo_resume(wlc_hw, TX_AC_VI_FIFO);
3065
3066                 /* Restore address */
3067                 wlc_bmac_set_addrmatch(wlc_hw, RCM_MAC_OFFSET,
3068                                        &wlc_hw->etheraddr);
3069         }
3070
3071         wlc_phy_mute_upd(wlc_hw->band->pi, on, flags);
3072
3073         if (on)
3074                 wlc_ucode_mute_override_set(wlc_hw);
3075         else
3076                 wlc_ucode_mute_override_clear(wlc_hw);
3077 }
3078
3079 void wlc_bmac_set_deaf(struct wlc_hw_info *wlc_hw, bool user_flag)
3080 {
3081         wlc_phy_set_deaf(wlc_hw->band->pi, user_flag);
3082 }
3083
3084 int wlc_bmac_xmtfifo_sz_get(struct wlc_hw_info *wlc_hw, uint fifo, uint *blocks)
3085 {
3086         if (fifo >= NFIFO)
3087                 return BCME_RANGE;
3088
3089         *blocks = wlc_hw->xmtfifo_sz[fifo];
3090
3091         return 0;
3092 }
3093
3094 int wlc_bmac_xmtfifo_sz_set(struct wlc_hw_info *wlc_hw, uint fifo, uint blocks)
3095 {
3096         if (fifo >= NFIFO || blocks > 299)
3097                 return BCME_RANGE;
3098
3099         /* BMAC_NOTE, change blocks to u16 */
3100         wlc_hw->xmtfifo_sz[fifo] = (u16) blocks;
3101
3102         return 0;
3103 }
3104
3105 /* wlc_bmac_tx_fifo_suspended:
3106  * Check the MAC's tx suspend status for a tx fifo.
3107  *
3108  * When the MAC acknowledges a tx suspend, it indicates that no more
3109  * packets will be transmitted out the radio. This is independent of
3110  * DMA channel suspension---the DMA may have finished suspending, or may still
3111  * be pulling data into a tx fifo, by the time the MAC acks the suspend
3112  * request.
3113  */
3114 bool wlc_bmac_tx_fifo_suspended(struct wlc_hw_info *wlc_hw, uint tx_fifo)
3115 {
3116         /* check that a suspend has been requested and is no longer pending */
3117
3118         /*
3119          * for DMA mode, the suspend request is set in xmtcontrol of the DMA engine,
3120          * and the tx fifo suspend at the lower end of the MAC is acknowledged in the
3121          * chnstatus register.
3122          * The tx fifo suspend completion is independent of the DMA suspend completion and
3123          *   may be acked before or after the DMA is suspended.
3124          */
3125         if (dma_txsuspended(wlc_hw->di[tx_fifo]) &&
3126             (R_REG(wlc_hw->osh, &wlc_hw->regs->chnstatus) &
3127              (1 << tx_fifo)) == 0)
3128                 return true;
3129
3130         return false;
3131 }
3132
3133 void wlc_bmac_tx_fifo_suspend(struct wlc_hw_info *wlc_hw, uint tx_fifo)
3134 {
3135         u8 fifo = 1 << tx_fifo;
3136
3137         /* Two clients of this code, 11h Quiet period and scanning. */
3138
3139         /* only suspend if not already suspended */
3140         if ((wlc_hw->suspended_fifos & fifo) == fifo)
3141                 return;
3142
3143         /* force the core awake only if not already */
3144         if (wlc_hw->suspended_fifos == 0)
3145                 wlc_ucode_wake_override_set(wlc_hw, WLC_WAKE_OVERRIDE_TXFIFO);
3146
3147         wlc_hw->suspended_fifos |= fifo;
3148
3149         if (wlc_hw->di[tx_fifo]) {
3150                 /* Suspending AMPDU transmissions in the middle can cause underflow
3151                  * which may result in mismatch between ucode and driver
3152                  * so suspend the mac before suspending the FIFO
3153                  */
3154                 if (WLC_PHY_11N_CAP(wlc_hw->band))
3155                         wlc_suspend_mac_and_wait(wlc_hw->wlc);
3156
3157                 dma_txsuspend(wlc_hw->di[tx_fifo]);
3158
3159                 if (WLC_PHY_11N_CAP(wlc_hw->band))
3160                         wlc_enable_mac(wlc_hw->wlc);
3161         }
3162 }
3163
3164 void wlc_bmac_tx_fifo_resume(struct wlc_hw_info *wlc_hw, uint tx_fifo)
3165 {
3166         /* BMAC_NOTE: WLC_TX_FIFO_ENAB is done in wlc_dpc() for DMA case but need to be done
3167          * here for PIO otherwise the watchdog will catch the inconsistency and fire
3168          */
3169         /* Two clients of this code, 11h Quiet period and scanning. */
3170         if (wlc_hw->di[tx_fifo])
3171                 dma_txresume(wlc_hw->di[tx_fifo]);
3172
3173         /* allow core to sleep again */
3174         if (wlc_hw->suspended_fifos == 0)
3175                 return;
3176         else {
3177                 wlc_hw->suspended_fifos &= ~(1 << tx_fifo);
3178                 if (wlc_hw->suspended_fifos == 0)
3179                         wlc_ucode_wake_override_clear(wlc_hw,
3180                                                       WLC_WAKE_OVERRIDE_TXFIFO);
3181         }
3182 }
3183
3184 /*
3185  * Read and clear macintmask and macintstatus and intstatus registers.
3186  * This routine should be called with interrupts off
3187  * Return:
3188  *   -1 if DEVICEREMOVED(wlc) evaluates to true;
3189  *   0 if the interrupt is not for us, or we are in some special cases;
3190  *   device interrupt status bits otherwise.
3191  */
3192 static inline u32 wlc_intstatus(struct wlc_info *wlc, bool in_isr)
3193 {
3194         struct wlc_hw_info *wlc_hw = wlc->hw;
3195         d11regs_t *regs = wlc_hw->regs;
3196         u32 macintstatus;
3197         u32 intstatus_rxfifo, intstatus_txsfifo;
3198         struct osl_info *osh;
3199
3200         osh = wlc_hw->osh;
3201
3202         /* macintstatus includes a DMA interrupt summary bit */
3203         macintstatus = R_REG(osh, &regs->macintstatus);
3204
3205         WL_TRACE("wl%d: macintstatus: 0x%x\n", wlc_hw->unit, macintstatus);
3206
3207         /* detect cardbus removed, in power down(suspend) and in reset */
3208         if (DEVICEREMOVED(wlc))
3209                 return -1;
3210
3211         /* DEVICEREMOVED succeeds even when the core is still resetting,
3212          * handle that case here.
3213          */
3214         if (macintstatus == 0xffffffff)
3215                 return 0;
3216
3217         /* defer unsolicited interrupts */
3218         macintstatus &= (in_isr ? wlc->macintmask : wlc->defmacintmask);
3219
3220         /* if not for us */
3221         if (macintstatus == 0)
3222                 return 0;
3223
3224         /* interrupts are already turned off for CFE build
3225          * Caution: For CFE Turning off the interrupts again has some undesired
3226          * consequences
3227          */
3228         /* turn off the interrupts */
3229         W_REG(osh, &regs->macintmask, 0);
3230         (void)R_REG(osh, &regs->macintmask);    /* sync readback */
3231         wlc->macintmask = 0;
3232
3233         /* clear device interrupts */
3234         W_REG(osh, &regs->macintstatus, macintstatus);
3235
3236         /* MI_DMAINT is indication of non-zero intstatus */
3237         if (macintstatus & MI_DMAINT) {
3238                 if (D11REV_IS(wlc_hw->corerev, 4)) {
3239                         intstatus_rxfifo =
3240                             R_REG(osh, &regs->intctrlregs[RX_FIFO].intstatus);
3241                         intstatus_txsfifo =
3242                             R_REG(osh,
3243                                   &regs->intctrlregs[RX_TXSTATUS_FIFO].
3244                                   intstatus);
3245                         WL_TRACE("wl%d: intstatus_rxfifo 0x%x, intstatus_txsfifo 0x%x\n",
3246                                  wlc_hw->unit,
3247                                  intstatus_rxfifo, intstatus_txsfifo);
3248
3249                         /* defer unsolicited interrupt hints */
3250                         intstatus_rxfifo &= DEF_RXINTMASK;
3251                         intstatus_txsfifo &= DEF_RXINTMASK;
3252
3253                         /* MI_DMAINT bit in macintstatus is indication of RX_FIFO interrupt */
3254                         /* clear interrupt hints */
3255                         if (intstatus_rxfifo)
3256                                 W_REG(osh,
3257                                       &regs->intctrlregs[RX_FIFO].intstatus,
3258                                       intstatus_rxfifo);
3259                         else
3260                                 macintstatus &= ~MI_DMAINT;
3261
3262                         /* MI_TFS bit in macintstatus is encoding of RX_TXSTATUS_FIFO interrupt */
3263                         if (intstatus_txsfifo) {
3264                                 W_REG(osh,
3265                                       &regs->intctrlregs[RX_TXSTATUS_FIFO].
3266                                       intstatus, intstatus_txsfifo);
3267                                 macintstatus |= MI_TFS;
3268                         }
3269                 } else {
3270                         /*
3271                          * For corerevs >= 5, only fifo interrupt enabled is I_RI in RX_FIFO.
3272                          * If MI_DMAINT is set, assume it is set and clear the interrupt.
3273                          */
3274                         W_REG(osh, &regs->intctrlregs[RX_FIFO].intstatus,
3275                               DEF_RXINTMASK);
3276                 }
3277         }
3278
3279         return macintstatus;
3280 }
3281
3282 /* Update wlc->macintstatus and wlc->intstatus[]. */
3283 /* Return true if they are updated successfully. false otherwise */
3284 bool wlc_intrsupd(struct wlc_info *wlc)
3285 {
3286         u32 macintstatus;
3287
3288         ASSERT(wlc->macintstatus != 0);
3289
3290         /* read and clear macintstatus and intstatus registers */
3291         macintstatus = wlc_intstatus(wlc, false);
3292
3293         /* device is removed */
3294         if (macintstatus == 0xffffffff)
3295                 return false;
3296
3297         /* update interrupt status in software */
3298         wlc->macintstatus |= macintstatus;
3299
3300         return true;
3301 }
3302
3303 /*
3304  * First-level interrupt processing.
3305  * Return true if this was our interrupt, false otherwise.
3306  * *wantdpc will be set to true if further wlc_dpc() processing is required,
3307  * false otherwise.
3308  */
3309 bool BCMFASTPATH wlc_isr(struct wlc_info *wlc, bool *wantdpc)
3310 {
3311         struct wlc_hw_info *wlc_hw = wlc->hw;
3312         u32 macintstatus;
3313
3314         *wantdpc = false;
3315
3316         if (!wlc_hw->up || !wlc->macintmask)
3317                 return false;
3318
3319         /* read and clear macintstatus and intstatus registers */
3320         macintstatus = wlc_intstatus(wlc, true);
3321
3322         if (macintstatus == 0xffffffff)
3323                 WL_ERROR("DEVICEREMOVED detected in the ISR code path\n");
3324
3325         /* it is not for us */
3326         if (macintstatus == 0)
3327                 return false;
3328
3329         *wantdpc = true;
3330
3331         /* save interrupt status bits */
3332         ASSERT(wlc->macintstatus == 0);
3333         wlc->macintstatus = macintstatus;
3334
3335         return true;
3336
3337 }
3338
3339 /* process tx completion events for corerev < 5 */
3340 static bool wlc_bmac_txstatus_corerev4(struct wlc_hw_info *wlc_hw)
3341 {
3342         struct sk_buff *status_p;
3343         tx_status_t *txs;
3344         struct osl_info *osh;
3345         bool fatal = false;
3346
3347         WL_TRACE("wl%d: wlc_txstatusrecv\n", wlc_hw->unit);
3348
3349         osh = wlc_hw->osh;
3350
3351         while (!fatal && (status_p = dma_rx(wlc_hw->di[RX_TXSTATUS_FIFO]))) {
3352
3353                 txs = (tx_status_t *) status_p->data;
3354                 /* MAC uses little endian only */
3355                 ltoh16_buf((void *)txs, sizeof(tx_status_t));
3356
3357                 /* shift low bits for tx_status_t status compatibility */
3358                 txs->status = (txs->status & ~TXS_COMPAT_MASK)
3359                     | (((txs->status & TXS_COMPAT_MASK) << TXS_COMPAT_SHIFT));
3360
3361                 fatal = wlc_bmac_dotxstatus(wlc_hw, txs, 0);
3362
3363                 pkt_buf_free_skb(osh, status_p, false);
3364         }
3365
3366         if (fatal)
3367                 return true;
3368
3369         /* post more rbufs */
3370         dma_rxfill(wlc_hw->di[RX_TXSTATUS_FIFO]);
3371
3372         return false;
3373 }
3374
3375 static bool BCMFASTPATH
3376 wlc_bmac_dotxstatus(struct wlc_hw_info *wlc_hw, tx_status_t *txs, u32 s2)
3377 {
3378         /* discard intermediate indications for ucode with one legitimate case:
3379          *   e.g. if "useRTS" is set. ucode did a successful rts/cts exchange, but the subsequent
3380          *   tx of DATA failed. so it will start rts/cts from the beginning (resetting the rts
3381          *   transmission count)
3382          */
3383         if (!(txs->status & TX_STATUS_AMPDU)
3384             && (txs->status & TX_STATUS_INTERMEDIATE)) {
3385                 return false;
3386         }
3387
3388         return wlc_dotxstatus(wlc_hw->wlc, txs, s2);
3389 }
3390
3391 /* process tx completion events in BMAC
3392  * Return true if more tx status need to be processed. false otherwise.
3393  */
3394 static bool BCMFASTPATH
3395 wlc_bmac_txstatus(struct wlc_hw_info *wlc_hw, bool bound, bool *fatal)
3396 {
3397         bool morepending = false;
3398         struct wlc_info *wlc = wlc_hw->wlc;
3399
3400         WL_TRACE("wl%d: wlc_bmac_txstatus\n", wlc_hw->unit);
3401
3402         if (D11REV_IS(wlc_hw->corerev, 4)) {
3403                 /* to retire soon */
3404                 *fatal = wlc_bmac_txstatus_corerev4(wlc->hw);
3405
3406                 if (*fatal)
3407                         return 0;
3408         } else {
3409                 /* corerev >= 5 */
3410                 d11regs_t *regs;
3411                 struct osl_info *osh;
3412                 tx_status_t txstatus, *txs;
3413                 u32 s1, s2;
3414                 uint n = 0;
3415                 /* Param 'max_tx_num' indicates max. # tx status to process before break out. */
3416                 uint max_tx_num = bound ? wlc->pub->tunables->txsbnd : -1;
3417
3418                 txs = &txstatus;
3419                 regs = wlc_hw->regs;
3420                 osh = wlc_hw->osh;
3421                 while (!(*fatal)
3422                        && (s1 = R_REG(osh, &regs->frmtxstatus)) & TXS_V) {
3423
3424                         if (s1 == 0xffffffff) {
3425                                 WL_ERROR("wl%d: %s: dead chip\n",
3426                                          wlc_hw->unit, __func__);
3427                                 ASSERT(s1 != 0xffffffff);
3428                                 return morepending;
3429                         }
3430
3431                         s2 = R_REG(osh, &regs->frmtxstatus2);
3432
3433                         txs->status = s1 & TXS_STATUS_MASK;
3434                         txs->frameid = (s1 & TXS_FID_MASK) >> TXS_FID_SHIFT;
3435                         txs->sequence = s2 & TXS_SEQ_MASK;
3436                         txs->phyerr = (s2 & TXS_PTX_MASK) >> TXS_PTX_SHIFT;
3437                         txs->lasttxtime = 0;
3438
3439                         *fatal = wlc_bmac_dotxstatus(wlc_hw, txs, s2);
3440
3441                         /* !give others some time to run! */
3442                         if (++n >= max_tx_num)
3443                                 break;
3444                 }
3445
3446                 if (*fatal)
3447                         return 0;
3448
3449                 if (n >= max_tx_num)
3450                         morepending = true;
3451         }
3452
3453         if (!pktq_empty(&wlc->active_queue->q))
3454                 wlc_send_q(wlc, wlc->active_queue);
3455
3456         return morepending;
3457 }
3458
3459 void wlc_suspend_mac_and_wait(struct wlc_info *wlc)
3460 {
3461         struct wlc_hw_info *wlc_hw = wlc->hw;
3462         d11regs_t *regs = wlc_hw->regs;
3463         u32 mc, mi;
3464         struct osl_info *osh;
3465
3466         WL_TRACE("wl%d: wlc_suspend_mac_and_wait: bandunit %d\n",
3467                  wlc_hw->unit, wlc_hw->band->bandunit);
3468
3469         /*
3470          * Track overlapping suspend requests
3471          */
3472         wlc_hw->mac_suspend_depth++;
3473         if (wlc_hw->mac_suspend_depth > 1)
3474                 return;
3475
3476         osh = wlc_hw->osh;
3477
3478         /* force the core awake */
3479         wlc_ucode_wake_override_set(wlc_hw, WLC_WAKE_OVERRIDE_MACSUSPEND);
3480
3481         mc = R_REG(osh, &regs->maccontrol);
3482
3483         if (mc == 0xffffffff) {
3484                 WL_ERROR("wl%d: %s: dead chip\n", wlc_hw->unit, __func__);
3485                 wl_down(wlc->wl);
3486                 return;
3487         }
3488         ASSERT(!(mc & MCTL_PSM_JMP_0));
3489         ASSERT(mc & MCTL_PSM_RUN);
3490         ASSERT(mc & MCTL_EN_MAC);
3491
3492         mi = R_REG(osh, &regs->macintstatus);
3493         if (mi == 0xffffffff) {
3494                 WL_ERROR("wl%d: %s: dead chip\n", wlc_hw->unit, __func__);
3495                 wl_down(wlc->wl);
3496                 return;
3497         }
3498         ASSERT(!(mi & MI_MACSSPNDD));
3499
3500         wlc_bmac_mctrl(wlc_hw, MCTL_EN_MAC, 0);
3501
3502         SPINWAIT(!(R_REG(osh, &regs->macintstatus) & MI_MACSSPNDD),
3503                  WLC_MAX_MAC_SUSPEND);
3504
3505         if (!(R_REG(osh, &regs->macintstatus) & MI_MACSSPNDD)) {
3506                 WL_ERROR("wl%d: wlc_suspend_mac_and_wait: waited %d uS and MI_MACSSPNDD is still not on.\n",
3507                          wlc_hw->unit, WLC_MAX_MAC_SUSPEND);
3508                 WL_ERROR("wl%d: psmdebug 0x%08x, phydebug 0x%08x, psm_brc 0x%04x\n",
3509                          wlc_hw->unit,
3510                          R_REG(osh, &regs->psmdebug),
3511                          R_REG(osh, &regs->phydebug),
3512                          R_REG(osh, &regs->psm_brc));
3513         }
3514
3515         mc = R_REG(osh, &regs->maccontrol);
3516         if (mc == 0xffffffff) {
3517                 WL_ERROR("wl%d: %s: dead chip\n", wlc_hw->unit, __func__);
3518                 wl_down(wlc->wl);
3519                 return;
3520         }
3521         ASSERT(!(mc & MCTL_PSM_JMP_0));
3522         ASSERT(mc & MCTL_PSM_RUN);
3523         ASSERT(!(mc & MCTL_EN_MAC));
3524 }
3525
3526 void wlc_enable_mac(struct wlc_info *wlc)
3527 {
3528         struct wlc_hw_info *wlc_hw = wlc->hw;
3529         d11regs_t *regs = wlc_hw->regs;
3530         u32 mc, mi;
3531         struct osl_info *osh;
3532
3533         WL_TRACE("wl%d: wlc_enable_mac: bandunit %d\n",
3534                  wlc_hw->unit, wlc->band->bandunit);
3535
3536         /*
3537          * Track overlapping suspend requests
3538          */
3539         ASSERT(wlc_hw->mac_suspend_depth > 0);
3540         wlc_hw->mac_suspend_depth--;
3541         if (wlc_hw->mac_suspend_depth > 0)
3542                 return;
3543
3544         osh = wlc_hw->osh;
3545
3546         mc = R_REG(osh, &regs->maccontrol);
3547         ASSERT(!(mc & MCTL_PSM_JMP_0));
3548         ASSERT(!(mc & MCTL_EN_MAC));
3549         ASSERT(mc & MCTL_PSM_RUN);
3550
3551         wlc_bmac_mctrl(wlc_hw, MCTL_EN_MAC, MCTL_EN_MAC);
3552         W_REG(osh, &regs->macintstatus, MI_MACSSPNDD);
3553
3554         mc = R_REG(osh, &regs->maccontrol);
3555         ASSERT(!(mc & MCTL_PSM_JMP_0));
3556         ASSERT(mc & MCTL_EN_MAC);
3557         ASSERT(mc & MCTL_PSM_RUN);
3558
3559         mi = R_REG(osh, &regs->macintstatus);
3560         ASSERT(!(mi & MI_MACSSPNDD));
3561
3562         wlc_ucode_wake_override_clear(wlc_hw, WLC_WAKE_OVERRIDE_MACSUSPEND);
3563 }
3564
3565 void wlc_bmac_ifsctl_edcrs_set(struct wlc_hw_info *wlc_hw, bool abie, bool isht)
3566 {
3567         if (!(WLCISNPHY(wlc_hw->band) && (D11REV_GE(wlc_hw->corerev, 16))))
3568                 return;
3569
3570         if (isht) {
3571                 if (WLCISNPHY(wlc_hw->band) && NREV_LT(wlc_hw->band->phyrev, 3)) {
3572                         AND_REG(wlc_hw->osh, &wlc_hw->regs->ifs_ctl1,
3573                                 ~IFS_CTL1_EDCRS);
3574                 }
3575         } else {
3576                 /* enable EDCRS for non-11n association */
3577                 OR_REG(wlc_hw->osh, &wlc_hw->regs->ifs_ctl1, IFS_CTL1_EDCRS);
3578         }
3579
3580         if (WLCISNPHY(wlc_hw->band) && NREV_GE(wlc_hw->band->phyrev, 3)) {
3581                 if (CHSPEC_IS20(wlc_hw->chanspec)) {
3582                         /* 20 mhz, use 20U ED only */
3583                         OR_REG(wlc_hw->osh, &wlc_hw->regs->ifs_ctl1,
3584                                IFS_CTL1_EDCRS);
3585                         AND_REG(wlc_hw->osh, &wlc_hw->regs->ifs_ctl1,
3586                                 ~IFS_CTL1_EDCRS_20L);
3587                         AND_REG(wlc_hw->osh, &wlc_hw->regs->ifs_ctl1,
3588                                 ~IFS_CTL1_EDCRS_40);
3589                 } else {
3590                         /* 40 mhz, use 20U 20L and 40 ED */
3591                         OR_REG(wlc_hw->osh, &wlc_hw->regs->ifs_ctl1,
3592                                IFS_CTL1_EDCRS);
3593                         OR_REG(wlc_hw->osh, &wlc_hw->regs->ifs_ctl1,
3594                                IFS_CTL1_EDCRS_20L);
3595                         OR_REG(wlc_hw->osh, &wlc_hw->regs->ifs_ctl1,
3596                                IFS_CTL1_EDCRS_40);
3597                 }
3598         }
3599 }
3600
3601 static void wlc_upd_ofdm_pctl1_table(struct wlc_hw_info *wlc_hw)
3602 {
3603         u8 rate;
3604         u8 rates[8] = {
3605                 WLC_RATE_6M, WLC_RATE_9M, WLC_RATE_12M, WLC_RATE_18M,
3606                 WLC_RATE_24M, WLC_RATE_36M, WLC_RATE_48M, WLC_RATE_54M
3607         };
3608         u16 entry_ptr;
3609         u16 pctl1;
3610         uint i;
3611
3612         if (!WLC_PHY_11N_CAP(wlc_hw->band))
3613                 return;
3614
3615         /* walk the phy rate table and update the entries */
3616         for (i = 0; i < ARRAY_SIZE(rates); i++) {
3617                 rate = rates[i];
3618
3619                 entry_ptr = wlc_bmac_ofdm_ratetable_offset(wlc_hw, rate);
3620
3621                 /* read the SHM Rate Table entry OFDM PCTL1 values */
3622                 pctl1 =
3623                     wlc_bmac_read_shm(wlc_hw, entry_ptr + M_RT_OFDM_PCTL1_POS);
3624
3625                 /* modify the value */
3626                 pctl1 &= ~PHY_TXC1_MODE_MASK;
3627                 pctl1 |= (wlc_hw->hw_stf_ss_opmode << PHY_TXC1_MODE_SHIFT);
3628
3629                 /* Update the SHM Rate Table entry OFDM PCTL1 values */
3630                 wlc_bmac_write_shm(wlc_hw, entry_ptr + M_RT_OFDM_PCTL1_POS,
3631                                    pctl1);
3632         }
3633 }
3634
3635 static u16 wlc_bmac_ofdm_ratetable_offset(struct wlc_hw_info *wlc_hw, u8 rate)
3636 {
3637         uint i;
3638         u8 plcp_rate = 0;
3639         struct plcp_signal_rate_lookup {
3640                 u8 rate;
3641                 u8 signal_rate;
3642         };
3643         /* OFDM RATE sub-field of PLCP SIGNAL field, per 802.11 sec 17.3.4.1 */
3644         const struct plcp_signal_rate_lookup rate_lookup[] = {
3645                 {WLC_RATE_6M, 0xB},
3646                 {WLC_RATE_9M, 0xF},
3647                 {WLC_RATE_12M, 0xA},
3648                 {WLC_RATE_18M, 0xE},
3649                 {WLC_RATE_24M, 0x9},
3650                 {WLC_RATE_36M, 0xD},
3651                 {WLC_RATE_48M, 0x8},
3652                 {WLC_RATE_54M, 0xC}
3653         };
3654
3655         for (i = 0; i < ARRAY_SIZE(rate_lookup); i++) {
3656                 if (rate == rate_lookup[i].rate) {
3657                         plcp_rate = rate_lookup[i].signal_rate;
3658                         break;
3659                 }
3660         }
3661
3662         /* Find the SHM pointer to the rate table entry by looking in the
3663          * Direct-map Table
3664          */
3665         return 2 * wlc_bmac_read_shm(wlc_hw, M_RT_DIRMAP_A + (plcp_rate * 2));
3666 }
3667
3668 void wlc_bmac_band_stf_ss_set(struct wlc_hw_info *wlc_hw, u8 stf_mode)
3669 {
3670         wlc_hw->hw_stf_ss_opmode = stf_mode;
3671
3672         if (wlc_hw->clk)
3673                 wlc_upd_ofdm_pctl1_table(wlc_hw);
3674 }
3675
3676 void BCMFASTPATH
3677 wlc_bmac_read_tsf(struct wlc_hw_info *wlc_hw, u32 *tsf_l_ptr,
3678                   u32 *tsf_h_ptr)
3679 {
3680         d11regs_t *regs = wlc_hw->regs;
3681
3682         /* read the tsf timer low, then high to get an atomic read */
3683         *tsf_l_ptr = R_REG(wlc_hw->osh, &regs->tsf_timerlow);
3684         *tsf_h_ptr = R_REG(wlc_hw->osh, &regs->tsf_timerhigh);
3685
3686         return;
3687 }
3688
3689 bool wlc_bmac_validate_chip_access(struct wlc_hw_info *wlc_hw)
3690 {
3691         d11regs_t *regs;
3692         u32 w, val;
3693         volatile u16 *reg16;
3694         struct osl_info *osh;
3695
3696         WL_TRACE("wl%d: validate_chip_access\n", wlc_hw->unit);
3697
3698         regs = wlc_hw->regs;
3699         osh = wlc_hw->osh;
3700
3701         /* Validate dchip register access */
3702
3703         W_REG(osh, &regs->objaddr, OBJADDR_SHM_SEL | 0);
3704         (void)R_REG(osh, &regs->objaddr);
3705         w = R_REG(osh, &regs->objdata);
3706
3707         /* Can we write and read back a 32bit register? */
3708         W_REG(osh, &regs->objaddr, OBJADDR_SHM_SEL | 0);
3709         (void)R_REG(osh, &regs->objaddr);
3710         W_REG(osh, &regs->objdata, (u32) 0xaa5555aa);
3711
3712         W_REG(osh, &regs->objaddr, OBJADDR_SHM_SEL | 0);
3713         (void)R_REG(osh, &regs->objaddr);
3714         val = R_REG(osh, &regs->objdata);
3715         if (val != (u32) 0xaa5555aa) {
3716                 WL_ERROR("wl%d: validate_chip_access: SHM = 0x%x, expected 0xaa5555aa\n",
3717                          wlc_hw->unit, val);
3718                 return false;
3719         }
3720
3721         W_REG(osh, &regs->objaddr, OBJADDR_SHM_SEL | 0);
3722         (void)R_REG(osh, &regs->objaddr);
3723         W_REG(osh, &regs->objdata, (u32) 0x55aaaa55);
3724
3725         W_REG(osh, &regs->objaddr, OBJADDR_SHM_SEL | 0);
3726         (void)R_REG(osh, &regs->objaddr);
3727         val = R_REG(osh, &regs->objdata);
3728         if (val != (u32) 0x55aaaa55) {
3729                 WL_ERROR("wl%d: validate_chip_access: SHM = 0x%x, expected 0x55aaaa55\n",
3730                          wlc_hw->unit, val);
3731                 return false;
3732         }
3733
3734         W_REG(osh, &regs->objaddr, OBJADDR_SHM_SEL | 0);
3735         (void)R_REG(osh, &regs->objaddr);
3736         W_REG(osh, &regs->objdata, w);
3737
3738         if (D11REV_LT(wlc_hw->corerev, 11)) {
3739                 /* if 32 bit writes are split into 16 bit writes, are they in the correct order
3740                  * for our interface, low to high
3741                  */
3742                 reg16 = (volatile u16 *)&regs->tsf_cfpstart;
3743
3744                 /* write the CFPStart register low half explicitly, starting a buffered write */
3745                 W_REG(osh, reg16, 0xAAAA);
3746
3747                 /* Write a 32 bit value to CFPStart to test the 16 bit split order.
3748                  * If the low 16 bits are written first, followed by the high 16 bits then the
3749                  * 32 bit value 0xCCCCBBBB should end up in the register.
3750                  * If the order is reversed, then the write to the high half will trigger a buffered
3751                  * write of 0xCCCCAAAA.
3752                  * If the bus is 32 bits, then this is not much of a test, and the reg should
3753                  * have the correct value 0xCCCCBBBB.
3754                  */
3755                 W_REG(osh, &regs->tsf_cfpstart, 0xCCCCBBBB);
3756
3757                 /* verify with the 16 bit registers that have no side effects */
3758                 val = R_REG(osh, &regs->tsf_cfpstrt_l);
3759                 if (val != (uint) 0xBBBB) {
3760                         WL_ERROR("wl%d: validate_chip_access: tsf_cfpstrt_l = 0x%x, expected 0x%x\n",
3761                                  wlc_hw->unit, val, 0xBBBB);
3762                         return false;
3763                 }
3764                 val = R_REG(osh, &regs->tsf_cfpstrt_h);
3765                 if (val != (uint) 0xCCCC) {
3766                         WL_ERROR("wl%d: validate_chip_access: tsf_cfpstrt_h = 0x%x, expected 0x%x\n",
3767                                  wlc_hw->unit, val, 0xCCCC);
3768                         return false;
3769                 }
3770
3771         }
3772
3773         /* clear CFPStart */
3774         W_REG(osh, &regs->tsf_cfpstart, 0);
3775
3776         w = R_REG(osh, &regs->maccontrol);
3777         if ((w != (MCTL_IHR_EN | MCTL_WAKE)) &&
3778             (w != (MCTL_IHR_EN | MCTL_GMODE | MCTL_WAKE))) {
3779                 WL_ERROR("wl%d: validate_chip_access: maccontrol = 0x%x, expected 0x%x or 0x%x\n",
3780                          wlc_hw->unit, w,
3781                          (MCTL_IHR_EN | MCTL_WAKE),
3782                          (MCTL_IHR_EN | MCTL_GMODE | MCTL_WAKE));
3783                 return false;
3784         }
3785
3786         return true;
3787 }
3788
3789 #define PHYPLL_WAIT_US  100000
3790
3791 void wlc_bmac_core_phypll_ctl(struct wlc_hw_info *wlc_hw, bool on)
3792 {
3793         d11regs_t *regs;
3794         struct osl_info *osh;
3795         u32 tmp;
3796
3797         WL_TRACE("wl%d: wlc_bmac_core_phypll_ctl\n", wlc_hw->unit);
3798
3799         tmp = 0;
3800         regs = wlc_hw->regs;
3801         osh = wlc_hw->osh;
3802
3803         if (D11REV_LE(wlc_hw->corerev, 16) || D11REV_IS(wlc_hw->corerev, 20))
3804                 return;
3805
3806         if (on) {
3807                 if ((wlc_hw->sih->chip == BCM4313_CHIP_ID)) {
3808                         OR_REG(osh, &regs->clk_ctl_st,
3809                                (CCS_ERSRC_REQ_HT | CCS_ERSRC_REQ_D11PLL |
3810                                 CCS_ERSRC_REQ_PHYPLL));
3811                         SPINWAIT((R_REG(osh, &regs->clk_ctl_st) &
3812                                   (CCS_ERSRC_AVAIL_HT)) != (CCS_ERSRC_AVAIL_HT),
3813                                  PHYPLL_WAIT_US);
3814
3815                         tmp = R_REG(osh, &regs->clk_ctl_st);
3816                         if ((tmp & (CCS_ERSRC_AVAIL_HT)) !=
3817                             (CCS_ERSRC_AVAIL_HT)) {
3818                                 WL_ERROR("%s: turn on PHY PLL failed\n",
3819                                          __func__);
3820                                 ASSERT(0);
3821                         }
3822                 } else {
3823                         OR_REG(osh, &regs->clk_ctl_st,
3824                                (CCS_ERSRC_REQ_D11PLL | CCS_ERSRC_REQ_PHYPLL));
3825                         SPINWAIT((R_REG(osh, &regs->clk_ctl_st) &
3826                                   (CCS_ERSRC_AVAIL_D11PLL |
3827                                    CCS_ERSRC_AVAIL_PHYPLL)) !=
3828                                  (CCS_ERSRC_AVAIL_D11PLL |
3829                                   CCS_ERSRC_AVAIL_PHYPLL), PHYPLL_WAIT_US);
3830
3831                         tmp = R_REG(osh, &regs->clk_ctl_st);
3832                         if ((tmp &
3833                              (CCS_ERSRC_AVAIL_D11PLL | CCS_ERSRC_AVAIL_PHYPLL))
3834                             !=
3835                             (CCS_ERSRC_AVAIL_D11PLL | CCS_ERSRC_AVAIL_PHYPLL)) {
3836                                 WL_ERROR("%s: turn on PHY PLL failed\n",
3837                                          __func__);
3838                                 ASSERT(0);
3839                         }
3840                 }
3841         } else {
3842                 /* Since the PLL may be shared, other cores can still be requesting it;
3843                  * so we'll deassert the request but not wait for status to comply.
3844                  */
3845                 AND_REG(osh, &regs->clk_ctl_st, ~CCS_ERSRC_REQ_PHYPLL);
3846                 tmp = R_REG(osh, &regs->clk_ctl_st);
3847         }
3848 }
3849
3850 void wlc_coredisable(struct wlc_hw_info *wlc_hw)
3851 {
3852         bool dev_gone;
3853
3854         WL_TRACE("wl%d: %s\n", wlc_hw->unit, __func__);
3855
3856         ASSERT(!wlc_hw->up);
3857
3858         dev_gone = DEVICEREMOVED(wlc_hw->wlc);
3859
3860         if (dev_gone)
3861                 return;
3862
3863         if (wlc_hw->noreset)
3864                 return;
3865
3866         /* radio off */
3867         wlc_phy_switch_radio(wlc_hw->band->pi, OFF);
3868
3869         /* turn off analog core */
3870         wlc_phy_anacore(wlc_hw->band->pi, OFF);
3871
3872         /* turn off PHYPLL to save power */
3873         wlc_bmac_core_phypll_ctl(wlc_hw, false);
3874
3875         /* No need to set wlc->pub->radio_active = OFF
3876          * because this function needs down capability and
3877          * radio_active is designed for BCMNODOWN.
3878          */
3879
3880         /* remove gpio controls */
3881         if (wlc_hw->ucode_dbgsel)
3882                 si_gpiocontrol(wlc_hw->sih, ~0, 0, GPIO_DRV_PRIORITY);
3883
3884         wlc_hw->clk = false;
3885         si_core_disable(wlc_hw->sih, 0);
3886         wlc_phy_hw_clk_state_upd(wlc_hw->band->pi, false);
3887 }
3888
3889 /* power both the pll and external oscillator on/off */
3890 void wlc_bmac_xtal(struct wlc_hw_info *wlc_hw, bool want)
3891 {
3892         WL_TRACE("wl%d: wlc_bmac_xtal: want %d\n", wlc_hw->unit, want);
3893
3894         /* dont power down if plldown is false or we must poll hw radio disable */
3895         if (!want && wlc_hw->pllreq)
3896                 return;
3897
3898         if (wlc_hw->sih)
3899                 si_clkctl_xtal(wlc_hw->sih, XTAL | PLL, want);
3900
3901         wlc_hw->sbclk = want;
3902         if (!wlc_hw->sbclk) {
3903                 wlc_hw->clk = false;
3904                 if (wlc_hw->band && wlc_hw->band->pi)
3905                         wlc_phy_hw_clk_state_upd(wlc_hw->band->pi, false);
3906         }
3907 }
3908
3909 static void wlc_flushqueues(struct wlc_info *wlc)
3910 {
3911         struct wlc_hw_info *wlc_hw = wlc->hw;
3912         uint i;
3913
3914         wlc->txpend16165war = 0;
3915
3916         /* free any posted tx packets */
3917         for (i = 0; i < NFIFO; i++)
3918                 if (wlc_hw->di[i]) {
3919                         dma_txreclaim(wlc_hw->di[i], HNDDMA_RANGE_ALL);
3920                         TXPKTPENDCLR(wlc, i);
3921                         WL_TRACE("wlc_flushqueues: pktpend fifo %d cleared\n",
3922                                  i);
3923                 }
3924
3925         /* free any posted rx packets */
3926         dma_rxreclaim(wlc_hw->di[RX_FIFO]);
3927         if (D11REV_IS(wlc_hw->corerev, 4))
3928                 dma_rxreclaim(wlc_hw->di[RX_TXSTATUS_FIFO]);
3929 }
3930
3931 u16 wlc_bmac_read_shm(struct wlc_hw_info *wlc_hw, uint offset)
3932 {
3933         return wlc_bmac_read_objmem(wlc_hw, offset, OBJADDR_SHM_SEL);
3934 }
3935
3936 void wlc_bmac_write_shm(struct wlc_hw_info *wlc_hw, uint offset, u16 v)
3937 {
3938         wlc_bmac_write_objmem(wlc_hw, offset, v, OBJADDR_SHM_SEL);
3939 }
3940
3941 /* Set a range of shared memory to a value.
3942  * SHM 'offset' needs to be an even address and
3943  * Buffer length 'len' must be an even number of bytes
3944  */
3945 void wlc_bmac_set_shm(struct wlc_hw_info *wlc_hw, uint offset, u16 v, int len)
3946 {
3947         int i;
3948
3949         /* offset and len need to be even */
3950         ASSERT((offset & 1) == 0);
3951         ASSERT((len & 1) == 0);
3952
3953         if (len <= 0)
3954                 return;
3955
3956         for (i = 0; i < len; i += 2) {
3957                 wlc_bmac_write_objmem(wlc_hw, offset + i, v, OBJADDR_SHM_SEL);
3958         }
3959 }
3960
3961 static u16
3962 wlc_bmac_read_objmem(struct wlc_hw_info *wlc_hw, uint offset, u32 sel)
3963 {
3964         d11regs_t *regs = wlc_hw->regs;
3965         volatile u16 *objdata_lo = (volatile u16 *)&regs->objdata;
3966         volatile u16 *objdata_hi = objdata_lo + 1;
3967         u16 v;
3968
3969         ASSERT((offset & 1) == 0);
3970
3971         W_REG(wlc_hw->osh, &regs->objaddr, sel | (offset >> 2));
3972         (void)R_REG(wlc_hw->osh, &regs->objaddr);
3973         if (offset & 2) {
3974                 v = R_REG(wlc_hw->osh, objdata_hi);
3975         } else {
3976                 v = R_REG(wlc_hw->osh, objdata_lo);
3977         }
3978
3979         return v;
3980 }
3981
3982 static void
3983 wlc_bmac_write_objmem(struct wlc_hw_info *wlc_hw, uint offset, u16 v, u32 sel)
3984 {
3985         d11regs_t *regs = wlc_hw->regs;
3986         volatile u16 *objdata_lo = (volatile u16 *)&regs->objdata;
3987         volatile u16 *objdata_hi = objdata_lo + 1;
3988
3989         ASSERT((offset & 1) == 0);
3990
3991         W_REG(wlc_hw->osh, &regs->objaddr, sel | (offset >> 2));
3992         (void)R_REG(wlc_hw->osh, &regs->objaddr);
3993         if (offset & 2) {
3994                 W_REG(wlc_hw->osh, objdata_hi, v);
3995         } else {
3996                 W_REG(wlc_hw->osh, objdata_lo, v);
3997         }
3998 }
3999
4000 /* Copy a buffer to shared memory of specified type .
4001  * SHM 'offset' needs to be an even address and
4002  * Buffer length 'len' must be an even number of bytes
4003  * 'sel' selects the type of memory
4004  */
4005 void
4006 wlc_bmac_copyto_objmem(struct wlc_hw_info *wlc_hw, uint offset, const void *buf,
4007                        int len, u32 sel)
4008 {
4009         u16 v;
4010         const u8 *p = (const u8 *)buf;
4011         int i;
4012
4013         /* offset and len need to be even */
4014         ASSERT((offset & 1) == 0);
4015         ASSERT((len & 1) == 0);
4016
4017         if (len <= 0)
4018                 return;
4019
4020         for (i = 0; i < len; i += 2) {
4021                 v = p[i] | (p[i + 1] << 8);
4022                 wlc_bmac_write_objmem(wlc_hw, offset + i, v, sel);
4023         }
4024 }
4025
4026 /* Copy a piece of shared memory of specified type to a buffer .
4027  * SHM 'offset' needs to be an even address and
4028  * Buffer length 'len' must be an even number of bytes
4029  * 'sel' selects the type of memory
4030  */
4031 void
4032 wlc_bmac_copyfrom_objmem(struct wlc_hw_info *wlc_hw, uint offset, void *buf,
4033                          int len, u32 sel)
4034 {
4035         u16 v;
4036         u8 *p = (u8 *) buf;
4037         int i;
4038
4039         /* offset and len need to be even */
4040         ASSERT((offset & 1) == 0);
4041         ASSERT((len & 1) == 0);
4042
4043         if (len <= 0)
4044                 return;
4045
4046         for (i = 0; i < len; i += 2) {
4047                 v = wlc_bmac_read_objmem(wlc_hw, offset + i, sel);
4048                 p[i] = v & 0xFF;
4049                 p[i + 1] = (v >> 8) & 0xFF;
4050         }
4051 }
4052
4053 void wlc_bmac_copyfrom_vars(struct wlc_hw_info *wlc_hw, char **buf, uint *len)
4054 {
4055         WL_TRACE("wlc_bmac_copyfrom_vars, nvram vars totlen=%d\n",
4056                  wlc_hw->vars_size);
4057
4058         *buf = wlc_hw->vars;
4059         *len = wlc_hw->vars_size;
4060 }
4061
4062 void wlc_bmac_retrylimit_upd(struct wlc_hw_info *wlc_hw, u16 SRL, u16 LRL)
4063 {
4064         wlc_hw->SRL = SRL;
4065         wlc_hw->LRL = LRL;
4066
4067         /* write retry limit to SCR, shouldn't need to suspend */
4068         if (wlc_hw->up) {
4069                 W_REG(wlc_hw->osh, &wlc_hw->regs->objaddr,
4070                       OBJADDR_SCR_SEL | S_DOT11_SRC_LMT);
4071                 (void)R_REG(wlc_hw->osh, &wlc_hw->regs->objaddr);
4072                 W_REG(wlc_hw->osh, &wlc_hw->regs->objdata, wlc_hw->SRL);
4073                 W_REG(wlc_hw->osh, &wlc_hw->regs->objaddr,
4074                       OBJADDR_SCR_SEL | S_DOT11_LRC_LMT);
4075                 (void)R_REG(wlc_hw->osh, &wlc_hw->regs->objaddr);
4076                 W_REG(wlc_hw->osh, &wlc_hw->regs->objdata, wlc_hw->LRL);
4077         }
4078 }
4079
4080 void wlc_bmac_set_noreset(struct wlc_hw_info *wlc_hw, bool noreset_flag)
4081 {
4082         wlc_hw->noreset = noreset_flag;
4083 }
4084
4085 void wlc_bmac_set_ucode_loaded(struct wlc_hw_info *wlc_hw, bool ucode_loaded)
4086 {
4087         wlc_hw->ucode_loaded = ucode_loaded;
4088 }
4089
4090 void wlc_bmac_pllreq(struct wlc_hw_info *wlc_hw, bool set, mbool req_bit)
4091 {
4092         ASSERT(req_bit);
4093
4094         if (set) {
4095                 if (mboolisset(wlc_hw->pllreq, req_bit))
4096                         return;
4097
4098                 mboolset(wlc_hw->pllreq, req_bit);
4099
4100                 if (mboolisset(wlc_hw->pllreq, WLC_PLLREQ_FLIP)) {
4101                         if (!wlc_hw->sbclk) {
4102                                 wlc_bmac_xtal(wlc_hw, ON);
4103                         }
4104                 }
4105         } else {
4106                 if (!mboolisset(wlc_hw->pllreq, req_bit))
4107                         return;
4108
4109                 mboolclr(wlc_hw->pllreq, req_bit);
4110
4111                 if (mboolisset(wlc_hw->pllreq, WLC_PLLREQ_FLIP)) {
4112                         if (wlc_hw->sbclk) {
4113                                 wlc_bmac_xtal(wlc_hw, OFF);
4114                         }
4115                 }
4116         }
4117
4118         return;
4119 }
4120
4121 void wlc_bmac_set_clk(struct wlc_hw_info *wlc_hw, bool on)
4122 {
4123         if (on) {
4124                 /* power up pll and oscillator */
4125                 wlc_bmac_xtal(wlc_hw, ON);
4126
4127                 /* enable core(s), ignore bandlocked
4128                  * Leave with the same band selected as we entered
4129                  */
4130                 wlc_bmac_corereset(wlc_hw, WLC_USE_COREFLAGS);
4131         } else {
4132                 /* if already down, must skip the core disable */
4133                 if (wlc_hw->clk) {
4134                         /* disable core(s), ignore bandlocked */
4135                         wlc_coredisable(wlc_hw);
4136                 }
4137                 /* power down pll and oscillator */
4138                 wlc_bmac_xtal(wlc_hw, OFF);
4139         }
4140 }
4141
4142 /* this will be true for all ai chips */
4143 bool wlc_bmac_taclear(struct wlc_hw_info *wlc_hw, bool ta_ok)
4144 {
4145         return true;
4146 }
4147
4148 /* Lower down relevant GPIOs like LED when going down w/o
4149  * doing PCI config cycles or touching interrupts
4150  */
4151 void wlc_gpio_fast_deinit(struct wlc_hw_info *wlc_hw)
4152 {
4153         if ((wlc_hw == NULL) || (wlc_hw->sih == NULL))
4154                 return;
4155
4156         /* Only chips with internal bus or PCIE cores or certain PCI cores
4157          * are able to switch cores w/o disabling interrupts
4158          */
4159         if (!((wlc_hw->sih->bustype == SI_BUS) ||
4160               ((wlc_hw->sih->bustype == PCI_BUS) &&
4161                ((wlc_hw->sih->buscoretype == PCIE_CORE_ID) ||
4162                 (wlc_hw->sih->buscorerev >= 13)))))
4163                 return;
4164
4165         WL_TRACE("wl%d: %s\n", wlc_hw->unit, __func__);
4166         return;
4167 }
4168
4169 bool wlc_bmac_radio_hw(struct wlc_hw_info *wlc_hw, bool enable)
4170 {
4171         /* Do not access Phy registers if core is not up */
4172         if (si_iscoreup(wlc_hw->sih) == false)
4173                 return false;
4174
4175         if (enable) {
4176                 if (PMUCTL_ENAB(wlc_hw->sih)) {
4177                         AND_REG(wlc_hw->osh, &wlc_hw->regs->clk_ctl_st,
4178                                 ~CCS_FORCEHWREQOFF);
4179                         si_pmu_radio_enable(wlc_hw->sih, true);
4180                 }
4181
4182                 wlc_phy_anacore(wlc_hw->band->pi, ON);
4183                 wlc_phy_switch_radio(wlc_hw->band->pi, ON);
4184
4185                 /* resume d11 core */
4186                 wlc_enable_mac(wlc_hw->wlc);
4187         } else {
4188                 /* suspend d11 core */
4189                 wlc_suspend_mac_and_wait(wlc_hw->wlc);
4190
4191                 wlc_phy_switch_radio(wlc_hw->band->pi, OFF);
4192                 wlc_phy_anacore(wlc_hw->band->pi, OFF);
4193
4194                 if (PMUCTL_ENAB(wlc_hw->sih)) {
4195                         si_pmu_radio_enable(wlc_hw->sih, false);
4196                         OR_REG(wlc_hw->osh, &wlc_hw->regs->clk_ctl_st,
4197                                CCS_FORCEHWREQOFF);
4198                 }
4199         }
4200
4201         return true;
4202 }
4203
4204 u16 wlc_bmac_rate_shm_offset(struct wlc_hw_info *wlc_hw, u8 rate)
4205 {
4206         u16 table_ptr;
4207         u8 phy_rate, index;
4208
4209         /* get the phy specific rate encoding for the PLCP SIGNAL field */
4210         /* XXX4321 fixup needed ? */
4211         if (IS_OFDM(rate))
4212                 table_ptr = M_RT_DIRMAP_A;
4213         else
4214                 table_ptr = M_RT_DIRMAP_B;
4215
4216         /* for a given rate, the LS-nibble of the PLCP SIGNAL field is
4217          * the index into the rate table.
4218          */
4219         phy_rate = rate_info[rate] & RATE_MASK;
4220         index = phy_rate & 0xf;
4221
4222         /* Find the SHM pointer to the rate table entry by looking in the
4223          * Direct-map Table
4224          */
4225         return 2 * wlc_bmac_read_shm(wlc_hw, table_ptr + (index * 2));
4226 }
4227
4228 void wlc_bmac_set_txpwr_percent(struct wlc_hw_info *wlc_hw, u8 val)
4229 {
4230         wlc_phy_txpwr_percent_set(wlc_hw->band->pi, val);
4231 }
4232
4233 void wlc_bmac_antsel_set(struct wlc_hw_info *wlc_hw, u32 antsel_avail)
4234 {
4235         wlc_hw->antsel_avail = antsel_avail;
4236 }