25/5/09 Should work on all ports that have a kernel which currently includes an "ath* at pci*" line Index: sys/conf/files =================================================================== RCS file: /cvsroot/src/sys/conf/files,v retrieving revision 1.924.4.1 diff -u -r1.924.4.1 files --- sys/conf/files 15 Mar 2009 19:43:48 -0000 1.924.4.1 +++ sys/conf/files 15 May 2009 13:10:30 -0000 @@ -582,15 +582,16 @@ device wi: arp, wlan, ifnet file dev/ic/wi.c wi +# Atheros HAL +# +include "external/isc/atheros_hal/conf/files.ath_hal" + # Atheros 5210/5211/5212 multi-mode 802.11 # -defflag opt_athhal.h ATHHAL_ASSERT ATHHAL_DEBUG ATHHAL_DEBUG_ALQ device ath: arp, wlan, ifnet file dev/ic/ath.c ath file dev/ic/ath_netbsd.c ath file dev/ic/athrate-sample.c ath -file contrib/dev/ath/netbsd/ah_osdep.c ath -object /athhal.o ath # ADMtek ADM8211 802.11 # Index: sys/arch/i386/conf/std.i386 =================================================================== RCS file: /cvsroot/src/sys/arch/i386/conf/std.i386,v retrieving revision 1.28 diff -u -r1.28 std.i386 --- sys/arch/i386/conf/std.i386 30 Apr 2008 15:29:12 -0000 1.28 +++ sys/arch/i386/conf/std.i386 15 May 2009 13:10:48 -0000 @@ -19,3 +19,6 @@ mainbus0 at root cpu* at mainbus? ioapic* at mainbus? + +# Atheros HAL options +include "external/isc/atheros_hal/conf/std.ath_hal" Index: sys/arch/macppc/conf/std.macppc =================================================================== RCS file: /cvsroot/src/sys/arch/macppc/conf/std.macppc,v retrieving revision 1.22 diff -u -r1.22 std.macppc --- sys/arch/macppc/conf/std.macppc 17 Oct 2007 19:55:17 -0000 1.22 +++ sys/arch/macppc/conf/std.macppc 15 May 2009 13:10:48 -0000 @@ -16,3 +16,6 @@ options EXEC_SCRIPT # shell script support options INTSTK=0x2000 + +# Atheros HAL options +include "external/isc/atheros_hal/conf/std.ath_hal" Index: sys/arch/macppc/conf/std.macppc.g5 =================================================================== RCS file: /cvsroot/src/sys/arch/macppc/conf/std.macppc.g5,v retrieving revision 1.2 diff -u -r1.2 std.macppc.g5 --- sys/arch/macppc/conf/std.macppc.g5 26 Aug 2008 16:18:49 -0000 1.2 +++ sys/arch/macppc/conf/std.macppc.g5 25 May 2009 19:39:27 -0000 @@ -15,3 +15,6 @@ options EXEC_SCRIPT # shell script support options INTSTK=0x2000 + +# Atheros HAL options +include "external/isc/atheros_hal/conf/std.ath_hal" Index: sys/arch/xen/conf/std.xen =================================================================== RCS file: /cvsroot/src/sys/arch/xen/conf/std.xen,v retrieving revision 1.5 diff -u -r1.5 std.xen --- sys/arch/xen/conf/std.xen 25 Jan 2008 21:12:14 -0000 1.5 +++ sys/arch/xen/conf/std.xen 15 May 2009 13:10:48 -0000 @@ -15,3 +15,6 @@ #options CRYPTO_MD_DES_CBC # machine-dependant DES CBC code #options CRYPTO_MD_BF_ENC # machine-dependant code for BF_encrypt #options CRYPTO_MD_BF_CBC # careful: uses bswapl, requires 486 + +# Atheros HAL options +include "external/isc/atheros_hal/conf/std.ath_hal" Index: sys/arch/amd64/conf/std.amd64 =================================================================== RCS file: /cvsroot/src/sys/arch/amd64/conf/std.amd64,v retrieving revision 1.6 diff -u -r1.6 std.amd64 --- sys/arch/amd64/conf/std.amd64 30 Apr 2008 22:08:18 -0000 1.6 +++ sys/arch/amd64/conf/std.amd64 15 May 2009 13:10:48 -0000 @@ -15,3 +15,5 @@ cpu* at mainbus? ioapic* at mainbus? apid ? +# Atheros HAL options +include "external/isc/atheros_hal/conf/std.ath_hal" Index: sys/arch/amd64/conf/std.xen =================================================================== RCS file: /cvsroot/src/sys/arch/amd64/conf/std.xen,v retrieving revision 1.3 diff -u -r1.3 std.xen --- sys/arch/amd64/conf/std.xen 25 Jan 2008 21:12:11 -0000 1.3 +++ sys/arch/amd64/conf/std.xen 15 May 2009 13:10:48 -0000 @@ -13,3 +13,6 @@ options EXEC_ELF64 # exec ELF binaries options EXEC_SCRIPT # exec #! scripts options MTRR + +# Atheros HAL options +include "external/isc/atheros_hal/conf/std.ath_hal" Index: sys/arch/evbmips/conf/std.adm5120 =================================================================== RCS file: /cvsroot/src/sys/arch/evbmips/conf/std.adm5120,v retrieving revision 1.1 diff -u -r1.1 std.adm5120 --- sys/arch/evbmips/conf/std.adm5120 20 Mar 2007 08:52:01 -0000 1.1 +++ sys/arch/evbmips/conf/std.adm5120 25 May 2009 19:39:27 -0000 @@ -16,3 +16,6 @@ include "arch/evbmips/conf/files.adm5120" include "arch/mips/conf/files.adm5120" + +# Atheros HAL options +include "external/isc/atheros_hal/conf/std.ath_hal" Index: sys/arch/evbmips/conf/std.alchemy =================================================================== RCS file: /cvsroot/src/sys/arch/evbmips/conf/std.alchemy,v retrieving revision 1.3 diff -u -r1.3 std.alchemy --- sys/arch/evbmips/conf/std.alchemy 28 Mar 2006 03:43:57 -0000 1.3 +++ sys/arch/evbmips/conf/std.alchemy 25 May 2009 19:39:27 -0000 @@ -15,3 +15,6 @@ include "arch/evbmips/conf/files.alchemy" include "arch/mips/conf/files.alchemy" + +# Atheros HAL options +include "external/isc/atheros_hal/conf/std.ath_hal" Index: sys/arch/evbmips/conf/std.atheros =================================================================== RCS file: /cvsroot/src/sys/arch/evbmips/conf/std.atheros,v retrieving revision 1.3 diff -u -r1.3 std.atheros --- sys/arch/evbmips/conf/std.atheros 26 Sep 2006 06:37:32 -0000 1.3 +++ sys/arch/evbmips/conf/std.atheros 25 May 2009 19:39:27 -0000 @@ -13,3 +13,6 @@ include "arch/evbmips/conf/files.atheros" include "arch/mips/conf/files.atheros" + +# Atheros HAL options +include "external/isc/atheros_hal/conf/std.ath_hal" Index: sys/arch/evbmips/conf/std.malta =================================================================== RCS file: /cvsroot/src/sys/arch/evbmips/conf/std.malta,v retrieving revision 1.5 diff -u -r1.5 std.malta --- sys/arch/evbmips/conf/std.malta 11 Dec 2005 12:17:11 -0000 1.5 +++ sys/arch/evbmips/conf/std.malta 25 May 2009 19:39:27 -0000 @@ -15,3 +15,6 @@ makeoptions BOARDTYPE="malta" include "arch/evbmips/conf/files.malta" + +# Atheros HAL options +include "external/isc/atheros_hal/conf/std.ath_hal" Index: sys/arch/evbmips/conf/std.meraki =================================================================== RCS file: /cvsroot/src/sys/arch/evbmips/conf/std.meraki,v retrieving revision 1.1 diff -u -r1.1 std.meraki --- sys/arch/evbmips/conf/std.meraki 26 Sep 2006 06:37:32 -0000 1.1 +++ sys/arch/evbmips/conf/std.meraki 25 May 2009 19:39:27 -0000 @@ -13,3 +13,6 @@ include "arch/evbmips/conf/files.atheros" include "arch/mips/conf/files.atheros" + +# Atheros HAL options +include "external/isc/atheros_hal/conf/std.ath_hal" Index: sys/arch/sparc64/conf/std.sparc64 =================================================================== RCS file: /cvsroot/src/sys/arch/sparc64/conf/std.sparc64,v retrieving revision 1.17 diff -u -r1.17 std.sparc64 --- sys/arch/sparc64/conf/std.sparc64 3 Feb 2008 13:27:12 -0000 1.17 +++ sys/arch/sparc64/conf/std.sparc64 25 May 2009 19:39:27 -0000 @@ -15,3 +15,6 @@ options EXEC_ELF64 # 64-bit NetBSD and SunOS 5 bins options CPU_IN_CKSUM # use optimized checksum method + +# Atheros HAL options +include "external/isc/atheros_hal/conf/std.ath_hal" Index: sys/arch/sparc64/conf/std.sparc64-32 =================================================================== RCS file: /cvsroot/src/sys/arch/sparc64/conf/std.sparc64-32,v retrieving revision 1.1 diff -u -r1.1 std.sparc64-32 --- sys/arch/sparc64/conf/std.sparc64-32 30 Jun 2006 10:27:48 -0000 1.1 +++ sys/arch/sparc64/conf/std.sparc64-32 25 May 2009 19:39:27 -0000 @@ -10,3 +10,6 @@ makeoptions LP64="no" no options EXEC_ELF64 + +# Atheros HAL options +include "external/isc/atheros_hal/conf/std.ath_hal" Index: sys/dev/ic/ath.c =================================================================== RCS file: /cvsroot/src/sys/dev/ic/ath.c,v retrieving revision 1.102 diff -u -r1.102 ath.c --- sys/dev/ic/ath.c 9 Jul 2008 19:47:24 -0000 1.102 +++ sys/dev/ic/ath.c 15 May 2009 13:10:50 -0000 @@ -1,4 +1,4 @@ -/* $NetBSD: ath.c,v 1.102 2008/07/09 19:47:24 joerg Exp $ */ +/* $NetBSD: ath.c,v 1.105 2008/12/11 06:04:01 alc Exp $ */ /*- * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting @@ -41,7 +41,7 @@ __FBSDID("$FreeBSD: src/sys/dev/ath/if_ath.c,v 1.104 2005/09/16 10:09:23 ru Exp $"); #endif #ifdef __NetBSD__ -__KERNEL_RCSID(0, "$NetBSD: ath.c,v 1.102 2008/07/09 19:47:24 joerg Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ath.c,v 1.105 2008/12/11 06:04:01 alc Exp $"); #endif /* @@ -96,9 +96,9 @@ #define AR_DEBUG #include -#include -#include /* XXX for softled */ -#include "athhal_options.h" +#include "ah_desc.h" +#include "ah_devid.h" /* XXX for softled */ +#include "opt_ah.h" #ifdef ATH_TX99_DIAG #include @@ -253,10 +253,10 @@ static void ath_printrxbuf(struct ath_buf *bf, int); static void ath_printtxbuf(struct ath_buf *bf, int); #else -#define IFF_DUMPPKTS(sc, m) \ +#define IFF_DUMPPKTS(sc, m) \ ((sc->sc_if.if_flags & (IFF_DEBUG|IFF_LINK2)) == (IFF_DEBUG|IFF_LINK2)) -#define DPRINTF(m, fmt, ...) -#define KEYPRINTF(sc, k, ix, mac) +#define DPRINTF(m, fmt, ...) +#define KEYPRINTF(sc, k, ix, mac) #endif MALLOC_DEFINE(M_ATHDEV, "athdev", "ath driver dma buffers"); @@ -371,7 +371,9 @@ } ATH_CALLOUT_INIT(&sc->sc_scan_ch, debug_mpsafenet ? CALLOUT_MPSAFE : 0); ATH_CALLOUT_INIT(&sc->sc_cal_ch, CALLOUT_MPSAFE); +#if 0 ATH_CALLOUT_INIT(&sc->sc_dfs_ch, CALLOUT_MPSAFE); +#endif ATH_TXBUF_LOCK_INIT(sc); @@ -518,13 +520,28 @@ * separate key cache entries are required to * handle both tx+rx MIC keys. */ - if (ath_hal_ciphersupported(ah, HAL_CIPHER_MIC)) + if (ath_hal_ciphersupported(ah, HAL_CIPHER_MIC)) { ic->ic_caps |= IEEE80211_C_TKIPMIC; - if (ath_hal_tkipsplit(ah)) + /* + * Check if h/w does MIC correctly when + * WMM is turned on. + */ + if (ath_hal_wmetkipmic(ah)) + ic->ic_caps |= IEEE80211_C_WME_TKIPMIC; + } + + /* + * If the h/w supports storing tx+rx MIC keys + * in one cache slot automatically enable use. + */ + if (ath_hal_tkipsplit(ah) || + !ath_hal_settkipsplit(ah, AH_FALSE)) sc->sc_splitmic = 1; } sc->sc_hasclrkey = ath_hal_ciphersupported(ah, HAL_CIPHER_CLR); +#if 0 sc->sc_mcastkey = ath_hal_getmcastkeysearch(ah); +#endif /* * TPC support can be done either with a global cap or * per-packet support. The latter is not available on @@ -661,6 +678,7 @@ void ath_suspend(struct ath_softc *sc) { +#if notyet /* * Set the chip in full sleep mode. Note that we are * careful to do this only when bringing the interface @@ -671,15 +689,22 @@ * issue with newer parts that go to sleep more quickly. */ ath_hal_setpower(sc->sc_ah, HAL_PM_FULL_SLEEP); +#endif } bool ath_resume(struct ath_softc *sc) { - int i; struct ath_hal *ah = sc->sc_ah; + struct ieee80211com *ic = &sc->sc_ic; + HAL_STATUS status; + int i; +#if notyet ath_hal_setpower(ah, HAL_PM_AWAKE); +#else + ath_hal_reset(ah, ic->ic_opmode, &sc->sc_curchan, AH_FALSE, &status); +#endif /* * Reset the key cache since some parts do not @@ -877,6 +902,7 @@ static void ath_radar_proc(void *arg, int pending) { +#if 0 struct ath_softc *sc = arg; struct ifnet *ifp = &sc->sc_if; struct ath_hal *ah = sc->sc_ah; @@ -890,6 +916,7 @@ */ /* XXX not yet */ } +#endif } static u_int @@ -946,6 +973,17 @@ */ ath_stop_locked(ifp, 0); + int dummy; /* XXX: gcc */ + /* Whether we should enable h/w TKIP MIC */ + if ((ic->ic_caps & IEEE80211_C_WME) && + ((ic->ic_caps & IEEE80211_C_WME_TKIPMIC) || + !(ic->ic_flags & IEEE80211_F_WME))) { + dummy = ath_hal_settkipmic(ah, AH_TRUE); + } else { + dummy = ath_hal_settkipmic(ah, AH_FALSE); + } + + /* * The basic interface to setting the hardware in a good * state is ``reset''. On return the hardware is known to @@ -1326,7 +1364,7 @@ * buffers to send all the fragments so all * go out or none... */ - if ((m->m_flags & M_FRAG) && + if ((m->m_flags & M_FRAG) && !ath_txfrag_setup(sc, &frags, m, ni)) { DPRINTF(sc, ATH_DEBUG_ANY, "%s: out of txfrag buffers\n", __func__); @@ -1450,21 +1488,36 @@ KASSERT(k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP, ("got a non-TKIP key, cipher %u", k->wk_cipher->ic_cipher)); - KASSERT(sc->sc_splitmic, ("key cache !split")); if ((k->wk_flags & IEEE80211_KEY_XR) == IEEE80211_KEY_XR) { - /* - * TX key goes at first index, RX key at the rx index. - * The hal handles the MIC keys at index+64. - */ - memcpy(hk->kv_mic, k->wk_txmic, sizeof(hk->kv_mic)); - KEYPRINTF(sc, k->wk_keyix, hk, zerobssid); - if (!ath_hal_keyset(ah, k->wk_keyix, hk, zerobssid)) - return 0; - - memcpy(hk->kv_mic, k->wk_rxmic, sizeof(hk->kv_mic)); - KEYPRINTF(sc, k->wk_keyix+32, hk, mac); - /* XXX delete tx key on failure? */ - return ath_hal_keyset(ah, k->wk_keyix+32, hk, mac); + if (sc->sc_splitmic) { + /* + * TX key goes at first index, RX key at the rx index. + * The hal handles the MIC keys at index+64. + */ + memcpy(hk->kv_mic, k->wk_txmic, sizeof(hk->kv_mic)); + KEYPRINTF(sc, k->wk_keyix, hk, zerobssid); + if (!ath_hal_keyset(ah, ATH_KEY(k->wk_keyix), hk, + zerobssid)) + return 0; + + memcpy(hk->kv_mic, k->wk_rxmic, sizeof(hk->kv_mic)); + KEYPRINTF(sc, k->wk_keyix+32, hk, mac); + /* XXX delete tx key on failure? */ + return ath_hal_keyset(ah, ATH_KEY(k->wk_keyix+32), + hk, mac); + } else { + /* + * Room for both TX+RX MIC keys in one key cache + * slot, just set key at the first index; the HAL + * will handle the reset. + */ + memcpy(hk->kv_mic, k->wk_rxmic, sizeof(hk->kv_mic)); +#if HAL_ABI_VERSION > 0x06052200 + memcpy(hk->kv_txmic, k->wk_txmic, sizeof(hk->kv_txmic)); +#endif + KEYPRINTF(sc, k->wk_keyix, hk, mac); + return ath_hal_keyset(ah, ATH_KEY(k->wk_keyix), hk, mac); + } } else if (k->wk_flags & IEEE80211_KEY_XR) { /* * TX/RX key goes at first index. @@ -1473,7 +1526,7 @@ memcpy(hk->kv_mic, k->wk_flags & IEEE80211_KEY_XMIT ? k->wk_txmic : k->wk_rxmic, sizeof(hk->kv_mic)); KEYPRINTF(sc, k->wk_keyix, hk, mac); - return ath_hal_keyset(ah, k->wk_keyix, hk, mac); + return ath_hal_keyset(ah, ATH_KEY(k->wk_keyix), hk, mac); } return 0; #undef IEEE80211_KEY_XR @@ -1532,13 +1585,12 @@ } else mac = mac0; - if (hk.kv_type == HAL_CIPHER_TKIP && - (k->wk_flags & IEEE80211_KEY_SWMIC) == 0 && - sc->sc_splitmic) { + if ((hk.kv_type == HAL_CIPHER_TKIP && + (k->wk_flags & IEEE80211_KEY_SWMIC) == 0) && sc->sc_splitmic) { return ath_keyset_tkip(sc, k, &hk, mac); } else { KEYPRINTF(sc, k->wk_keyix, &hk, mac); - return ath_hal_keyset(ah, k->wk_keyix, &hk, mac); + return ath_hal_keyset(ah, ATH_KEY(k->wk_keyix), &hk, mac); } #undef N } @@ -1590,11 +1642,11 @@ keyix+32, keyix+32+64); *txkeyix = keyix; *rxkeyix = keyix+32; - return 1; + return keyix; } } DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s: out of pair space\n", __func__); - return 0; + return IEEE80211_KEYIX_NONE; #undef N } @@ -1813,6 +1865,8 @@ if (ic->ic_opmode != IEEE80211_M_HOSTAP && (ifp->if_flags & IFF_PROMISC)) rfilt |= HAL_RX_FILTER_PROM; + if (ifp->if_flags & IFF_PROMISC) + rfilt |= HAL_RX_FILTER_CONTROL | HAL_RX_FILTER_PROBEREQ; if (ic->ic_opmode == IEEE80211_M_STA || ic->ic_opmode == IEEE80211_M_IBSS || state == IEEE80211_S_SCAN) @@ -2103,8 +2157,8 @@ , ds /* first descriptor */ ); - /* NB: The desc swap function becomes void, - * if descriptor swapping is not enabled + /* NB: The desc swap function becomes void, if descriptor swapping + * is not enabled */ ath_desc_swap(ds); @@ -2750,7 +2804,7 @@ ds = bf->bf_desc; ds->ds_link = HTOAH32(bf->bf_daddr); /* link to self */ ds->ds_data = bf->bf_segs[0].ds_addr; - ds->ds_vdata = mtod(m, void *); /* for radar */ + /* ds->ds_vdata = mtod(m, void *); for radar */ ath_hal_setuprxdesc(ah, ds , m->m_len /* buffer size */ , 0 @@ -2848,6 +2902,21 @@ } static void +ath_handle_micerror(struct ieee80211com *ic, + struct ieee80211_frame *wh, int keyix) +{ + struct ieee80211_node *ni; + + /* XXX recheck MIC to deal w/ chips that lie */ + /* XXX discard MIC errors on !data frames */ + ni = ieee80211_find_rxnode_withkey(ic, (const struct ieee80211_frame_min *) wh, keyix); + if (ni != NULL) { + ieee80211_notify_michael_failure(ic, wh, keyix); + ieee80211_free_node(ni); + } +} + +static void ath_rx_proc(void *arg, int npending) { #define PA2DESC(_sc, _pa) \ @@ -2862,14 +2931,23 @@ struct mbuf *m; struct ieee80211_node *ni; struct ath_node *an; - int len, type, ngood; + int len, ngood, type; u_int phyerr; HAL_STATUS status; int16_t nf; u_int64_t tsf; + uint8_t rxerr_tap, rxerr_mon; NET_LOCK_GIANT(); /* XXX */ + rxerr_tap = + (ifp->if_flags & IFF_PROMISC) ? HAL_RXERR_CRC|HAL_RXERR_PHY : 0; + + if (sc->sc_ic.ic_opmode == IEEE80211_M_MONITOR) + rxerr_mon = HAL_RXERR_DECRYPT|HAL_RXERR_MIC; + else if (ifp->if_flags & IFF_PROMISC) + rxerr_tap |= HAL_RXERR_DECRYPT|HAL_RXERR_MIC; + DPRINTF(sc, ATH_DEBUG_RX_PROC, "%s: pending %u\n", __func__, npending); ngood = 0; nf = ath_hal_getchannoise(ah, &sc->sc_curchan); @@ -2903,7 +2981,8 @@ * a self-linked list to avoid rx overruns. */ status = ath_hal_rxprocdesc(ah, ds, - bf->bf_daddr, PA2DESC(sc, ds->ds_link)); + bf->bf_daddr, PA2DESC(sc, ds->ds_link), + tsf, &ds->ds_rxstat); #ifdef AR_DEBUG if (sc->sc_debug & ATH_DEBUG_RECV_DESC) ath_printrxbuf(bf, status == HAL_OK); @@ -2962,12 +3041,10 @@ bf->bf_dmamap, 0, bf->bf_dmamap->dm_mapsize, BUS_DMASYNC_POSTREAD); - ieee80211_notify_michael_failure(ic, + ath_handle_micerror(ic, mtod(m, struct ieee80211_frame *), sc->sc_splitmic ? - ds->ds_rxstat.rs_keyix-32 : - ds->ds_rxstat.rs_keyix - ); + ds->ds_rxstat.rs_keyix-32 : ds->ds_rxstat.rs_keyix); } } ifp->if_ierrors++; @@ -2976,9 +3053,8 @@ * to see them in monitor mode (in monitor mode * allow through packets that have crypto problems). */ - if ((ds->ds_rxstat.rs_status &~ - (HAL_RXERR_DECRYPT|HAL_RXERR_MIC)) || - sc->sc_ic.ic_opmode != IEEE80211_M_MONITOR) + + if (ds->ds_rxstat.rs_status &~ (rxerr_tap|rxerr_mon)) goto rx_next; } rx_accept: @@ -3020,6 +3096,11 @@ sc->sc_rx_th.wr_tsf = htole64( ath_extend_tsf(ds->ds_rxstat.rs_tstamp, tsf)); sc->sc_rx_th.wr_flags = sc->sc_hwmap[rix].rxflags; + if (ds->ds_rxstat.rs_status & + (HAL_RXERR_CRC|HAL_RXERR_PHY)) { + sc->sc_rx_th.wr_flags |= + IEEE80211_RADIOTAP_F_BADFCS; + } sc->sc_rx_th.wr_rate = sc->sc_hwmap[rix].ieeerate; sc->sc_rx_th.wr_antsignal = ds->ds_rxstat.rs_rssi + nf; sc->sc_rx_th.wr_antnoise = nf; @@ -3030,6 +3111,10 @@ } #endif + if (ds->ds_rxstat.rs_status & rxerr_tap) { + m_freem(m); + goto rx_next; + } /* * From this point on we assume the frame is at least * as large as ieee80211_frame_min; verify that. @@ -3111,8 +3196,10 @@ /* rx signal state monitoring */ ath_hal_rxmonitor(ah, &sc->sc_halstats, &sc->sc_curchan); +#if 0 if (ath_hal_radar_event(ah)) TASK_RUN_OR_ENQUEUE(&sc->sc_radartask); +#endif if (ngood) sc->sc_lastrx = tsf; @@ -3715,7 +3802,7 @@ */ dur += ath_hal_computetxtime(ah, rt, deduct_pad_bytes(m0->m_nextpkt->m_pkthdr.len, - hdrlen) - + hdrlen) - deduct_pad_bytes(m0->m_pkthdr.len, hdrlen) + pktlen, rix, shortPreamble); } @@ -3866,7 +3953,7 @@ , ds0 /* first descriptor */ ); - /* NB: The desc swap function becomes void, + /* NB: The desc swap function becomes void, * if descriptor swapping is not enabled */ ath_desc_swap(ds); @@ -3938,11 +4025,9 @@ } ds0 = &bf->bf_desc[0]; ds = &bf->bf_desc[bf->bf_nseg - 1]; - status = ath_hal_txprocdesc(ah, ds); -#ifdef AR_DEBUG + status = ath_hal_txprocdesc(ah, ds, &ds->ds_txstat); if (sc->sc_debug & ATH_DEBUG_XMIT_DESC) ath_printtxbuf(bf, status == HAL_OK); -#endif if (status == HAL_EINPROGRESS) { ATH_TXQ_UNLOCK(txq); break; @@ -4114,6 +4199,7 @@ struct ath_hal *ah = sc->sc_ah; struct ieee80211_node *ni; struct ath_buf *bf; + struct ath_desc *ds; /* * NB: this assumes output has been stopped and @@ -4129,11 +4215,11 @@ } ATH_TXQ_REMOVE_HEAD(txq, bf_list); ATH_TXQ_UNLOCK(txq); -#ifdef AR_DEBUG + ds = &bf->bf_desc[bf->bf_nseg - 1]; if (sc->sc_debug & ATH_DEBUG_RESET) ath_printtxbuf(bf, - ath_hal_txprocdesc(ah, bf->bf_desc) == HAL_OK); -#endif /* AR_DEBUG */ + ath_hal_txprocdesc(ah, bf->bf_desc, + &ds->ds_txstat) == HAL_OK); bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap); m_freem(bf->bf_m); bf->bf_m = NULL; @@ -4199,12 +4285,12 @@ ((struct ath_desc *)((char *)(_sc)->sc_rxdma.dd_desc + \ ((_pa) - (_sc)->sc_rxdma.dd_desc_paddr))) struct ath_hal *ah = sc->sc_ah; + u_int64_t tsf; ath_hal_stoppcurecv(ah); /* disable PCU */ ath_hal_setrxfilter(ah, 0); /* clear recv filter */ ath_hal_stopdmarecv(ah); /* disable DMA engine */ DELAY(3000); /* 3ms is long enough for 1 frame */ -#ifdef AR_DEBUG if (sc->sc_debug & (ATH_DEBUG_RESET | ATH_DEBUG_FATAL)) { struct ath_buf *bf; @@ -4212,13 +4298,14 @@ (void *)(uintptr_t) ath_hal_getrxbuf(ah), sc->sc_rxlink); STAILQ_FOREACH(bf, &sc->sc_rxbuf, bf_list) { struct ath_desc *ds = bf->bf_desc; + tsf = ath_hal_gettsf64(sc->sc_ah); HAL_STATUS status = ath_hal_rxprocdesc(ah, ds, - bf->bf_daddr, PA2DESC(sc, ds->ds_link)); + bf->bf_daddr, PA2DESC(sc, ds->ds_link), + tsf, &ds->ds_rxstat); if (status == HAL_OK || (sc->sc_debug & ATH_DEBUG_FATAL)) ath_printrxbuf(bf, status == HAL_OK); } } -#endif sc->sc_rxlink = NULL; /* just in case */ #undef PA2DESC } @@ -4288,6 +4375,7 @@ htole16(flags); } +#if 0 /* * Poll for a channel clear indication; this is required * for channels requiring DFS and not previously visited @@ -4320,6 +4408,7 @@ } else callout_reset(&sc->sc_dfs_ch, 2 * hz, ath_dfswait, sc); } +#endif /* * Set/change channels. If the channel is really being changed, @@ -4392,6 +4481,7 @@ ic->ic_ibss_chan = chan; ath_chan_change(sc, chan); +#if 0 /* * Handle DFS required waiting period to determine * if channel is clear of radar traffic. @@ -4410,6 +4500,7 @@ callout_stop(&sc->sc_dfs_ch); #undef DFS_NOT_CLEAR } +#endif /* * Re-enable interrupts. @@ -4520,7 +4611,9 @@ callout_stop(&sc->sc_scan_ch); callout_stop(&sc->sc_cal_ch); +#if 0 callout_stop(&sc->sc_dfs_ch); +#endif ath_hal_setledstate(ah, leds[nstate]); /* set LED */ if (nstate == IEEE80211_S_INIT) { @@ -5036,7 +5129,7 @@ !done ? ' ' : (ds->ds_txstat.ts_status == 0) ? '*' : '!'); } } -#endif /* AR_DEBUG */ +#endif /* AR_DEBUG */ static void ath_watchdog(struct ifnet *ifp) @@ -5148,6 +5241,8 @@ ATH_LOCK(sc); switch (cmd) { case SIOCSIFFLAGS: + if ((error = ifioctl_common(ifp, cmd, data)) != 0) + break; if (IS_RUNNING(ifp)) { /* * To avoid rescanning another access point, Index: sys/dev/ic/athrate-amrr.c =================================================================== RCS file: /cvsroot/src/sys/dev/ic/athrate-amrr.c,v retrieving revision 1.10 diff -u -r1.10 athrate-amrr.c --- sys/dev/ic/athrate-amrr.c 4 Jan 2008 21:17:56 -0000 1.10 +++ sys/dev/ic/athrate-amrr.c 15 May 2009 13:10:51 -0000 @@ -1,4 +1,4 @@ -/* $NetBSD: athrate-amrr.c,v 1.10 2008/01/04 21:17:56 ad Exp $ */ +/* $NetBSD: athrate-amrr.c,v 1.11 2008/12/11 05:45:29 alc Exp $ */ /*- * Copyright (c) 2004 INRIA @@ -43,7 +43,7 @@ __FBSDID("$FreeBSD: src/sys/dev/ath/ath_rate/amrr/amrr.c,v 1.10 2005/08/09 10:19:43 rwatson Exp $"); #endif #ifdef __NetBSD__ -__KERNEL_RCSID(0, "$NetBSD: athrate-amrr.c,v 1.10 2008/01/04 21:17:56 ad Exp $"); +__KERNEL_RCSID(0, "$NetBSD: athrate-amrr.c,v 1.11 2008/12/11 05:45:29 alc Exp $"); #endif /* @@ -77,7 +77,8 @@ #include #include -#include + +#include #define AMRR_DEBUG #ifdef AMRR_DEBUG Index: sys/dev/ic/athrate-onoe.c =================================================================== RCS file: /cvsroot/src/sys/dev/ic/athrate-onoe.c,v retrieving revision 1.12 diff -u -r1.12 athrate-onoe.c --- sys/dev/ic/athrate-onoe.c 4 Jan 2008 21:17:57 -0000 1.12 +++ sys/dev/ic/athrate-onoe.c 15 May 2009 13:10:51 -0000 @@ -1,4 +1,4 @@ -/* $NetBSD: athrate-onoe.c,v 1.12 2008/01/04 21:17:57 ad Exp $ */ +/* $NetBSD: athrate-onoe.c,v 1.13 2008/12/11 05:45:29 alc Exp $ */ /*- * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting @@ -41,7 +41,7 @@ __FBSDID("$FreeBSD: src/sys/dev/ath/ath_rate/onoe/onoe.c,v 1.10 2005/08/09 10:19:43 rwatson Exp $"); #endif #ifdef __NetBSD__ -__KERNEL_RCSID(0, "$NetBSD: athrate-onoe.c,v 1.12 2008/01/04 21:17:57 ad Exp $"); +__KERNEL_RCSID(0, "$NetBSD: athrate-onoe.c,v 1.13 2008/12/11 05:45:29 alc Exp $"); #endif /* @@ -74,7 +74,8 @@ #include #include #include -#include + +#include #define ONOE_DEBUG #ifdef ONOE_DEBUG Index: sys/dev/ic/athrate-sample.c =================================================================== RCS file: /cvsroot/src/sys/dev/ic/athrate-sample.c,v retrieving revision 1.16 diff -u -r1.16 athrate-sample.c --- sys/dev/ic/athrate-sample.c 9 Jul 2008 19:47:24 -0000 1.16 +++ sys/dev/ic/athrate-sample.c 15 May 2009 13:10:51 -0000 @@ -1,4 +1,4 @@ -/* $NetBSD: athrate-sample.c,v 1.16 2008/07/09 19:47:24 joerg Exp $ */ +/* $NetBSD: athrate-sample.c,v 1.17 2008/12/11 05:45:29 alc Exp $ */ /*- * Copyright (c) 2005 John Bicket @@ -41,7 +41,7 @@ __FBSDID("$FreeBSD: src/sys/dev/ath/ath_rate/sample/sample.c,v 1.9 2005/07/22 16:50:17 sam Exp $"); #endif #ifdef __NetBSD__ -__KERNEL_RCSID(0, "$NetBSD: athrate-sample.c,v 1.16 2008/07/09 19:47:24 joerg Exp $"); +__KERNEL_RCSID(0, "$NetBSD: athrate-sample.c,v 1.17 2008/12/11 05:45:29 alc Exp $"); #endif @@ -74,9 +74,9 @@ #include #endif +#include "ah_desc.h" #include #include -#include #define SAMPLE_DEBUG #ifdef SAMPLE_DEBUG Index: sys/dev/ic/athvar.h =================================================================== RCS file: /cvsroot/src/sys/dev/ic/athvar.h,v retrieving revision 1.25 diff -u -r1.25 athvar.h --- sys/dev/ic/athvar.h 9 Jul 2008 19:47:24 -0000 1.25 +++ sys/dev/ic/athvar.h 15 May 2009 13:10:51 -0000 @@ -1,4 +1,4 @@ -/* $NetBSD: athvar.h,v 1.25 2008/07/09 19:47:24 joerg Exp $ */ +/* $NetBSD: athvar.h,v 1.26 2008/12/11 05:45:29 alc Exp $ */ /*- * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting @@ -44,9 +44,11 @@ #ifndef _DEV_ATH_ATHVAR_H #define _DEV_ATH_ATHVAR_H -#include -#include #include + +#include + +#include #include #include @@ -77,6 +79,12 @@ */ #define ATH_KEYMAX 128 /* max key cache size we handle */ #define ATH_KEYBYTES (ATH_KEYMAX/NBBY) /* storage space in bytes */ +/* + * Convert from net80211 layer values to Ath layer values. Hopefully this will + * be optimised away when the two constants are the same. + */ +typedef unsigned int ath_keyix_t; +#define ATH_KEY(_keyix) ((_keyix == IEEE80211_KEYIX_NONE) ? HAL_TXKEYIX_INVALID : _keyix) /* driver-specific node state */ struct ath_node { @@ -454,6 +462,12 @@ (*(_pcc) = (_ah)->ah_countryCode) #define ath_hal_tkipsplit(_ah) \ (ath_hal_getcapability(_ah, HAL_CAP_TKIP_SPLIT, 0, NULL) == HAL_OK) +#define ath_hal_settkipmic(_ah, _v) \ + (ath_hal_setcapability(_ah, HAL_CAP_TKIP_MIC, 1, _v, NULL) == HAL_OK) +#define ath_hal_settkipsplit(_ah, _v) \ + (ath_hal_setcapability(_ah, HAL_CAP_TKIP_SPLIT, 1, _v, NULL) == HAL_OK) +#define ath_hal_wmetkipmic(_ah) \ + (ath_hal_getcapability(_ah, HAL_CAP_WME_TKIPMIC, 0, NULL) == HAL_OK) #define ath_hal_hwphycounters(_ah) \ (ath_hal_getcapability(_ah, HAL_CAP_PHYCOUNTERS, 0, NULL) == HAL_OK) #define ath_hal_hasdiversity(_ah) \ @@ -528,8 +542,8 @@ #define ath_hal_setuprxdesc(_ah, _ds, _size, _intreq) \ ((*(_ah)->ah_setupRxDesc)((_ah), (_ds), (_size), (_intreq))) -#define ath_hal_rxprocdesc(_ah, _ds, _dspa, _dsnext) \ - ((*(_ah)->ah_procRxDesc)((_ah), (_ds), (_dspa), (_dsnext), 0)) +#define ath_hal_rxprocdesc(_ah, _ds, _dspa, _dsnext, tsf, a5) \ + ((*(_ah)->ah_procRxDesc)((_ah), (_ds), (_dspa), (_dsnext), (tsf), (a5))) #define ath_hal_setuptxdesc(_ah, _ds, _plen, _hlen, _atype, _txpow, \ _txr0, _txtr0, _keyix, _ant, _flags, \ _rtsrate, _rtsdura) \ @@ -542,8 +556,8 @@ (_txr1), (_txtr1), (_txr2), (_txtr2), (_txr3), (_txtr3))) #define ath_hal_filltxdesc(_ah, _ds, _l, _first, _last, _ds0) \ ((*(_ah)->ah_fillTxDesc)((_ah), (_ds), (_l), (_first), (_last), (_ds0))) -#define ath_hal_txprocdesc(_ah, _ds) \ - ((*(_ah)->ah_procTxDesc)((_ah), (_ds))) +#define ath_hal_txprocdesc(_ah, _ds, _a2) \ + ((*(_ah)->ah_procTxDesc)((_ah), (_ds), (_a2))) #define ath_hal_gettxintrtxqs(_ah, _txqs) \ ((*(_ah)->ah_getTxIntrQueue)((_ah), (_txqs))) @@ -558,7 +572,5 @@ ((*(_ah)->ah_processDfs)((_ah), (_chan))) #define ath_hal_checknol(_ah, _chan, _nchans) \ ((*(_ah)->ah_dfsNolCheck)((_ah), (_chan), (_nchans))) -#define ath_hal_radar_wait(_ah, _chan) \ - ((*(_ah)->ah_radarWait)((_ah), (_chan))) #endif /* _DEV_ATH_ATHVAR_H */ --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/conf/files.ath_hal 2009-03-23 17:36:55.000000000 +0000 @@ -0,0 +1,138 @@ +# $NetBSD: files.ath_hal,v 1.1 2008/12/11 14:11:43 alc Exp $ + +defflag opt_athhal.h ATHHAL_ASSERT ATHHAL_DEBUG ATHHAL_DEBUG_ALQ +defflag opt_athhal.h ATHHAL_WRITE_EEPROM ATHHAL_WRITE_REGDOMAIN + +define athhal_eeprom_v1 +define athhal_eeprom_v3 +define athhal_eeprom_v14 + +file external/isc/atheros_hal/dist/ah.c ath +file external/isc/atheros_hal/dist/ah_eeprom_v1.c ath & athhal_eeprom_v1 +file external/isc/atheros_hal/dist/ah_eeprom_v3.c ath & athhal_eeprom_v3 +file external/isc/atheros_hal/dist/ah_eeprom_v14.c ath & athhal_eeprom_v14 +file external/isc/atheros_hal/dist/ah_regdomain.c ath + +# Atheros HAL's OS dependant code +# +file external/isc/atheros_hal/ic/ah_osdep.c ath + + +# Atheros AR5210 family +# +defflag opt_athhal.h ATHHAL_AR5210: athhal_eeprom_v1 + +file external/isc/atheros_hal/dist/ar5210/ar5210_attach.c ath & athhal_ar5210 +file external/isc/atheros_hal/dist/ar5210/ar5210_beacon.c ath & athhal_ar5210 +file external/isc/atheros_hal/dist/ar5210/ar5210_interrupts.c ath & athhal_ar5210 +file external/isc/atheros_hal/dist/ar5210/ar5210_keycache.c ath & athhal_ar5210 +file external/isc/atheros_hal/dist/ar5210/ar5210_misc.c ath & athhal_ar5210 +file external/isc/atheros_hal/dist/ar5210/ar5210_phy.c ath & athhal_ar5210 +file external/isc/atheros_hal/dist/ar5210/ar5210_power.c ath & athhal_ar5210 +file external/isc/atheros_hal/dist/ar5210/ar5210_recv.c ath & athhal_ar5210 +file external/isc/atheros_hal/dist/ar5210/ar5210_reset.c ath & athhal_ar5210 +file external/isc/atheros_hal/dist/ar5210/ar5210_xmit.c ath & athhal_ar5210 + +# Atheros AR5211 family +# +defflag opt_athhal.h ATHHAL_AR5211: athhal_eeprom_v3 + +file external/isc/atheros_hal/dist/ar5211/ar5211_attach.c ath & athhal_ar5211 +file external/isc/atheros_hal/dist/ar5211/ar5211_beacon.c ath & athhal_ar5211 +file external/isc/atheros_hal/dist/ar5211/ar5211_interrupts.c ath & athhal_ar5211 +file external/isc/atheros_hal/dist/ar5211/ar5211_keycache.c ath & athhal_ar5211 +file external/isc/atheros_hal/dist/ar5211/ar5211_misc.c ath & athhal_ar5211 +file external/isc/atheros_hal/dist/ar5211/ar5211_phy.c ath & athhal_ar5211 +file external/isc/atheros_hal/dist/ar5211/ar5211_power.c ath & athhal_ar5211 +file external/isc/atheros_hal/dist/ar5211/ar5211_recv.c ath & athhal_ar5211 +file external/isc/atheros_hal/dist/ar5211/ar5211_reset.c ath & athhal_ar5211 +file external/isc/atheros_hal/dist/ar5211/ar5211_xmit.c ath & athhal_ar5211 + +# Atheros AR5212/AR5312 RF support +# +defflag opt_athhal.h ATHHAL_RF2316 +defflag opt_athhal.h ATHHAL_RF2317 +defflag opt_athhal.h ATHHAL_RF2413 +defflag opt_athhal.h ATHHAL_RF2425 +defflag opt_athhal.h ATHHAL_RF5111 +defflag opt_athhal.h ATHHAL_RF5112 +defflag opt_athhal.h ATHHAL_RF5413 + +file external/isc/atheros_hal/dist/ar5212/ar2316.c ath & athhal_rf2316 +file external/isc/atheros_hal/dist/ar5212/ar2317.c ath & athhal_rf2317 +file external/isc/atheros_hal/dist/ar5212/ar2413.c ath & athhal_rf2413 +file external/isc/atheros_hal/dist/ar5212/ar2425.c ath & athhal_rf2425 +file external/isc/atheros_hal/dist/ar5212/ar5111.c ath & athhal_rf5111 +file external/isc/atheros_hal/dist/ar5212/ar5112.c ath & athhal_rf5112 +file external/isc/atheros_hal/dist/ar5212/ar5413.c ath & athhal_rf5413 + +# Atheros AR5212 family +# +define athhal_ar5212_attach +define athhal_ar5212_subr + +defflag opt_athhal.h ATHHAL_AR5212: athhal_eeprom_v3, + athhal_ar5212_attach, athhal_ar5212_subr + +defflag opt_athhal.h ATHHAL_AR5311: ATHHAL_AR5212 + +file external/isc/atheros_hal/dist/ar5212/ar5212_ani.c ath & athhal_ar5212_subr +file external/isc/atheros_hal/dist/ar5212/ar5212_attach.c ath & athhal_ar5212_attach +file external/isc/atheros_hal/dist/ar5212/ar5212_beacon.c ath & athhal_ar5212_subr +file external/isc/atheros_hal/dist/ar5212/ar5212_eeprom.c ath & athhal_ar5212_subr +file external/isc/atheros_hal/dist/ar5212/ar5212_gpio.c ath & athhal_ar5212_subr +file external/isc/atheros_hal/dist/ar5212/ar5212_interrupts.c ath & athhal_ar5212_subr +file external/isc/atheros_hal/dist/ar5212/ar5212_keycache.c ath & athhal_ar5212_subr +file external/isc/atheros_hal/dist/ar5212/ar5212_misc.c ath & athhal_ar5212_subr +file external/isc/atheros_hal/dist/ar5212/ar5212_phy.c ath & athhal_ar5212_subr +file external/isc/atheros_hal/dist/ar5212/ar5212_power.c ath & athhal_ar5212_subr +file external/isc/atheros_hal/dist/ar5212/ar5212_recv.c ath & athhal_ar5212_subr +file external/isc/atheros_hal/dist/ar5212/ar5212_reset.c ath & athhal_ar5212_subr +file external/isc/atheros_hal/dist/ar5212/ar5212_rfgain.c ath & athhal_ar5212_subr +file external/isc/atheros_hal/dist/ar5212/ar5212_xmit.c ath & athhal_ar5212_subr + +# Atheros AR5312 family +# +defflag opt_athhal.h ATHHAL_AR5312: athhal_eeprom_v3, athhal_ar5212_subr + +defflag opt_athhal.h ATHHAL_AR2316: ATHHAL_AR5312 +defflag opt_athhal.h ATHHAL_AR2317: ATHHAL_AR5312 + +file external/isc/atheros_hal/dist/ar5312/ar5312_attach.c ath & athhal_ar5312 +file external/isc/atheros_hal/dist/ar5312/ar5312_eeprom.c ath & athhal_ar5312 +file external/isc/atheros_hal/dist/ar5312/ar5312_gpio.c ath & athhal_ar5312 +file external/isc/atheros_hal/dist/ar5312/ar5312_interrupts.c ath & athhal_ar5312 +file external/isc/atheros_hal/dist/ar5312/ar5312_misc.c ath & athhal_ar5312 +file external/isc/atheros_hal/dist/ar5312/ar5312_power.c ath & athhal_ar5312 +file external/isc/atheros_hal/dist/ar5312/ar5312_reset.c ath & athhal_ar5312 +file external/isc/atheros_hal/dist/ar5312/ar5315_gpio.c ath & (athhal_ar2316 | athhal_ar2317) + +# Atheros AR5416 family +# +defflag opt_athhal.h ATHHAL_AR5416: athhal_eeprom_v14, athhal_ar5212_subr +defflag opt_athhal.h ATHHAL_AR9280: ATHHAL_AR5416 + +file external/isc/atheros_hal/dist/ar5416/ar2133.c ath & athhal_ar5416 +file external/isc/atheros_hal/dist/ar5416/ar5416_ani.c ath & athhal_ar5416 +file external/isc/atheros_hal/dist/ar5416/ar5416_attach.c ath & athhal_ar5416 +file external/isc/atheros_hal/dist/ar5416/ar5416_beacon.c ath & athhal_ar5416 +file external/isc/atheros_hal/dist/ar5416/ar5416_cal.c ath & athhal_ar5416 +file external/isc/atheros_hal/dist/ar5416/ar5416_cal_adcdc.c ath & athhal_ar5416 +file external/isc/atheros_hal/dist/ar5416/ar5416_cal_adcgain.c ath & athhal_ar5416 +file external/isc/atheros_hal/dist/ar5416/ar5416_cal_iq.c ath & athhal_ar5416 +file external/isc/atheros_hal/dist/ar5416/ar5416_eeprom.c ath & athhal_ar5416 +file external/isc/atheros_hal/dist/ar5416/ar5416_gpio.c ath & athhal_ar5416 +file external/isc/atheros_hal/dist/ar5416/ar5416_interrupts.c ath & athhal_ar5416 +file external/isc/atheros_hal/dist/ar5416/ar5416_keycache.c ath & athhal_ar5416 +file external/isc/atheros_hal/dist/ar5416/ar5416_misc.c ath & athhal_ar5416 +file external/isc/atheros_hal/dist/ar5416/ar5416_phy.c ath & athhal_ar5416 +file external/isc/atheros_hal/dist/ar5416/ar5416_power.c ath & athhal_ar5416 +file external/isc/atheros_hal/dist/ar5416/ar5416_recv.c ath & athhal_ar5416 +file external/isc/atheros_hal/dist/ar5416/ar5416_reset.c ath & athhal_ar5416 +file external/isc/atheros_hal/dist/ar5416/ar5416_xmit.c ath & athhal_ar5416 +file external/isc/atheros_hal/dist/ar5416/ar9160_attach.c ath & athhal_ar5416 + +# +# +makeoptions ath CPPFLAGS+="-I${S}/external/isc/atheros_hal/dist" +makeoptions ath CPPFLAGS+="-I${S}/external/isc/atheros_hal/ic" --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/conf/std.ath_hal 2009-03-23 17:36:55.000000000 +0000 @@ -0,0 +1,25 @@ +#options ATHHAL_ASSERT +#options ATHHAL_DEBUG +#options ATHHAL_DEBUG_ALQ + +# Atheros HAL Chipset Support +# +options ATHHAL_AR5210 +options ATHHAL_AR5211 +options ATHHAL_AR5212 +options ATHHAL_AR5311 +#options ATHHAL_AR5312 +#options ATHHAL_AR2316 +#options ATHHAL_AR2317 +options ATHHAL_AR5416 +#options ATHHAL_AR9280 + +# Atheros AR5212/AR5312 RF Support +# +options ATHHAL_RF2316 +options ATHHAL_RF2317 +options ATHHAL_RF2413 +options ATHHAL_RF2425 +options ATHHAL_RF5111 +options ATHHAL_RF5112 +options ATHHAL_RF5413 --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5211/ar5211.h 2009-03-23 17:36:55.000000000 +0000 @@ -0,0 +1,308 @@ +/* + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2006 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ar5211.h,v 1.1 2009/03/23 17:14:47 sborrill Exp $ + */ +#ifndef _ATH_AR5211_H_ +#define _ATH_AR5211_H_ + +#include "ah_eeprom.h" + +#define AR5211_MAGIC 0x19570405 + +/* Classes for WME streams */ +#define AC_BK 0 +#define AC_BE 1 +#define AC_VI 2 +#define AC_VO 3 + +/* DCU Transmit Filter macros */ +#define CALC_MMR(dcu, idx) \ + ( (4 * dcu) + (idx < 32 ? 0 : (idx < 64 ? 1 : (idx < 96 ? 2 : 3))) ) +#define TXBLK_FROM_MMR(mmr) \ + (AR_D_TXBLK_BASE + ((mmr & 0x1f) << 6) + ((mmr & 0x20) >> 3)) +#define CALC_TXBLK_ADDR(dcu, idx) (TXBLK_FROM_MMR(CALC_MMR(dcu, idx))) +#define CALC_TXBLK_VALUE(idx) (1 << (idx & 0x1f)) + +/* MAC register values */ + +#define INIT_INTERRUPT_MASK \ + ( AR_IMR_TXERR | AR_IMR_TXOK | AR_IMR_RXORN | \ + AR_IMR_RXERR | AR_IMR_RXOK | AR_IMR_TXURN | \ + AR_IMR_HIUERR ) +#define INIT_BEACON_CONTROL \ + ( (INIT_RESET_TSF << 24) | (INIT_BEACON_EN << 23) | \ + (INIT_TIM_OFFSET << 16) | INIT_BEACON_PERIOD ) + +#define INIT_CONFIG_STATUS 0x00000000 +#define INIT_RSSI_THR 0x00000700 /* Missed beacon counter initialized to 0x7 (max is 0xff) */ +#define INIT_IQCAL_LOG_COUNT_MAX 0xF +#define INIT_BCON_CNTRL_REG 0x00000000 + +#define INIT_BEACON_PERIOD 0xffff +#define INIT_TIM_OFFSET 0 +#define INIT_BEACON_EN 0 /* this should be set by AP only when it's ready */ +#define INIT_RESET_TSF 0 + +/* + * Various fifo fill before Tx start, in 64-byte units + * i.e. put the frame in the air while still DMAing + */ +#define MIN_TX_FIFO_THRESHOLD 0x1 +#define MAX_TX_FIFO_THRESHOLD ((IEEE80211_MAX_LEN / 64) + 1) +#define INIT_TX_FIFO_THRESHOLD MIN_TX_FIFO_THRESHOLD + +/* + * Gain support. + */ +typedef struct _gainOptStep { + int16_t paramVal[4]; + int32_t stepGain; + int8_t stepName[16]; +} GAIN_OPTIMIZATION_STEP; + +typedef struct { + uint32_t numStepsInLadder; + uint32_t defaultStepNum; + GAIN_OPTIMIZATION_STEP optStep[10]; +} GAIN_OPTIMIZATION_LADDER; + +typedef struct { + uint32_t currStepNum; + uint32_t currGain; + uint32_t targetGain; + uint32_t loTrig; + uint32_t hiTrig; + uint32_t active; + const GAIN_OPTIMIZATION_STEP *currStep; +} GAIN_VALUES; + +enum { + RFGAIN_INACTIVE, + RFGAIN_READ_REQUESTED, + RFGAIN_NEED_CHANGE +}; + +/* + * Header Info - general parameters and + * values set for each chipset board solution + * that are programmed every reset + */ +struct ath_hal_5211 { + struct ath_hal_private ah_priv; /* base class */ + + GAIN_VALUES ah_gainValues; + + uint8_t ah_macaddr[IEEE80211_ADDR_LEN]; + uint8_t ah_bssid[IEEE80211_ADDR_LEN]; + + /* + * Runtime state. + */ + uint32_t ah_maskReg; /* copy of AR_IMR */ + uint32_t ah_txOkInterruptMask; + uint32_t ah_txErrInterruptMask; + uint32_t ah_txDescInterruptMask; + uint32_t ah_txEolInterruptMask; + uint32_t ah_txUrnInterruptMask; + HAL_TX_QUEUE_INFO ah_txq[HAL_NUM_TX_QUEUES]; + HAL_POWER_MODE ah_powerMode; + HAL_ANT_SETTING ah_diversityControl; /* antenna setting */ + uint32_t ah_calibrationTime; + HAL_BOOL ah_bIQCalibration; + HAL_CHANNEL ah_curchan; /* XXX */ + int ah_rfgainState; + uint32_t ah_tx6PowerInHalfDbm; /* power output for 6Mb tx */ + uint32_t ah_staId1Defaults; /* STA_ID1 default settings */ + uint32_t ah_beaconInterval; + uint32_t ah_rssiThr; /* RSSI_THR settings */ + + u_int ah_sifstime; /* user-specified sifs time */ + u_int ah_slottime; /* user-specified slot time */ + u_int ah_acktimeout; /* user-specified ack timeout */ + u_int ah_ctstimeout; /* user-specified cts timeout */ + /* + * RF Silent handling. + */ + uint32_t ah_gpioSelect; /* GPIO pin to use */ + uint32_t ah_polarity; /* polarity to disable RF */ + uint32_t ah_gpioBit; /* after init, prev value */ +}; +#define AH5211(ah) ((struct ath_hal_5211 *)(ah)) + +struct ath_hal; + +extern struct ath_hal *ar5211Attach(uint16_t, HAL_SOFTC, + HAL_BUS_TAG, HAL_BUS_HANDLE, HAL_STATUS *); +extern void ar5211Detach(struct ath_hal *); + +extern HAL_BOOL ar5211Reset(struct ath_hal *, HAL_OPMODE, + HAL_CHANNEL *, HAL_BOOL bChannelChange, HAL_STATUS *); +extern HAL_BOOL ar5211PhyDisable(struct ath_hal *); +extern HAL_BOOL ar5211Disable(struct ath_hal *); +extern HAL_BOOL ar5211ChipReset(struct ath_hal *, uint16_t); +extern HAL_BOOL ar5211PerCalibration(struct ath_hal *, HAL_CHANNEL *, HAL_BOOL *); +extern HAL_BOOL ar5211PerCalibrationN(struct ath_hal *ah, HAL_CHANNEL *chan, + u_int chainMask, HAL_BOOL longCal, HAL_BOOL *isCalDone); +extern HAL_BOOL ar5211ResetCalValid(struct ath_hal *ah, HAL_CHANNEL *chan); +extern HAL_BOOL ar5211SetTxPowerLimit(struct ath_hal *, uint32_t limit); +extern HAL_BOOL ar5211SetTransmitPower(struct ath_hal *, HAL_CHANNEL *); +extern HAL_BOOL ar5211CalNoiseFloor(struct ath_hal *, HAL_CHANNEL_INTERNAL *); +extern HAL_BOOL ar5211SetAntennaSwitchInternal(struct ath_hal *, + HAL_ANT_SETTING, const HAL_CHANNEL *); +extern int16_t ar5211GetNfAdjust(struct ath_hal *, + const HAL_CHANNEL_INTERNAL *); +extern HAL_BOOL ar5211ResetDma(struct ath_hal *, HAL_OPMODE); +extern void ar5211InitializeGainValues(struct ath_hal *); +extern HAL_RFGAIN ar5211GetRfgain(struct ath_hal *); +extern void ar5211SetPCUConfig(struct ath_hal *); + +extern HAL_BOOL ar5211SetTxQueueProps(struct ath_hal *ah, int q, + const HAL_TXQ_INFO *qInfo); +extern HAL_BOOL ar5211GetTxQueueProps(struct ath_hal *ah, int q, + HAL_TXQ_INFO *qInfo); +extern int ar5211SetupTxQueue(struct ath_hal *ah, HAL_TX_QUEUE type, + const HAL_TXQ_INFO *qInfo); +extern HAL_BOOL ar5211ReleaseTxQueue(struct ath_hal *ah, u_int q); +extern HAL_BOOL ar5211ResetTxQueue(struct ath_hal *ah, u_int q); +extern uint32_t ar5211GetTxDP(struct ath_hal *, u_int); +extern HAL_BOOL ar5211SetTxDP(struct ath_hal *, u_int, uint32_t txdp); +extern HAL_BOOL ar5211UpdateTxTrigLevel(struct ath_hal *, HAL_BOOL); +extern HAL_BOOL ar5211StartTxDma(struct ath_hal *, u_int); +extern HAL_BOOL ar5211StopTxDma(struct ath_hal *, u_int); +extern uint32_t ar5211NumTxPending(struct ath_hal *, u_int qnum); +extern HAL_BOOL ar5211IsTxQueueStopped(struct ath_hal *, u_int); +extern HAL_BOOL ar5211GetTransmitFilterIndex(struct ath_hal *, uint32_t); +extern HAL_BOOL ar5211SetupTxDesc(struct ath_hal *, struct ath_desc *, + u_int pktLen, u_int hdrLen, HAL_PKT_TYPE type, u_int txPower, + u_int txRate0, u_int txTries0, + u_int keyIx, u_int antMode, u_int flags, + u_int rtsctsRate, u_int rtsctsDuration, + u_int compicvLen, u_int compivLen, u_int comp); +extern HAL_BOOL ar5211SetupXTxDesc(struct ath_hal *, struct ath_desc *, + u_int txRate1, u_int txRetries1, + u_int txRate2, u_int txRetries2, + u_int txRate3, u_int txRetries3); +extern HAL_BOOL ar5211FillTxDesc(struct ath_hal *, struct ath_desc *, + u_int segLen, HAL_BOOL firstSeg, HAL_BOOL lastSeg, + const struct ath_desc *ds0); +extern HAL_STATUS ar5211ProcTxDesc(struct ath_hal *, + struct ath_desc *, struct ath_tx_status *); +extern void ar5211GetTxIntrQueue(struct ath_hal *ah, uint32_t *); +extern void ar5211IntrReqTxDesc(struct ath_hal *ah, struct ath_desc *); + +extern uint32_t ar5211GetRxDP(struct ath_hal *); +extern void ar5211SetRxDP(struct ath_hal *, uint32_t rxdp); +extern void ar5211EnableReceive(struct ath_hal *); +extern HAL_BOOL ar5211StopDmaReceive(struct ath_hal *); +extern void ar5211StartPcuReceive(struct ath_hal *); +extern void ar5211StopPcuReceive(struct ath_hal *); +extern void ar5211SetMulticastFilter(struct ath_hal *, + uint32_t filter0, uint32_t filter1); +extern HAL_BOOL ar5211ClrMulticastFilterIndex(struct ath_hal *, uint32_t); +extern HAL_BOOL ar5211SetMulticastFilterIndex(struct ath_hal *, uint32_t); +extern uint32_t ar5211GetRxFilter(struct ath_hal *); +extern void ar5211SetRxFilter(struct ath_hal *, uint32_t); +extern HAL_BOOL ar5211SetupRxDesc(struct ath_hal *, struct ath_desc *, + uint32_t, u_int flags); +extern HAL_STATUS ar5211ProcRxDesc(struct ath_hal *, struct ath_desc *, + uint32_t, struct ath_desc *, uint64_t, + struct ath_rx_status *); + +extern void ar5211GetMacAddress(struct ath_hal *, uint8_t *); +extern HAL_BOOL ar5211SetMacAddress(struct ath_hal *ah, const uint8_t *); +extern void ar5211GetBssIdMask(struct ath_hal *, uint8_t *); +extern HAL_BOOL ar5211SetBssIdMask(struct ath_hal *, const uint8_t *); +extern HAL_BOOL ar5211EepromRead(struct ath_hal *, u_int off, uint16_t *data); +extern HAL_BOOL ar5211EepromWrite(struct ath_hal *, u_int off, uint16_t data); +extern HAL_BOOL ar5211SetRegulatoryDomain(struct ath_hal *, + uint16_t, HAL_STATUS *); +extern u_int ar5211GetWirelessModes(struct ath_hal *); +extern void ar5211EnableRfKill(struct ath_hal *); +extern uint32_t ar5211GpioGet(struct ath_hal *, uint32_t gpio); +extern void ar5211GpioSetIntr(struct ath_hal *, u_int, uint32_t ilevel); +extern HAL_BOOL ar5211GpioCfgOutput(struct ath_hal *, uint32_t gpio); +extern HAL_BOOL ar5211GpioCfgInput(struct ath_hal *, uint32_t gpio); +extern HAL_BOOL ar5211GpioSet(struct ath_hal *, uint32_t gpio, uint32_t val); +extern void ar5211SetLedState(struct ath_hal *, HAL_LED_STATE); +extern u_int ar5211AntennaGet(struct ath_hal *); +extern void ar5211WriteAssocid(struct ath_hal *, + const uint8_t *bssid, uint16_t assocId); +extern uint64_t ar5211GetTsf64(struct ath_hal *); +extern uint32_t ar5211GetTsf32(struct ath_hal *); +extern void ar5211ResetTsf(struct ath_hal *); +extern uint32_t ar5211GetMaxTurboRate(struct ath_hal *); +extern uint32_t ar5211GetRandomSeed(struct ath_hal *); +extern HAL_BOOL ar5211DetectCardPresent(struct ath_hal *); +extern void ar5211UpdateMibCounters(struct ath_hal *, HAL_MIB_STATS *); +extern void ar5211EnableHwEncryption(struct ath_hal *); +extern void ar5211DisableHwEncryption(struct ath_hal *); +extern HAL_BOOL ar5211SetSlotTime(struct ath_hal *, u_int); +extern u_int ar5211GetSlotTime(struct ath_hal *); +extern HAL_BOOL ar5211SetAckTimeout(struct ath_hal *, u_int); +extern u_int ar5211GetAckTimeout(struct ath_hal *); +extern HAL_BOOL ar5211SetAckCTSRate(struct ath_hal *, u_int); +extern u_int ar5211GetAckCTSRate(struct ath_hal *); +extern HAL_BOOL ar5211SetCTSTimeout(struct ath_hal *, u_int); +extern u_int ar5211GetCTSTimeout(struct ath_hal *); +extern HAL_BOOL ar5211SetSifsTime(struct ath_hal *, u_int); +extern u_int ar5211GetSifsTime(struct ath_hal *); +extern HAL_BOOL ar5211SetDecompMask(struct ath_hal *, uint16_t, int); +extern void ar5211SetCoverageClass(struct ath_hal *, uint8_t, int); +extern uint32_t ar5211GetCurRssi(struct ath_hal *); +extern u_int ar5211GetDefAntenna(struct ath_hal *); +extern void ar5211SetDefAntenna(struct ath_hal *ah, u_int antenna); +extern HAL_ANT_SETTING ar5211GetAntennaSwitch(struct ath_hal *); +extern HAL_BOOL ar5211SetAntennaSwitch(struct ath_hal *, HAL_ANT_SETTING); +extern HAL_STATUS ar5211GetCapability(struct ath_hal *, HAL_CAPABILITY_TYPE, + uint32_t, uint32_t *); +extern HAL_BOOL ar5211SetCapability(struct ath_hal *, HAL_CAPABILITY_TYPE, + uint32_t, uint32_t, HAL_STATUS *); +extern HAL_BOOL ar5211GetDiagState(struct ath_hal *ah, int request, + const void *args, uint32_t argsize, + void **result, uint32_t *resultsize); + +extern u_int ar5211GetKeyCacheSize(struct ath_hal *); +extern HAL_BOOL ar5211IsKeyCacheEntryValid(struct ath_hal *, uint16_t); +extern HAL_BOOL ar5211ResetKeyCacheEntry(struct ath_hal *, uint16_t entry); +extern HAL_BOOL ar5211SetKeyCacheEntry(struct ath_hal *, uint16_t entry, + const HAL_KEYVAL *, const uint8_t *mac, + int xorKey); +extern HAL_BOOL ar5211SetKeyCacheEntryMac(struct ath_hal *, + uint16_t, const uint8_t *); + +extern HAL_BOOL ar5211SetPowerMode(struct ath_hal *, uint32_t powerRequest, + int setChip); +extern HAL_POWER_MODE ar5211GetPowerMode(struct ath_hal *); + +extern void ar5211SetBeaconTimers(struct ath_hal *, + const HAL_BEACON_TIMERS *); +extern void ar5211BeaconInit(struct ath_hal *, uint32_t, uint32_t); +extern void ar5211SetStaBeaconTimers(struct ath_hal *, + const HAL_BEACON_STATE *); +extern void ar5211ResetStaBeaconTimers(struct ath_hal *); + +extern HAL_BOOL ar5211IsInterruptPending(struct ath_hal *); +extern HAL_BOOL ar5211GetPendingInterrupts(struct ath_hal *, HAL_INT *); +extern HAL_INT ar5211GetInterrupts(struct ath_hal *); +extern HAL_INT ar5211SetInterrupts(struct ath_hal *, HAL_INT ints); + +extern const HAL_RATE_TABLE *ar5211GetRateTable(struct ath_hal *, u_int mode); + +extern HAL_BOOL ar5211AniControl(struct ath_hal *, HAL_ANI_CMD, int ); +extern void ar5211AniPoll(struct ath_hal *, const HAL_NODE_STATS *, HAL_CHANNEL *); +extern void ar5211MibEvent(struct ath_hal *, const HAL_NODE_STATS *); +#endif /* _ATH_AR5211_H_ */ --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5211/ar5211_attach.c 2009-03-23 17:36:55.000000000 +0000 @@ -0,0 +1,516 @@ +/* + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2006 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ar5211_attach.c,v 1.1 2009/03/23 17:14:47 sborrill Exp $ + */ +#include "opt_ah.h" + +#include "ah.h" +#include "ah_internal.h" +#include "ah_devid.h" + +#include "ar5211/ar5211.h" +#include "ar5211/ar5211reg.h" +#include "ar5211/ar5211phy.h" + +#include "ah_eeprom_v3.h" + +static HAL_BOOL ar5211GetChannelEdges(struct ath_hal *ah, + uint16_t flags, uint16_t *low, uint16_t *high); +static HAL_BOOL ar5211GetChipPowerLimits(struct ath_hal *ah, + HAL_CHANNEL *chans, uint32_t nchans); + +static const struct ath_hal_private ar5211hal = {{ + .ah_magic = AR5211_MAGIC, + .ah_abi = HAL_ABI_VERSION, + .ah_countryCode = CTRY_DEFAULT, + + .ah_getRateTable = ar5211GetRateTable, + .ah_detach = ar5211Detach, + + /* Reset Functions */ + .ah_reset = ar5211Reset, + .ah_phyDisable = ar5211PhyDisable, + .ah_disable = ar5211Disable, + .ah_setPCUConfig = ar5211SetPCUConfig, + .ah_perCalibration = ar5211PerCalibration, + .ah_perCalibrationN = ar5211PerCalibrationN, + .ah_resetCalValid = ar5211ResetCalValid, + .ah_setTxPowerLimit = ar5211SetTxPowerLimit, + .ah_getChanNoise = ath_hal_getChanNoise, + + /* Transmit functions */ + .ah_updateTxTrigLevel = ar5211UpdateTxTrigLevel, + .ah_setupTxQueue = ar5211SetupTxQueue, + .ah_setTxQueueProps = ar5211SetTxQueueProps, + .ah_getTxQueueProps = ar5211GetTxQueueProps, + .ah_releaseTxQueue = ar5211ReleaseTxQueue, + .ah_resetTxQueue = ar5211ResetTxQueue, + .ah_getTxDP = ar5211GetTxDP, + .ah_setTxDP = ar5211SetTxDP, + .ah_numTxPending = ar5211NumTxPending, + .ah_startTxDma = ar5211StartTxDma, + .ah_stopTxDma = ar5211StopTxDma, + .ah_setupTxDesc = ar5211SetupTxDesc, + .ah_setupXTxDesc = ar5211SetupXTxDesc, + .ah_fillTxDesc = ar5211FillTxDesc, + .ah_procTxDesc = ar5211ProcTxDesc, + .ah_getTxIntrQueue = ar5211GetTxIntrQueue, + .ah_reqTxIntrDesc = ar5211IntrReqTxDesc, + + /* RX Functions */ + .ah_getRxDP = ar5211GetRxDP, + .ah_setRxDP = ar5211SetRxDP, + .ah_enableReceive = ar5211EnableReceive, + .ah_stopDmaReceive = ar5211StopDmaReceive, + .ah_startPcuReceive = ar5211StartPcuReceive, + .ah_stopPcuReceive = ar5211StopPcuReceive, + .ah_setMulticastFilter = ar5211SetMulticastFilter, + .ah_setMulticastFilterIndex = ar5211SetMulticastFilterIndex, + .ah_clrMulticastFilterIndex = ar5211ClrMulticastFilterIndex, + .ah_getRxFilter = ar5211GetRxFilter, + .ah_setRxFilter = ar5211SetRxFilter, + .ah_setupRxDesc = ar5211SetupRxDesc, + .ah_procRxDesc = ar5211ProcRxDesc, + .ah_rxMonitor = ar5211AniPoll, + .ah_procMibEvent = ar5211MibEvent, + + /* Misc Functions */ + .ah_getCapability = ar5211GetCapability, + .ah_setCapability = ar5211SetCapability, + .ah_getDiagState = ar5211GetDiagState, + .ah_getMacAddress = ar5211GetMacAddress, + .ah_setMacAddress = ar5211SetMacAddress, + .ah_getBssIdMask = ar5211GetBssIdMask, + .ah_setBssIdMask = ar5211SetBssIdMask, + .ah_setRegulatoryDomain = ar5211SetRegulatoryDomain, + .ah_setLedState = ar5211SetLedState, + .ah_writeAssocid = ar5211WriteAssocid, + .ah_gpioCfgInput = ar5211GpioCfgInput, + .ah_gpioCfgOutput = ar5211GpioCfgOutput, + .ah_gpioGet = ar5211GpioGet, + .ah_gpioSet = ar5211GpioSet, + .ah_gpioSetIntr = ar5211GpioSetIntr, + .ah_getTsf32 = ar5211GetTsf32, + .ah_getTsf64 = ar5211GetTsf64, + .ah_resetTsf = ar5211ResetTsf, + .ah_detectCardPresent = ar5211DetectCardPresent, + .ah_updateMibCounters = ar5211UpdateMibCounters, + .ah_getRfGain = ar5211GetRfgain, + .ah_getDefAntenna = ar5211GetDefAntenna, + .ah_setDefAntenna = ar5211SetDefAntenna, + .ah_getAntennaSwitch = ar5211GetAntennaSwitch, + .ah_setAntennaSwitch = ar5211SetAntennaSwitch, + .ah_setSifsTime = ar5211SetSifsTime, + .ah_getSifsTime = ar5211GetSifsTime, + .ah_setSlotTime = ar5211SetSlotTime, + .ah_getSlotTime = ar5211GetSlotTime, + .ah_setAckTimeout = ar5211SetAckTimeout, + .ah_getAckTimeout = ar5211GetAckTimeout, + .ah_setAckCTSRate = ar5211SetAckCTSRate, + .ah_getAckCTSRate = ar5211GetAckCTSRate, + .ah_setCTSTimeout = ar5211SetCTSTimeout, + .ah_getCTSTimeout = ar5211GetCTSTimeout, + .ah_setDecompMask = ar5211SetDecompMask, + .ah_setCoverageClass = ar5211SetCoverageClass, + + /* Key Cache Functions */ + .ah_getKeyCacheSize = ar5211GetKeyCacheSize, + .ah_resetKeyCacheEntry = ar5211ResetKeyCacheEntry, + .ah_isKeyCacheEntryValid = ar5211IsKeyCacheEntryValid, + .ah_setKeyCacheEntry = ar5211SetKeyCacheEntry, + .ah_setKeyCacheEntryMac = ar5211SetKeyCacheEntryMac, + + /* Power Management Functions */ + .ah_setPowerMode = ar5211SetPowerMode, + .ah_getPowerMode = ar5211GetPowerMode, + + /* Beacon Functions */ + .ah_setBeaconTimers = ar5211SetBeaconTimers, + .ah_beaconInit = ar5211BeaconInit, + .ah_setStationBeaconTimers = ar5211SetStaBeaconTimers, + .ah_resetStationBeaconTimers = ar5211ResetStaBeaconTimers, + + /* Interrupt Functions */ + .ah_isInterruptPending = ar5211IsInterruptPending, + .ah_getPendingInterrupts = ar5211GetPendingInterrupts, + .ah_getInterrupts = ar5211GetInterrupts, + .ah_setInterrupts = ar5211SetInterrupts }, + + .ah_getChannelEdges = ar5211GetChannelEdges, + .ah_getWirelessModes = ar5211GetWirelessModes, + .ah_eepromRead = ar5211EepromRead, +#ifdef AH_SUPPORT_WRITE_EEPROM + .ah_eepromWrite = ar5211EepromWrite, +#endif + .ah_gpioCfgInput = ar5211GpioCfgInput, + .ah_gpioCfgOutput = ar5211GpioCfgOutput, + .ah_gpioGet = ar5211GpioGet, + .ah_gpioSet = ar5211GpioSet, + .ah_gpioSetIntr = ar5211GpioSetIntr, + .ah_getChipPowerLimits = ar5211GetChipPowerLimits, +}; + +static HAL_BOOL ar5211ChipTest(struct ath_hal *); +static HAL_BOOL ar5211FillCapabilityInfo(struct ath_hal *ah); + +/* + * Return the revsion id for the radio chip. This + * fetched via the PHY. + */ +static uint32_t +ar5211GetRadioRev(struct ath_hal *ah) +{ + uint32_t val; + int i; + + OS_REG_WRITE(ah, (AR_PHY_BASE + (0x34 << 2)), 0x00001c16); + for (i = 0; i < 8; i++) + OS_REG_WRITE(ah, (AR_PHY_BASE + (0x20 << 2)), 0x00010000); + val = (OS_REG_READ(ah, AR_PHY_BASE + (256 << 2)) >> 24) & 0xff; + val = ((val & 0xf0) >> 4) | ((val & 0x0f) << 4); + return ath_hal_reverseBits(val, 8); +} + +/* + * Attach for an AR5211 part. + */ +struct ath_hal * +ar5211Attach(uint16_t devid, HAL_SOFTC sc, + HAL_BUS_TAG st, HAL_BUS_HANDLE sh, HAL_STATUS *status) +{ +#define N(a) (sizeof(a)/sizeof(a[0])) + struct ath_hal_5211 *ahp; + struct ath_hal *ah; + uint32_t val; + uint16_t eeval; + HAL_STATUS ecode; + + HALDEBUG(AH_NULL, HAL_DEBUG_ATTACH, "%s: sc %p st %p sh %p\n", + __func__, sc, (void*) st, (void*) sh); + + /* NB: memory is returned zero'd */ + ahp = ath_hal_malloc(sizeof (struct ath_hal_5211)); + if (ahp == AH_NULL) { + HALDEBUG(AH_NULL, HAL_DEBUG_ANY, + "%s: cannot allocate memory for state block\n", __func__); + ecode = HAL_ENOMEM; + goto bad; + } + ah = &ahp->ah_priv.h; + /* set initial values */ + OS_MEMCPY(&ahp->ah_priv, &ar5211hal, sizeof(struct ath_hal_private)); + ah->ah_sc = sc; + ah->ah_st = st; + ah->ah_sh = sh; + + ah->ah_devid = devid; /* NB: for AH_DEBUG_ALQ */ + AH_PRIVATE(ah)->ah_devid = devid; + AH_PRIVATE(ah)->ah_subvendorid = 0; /* XXX */ + + AH_PRIVATE(ah)->ah_powerLimit = MAX_RATE_POWER; + AH_PRIVATE(ah)->ah_tpScale = HAL_TP_SCALE_MAX; /* no scaling */ + + ahp->ah_diversityControl = HAL_ANT_VARIABLE; + ahp->ah_staId1Defaults = 0; + ahp->ah_rssiThr = INIT_RSSI_THR; + ahp->ah_sifstime = (u_int) -1; + ahp->ah_slottime = (u_int) -1; + ahp->ah_acktimeout = (u_int) -1; + ahp->ah_ctstimeout = (u_int) -1; + + if (!ar5211ChipReset(ah, AH_FALSE)) { /* reset chip */ + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: chip reset failed\n", __func__); + ecode = HAL_EIO; + goto bad; + } + if (AH_PRIVATE(ah)->ah_devid == AR5211_FPGA11B) { + /* set it back to OFDM mode to be able to read analog rev id */ + OS_REG_WRITE(ah, AR5211_PHY_MODE, AR5211_PHY_MODE_OFDM); + OS_REG_WRITE(ah, AR_PHY_PLL_CTL, AR_PHY_PLL_CTL_44); + OS_DELAY(1000); + } + + /* Read Revisions from Chips */ + val = OS_REG_READ(ah, AR_SREV) & AR_SREV_ID_M; + AH_PRIVATE(ah)->ah_macVersion = val >> AR_SREV_ID_S; + AH_PRIVATE(ah)->ah_macRev = val & AR_SREV_REVISION_M; + + if (AH_PRIVATE(ah)->ah_macVersion < AR_SREV_VERSION_MAUI_2 || + AH_PRIVATE(ah)->ah_macVersion > AR_SREV_VERSION_OAHU) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: Mac Chip Rev 0x%x is not supported by this driver\n", + __func__, AH_PRIVATE(ah)->ah_macVersion); + ecode = HAL_ENOTSUPP; + goto bad; + } + + AH_PRIVATE(ah)->ah_phyRev = OS_REG_READ(ah, AR_PHY_CHIP_ID); + + if (!ar5211ChipTest(ah)) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: hardware self-test failed\n", + __func__); + ecode = HAL_ESELFTEST; + goto bad; + } + + /* Set correct Baseband to analog shift setting to access analog chips. */ + if (AH_PRIVATE(ah)->ah_macVersion >= AR_SREV_VERSION_OAHU) { + OS_REG_WRITE(ah, AR_PHY_BASE, 0x00000007); + } else { + OS_REG_WRITE(ah, AR_PHY_BASE, 0x00000047); + } + OS_DELAY(2000); + + /* Read Radio Chip Rev Extract */ + AH_PRIVATE(ah)->ah_analog5GhzRev = ar5211GetRadioRev(ah); + if ((AH_PRIVATE(ah)->ah_analog5GhzRev & 0xf0) != RAD5_SREV_MAJOR) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: 5G Radio Chip Rev 0x%02X is not supported by this " + "driver\n", __func__, AH_PRIVATE(ah)->ah_analog5GhzRev); + ecode = HAL_ENOTSUPP; + goto bad; + } + + val = (OS_REG_READ(ah, AR_PCICFG) & AR_PCICFG_EEPROM_SIZE_M) >> + AR_PCICFG_EEPROM_SIZE_S; + if (val != AR_PCICFG_EEPROM_SIZE_16K) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unsupported EEPROM size " + "%u (0x%x) found\n", __func__, val, val); + ecode = HAL_EESIZE; + goto bad; + } + ecode = ath_hal_legacyEepromAttach(ah); + if (ecode != HAL_OK) { + goto bad; + } + + /* If Bmode and AR5211, verify 2.4 analog exists */ + if (AH_PRIVATE(ah)->ah_macVersion >= AR_SREV_VERSION_OAHU && + ath_hal_eepromGetFlag(ah, AR_EEP_BMODE)) { + /* Set correct Baseband to analog shift setting to access analog chips. */ + OS_REG_WRITE(ah, AR_PHY_BASE, 0x00004007); + OS_DELAY(2000); + AH_PRIVATE(ah)->ah_analog2GhzRev = ar5211GetRadioRev(ah); + + /* Set baseband for 5GHz chip */ + OS_REG_WRITE(ah, AR_PHY_BASE, 0x00000007); + OS_DELAY(2000); + if ((AH_PRIVATE(ah)->ah_analog2GhzRev & 0xF0) != RAD2_SREV_MAJOR) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: 2G Radio Chip Rev 0x%x is not supported by " + "this driver\n", __func__, + AH_PRIVATE(ah)->ah_analog2GhzRev); + ecode = HAL_ENOTSUPP; + goto bad; + } + } else { + ath_hal_eepromSet(ah, AR_EEP_BMODE, AH_FALSE); + } + + ecode = ath_hal_eepromGet(ah, AR_EEP_REGDMN_0, &eeval); + if (ecode != HAL_OK) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: cannot read regulatory domain from EEPROM\n", + __func__); + goto bad; + } + AH_PRIVATE(ah)->ah_currentRD = eeval; + AH_PRIVATE(ah)->ah_getNfAdjust = ar5211GetNfAdjust; + + /* + * Got everything we need now to setup the capabilities. + */ + (void) ar5211FillCapabilityInfo(ah); + + /* Initialize gain ladder thermal calibration structure */ + ar5211InitializeGainValues(ah); + + ecode = ath_hal_eepromGet(ah, AR_EEP_MACADDR, ahp->ah_macaddr); + if (ecode != HAL_OK) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: error getting mac address from EEPROM\n", __func__); + goto bad; + } + + HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s: return\n", __func__); + + return ah; +bad: + if (ahp) + ar5211Detach((struct ath_hal *) ahp); + if (status) + *status = ecode; + return AH_NULL; +#undef N +} + +void +ar5211Detach(struct ath_hal *ah) +{ + HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s:\n", __func__); + + HALASSERT(ah != AH_NULL); + HALASSERT(ah->ah_magic == AR5211_MAGIC); + + ath_hal_eepromDetach(ah); + ath_hal_free(ah); +} + +static HAL_BOOL +ar5211ChipTest(struct ath_hal *ah) +{ + uint32_t regAddr[2] = { AR_STA_ID0, AR_PHY_BASE+(8 << 2) }; + uint32_t regHold[2]; + uint32_t patternData[4] = + { 0x55555555, 0xaaaaaaaa, 0x66666666, 0x99999999 }; + int i, j; + + /* Test PHY & MAC registers */ + for (i = 0; i < 2; i++) { + uint32_t addr = regAddr[i]; + uint32_t wrData, rdData; + + regHold[i] = OS_REG_READ(ah, addr); + for (j = 0; j < 0x100; j++) { + wrData = (j << 16) | j; + OS_REG_WRITE(ah, addr, wrData); + rdData = OS_REG_READ(ah, addr); + if (rdData != wrData) { + HALDEBUG(ah, HAL_DEBUG_ANY, +"%s: address test failed addr: 0x%08x - wr:0x%08x != rd:0x%08x\n", + __func__, addr, wrData, rdData); + return AH_FALSE; + } + } + for (j = 0; j < 4; j++) { + wrData = patternData[j]; + OS_REG_WRITE(ah, addr, wrData); + rdData = OS_REG_READ(ah, addr); + if (wrData != rdData) { + HALDEBUG(ah, HAL_DEBUG_ANY, +"%s: address test failed addr: 0x%08x - wr:0x%08x != rd:0x%08x\n", + __func__, addr, wrData, rdData); + return AH_FALSE; + } + } + OS_REG_WRITE(ah, regAddr[i], regHold[i]); + } + OS_DELAY(100); + return AH_TRUE; +} + +/* + * Store the channel edges for the requested operational mode + */ +static HAL_BOOL +ar5211GetChannelEdges(struct ath_hal *ah, + uint16_t flags, uint16_t *low, uint16_t *high) +{ + if (flags & CHANNEL_5GHZ) { + *low = 4920; + *high = 6100; + return AH_TRUE; + } + if (flags & CHANNEL_2GHZ && ath_hal_eepromGetFlag(ah, AR_EEP_BMODE)) { + *low = 2312; + *high = 2732; + return AH_TRUE; + } + return AH_FALSE; +} + +static HAL_BOOL +ar5211GetChipPowerLimits(struct ath_hal *ah, HAL_CHANNEL *chans, uint32_t nchans) +{ + HAL_CHANNEL *chan; + int i; + + /* XXX fill in, this is just a placeholder */ + for (i = 0; i < nchans; i++) { + chan = &chans[i]; + HALDEBUG(ah, HAL_DEBUG_ATTACH, + "%s: no min/max power for %u/0x%x\n", + __func__, chan->channel, chan->channelFlags); + chan->maxTxPower = MAX_RATE_POWER; + chan->minTxPower = 0; + } + return AH_TRUE; +} + +/* + * Fill all software cached or static hardware state information. + */ +static HAL_BOOL +ar5211FillCapabilityInfo(struct ath_hal *ah) +{ + struct ath_hal_private *ahpriv = AH_PRIVATE(ah); + HAL_CAPABILITIES *pCap = &ahpriv->ah_caps; + + /* Construct wireless mode from EEPROM */ + pCap->halWirelessModes = 0; + if (ath_hal_eepromGetFlag(ah, AR_EEP_AMODE)) { + pCap->halWirelessModes |= HAL_MODE_11A; + if (!ath_hal_eepromGetFlag(ah, AR_EEP_TURBO5DISABLE)) + pCap->halWirelessModes |= HAL_MODE_TURBO; + } + if (ath_hal_eepromGetFlag(ah, AR_EEP_BMODE)) + pCap->halWirelessModes |= HAL_MODE_11B; + + pCap->halLow2GhzChan = 2312; + pCap->halHigh2GhzChan = 2732; + pCap->halLow5GhzChan = 4920; + pCap->halHigh5GhzChan = 6100; + + pCap->halChanSpreadSupport = AH_TRUE; + pCap->halSleepAfterBeaconBroken = AH_TRUE; + pCap->halPSPollBroken = AH_TRUE; + pCap->halVEOLSupport = AH_TRUE; + + pCap->halTotalQueues = HAL_NUM_TX_QUEUES; + pCap->halKeyCacheSize = 128; + + /* XXX not needed */ + pCap->halChanHalfRate = AH_FALSE; + pCap->halChanQuarterRate = AH_FALSE; + + if (ath_hal_eepromGetFlag(ah, AR_EEP_RFKILL) && + ath_hal_eepromGet(ah, AR_EEP_RFSILENT, &ahpriv->ah_rfsilent) == HAL_OK) { + /* NB: enabled by default */ + ahpriv->ah_rfkillEnabled = AH_TRUE; + pCap->halRfSilentSupport = AH_TRUE; + } + + pCap->halTstampPrecision = 13; + + /* XXX might be ok w/ some chip revs */ + ahpriv->ah_rxornIsFatal = AH_TRUE; + return AH_TRUE; +} + +static const char* +ar5211Probe(uint16_t vendorid, uint16_t devid) +{ + if (vendorid == ATHEROS_VENDOR_ID) { + if (devid == AR5211_DEVID || devid == AR5311_DEVID || + devid == AR5211_DEFAULT) + return "Atheros 5211"; + if (devid == AR5211_FPGA11B) + return "Atheros 5211 (FPGA)"; + } + return AH_NULL; +} +AH_CHIP(AR5211, ar5211Probe, ar5211Attach); --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5211/ar5211_beacon.c 2009-03-23 17:36:55.000000000 +0000 @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2006 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ar5211_beacon.c,v 1.1 2009/03/23 17:14:47 sborrill Exp $ + */ +#include "opt_ah.h" + +#include "ah.h" +#include "ah_internal.h" + +#include "ar5211/ar5211.h" +#include "ar5211/ar5211reg.h" +#include "ar5211/ar5211desc.h" + +/* + * Routines used to initialize and generated beacons for the AR5211/AR5311. + */ + +/* + * Initialize all of the hardware registers used to send beacons. + */ +void +ar5211SetBeaconTimers(struct ath_hal *ah, const HAL_BEACON_TIMERS *bt) +{ + + OS_REG_WRITE(ah, AR_TIMER0, bt->bt_nexttbtt); + OS_REG_WRITE(ah, AR_TIMER1, bt->bt_nextdba); + OS_REG_WRITE(ah, AR_TIMER2, bt->bt_nextswba); + OS_REG_WRITE(ah, AR_TIMER3, bt->bt_nextatim); + /* + * Set the Beacon register after setting all timers. + */ + OS_REG_WRITE(ah, AR_BEACON, bt->bt_intval); +} + +/* + * Legacy api to initialize all of the beacon registers. + */ +void +ar5211BeaconInit(struct ath_hal *ah, + uint32_t next_beacon, uint32_t beacon_period) +{ + HAL_BEACON_TIMERS bt; + + bt.bt_nextdba = 0; + bt.bt_nextswba = 0; + bt.bt_nexttbtt = next_beacon; + /* + * TIMER1: in AP/adhoc mode this controls the DMA beacon + * alert timer; otherwise it controls the next wakeup time. + * TIMER2: in AP mode, it controls the SBA beacon alert + * interrupt; otherwise it sets the start of the next CFP. + */ + switch (AH_PRIVATE(ah)->ah_opmode) { + case HAL_M_STA: + case HAL_M_MONITOR: + bt.bt_nextdba = 0xffff; + bt.bt_nextswba = 0x7ffff; + break; + case HAL_M_IBSS: + case HAL_M_HOSTAP: + bt.bt_nextdba = (next_beacon - + ath_hal_dma_beacon_response_time) << 3; /* 1/8 TU */ + bt.bt_nextswba = (next_beacon - + ath_hal_sw_beacon_response_time) << 3; /* 1/8 TU */ + break; + } + /* + * Set the ATIM window + * Our hardware does not support an ATIM window of 0 + * (beacons will not work). If the ATIM windows is 0, + * force it to 1. + */ + bt.bt_nextatim = next_beacon + 1; + bt.bt_intval = beacon_period & + (AR_BEACON_PERIOD | AR_BEACON_RESET_TSF | AR_BEACON_EN); + ar5211SetBeaconTimers(ah, &bt); +} + +void +ar5211ResetStaBeaconTimers(struct ath_hal *ah) +{ + uint32_t val; + + OS_REG_WRITE(ah, AR_TIMER0, 0); /* no beacons */ + val = OS_REG_READ(ah, AR_STA_ID1); + val |= AR_STA_ID1_PWR_SAV; /* XXX */ + /* tell the h/w that the associated AP is not PCF capable */ + OS_REG_WRITE(ah, AR_STA_ID1, + val & ~(AR_STA_ID1_DEFAULT_ANTENNA | AR_STA_ID1_PCF)); + OS_REG_WRITE(ah, AR_BEACON, AR_BEACON_PERIOD); +} + +/* + * Set all the beacon related bits on the h/w for stations + * i.e. initializes the corresponding h/w timers; + * also tells the h/w whether to anticipate PCF beacons + */ +void +ar5211SetStaBeaconTimers(struct ath_hal *ah, const HAL_BEACON_STATE *bs) +{ + struct ath_hal_5211 *ahp = AH5211(ah); + + HALDEBUG(ah, HAL_DEBUG_BEACON, "%s: setting beacon timers\n", __func__); + + HALASSERT(bs->bs_intval != 0); + /* if the AP will do PCF */ + if (bs->bs_cfpmaxduration != 0) { + /* tell the h/w that the associated AP is PCF capable */ + OS_REG_WRITE(ah, AR_STA_ID1, + OS_REG_READ(ah, AR_STA_ID1) | AR_STA_ID1_PCF); + + /* set CFP_PERIOD(1.024ms) register */ + OS_REG_WRITE(ah, AR_CFP_PERIOD, bs->bs_cfpperiod); + + /* set CFP_DUR(1.024ms) register to max cfp duration */ + OS_REG_WRITE(ah, AR_CFP_DUR, bs->bs_cfpmaxduration); + + /* set TIMER2(128us) to anticipated time of next CFP */ + OS_REG_WRITE(ah, AR_TIMER2, bs->bs_cfpnext << 3); + } else { + /* tell the h/w that the associated AP is not PCF capable */ + OS_REG_WRITE(ah, AR_STA_ID1, + OS_REG_READ(ah, AR_STA_ID1) &~ AR_STA_ID1_PCF); + } + + /* + * Set TIMER0(1.024ms) to the anticipated time of the next beacon. + */ + OS_REG_WRITE(ah, AR_TIMER0, bs->bs_nexttbtt); + + /* + * Start the beacon timers by setting the BEACON register + * to the beacon interval; also write the tim offset which + * we should know by now. The code, in ar5211WriteAssocid, + * also sets the tim offset once the AID is known which can + * be left as such for now. + */ + OS_REG_WRITE(ah, AR_BEACON, + (OS_REG_READ(ah, AR_BEACON) &~ (AR_BEACON_PERIOD|AR_BEACON_TIM)) + | SM(bs->bs_intval, AR_BEACON_PERIOD) + | SM(bs->bs_timoffset ? bs->bs_timoffset + 4 : 0, AR_BEACON_TIM) + ); + + /* + * Configure the BMISS interrupt. Note that we + * assume the caller blocks interrupts while enabling + * the threshold. + */ + HALASSERT(bs->bs_bmissthreshold <= MS(0xffffffff, AR_RSSI_THR_BM_THR)); + ahp->ah_rssiThr = (ahp->ah_rssiThr &~ AR_RSSI_THR_BM_THR) + | SM(bs->bs_bmissthreshold, AR_RSSI_THR_BM_THR); + OS_REG_WRITE(ah, AR_RSSI_THR, ahp->ah_rssiThr); + + /* + * Set the sleep duration in 1/8 TU's. + */ +#define SLEEP_SLOP 3 + OS_REG_RMW_FIELD(ah, AR_SCR, AR_SCR_SLDUR, + (bs->bs_sleepduration - SLEEP_SLOP) << 3); +#undef SLEEP_SLOP +} --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5211/ar5211_interrupts.c 2009-03-23 17:36:55.000000000 +0000 @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2006 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ar5211_interrupts.c,v 1.1 2009/03/23 17:14:47 sborrill Exp $ + */ +#include "opt_ah.h" + +#include "ah.h" +#include "ah_internal.h" + +#include "ar5211/ar5211.h" +#include "ar5211/ar5211reg.h" + +/* + * Checks to see if an interrupt is pending on our NIC + * + * Returns: TRUE if an interrupt is pending + * FALSE if not + */ +HAL_BOOL +ar5211IsInterruptPending(struct ath_hal *ah) +{ + return OS_REG_READ(ah, AR_INTPEND) != 0; +} + +/* + * Reads the Interrupt Status Register value from the NIC, thus deasserting + * the interrupt line, and returns both the masked and unmasked mapped ISR + * values. The value returned is mapped to abstract the hw-specific bit + * locations in the Interrupt Status Register. + * + * Returns: A hardware-abstracted bitmap of all non-masked-out + * interrupts pending, as well as an unmasked value + */ +HAL_BOOL +ar5211GetPendingInterrupts(struct ath_hal *ah, HAL_INT *masked) +{ + uint32_t isr; + + isr = OS_REG_READ(ah, AR_ISR_RAC); + if (isr == 0xffffffff) { + *masked = 0; + return AH_FALSE; + } + + *masked = isr & HAL_INT_COMMON; + + if (isr & AR_ISR_HIUERR) + *masked |= HAL_INT_FATAL; + if (isr & (AR_ISR_RXOK | AR_ISR_RXERR)) + *masked |= HAL_INT_RX; + if (isr & (AR_ISR_TXOK | AR_ISR_TXDESC | AR_ISR_TXERR | AR_ISR_TXEOL)) + *masked |= HAL_INT_TX; + /* + * Receive overrun is usually non-fatal on Oahu/Spirit. + * BUT on some parts rx could fail and the chip must be reset. + * So we force a hardware reset in all cases. + */ + if ((isr & AR_ISR_RXORN) && AH_PRIVATE(ah)->ah_rxornIsFatal) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: receive FIFO overrun interrupt\n", __func__); + *masked |= HAL_INT_FATAL; + } + + /* + * On fatal errors collect ISR state for debugging. + */ + if (*masked & HAL_INT_FATAL) { + AH_PRIVATE(ah)->ah_fatalState[0] = isr; + AH_PRIVATE(ah)->ah_fatalState[1] = OS_REG_READ(ah, AR_ISR_S0_S); + AH_PRIVATE(ah)->ah_fatalState[2] = OS_REG_READ(ah, AR_ISR_S1_S); + AH_PRIVATE(ah)->ah_fatalState[3] = OS_REG_READ(ah, AR_ISR_S2_S); + AH_PRIVATE(ah)->ah_fatalState[4] = OS_REG_READ(ah, AR_ISR_S3_S); + AH_PRIVATE(ah)->ah_fatalState[5] = OS_REG_READ(ah, AR_ISR_S4_S); + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: fatal error, ISR_RAC=0x%x ISR_S2_S=0x%x\n", + __func__, isr, AH_PRIVATE(ah)->ah_fatalState[3]); + } + return AH_TRUE; +} + +HAL_INT +ar5211GetInterrupts(struct ath_hal *ah) +{ + return AH5211(ah)->ah_maskReg; +} + +/* + * Atomically enables NIC interrupts. Interrupts are passed in + * via the enumerated bitmask in ints. + */ +HAL_INT +ar5211SetInterrupts(struct ath_hal *ah, HAL_INT ints) +{ + struct ath_hal_5211 *ahp = AH5211(ah); + uint32_t omask = ahp->ah_maskReg; + uint32_t mask; + + HALDEBUG(ah, HAL_DEBUG_INTERRUPT, "%s: 0x%x => 0x%x\n", + __func__, omask, ints); + + /* + * Disable interrupts here before reading & modifying + * the mask so that the ISR does not modify the mask + * out from under us. + */ + if (omask & HAL_INT_GLOBAL) { + HALDEBUG(ah, HAL_DEBUG_INTERRUPT, "%s: disable IER\n", __func__); + OS_REG_WRITE(ah, AR_IER, AR_IER_DISABLE); + /* XXX??? */ + (void) OS_REG_READ(ah, AR_IER); /* flush write to HW */ + } + + mask = ints & HAL_INT_COMMON; + if (ints & HAL_INT_TX) { + if (ahp->ah_txOkInterruptMask) + mask |= AR_IMR_TXOK; + if (ahp->ah_txErrInterruptMask) + mask |= AR_IMR_TXERR; + if (ahp->ah_txDescInterruptMask) + mask |= AR_IMR_TXDESC; + if (ahp->ah_txEolInterruptMask) + mask |= AR_IMR_TXEOL; + } + if (ints & HAL_INT_RX) + mask |= AR_IMR_RXOK | AR_IMR_RXERR | AR_IMR_RXDESC; + if (ints & HAL_INT_FATAL) { + /* + * NB: ar5212Reset sets MCABT+SSERR+DPERR in AR_IMR_S2 + * so enabling HIUERR enables delivery. + */ + mask |= AR_IMR_HIUERR; + } + + /* Write the new IMR and store off our SW copy. */ + HALDEBUG(ah, HAL_DEBUG_INTERRUPT, "%s: new IMR 0x%x\n", __func__, mask); + OS_REG_WRITE(ah, AR_IMR, mask); + ahp->ah_maskReg = ints; + + /* Re-enable interrupts as appropriate. */ + if (ints & HAL_INT_GLOBAL) { + HALDEBUG(ah, HAL_DEBUG_INTERRUPT, "%s: enable IER\n", __func__); + OS_REG_WRITE(ah, AR_IER, AR_IER_ENABLE); + } + + return omask; +} --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5211/ar5211_keycache.c 2009-03-23 17:36:55.000000000 +0000 @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2006 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ar5211_keycache.c,v 1.1 2009/03/23 17:14:47 sborrill Exp $ + */ +#include "opt_ah.h" + +#include "ah.h" +#include "ah_internal.h" + +#include "ar5211/ar5211.h" +#include "ar5211/ar5211reg.h" + +/* + * Chips-specific key cache routines. + */ + +#define AR_KEYTABLE_SIZE 128 +#define KEY_XOR 0xaa + +/* + * Return the size of the hardware key cache. + */ +uint32_t +ar5211GetKeyCacheSize(struct ath_hal *ah) +{ + return AR_KEYTABLE_SIZE; +} + +/* + * Return true if the specific key cache entry is valid. + */ +HAL_BOOL +ar5211IsKeyCacheEntryValid(struct ath_hal *ah, uint16_t entry) +{ + if (entry < AR_KEYTABLE_SIZE) { + uint32_t val = OS_REG_READ(ah, AR_KEYTABLE_MAC1(entry)); + if (val & AR_KEYTABLE_VALID) + return AH_TRUE; + } + return AH_FALSE; +} + +/* + * Clear the specified key cache entry + */ +HAL_BOOL +ar5211ResetKeyCacheEntry(struct ath_hal *ah, uint16_t entry) +{ + if (entry < AR_KEYTABLE_SIZE) { + OS_REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), 0); + OS_REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), 0); + OS_REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), 0); + OS_REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), 0); + OS_REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), 0); + OS_REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), 0); + OS_REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), 0); + OS_REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), 0); + return AH_TRUE; + } + return AH_FALSE; +} + +/* + * Sets the mac part of the specified key cache entry and mark it valid. + */ +HAL_BOOL +ar5211SetKeyCacheEntryMac(struct ath_hal *ah, uint16_t entry, const uint8_t *mac) +{ + uint32_t macHi, macLo; + + if (entry >= AR_KEYTABLE_SIZE) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: entry %u out of range\n", + __func__, entry); + return AH_FALSE; + } + + /* + * Set MAC address -- shifted right by 1. MacLo is + * the 4 MSBs, and MacHi is the 2 LSBs. + */ + if (mac != AH_NULL) { + macHi = (mac[5] << 8) | mac[4]; + macLo = (mac[3] << 24)| (mac[2] << 16) + | (mac[1] << 8) | mac[0]; + macLo >>= 1; + macLo |= (macHi & 1) << 31; /* carry */ + macHi >>= 1; + } else { + macLo = macHi = 0; + } + + OS_REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), macLo); + OS_REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), macHi | AR_KEYTABLE_VALID); + return AH_TRUE; +} + +/* + * Sets the contents of the specified key cache entry. + */ +HAL_BOOL +ar5211SetKeyCacheEntry(struct ath_hal *ah, uint16_t entry, + const HAL_KEYVAL *k, const uint8_t *mac, + int xorKey) +{ + uint32_t key0, key1, key2, key3, key4; + uint32_t keyType; + uint32_t xorMask= xorKey ? + (KEY_XOR << 24 | KEY_XOR << 16 | KEY_XOR << 8 | KEY_XOR) : 0; + + if (entry >= AR_KEYTABLE_SIZE) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: entry %u out of range\n", + __func__, entry); + return AH_FALSE; + } + switch (k->kv_type) { + case HAL_CIPHER_AES_OCB: + keyType = AR_KEYTABLE_TYPE_AES; + break; + case HAL_CIPHER_WEP: + if (k->kv_len < 40 / NBBY) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: WEP key length %u too small\n", + __func__, k->kv_len); + return AH_FALSE; + } + if (k->kv_len <= 40 / NBBY) + keyType = AR_KEYTABLE_TYPE_40; + else if (k->kv_len <= 104 / NBBY) + keyType = AR_KEYTABLE_TYPE_104; + else + keyType = AR_KEYTABLE_TYPE_128; + break; + case HAL_CIPHER_CLR: + keyType = AR_KEYTABLE_TYPE_CLR; + break; + default: + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: cipher %u not supported\n", + __func__, k->kv_type); + return AH_FALSE; + } + + key0 = LE_READ_4(k->kv_val+0) ^ xorMask; + key1 = (LE_READ_2(k->kv_val+4) ^ xorMask) & 0xffff; + key2 = LE_READ_4(k->kv_val+6) ^ xorMask; + key3 = (LE_READ_2(k->kv_val+10) ^ xorMask) & 0xffff; + key4 = LE_READ_4(k->kv_val+12) ^ xorMask; + if (k->kv_len <= 104 / NBBY) + key4 &= 0xff; + + + /* + * Note: WEP key cache hardware requires that each double-word + * pair be written in even/odd order (since the destination is + * a 64-bit register). Don't reorder these writes w/o + * understanding this! + */ + OS_REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0); + OS_REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1); + OS_REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2); + OS_REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3); + OS_REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4); + OS_REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType); + return ar5211SetKeyCacheEntryMac(ah, entry, mac); +} --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5211/ar5211_misc.c 2009-03-23 17:36:55.000000000 +0000 @@ -0,0 +1,685 @@ +/* + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2006 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ar5211_misc.c,v 1.1 2009/03/23 17:14:47 sborrill Exp $ + */ +#include "opt_ah.h" + +#include "ah.h" +#include "ah_internal.h" + +#include "ar5211/ar5211.h" +#include "ar5211/ar5211reg.h" +#include "ar5211/ar5211phy.h" + +#include "ah_eeprom_v3.h" + +#define AR_NUM_GPIO 6 /* 6 GPIO bits */ +#define AR_GPIOD_MASK 0x2f /* 6-bit mask */ + +void +ar5211GetMacAddress(struct ath_hal *ah, uint8_t *mac) +{ + struct ath_hal_5211 *ahp = AH5211(ah); + + OS_MEMCPY(mac, ahp->ah_macaddr, IEEE80211_ADDR_LEN); +} + +HAL_BOOL +ar5211SetMacAddress(struct ath_hal *ah, const uint8_t *mac) +{ + struct ath_hal_5211 *ahp = AH5211(ah); + + OS_MEMCPY(ahp->ah_macaddr, mac, IEEE80211_ADDR_LEN); + return AH_TRUE; +} + +void +ar5211GetBssIdMask(struct ath_hal *ah, uint8_t *mask) +{ + static const uint8_t ones[IEEE80211_ADDR_LEN] = + { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + OS_MEMCPY(mask, ones, IEEE80211_ADDR_LEN); +} + +HAL_BOOL +ar5211SetBssIdMask(struct ath_hal *ah, const uint8_t *mask) +{ + return AH_FALSE; +} + +/* + * Read 16 bits of data from the specified EEPROM offset. + */ +HAL_BOOL +ar5211EepromRead(struct ath_hal *ah, u_int off, uint16_t *data) +{ + OS_REG_WRITE(ah, AR_EEPROM_ADDR, off); + OS_REG_WRITE(ah, AR_EEPROM_CMD, AR_EEPROM_CMD_READ); + + if (!ath_hal_wait(ah, AR_EEPROM_STS, + AR_EEPROM_STS_READ_COMPLETE | AR_EEPROM_STS_READ_ERROR, + AR_EEPROM_STS_READ_COMPLETE)) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: read failed for entry 0x%x\n", __func__, off); + return AH_FALSE; + } + *data = OS_REG_READ(ah, AR_EEPROM_DATA) & 0xffff; + return AH_TRUE; +} + +#ifdef AH_SUPPORT_WRITE_EEPROM +/* + * Write 16 bits of data to the specified EEPROM offset. + */ +HAL_BOOL +ar5211EepromWrite(struct ath_hal *ah, u_int off, uint16_t data) +{ + return AH_FALSE; +} +#endif /* AH_SUPPORT_WRITE_EEPROM */ + +/* + * Attempt to change the cards operating regulatory domain to the given value + */ +HAL_BOOL +ar5211SetRegulatoryDomain(struct ath_hal *ah, + uint16_t regDomain, HAL_STATUS *status) +{ + HAL_STATUS ecode; + + if (AH_PRIVATE(ah)->ah_currentRD == regDomain) { + ecode = HAL_EINVAL; + goto bad; + } + /* + * Check if EEPROM is configured to allow this; must + * be a proper version and the protection bits must + * permit re-writing that segment of the EEPROM. + */ + if (ath_hal_eepromGetFlag(ah, AR_EEP_WRITEPROTECT)) { + ecode = HAL_EEWRITE; + goto bad; + } +#ifdef AH_SUPPORT_WRITE_REGDOMAIN + if (ar5211EepromWrite(ah, AR_EEPROM_REG_DOMAIN, regDomain)) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: set regulatory domain to %u (0x%x)\n", + __func__, regDomain, regDomain); + AH_PRIVATE(ah)->ah_currentRD = regDomain; + return AH_TRUE; + } +#endif + ecode = HAL_EIO; +bad: + if (status) + *status = ecode; + return AH_FALSE; +} + +/* + * Return the wireless modes (a,b,g,t) supported by hardware. + * + * This value is what is actually supported by the hardware + * and is unaffected by regulatory/country code settings. + * + */ +u_int +ar5211GetWirelessModes(struct ath_hal *ah) +{ + u_int mode = 0; + + if (ath_hal_eepromGetFlag(ah, AR_EEP_AMODE)) { + mode = HAL_MODE_11A; + if (!ath_hal_eepromGetFlag(ah, AR_EEP_TURBO5DISABLE)) + mode |= HAL_MODE_TURBO | HAL_MODE_108A; + } + if (ath_hal_eepromGetFlag(ah, AR_EEP_BMODE)) + mode |= HAL_MODE_11B; + return mode; +} + +#if 0 +HAL_BOOL +ar5211GetTurboDisable(struct ath_hal *ah) +{ + return (AH5211(ah)->ah_turboDisable != 0); +} +#endif + +/* + * Called if RfKill is supported (according to EEPROM). Set the interrupt and + * GPIO values so the ISR and can disable RF on a switch signal + */ +void +ar5211EnableRfKill(struct ath_hal *ah) +{ + uint16_t rfsilent = AH_PRIVATE(ah)->ah_rfsilent; + int select = MS(rfsilent, AR_EEPROM_RFSILENT_GPIO_SEL); + int polarity = MS(rfsilent, AR_EEPROM_RFSILENT_POLARITY); + + /* + * Configure the desired GPIO port for input + * and enable baseband rf silence. + */ + ar5211GpioCfgInput(ah, select); + OS_REG_SET_BIT(ah, AR_PHY_BASE, 0x00002000); + /* + * If radio disable switch connection to GPIO bit x is enabled + * program GPIO interrupt. + * If rfkill bit on eeprom is 1, setupeeprommap routine has already + * verified that it is a later version of eeprom, it has a place for + * rfkill bit and it is set to 1, indicating that GPIO bit x hardware + * connection is present. + */ + ar5211GpioSetIntr(ah, select, (ar5211GpioGet(ah, select) != polarity)); +} + +/* + * Configure GPIO Output lines + */ +HAL_BOOL +ar5211GpioCfgOutput(struct ath_hal *ah, uint32_t gpio) +{ + uint32_t reg; + + HALASSERT(gpio < AR_NUM_GPIO); + + reg = OS_REG_READ(ah, AR_GPIOCR); + reg &= ~(AR_GPIOCR_0_CR_A << (gpio * AR_GPIOCR_CR_SHIFT)); + reg |= AR_GPIOCR_0_CR_A << (gpio * AR_GPIOCR_CR_SHIFT); + + OS_REG_WRITE(ah, AR_GPIOCR, reg); + return AH_TRUE; +} + +/* + * Configure GPIO Input lines + */ +HAL_BOOL +ar5211GpioCfgInput(struct ath_hal *ah, uint32_t gpio) +{ + uint32_t reg; + + HALASSERT(gpio < AR_NUM_GPIO); + + reg = OS_REG_READ(ah, AR_GPIOCR); + reg &= ~(AR_GPIOCR_0_CR_A << (gpio * AR_GPIOCR_CR_SHIFT)); + reg |= AR_GPIOCR_0_CR_N << (gpio * AR_GPIOCR_CR_SHIFT); + + OS_REG_WRITE(ah, AR_GPIOCR, reg); + return AH_TRUE; +} + +/* + * Once configured for I/O - set output lines + */ +HAL_BOOL +ar5211GpioSet(struct ath_hal *ah, uint32_t gpio, uint32_t val) +{ + uint32_t reg; + + HALASSERT(gpio < AR_NUM_GPIO); + + reg = OS_REG_READ(ah, AR_GPIODO); + reg &= ~(1 << gpio); + reg |= (val&1) << gpio; + + OS_REG_WRITE(ah, AR_GPIODO, reg); + return AH_TRUE; +} + +/* + * Once configured for I/O - get input lines + */ +uint32_t +ar5211GpioGet(struct ath_hal *ah, uint32_t gpio) +{ + if (gpio < AR_NUM_GPIO) { + uint32_t val = OS_REG_READ(ah, AR_GPIODI); + val = ((val & AR_GPIOD_MASK) >> gpio) & 0x1; + return val; + } else { + return 0xffffffff; + } +} + +/* + * Set the GPIO 0 Interrupt (gpio is ignored) + */ +void +ar5211GpioSetIntr(struct ath_hal *ah, u_int gpio, uint32_t ilevel) +{ + uint32_t val = OS_REG_READ(ah, AR_GPIOCR); + + /* Clear the bits that we will modify. */ + val &= ~(AR_GPIOCR_INT_SEL0 | AR_GPIOCR_INT_SELH | AR_GPIOCR_INT_ENA | + AR_GPIOCR_0_CR_A); + + val |= AR_GPIOCR_INT_SEL0 | AR_GPIOCR_INT_ENA; + if (ilevel) + val |= AR_GPIOCR_INT_SELH; + + /* Don't need to change anything for low level interrupt. */ + OS_REG_WRITE(ah, AR_GPIOCR, val); + + /* Change the interrupt mask. */ + ar5211SetInterrupts(ah, AH5211(ah)->ah_maskReg | HAL_INT_GPIO); +} + +/* + * Change the LED blinking pattern to correspond to the connectivity + */ +void +ar5211SetLedState(struct ath_hal *ah, HAL_LED_STATE state) +{ + static const uint32_t ledbits[8] = { + AR_PCICFG_LEDCTL_NONE|AR_PCICFG_LEDMODE_PROP, /* HAL_LED_INIT */ + AR_PCICFG_LEDCTL_PEND|AR_PCICFG_LEDMODE_PROP, /* HAL_LED_SCAN */ + AR_PCICFG_LEDCTL_PEND|AR_PCICFG_LEDMODE_PROP, /* HAL_LED_AUTH */ + AR_PCICFG_LEDCTL_ASSOC|AR_PCICFG_LEDMODE_PROP,/* HAL_LED_ASSOC*/ + AR_PCICFG_LEDCTL_ASSOC|AR_PCICFG_LEDMODE_PROP,/* HAL_LED_RUN */ + AR_PCICFG_LEDCTL_NONE|AR_PCICFG_LEDMODE_RAND, + AR_PCICFG_LEDCTL_NONE|AR_PCICFG_LEDMODE_RAND, + AR_PCICFG_LEDCTL_NONE|AR_PCICFG_LEDMODE_RAND, + }; + OS_REG_WRITE(ah, AR_PCICFG, + (OS_REG_READ(ah, AR_PCICFG) &~ + (AR_PCICFG_LEDCTL | AR_PCICFG_LEDMODE)) + | ledbits[state & 0x7] + ); +} + +/* + * Change association related fields programmed into the hardware. + * Writing a valid BSSID to the hardware effectively enables the hardware + * to synchronize its TSF to the correct beacons and receive frames coming + * from that BSSID. It is called by the SME JOIN operation. + */ +void +ar5211WriteAssocid(struct ath_hal *ah, const uint8_t *bssid, uint16_t assocId) +{ + struct ath_hal_5211 *ahp = AH5211(ah); + + /* XXX save bssid for possible re-use on reset */ + OS_MEMCPY(ahp->ah_bssid, bssid, IEEE80211_ADDR_LEN); + OS_REG_WRITE(ah, AR_BSS_ID0, LE_READ_4(ahp->ah_bssid)); + OS_REG_WRITE(ah, AR_BSS_ID1, LE_READ_2(ahp->ah_bssid+4) | + ((assocId & 0x3fff)<> 19) & 0x1ff; + if (nf & 0x100) + nf = 0 - ((nf ^ 0x1ff) + 1); + return (OS_REG_READ(ah, AR_TSF_U32) ^ + OS_REG_READ(ah, AR_TSF_L32) ^ nf); +} + +/* + * Detect if our card is present + */ +HAL_BOOL +ar5211DetectCardPresent(struct ath_hal *ah) +{ + uint16_t macVersion, macRev; + uint32_t v; + + /* + * Read the Silicon Revision register and compare that + * to what we read at attach time. If the same, we say + * a card/device is present. + */ + v = OS_REG_READ(ah, AR_SREV) & AR_SREV_ID_M; + macVersion = v >> AR_SREV_ID_S; + macRev = v & AR_SREV_REVISION_M; + return (AH_PRIVATE(ah)->ah_macVersion == macVersion && + AH_PRIVATE(ah)->ah_macRev == macRev); +} + +/* + * Update MIB Counters + */ +void +ar5211UpdateMibCounters(struct ath_hal *ah, HAL_MIB_STATS *stats) +{ + stats->ackrcv_bad += OS_REG_READ(ah, AR_ACK_FAIL); + stats->rts_bad += OS_REG_READ(ah, AR_RTS_FAIL); + stats->fcs_bad += OS_REG_READ(ah, AR_FCS_FAIL); + stats->rts_good += OS_REG_READ(ah, AR_RTS_OK); + stats->beacons += OS_REG_READ(ah, AR_BEACON_CNT); +} + +HAL_BOOL +ar5211SetSifsTime(struct ath_hal *ah, u_int us) +{ + struct ath_hal_5211 *ahp = AH5211(ah); + + if (us > ath_hal_mac_usec(ah, 0xffff)) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad SIFS time %u\n", + __func__, us); + ahp->ah_sifstime = (u_int) -1; /* restore default handling */ + return AH_FALSE; + } else { + /* convert to system clocks */ + OS_REG_WRITE(ah, AR_D_GBL_IFS_SIFS, ath_hal_mac_clks(ah, us)); + ahp->ah_slottime = us; + return AH_TRUE; + } +} + +u_int +ar5211GetSifsTime(struct ath_hal *ah) +{ + u_int clks = OS_REG_READ(ah, AR_D_GBL_IFS_SIFS) & 0xffff; + return ath_hal_mac_usec(ah, clks); /* convert from system clocks */ +} + +HAL_BOOL +ar5211SetSlotTime(struct ath_hal *ah, u_int us) +{ + struct ath_hal_5211 *ahp = AH5211(ah); + + if (us < HAL_SLOT_TIME_9 || us > ath_hal_mac_usec(ah, 0xffff)) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad slot time %u\n", + __func__, us); + ahp->ah_slottime = us; /* restore default handling */ + return AH_FALSE; + } else { + /* convert to system clocks */ + OS_REG_WRITE(ah, AR_D_GBL_IFS_SLOT, ath_hal_mac_clks(ah, us)); + ahp->ah_slottime = us; + return AH_TRUE; + } +} + +u_int +ar5211GetSlotTime(struct ath_hal *ah) +{ + u_int clks = OS_REG_READ(ah, AR_D_GBL_IFS_SLOT) & 0xffff; + return ath_hal_mac_usec(ah, clks); /* convert from system clocks */ +} + +HAL_BOOL +ar5211SetAckTimeout(struct ath_hal *ah, u_int us) +{ + struct ath_hal_5211 *ahp = AH5211(ah); + + if (us > ath_hal_mac_usec(ah, MS(0xffffffff, AR_TIME_OUT_ACK))) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad ack timeout %u\n", + __func__, us); + ahp->ah_acktimeout = (u_int) -1; /* restore default handling */ + return AH_FALSE; + } else { + /* convert to system clocks */ + OS_REG_RMW_FIELD(ah, AR_TIME_OUT, + AR_TIME_OUT_ACK, ath_hal_mac_clks(ah, us)); + ahp->ah_acktimeout = us; + return AH_TRUE; + } +} + +u_int +ar5211GetAckTimeout(struct ath_hal *ah) +{ + u_int clks = MS(OS_REG_READ(ah, AR_TIME_OUT), AR_TIME_OUT_ACK); + return ath_hal_mac_usec(ah, clks); /* convert from system clocks */ +} + +u_int +ar5211GetAckCTSRate(struct ath_hal *ah) +{ + return ((AH5211(ah)->ah_staId1Defaults & AR_STA_ID1_ACKCTS_6MB) == 0); +} + +HAL_BOOL +ar5211SetAckCTSRate(struct ath_hal *ah, u_int high) +{ + struct ath_hal_5211 *ahp = AH5211(ah); + + if (high) { + OS_REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_ACKCTS_6MB); + ahp->ah_staId1Defaults &= ~AR_STA_ID1_ACKCTS_6MB; + } else { + OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_ACKCTS_6MB); + ahp->ah_staId1Defaults |= AR_STA_ID1_ACKCTS_6MB; + } + return AH_TRUE; +} + +HAL_BOOL +ar5211SetCTSTimeout(struct ath_hal *ah, u_int us) +{ + struct ath_hal_5211 *ahp = AH5211(ah); + + if (us > ath_hal_mac_usec(ah, MS(0xffffffff, AR_TIME_OUT_CTS))) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad cts timeout %u\n", + __func__, us); + ahp->ah_ctstimeout = (u_int) -1; /* restore default handling */ + return AH_FALSE; + } else { + /* convert to system clocks */ + OS_REG_RMW_FIELD(ah, AR_TIME_OUT, + AR_TIME_OUT_CTS, ath_hal_mac_clks(ah, us)); + ahp->ah_ctstimeout = us; + return AH_TRUE; + } +} + +u_int +ar5211GetCTSTimeout(struct ath_hal *ah) +{ + u_int clks = MS(OS_REG_READ(ah, AR_TIME_OUT), AR_TIME_OUT_CTS); + return ath_hal_mac_usec(ah, clks); /* convert from system clocks */ +} + +HAL_BOOL +ar5211SetDecompMask(struct ath_hal *ah, uint16_t keyidx, int en) +{ + /* nothing to do */ + return AH_TRUE; +} + +void +ar5211SetCoverageClass(struct ath_hal *ah, uint8_t coverageclass, int now) +{ +} + +/* + * Control Adaptive Noise Immunity Parameters + */ +HAL_BOOL +ar5211AniControl(struct ath_hal *ah, HAL_ANI_CMD cmd, int param) +{ + return AH_FALSE; +} + +void +ar5211AniPoll(struct ath_hal *ah, const HAL_NODE_STATS *stats, HAL_CHANNEL *chan) +{ +} + +void +ar5211MibEvent(struct ath_hal *ah, const HAL_NODE_STATS *stats) +{ +} + +/* + * Get the rssi of frame curently being received. + */ +uint32_t +ar5211GetCurRssi(struct ath_hal *ah) +{ + return (OS_REG_READ(ah, AR_PHY_CURRENT_RSSI) & 0xff); +} + +u_int +ar5211GetDefAntenna(struct ath_hal *ah) +{ + return (OS_REG_READ(ah, AR_DEF_ANTENNA) & 0x7); +} + +void +ar5211SetDefAntenna(struct ath_hal *ah, u_int antenna) +{ + OS_REG_WRITE(ah, AR_DEF_ANTENNA, (antenna & 0x7)); +} + +HAL_ANT_SETTING +ar5211GetAntennaSwitch(struct ath_hal *ah) +{ + return AH5211(ah)->ah_diversityControl; +} + +HAL_BOOL +ar5211SetAntennaSwitch(struct ath_hal *ah, HAL_ANT_SETTING settings) +{ + const HAL_CHANNEL *chan = + (const HAL_CHANNEL *) AH_PRIVATE(ah)->ah_curchan; + + if (chan == AH_NULL) { + AH5211(ah)->ah_diversityControl = settings; + return AH_TRUE; + } + return ar5211SetAntennaSwitchInternal(ah, settings, chan); +} + +HAL_STATUS +ar5211GetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, + uint32_t capability, uint32_t *result) +{ + + switch (type) { + case HAL_CAP_CIPHER: /* cipher handled in hardware */ + switch (capability) { + case HAL_CIPHER_AES_OCB: + case HAL_CIPHER_WEP: + case HAL_CIPHER_CLR: + return HAL_OK; + default: + return HAL_ENOTSUPP; + } + default: + return ath_hal_getcapability(ah, type, capability, result); + } +} + +HAL_BOOL +ar5211SetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, + uint32_t capability, uint32_t setting, HAL_STATUS *status) +{ + switch (type) { + case HAL_CAP_DIAG: /* hardware diagnostic support */ + /* + * NB: could split this up into virtual capabilities, + * (e.g. 1 => ACK, 2 => CTS, etc.) but it hardly + * seems worth the additional complexity. + */ +#ifdef AH_DEBUG + AH_PRIVATE(ah)->ah_diagreg = setting; +#else + AH_PRIVATE(ah)->ah_diagreg = setting & 0x6; /* ACK+CTS */ +#endif + OS_REG_WRITE(ah, AR_DIAG_SW, AH_PRIVATE(ah)->ah_diagreg); + return AH_TRUE; + default: + return ath_hal_setcapability(ah, type, capability, + setting, status); + } +} + +HAL_BOOL +ar5211GetDiagState(struct ath_hal *ah, int request, + const void *args, uint32_t argsize, + void **result, uint32_t *resultsize) +{ + struct ath_hal_5211 *ahp = AH5211(ah); + + (void) ahp; + if (ath_hal_getdiagstate(ah, request, args, argsize, result, resultsize)) + return AH_TRUE; + switch (request) { + case HAL_DIAG_EEPROM: + return ath_hal_eepromDiag(ah, request, + args, argsize, result, resultsize); + case HAL_DIAG_RFGAIN: + *result = &ahp->ah_gainValues; + *resultsize = sizeof(GAIN_VALUES); + return AH_TRUE; + case HAL_DIAG_RFGAIN_CURSTEP: + *result = __DECONST(void *, ahp->ah_gainValues.currStep); + *resultsize = (*result == AH_NULL) ? + 0 : sizeof(GAIN_OPTIMIZATION_STEP); + return AH_TRUE; + } + return AH_FALSE; +} --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5211/ar5211_phy.c 2009-03-23 17:36:55.000000000 +0000 @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2006 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ar5211_phy.c,v 1.1 2009/03/23 17:14:47 sborrill Exp $ + */ +#include "opt_ah.h" + +#include "ah.h" +#include "ah_internal.h" + +#include "ar5211/ar5211.h" + +/* shorthands to compact tables for readability */ +#define OFDM IEEE80211_T_OFDM +#define CCK IEEE80211_T_CCK +#define TURBO IEEE80211_T_TURBO + +HAL_RATE_TABLE ar5211_11a_table = { + 8, /* number of rates */ + { 0 }, + { +/* short ctrl */ +/* valid rateCode Preamble dot11Rate Rate */ +/* 6 Mb */ { AH_TRUE, OFDM, 6000, 0x0b, 0x00, (0x80|12), 0, 0, 0 }, +/* 9 Mb */ { AH_TRUE, OFDM, 9000, 0x0f, 0x00, 18, 0, 0, 0 }, +/* 12 Mb */ { AH_TRUE, OFDM, 12000, 0x0a, 0x00, (0x80|24), 2, 0, 0 }, +/* 18 Mb */ { AH_TRUE, OFDM, 18000, 0x0e, 0x00, 36, 2, 0, 0 }, +/* 24 Mb */ { AH_TRUE, OFDM, 24000, 0x09, 0x00, (0x80|48), 4, 0, 0 }, +/* 36 Mb */ { AH_TRUE, OFDM, 36000, 0x0d, 0x00, 72, 4, 0, 0 }, +/* 48 Mb */ { AH_TRUE, OFDM, 48000, 0x08, 0x00, 96, 4, 0, 0 }, +/* 54 Mb */ { AH_TRUE, OFDM, 54000, 0x0c, 0x00, 108, 4, 0, 0 } + }, +}; + +HAL_RATE_TABLE ar5211_turbo_table = { + 8, /* number of rates */ + { 0 }, + { +/* short ctrl */ +/* valid rateCode Preamble dot11Rate Rate */ +/* 6 Mb */ { AH_TRUE, TURBO, 6000, 0x0b, 0x00, (0x80|12), 0, 0, 0 }, +/* 9 Mb */ { AH_TRUE, TURBO, 9000, 0x0f, 0x00, 18, 0, 0, 0 }, +/* 12 Mb */ { AH_TRUE, TURBO, 12000, 0x0a, 0x00, (0x80|24), 2, 0, 0 }, +/* 18 Mb */ { AH_TRUE, TURBO, 18000, 0x0e, 0x00, 36, 2, 0, 0 }, +/* 24 Mb */ { AH_TRUE, TURBO, 24000, 0x09, 0x00, (0x80|48), 4, 0, 0 }, +/* 36 Mb */ { AH_TRUE, TURBO, 36000, 0x0d, 0x00, 72, 4, 0, 0 }, +/* 48 Mb */ { AH_TRUE, TURBO, 48000, 0x08, 0x00, 96, 4, 0, 0 }, +/* 54 Mb */ { AH_TRUE, TURBO, 54000, 0x0c, 0x00, 108, 4, 0, 0 } + }, +}; + +HAL_RATE_TABLE ar5211_11b_table = { + 4, /* number of rates */ + { 0 }, + { +/* short ctrl */ +/* valid rateCode Preamble dot11Rate Rate */ +/* 1 Mb */ { AH_TRUE, CCK, 1000, 0x0b, 0x00, (0x80| 2), 0, 0, 0 }, +/* 2 Mb */ { AH_TRUE, CCK, 2000, 0x0a, 0x04, (0x80| 4), 1, 0, 0 }, +/* 5.5 Mb */ { AH_TRUE, CCK, 5500, 0x09, 0x04, (0x80|11), 1, 0, 0 }, +/* 11 Mb */ { AH_TRUE, CCK, 11000, 0x08, 0x04, (0x80|22), 1, 0, 0 } + }, +}; + +#undef OFDM +#undef CCK +#undef TURBO + + +const HAL_RATE_TABLE * +ar5211GetRateTable(struct ath_hal *ah, u_int mode) +{ + HAL_RATE_TABLE *rt; + switch (mode) { + case HAL_MODE_11A: + rt = &ar5211_11a_table; + break; + case HAL_MODE_11B: + rt = &ar5211_11b_table; + break; + case HAL_MODE_TURBO: + rt = &ar5211_turbo_table; + break; + default: + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid mode 0x%x\n", + __func__, mode); + return AH_NULL; + } + ath_hal_setupratetable(ah, rt); + return rt; +} --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5211/ar5211_power.c 2009-03-23 17:36:55.000000000 +0000 @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2006 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ar5211_power.c,v 1.1 2009/03/23 17:14:47 sborrill Exp $ + */ +#include "opt_ah.h" + +#include "ah.h" +#include "ah_internal.h" + +#include "ar5211/ar5211.h" +#include "ar5211/ar5211reg.h" +#include "ar5211/ar5211desc.h" + +/* + * Notify Power Mgt is enabled in self-generated frames. + * If requested, force chip awake. + * + * Returns A_OK if chip is awake or successfully forced awake. + * + * WARNING WARNING WARNING + * There is a problem with the chip where sometimes it will not wake up. + */ +static HAL_BOOL +ar5211SetPowerModeAwake(struct ath_hal *ah, int setChip) +{ +#define POWER_UP_TIME 2000 + uint32_t val; + int i; + + if (setChip) { + OS_REG_RMW_FIELD(ah, AR_SCR, AR_SCR_SLE, AR_SCR_SLE_WAKE); + OS_DELAY(10); /* Give chip the chance to awake */ + + for (i = POWER_UP_TIME / 200; i != 0; i--) { + val = OS_REG_READ(ah, AR_PCICFG); + if ((val & AR_PCICFG_SPWR_DN) == 0) + break; + OS_DELAY(200); + OS_REG_RMW_FIELD(ah, AR_SCR, AR_SCR_SLE, + AR_SCR_SLE_WAKE); + } + if (i == 0) { +#ifdef AH_DEBUG + ath_hal_printf(ah, "%s: Failed to wakeup in %ums\n", + __func__, POWER_UP_TIME/20); +#endif + return AH_FALSE; + } + } + + OS_REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); + return AH_TRUE; +#undef POWER_UP_TIME +} + +/* + * Notify Power Mgt is disabled in self-generated frames. + * If requested, force chip to sleep. + */ +static void +ar5211SetPowerModeSleep(struct ath_hal *ah, int setChip) +{ + OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); + if (setChip) + OS_REG_RMW_FIELD(ah, AR_SCR, AR_SCR_SLE, AR_SCR_SLE_SLP); +} + +/* + * Notify Power Management is enabled in self-generating + * fames. If request, set power mode of chip to + * auto/normal. Duration in units of 128us (1/8 TU). + */ +static void +ar5211SetPowerModeNetworkSleep(struct ath_hal *ah, int setChip) +{ + OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); + if (setChip) + OS_REG_RMW_FIELD(ah, AR_SCR, AR_SCR_SLE, AR_SCR_SLE_NORM); +} + +HAL_BOOL +ar5211SetPowerMode(struct ath_hal *ah, HAL_POWER_MODE mode, int setChip) +{ + struct ath_hal_5211 *ahp = AH5211(ah); +#ifdef AH_DEBUG + static const char* modes[] = { + "AWAKE", + "FULL-SLEEP", + "NETWORK SLEEP", + "UNDEFINED" + }; +#endif + int status = AH_TRUE; + + HALDEBUG(ah, HAL_DEBUG_POWER, "%s: %s -> %s (%s)\n", __func__, + modes[ahp->ah_powerMode], modes[mode], + setChip ? "set chip " : ""); + switch (mode) { + case HAL_PM_AWAKE: + status = ar5211SetPowerModeAwake(ah, setChip); + break; + case HAL_PM_FULL_SLEEP: + ar5211SetPowerModeSleep(ah, setChip); + break; + case HAL_PM_NETWORK_SLEEP: + ar5211SetPowerModeNetworkSleep(ah, setChip); + break; + default: + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unknown power mode %u\n", + __func__, mode); + return AH_FALSE; + } + ahp->ah_powerMode = mode; + return status; +} + +HAL_POWER_MODE +ar5211GetPowerMode(struct ath_hal *ah) +{ + /* Just so happens the h/w maps directly to the abstracted value */ + return MS(OS_REG_READ(ah, AR_SCR), AR_SCR_SLE); +} --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5211/ar5211_recv.c 2009-03-23 17:36:55.000000000 +0000 @@ -0,0 +1,245 @@ +/* + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2006 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ar5211_recv.c,v 1.1 2009/03/23 17:14:47 sborrill Exp $ + */ +#include "opt_ah.h" + +#include "ah.h" +#include "ah_internal.h" +#include "ah_desc.h" + +#include "ar5211/ar5211.h" +#include "ar5211/ar5211reg.h" +#include "ar5211/ar5211desc.h" + +/* + * Get the RXDP. + */ +uint32_t +ar5211GetRxDP(struct ath_hal *ah) +{ + return OS_REG_READ(ah, AR_RXDP); +} + +/* + * Set the RxDP. + */ +void +ar5211SetRxDP(struct ath_hal *ah, uint32_t rxdp) +{ + OS_REG_WRITE(ah, AR_RXDP, rxdp); + HALASSERT(OS_REG_READ(ah, AR_RXDP) == rxdp); +} + + +/* + * Set Receive Enable bits. + */ +void +ar5211EnableReceive(struct ath_hal *ah) +{ + OS_REG_WRITE(ah, AR_CR, AR_CR_RXE); +} + +/* + * Stop Receive at the DMA engine + */ +HAL_BOOL +ar5211StopDmaReceive(struct ath_hal *ah) +{ + OS_REG_WRITE(ah, AR_CR, AR_CR_RXD); /* Set receive disable bit */ + if (!ath_hal_wait(ah, AR_CR, AR_CR_RXE, 0)) { +#ifdef AH_DEBUG + ath_hal_printf(ah, "%s failed to stop in 10ms\n" + "AR_CR=0x%08X\nAR_DIAG_SW=0x%08X\n" + , __func__ + , OS_REG_READ(ah, AR_CR) + , OS_REG_READ(ah, AR_DIAG_SW) + ); +#endif + return AH_FALSE; + } else { + return AH_TRUE; + } +} + +/* + * Start Transmit at the PCU engine (unpause receive) + */ +void +ar5211StartPcuReceive(struct ath_hal *ah) +{ + OS_REG_WRITE(ah, AR_DIAG_SW, + OS_REG_READ(ah, AR_DIAG_SW) & ~(AR_DIAG_SW_DIS_RX)); +} + +/* + * Stop Transmit at the PCU engine (pause receive) + */ +void +ar5211StopPcuReceive(struct ath_hal *ah) +{ + OS_REG_WRITE(ah, AR_DIAG_SW, + OS_REG_READ(ah, AR_DIAG_SW) | AR_DIAG_SW_DIS_RX); +} + +/* + * Set multicast filter 0 (lower 32-bits) + * filter 1 (upper 32-bits) + */ +void +ar5211SetMulticastFilter(struct ath_hal *ah, uint32_t filter0, uint32_t filter1) +{ + OS_REG_WRITE(ah, AR_MCAST_FIL0, filter0); + OS_REG_WRITE(ah, AR_MCAST_FIL1, filter1); +} + +/* + * Clear multicast filter by index + */ +HAL_BOOL +ar5211ClrMulticastFilterIndex(struct ath_hal *ah, uint32_t ix) +{ + uint32_t val; + + if (ix >= 64) + return AH_FALSE; + if (ix >= 32) { + val = OS_REG_READ(ah, AR_MCAST_FIL1); + OS_REG_WRITE(ah, AR_MCAST_FIL1, (val &~ (1<<(ix-32)))); + } else { + val = OS_REG_READ(ah, AR_MCAST_FIL0); + OS_REG_WRITE(ah, AR_MCAST_FIL0, (val &~ (1<= 64) + return AH_FALSE; + if (ix >= 32) { + val = OS_REG_READ(ah, AR_MCAST_FIL1); + OS_REG_WRITE(ah, AR_MCAST_FIL1, (val | (1<<(ix-32)))); + } else { + val = OS_REG_READ(ah, AR_MCAST_FIL0); + OS_REG_WRITE(ah, AR_MCAST_FIL0, (val | (1<ds_ctl0 = 0; + ads->ds_ctl1 = size & AR_BufLen; + if (ads->ds_ctl1 != size) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: buffer size %u too large\n", + __func__, size); + return AH_FALSE; + } + if (flags & HAL_RXDESC_INTREQ) + ads->ds_ctl1 |= AR_RxInterReq; + ads->ds_status0 = ads->ds_status1 = 0; + + return AH_TRUE; +} + +/* + * Process an RX descriptor, and return the status to the caller. + * Copy some hardware specific items into the software portion + * of the descriptor. + * + * NB: the caller is responsible for validating the memory contents + * of the descriptor (e.g. flushing any cached copy). + */ +HAL_STATUS +ar5211ProcRxDesc(struct ath_hal *ah, struct ath_desc *ds, + uint32_t pa, struct ath_desc *nds, uint64_t tsf, + struct ath_rx_status *rs) +{ + struct ar5211_desc *ads = AR5211DESC(ds); + struct ar5211_desc *ands = AR5211DESC(nds); + + if ((ads->ds_status1 & AR_Done) == 0) + return HAL_EINPROGRESS; + /* + * Given the use of a self-linked tail be very sure that the hw is + * done with this descriptor; the hw may have done this descriptor + * once and picked it up again...make sure the hw has moved on. + */ + if ((ands->ds_status1 & AR_Done) == 0 && OS_REG_READ(ah, AR_RXDP) == pa) + return HAL_EINPROGRESS; + + rs->rs_datalen = ads->ds_status0 & AR_DataLen; + rs->rs_tstamp = MS(ads->ds_status1, AR_RcvTimestamp); + rs->rs_status = 0; + if ((ads->ds_status1 & AR_FrmRcvOK) == 0) { + if (ads->ds_status1 & AR_CRCErr) + rs->rs_status |= HAL_RXERR_CRC; + else if (ads->ds_status1 & AR_DecryptCRCErr) + rs->rs_status |= HAL_RXERR_DECRYPT; + else { + rs->rs_status |= HAL_RXERR_PHY; + rs->rs_phyerr = MS(ads->ds_status1, AR_PHYErr); + } + } + /* XXX what about KeyCacheMiss? */ + rs->rs_rssi = MS(ads->ds_status0, AR_RcvSigStrength); + if (ads->ds_status1 & AR_KeyIdxValid) + rs->rs_keyix = MS(ads->ds_status1, AR_KeyIdx); + else + rs->rs_keyix = HAL_RXKEYIX_INVALID; + /* NB: caller expected to do rate table mapping */ + rs->rs_rate = MS(ads->ds_status0, AR_RcvRate); + rs->rs_antenna = MS(ads->ds_status0, AR_RcvAntenna); + rs->rs_more = (ads->ds_status0 & AR_More) ? 1 : 0; + + return HAL_OK; +} --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5211/ar5211_reset.c 2009-03-23 17:36:55.000000000 +0000 @@ -0,0 +1,2140 @@ +/* + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2006 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ar5211_reset.c,v 1.1 2009/03/23 17:14:47 sborrill Exp $ + */ +#include "opt_ah.h" + +/* + * Chips specific device attachment and device info collection + * Connects Init Reg Vectors, EEPROM Data, and device Functions. + */ +#include "ah.h" +#include "ah_internal.h" +#include "ah_devid.h" + +#include "ar5211/ar5211.h" +#include "ar5211/ar5211reg.h" +#include "ar5211/ar5211phy.h" + +#include "ah_eeprom_v3.h" + +/* Add static register initialization vectors */ +#include "ar5211/boss.ini" + +/* + * Structure to hold 11b tuning information for Beanie/Sombrero + * 16 MHz mode, divider ratio = 198 = NP+S. N=16, S=4 or 6, P=12 + */ +typedef struct { + uint32_t refClkSel; /* reference clock, 1 for 16 MHz */ + uint32_t channelSelect; /* P[7:4]S[3:0] bits */ + uint16_t channel5111; /* 11a channel for 5111 */ +} CHAN_INFO_2GHZ; + +#define CI_2GHZ_INDEX_CORRECTION 19 +static const CHAN_INFO_2GHZ chan2GHzData[] = { + { 1, 0x46, 96 }, /* 2312 -19 */ + { 1, 0x46, 97 }, /* 2317 -18 */ + { 1, 0x46, 98 }, /* 2322 -17 */ + { 1, 0x46, 99 }, /* 2327 -16 */ + { 1, 0x46, 100 }, /* 2332 -15 */ + { 1, 0x46, 101 }, /* 2337 -14 */ + { 1, 0x46, 102 }, /* 2342 -13 */ + { 1, 0x46, 103 }, /* 2347 -12 */ + { 1, 0x46, 104 }, /* 2352 -11 */ + { 1, 0x46, 105 }, /* 2357 -10 */ + { 1, 0x46, 106 }, /* 2362 -9 */ + { 1, 0x46, 107 }, /* 2367 -8 */ + { 1, 0x46, 108 }, /* 2372 -7 */ + /* index -6 to 0 are pad to make this a nolookup table */ + { 1, 0x46, 116 }, /* -6 */ + { 1, 0x46, 116 }, /* -5 */ + { 1, 0x46, 116 }, /* -4 */ + { 1, 0x46, 116 }, /* -3 */ + { 1, 0x46, 116 }, /* -2 */ + { 1, 0x46, 116 }, /* -1 */ + { 1, 0x46, 116 }, /* 0 */ + { 1, 0x46, 116 }, /* 2412 1 */ + { 1, 0x46, 117 }, /* 2417 2 */ + { 1, 0x46, 118 }, /* 2422 3 */ + { 1, 0x46, 119 }, /* 2427 4 */ + { 1, 0x46, 120 }, /* 2432 5 */ + { 1, 0x46, 121 }, /* 2437 6 */ + { 1, 0x46, 122 }, /* 2442 7 */ + { 1, 0x46, 123 }, /* 2447 8 */ + { 1, 0x46, 124 }, /* 2452 9 */ + { 1, 0x46, 125 }, /* 2457 10 */ + { 1, 0x46, 126 }, /* 2462 11 */ + { 1, 0x46, 127 }, /* 2467 12 */ + { 1, 0x46, 128 }, /* 2472 13 */ + { 1, 0x44, 124 }, /* 2484 14 */ + { 1, 0x46, 136 }, /* 2512 15 */ + { 1, 0x46, 140 }, /* 2532 16 */ + { 1, 0x46, 144 }, /* 2552 17 */ + { 1, 0x46, 148 }, /* 2572 18 */ + { 1, 0x46, 152 }, /* 2592 19 */ + { 1, 0x46, 156 }, /* 2612 20 */ + { 1, 0x46, 160 }, /* 2632 21 */ + { 1, 0x46, 164 }, /* 2652 22 */ + { 1, 0x46, 168 }, /* 2672 23 */ + { 1, 0x46, 172 }, /* 2692 24 */ + { 1, 0x46, 176 }, /* 2712 25 */ + { 1, 0x46, 180 } /* 2732 26 */ +}; + +/* Power timeouts in usec to wait for chip to wake-up. */ +#define POWER_UP_TIME 2000 + +#define DELAY_PLL_SETTLE 300 /* 300 us */ +#define DELAY_BASE_ACTIVATE 100 /* 100 us */ + +#define NUM_RATES 8 + +static HAL_BOOL ar5211SetResetReg(struct ath_hal *ah, uint32_t resetMask); +static HAL_BOOL ar5211SetChannel(struct ath_hal *, HAL_CHANNEL_INTERNAL *); +static int16_t ar5211RunNoiseFloor(struct ath_hal *, + uint8_t runTime, int16_t startingNF); +static HAL_BOOL ar5211IsNfGood(struct ath_hal *, HAL_CHANNEL_INTERNAL *chan); +static HAL_BOOL ar5211SetRf6and7(struct ath_hal *, HAL_CHANNEL *chan); +static HAL_BOOL ar5211SetBoardValues(struct ath_hal *, HAL_CHANNEL *chan); +static void ar5211SetPowerTable(struct ath_hal *, + PCDACS_EEPROM *pSrcStruct, uint16_t channel); +static void ar5211SetRateTable(struct ath_hal *, + RD_EDGES_POWER *pRdEdgesPower, TRGT_POWER_INFO *pPowerInfo, + uint16_t numChannels, HAL_CHANNEL *chan); +static uint16_t ar5211GetScaledPower(uint16_t channel, uint16_t pcdacValue, + const PCDACS_EEPROM *pSrcStruct); +static HAL_BOOL ar5211FindValueInList(uint16_t channel, uint16_t pcdacValue, + const PCDACS_EEPROM *pSrcStruct, uint16_t *powerValue); +static uint16_t ar5211GetInterpolatedValue(uint16_t target, + uint16_t srcLeft, uint16_t srcRight, + uint16_t targetLeft, uint16_t targetRight, HAL_BOOL scaleUp); +static void ar5211GetLowerUpperValues(uint16_t value, + const uint16_t *pList, uint16_t listSize, + uint16_t *pLowerValue, uint16_t *pUpperValue); +static void ar5211GetLowerUpperPcdacs(uint16_t pcdac, + uint16_t channel, const PCDACS_EEPROM *pSrcStruct, + uint16_t *pLowerPcdac, uint16_t *pUpperPcdac); + +static void ar5211SetRfgain(struct ath_hal *, const GAIN_VALUES *);; +static void ar5211RequestRfgain(struct ath_hal *); +static HAL_BOOL ar5211InvalidGainReadback(struct ath_hal *, GAIN_VALUES *); +static HAL_BOOL ar5211IsGainAdjustNeeded(struct ath_hal *, const GAIN_VALUES *); +static int32_t ar5211AdjustGain(struct ath_hal *, GAIN_VALUES *); +static void ar5211SetOperatingMode(struct ath_hal *, int opmode); + +/* + * Places the device in and out of reset and then places sane + * values in the registers based on EEPROM config, initialization + * vectors (as determined by the mode), and station configuration + * + * bChannelChange is used to preserve DMA/PCU registers across + * a HW Reset during channel change. + */ +HAL_BOOL +ar5211Reset(struct ath_hal *ah, HAL_OPMODE opmode, + HAL_CHANNEL *chan, HAL_BOOL bChannelChange, HAL_STATUS *status) +{ +uint32_t softLedCfg, softLedState; +#define N(a) (sizeof (a) /sizeof (a[0])) +#define FAIL(_code) do { ecode = _code; goto bad; } while (0) + struct ath_hal_5211 *ahp = AH5211(ah); + HAL_CHANNEL_INTERNAL *ichan; + uint32_t i, ledstate; + HAL_STATUS ecode; + int q; + + uint32_t data, synthDelay; + uint32_t macStaId1; + uint16_t modesIndex = 0, freqIndex = 0; + uint32_t saveFrameSeqCount[AR_NUM_DCU]; + uint32_t saveTsfLow = 0, saveTsfHigh = 0; + uint32_t saveDefAntenna; + + HALDEBUG(ah, HAL_DEBUG_RESET, + "%s: opmode %u channel %u/0x%x %s channel\n", + __func__, opmode, chan->channel, chan->channelFlags, + bChannelChange ? "change" : "same"); + + OS_MARK(ah, AH_MARK_RESET, bChannelChange); +#define IS(_c,_f) (((_c)->channelFlags & _f) || 0) + if ((IS(chan, CHANNEL_2GHZ) ^ IS(chan,CHANNEL_5GHZ)) == 0) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: invalid channel %u/0x%x; not marked as 2GHz or 5GHz\n", + __func__, chan->channel, chan->channelFlags); + FAIL(HAL_EINVAL); + } + if ((IS(chan, CHANNEL_OFDM) ^ IS(chan, CHANNEL_CCK)) == 0) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: invalid channel %u/0x%x; not marked as OFDM or CCK\n", + __func__, chan->channel, chan->channelFlags); + FAIL(HAL_EINVAL); + } +#undef IS + /* + * Map public channel to private. + */ + ichan = ath_hal_checkchannel(ah, chan); + if (ichan == AH_NULL) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: invalid channel %u/0x%x; no mapping\n", + __func__, chan->channel, chan->channelFlags); + FAIL(HAL_EINVAL); + } + switch (opmode) { + case HAL_M_STA: + case HAL_M_IBSS: + case HAL_M_HOSTAP: + case HAL_M_MONITOR: + break; + default: + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: invalid operating mode %u\n", __func__, opmode); + FAIL(HAL_EINVAL); + break; + } + HALASSERT(AH_PRIVATE(ah)->ah_eeversion >= AR_EEPROM_VER3); + + /* Preserve certain DMA hardware registers on a channel change */ + if (bChannelChange) { + /* + * Need to save/restore the TSF because of an issue + * that accelerates the TSF during a chip reset. + * + * We could use system timer routines to more + * accurately restore the TSF, but + * 1. Timer routines on certain platforms are + * not accurate enough (e.g. 1 ms resolution). + * 2. It would still not be accurate. + * + * The most important aspect of this workaround, + * is that, after reset, the TSF is behind + * other STAs TSFs. This will allow the STA to + * properly resynchronize its TSF in adhoc mode. + */ + saveTsfLow = OS_REG_READ(ah, AR_TSF_L32); + saveTsfHigh = OS_REG_READ(ah, AR_TSF_U32); + + /* Read frame sequence count */ + if (AH_PRIVATE(ah)->ah_macVersion >= AR_SREV_VERSION_OAHU) { + saveFrameSeqCount[0] = OS_REG_READ(ah, AR_D0_SEQNUM); + } else { + for (i = 0; i < AR_NUM_DCU; i++) + saveFrameSeqCount[i] = OS_REG_READ(ah, AR_DSEQNUM(i)); + } + if (!(ichan->privFlags & CHANNEL_DFS)) + ichan->privFlags &= ~CHANNEL_INTERFERENCE; + chan->channelFlags = ichan->channelFlags; + chan->privFlags = ichan->privFlags; + } + + /* + * Preserve the antenna on a channel change + */ + saveDefAntenna = OS_REG_READ(ah, AR_DEF_ANTENNA); + if (saveDefAntenna == 0) + saveDefAntenna = 1; + + /* Save hardware flag before chip reset clears the register */ + macStaId1 = OS_REG_READ(ah, AR_STA_ID1) & AR_STA_ID1_BASE_RATE_11B; + + /* Save led state from pci config register */ + ledstate = OS_REG_READ(ah, AR_PCICFG) & + (AR_PCICFG_LEDCTL | AR_PCICFG_LEDMODE | AR_PCICFG_LEDBLINK | + AR_PCICFG_LEDSLOW); + softLedCfg = OS_REG_READ(ah, AR_GPIOCR); + softLedState = OS_REG_READ(ah, AR_GPIODO); + + if (!ar5211ChipReset(ah, chan->channelFlags)) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: chip reset failed\n", __func__); + FAIL(HAL_EIO); + } + + /* Setup the indices for the next set of register array writes */ + switch (chan->channelFlags & CHANNEL_ALL) { + case CHANNEL_A: + modesIndex = 1; + freqIndex = 1; + break; + case CHANNEL_T: + modesIndex = 2; + freqIndex = 1; + break; + case CHANNEL_B: + modesIndex = 3; + freqIndex = 2; + break; + case CHANNEL_PUREG: + modesIndex = 4; + freqIndex = 2; + break; + default: + /* Ah, a new wireless mode */ + HALASSERT(0); + break; + } + + /* Set correct Baseband to analog shift setting to access analog chips. */ + if (AH_PRIVATE(ah)->ah_macVersion >= AR_SREV_VERSION_OAHU) { + OS_REG_WRITE(ah, AR_PHY_BASE, 0x00000007); + } else { + OS_REG_WRITE(ah, AR_PHY_BASE, 0x00000047); + } + + /* Write parameters specific to AR5211 */ + if (AH_PRIVATE(ah)->ah_macVersion >= AR_SREV_VERSION_OAHU) { + if (IS_CHAN_2GHZ(chan) && + AH_PRIVATE(ah)->ah_eeversion >= AR_EEPROM_VER3_1) { + HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom; + uint32_t ob2GHz, db2GHz; + + if (IS_CHAN_CCK(chan)) { + ob2GHz = ee->ee_ob2GHz[0]; + db2GHz = ee->ee_db2GHz[0]; + } else { + ob2GHz = ee->ee_ob2GHz[1]; + db2GHz = ee->ee_db2GHz[1]; + } + ob2GHz = ath_hal_reverseBits(ob2GHz, 3); + db2GHz = ath_hal_reverseBits(db2GHz, 3); + ar5211Mode2_4[25][freqIndex] = + (ar5211Mode2_4[25][freqIndex] & ~0xC0) | + ((ob2GHz << 6) & 0xC0); + ar5211Mode2_4[26][freqIndex] = + (ar5211Mode2_4[26][freqIndex] & ~0x0F) | + (((ob2GHz >> 2) & 0x1) | + ((db2GHz << 1) & 0x0E)); + } + for (i = 0; i < N(ar5211Mode2_4); i++) + OS_REG_WRITE(ah, ar5211Mode2_4[i][0], + ar5211Mode2_4[i][freqIndex]); + } + + /* Write the analog registers 6 and 7 before other config */ + ar5211SetRf6and7(ah, chan); + + /* Write registers that vary across all modes */ + for (i = 0; i < N(ar5211Modes); i++) + OS_REG_WRITE(ah, ar5211Modes[i][0], ar5211Modes[i][modesIndex]); + + /* Write RFGain Parameters that differ between 2.4 and 5 GHz */ + for (i = 0; i < N(ar5211BB_RfGain); i++) + OS_REG_WRITE(ah, ar5211BB_RfGain[i][0], ar5211BB_RfGain[i][freqIndex]); + + /* Write Common Array Parameters */ + for (i = 0; i < N(ar5211Common); i++) { + uint32_t reg = ar5211Common[i][0]; + /* On channel change, don't reset the PCU registers */ + if (!(bChannelChange && (0x8000 <= reg && reg < 0x9000))) + OS_REG_WRITE(ah, reg, ar5211Common[i][1]); + } + + /* Fix pre-AR5211 register values, this includes AR5311s. */ + if (AH_PRIVATE(ah)->ah_macVersion < AR_SREV_VERSION_OAHU) { + /* + * The TX and RX latency values have changed locations + * within the USEC register in AR5211. Since they're + * set via the .ini, for both AR5211 and AR5311, they + * are written properly here for AR5311. + */ + data = OS_REG_READ(ah, AR_USEC); + /* Must be 0 for proper write in AR5311 */ + HALASSERT((data & 0x00700000) == 0); + OS_REG_WRITE(ah, AR_USEC, + (data & (AR_USEC_M | AR_USEC_32_M | AR5311_USEC_TX_LAT_M)) | + ((29 << AR5311_USEC_RX_LAT_S) & AR5311_USEC_RX_LAT_M)); + /* The following registers exist only on AR5311. */ + OS_REG_WRITE(ah, AR5311_QDCLKGATE, 0); + + /* Set proper ADC & DAC delays for AR5311. */ + OS_REG_WRITE(ah, 0x00009878, 0x00000008); + + /* Enable the PCU FIFO corruption ECO on AR5311. */ + OS_REG_WRITE(ah, AR_DIAG_SW, + OS_REG_READ(ah, AR_DIAG_SW) | AR5311_DIAG_SW_USE_ECO); + } + + /* Restore certain DMA hardware registers on a channel change */ + if (bChannelChange) { + /* Restore TSF */ + OS_REG_WRITE(ah, AR_TSF_L32, saveTsfLow); + OS_REG_WRITE(ah, AR_TSF_U32, saveTsfHigh); + + if (AH_PRIVATE(ah)->ah_macVersion >= AR_SREV_VERSION_OAHU) { + OS_REG_WRITE(ah, AR_D0_SEQNUM, saveFrameSeqCount[0]); + } else { + for (i = 0; i < AR_NUM_DCU; i++) + OS_REG_WRITE(ah, AR_DSEQNUM(i), saveFrameSeqCount[i]); + } + } + + OS_REG_WRITE(ah, AR_STA_ID0, LE_READ_4(ahp->ah_macaddr)); + OS_REG_WRITE(ah, AR_STA_ID1, LE_READ_2(ahp->ah_macaddr + 4) + | macStaId1 + ); + ar5211SetOperatingMode(ah, opmode); + + /* Restore previous led state */ + OS_REG_WRITE(ah, AR_PCICFG, OS_REG_READ(ah, AR_PCICFG) | ledstate); + OS_REG_WRITE(ah, AR_GPIOCR, softLedCfg); + OS_REG_WRITE(ah, AR_GPIODO, softLedState); + + /* Restore previous antenna */ + OS_REG_WRITE(ah, AR_DEF_ANTENNA, saveDefAntenna); + + OS_REG_WRITE(ah, AR_BSS_ID0, LE_READ_4(ahp->ah_bssid)); + OS_REG_WRITE(ah, AR_BSS_ID1, LE_READ_2(ahp->ah_bssid + 4)); + + /* Restore bmiss rssi & count thresholds */ + OS_REG_WRITE(ah, AR_RSSI_THR, ahp->ah_rssiThr); + + OS_REG_WRITE(ah, AR_ISR, ~0); /* cleared on write */ + + /* + * for pre-Production Oahu only. + * Disable clock gating in all DMA blocks. Helps when using + * 11B and AES but results in higher power consumption. + */ + if (AH_PRIVATE(ah)->ah_macVersion == AR_SREV_VERSION_OAHU && + AH_PRIVATE(ah)->ah_macRev < AR_SREV_OAHU_PROD) { + OS_REG_WRITE(ah, AR_CFG, + OS_REG_READ(ah, AR_CFG) | AR_CFG_CLK_GATE_DIS); + } + + /* Setup the transmit power values. */ + if (!ar5211SetTransmitPower(ah, chan)) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: error init'ing transmit power\n", __func__); + FAIL(HAL_EIO); + } + + /* + * Configurable OFDM spoofing for 11n compatibility; used + * only when operating in station mode. + */ + if (opmode != HAL_M_HOSTAP && + (AH_PRIVATE(ah)->ah_11nCompat & HAL_DIAG_11N_SERVICES) != 0) { + /* NB: override the .ini setting */ + OS_REG_RMW_FIELD(ah, AR_PHY_FRAME_CTL, + AR_PHY_FRAME_CTL_ERR_SERV, + MS(AH_PRIVATE(ah)->ah_11nCompat, HAL_DIAG_11N_SERVICES)&1); + } + + /* Setup board specific options for EEPROM version 3 */ + ar5211SetBoardValues(ah, chan); + + if (!ar5211SetChannel(ah, ichan)) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unable to set channel\n", + __func__); + FAIL(HAL_EIO); + } + + /* Activate the PHY */ + if (AH_PRIVATE(ah)->ah_devid == AR5211_FPGA11B && IS_CHAN_2GHZ(chan)) + OS_REG_WRITE(ah, 0xd808, 0x502); /* required for FPGA */ + OS_REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); + + /* + * Wait for the frequency synth to settle (synth goes on + * via AR_PHY_ACTIVE_EN). Read the phy active delay register. + * Value is in 100ns increments. + */ + data = OS_REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_M; + if (IS_CHAN_CCK(chan)) { + synthDelay = (4 * data) / 22; + } else { + synthDelay = data / 10; + } + /* + * There is an issue if the AP starts the calibration before + * the baseband timeout completes. This could result in the + * rxclear false triggering. Add an extra delay to ensure this + * this does not happen. + */ + OS_DELAY(synthDelay + DELAY_BASE_ACTIVATE); + + /* Calibrate the AGC and wait for completion. */ + OS_REG_WRITE(ah, AR_PHY_AGC_CONTROL, + OS_REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_CAL); + (void) ath_hal_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0); + + /* Perform noise floor and set status */ + if (!ar5211CalNoiseFloor(ah, ichan)) { + if (!IS_CHAN_CCK(chan)) + chan->channelFlags |= CHANNEL_CW_INT; + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: noise floor calibration failed\n", __func__); + FAIL(HAL_EIO); + } + + /* Start IQ calibration w/ 2^(INIT_IQCAL_LOG_COUNT_MAX+1) samples */ + if (ahp->ah_calibrationTime != 0) { + OS_REG_WRITE(ah, AR_PHY_TIMING_CTRL4, + AR_PHY_TIMING_CTRL4_DO_IQCAL | (INIT_IQCAL_LOG_COUNT_MAX << AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX_S)); + ahp->ah_bIQCalibration = AH_TRUE; + } + + /* set 1:1 QCU to DCU mapping for all queues */ + for (q = 0; q < AR_NUM_DCU; q++) + OS_REG_WRITE(ah, AR_DQCUMASK(q), 1<ah_maskReg = INIT_INTERRUPT_MASK; + + /* Enable bus error interrupts */ + OS_REG_WRITE(ah, AR_IMR_S2, OS_REG_READ(ah, AR_IMR_S2) | + AR_IMR_S2_MCABT | AR_IMR_S2_SSERR | AR_IMR_S2_DPERR); + + /* Enable interrupts specific to AP */ + if (opmode == HAL_M_HOSTAP) { + OS_REG_WRITE(ah, AR_IMR, OS_REG_READ(ah, AR_IMR) | AR_IMR_MIB); + ahp->ah_maskReg |= AR_IMR_MIB; + } + + if (AH_PRIVATE(ah)->ah_rfkillEnabled) + ar5211EnableRfKill(ah); + + /* + * Writing to AR_BEACON will start timers. Hence it should + * be the last register to be written. Do not reset tsf, do + * not enable beacons at this point, but preserve other values + * like beaconInterval. + */ + OS_REG_WRITE(ah, AR_BEACON, + (OS_REG_READ(ah, AR_BEACON) &~ (AR_BEACON_EN | AR_BEACON_RESET_TSF))); + + /* Restore user-specified slot time and timeouts */ + if (ahp->ah_sifstime != (u_int) -1) + ar5211SetSifsTime(ah, ahp->ah_sifstime); + if (ahp->ah_slottime != (u_int) -1) + ar5211SetSlotTime(ah, ahp->ah_slottime); + if (ahp->ah_acktimeout != (u_int) -1) + ar5211SetAckTimeout(ah, ahp->ah_acktimeout); + if (ahp->ah_ctstimeout != (u_int) -1) + ar5211SetCTSTimeout(ah, ahp->ah_ctstimeout); + if (AH_PRIVATE(ah)->ah_diagreg != 0) + OS_REG_WRITE(ah, AR_DIAG_SW, AH_PRIVATE(ah)->ah_diagreg); + + AH_PRIVATE(ah)->ah_opmode = opmode; /* record operating mode */ + + HALDEBUG(ah, HAL_DEBUG_RESET, "%s: done\n", __func__); + + return AH_TRUE; +bad: + if (*status) + *status = ecode; + return AH_FALSE; +#undef FAIL +#undef N +} + +/* + * Places the PHY and Radio chips into reset. A full reset + * must be called to leave this state. The PCI/MAC/PCU are + * not placed into reset as we must receive interrupt to + * re-enable the hardware. + */ +HAL_BOOL +ar5211PhyDisable(struct ath_hal *ah) +{ + return ar5211SetResetReg(ah, AR_RC_BB); +} + +/* + * Places all of hardware into reset + */ +HAL_BOOL +ar5211Disable(struct ath_hal *ah) +{ + if (!ar5211SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE)) + return AH_FALSE; + /* + * Reset the HW - PCI must be reset after the rest of the + * device has been reset. + */ + if (!ar5211SetResetReg(ah, AR_RC_MAC | AR_RC_BB | AR_RC_PCI)) + return AH_FALSE; + OS_DELAY(2100); /* 8245 @ 96Mhz hangs with 2000us. */ + + return AH_TRUE; +} + +/* + * Places the hardware into reset and then pulls it out of reset + * + * Only write the PLL if we're changing to or from CCK mode + * + * Attach calls with channelFlags = 0, as the coldreset should have + * us in the correct mode and we cannot check the hwchannel flags. + */ +HAL_BOOL +ar5211ChipReset(struct ath_hal *ah, uint16_t channelFlags) +{ + if (!ar5211SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE)) + return AH_FALSE; + + /* Set CCK and Turbo modes correctly */ + switch (channelFlags & CHANNEL_ALL) { + case CHANNEL_2GHZ|CHANNEL_CCK: + case CHANNEL_2GHZ|CHANNEL_CCK|CHANNEL_TURBO: + OS_REG_WRITE(ah, AR_PHY_TURBO, 0); + OS_REG_WRITE(ah, AR5211_PHY_MODE, + AR5211_PHY_MODE_CCK | AR5211_PHY_MODE_RF2GHZ); + OS_REG_WRITE(ah, AR_PHY_PLL_CTL, AR_PHY_PLL_CTL_44); + /* Wait for the PLL to settle */ + OS_DELAY(DELAY_PLL_SETTLE); + break; + case CHANNEL_2GHZ|CHANNEL_OFDM: + case CHANNEL_2GHZ|CHANNEL_OFDM|CHANNEL_TURBO: + OS_REG_WRITE(ah, AR_PHY_TURBO, 0); + if (AH_PRIVATE(ah)->ah_devid == AR5211_DEVID) { + OS_REG_WRITE(ah, AR_PHY_PLL_CTL, AR_PHY_PLL_CTL_40); + OS_DELAY(DELAY_PLL_SETTLE); + OS_REG_WRITE(ah, AR5211_PHY_MODE, + AR5211_PHY_MODE_OFDM | AR5211_PHY_MODE_RF2GHZ); + } + break; + case CHANNEL_A: + case CHANNEL_T: + if (channelFlags & CHANNEL_TURBO) { + OS_REG_WRITE(ah, AR_PHY_TURBO, + AR_PHY_FC_TURBO_MODE | AR_PHY_FC_TURBO_SHORT); + } else { /* 5 GHZ OFDM Mode */ + OS_REG_WRITE(ah, AR_PHY_TURBO, 0); + } + if (AH_PRIVATE(ah)->ah_devid == AR5211_DEVID) { + OS_REG_WRITE(ah, AR_PHY_PLL_CTL, AR_PHY_PLL_CTL_40); + OS_DELAY(DELAY_PLL_SETTLE); + OS_REG_WRITE(ah, AR5211_PHY_MODE, + AR5211_PHY_MODE_OFDM | AR5211_PHY_MODE_RF5GHZ); + } + break; + } + /* NB: else no flags set - must be attach calling - do nothing */ + + /* + * Reset the HW - PCI must be reset after the rest of the + * device has been reset + */ + if (!ar5211SetResetReg(ah, AR_RC_MAC | AR_RC_BB | AR_RC_PCI)) + return AH_FALSE; + OS_DELAY(2100); /* 8245 @ 96Mhz hangs with 2000us. */ + + /* Bring out of sleep mode (AGAIN) */ + if (!ar5211SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE)) + return AH_FALSE; + + /* Clear warm reset register */ + return ar5211SetResetReg(ah, 0); +} + +/* + * Recalibrate the lower PHY chips to account for temperature/environment + * changes. + */ +HAL_BOOL +ar5211PerCalibrationN(struct ath_hal *ah, HAL_CHANNEL *chan, u_int chainMask, + HAL_BOOL longCal, HAL_BOOL *isCalDone) +{ + struct ath_hal_5211 *ahp = AH5211(ah); + HAL_CHANNEL_INTERNAL *ichan; + int32_t qCoff, qCoffDenom; + uint32_t data; + int32_t iqCorrMeas; + int32_t iCoff, iCoffDenom; + uint32_t powerMeasQ, powerMeasI; + + ichan = ath_hal_checkchannel(ah, chan); + if (ichan == AH_NULL) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: invalid channel %u/0x%x; no mapping\n", + __func__, chan->channel, chan->channelFlags); + return AH_FALSE; + } + /* IQ calibration in progress. Check to see if it has finished. */ + if (ahp->ah_bIQCalibration && + !(OS_REG_READ(ah, AR_PHY_TIMING_CTRL4) & AR_PHY_TIMING_CTRL4_DO_IQCAL)) { + /* IQ Calibration has finished. */ + ahp->ah_bIQCalibration = AH_FALSE; + + /* Read calibration results. */ + powerMeasI = OS_REG_READ(ah, AR_PHY_IQCAL_RES_PWR_MEAS_I); + powerMeasQ = OS_REG_READ(ah, AR_PHY_IQCAL_RES_PWR_MEAS_Q); + iqCorrMeas = OS_REG_READ(ah, AR_PHY_IQCAL_RES_IQ_CORR_MEAS); + + /* + * Prescale these values to remove 64-bit operation requirement at the loss + * of a little precision. + */ + iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 128; + qCoffDenom = powerMeasQ / 64; + + /* Protect against divide-by-0. */ + if (iCoffDenom != 0 && qCoffDenom != 0) { + iCoff = (-iqCorrMeas) / iCoffDenom; + /* IQCORR_Q_I_COFF is a signed 6 bit number */ + iCoff = iCoff & 0x3f; + + qCoff = ((int32_t)powerMeasI / qCoffDenom) - 64; + /* IQCORR_Q_Q_COFF is a signed 5 bit number */ + qCoff = qCoff & 0x1f; + + HALDEBUG(ah, HAL_DEBUG_PERCAL, "powerMeasI = 0x%08x\n", + powerMeasI); + HALDEBUG(ah, HAL_DEBUG_PERCAL, "powerMeasQ = 0x%08x\n", + powerMeasQ); + HALDEBUG(ah, HAL_DEBUG_PERCAL, "iqCorrMeas = 0x%08x\n", + iqCorrMeas); + HALDEBUG(ah, HAL_DEBUG_PERCAL, "iCoff = %d\n", + iCoff); + HALDEBUG(ah, HAL_DEBUG_PERCAL, "qCoff = %d\n", + qCoff); + + /* Write IQ */ + data = OS_REG_READ(ah, AR_PHY_TIMING_CTRL4) | + AR_PHY_TIMING_CTRL4_IQCORR_ENABLE | + (((uint32_t)iCoff) << AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF_S) | + ((uint32_t)qCoff); + OS_REG_WRITE(ah, AR_PHY_TIMING_CTRL4, data); + } + } + *isCalDone = !ahp->ah_bIQCalibration; + + if (longCal) { + /* Perform noise floor and set status */ + if (!ar5211IsNfGood(ah, ichan)) { + /* report up and clear internal state */ + chan->channelFlags |= CHANNEL_CW_INT; + ichan->channelFlags &= ~CHANNEL_CW_INT; + return AH_FALSE; + } + if (!ar5211CalNoiseFloor(ah, ichan)) { + /* + * Delay 5ms before retrying the noise floor + * just to make sure, as we are in an error + * condition here. + */ + OS_DELAY(5000); + if (!ar5211CalNoiseFloor(ah, ichan)) { + if (!IS_CHAN_CCK(chan)) + chan->channelFlags |= CHANNEL_CW_INT; + return AH_FALSE; + } + } + ar5211RequestRfgain(ah); + } + return AH_TRUE; +} + +HAL_BOOL +ar5211PerCalibration(struct ath_hal *ah, HAL_CHANNEL *chan, HAL_BOOL *isIQdone) +{ + return ar5211PerCalibrationN(ah, chan, 0x1, AH_TRUE, isIQdone); +} + +HAL_BOOL +ar5211ResetCalValid(struct ath_hal *ah, HAL_CHANNEL *chan) +{ + /* XXX */ + return AH_TRUE; +} + +/* + * Writes the given reset bit mask into the reset register + */ +static HAL_BOOL +ar5211SetResetReg(struct ath_hal *ah, uint32_t resetMask) +{ + uint32_t mask = resetMask ? resetMask : ~0; + HAL_BOOL rt; + + (void) OS_REG_READ(ah, AR_RXDP);/* flush any pending MMR writes */ + OS_REG_WRITE(ah, AR_RC, resetMask); + + /* need to wait at least 128 clocks when reseting PCI before read */ + OS_DELAY(15); + + resetMask &= AR_RC_MAC | AR_RC_BB; + mask &= AR_RC_MAC | AR_RC_BB; + rt = ath_hal_wait(ah, AR_RC, mask, resetMask); + if ((resetMask & AR_RC_MAC) == 0) { + if (isBigEndian()) { + /* + * Set CFG, little-endian for register + * and descriptor accesses. + */ + mask = INIT_CONFIG_STATUS | + AR_CFG_SWTD | AR_CFG_SWRD | AR_CFG_SWRG; + OS_REG_WRITE(ah, AR_CFG, LE_READ_4(&mask)); + } else + OS_REG_WRITE(ah, AR_CFG, INIT_CONFIG_STATUS); + } + return rt; +} + +/* + * Takes the MHz channel value and sets the Channel value + * + * ASSUMES: Writes enabled to analog bus before AGC is active + * or by disabling the AGC. + */ +static HAL_BOOL +ar5211SetChannel(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan) +{ + uint32_t refClk, reg32, data2111; + int16_t chan5111, chanIEEE; + + chanIEEE = ath_hal_mhz2ieee(ah, chan->channel, chan->channelFlags); + if (IS_CHAN_2GHZ(chan)) { + const CHAN_INFO_2GHZ* ci = + &chan2GHzData[chanIEEE + CI_2GHZ_INDEX_CORRECTION]; + + data2111 = ((ath_hal_reverseBits(ci->channelSelect, 8) & 0xff) + << 5) + | (ci->refClkSel << 4); + chan5111 = ci->channel5111; + } else { + data2111 = 0; + chan5111 = chanIEEE; + } + + /* Rest of the code is common for 5 GHz and 2.4 GHz. */ + if (chan5111 >= 145 || (chan5111 & 0x1)) { + reg32 = ath_hal_reverseBits(chan5111 - 24, 8) & 0xFF; + refClk = 1; + } else { + reg32 = ath_hal_reverseBits(((chan5111 - 24) / 2), 8) & 0xFF; + refClk = 0; + } + + reg32 = (reg32 << 2) | (refClk << 1) | (1 << 10) | 0x1; + OS_REG_WRITE(ah, AR_PHY(0x27), ((data2111 & 0xff) << 8) | (reg32 & 0xff)); + reg32 >>= 8; + OS_REG_WRITE(ah, AR_PHY(0x34), (data2111 & 0xff00) | (reg32 & 0xff)); + + AH_PRIVATE(ah)->ah_curchan = chan; + return AH_TRUE; +} + +static int16_t +ar5211GetNoiseFloor(struct ath_hal *ah) +{ + int16_t nf; + + nf = (OS_REG_READ(ah, AR_PHY(25)) >> 19) & 0x1ff; + if (nf & 0x100) + nf = 0 - ((nf ^ 0x1ff) + 1); + return nf; +} + +/* + * Peform the noisefloor calibration for the length of time set + * in runTime (valid values 1 to 7) + * + * Returns: The NF value at the end of the given time (or 0 for failure) + */ +int16_t +ar5211RunNoiseFloor(struct ath_hal *ah, uint8_t runTime, int16_t startingNF) +{ + int i, searchTime; + + HALASSERT(runTime <= 7); + + /* Setup noise floor run time and starting value */ + OS_REG_WRITE(ah, AR_PHY(25), + (OS_REG_READ(ah, AR_PHY(25)) & ~0xFFF) | + ((runTime << 9) & 0xE00) | (startingNF & 0x1FF)); + /* Calibrate the noise floor */ + OS_REG_WRITE(ah, AR_PHY_AGC_CONTROL, + OS_REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_NF); + + /* Compute the required amount of searchTime needed to finish NF */ + if (runTime == 0) { + /* 8 search windows * 6.4us each */ + searchTime = 8 * 7; + } else { + /* 512 * runtime search windows * 6.4us each */ + searchTime = (runTime * 512) * 7; + } + + /* + * Do not read noise floor until it has been updated + * + * As a guesstimate - we may only get 1/60th the time on + * the air to see search windows in a heavily congested + * network (40 us every 2400 us of time) + */ + for (i = 0; i < 60; i++) { + if ((OS_REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) == 0) + break; + OS_DELAY(searchTime); + } + if (i >= 60) { + HALDEBUG(ah, HAL_DEBUG_NFCAL, + "NF with runTime %d failed to end on channel %d\n", + runTime, AH_PRIVATE(ah)->ah_curchan->channel); + HALDEBUG(ah, HAL_DEBUG_NFCAL, + " PHY NF Reg state: 0x%x\n", + OS_REG_READ(ah, AR_PHY_AGC_CONTROL)); + HALDEBUG(ah, HAL_DEBUG_NFCAL, + " PHY Active Reg state: 0x%x\n", + OS_REG_READ(ah, AR_PHY_ACTIVE)); + return 0; + } + + return ar5211GetNoiseFloor(ah); +} + +static HAL_BOOL +getNoiseFloorThresh(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan, int16_t *nft) +{ + HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom; + + switch (chan->channelFlags & CHANNEL_ALL_NOTURBO) { + case CHANNEL_A: + *nft = ee->ee_noiseFloorThresh[0]; + break; + case CHANNEL_CCK|CHANNEL_2GHZ: + *nft = ee->ee_noiseFloorThresh[1]; + break; + case CHANNEL_OFDM|CHANNEL_2GHZ: + *nft = ee->ee_noiseFloorThresh[2]; + break; + default: + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel flags 0x%x\n", + __func__, chan->channelFlags); + return AH_FALSE; + } + return AH_TRUE; +} + +/* + * Read the NF and check it against the noise floor threshhold + * + * Returns: TRUE if the NF is good + */ +static HAL_BOOL +ar5211IsNfGood(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan) +{ + int16_t nf, nfThresh; + + if (!getNoiseFloorThresh(ah, chan, &nfThresh)) + return AH_FALSE; +#ifdef AH_DEBUG + if (OS_REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: NF did not complete in calibration window\n", __func__); +#endif + nf = ar5211GetNoiseFloor(ah); + if (nf > nfThresh) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: noise floor failed; detected %u, threshold %u\n", + __func__, nf, nfThresh); + /* + * NB: Don't discriminate 2.4 vs 5Ghz, if this + * happens it indicates a problem regardless + * of the band. + */ + chan->channelFlags |= CHANNEL_CW_INT; + } + chan->rawNoiseFloor = nf; + return (nf <= nfThresh); +} + +/* + * Peform the noisefloor calibration and check for any constant channel + * interference. + * + * NOTE: preAR5211 have a lengthy carrier wave detection process - hence + * it is if'ed for MKK regulatory domain only. + * + * Returns: TRUE for a successful noise floor calibration; else FALSE + */ +HAL_BOOL +ar5211CalNoiseFloor(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan) +{ +#define N(a) (sizeof (a) / sizeof (a[0])) + /* Check for Carrier Wave interference in MKK regulatory zone */ + if (AH_PRIVATE(ah)->ah_macVersion < AR_SREV_VERSION_OAHU && + ath_hal_getnfcheckrequired(ah, (HAL_CHANNEL *) chan)) { + static const uint8_t runtime[3] = { 0, 2, 7 }; + int16_t nf, nfThresh; + int i; + + if (!getNoiseFloorThresh(ah, chan, &nfThresh)) + return AH_FALSE; + /* + * Run a quick noise floor that will hopefully + * complete (decrease delay time). + */ + for (i = 0; i < N(runtime); i++) { + nf = ar5211RunNoiseFloor(ah, runtime[i], 0); + if (nf > nfThresh) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: run failed with %u > threshold %u " + "(runtime %u)\n", __func__, + nf, nfThresh, runtime[i]); + chan->rawNoiseFloor = 0; + } else + chan->rawNoiseFloor = nf; + } + return (i <= N(runtime)); + } else { + /* Calibrate the noise floor */ + OS_REG_WRITE(ah, AR_PHY_AGC_CONTROL, + OS_REG_READ(ah, AR_PHY_AGC_CONTROL) | + AR_PHY_AGC_CONTROL_NF); + } + return AH_TRUE; +#undef N +} + +/* + * Adjust NF based on statistical values for 5GHz frequencies. + */ +int16_t +ar5211GetNfAdjust(struct ath_hal *ah, const HAL_CHANNEL_INTERNAL *c) +{ + static const struct { + uint16_t freqLow; + int16_t adjust; + } adjust5111[] = { + { 5790, 11 }, /* NB: ordered high -> low */ + { 5730, 10 }, + { 5690, 9 }, + { 5660, 8 }, + { 5610, 7 }, + { 5530, 5 }, + { 5450, 4 }, + { 5379, 2 }, + { 5209, 0 }, /* XXX? bogus but doesn't matter */ + { 0, 1 }, + }; + int i; + + for (i = 0; c->channel <= adjust5111[i].freqLow; i++) + ; + /* NB: placeholder for 5111's less severe requirement */ + return adjust5111[i].adjust / 3; +} + +/* + * Reads EEPROM header info from device structure and programs + * analog registers 6 and 7 + * + * REQUIRES: Access to the analog device + */ +static HAL_BOOL +ar5211SetRf6and7(struct ath_hal *ah, HAL_CHANNEL *chan) +{ +#define N(a) (sizeof (a) / sizeof (a[0])) + HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom; + struct ath_hal_5211 *ahp = AH5211(ah); + uint16_t rfXpdGain, rfPloSel, rfPwdXpd; + uint16_t tempOB, tempDB; + uint16_t freqIndex; + int i; + + freqIndex = (chan->channelFlags & CHANNEL_2GHZ) ? 2 : 1; + + /* + * TODO: This array mode correspondes with the index used + * during the read. + * For readability, this should be changed to an enum or #define + */ + switch (chan->channelFlags & CHANNEL_ALL_NOTURBO) { + case CHANNEL_A: + if (chan->channel > 4000 && chan->channel < 5260) { + tempOB = ee->ee_ob1; + tempDB = ee->ee_db1; + } else if (chan->channel >= 5260 && chan->channel < 5500) { + tempOB = ee->ee_ob2; + tempDB = ee->ee_db2; + } else if (chan->channel >= 5500 && chan->channel < 5725) { + tempOB = ee->ee_ob3; + tempDB = ee->ee_db3; + } else if (chan->channel >= 5725) { + tempOB = ee->ee_ob4; + tempDB = ee->ee_db4; + } else { + /* XXX panic?? */ + tempOB = tempDB = 0; + } + + rfXpdGain = ee->ee_xgain[0]; + rfPloSel = ee->ee_xpd[0]; + rfPwdXpd = !ee->ee_xpd[0]; + + ar5211Rf6n7[5][freqIndex] = + (ar5211Rf6n7[5][freqIndex] & ~0x10000000) | + (ee->ee_cornerCal.pd84<< 28); + ar5211Rf6n7[6][freqIndex] = + (ar5211Rf6n7[6][freqIndex] & ~0x04000000) | + (ee->ee_cornerCal.pd90 << 26); + ar5211Rf6n7[21][freqIndex] = + (ar5211Rf6n7[21][freqIndex] & ~0x08) | + (ee->ee_cornerCal.gSel << 3); + break; + case CHANNEL_CCK|CHANNEL_2GHZ: + tempOB = ee->ee_obFor24; + tempDB = ee->ee_dbFor24; + rfXpdGain = ee->ee_xgain[1]; + rfPloSel = ee->ee_xpd[1]; + rfPwdXpd = !ee->ee_xpd[1]; + break; + case CHANNEL_OFDM|CHANNEL_2GHZ: + tempOB = ee->ee_obFor24g; + tempDB = ee->ee_dbFor24g; + rfXpdGain = ee->ee_xgain[2]; + rfPloSel = ee->ee_xpd[2]; + rfPwdXpd = !ee->ee_xpd[2]; + break; + default: + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel flags 0x%x\n", + __func__, chan->channelFlags); + return AH_FALSE; + } + + HALASSERT(1 <= tempOB && tempOB <= 5); + HALASSERT(1 <= tempDB && tempDB <= 5); + + /* Set rfXpdGain and rfPwdXpd */ + ar5211Rf6n7[11][freqIndex] = (ar5211Rf6n7[11][freqIndex] & ~0xC0) | + (((ath_hal_reverseBits(rfXpdGain, 4) << 7) | (rfPwdXpd << 6)) & 0xC0); + ar5211Rf6n7[12][freqIndex] = (ar5211Rf6n7[12][freqIndex] & ~0x07) | + ((ath_hal_reverseBits(rfXpdGain, 4) >> 1) & 0x07); + + /* Set OB */ + ar5211Rf6n7[12][freqIndex] = (ar5211Rf6n7[12][freqIndex] & ~0x80) | + ((ath_hal_reverseBits(tempOB, 3) << 7) & 0x80); + ar5211Rf6n7[13][freqIndex] = (ar5211Rf6n7[13][freqIndex] & ~0x03) | + ((ath_hal_reverseBits(tempOB, 3) >> 1) & 0x03); + + /* Set DB */ + ar5211Rf6n7[13][freqIndex] = (ar5211Rf6n7[13][freqIndex] & ~0x1C) | + ((ath_hal_reverseBits(tempDB, 3) << 2) & 0x1C); + + /* Set rfPloSel */ + ar5211Rf6n7[17][freqIndex] = (ar5211Rf6n7[17][freqIndex] & ~0x08) | + ((rfPloSel << 3) & 0x08); + + /* Write the Rf registers 6 & 7 */ + for (i = 0; i < N(ar5211Rf6n7); i++) + OS_REG_WRITE(ah, ar5211Rf6n7[i][0], ar5211Rf6n7[i][freqIndex]); + + /* Now that we have reprogrammed rfgain value, clear the flag. */ + ahp->ah_rfgainState = RFGAIN_INACTIVE; + + return AH_TRUE; +#undef N +} + +HAL_BOOL +ar5211SetAntennaSwitchInternal(struct ath_hal *ah, HAL_ANT_SETTING settings, + const HAL_CHANNEL *chan) +{ +#define ANT_SWITCH_TABLE1 0x9960 +#define ANT_SWITCH_TABLE2 0x9964 + HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom; + struct ath_hal_5211 *ahp = AH5211(ah); + uint32_t antSwitchA, antSwitchB; + int ix; + + switch (chan->channelFlags & CHANNEL_ALL_NOTURBO) { + case CHANNEL_A: ix = 0; break; + case CHANNEL_B: ix = 1; break; + case CHANNEL_PUREG: ix = 2; break; + default: + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel flags 0x%x\n", + __func__, chan->channelFlags); + return AH_FALSE; + } + + antSwitchA = ee->ee_antennaControl[1][ix] + | (ee->ee_antennaControl[2][ix] << 6) + | (ee->ee_antennaControl[3][ix] << 12) + | (ee->ee_antennaControl[4][ix] << 18) + | (ee->ee_antennaControl[5][ix] << 24) + ; + antSwitchB = ee->ee_antennaControl[6][ix] + | (ee->ee_antennaControl[7][ix] << 6) + | (ee->ee_antennaControl[8][ix] << 12) + | (ee->ee_antennaControl[9][ix] << 18) + | (ee->ee_antennaControl[10][ix] << 24) + ; + /* + * For fixed antenna, give the same setting for both switch banks + */ + switch (settings) { + case HAL_ANT_FIXED_A: + antSwitchB = antSwitchA; + break; + case HAL_ANT_FIXED_B: + antSwitchA = antSwitchB; + break; + case HAL_ANT_VARIABLE: + break; + default: + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad antenna setting %u\n", + __func__, settings); + return AH_FALSE; + } + ahp->ah_diversityControl = settings; + + OS_REG_WRITE(ah, ANT_SWITCH_TABLE1, antSwitchA); + OS_REG_WRITE(ah, ANT_SWITCH_TABLE2, antSwitchB); + + return AH_TRUE; +#undef ANT_SWITCH_TABLE1 +#undef ANT_SWITCH_TABLE2 +} + +/* + * Reads EEPROM header info and programs the device for correct operation + * given the channel value + */ +static HAL_BOOL +ar5211SetBoardValues(struct ath_hal *ah, HAL_CHANNEL *chan) +{ + HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom; + struct ath_hal_5211 *ahp = AH5211(ah); + int arrayMode, falseDectectBackoff; + + switch (chan->channelFlags & CHANNEL_ALL_NOTURBO) { + case CHANNEL_A: + arrayMode = 0; + OS_REG_RMW_FIELD(ah, AR_PHY_FRAME_CTL, + AR_PHY_FRAME_CTL_TX_CLIP, ee->ee_cornerCal.clip); + break; + case CHANNEL_CCK|CHANNEL_2GHZ: + arrayMode = 1; + break; + case CHANNEL_OFDM|CHANNEL_2GHZ: + arrayMode = 2; + break; + default: + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel flags 0x%x\n", + __func__, chan->channelFlags); + return AH_FALSE; + } + + /* Set the antenna register(s) correctly for the chip revision */ + if (AH_PRIVATE(ah)->ah_macVersion < AR_SREV_VERSION_OAHU) { + OS_REG_WRITE(ah, AR_PHY(68), + (OS_REG_READ(ah, AR_PHY(68)) & 0xFFFFFFFC) | 0x3); + } else { + OS_REG_WRITE(ah, AR_PHY(68), + (OS_REG_READ(ah, AR_PHY(68)) & 0xFFFFFC06) | + (ee->ee_antennaControl[0][arrayMode] << 4) | 0x1); + + ar5211SetAntennaSwitchInternal(ah, + ahp->ah_diversityControl, chan); + + /* Set the Noise Floor Thresh on ar5211 devices */ + OS_REG_WRITE(ah, AR_PHY_BASE + (90 << 2), + (ee->ee_noiseFloorThresh[arrayMode] & 0x1FF) | (1<<9)); + } + OS_REG_WRITE(ah, AR_PHY_BASE + (17 << 2), + (OS_REG_READ(ah, AR_PHY_BASE + (17 << 2)) & 0xFFFFC07F) | + ((ee->ee_switchSettling[arrayMode] << 7) & 0x3F80)); + OS_REG_WRITE(ah, AR_PHY_BASE + (18 << 2), + (OS_REG_READ(ah, AR_PHY_BASE + (18 << 2)) & 0xFFFC0FFF) | + ((ee->ee_txrxAtten[arrayMode] << 12) & 0x3F000)); + OS_REG_WRITE(ah, AR_PHY_BASE + (20 << 2), + (OS_REG_READ(ah, AR_PHY_BASE + (20 << 2)) & 0xFFFF0000) | + ((ee->ee_pgaDesiredSize[arrayMode] << 8) & 0xFF00) | + (ee->ee_adcDesiredSize[arrayMode] & 0x00FF)); + OS_REG_WRITE(ah, AR_PHY_BASE + (13 << 2), + (ee->ee_txEndToXPAOff[arrayMode] << 24) | + (ee->ee_txEndToXPAOff[arrayMode] << 16) | + (ee->ee_txFrameToXPAOn[arrayMode] << 8) | + ee->ee_txFrameToXPAOn[arrayMode]); + OS_REG_WRITE(ah, AR_PHY_BASE + (10 << 2), + (OS_REG_READ(ah, AR_PHY_BASE + (10 << 2)) & 0xFFFF00FF) | + (ee->ee_txEndToXLNAOn[arrayMode] << 8)); + OS_REG_WRITE(ah, AR_PHY_BASE + (25 << 2), + (OS_REG_READ(ah, AR_PHY_BASE + (25 << 2)) & 0xFFF80FFF) | + ((ee->ee_thresh62[arrayMode] << 12) & 0x7F000)); + +#define NO_FALSE_DETECT_BACKOFF 2 +#define CB22_FALSE_DETECT_BACKOFF 6 + /* + * False detect backoff - suspected 32 MHz spur causes + * false detects in OFDM, causing Tx Hangs. Decrease + * weak signal sensitivity for this card. + */ + falseDectectBackoff = NO_FALSE_DETECT_BACKOFF; + if (AH_PRIVATE(ah)->ah_eeversion < AR_EEPROM_VER3_3) { + if (AH_PRIVATE(ah)->ah_subvendorid == 0x1022 && + IS_CHAN_OFDM(chan)) + falseDectectBackoff += CB22_FALSE_DETECT_BACKOFF; + } else { + uint32_t remainder = chan->channel % 32; + + if (remainder && (remainder < 10 || remainder > 22)) + falseDectectBackoff += ee->ee_falseDetectBackoff[arrayMode]; + } + OS_REG_WRITE(ah, 0x9924, + (OS_REG_READ(ah, 0x9924) & 0xFFFFFF01) + | ((falseDectectBackoff << 1) & 0xF7)); + + return AH_TRUE; +#undef NO_FALSE_DETECT_BACKOFF +#undef CB22_FALSE_DETECT_BACKOFF +} + +/* + * Set the limit on the overall output power. Used for dynamic + * transmit power control and the like. + * + * NOTE: The power is passed in is in units of 0.5 dBm. + */ +HAL_BOOL +ar5211SetTxPowerLimit(struct ath_hal *ah, uint32_t limit) +{ + + AH_PRIVATE(ah)->ah_powerLimit = AH_MIN(limit, MAX_RATE_POWER); + OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE_MAX, limit); + return AH_TRUE; +} + +/* + * Sets the transmit power in the baseband for the given + * operating channel and mode. + */ +HAL_BOOL +ar5211SetTransmitPower(struct ath_hal *ah, HAL_CHANNEL *chan) +{ + HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom; + TRGT_POWER_INFO *pi; + RD_EDGES_POWER *rep; + PCDACS_EEPROM eepromPcdacs; + u_int nchan, cfgCtl; + int i; + + /* setup the pcdac struct to point to the correct info, based on mode */ + switch (chan->channelFlags & CHANNEL_ALL_NOTURBO) { + case CHANNEL_A: + eepromPcdacs.numChannels = ee->ee_numChannels11a; + eepromPcdacs.pChannelList= ee->ee_channels11a; + eepromPcdacs.pDataPerChannel = ee->ee_dataPerChannel11a; + nchan = ee->ee_numTargetPwr_11a; + pi = ee->ee_trgtPwr_11a; + break; + case CHANNEL_OFDM|CHANNEL_2GHZ: + eepromPcdacs.numChannels = ee->ee_numChannels2_4; + eepromPcdacs.pChannelList= ee->ee_channels11g; + eepromPcdacs.pDataPerChannel = ee->ee_dataPerChannel11g; + nchan = ee->ee_numTargetPwr_11g; + pi = ee->ee_trgtPwr_11g; + break; + case CHANNEL_CCK|CHANNEL_2GHZ: + eepromPcdacs.numChannels = ee->ee_numChannels2_4; + eepromPcdacs.pChannelList= ee->ee_channels11b; + eepromPcdacs.pDataPerChannel = ee->ee_dataPerChannel11b; + nchan = ee->ee_numTargetPwr_11b; + pi = ee->ee_trgtPwr_11b; + break; + default: + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel flags 0x%x\n", + __func__, chan->channelFlags); + return AH_FALSE; + } + + ar5211SetPowerTable(ah, &eepromPcdacs, chan->channel); + + rep = AH_NULL; + /* Match CTL to EEPROM value */ + cfgCtl = ath_hal_getctl(ah, chan); + for (i = 0; i < ee->ee_numCtls; i++) + if (ee->ee_ctl[i] != 0 && ee->ee_ctl[i] == cfgCtl) { + rep = &ee->ee_rdEdgesPower[i * NUM_EDGES]; + break; + } + ar5211SetRateTable(ah, rep, pi, nchan, chan); + + return AH_TRUE; +} + +/* + * Read the transmit power levels from the structures taken + * from EEPROM. Interpolate read transmit power values for + * this channel. Organize the transmit power values into a + * table for writing into the hardware. + */ +void +ar5211SetPowerTable(struct ath_hal *ah, PCDACS_EEPROM *pSrcStruct, uint16_t channel) +{ + static FULL_PCDAC_STRUCT pcdacStruct; + static uint16_t pcdacTable[PWR_TABLE_SIZE]; + + uint16_t i, j; + uint16_t *pPcdacValues; + int16_t *pScaledUpDbm; + int16_t minScaledPwr; + int16_t maxScaledPwr; + int16_t pwr; + uint16_t pcdacMin = 0; + uint16_t pcdacMax = 63; + uint16_t pcdacTableIndex; + uint16_t scaledPcdac; + uint32_t addr; + uint32_t temp32; + + OS_MEMZERO(&pcdacStruct, sizeof(FULL_PCDAC_STRUCT)); + OS_MEMZERO(pcdacTable, sizeof(uint16_t) * PWR_TABLE_SIZE); + pPcdacValues = pcdacStruct.PcdacValues; + pScaledUpDbm = pcdacStruct.PwrValues; + + /* Initialize the pcdacs to dBM structs pcdacs to be 1 to 63 */ + for (i = PCDAC_START, j = 0; i <= PCDAC_STOP; i+= PCDAC_STEP, j++) + pPcdacValues[j] = i; + + pcdacStruct.numPcdacValues = j; + pcdacStruct.pcdacMin = PCDAC_START; + pcdacStruct.pcdacMax = PCDAC_STOP; + + /* Fill out the power values for this channel */ + for (j = 0; j < pcdacStruct.numPcdacValues; j++ ) + pScaledUpDbm[j] = ar5211GetScaledPower(channel, pPcdacValues[j], pSrcStruct); + + /* Now scale the pcdac values to fit in the 64 entry power table */ + minScaledPwr = pScaledUpDbm[0]; + maxScaledPwr = pScaledUpDbm[pcdacStruct.numPcdacValues - 1]; + + /* find minimum and make monotonic */ + for (j = 0; j < pcdacStruct.numPcdacValues; j++) { + if (minScaledPwr >= pScaledUpDbm[j]) { + minScaledPwr = pScaledUpDbm[j]; + pcdacMin = j; + } + /* + * Make the full_hsh monotonically increasing otherwise + * interpolation algorithm will get fooled gotta start + * working from the top, hence i = 63 - j. + */ + i = (uint16_t)(pcdacStruct.numPcdacValues - 1 - j); + if (i == 0) + break; + if (pScaledUpDbm[i-1] > pScaledUpDbm[i]) { + /* + * It could be a glitch, so make the power for + * this pcdac the same as the power from the + * next highest pcdac. + */ + pScaledUpDbm[i - 1] = pScaledUpDbm[i]; + } + } + + for (j = 0; j < pcdacStruct.numPcdacValues; j++) + if (maxScaledPwr < pScaledUpDbm[j]) { + maxScaledPwr = pScaledUpDbm[j]; + pcdacMax = j; + } + + /* Find the first power level with a pcdac */ + pwr = (uint16_t)(PWR_STEP * ((minScaledPwr - PWR_MIN + PWR_STEP / 2) / PWR_STEP) + PWR_MIN); + + /* Write all the first pcdac entries based off the pcdacMin */ + pcdacTableIndex = 0; + for (i = 0; i < (2 * (pwr - PWR_MIN) / EEP_SCALE + 1); i++) + pcdacTable[pcdacTableIndex++] = pcdacMin; + + i = 0; + while (pwr < pScaledUpDbm[pcdacStruct.numPcdacValues - 1]) { + pwr += PWR_STEP; + /* stop if dbM > max_power_possible */ + while (pwr < pScaledUpDbm[pcdacStruct.numPcdacValues - 1] && + (pwr - pScaledUpDbm[i])*(pwr - pScaledUpDbm[i+1]) > 0) + i++; + /* scale by 2 and add 1 to enable round up or down as needed */ + scaledPcdac = (uint16_t)(ar5211GetInterpolatedValue(pwr, + pScaledUpDbm[i], pScaledUpDbm[i+1], + (uint16_t)(pPcdacValues[i] * 2), + (uint16_t)(pPcdacValues[i+1] * 2), 0) + 1); + + pcdacTable[pcdacTableIndex] = scaledPcdac / 2; + if (pcdacTable[pcdacTableIndex] > pcdacMax) + pcdacTable[pcdacTableIndex] = pcdacMax; + pcdacTableIndex++; + } + + /* Write all the last pcdac entries based off the last valid pcdac */ + while (pcdacTableIndex < PWR_TABLE_SIZE) { + pcdacTable[pcdacTableIndex] = pcdacTable[pcdacTableIndex - 1]; + pcdacTableIndex++; + } + + /* Finally, write the power values into the baseband power table */ + addr = AR_PHY_BASE + (608 << 2); + for (i = 0; i < 32; i++) { + temp32 = 0xffff & ((pcdacTable[2 * i + 1] << 8) | 0xff); + temp32 = (temp32 << 16) | (0xffff & ((pcdacTable[2 * i] << 8) | 0xff)); + OS_REG_WRITE(ah, addr, temp32); + addr += 4; + } + +} + +/* + * Set the transmit power in the baseband for the given + * operating channel and mode. + */ +void +ar5211SetRateTable(struct ath_hal *ah, RD_EDGES_POWER *pRdEdgesPower, + TRGT_POWER_INFO *pPowerInfo, uint16_t numChannels, + HAL_CHANNEL *chan) +{ + HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom; + struct ath_hal_5211 *ahp = AH5211(ah); + static uint16_t ratesArray[NUM_RATES]; + static const uint16_t tpcScaleReductionTable[5] = + { 0, 3, 6, 9, MAX_RATE_POWER }; + + uint16_t *pRatesPower; + uint16_t lowerChannel = 0, lowerIndex=0, lowerPower=0; + uint16_t upperChannel = 0, upperIndex=0, upperPower=0; + uint16_t twiceMaxEdgePower=63; + uint16_t twicePower = 0; + uint16_t i, numEdges; + uint16_t tempChannelList[NUM_EDGES]; /* temp array for holding edge channels */ + uint16_t twiceMaxRDPower; + int16_t scaledPower = 0; /* for gcc -O2 */ + uint16_t mask = 0x3f; + HAL_BOOL paPreDEnable = 0; + int8_t twiceAntennaGain, twiceAntennaReduction = 0; + + pRatesPower = ratesArray; + twiceMaxRDPower = chan->maxRegTxPower * 2; + + if (IS_CHAN_5GHZ(chan)) { + twiceAntennaGain = ee->ee_antennaGainMax[0]; + } else { + twiceAntennaGain = ee->ee_antennaGainMax[1]; + } + + twiceAntennaReduction = ath_hal_getantennareduction(ah, chan, twiceAntennaGain); + + if (pRdEdgesPower) { + /* Get the edge power */ + for (i = 0; i < NUM_EDGES; i++) { + if (pRdEdgesPower[i].rdEdge == 0) + break; + tempChannelList[i] = pRdEdgesPower[i].rdEdge; + } + numEdges = i; + + ar5211GetLowerUpperValues(chan->channel, tempChannelList, + numEdges, &lowerChannel, &upperChannel); + /* Get the index for this channel */ + for (i = 0; i < numEdges; i++) + if (lowerChannel == tempChannelList[i]) + break; + HALASSERT(i != numEdges); + + if ((lowerChannel == upperChannel && + lowerChannel == chan->channel) || + pRdEdgesPower[i].flag) { + twiceMaxEdgePower = pRdEdgesPower[i].twice_rdEdgePower; + HALASSERT(twiceMaxEdgePower > 0); + } + } + + /* extrapolate the power values for the test Groups */ + for (i = 0; i < numChannels; i++) + tempChannelList[i] = pPowerInfo[i].testChannel; + + ar5211GetLowerUpperValues(chan->channel, tempChannelList, + numChannels, &lowerChannel, &upperChannel); + + /* get the index for the channel */ + for (i = 0; i < numChannels; i++) { + if (lowerChannel == tempChannelList[i]) + lowerIndex = i; + if (upperChannel == tempChannelList[i]) { + upperIndex = i; + break; + } + } + + for (i = 0; i < NUM_RATES; i++) { + if (IS_CHAN_OFDM(chan)) { + /* power for rates 6,9,12,18,24 is all the same */ + if (i < 5) { + lowerPower = pPowerInfo[lowerIndex].twicePwr6_24; + upperPower = pPowerInfo[upperIndex].twicePwr6_24; + } else if (i == 5) { + lowerPower = pPowerInfo[lowerIndex].twicePwr36; + upperPower = pPowerInfo[upperIndex].twicePwr36; + } else if (i == 6) { + lowerPower = pPowerInfo[lowerIndex].twicePwr48; + upperPower = pPowerInfo[upperIndex].twicePwr48; + } else if (i == 7) { + lowerPower = pPowerInfo[lowerIndex].twicePwr54; + upperPower = pPowerInfo[upperIndex].twicePwr54; + } + } else { + switch (i) { + case 0: + case 1: + lowerPower = pPowerInfo[lowerIndex].twicePwr6_24; + upperPower = pPowerInfo[upperIndex].twicePwr6_24; + break; + case 2: + case 3: + lowerPower = pPowerInfo[lowerIndex].twicePwr36; + upperPower = pPowerInfo[upperIndex].twicePwr36; + break; + case 4: + case 5: + lowerPower = pPowerInfo[lowerIndex].twicePwr48; + upperPower = pPowerInfo[upperIndex].twicePwr48; + break; + case 6: + case 7: + lowerPower = pPowerInfo[lowerIndex].twicePwr54; + upperPower = pPowerInfo[upperIndex].twicePwr54; + break; + } + } + + twicePower = ar5211GetInterpolatedValue(chan->channel, + lowerChannel, upperChannel, lowerPower, upperPower, 0); + + /* Reduce power by band edge restrictions */ + twicePower = AH_MIN(twicePower, twiceMaxEdgePower); + + /* + * If turbo is set, reduce power to keep power + * consumption under 2 Watts. Note that we always do + * this unless specially configured. Then we limit + * power only for non-AP operation. + */ + if (IS_CHAN_TURBO(chan) && + AH_PRIVATE(ah)->ah_eeversion >= AR_EEPROM_VER3_1 +#ifdef AH_ENABLE_AP_SUPPORT + && AH_PRIVATE(ah)->ah_opmode != HAL_M_HOSTAP +#endif + ) { + twicePower = AH_MIN(twicePower, ee->ee_turbo2WMaxPower5); + } + + /* Reduce power by max regulatory domain allowed restrictions */ + pRatesPower[i] = AH_MIN(twicePower, twiceMaxRDPower - twiceAntennaReduction); + + /* Use 6 Mb power level for transmit power scaling reduction */ + /* We don't want to reduce higher rates if its not needed */ + if (i == 0) { + scaledPower = pRatesPower[0] - + (tpcScaleReductionTable[AH_PRIVATE(ah)->ah_tpScale] * 2); + if (scaledPower < 1) + scaledPower = 1; + } + + pRatesPower[i] = AH_MIN(pRatesPower[i], scaledPower); + } + + /* Record txPower at Rate 6 for info gathering */ + ahp->ah_tx6PowerInHalfDbm = pRatesPower[0]; + +#ifdef AH_DEBUG + HALDEBUG(ah, HAL_DEBUG_RESET, + "%s: final output power setting %d MHz:\n", + __func__, chan->channel); + HALDEBUG(ah, HAL_DEBUG_RESET, + "6 Mb %d dBm, MaxRD: %d dBm, MaxEdge %d dBm\n", + scaledPower / 2, twiceMaxRDPower / 2, twiceMaxEdgePower / 2); + HALDEBUG(ah, HAL_DEBUG_RESET, "TPC Scale %d dBm - Ant Red %d dBm\n", + tpcScaleReductionTable[AH_PRIVATE(ah)->ah_tpScale] * 2, + twiceAntennaReduction / 2); + if (IS_CHAN_TURBO(chan) && + AH_PRIVATE(ah)->ah_eeversion >= AR_EEPROM_VER3_1) + HALDEBUG(ah, HAL_DEBUG_RESET, "Max Turbo %d dBm\n", + ee->ee_turbo2WMaxPower5); + HALDEBUG(ah, HAL_DEBUG_RESET, + " %2d | %2d | %2d | %2d | %2d | %2d | %2d | %2d dBm\n", + pRatesPower[0] / 2, pRatesPower[1] / 2, pRatesPower[2] / 2, + pRatesPower[3] / 2, pRatesPower[4] / 2, pRatesPower[5] / 2, + pRatesPower[6] / 2, pRatesPower[7] / 2); +#endif /* AH_DEBUG */ + + /* Write the power table into the hardware */ + OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, + ((paPreDEnable & 1)<< 30) | ((pRatesPower[3] & mask) << 24) | + ((paPreDEnable & 1)<< 22) | ((pRatesPower[2] & mask) << 16) | + ((paPreDEnable & 1)<< 14) | ((pRatesPower[1] & mask) << 8) | + ((paPreDEnable & 1)<< 6 ) | (pRatesPower[0] & mask)); + OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE2, + ((paPreDEnable & 1)<< 30) | ((pRatesPower[7] & mask) << 24) | + ((paPreDEnable & 1)<< 22) | ((pRatesPower[6] & mask) << 16) | + ((paPreDEnable & 1)<< 14) | ((pRatesPower[5] & mask) << 8) | + ((paPreDEnable & 1)<< 6 ) | (pRatesPower[4] & mask)); + + /* set max power to the power value at rate 6 */ + ar5211SetTxPowerLimit(ah, pRatesPower[0]); + + AH_PRIVATE(ah)->ah_maxPowerLevel = pRatesPower[0]; +} + +/* + * Get or interpolate the pcdac value from the calibrated data + */ +uint16_t +ar5211GetScaledPower(uint16_t channel, uint16_t pcdacValue, const PCDACS_EEPROM *pSrcStruct) +{ + uint16_t powerValue; + uint16_t lFreq = 0, rFreq = 0; /* left and right frequency values */ + uint16_t llPcdac = 0, ulPcdac = 0; /* lower and upper left pcdac values */ + uint16_t lrPcdac = 0, urPcdac = 0; /* lower and upper right pcdac values */ + uint16_t lPwr = 0, uPwr = 0; /* lower and upper temp pwr values */ + uint16_t lScaledPwr, rScaledPwr; /* left and right scaled power */ + + if (ar5211FindValueInList(channel, pcdacValue, pSrcStruct, &powerValue)) + /* value was copied from srcStruct */ + return powerValue; + + ar5211GetLowerUpperValues(channel, pSrcStruct->pChannelList, + pSrcStruct->numChannels, &lFreq, &rFreq); + ar5211GetLowerUpperPcdacs(pcdacValue, lFreq, pSrcStruct, + &llPcdac, &ulPcdac); + ar5211GetLowerUpperPcdacs(pcdacValue, rFreq, pSrcStruct, + &lrPcdac, &urPcdac); + + /* get the power index for the pcdac value */ + ar5211FindValueInList(lFreq, llPcdac, pSrcStruct, &lPwr); + ar5211FindValueInList(lFreq, ulPcdac, pSrcStruct, &uPwr); + lScaledPwr = ar5211GetInterpolatedValue(pcdacValue, + llPcdac, ulPcdac, lPwr, uPwr, 0); + + ar5211FindValueInList(rFreq, lrPcdac, pSrcStruct, &lPwr); + ar5211FindValueInList(rFreq, urPcdac, pSrcStruct, &uPwr); + rScaledPwr = ar5211GetInterpolatedValue(pcdacValue, + lrPcdac, urPcdac, lPwr, uPwr, 0); + + return ar5211GetInterpolatedValue(channel, lFreq, rFreq, + lScaledPwr, rScaledPwr, 0); +} + +/* + * Find the value from the calibrated source data struct + */ +HAL_BOOL +ar5211FindValueInList(uint16_t channel, uint16_t pcdacValue, + const PCDACS_EEPROM *pSrcStruct, uint16_t *powerValue) +{ + const DATA_PER_CHANNEL *pChannelData; + const uint16_t *pPcdac; + uint16_t i, j; + + pChannelData = pSrcStruct->pDataPerChannel; + for (i = 0; i < pSrcStruct->numChannels; i++ ) { + if (pChannelData->channelValue == channel) { + pPcdac = pChannelData->PcdacValues; + for (j = 0; j < pChannelData->numPcdacValues; j++ ) { + if (*pPcdac == pcdacValue) { + *powerValue = pChannelData->PwrValues[j]; + return AH_TRUE; + } + pPcdac++; + } + } + pChannelData++; + } + return AH_FALSE; +} + +/* + * Returns interpolated or the scaled up interpolated value + */ +uint16_t +ar5211GetInterpolatedValue(uint16_t target, + uint16_t srcLeft, uint16_t srcRight, + uint16_t targetLeft, uint16_t targetRight, + HAL_BOOL scaleUp) +{ + uint16_t rv; + int16_t lRatio; + uint16_t scaleValue = EEP_SCALE; + + /* to get an accurate ratio, always scale, if want to scale, then don't scale back down */ + if ((targetLeft * targetRight) == 0) + return 0; + if (scaleUp) + scaleValue = 1; + + if (srcRight != srcLeft) { + /* + * Note the ratio always need to be scaled, + * since it will be a fraction. + */ + lRatio = (target - srcLeft) * EEP_SCALE / (srcRight - srcLeft); + if (lRatio < 0) { + /* Return as Left target if value would be negative */ + rv = targetLeft * (scaleUp ? EEP_SCALE : 1); + } else if (lRatio > EEP_SCALE) { + /* Return as Right target if Ratio is greater than 100% (SCALE) */ + rv = targetRight * (scaleUp ? EEP_SCALE : 1); + } else { + rv = (lRatio * targetRight + (EEP_SCALE - lRatio) * + targetLeft) / scaleValue; + } + } else { + rv = targetLeft; + if (scaleUp) + rv *= EEP_SCALE; + } + return rv; +} + +/* + * Look for value being within 0.1 of the search values + * however, NDIS can't do float calculations, so multiply everything + * up by EEP_SCALE so can do integer arithmatic + * + * INPUT value -value to search for + * INPUT pList -ptr to the list to search + * INPUT listSize -number of entries in list + * OUTPUT pLowerValue -return the lower value + * OUTPUT pUpperValue -return the upper value + */ +void +ar5211GetLowerUpperValues(uint16_t value, + const uint16_t *pList, uint16_t listSize, + uint16_t *pLowerValue, uint16_t *pUpperValue) +{ + const uint16_t listEndValue = *(pList + listSize - 1); + uint32_t target = value * EEP_SCALE; + int i; + + /* + * See if value is lower than the first value in the list + * if so return first value + */ + if (target < (uint32_t)(*pList * EEP_SCALE - EEP_DELTA)) { + *pLowerValue = *pList; + *pUpperValue = *pList; + return; + } + + /* + * See if value is greater than last value in list + * if so return last value + */ + if (target > (uint32_t)(listEndValue * EEP_SCALE + EEP_DELTA)) { + *pLowerValue = listEndValue; + *pUpperValue = listEndValue; + return; + } + + /* look for value being near or between 2 values in list */ + for (i = 0; i < listSize; i++) { + /* + * If value is close to the current value of the list + * then target is not between values, it is one of the values + */ + if (abs(pList[i] * EEP_SCALE - (int32_t) target) < EEP_DELTA) { + *pLowerValue = pList[i]; + *pUpperValue = pList[i]; + return; + } + + /* + * Look for value being between current value and next value + * if so return these 2 values + */ + if (target < (uint32_t)(pList[i + 1] * EEP_SCALE - EEP_DELTA)) { + *pLowerValue = pList[i]; + *pUpperValue = pList[i + 1]; + return; + } + } +} + +/* + * Get the upper and lower pcdac given the channel and the pcdac + * used in the search + */ +void +ar5211GetLowerUpperPcdacs(uint16_t pcdac, uint16_t channel, + const PCDACS_EEPROM *pSrcStruct, + uint16_t *pLowerPcdac, uint16_t *pUpperPcdac) +{ + const DATA_PER_CHANNEL *pChannelData; + int i; + + /* Find the channel information */ + pChannelData = pSrcStruct->pDataPerChannel; + for (i = 0; i < pSrcStruct->numChannels; i++) { + if (pChannelData->channelValue == channel) + break; + pChannelData++; + } + ar5211GetLowerUpperValues(pcdac, pChannelData->PcdacValues, + pChannelData->numPcdacValues, pLowerPcdac, pUpperPcdac); +} + +#define DYN_ADJ_UP_MARGIN 15 +#define DYN_ADJ_LO_MARGIN 20 + +static const GAIN_OPTIMIZATION_LADDER gainLadder = { + 9, /* numStepsInLadder */ + 4, /* defaultStepNum */ + { { {4, 1, 1, 1}, 6, "FG8"}, + { {4, 0, 1, 1}, 4, "FG7"}, + { {3, 1, 1, 1}, 3, "FG6"}, + { {4, 0, 0, 1}, 1, "FG5"}, + { {4, 1, 1, 0}, 0, "FG4"}, /* noJack */ + { {4, 0, 1, 0}, -2, "FG3"}, /* halfJack */ + { {3, 1, 1, 0}, -3, "FG2"}, /* clip3 */ + { {4, 0, 0, 0}, -4, "FG1"}, /* noJack */ + { {2, 1, 1, 0}, -6, "FG0"} /* clip2 */ + } +}; + +/* + * Initialize the gain structure to good values + */ +void +ar5211InitializeGainValues(struct ath_hal *ah) +{ + struct ath_hal_5211 *ahp = AH5211(ah); + GAIN_VALUES *gv = &ahp->ah_gainValues; + + /* initialize gain optimization values */ + gv->currStepNum = gainLadder.defaultStepNum; + gv->currStep = &gainLadder.optStep[gainLadder.defaultStepNum]; + gv->active = AH_TRUE; + gv->loTrig = 20; + gv->hiTrig = 35; +} + +static HAL_BOOL +ar5211InvalidGainReadback(struct ath_hal *ah, GAIN_VALUES *gv) +{ + HAL_CHANNEL_INTERNAL *chan = AH_PRIVATE(ah)->ah_curchan; + uint32_t gStep, g; + uint32_t L1, L2, L3, L4; + + if (IS_CHAN_CCK(chan)) { + gStep = 0x18; + L1 = 0; + L2 = gStep + 4; + L3 = 0x40; + L4 = L3 + 50; + + gv->loTrig = L1; + gv->hiTrig = L4+5; + } else { + gStep = 0x3f; + L1 = 0; + L2 = 50; + L3 = L1; + L4 = L3 + 50; + + gv->loTrig = L1 + DYN_ADJ_LO_MARGIN; + gv->hiTrig = L4 - DYN_ADJ_UP_MARGIN; + } + g = gv->currGain; + + return !((g >= L1 && g<= L2) || (g >= L3 && g <= L4)); +} + +/* + * Enable the probe gain check on the next packet + */ +static void +ar5211RequestRfgain(struct ath_hal *ah) +{ + struct ath_hal_5211 *ahp = AH5211(ah); + + /* Enable the gain readback probe */ + OS_REG_WRITE(ah, AR_PHY_PAPD_PROBE, + SM(ahp->ah_tx6PowerInHalfDbm, AR_PHY_PAPD_PROBE_POWERTX) + | AR_PHY_PAPD_PROBE_NEXT_TX); + + ahp->ah_rfgainState = HAL_RFGAIN_READ_REQUESTED; +} + +/* + * Exported call to check for a recent gain reading and return + * the current state of the thermal calibration gain engine. + */ +HAL_RFGAIN +ar5211GetRfgain(struct ath_hal *ah) +{ + struct ath_hal_5211 *ahp = AH5211(ah); + GAIN_VALUES *gv = &ahp->ah_gainValues; + uint32_t rddata; + + if (!gv->active) + return HAL_RFGAIN_INACTIVE; + + if (ahp->ah_rfgainState == HAL_RFGAIN_READ_REQUESTED) { + /* Caller had asked to setup a new reading. Check it. */ + rddata = OS_REG_READ(ah, AR_PHY_PAPD_PROBE); + + if ((rddata & AR_PHY_PAPD_PROBE_NEXT_TX) == 0) { + /* bit got cleared, we have a new reading. */ + gv->currGain = rddata >> AR_PHY_PAPD_PROBE_GAINF_S; + /* inactive by default */ + ahp->ah_rfgainState = HAL_RFGAIN_INACTIVE; + + if (!ar5211InvalidGainReadback(ah, gv) && + ar5211IsGainAdjustNeeded(ah, gv) && + ar5211AdjustGain(ah, gv) > 0) { + /* + * Change needed. Copy ladder info + * into eeprom info. + */ + ar5211SetRfgain(ah, gv); + ahp->ah_rfgainState = HAL_RFGAIN_NEED_CHANGE; + } + } + } + return ahp->ah_rfgainState; +} + +/* + * Check to see if our readback gain level sits within the linear + * region of our current variable attenuation window + */ +static HAL_BOOL +ar5211IsGainAdjustNeeded(struct ath_hal *ah, const GAIN_VALUES *gv) +{ + return (gv->currGain <= gv->loTrig || gv->currGain >= gv->hiTrig); +} + +/* + * Move the rabbit ears in the correct direction. + */ +static int32_t +ar5211AdjustGain(struct ath_hal *ah, GAIN_VALUES *gv) +{ + /* return > 0 for valid adjustments. */ + if (!gv->active) + return -1; + + gv->currStep = &gainLadder.optStep[gv->currStepNum]; + if (gv->currGain >= gv->hiTrig) { + if (gv->currStepNum == 0) { + HALDEBUG(ah, HAL_DEBUG_RFPARAM, + "%s: Max gain limit.\n", __func__); + return -1; + } + HALDEBUG(ah, HAL_DEBUG_RFPARAM, + "%s: Adding gain: currG=%d [%s] --> ", + __func__, gv->currGain, gv->currStep->stepName); + gv->targetGain = gv->currGain; + while (gv->targetGain >= gv->hiTrig && gv->currStepNum > 0) { + gv->targetGain -= 2 * (gainLadder.optStep[--(gv->currStepNum)].stepGain - + gv->currStep->stepGain); + gv->currStep = &gainLadder.optStep[gv->currStepNum]; + } + HALDEBUG(ah, HAL_DEBUG_RFPARAM, "targG=%d [%s]\n", + gv->targetGain, gv->currStep->stepName); + return 1; + } + if (gv->currGain <= gv->loTrig) { + if (gv->currStepNum == gainLadder.numStepsInLadder-1) { + HALDEBUG(ah, HAL_DEBUG_RFPARAM, + "%s: Min gain limit.\n", __func__); + return -2; + } + HALDEBUG(ah, HAL_DEBUG_RFPARAM, + "%s: Deducting gain: currG=%d [%s] --> ", + __func__, gv->currGain, gv->currStep->stepName); + gv->targetGain = gv->currGain; + while (gv->targetGain <= gv->loTrig && + gv->currStepNum < (gainLadder.numStepsInLadder - 1)) { + gv->targetGain -= 2 * + (gainLadder.optStep[++(gv->currStepNum)].stepGain - gv->currStep->stepGain); + gv->currStep = &gainLadder.optStep[gv->currStepNum]; + } + HALDEBUG(ah, HAL_DEBUG_RFPARAM, "targG=%d [%s]\n", + gv->targetGain, gv->currStep->stepName); + return 2; + } + return 0; /* caller didn't call needAdjGain first */ +} + +/* + * Adjust the 5GHz EEPROM information with the desired calibration values. + */ +static void +ar5211SetRfgain(struct ath_hal *ah, const GAIN_VALUES *gv) +{ + HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom; + + if (!gv->active) + return; + ee->ee_cornerCal.clip = gv->currStep->paramVal[0]; /* bb_tx_clip */ + ee->ee_cornerCal.pd90 = gv->currStep->paramVal[1]; /* rf_pwd_90 */ + ee->ee_cornerCal.pd84 = gv->currStep->paramVal[2]; /* rf_pwd_84 */ + ee->ee_cornerCal.gSel = gv->currStep->paramVal[3]; /* rf_rfgainsel */ +} + +static void +ar5211SetOperatingMode(struct ath_hal *ah, int opmode) +{ + struct ath_hal_5211 *ahp = AH5211(ah); + uint32_t val; + + val = OS_REG_READ(ah, AR_STA_ID1) & 0xffff; + switch (opmode) { + case HAL_M_HOSTAP: + OS_REG_WRITE(ah, AR_STA_ID1, val + | AR_STA_ID1_STA_AP + | AR_STA_ID1_RTS_USE_DEF + | ahp->ah_staId1Defaults); + break; + case HAL_M_IBSS: + OS_REG_WRITE(ah, AR_STA_ID1, val + | AR_STA_ID1_ADHOC + | AR_STA_ID1_DESC_ANTENNA + | ahp->ah_staId1Defaults); + break; + case HAL_M_STA: + case HAL_M_MONITOR: + OS_REG_WRITE(ah, AR_STA_ID1, val + | AR_STA_ID1_DEFAULT_ANTENNA + | ahp->ah_staId1Defaults); + break; + } +} + +void +ar5211SetPCUConfig(struct ath_hal *ah) +{ + ar5211SetOperatingMode(ah, AH_PRIVATE(ah)->ah_opmode); +} --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5211/ar5211_xmit.c 2009-03-23 17:36:55.000000000 +0000 @@ -0,0 +1,662 @@ +/* + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2006 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ar5211_xmit.c,v 1.1 2009/03/23 17:14:47 sborrill Exp $ + */ +#include "opt_ah.h" + +#include "ah.h" +#include "ah_internal.h" +#include "ah_desc.h" + +#include "ar5211/ar5211.h" +#include "ar5211/ar5211reg.h" +#include "ar5211/ar5211desc.h" + +/* + * Update Tx FIFO trigger level. + * + * Set bIncTrigLevel to TRUE to increase the trigger level. + * Set bIncTrigLevel to FALSE to decrease the trigger level. + * + * Returns TRUE if the trigger level was updated + */ +HAL_BOOL +ar5211UpdateTxTrigLevel(struct ath_hal *ah, HAL_BOOL bIncTrigLevel) +{ + uint32_t curTrigLevel, txcfg; + HAL_INT ints = ar5211GetInterrupts(ah); + + /* + * Disable chip interrupts. This is because halUpdateTxTrigLevel + * is called from both ISR and non-ISR contexts. + */ + ar5211SetInterrupts(ah, ints &~ HAL_INT_GLOBAL); + txcfg = OS_REG_READ(ah, AR_TXCFG); + curTrigLevel = (txcfg & AR_TXCFG_FTRIG_M) >> AR_TXCFG_FTRIG_S; + if (bIncTrigLevel){ + /* increase the trigger level */ + curTrigLevel = curTrigLevel + + ((MAX_TX_FIFO_THRESHOLD - curTrigLevel) / 2); + } else { + /* decrease the trigger level if not already at the minimum */ + if (curTrigLevel > MIN_TX_FIFO_THRESHOLD) { + /* decrease the trigger level */ + curTrigLevel--; + } else { + /* no update to the trigger level */ + /* re-enable chip interrupts */ + ar5211SetInterrupts(ah, ints); + return AH_FALSE; + } + } + /* Update the trigger level */ + OS_REG_WRITE(ah, AR_TXCFG, (txcfg &~ AR_TXCFG_FTRIG_M) | + ((curTrigLevel << AR_TXCFG_FTRIG_S) & AR_TXCFG_FTRIG_M)); + /* re-enable chip interrupts */ + ar5211SetInterrupts(ah, ints); + return AH_TRUE; +} + +/* + * Set the properties of the tx queue with the parameters + * from qInfo. The queue must previously have been setup + * with a call to ar5211SetupTxQueue. + */ +HAL_BOOL +ar5211SetTxQueueProps(struct ath_hal *ah, int q, const HAL_TXQ_INFO *qInfo) +{ + struct ath_hal_5211 *ahp = AH5211(ah); + + if (q >= HAL_NUM_TX_QUEUES) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid queue num %u\n", + __func__, q); + return AH_FALSE; + } + return ath_hal_setTxQProps(ah, &ahp->ah_txq[q], qInfo); +} + +/* + * Return the properties for the specified tx queue. + */ +HAL_BOOL +ar5211GetTxQueueProps(struct ath_hal *ah, int q, HAL_TXQ_INFO *qInfo) +{ + struct ath_hal_5211 *ahp = AH5211(ah); + + if (q >= HAL_NUM_TX_QUEUES) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid queue num %u\n", + __func__, q); + return AH_FALSE; + } + return ath_hal_getTxQProps(ah, qInfo, &ahp->ah_txq[q]); +} + +/* + * Allocate and initialize a tx DCU/QCU combination. + */ +int +ar5211SetupTxQueue(struct ath_hal *ah, HAL_TX_QUEUE type, + const HAL_TXQ_INFO *qInfo) +{ + struct ath_hal_5211 *ahp = AH5211(ah); + HAL_TX_QUEUE_INFO *qi; + int q; + + switch (type) { + case HAL_TX_QUEUE_BEACON: + q = 9; + break; + case HAL_TX_QUEUE_CAB: + q = 8; + break; + case HAL_TX_QUEUE_DATA: + q = 0; + if (ahp->ah_txq[q].tqi_type != HAL_TX_QUEUE_INACTIVE) + return q; + break; + default: + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad tx queue type %u\n", + __func__, type); + return -1; + } + + HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: queue %u\n", __func__, q); + + qi = &ahp->ah_txq[q]; + if (qi->tqi_type != HAL_TX_QUEUE_INACTIVE) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: tx queue %u already active\n", + __func__, q); + return -1; + } + OS_MEMZERO(qi, sizeof(HAL_TX_QUEUE_INFO)); + qi->tqi_type = type; + if (qInfo == AH_NULL) { + /* by default enable OK+ERR+DESC+URN interrupts */ + qi->tqi_qflags = + HAL_TXQ_TXOKINT_ENABLE + | HAL_TXQ_TXERRINT_ENABLE + | HAL_TXQ_TXDESCINT_ENABLE + | HAL_TXQ_TXURNINT_ENABLE + ; + qi->tqi_aifs = INIT_AIFS; + qi->tqi_cwmin = HAL_TXQ_USEDEFAULT; /* NB: do at reset */ + qi->tqi_cwmax = INIT_CWMAX; + qi->tqi_shretry = INIT_SH_RETRY; + qi->tqi_lgretry = INIT_LG_RETRY; + } else + (void) ar5211SetTxQueueProps(ah, q, qInfo); + return q; +} + +/* + * Update the h/w interrupt registers to reflect a tx q's configuration. + */ +static void +setTxQInterrupts(struct ath_hal *ah, HAL_TX_QUEUE_INFO *qi) +{ + struct ath_hal_5211 *ahp = AH5211(ah); + + HALDEBUG(ah, HAL_DEBUG_TXQUEUE, + "%s: tx ok 0x%x err 0x%x desc 0x%x eol 0x%x urn 0x%x\n", __func__ + , ahp->ah_txOkInterruptMask + , ahp->ah_txErrInterruptMask + , ahp->ah_txDescInterruptMask + , ahp->ah_txEolInterruptMask + , ahp->ah_txUrnInterruptMask + ); + + OS_REG_WRITE(ah, AR_IMR_S0, + SM(ahp->ah_txOkInterruptMask, AR_IMR_S0_QCU_TXOK) + | SM(ahp->ah_txDescInterruptMask, AR_IMR_S0_QCU_TXDESC) + ); + OS_REG_WRITE(ah, AR_IMR_S1, + SM(ahp->ah_txErrInterruptMask, AR_IMR_S1_QCU_TXERR) + | SM(ahp->ah_txEolInterruptMask, AR_IMR_S1_QCU_TXEOL) + ); + OS_REG_RMW_FIELD(ah, AR_IMR_S2, + AR_IMR_S2_QCU_TXURN, ahp->ah_txUrnInterruptMask); +} + + +/* + * Free a tx DCU/QCU combination. + */ +HAL_BOOL +ar5211ReleaseTxQueue(struct ath_hal *ah, u_int q) +{ + struct ath_hal_5211 *ahp = AH5211(ah); + HAL_TX_QUEUE_INFO *qi; + + if (q >= HAL_NUM_TX_QUEUES) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid queue num %u\n", + __func__, q); + return AH_FALSE; + } + qi = &ahp->ah_txq[q]; + if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) { + HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: inactive queue %u\n", + __func__, q); + return AH_FALSE; + } + + HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: release queue %u\n", __func__, q); + + qi->tqi_type = HAL_TX_QUEUE_INACTIVE; + ahp->ah_txOkInterruptMask &= ~(1 << q); + ahp->ah_txErrInterruptMask &= ~(1 << q); + ahp->ah_txDescInterruptMask &= ~(1 << q); + ahp->ah_txEolInterruptMask &= ~(1 << q); + ahp->ah_txUrnInterruptMask &= ~(1 << q); + setTxQInterrupts(ah, qi); + + return AH_TRUE; +} + +/* + * Set the retry, aifs, cwmin/max, readyTime regs for specified queue + */ +HAL_BOOL +ar5211ResetTxQueue(struct ath_hal *ah, u_int q) +{ + struct ath_hal_5211 *ahp = AH5211(ah); + HAL_CHANNEL_INTERNAL *chan = AH_PRIVATE(ah)->ah_curchan; + HAL_TX_QUEUE_INFO *qi; + uint32_t cwMin, chanCwMin, value; + + if (q >= HAL_NUM_TX_QUEUES) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid queue num %u\n", + __func__, q); + return AH_FALSE; + } + qi = &ahp->ah_txq[q]; + if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) { + HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: inactive queue %u\n", + __func__, q); + return AH_TRUE; /* XXX??? */ + } + + if (qi->tqi_cwmin == HAL_TXQ_USEDEFAULT) { + /* + * Select cwmin according to channel type. + * NB: chan can be NULL during attach + */ + if (chan && IS_CHAN_B(chan)) + chanCwMin = INIT_CWMIN_11B; + else + chanCwMin = INIT_CWMIN; + /* make sure that the CWmin is of the form (2^n - 1) */ + for (cwMin = 1; cwMin < chanCwMin; cwMin = (cwMin << 1) | 1) + ; + } else + cwMin = qi->tqi_cwmin; + + /* set cwMin/Max and AIFS values */ + OS_REG_WRITE(ah, AR_DLCL_IFS(q), + SM(cwMin, AR_D_LCL_IFS_CWMIN) + | SM(qi->tqi_cwmax, AR_D_LCL_IFS_CWMAX) + | SM(qi->tqi_aifs, AR_D_LCL_IFS_AIFS)); + + /* Set retry limit values */ + OS_REG_WRITE(ah, AR_DRETRY_LIMIT(q), + SM(INIT_SSH_RETRY, AR_D_RETRY_LIMIT_STA_SH) + | SM(INIT_SLG_RETRY, AR_D_RETRY_LIMIT_STA_LG) + | SM(qi->tqi_lgretry, AR_D_RETRY_LIMIT_FR_LG) + | SM(qi->tqi_shretry, AR_D_RETRY_LIMIT_FR_SH) + ); + + /* enable early termination on the QCU */ + OS_REG_WRITE(ah, AR_QMISC(q), AR_Q_MISC_DCU_EARLY_TERM_REQ); + + if (AH_PRIVATE(ah)->ah_macVersion < AR_SREV_VERSION_OAHU) { + /* Configure DCU to use the global sequence count */ + OS_REG_WRITE(ah, AR_DMISC(q), AR5311_D_MISC_SEQ_NUM_CONTROL); + } + /* multiqueue support */ + if (qi->tqi_cbrPeriod) { + OS_REG_WRITE(ah, AR_QCBRCFG(q), + SM(qi->tqi_cbrPeriod,AR_Q_CBRCFG_CBR_INTERVAL) + | SM(qi->tqi_cbrOverflowLimit, AR_Q_CBRCFG_CBR_OVF_THRESH)); + OS_REG_WRITE(ah, AR_QMISC(q), + OS_REG_READ(ah, AR_QMISC(q)) | + AR_Q_MISC_FSP_CBR | + (qi->tqi_cbrOverflowLimit ? + AR_Q_MISC_CBR_EXP_CNTR_LIMIT : 0)); + } + if (qi->tqi_readyTime) { + OS_REG_WRITE(ah, AR_QRDYTIMECFG(q), + SM(qi->tqi_readyTime, AR_Q_RDYTIMECFG_INT) | + AR_Q_RDYTIMECFG_EN); + } + if (qi->tqi_burstTime) { + OS_REG_WRITE(ah, AR_DCHNTIME(q), + SM(qi->tqi_burstTime, AR_D_CHNTIME_DUR) | + AR_D_CHNTIME_EN); + if (qi->tqi_qflags & HAL_TXQ_RDYTIME_EXP_POLICY_ENABLE) { + OS_REG_WRITE(ah, AR_QMISC(q), + OS_REG_READ(ah, AR_QMISC(q)) | + AR_Q_MISC_RDYTIME_EXP_POLICY); + } + } + + if (qi->tqi_qflags & HAL_TXQ_BACKOFF_DISABLE) { + OS_REG_WRITE(ah, AR_DMISC(q), + OS_REG_READ(ah, AR_DMISC(q)) | + AR_D_MISC_POST_FR_BKOFF_DIS); + } + if (qi->tqi_qflags & HAL_TXQ_FRAG_BURST_BACKOFF_ENABLE) { + OS_REG_WRITE(ah, AR_DMISC(q), + OS_REG_READ(ah, AR_DMISC(q)) | + AR_D_MISC_FRAG_BKOFF_EN); + } + switch (qi->tqi_type) { + case HAL_TX_QUEUE_BEACON: + /* Configure QCU for beacons */ + OS_REG_WRITE(ah, AR_QMISC(q), + OS_REG_READ(ah, AR_QMISC(q)) + | AR_Q_MISC_FSP_DBA_GATED + | AR_Q_MISC_BEACON_USE + | AR_Q_MISC_CBR_INCR_DIS1); + /* Configure DCU for beacons */ + value = (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL << AR_D_MISC_ARB_LOCKOUT_CNTRL_S) + | AR_D_MISC_BEACON_USE | AR_D_MISC_POST_FR_BKOFF_DIS; + if (AH_PRIVATE(ah)->ah_macVersion < AR_SREV_VERSION_OAHU) + value |= AR5311_D_MISC_SEQ_NUM_CONTROL; + OS_REG_WRITE(ah, AR_DMISC(q), value); + break; + case HAL_TX_QUEUE_CAB: + /* Configure QCU for CAB (Crap After Beacon) frames */ + OS_REG_WRITE(ah, AR_QMISC(q), + OS_REG_READ(ah, AR_QMISC(q)) + | AR_Q_MISC_FSP_DBA_GATED | AR_Q_MISC_CBR_INCR_DIS1 + | AR_Q_MISC_CBR_INCR_DIS0 | AR_Q_MISC_RDYTIME_EXP_POLICY); + + value = (ahp->ah_beaconInterval + - (ath_hal_sw_beacon_response_time - ath_hal_dma_beacon_response_time) + - ath_hal_additional_swba_backoff) * 1024; + OS_REG_WRITE(ah, AR_QRDYTIMECFG(q), value | AR_Q_RDYTIMECFG_EN); + + /* Configure DCU for CAB */ + value = (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL << AR_D_MISC_ARB_LOCKOUT_CNTRL_S); + if (AH_PRIVATE(ah)->ah_macVersion < AR_SREV_VERSION_OAHU) + value |= AR5311_D_MISC_SEQ_NUM_CONTROL; + OS_REG_WRITE(ah, AR_QMISC(q), value); + break; + default: + /* NB: silence compiler */ + break; + } + + /* + * Always update the secondary interrupt mask registers - this + * could be a new queue getting enabled in a running system or + * hw getting re-initialized during a reset! + * + * Since we don't differentiate between tx interrupts corresponding + * to individual queues - secondary tx mask regs are always unmasked; + * tx interrupts are enabled/disabled for all queues collectively + * using the primary mask reg + */ + if (qi->tqi_qflags & HAL_TXQ_TXOKINT_ENABLE) + ahp->ah_txOkInterruptMask |= 1 << q; + else + ahp->ah_txOkInterruptMask &= ~(1 << q); + if (qi->tqi_qflags & HAL_TXQ_TXERRINT_ENABLE) + ahp->ah_txErrInterruptMask |= 1 << q; + else + ahp->ah_txErrInterruptMask &= ~(1 << q); + if (qi->tqi_qflags & HAL_TXQ_TXDESCINT_ENABLE) + ahp->ah_txDescInterruptMask |= 1 << q; + else + ahp->ah_txDescInterruptMask &= ~(1 << q); + if (qi->tqi_qflags & HAL_TXQ_TXEOLINT_ENABLE) + ahp->ah_txEolInterruptMask |= 1 << q; + else + ahp->ah_txEolInterruptMask &= ~(1 << q); + if (qi->tqi_qflags & HAL_TXQ_TXURNINT_ENABLE) + ahp->ah_txUrnInterruptMask |= 1 << q; + else + ahp->ah_txUrnInterruptMask &= ~(1 << q); + setTxQInterrupts(ah, qi); + + return AH_TRUE; +} + +/* + * Get the TXDP for the specified data queue. + */ +uint32_t +ar5211GetTxDP(struct ath_hal *ah, u_int q) +{ + HALASSERT(q < HAL_NUM_TX_QUEUES); + return OS_REG_READ(ah, AR_QTXDP(q)); +} + +/* + * Set the TxDP for the specified tx queue. + */ +HAL_BOOL +ar5211SetTxDP(struct ath_hal *ah, u_int q, uint32_t txdp) +{ + HALASSERT(q < HAL_NUM_TX_QUEUES); + HALASSERT(AH5211(ah)->ah_txq[q].tqi_type != HAL_TX_QUEUE_INACTIVE); + + /* + * Make sure that TXE is deasserted before setting the TXDP. If TXE + * is still asserted, setting TXDP will have no effect. + */ + HALASSERT((OS_REG_READ(ah, AR_Q_TXE) & (1 << q)) == 0); + + OS_REG_WRITE(ah, AR_QTXDP(q), txdp); + + return AH_TRUE; +} + +/* + * Set Transmit Enable bits for the specified queues. + */ +HAL_BOOL +ar5211StartTxDma(struct ath_hal *ah, u_int q) +{ + HALASSERT(q < HAL_NUM_TX_QUEUES); + HALASSERT(AH5211(ah)->ah_txq[q].tqi_type != HAL_TX_QUEUE_INACTIVE); + + /* Check that queue is not already active */ + HALASSERT((OS_REG_READ(ah, AR_Q_TXD) & (1<ah_txq[q].tqi_type != HAL_TX_QUEUE_INACTIVE); + + n = OS_REG_READ(ah, AR_QSTS(q)) & AR_Q_STS_PEND_FR_CNT_M; + /* + * Pending frame count (PFC) can momentarily go to zero + * while TXE remains asserted. In other words a PFC of + * zero is not sufficient to say that the queue has stopped. + */ + if (n == 0 && (OS_REG_READ(ah, AR_Q_TXE) & (1<ah_txq[q].tqi_type != HAL_TX_QUEUE_INACTIVE); + + OS_REG_WRITE(ah, AR_Q_TXD, 1<ds_ctl0 = (pktLen & AR_FrameLen) + | (txRate0 << AR_XmitRate_S) + | (antMode << AR_AntModeXmit_S) + | (flags & HAL_TXDESC_CLRDMASK ? AR_ClearDestMask : 0) + | (flags & HAL_TXDESC_INTREQ ? AR_TxInterReq : 0) + | (flags & HAL_TXDESC_RTSENA ? AR_RTSCTSEnable : 0) + | (flags & HAL_TXDESC_VEOL ? AR_VEOL : 0) + ; + ads->ds_ctl1 = (type << 26) + | (flags & HAL_TXDESC_NOACK ? AR_NoAck : 0) + ; + + if (keyIx != HAL_TXKEYIX_INVALID) { + ads->ds_ctl1 |= + (keyIx << AR_EncryptKeyIdx_S) & AR_EncryptKeyIdx; + ads->ds_ctl0 |= AR_EncryptKeyValid; + } + return AH_TRUE; +#undef RATE +} + +HAL_BOOL +ar5211SetupXTxDesc(struct ath_hal *ah, struct ath_desc *ds, + u_int txRate1, u_int txTries1, + u_int txRate2, u_int txTries2, + u_int txRate3, u_int txTries3) +{ + (void) ah; (void) ds; + (void) txRate1; (void) txTries1; + (void) txRate2; (void) txTries2; + (void) txRate3; (void) txTries3; + return AH_FALSE; +} + +void +ar5211IntrReqTxDesc(struct ath_hal *ah, struct ath_desc *ds) +{ + struct ar5211_desc *ads = AR5211DESC(ds); + + ads->ds_ctl0 |= AR_TxInterReq; +} + +HAL_BOOL +ar5211FillTxDesc(struct ath_hal *ah, struct ath_desc *ds, + u_int segLen, HAL_BOOL firstSeg, HAL_BOOL lastSeg, + const struct ath_desc *ds0) +{ + struct ar5211_desc *ads = AR5211DESC(ds); + + HALASSERT((segLen &~ AR_BufLen) == 0); + + if (firstSeg) { + /* + * First descriptor, don't clobber xmit control data + * setup by ar5211SetupTxDesc. + */ + ads->ds_ctl1 |= segLen | (lastSeg ? 0 : AR_More); + } else if (lastSeg) { /* !firstSeg && lastSeg */ + /* + * Last descriptor in a multi-descriptor frame, + * copy the transmit parameters from the first + * frame for processing on completion. + */ + ads->ds_ctl0 = AR5211DESC_CONST(ds0)->ds_ctl0; + ads->ds_ctl1 = segLen; + } else { /* !firstSeg && !lastSeg */ + /* + * Intermediate descriptor in a multi-descriptor frame. + */ + ads->ds_ctl0 = 0; + ads->ds_ctl1 = segLen | AR_More; + } + ads->ds_status0 = ads->ds_status1 = 0; + return AH_TRUE; +} + +/* + * Processing of HW TX descriptor. + */ +HAL_STATUS +ar5211ProcTxDesc(struct ath_hal *ah, + struct ath_desc *ds, struct ath_tx_status *ts) +{ + struct ar5211_desc *ads = AR5211DESC(ds); + + if ((ads->ds_status1 & AR_Done) == 0) + return HAL_EINPROGRESS; + + /* Update software copies of the HW status */ + ts->ts_seqnum = MS(ads->ds_status1, AR_SeqNum); + ts->ts_tstamp = MS(ads->ds_status0, AR_SendTimestamp); + ts->ts_status = 0; + if ((ads->ds_status0 & AR_FrmXmitOK) == 0) { + if (ads->ds_status0 & AR_ExcessiveRetries) + ts->ts_status |= HAL_TXERR_XRETRY; + if (ads->ds_status0 & AR_Filtered) + ts->ts_status |= HAL_TXERR_FILT; + if (ads->ds_status0 & AR_FIFOUnderrun) + ts->ts_status |= HAL_TXERR_FIFO; + } + ts->ts_rate = MS(ads->ds_ctl0, AR_XmitRate); + ts->ts_rssi = MS(ads->ds_status1, AR_AckSigStrength); + ts->ts_shortretry = MS(ads->ds_status0, AR_ShortRetryCnt); + ts->ts_longretry = MS(ads->ds_status0, AR_LongRetryCnt); + ts->ts_virtcol = MS(ads->ds_status0, AR_VirtCollCnt); + ts->ts_antenna = 0; /* NB: don't know */ + ts->ts_finaltsi = 0; + /* + * NB: the number of retries is one less than it should be. + * Also, 0 retries and 1 retry are both reported as 0 retries. + */ + if (ts->ts_shortretry > 0) + ts->ts_shortretry++; + if (ts->ts_longretry > 0) + ts->ts_longretry++; + + return HAL_OK; +} + +/* + * Determine which tx queues need interrupt servicing. + * STUB. + */ +void +ar5211GetTxIntrQueue(struct ath_hal *ah, uint32_t *txqs) +{ + return; +} --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5211/ar5211desc.h 2009-03-23 17:36:55.000000000 +0000 @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2006 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ar5211desc.h,v 1.1 2009/03/23 17:14:47 sborrill Exp $ + */ +#ifndef _DEV_ATH_AR5211DESC_H +#define _DEV_ATH_AR5211DESC_H + +#include "ah_desc.h" + +/* + * Defintions for the DMA descriptors used by the Atheros + * AR5211 and AR5110 Wireless Lan controller parts. + */ + +/* DMA descriptors */ +struct ar5211_desc { + uint32_t ds_link; /* link pointer */ + uint32_t ds_data; /* data buffer pointer */ + uint32_t ds_ctl0; /* DMA control 0 */ + uint32_t ds_ctl1; /* DMA control 1 */ + uint32_t ds_status0; /* DMA status 0 */ + uint32_t ds_status1; /* DMA status 1 */ +} __packed; +#define AR5211DESC(_ds) ((struct ar5211_desc *)(_ds)) +#define AR5211DESC_CONST(_ds) ((const struct ar5211_desc *)(_ds)) + +/* TX ds_ctl0 */ +#define AR_FrameLen 0x00000fff /* frame length */ +/* bits 12-17 are reserved */ +#define AR_XmitRate 0x003c0000 /* txrate */ +#define AR_XmitRate_S 18 +#define AR_RTSCTSEnable 0x00400000 /* RTS/CTS enable */ +#define AR_VEOL 0x00800000 /* virtual end-of-list */ +#define AR_ClearDestMask 0x01000000 /* Clear destination mask bit */ +#define AR_AntModeXmit 0x1e000000 /* TX antenna seslection */ +#define AR_AntModeXmit_S 25 +#define AR_TxInterReq 0x20000000 /* TX interrupt request */ +#define AR_EncryptKeyValid 0x40000000 /* EncryptKeyIdx is valid */ +/* bit 31 is reserved */ + +/* TX ds_ctl1 */ +#define AR_BufLen 0x00000fff /* data buffer length */ +#define AR_More 0x00001000 /* more desc in this frame */ +#define AR_EncryptKeyIdx 0x000fe000 /* ecnrypt key table index */ +#define AR_EncryptKeyIdx_S 13 +#define AR_FrmType 0x00700000 /* frame type indication */ +#define AR_FrmType_S 20 +#define AR_Frm_Normal 0x00000000 /* normal frame */ +#define AR_Frm_ATIM 0x00100000 /* ATIM frame */ +#define AR_Frm_PSPOLL 0x00200000 /* PS poll frame */ +#define AR_Frm_Beacon 0x00300000 /* Beacon frame */ +#define AR_Frm_ProbeResp 0x00400000 /* no delay data */ +#define AR_NoAck 0x00800000 /* No ACK flag */ +/* bits 24-31 are reserved */ + +/* RX ds_ctl1 */ +/* AR_BufLen 0x00000fff data buffer length */ +/* bit 12 is reserved */ +#define AR_RxInterReq 0x00002000 /* RX interrupt request */ +/* bits 14-31 are reserved */ + +/* TX ds_status0 */ +#define AR_FrmXmitOK 0x00000001 /* TX success */ +#define AR_ExcessiveRetries 0x00000002 /* excessive retries */ +#define AR_FIFOUnderrun 0x00000004 /* TX FIFO underrun */ +#define AR_Filtered 0x00000008 /* TX filter indication */ +/* NB: the spec has the Short+Long retry counts reversed */ +#define AR_LongRetryCnt 0x000000f0 /* long retry count */ +#define AR_LongRetryCnt_S 4 +#define AR_ShortRetryCnt 0x00000f00 /* short retry count */ +#define AR_ShortRetryCnt_S 8 +#define AR_VirtCollCnt 0x0000f000 /* virtual collision count */ +#define AR_VirtCollCnt_S 12 +#define AR_SendTimestamp 0xffff0000 /* TX timestamp */ +#define AR_SendTimestamp_S 16 + +/* RX ds_status0 */ +#define AR_DataLen 0x00000fff /* RX data length */ +/* AR_More 0x00001000 more desc in this frame */ +/* bits 13-14 are reserved */ +#define AR_RcvRate 0x00078000 /* reception rate */ +#define AR_RcvRate_S 15 +#define AR_RcvSigStrength 0x07f80000 /* receive signal strength */ +#define AR_RcvSigStrength_S 19 +#define AR_RcvAntenna 0x38000000 /* receive antenaa */ +#define AR_RcvAntenna_S 27 +/* bits 30-31 are reserved */ + +/* TX ds_status1 */ +#define AR_Done 0x00000001 /* descripter complete */ +#define AR_SeqNum 0x00001ffe /* TX sequence number */ +#define AR_SeqNum_S 1 +#define AR_AckSigStrength 0x001fe000 /* strength of ACK */ +#define AR_AckSigStrength_S 13 +/* bits 21-31 are reserved */ + +/* RX ds_status1 */ +/* AR_Done 0x00000001 descripter complete */ +#define AR_FrmRcvOK 0x00000002 /* frame reception success */ +#define AR_CRCErr 0x00000004 /* CRC error */ +/* bit 3 reserved */ +#define AR_DecryptCRCErr 0x00000010 /* Decryption CRC fiailure */ +#define AR_PHYErr 0x000000e0 /* PHY error */ +#define AR_PHYErr_S 5 +#define AR_PHYErr_Underrun 0x00000000 /* Transmit underrun */ +#define AR_PHYErr_Tim 0x00000020 /* Timing error */ +#define AR_PHYErr_Par 0x00000040 /* Parity error */ +#define AR_PHYErr_Rate 0x00000060 /* Illegal rate */ +#define AR_PHYErr_Len 0x00000080 /* Illegal length */ +#define AR_PHYErr_Radar 0x000000a0 /* Radar detect */ +#define AR_PHYErr_Srv 0x000000c0 /* Illegal service */ +#define AR_PHYErr_TOR 0x000000e0 /* Transmit override receive */ +#define AR_KeyIdxValid 0x00000100 /* decryption key index valid */ +#define AR_KeyIdx 0x00007e00 /* Decryption key index */ +#define AR_KeyIdx_S 9 +#define AR_RcvTimestamp 0x0fff8000 /* timestamp */ +#define AR_RcvTimestamp_S 15 +#define AR_KeyCacheMiss 0x10000000 /* key cache miss indication */ + +#endif /* _DEV_ATH_AR5211DESC_H_ */ --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5211/ar5211phy.h 2009-03-23 17:36:55.000000000 +0000 @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2006 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ar5211phy.h,v 1.1 2009/03/23 17:14:47 sborrill Exp $ + */ +#ifndef _DEV_ATH_AR5211PHY_H +#define _DEV_ATH_AR5211PHY_H + +/* + * Definitions for the PHY on the Atheros AR5211/5311 chipset. + */ + +/* PHY registers */ +#define AR_PHY_BASE 0x9800 /* PHY registers base address */ +#define AR_PHY(_n) (AR_PHY_BASE + ((_n)<<2)) + +#define AR_PHY_TURBO 0x9804 /* PHY frame control register */ +#define AR_PHY_FC_TURBO_MODE 0x00000001 /* Set turbo mode bits */ +#define AR_PHY_FC_TURBO_SHORT 0x00000002 /* Set short symbols to turbo mode setting */ + +#define AR_PHY_CHIP_ID 0x9818 /* PHY chip revision ID */ + +#define AR_PHY_ACTIVE 0x981C /* PHY activation register */ +#define AR_PHY_ACTIVE_EN 0x00000001 /* Activate PHY chips */ +#define AR_PHY_ACTIVE_DIS 0x00000000 /* Deactivate PHY chips */ + +#define AR_PHY_AGC_CONTROL 0x9860 /* PHY chip calibration and noise floor setting */ +#define AR_PHY_AGC_CONTROL_CAL 0x00000001 /* Perform PHY chip internal calibration */ +#define AR_PHY_AGC_CONTROL_NF 0x00000002 /* Perform PHY chip noise-floor calculation */ + +#define AR_PHY_PLL_CTL 0x987c /* PLL control register */ +#define AR_PHY_PLL_CTL_44 0x19 /* 44 MHz for 11b channels and FPGA */ +#define AR_PHY_PLL_CTL_40 0x18 /* 40 MHz */ +#define AR_PHY_PLL_CTL_20 0x13 /* 20 MHz half rate 11a for emulation */ + + +#define AR_PHY_RX_DELAY 0x9914 /* PHY analog_power_on_time, in 100ns increments */ +#define AR_PHY_RX_DELAY_M 0x00003FFF /* Mask for delay from active assertion (wake up) */ + /* to enable_receiver */ + +#define AR_PHY_TIMING_CTRL4 0x9920 /* PHY */ +#define AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF_M 0x0000001F /* Mask for kcos_theta-1 for q correction */ +#define AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF_M 0x000007E0 /* Mask for sin_theta for i correction */ +#define AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF_S 5 /* Shift for sin_theta for i correction */ +#define AR_PHY_TIMING_CTRL4_IQCORR_ENABLE 0x00000800 /* enable IQ correction */ +#define AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX_M 0x0000F000 /* Mask for max number of samples (logarithmic) */ +#define AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX_S 12 /* Shift for max number of samples */ +#define AR_PHY_TIMING_CTRL4_DO_IQCAL 0x00010000 /* perform IQ calibration */ + +#define AR_PHY_PAPD_PROBE 0x9930 +#define AR_PHY_PAPD_PROBE_POWERTX 0x00007E00 +#define AR_PHY_PAPD_PROBE_POWERTX_S 9 +#define AR_PHY_PAPD_PROBE_NEXT_TX 0x00008000 /* command to take next reading */ +#define AR_PHY_PAPD_PROBE_GAINF 0xFE000000 +#define AR_PHY_PAPD_PROBE_GAINF_S 25 + +#define AR_PHY_POWER_TX_RATE1 0x9934 +#define AR_PHY_POWER_TX_RATE2 0x9938 +#define AR_PHY_POWER_TX_RATE_MAX 0x993c + +#define AR_PHY_FRAME_CTL 0x9944 +#define AR_PHY_FRAME_CTL_TX_CLIP 0x00000038 +#define AR_PHY_FRAME_CTL_TX_CLIP_S 3 +#define AR_PHY_FRAME_CTL_ERR_SERV 0x20000000 +#define AR_PHY_FRAME_CTL_ERR_SERV_S 29 + +#define AR_PHY_RADAR_0 0x9954 /* PHY radar detection settings */ +#define AR_PHY_RADAR_0_ENA 0x00000001 /* Enable radar detection */ + +#define AR_PHY_IQCAL_RES_PWR_MEAS_I 0x9c10 /*PHY IQ calibration results - power measurement for I */ +#define AR_PHY_IQCAL_RES_PWR_MEAS_Q 0x9c14 /*PHY IQ calibration results - power measurement for Q */ +#define AR_PHY_IQCAL_RES_IQ_CORR_MEAS 0x9c18 /*PHY IQ calibration results - IQ correlation measurement */ +#define AR_PHY_CURRENT_RSSI 0x9c1c /* rssi of current frame being received */ + +#define AR5211_PHY_MODE 0xA200 /* Mode register */ +#define AR5211_PHY_MODE_OFDM 0x0 /* bit 0 = 0 for OFDM */ +#define AR5211_PHY_MODE_CCK 0x1 /* bit 0 = 1 for CCK */ +#define AR5211_PHY_MODE_RF5GHZ 0x0 /* bit 1 = 0 for 5 GHz */ +#define AR5211_PHY_MODE_RF2GHZ 0x2 /* bit 1 = 1 for 2.4 GHz */ + +#endif /* _DEV_ATH_AR5211PHY_H */ --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5211/ar5211reg.h 2009-03-23 17:36:55.000000000 +0000 @@ -0,0 +1,853 @@ +/* + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2006 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ar5211reg.h,v 1.1 2009/03/23 17:14:47 sborrill Exp $ + */ +#ifndef _DEV_ATH_AR5211REG_H +#define _DEV_ATH_AR5211REG_H + +/* + * Definitions for the Atheros AR5211/5311 chipset. + */ + +/* + * Maui2/Spirit specific registers/fields are indicated by AR5311. + * Oahu specific registers/fields are indicated by AR5211. + */ + +/* DMA Control and Interrupt Registers */ +#define AR_CR 0x0008 /* control register */ +#define AR_RXDP 0x000C /* receive queue descriptor pointer */ +#define AR_CFG 0x0014 /* configuration and status register */ +#define AR_IER 0x0024 /* Interrupt enable register */ +#define AR_RTSD0 0x0028 /* RTS Duration Parameters 0 */ +#define AR_RTSD1 0x002c /* RTS Duration Parameters 1 */ +#define AR_TXCFG 0x0030 /* tx DMA size config register */ +#define AR_RXCFG 0x0034 /* rx DMA size config register */ +#define AR5211_JUMBO_LAST 0x0038 /* Jumbo descriptor last address */ +#define AR_MIBC 0x0040 /* MIB control register */ +#define AR_TOPS 0x0044 /* timeout prescale count */ +#define AR_RXNPTO 0x0048 /* no frame received timeout */ +#define AR_TXNPTO 0x004C /* no frame trasmitted timeout */ +#define AR_RFGTO 0x0050 /* receive frame gap timeout */ +#define AR_RFCNT 0x0054 /* receive frame count limit */ +#define AR_MACMISC 0x0058 /* miscellaneous control/status */ +#define AR5311_QDCLKGATE 0x005c /* QCU/DCU clock gating control */ +#define AR_ISR 0x0080 /* Primary interrupt status register */ +#define AR_ISR_S0 0x0084 /* Secondary interrupt status reg 0 */ +#define AR_ISR_S1 0x0088 /* Secondary interrupt status reg 1 */ +#define AR_ISR_S2 0x008c /* Secondary interrupt status reg 2 */ +#define AR_ISR_S3 0x0090 /* Secondary interrupt status reg 3 */ +#define AR_ISR_S4 0x0094 /* Secondary interrupt status reg 4 */ +#define AR_IMR 0x00a0 /* Primary interrupt mask register */ +#define AR_IMR_S0 0x00a4 /* Secondary interrupt mask reg 0 */ +#define AR_IMR_S1 0x00a8 /* Secondary interrupt mask reg 1 */ +#define AR_IMR_S2 0x00ac /* Secondary interrupt mask reg 2 */ +#define AR_IMR_S3 0x00b0 /* Secondary interrupt mask reg 3 */ +#define AR_IMR_S4 0x00b4 /* Secondary interrupt mask reg 4 */ +#define AR_ISR_RAC 0x00c0 /* Primary interrupt status reg, */ +/* Shadow copies with read-and-clear access */ +#define AR_ISR_S0_S 0x00c4 /* Secondary interrupt status reg 0 */ +#define AR_ISR_S1_S 0x00c8 /* Secondary interrupt status reg 1 */ +#define AR_ISR_S2_S 0x00cc /* Secondary interrupt status reg 2 */ +#define AR_ISR_S3_S 0x00d0 /* Secondary interrupt status reg 3 */ +#define AR_ISR_S4_S 0x00d4 /* Secondary interrupt status reg 4 */ + +#define AR_Q0_TXDP 0x0800 /* Transmit Queue descriptor pointer */ +#define AR_Q1_TXDP 0x0804 /* Transmit Queue descriptor pointer */ +#define AR_Q2_TXDP 0x0808 /* Transmit Queue descriptor pointer */ +#define AR_Q3_TXDP 0x080c /* Transmit Queue descriptor pointer */ +#define AR_Q4_TXDP 0x0810 /* Transmit Queue descriptor pointer */ +#define AR_Q5_TXDP 0x0814 /* Transmit Queue descriptor pointer */ +#define AR_Q6_TXDP 0x0818 /* Transmit Queue descriptor pointer */ +#define AR_Q7_TXDP 0x081c /* Transmit Queue descriptor pointer */ +#define AR_Q8_TXDP 0x0820 /* Transmit Queue descriptor pointer */ +#define AR_Q9_TXDP 0x0824 /* Transmit Queue descriptor pointer */ +#define AR_QTXDP(i) (AR_Q0_TXDP + ((i)<<2)) + +#define AR_Q_TXE 0x0840 /* Transmit Queue enable */ +#define AR_Q_TXD 0x0880 /* Transmit Queue disable */ + +#define AR_Q0_CBRCFG 0x08c0 /* CBR configuration */ +#define AR_Q1_CBRCFG 0x08c4 /* CBR configuration */ +#define AR_Q2_CBRCFG 0x08c8 /* CBR configuration */ +#define AR_Q3_CBRCFG 0x08cc /* CBR configuration */ +#define AR_Q4_CBRCFG 0x08d0 /* CBR configuration */ +#define AR_Q5_CBRCFG 0x08d4 /* CBR configuration */ +#define AR_Q6_CBRCFG 0x08d8 /* CBR configuration */ +#define AR_Q7_CBRCFG 0x08dc /* CBR configuration */ +#define AR_Q8_CBRCFG 0x08e0 /* CBR configuration */ +#define AR_Q9_CBRCFG 0x08e4 /* CBR configuration */ +#define AR_QCBRCFG(i) (AR_Q0_CBRCFG + ((i)<<2)) + +#define AR_Q0_RDYTIMECFG 0x0900 /* ReadyTime configuration */ +#define AR_Q1_RDYTIMECFG 0x0904 /* ReadyTime configuration */ +#define AR_Q2_RDYTIMECFG 0x0908 /* ReadyTime configuration */ +#define AR_Q3_RDYTIMECFG 0x090c /* ReadyTime configuration */ +#define AR_Q4_RDYTIMECFG 0x0910 /* ReadyTime configuration */ +#define AR_Q5_RDYTIMECFG 0x0914 /* ReadyTime configuration */ +#define AR_Q6_RDYTIMECFG 0x0918 /* ReadyTime configuration */ +#define AR_Q7_RDYTIMECFG 0x091c /* ReadyTime configuration */ +#define AR_Q8_RDYTIMECFG 0x0920 /* ReadyTime configuration */ +#define AR_Q9_RDYTIMECFG 0x0924 /* ReadyTime configuration */ +#define AR_QRDYTIMECFG(i) (AR_Q0_RDYTIMECFG + ((i)<<2)) + +#define AR_Q_ONESHOTARM_SC 0x0940 /* OneShotArm set control */ +#define AR_Q_ONESHOTARM_CC 0x0980 /* OneShotArm clear control */ + +#define AR_Q0_MISC 0x09c0 /* Miscellaneous QCU settings */ +#define AR_Q1_MISC 0x09c4 /* Miscellaneous QCU settings */ +#define AR_Q2_MISC 0x09c8 /* Miscellaneous QCU settings */ +#define AR_Q3_MISC 0x09cc /* Miscellaneous QCU settings */ +#define AR_Q4_MISC 0x09d0 /* Miscellaneous QCU settings */ +#define AR_Q5_MISC 0x09d4 /* Miscellaneous QCU settings */ +#define AR_Q6_MISC 0x09d8 /* Miscellaneous QCU settings */ +#define AR_Q7_MISC 0x09dc /* Miscellaneous QCU settings */ +#define AR_Q8_MISC 0x09e0 /* Miscellaneous QCU settings */ +#define AR_Q9_MISC 0x09e4 /* Miscellaneous QCU settings */ +#define AR_QMISC(i) (AR_Q0_MISC + ((i)<<2)) + +#define AR_Q0_STS 0x0a00 /* Miscellaneous QCU status */ +#define AR_Q1_STS 0x0a04 /* Miscellaneous QCU status */ +#define AR_Q2_STS 0x0a08 /* Miscellaneous QCU status */ +#define AR_Q3_STS 0x0a0c /* Miscellaneous QCU status */ +#define AR_Q4_STS 0x0a10 /* Miscellaneous QCU status */ +#define AR_Q5_STS 0x0a14 /* Miscellaneous QCU status */ +#define AR_Q6_STS 0x0a18 /* Miscellaneous QCU status */ +#define AR_Q7_STS 0x0a1c /* Miscellaneous QCU status */ +#define AR_Q8_STS 0x0a20 /* Miscellaneous QCU status */ +#define AR_Q9_STS 0x0a24 /* Miscellaneous QCU status */ +#define AR_QSTS(i) (AR_Q0_STS + ((i)<<2)) + +#define AR_Q_RDYTIMESHDN 0x0a40 /* ReadyTimeShutdown status */ +#define AR_D0_QCUMASK 0x1000 /* QCU Mask */ +#define AR_D1_QCUMASK 0x1004 /* QCU Mask */ +#define AR_D2_QCUMASK 0x1008 /* QCU Mask */ +#define AR_D3_QCUMASK 0x100c /* QCU Mask */ +#define AR_D4_QCUMASK 0x1010 /* QCU Mask */ +#define AR_D5_QCUMASK 0x1014 /* QCU Mask */ +#define AR_D6_QCUMASK 0x1018 /* QCU Mask */ +#define AR_D7_QCUMASK 0x101c /* QCU Mask */ +#define AR_D8_QCUMASK 0x1020 /* QCU Mask */ +#define AR_D9_QCUMASK 0x1024 /* QCU Mask */ +#define AR_DQCUMASK(i) (AR_D0_QCUMASK + ((i)<<2)) + +#define AR_D0_LCL_IFS 0x1040 /* DCU-specific IFS settings */ +#define AR_D1_LCL_IFS 0x1044 /* DCU-specific IFS settings */ +#define AR_D2_LCL_IFS 0x1048 /* DCU-specific IFS settings */ +#define AR_D3_LCL_IFS 0x104c /* DCU-specific IFS settings */ +#define AR_D4_LCL_IFS 0x1050 /* DCU-specific IFS settings */ +#define AR_D5_LCL_IFS 0x1054 /* DCU-specific IFS settings */ +#define AR_D6_LCL_IFS 0x1058 /* DCU-specific IFS settings */ +#define AR_D7_LCL_IFS 0x105c /* DCU-specific IFS settings */ +#define AR_D8_LCL_IFS 0x1060 /* DCU-specific IFS settings */ +#define AR_D9_LCL_IFS 0x1064 /* DCU-specific IFS settings */ +#define AR_DLCL_IFS(i) (AR_D0_LCL_IFS + ((i)<<2)) + +#define AR_D0_RETRY_LIMIT 0x1080 /* Retry limits */ +#define AR_D1_RETRY_LIMIT 0x1084 /* Retry limits */ +#define AR_D2_RETRY_LIMIT 0x1088 /* Retry limits */ +#define AR_D3_RETRY_LIMIT 0x108c /* Retry limits */ +#define AR_D4_RETRY_LIMIT 0x1090 /* Retry limits */ +#define AR_D5_RETRY_LIMIT 0x1094 /* Retry limits */ +#define AR_D6_RETRY_LIMIT 0x1098 /* Retry limits */ +#define AR_D7_RETRY_LIMIT 0x109c /* Retry limits */ +#define AR_D8_RETRY_LIMIT 0x10a0 /* Retry limits */ +#define AR_D9_RETRY_LIMIT 0x10a4 /* Retry limits */ +#define AR_DRETRY_LIMIT(i) (AR_D0_RETRY_LIMIT + ((i)<<2)) + +#define AR_D0_CHNTIME 0x10c0 /* ChannelTime settings */ +#define AR_D1_CHNTIME 0x10c4 /* ChannelTime settings */ +#define AR_D2_CHNTIME 0x10c8 /* ChannelTime settings */ +#define AR_D3_CHNTIME 0x10cc /* ChannelTime settings */ +#define AR_D4_CHNTIME 0x10d0 /* ChannelTime settings */ +#define AR_D5_CHNTIME 0x10d4 /* ChannelTime settings */ +#define AR_D6_CHNTIME 0x10d8 /* ChannelTime settings */ +#define AR_D7_CHNTIME 0x10dc /* ChannelTime settings */ +#define AR_D8_CHNTIME 0x10e0 /* ChannelTime settings */ +#define AR_D9_CHNTIME 0x10e4 /* ChannelTime settings */ +#define AR_DCHNTIME(i) (AR_D0_CHNTIME + ((i)<<2)) + +#define AR_D0_MISC 0x1100 /* Misc DCU-specific settings */ +#define AR_D1_MISC 0x1104 /* Misc DCU-specific settings */ +#define AR_D2_MISC 0x1108 /* Misc DCU-specific settings */ +#define AR_D3_MISC 0x110c /* Misc DCU-specific settings */ +#define AR_D4_MISC 0x1110 /* Misc DCU-specific settings */ +#define AR_D5_MISC 0x1114 /* Misc DCU-specific settings */ +#define AR_D6_MISC 0x1118 /* Misc DCU-specific settings */ +#define AR_D7_MISC 0x111c /* Misc DCU-specific settings */ +#define AR_D8_MISC 0x1120 /* Misc DCU-specific settings */ +#define AR_D9_MISC 0x1124 /* Misc DCU-specific settings */ +#define AR_DMISC(i) (AR_D0_MISC + ((i)<<2)) + +#define AR_D0_SEQNUM 0x1140 /* Frame seqnum control/status */ +#define AR_D1_SEQNUM 0x1144 /* Frame seqnum control/status */ +#define AR_D2_SEQNUM 0x1148 /* Frame seqnum control/status */ +#define AR_D3_SEQNUM 0x114c /* Frame seqnum control/status */ +#define AR_D4_SEQNUM 0x1150 /* Frame seqnum control/status */ +#define AR_D5_SEQNUM 0x1154 /* Frame seqnum control/status */ +#define AR_D6_SEQNUM 0x1158 /* Frame seqnum control/status */ +#define AR_D7_SEQNUM 0x115c /* Frame seqnum control/status */ +#define AR_D8_SEQNUM 0x1160 /* Frame seqnum control/status */ +#define AR_D9_SEQNUM 0x1164 /* Frame seqnum control/status */ +#define AR_DSEQNUM(i) (AR_D0_SEQNUM + ((i<<2))) + +/* MAC DCU-global IFS settings */ +#define AR_D_GBL_IFS_SIFS 0x1030 /* DCU global SIFS settings */ +#define AR_D_GBL_IFS_SLOT 0x1070 /* DC global slot interval */ +#define AR_D_GBL_IFS_EIFS 0x10b0 /* DCU global EIFS setting */ +#define AR_D_GBL_IFS_MISC 0x10f0 /* DCU global misc. IFS settings */ +#define AR_D_FPCTL 0x1230 /* DCU frame prefetch settings */ +#define AR_D_TXPSE 0x1270 /* DCU transmit pause control/status */ +#define AR_D_TXBLK_CMD 0x1038 /* DCU transmit filter cmd (w/only) */ +#define AR_D_TXBLK_DATA(i) (AR_D_TXBLK_CMD+(i)) /* DCU transmit filter data */ +#define AR_D_TXBLK_CLR 0x143c /* DCU clear tx filter (w/only) */ +#define AR_D_TXBLK_SET 0x147c /* DCU set tx filter (w/only) */ + +#define AR_D_TXPSE 0x1270 /* DCU transmit pause control/status */ + +#define AR_RC 0x4000 /* Warm reset control register */ +#define AR_SCR 0x4004 /* Sleep control register */ +#define AR_INTPEND 0x4008 /* Interrupt Pending register */ +#define AR_SFR 0x400C /* Sleep force register */ +#define AR_PCICFG 0x4010 /* PCI configuration register */ +#define AR_GPIOCR 0x4014 /* GPIO control register */ +#define AR_GPIODO 0x4018 /* GPIO data output access register */ +#define AR_GPIODI 0x401C /* GPIO data input access register */ +#define AR_SREV 0x4020 /* Silicon Revision register */ + +#define AR_EEPROM_ADDR 0x6000 /* EEPROM address register (10 bit) */ +#define AR_EEPROM_DATA 0x6004 /* EEPROM data register (16 bit) */ +#define AR_EEPROM_CMD 0x6008 /* EEPROM command register */ +#define AR_EEPROM_STS 0x600c /* EEPROM status register */ +#define AR_EEPROM_CFG 0x6010 /* EEPROM configuration register */ + +#define AR_STA_ID0 0x8000 /* station ID0 - low 32 bits */ +#define AR_STA_ID1 0x8004 /* station ID1 - upper 16 bits */ +#define AR_BSS_ID0 0x8008 /* BSSID low 32 bits */ +#define AR_BSS_ID1 0x800C /* BSSID upper 16 bits / AID */ +#define AR_SLOT_TIME 0x8010 /* Time-out after a collision */ +#define AR_TIME_OUT 0x8014 /* ACK & CTS time-out */ +#define AR_RSSI_THR 0x8018 /* RSSI warning & missed beacon threshold */ +#define AR_USEC 0x801c /* transmit latency register */ +#define AR_BEACON 0x8020 /* beacon control value/mode bits */ +#define AR_CFP_PERIOD 0x8024 /* CFP Interval (TU/msec) */ +#define AR_TIMER0 0x8028 /* Next beacon time (TU/msec) */ +#define AR_TIMER1 0x802c /* DMA beacon alert time (1/8 TU) */ +#define AR_TIMER2 0x8030 /* Software beacon alert (1/8 TU) */ +#define AR_TIMER3 0x8034 /* ATIM window time */ +#define AR_CFP_DUR 0x8038 /* maximum CFP duration in TU */ +#define AR_RX_FILTER 0x803C /* receive filter register */ +#define AR_MCAST_FIL0 0x8040 /* multicast filter lower 32 bits */ +#define AR_MCAST_FIL1 0x8044 /* multicast filter upper 32 bits */ +#define AR_DIAG_SW 0x8048 /* PCU control register */ +#define AR_TSF_L32 0x804c /* local clock lower 32 bits */ +#define AR_TSF_U32 0x8050 /* local clock upper 32 bits */ +#define AR_TST_ADDAC 0x8054 /* ADDAC test register */ +#define AR_DEF_ANTENNA 0x8058 /* default antenna register */ + +#define AR_LAST_TSTP 0x8080 /* Time stamp of the last beacon rcvd */ +#define AR_NAV 0x8084 /* current NAV value */ +#define AR_RTS_OK 0x8088 /* RTS exchange success counter */ +#define AR_RTS_FAIL 0x808c /* RTS exchange failure counter */ +#define AR_ACK_FAIL 0x8090 /* ACK failure counter */ +#define AR_FCS_FAIL 0x8094 /* FCS check failure counter */ +#define AR_BEACON_CNT 0x8098 /* Valid beacon counter */ + +#define AR_KEYTABLE_0 0x8800 /* Encryption key table */ +#define AR_KEYTABLE(n) (AR_KEYTABLE_0 + ((n)*32)) + +#define AR_CR_RXE 0x00000004 /* Receive enable */ +#define AR_CR_RXD 0x00000020 /* Receive disable */ +#define AR_CR_SWI 0x00000040 /* One-shot software interrupt */ +#define AR_CR_BITS "\20\3RXE\6RXD\7SWI" + +#define AR_CFG_SWTD 0x00000001 /* byteswap tx descriptor words */ +#define AR_CFG_SWTB 0x00000002 /* byteswap tx data buffer words */ +#define AR_CFG_SWRD 0x00000004 /* byteswap rx descriptor words */ +#define AR_CFG_SWRB 0x00000008 /* byteswap rx data buffer words */ +#define AR_CFG_SWRG 0x00000010 /* byteswap register access data words */ +#define AR_CFG_AP_ADHOC_INDICATION 0x00000020 /* AP/adhoc indication (0-AP, 1-Adhoc) */ +#define AR_CFG_PHOK 0x00000100 /* PHY OK status */ +#define AR_CFG_EEBS 0x00000200 /* EEPROM busy */ +#define AR_CFG_CLK_GATE_DIS 0x00000400 /* Clock gating disable (Oahu only) */ +#define AR_CFG_PCI_MASTER_REQ_Q_THRESH_M 0x00060000 /* Mask of PCI core master request queue full threshold */ +#define AR_CFG_PCI_MASTER_REQ_Q_THRESH_S 17 /* Shift for PCI core master request queue full threshold */ +#define AR_CFG_BITS \ + "\20\1SWTD\2SWTB\3SWRD\4SWRB\5SWRG\10PHYOK11EEBS" + +#define AR_IER_ENABLE 0x00000001 /* Global interrupt enable */ +#define AR_IER_DISABLE 0x00000000 /* Global interrupt disable */ +#define AR_IER_BITS "\20\1ENABLE" + +#define AR_RTSD0_RTS_DURATION_6_M 0x000000FF +#define AR_RTSD0_RTS_DURATION_6_S 0 +#define AR_RTSD0_RTS_DURATION_9_M 0x0000FF00 +#define AR_RTSD0_RTS_DURATION_9_S 8 +#define AR_RTSD0_RTS_DURATION_12_M 0x00FF0000 +#define AR_RTSD0_RTS_DURATION_12_S 16 +#define AR_RTSD0_RTS_DURATION_18_M 0xFF000000 +#define AR_RTSD0_RTS_DURATION_18_S 24 + +#define AR_RTSD0_RTS_DURATION_24_M 0x000000FF +#define AR_RTSD0_RTS_DURATION_24_S 0 +#define AR_RTSD0_RTS_DURATION_36_M 0x0000FF00 +#define AR_RTSD0_RTS_DURATION_36_S 8 +#define AR_RTSD0_RTS_DURATION_48_M 0x00FF0000 +#define AR_RTSD0_RTS_DURATION_48_S 16 +#define AR_RTSD0_RTS_DURATION_54_M 0xFF000000 +#define AR_RTSD0_RTS_DURATION_54_S 24 + +#define AR_DMASIZE_4B 0x00000000 /* DMA size 4 bytes (TXCFG + RXCFG) */ +#define AR_DMASIZE_8B 0x00000001 /* DMA size 8 bytes */ +#define AR_DMASIZE_16B 0x00000002 /* DMA size 16 bytes */ +#define AR_DMASIZE_32B 0x00000003 /* DMA size 32 bytes */ +#define AR_DMASIZE_64B 0x00000004 /* DMA size 64 bytes */ +#define AR_DMASIZE_128B 0x00000005 /* DMA size 128 bytes */ +#define AR_DMASIZE_256B 0x00000006 /* DMA size 256 bytes */ +#define AR_DMASIZE_512B 0x00000007 /* DMA size 512 bytes */ + +#define AR_TXCFG_FTRIG_M 0x000003F0 /* Mask for Frame trigger level */ +#define AR_TXCFG_FTRIG_S 4 /* Shift for Frame trigger level */ +#define AR_TXCFG_FTRIG_IMMED 0x00000000 /* bytes in PCU TX FIFO before air */ +#define AR_TXCFG_FTRIG_64B 0x00000010 /* default */ +#define AR_TXCFG_FTRIG_128B 0x00000020 +#define AR_TXCFG_FTRIG_192B 0x00000030 +#define AR_TXCFG_FTRIG_256B 0x00000040 /* 5 bits total */ +#define AR_TXCFG_BITS "\20" + +#define AR5311_RXCFG_DEF_RX_ANTENNA 0x00000008 /* Default Receive Antenna */ + /* Maui2/Spirit only - reserved on Oahu */ +#define AR_RXCFG_ZLFDMA 0x00000010 /* Enable DMA of zero-length frame */ +#define AR_RXCFG_EN_JUM 0x00000020 /* Enable jumbo rx descriptors */ +#define AR_RXCFG_WR_JUM 0x00000040 /* Wrap jumbo rx descriptors */ + +#define AR_MIBC_COW 0x00000001 /* counter overflow warning */ +#define AR_MIBC_FMC 0x00000002 /* freeze MIB counters */ +#define AR_MIBC_CMC 0x00000004 /* clear MIB counters */ +#define AR_MIBC_MCS 0x00000008 /* MIB counter strobe, increment all */ + +#define AR_TOPS_MASK 0x0000FFFF /* Mask for timeout prescale */ + +#define AR_RXNPTO_MASK 0x000003FF /* Mask for no frame received timeout */ + +#define AR_TXNPTO_MASK 0x000003FF /* Mask for no frame transmitted timeout */ +#define AR_TXNPTO_QCU_MASK 0x03FFFC00 /* Mask indicating the set of QCUs */ + /* for which frame completions will cause */ + /* a reset of the no frame transmitted timeout */ + +#define AR_RPGTO_MASK 0x000003FF /* Mask for receive frame gap timeout */ + +#define AR_RPCNT_MASK 0x0000001F /* Mask for receive frame count limit */ + +#define AR_MACMISC_DMA_OBS_M 0x000001E0 /* Mask for DMA observation bus mux select */ +#define AR_MACMISC_DMA_OBS_S 5 /* Shift for DMA observation bus mux select */ +#define AR_MACMISC_MISC_OBS_M 0x00000E00 /* Mask for MISC observation bus mux select */ +#define AR_MACMISC_MISC_OBS_S 9 /* Shift for MISC observation bus mux select */ +#define AR_MACMISC_MAC_OBS_BUS_LSB_M 0x00007000 /* Mask for MAC observation bus mux select (lsb) */ +#define AR_MACMISC_MAC_OBS_BUS_LSB_S 12 /* Shift for MAC observation bus mux select (lsb) */ +#define AR_MACMISC_MAC_OBS_BUS_MSB_M 0x00038000 /* Mask for MAC observation bus mux select (msb) */ +#define AR_MACMISC_MAC_OBS_BUS_MSB_S 15 /* Shift for MAC observation bus mux select (msb) */ + + /* Maui2/Spirit only. */ +#define AR5311_QDCLKGATE_QCU_M 0x0000FFFF /* Mask for QCU clock disable */ +#define AR5311_QDCLKGATE_DCU_M 0x07FF0000 /* Mask for DCU clock disable */ + + /* Interrupt Status Registers */ +#define AR_ISR_RXOK 0x00000001 /* At least one frame received sans errors */ +#define AR_ISR_RXDESC 0x00000002 /* Receive interrupt request */ +#define AR_ISR_RXERR 0x00000004 /* Receive error interrupt */ +#define AR_ISR_RXNOPKT 0x00000008 /* No frame received within timeout clock */ +#define AR_ISR_RXEOL 0x00000010 /* Received descriptor empty interrupt */ +#define AR_ISR_RXORN 0x00000020 /* Receive FIFO overrun interrupt */ +#define AR_ISR_TXOK 0x00000040 /* Transmit okay interrupt */ +#define AR_ISR_TXDESC 0x00000080 /* Transmit interrupt request */ +#define AR_ISR_TXERR 0x00000100 /* Transmit error interrupt */ +#define AR_ISR_TXNOPKT 0x00000200 /* No frame transmitted interrupt */ +#define AR_ISR_TXEOL 0x00000400 /* Transmit descriptor empty interrupt */ +#define AR_ISR_TXURN 0x00000800 /* Transmit FIFO underrun interrupt */ +#define AR_ISR_MIB 0x00001000 /* MIB interrupt - see MIBC */ +#define AR_ISR_SWI 0x00002000 /* Software interrupt */ +#define AR_ISR_RXPHY 0x00004000 /* PHY receive error interrupt */ +#define AR_ISR_RXKCM 0x00008000 /* Key-cache miss interrupt */ +#define AR_ISR_SWBA 0x00010000 /* Software beacon alert interrupt */ +#define AR_ISR_BRSSI 0x00020000 /* Beacon threshold interrupt */ +#define AR_ISR_BMISS 0x00040000 /* Beacon missed interrupt */ +#define AR_ISR_HIUERR 0x00080000 /* An unexpected bus error has occurred */ +#define AR_ISR_BNR 0x00100000 /* Beacon not ready interrupt */ +#define AR_ISR_TIM 0x00800000 /* TIM interrupt */ +#define AR_ISR_GPIO 0x01000000 /* GPIO Interrupt */ +#define AR_ISR_QCBROVF 0x02000000 /* QCU CBR overflow interrupt */ +#define AR_ISR_QCBRURN 0x04000000 /* QCU CBR underrun interrupt */ +#define AR_ISR_QTRIG 0x08000000 /* QCU scheduling trigger interrupt */ +#define AR_ISR_RESV0 0xF0000000 /* Reserved */ + +#define AR_ISR_S0_QCU_TXOK_M 0x000003FF /* Mask for TXOK (QCU 0-9) */ +#define AR_ISR_S0_QCU_TXDESC_M 0x03FF0000 /* Mask for TXDESC (QCU 0-9) */ + +#define AR_ISR_S1_QCU_TXERR_M 0x000003FF /* Mask for TXERR (QCU 0-9) */ +#define AR_ISR_S1_QCU_TXEOL_M 0x03FF0000 /* Mask for TXEOL (QCU 0-9) */ + +#define AR_ISR_S2_QCU_TXURN_M 0x000003FF /* Mask for TXURN (QCU 0-9) */ +#define AR_ISR_S2_MCABT 0x00010000 /* Master cycle abort interrupt */ +#define AR_ISR_S2_SSERR 0x00020000 /* SERR interrupt */ +#define AR_ISR_S2_DPERR 0x00040000 /* PCI bus parity error */ +#define AR_ISR_S2_RESV0 0xFFF80000 /* Reserved */ + +#define AR_ISR_S3_QCU_QCBROVF_M 0x000003FF /* Mask for QCBROVF (QCU 0-9) */ +#define AR_ISR_S3_QCU_QCBRURN_M 0x03FF0000 /* Mask for QCBRURN (QCU 0-9) */ + +#define AR_ISR_S4_QCU_QTRIG_M 0x000003FF /* Mask for QTRIG (QCU 0-9) */ +#define AR_ISR_S4_RESV0 0xFFFFFC00 /* Reserved */ + + /* Interrupt Mask Registers */ +#define AR_IMR_RXOK 0x00000001 /* At least one frame received sans errors */ +#define AR_IMR_RXDESC 0x00000002 /* Receive interrupt request */ +#define AR_IMR_RXERR 0x00000004 /* Receive error interrupt */ +#define AR_IMR_RXNOPKT 0x00000008 /* No frame received within timeout clock */ +#define AR_IMR_RXEOL 0x00000010 /* Received descriptor empty interrupt */ +#define AR_IMR_RXORN 0x00000020 /* Receive FIFO overrun interrupt */ +#define AR_IMR_TXOK 0x00000040 /* Transmit okay interrupt */ +#define AR_IMR_TXDESC 0x00000080 /* Transmit interrupt request */ +#define AR_IMR_TXERR 0x00000100 /* Transmit error interrupt */ +#define AR_IMR_TXNOPKT 0x00000200 /* No frame transmitted interrupt */ +#define AR_IMR_TXEOL 0x00000400 /* Transmit descriptor empty interrupt */ +#define AR_IMR_TXURN 0x00000800 /* Transmit FIFO underrun interrupt */ +#define AR_IMR_MIB 0x00001000 /* MIB interrupt - see MIBC */ +#define AR_IMR_SWI 0x00002000 /* Software interrupt */ +#define AR_IMR_RXPHY 0x00004000 /* PHY receive error interrupt */ +#define AR_IMR_RXKCM 0x00008000 /* Key-cache miss interrupt */ +#define AR_IMR_SWBA 0x00010000 /* Software beacon alert interrupt */ +#define AR_IMR_BRSSI 0x00020000 /* Beacon threshold interrupt */ +#define AR_IMR_BMISS 0x00040000 /* Beacon missed interrupt */ +#define AR_IMR_HIUERR 0x00080000 /* An unexpected bus error has occurred */ +#define AR_IMR_BNR 0x00100000 /* BNR interrupt */ +#define AR_IMR_TIM 0x00800000 /* TIM interrupt */ +#define AR_IMR_GPIO 0x01000000 /* GPIO Interrupt */ +#define AR_IMR_QCBROVF 0x02000000 /* QCU CBR overflow interrupt */ +#define AR_IMR_QCBRURN 0x04000000 /* QCU CBR underrun interrupt */ +#define AR_IMR_QTRIG 0x08000000 /* QCU scheduling trigger interrupt */ +#define AR_IMR_RESV0 0xF0000000 /* Reserved */ + +#define AR_IMR_S0_QCU_TXOK 0x000003FF /* Mask for TXOK (QCU 0-9) */ +#define AR_IMR_S0_QCU_TXOK_S 0 +#define AR_IMR_S0_QCU_TXDESC 0x03FF0000 /* Mask for TXDESC (QCU 0-9) */ +#define AR_IMR_S0_QCU_TXDESC_S 16 /* Shift for TXDESC (QCU 0-9) */ + +#define AR_IMR_S1_QCU_TXERR 0x000003FF /* Mask for TXERR (QCU 0-9) */ +#define AR_IMR_S1_QCU_TXERR_S 0 +#define AR_IMR_S1_QCU_TXEOL 0x03FF0000 /* Mask for TXEOL (QCU 0-9) */ +#define AR_IMR_S1_QCU_TXEOL_S 16 /* Shift for TXEOL (QCU 0-9) */ + +#define AR_IMR_S2_QCU_TXURN 0x000003FF /* Mask for TXURN (QCU 0-9) */ +#define AR_IMR_S2_QCU_TXURN_S 0 +#define AR_IMR_S2_MCABT 0x00010000 /* Master cycle abort interrupt */ +#define AR_IMR_S2_SSERR 0x00020000 /* SERR interrupt */ +#define AR_IMR_S2_DPERR 0x00040000 /* PCI bus parity error */ +#define AR_IMR_S2_RESV0 0xFFF80000 /* Reserved */ + +#define AR_IMR_S3_QCU_QCBROVF_M 0x000003FF /* Mask for QCBROVF (QCU 0-9) */ +#define AR_IMR_S3_QCU_QCBRURN_M 0x03FF0000 /* Mask for QCBRURN (QCU 0-9) */ +#define AR_IMR_S3_QCU_QCBRURN_S 16 /* Shift for QCBRURN (QCU 0-9) */ + +#define AR_IMR_S4_QCU_QTRIG_M 0x000003FF /* Mask for QTRIG (QCU 0-9) */ +#define AR_IMR_S4_RESV0 0xFFFFFC00 /* Reserved */ + + /* Interrupt status registers (read-and-clear access, secondary shadow copies) */ + + /* QCU registers */ +#define AR_NUM_QCU 10 /* Only use QCU 0-9 for forward QCU compatibility */ +#define AR_QCU_0 0x0001 +#define AR_QCU_1 0x0002 +#define AR_QCU_2 0x0004 +#define AR_QCU_3 0x0008 +#define AR_QCU_4 0x0010 +#define AR_QCU_5 0x0020 +#define AR_QCU_6 0x0040 +#define AR_QCU_7 0x0080 +#define AR_QCU_8 0x0100 +#define AR_QCU_9 0x0200 + +#define AR_Q_TXE_M 0x000003FF /* Mask for TXE (QCU 0-9) */ + +#define AR_Q_TXD_M 0x000003FF /* Mask for TXD (QCU 0-9) */ + +#define AR_Q_CBRCFG_CBR_INTERVAL 0x00FFFFFF /* Mask for CBR interval (us) */ +#define AR_Q_CBRCFG_CBR_INTERVAL_S 0 /* Shift for CBR interval */ +#define AR_Q_CBRCFG_CBR_OVF_THRESH 0xFF000000 /* Mask for CBR overflow threshold */ +#define AR_Q_CBRCFG_CBR_OVF_THRESH_S 24 /* Shift for " " " */ + +#define AR_Q_RDYTIMECFG_INT 0x00FFFFFF /* CBR interval (us) */ +#define AR_Q_RDYTIMECFG_INT_S 0 /* Shift for ReadyTime Interval (us) */ +#define AR_Q_RDYTIMECFG_DURATION_M 0x00FFFFFF /* Mask for CBR interval (us) */ +#define AR_Q_RDYTIMECFG_EN 0x01000000 /* ReadyTime enable */ +#define AR_Q_RDYTIMECFG_RESV0 0xFE000000 /* Reserved */ + +#define AR_Q_ONESHOTARM_SC_M 0x0000FFFF /* Mask for MAC_Q_ONESHOTARM_SC (QCU 0-15) */ +#define AR_Q_ONESHOTARM_SC_RESV0 0xFFFF0000 /* Reserved */ + +#define AR_Q_ONESHOTARM_CC_M 0x0000FFFF /* Mask for MAC_Q_ONESHOTARM_CC (QCU 0-15) */ +#define AR_Q_ONESHOTARM_CC_RESV0 0xFFFF0000 /* Reserved */ + +#define AR_Q_MISC_FSP_M 0x0000000F /* Mask for Frame Scheduling Policy */ +#define AR_Q_MISC_FSP_ASAP 0 /* ASAP */ +#define AR_Q_MISC_FSP_CBR 1 /* CBR */ +#define AR_Q_MISC_FSP_DBA_GATED 2 /* DMA Beacon Alert gated */ +#define AR_Q_MISC_FSP_TIM_GATED 3 /* TIM gated */ +#define AR_Q_MISC_FSP_BEACON_SENT_GATED 4 /* Beacon-sent-gated */ +#define AR_Q_MISC_ONE_SHOT_EN 0x00000010 /* OneShot enable */ +#define AR_Q_MISC_CBR_INCR_DIS1 0x00000020 /* Disable CBR expired counter + incr (empty q) */ +#define AR_Q_MISC_CBR_INCR_DIS0 0x00000040 /* Disable CBR expired counter + incr (empty beacon q) */ +#define AR_Q_MISC_BEACON_USE 0x00000080 /* Beacon use indication */ +#define AR_Q_MISC_CBR_EXP_CNTR_LIMIT 0x00000100 /* CBR expired counter limit enable */ +#define AR_Q_MISC_RDYTIME_EXP_POLICY 0x00000200 /* Enable TXE cleared on ReadyTime expired or VEOL */ +#define AR_Q_MISC_RESET_CBR_EXP_CTR 0x00000400 /* Reset CBR expired counter */ +#define AR_Q_MISC_DCU_EARLY_TERM_REQ 0x00000800 /* DCU frame early termination request control */ +#define AR_Q_MISC_RESV0 0xFFFFF000 /* Reserved */ + +#define AR_Q_STS_PEND_FR_CNT_M 0x00000003 /* Mask for Pending Frame Count */ +#define AR_Q_STS_RESV0 0x000000FC /* Reserved */ +#define AR_Q_STS_CBR_EXP_CNT_M 0x0000FF00 /* Mask for CBR expired counter */ +#define AR_Q_STS_RESV1 0xFFFF0000 /* Reserved */ + +#define AR_Q_RDYTIMESHDN_M 0x000003FF /* Mask for ReadyTimeShutdown status (QCU 0-9) */ + + /* DCU registers */ +#define AR_NUM_DCU 10 /* Only use 10 DCU's for forward QCU/DCU compatibility */ +#define AR_DCU_0 0x0001 +#define AR_DCU_1 0x0002 +#define AR_DCU_2 0x0004 +#define AR_DCU_3 0x0008 +#define AR_DCU_4 0x0010 +#define AR_DCU_5 0x0020 +#define AR_DCU_6 0x0040 +#define AR_DCU_7 0x0080 +#define AR_DCU_8 0x0100 +#define AR_DCU_9 0x0200 + +#define AR_D_QCUMASK_M 0x000003FF /* Mask for QCU Mask (QCU 0-9) */ +#define AR_D_QCUMASK_RESV0 0xFFFFFC00 /* Reserved */ + +#define AR_D_LCL_IFS_CWMIN 0x000003FF /* Mask for CW_MIN */ +#define AR_D_LCL_IFS_CWMIN_S 0 /* Shift for CW_MIN */ +#define AR_D_LCL_IFS_CWMAX 0x000FFC00 /* Mask for CW_MAX */ +#define AR_D_LCL_IFS_CWMAX_S 10 /* Shift for CW_MAX */ +#define AR_D_LCL_IFS_AIFS 0x0FF00000 /* Mask for AIFS */ +#define AR_D_LCL_IFS_AIFS_S 20 /* Shift for AIFS */ +#define AR_D_LCL_IFS_RESV0 0xF0000000 /* Reserved */ + +#define AR_D_RETRY_LIMIT_FR_SH 0x0000000F /* Mask for frame short retry limit */ +#define AR_D_RETRY_LIMIT_FR_SH_S 0 /* Shift for frame short retry limit */ +#define AR_D_RETRY_LIMIT_FR_LG 0x000000F0 /* Mask for frame long retry limit */ +#define AR_D_RETRY_LIMIT_FR_LG_S 4 /* Shift for frame long retry limit */ +#define AR_D_RETRY_LIMIT_STA_SH 0x00003F00 /* Mask for station short retry limit */ +#define AR_D_RETRY_LIMIT_STA_SH_S 8 /* Shift for station short retry limit */ +#define AR_D_RETRY_LIMIT_STA_LG 0x000FC000 /* Mask for station short retry limit */ +#define AR_D_RETRY_LIMIT_STA_LG_S 14 /* Shift for station short retry limit */ +#define AR_D_RETRY_LIMIT_RESV0 0xFFF00000 /* Reserved */ + +#define AR_D_CHNTIME_EN 0x00100000 /* ChannelTime enable */ +#define AR_D_CHNTIME_RESV0 0xFFE00000 /* Reserved */ +#define AR_D_CHNTIME_DUR 0x000FFFFF /* Mask for ChannelTime duration (us) */ +#define AR_D_CHNTIME_DUR_S 0 /* Shift for ChannelTime duration */ + +#define AR_D_MISC_BKOFF_THRESH_M 0x000007FF /* Mask for Backoff threshold setting */ +#define AR_D_MISC_FRAG_BKOFF_EN 0x00000200 /* Backoff during a frag burst */ +#define AR_D_MISC_HCF_POLL_EN 0x00000800 /* HFC poll enable */ +#define AR_D_MISC_BKOFF_PERSISTENCE 0x00001000 /* Backoff persistence factor setting */ +#define AR_D_MISC_FR_PREFETCH_EN 0x00002000 /* Frame prefetch enable */ +#define AR_D_MISC_VIR_COL_HANDLING_M 0x0000C000 /* Mask for Virtual collision handling policy */ +#define AR_D_MISC_VIR_COL_HANDLING_NORMAL 0 /* Normal */ +#define AR_D_MISC_VIR_COL_HANDLING_MODIFIED 1 /* Modified */ +#define AR_D_MISC_VIR_COL_HANDLING_IGNORE 2 /* Ignore */ +#define AR_D_MISC_BEACON_USE 0x00010000 /* Beacon use indication */ +#define AR_D_MISC_ARB_LOCKOUT_CNTRL 0x00060000 /* Mask for DCU arbiter lockout control */ +#define AR_D_MISC_ARB_LOCKOUT_CNTRL_S 17 /* Shift for DCU arbiter lockout control */ +#define AR_D_MISC_ARB_LOCKOUT_CNTRL_NONE 0 /* No lockout */ +#define AR_D_MISC_ARB_LOCKOUT_CNTRL_INTRA_FR 1 /* Intra-frame */ +#define AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL 2 /* Global */ +#define AR_D_MISC_ARB_LOCKOUT_IGNORE 0x00080000 /* DCU arbiter lockout ignore control */ +#define AR_D_MISC_SEQ_NUM_INCR_DIS 0x00100000 /* Sequence number increment disable */ +#define AR_D_MISC_POST_FR_BKOFF_DIS 0x00200000 /* Post-frame backoff disable */ +#define AR_D_MISC_VIRT_COLL_POLICY 0x00400000 /* Virtual coll. handling policy */ +#define AR_D_MISC_BLOWN_IFS_POLICY 0x00800000 /* Blown IFS handling policy */ +#define AR5311_D_MISC_SEQ_NUM_CONTROL 0x01000000 /* Sequence Number local or global */ + /* Maui2/Spirit only, reserved on Oahu */ +#define AR_D_MISC_RESV0 0xFE000000 /* Reserved */ + +#define AR_D_SEQNUM_M 0x00000FFF /* Mask for value of sequence number */ +#define AR_D_SEQNUM_RESV0 0xFFFFF000 /* Reserved */ + +#define AR_D_GBL_IFS_MISC_LFSR_SLICE_SEL 0x00000007 /* Mask forLFSR slice select */ +#define AR_D_GBL_IFS_MISC_TURBO_MODE 0x00000008 /* Turbo mode indication */ +#define AR_D_GBL_IFS_MISC_SIFS_DURATION_USEC 0x000003F0 /* Mask for SIFS duration (us) */ +#define AR_D_GBL_IFS_MISC_USEC_DURATION 0x000FFC00 /* Mask for microsecond duration */ +#define AR_D_GBL_IFS_MISC_DCU_ARBITER_DLY 0x00300000 /* Mask for DCU arbiter delay */ +#define AR_D_GBL_IFS_MISC_RESV0 0xFFC00000 /* Reserved */ + +/* Oahu only */ +#define AR_D_TXPSE_CTRL_M 0x000003FF /* Mask of DCUs to pause (DCUs 0-9) */ +#define AR_D_TXPSE_RESV0 0x0000FC00 /* Reserved */ +#define AR_D_TXPSE_STATUS 0x00010000 /* Transmit pause status */ +#define AR_D_TXPSE_RESV1 0xFFFE0000 /* Reserved */ + + /* DMA & PCI Registers in PCI space (usable during sleep) */ +#define AR_RC_MAC 0x00000001 /* MAC reset */ +#define AR_RC_BB 0x00000002 /* Baseband reset */ +#define AR_RC_RESV0 0x00000004 /* Reserved */ +#define AR_RC_RESV1 0x00000008 /* Reserved */ +#define AR_RC_PCI 0x00000010 /* PCI-core reset */ +#define AR_RC_BITS "\20\1MAC\2BB\3RESV0\4RESV1\5RPCI" + +#define AR_SCR_SLDUR 0x0000ffff /* sleep duration mask, units of 128us */ +#define AR_SCR_SLDUR_S 0 +#define AR_SCR_SLE 0x00030000 /* sleep enable mask */ +#define AR_SCR_SLE_S 16 /* sleep enable bits shift */ +#define AR_SCR_SLE_WAKE 0x00000000 /* force wake */ +#define AR_SCR_SLE_SLP 0x00010000 /* force sleep */ +#define AR_SCR_SLE_NORM 0x00020000 /* sleep logic normal operation */ +#define AR_SCR_SLE_UNITS 0x00000008 /* SCR units/TU */ +#define AR_SCR_BITS "\20\20SLE_SLP\21SLE" + +#define AR_INTPEND_TRUE 0x00000001 /* interrupt pending */ +#define AR_INTPEND_BITS "\20\1IP" + +#define AR_SFR_SLEEP 0x00000001 /* force sleep */ + +#define AR_PCICFG_CLKRUNEN 0x00000004 /* enable PCI CLKRUN function */ +#define AR_PCICFG_EEPROM_SIZE_M 0x00000018 /* Mask for EEPROM size */ +#define AR_PCICFG_EEPROM_SIZE_S 3 /* Mask for EEPROM size */ +#define AR_PCICFG_EEPROM_SIZE_4K 0 /* EEPROM size 4 Kbit */ +#define AR_PCICFG_EEPROM_SIZE_8K 1 /* EEPROM size 8 Kbit */ +#define AR_PCICFG_EEPROM_SIZE_16K 2 /* EEPROM size 16 Kbit */ +#define AR_PCICFG_EEPROM_SIZE_FAILED 3 /* Failure */ +#define AR_PCICFG_LEDCTL 0x00000060 /* LED control Status */ +#define AR_PCICFG_LEDCTL_NONE 0x00000000 /* STA is not associated or trying */ +#define AR_PCICFG_LEDCTL_PEND 0x00000020 /* STA is trying to associate */ +#define AR_PCICFG_LEDCTL_ASSOC 0x00000040 /* STA is associated */ +#define AR_PCICFG_PCI_BUS_SEL_M 0x00000380 /* Mask for PCI observation bus mux select */ +#define AR_PCICFG_DIS_CBE_FIX 0x00000400 /* Disable fix for bad PCI CBE# generation */ +#define AR_PCICFG_SL_INTEN 0x00000800 /* enable interrupt line assertion when asleep */ +#define AR_PCICFG_RESV0 0x00001000 /* Reserved */ +#define AR_PCICFG_SL_INPEN 0x00002000 /* Force asleep when an interrupt is pending */ +#define AR_PCICFG_RESV1 0x0000C000 /* Reserved */ +#define AR_PCICFG_SPWR_DN 0x00010000 /* mask for sleep/awake indication */ +#define AR_PCICFG_LEDMODE 0x000E0000 /* LED mode */ +#define AR_PCICFG_LEDMODE_PROP 0x00000000 /* Blink prop to filtered tx/rx */ +#define AR_PCICFG_LEDMODE_RPROP 0x00020000 /* Blink prop to unfiltered tx/rx */ +#define AR_PCICFG_LEDMODE_SPLIT 0x00040000 /* Blink power for tx/net for rx */ +#define AR_PCICFG_LEDMODE_RAND 0x00060000 /* Blink randomly */ +#define AR_PCICFG_LEDBLINK 0x00700000 /* LED blink threshold select */ +#define AR_PCICFG_LEDBLINK_S 20 +#define AR_PCICFG_LEDSLOW 0x00800000 /* LED slowest blink rate mode */ +#define AR_PCICFG_RESV2 0xFF000000 /* Reserved */ +#define AR_PCICFG_BITS "\20\3CLKRUNEN\13SL_INTEN" + +#define AR_GPIOCR_CR_SHIFT 2 /* Each CR is 2 bits */ +#define AR_GPIOCR_0_CR_N 0x00000000 /* Input only mode for GPIODO[0] */ +#define AR_GPIOCR_0_CR_0 0x00000001 /* Output only if GPIODO[0] = 0 */ +#define AR_GPIOCR_0_CR_1 0x00000002 /* Output only if GPIODO[0] = 1 */ +#define AR_GPIOCR_0_CR_A 0x00000003 /* Always output */ +#define AR_GPIOCR_1_CR_N 0x00000000 /* Input only mode for GPIODO[1] */ +#define AR_GPIOCR_1_CR_0 0x00000004 /* Output only if GPIODO[1] = 0 */ +#define AR_GPIOCR_1_CR_1 0x00000008 /* Output only if GPIODO[1] = 1 */ +#define AR_GPIOCR_1_CR_A 0x0000000C /* Always output */ +#define AR_GPIOCR_2_CR_N 0x00000000 /* Input only mode for GPIODO[2] */ +#define AR_GPIOCR_2_CR_0 0x00000010 /* Output only if GPIODO[2] = 0 */ +#define AR_GPIOCR_2_CR_1 0x00000020 /* Output only if GPIODO[2] = 1 */ +#define AR_GPIOCR_2_CR_A 0x00000030 /* Always output */ +#define AR_GPIOCR_3_CR_N 0x00000000 /* Input only mode for GPIODO[3] */ +#define AR_GPIOCR_3_CR_0 0x00000040 /* Output only if GPIODO[3] = 0 */ +#define AR_GPIOCR_3_CR_1 0x00000080 /* Output only if GPIODO[3] = 1 */ +#define AR_GPIOCR_3_CR_A 0x000000C0 /* Always output */ +#define AR_GPIOCR_4_CR_N 0x00000000 /* Input only mode for GPIODO[4] */ +#define AR_GPIOCR_4_CR_0 0x00000100 /* Output only if GPIODO[4] = 0 */ +#define AR_GPIOCR_4_CR_1 0x00000200 /* Output only if GPIODO[4] = 1 */ +#define AR_GPIOCR_4_CR_A 0x00000300 /* Always output */ +#define AR_GPIOCR_5_CR_N 0x00000000 /* Input only mode for GPIODO[5] */ +#define AR_GPIOCR_5_CR_0 0x00000400 /* Output only if GPIODO[5] = 0 */ +#define AR_GPIOCR_5_CR_1 0x00000800 /* Output only if GPIODO[5] = 1 */ +#define AR_GPIOCR_5_CR_A 0x00000C00 /* Always output */ +#define AR_GPIOCR_INT_SHIFT 12 /* Interrupt select field shifter */ +#define AR_GPIOCR_INT_MASK 0x00007000 /* Interrupt select field mask */ +#define AR_GPIOCR_INT_SEL0 0x00000000 /* Select Interrupt Pin GPIO_0 */ +#define AR_GPIOCR_INT_SEL1 0x00001000 /* Select Interrupt Pin GPIO_1 */ +#define AR_GPIOCR_INT_SEL2 0x00002000 /* Select Interrupt Pin GPIO_2 */ +#define AR_GPIOCR_INT_SEL3 0x00003000 /* Select Interrupt Pin GPIO_3 */ +#define AR_GPIOCR_INT_SEL4 0x00004000 /* Select Interrupt Pin GPIO_4 */ +#define AR_GPIOCR_INT_SEL5 0x00005000 /* Select Interrupt Pin GPIO_5 */ +#define AR_GPIOCR_INT_ENA 0x00008000 /* Enable GPIO Interrupt */ +#define AR_GPIOCR_INT_SELL 0x00000000 /* Generate Interrupt if selected pin is low */ +#define AR_GPIOCR_INT_SELH 0x00010000 /* Generate Interrupt if selected pin is high */ + +#define AR_SREV_ID_M 0x000000FF /* Mask to read SREV info */ +#define AR_PCICFG_EEPROM_SIZE_16K 2 /* EEPROM size 16 Kbit */ +#define AR_SREV_ID_S 4 /* Major Rev Info */ +#define AR_SREV_REVISION_M 0x0000000F /* Chip revision level */ +#define AR_SREV_FPGA 1 +#define AR_SREV_D2PLUS 2 +#define AR_SREV_D2PLUS_MS 3 /* metal spin */ +#define AR_SREV_CRETE 4 +#define AR_SREV_CRETE_MS 5 /* FCS metal spin */ +#define AR_SREV_CRETE_MS23 7 /* 2.3 metal spin (6 skipped) */ +#define AR_SREV_CRETE_23 8 /* 2.3 full tape out */ +#define AR_SREV_VERSION_M 0x000000F0 /* Chip version indication */ +#define AR_SREV_VERSION_CRETE 0 +#define AR_SREV_VERSION_MAUI_1 1 +#define AR_SREV_VERSION_MAUI_2 2 +#define AR_SREV_VERSION_SPIRIT 3 +#define AR_SREV_VERSION_OAHU 4 +#define AR_SREV_OAHU_ES 0 /* Engineering Sample */ +#define AR_SREV_OAHU_PROD 2 /* Production */ + +#define RAD5_SREV_MAJOR 0x10 /* All current supported ar5211 5 GHz radios are rev 0x10 */ +#define RAD5_SREV_PROD 0x15 /* Current production level radios */ +#define RAD2_SREV_MAJOR 0x20 /* All current supported ar5211 2 GHz radios are rev 0x10 */ + + /* EEPROM Registers in the MAC */ +#define AR_EEPROM_CMD_READ 0x00000001 +#define AR_EEPROM_CMD_WRITE 0x00000002 +#define AR_EEPROM_CMD_RESET 0x00000004 + +#define AR_EEPROM_STS_READ_ERROR 0x00000001 +#define AR_EEPROM_STS_READ_COMPLETE 0x00000002 +#define AR_EEPROM_STS_WRITE_ERROR 0x00000004 +#define AR_EEPROM_STS_WRITE_COMPLETE 0x00000008 + +#define AR_EEPROM_CFG_SIZE_M 0x00000003 /* Mask for EEPROM size determination override */ +#define AR_EEPROM_CFG_SIZE_AUTO 0 +#define AR_EEPROM_CFG_SIZE_4KBIT 1 +#define AR_EEPROM_CFG_SIZE_8KBIT 2 +#define AR_EEPROM_CFG_SIZE_16KBIT 3 +#define AR_EEPROM_CFG_DIS_WAIT_WRITE_COMPL 0x00000004 /* Disable wait for write completion */ +#define AR_EEPROM_CFG_CLOCK_M 0x00000018 /* Mask for EEPROM clock rate control */ +#define AR_EEPROM_CFG_CLOCK_S 3 /* Shift for EEPROM clock rate control */ +#define AR_EEPROM_CFG_CLOCK_156KHZ 0 +#define AR_EEPROM_CFG_CLOCK_312KHZ 1 +#define AR_EEPROM_CFG_CLOCK_625KHZ 2 +#define AR_EEPROM_CFG_RESV0 0x000000E0 /* Reserved */ +#define AR_EEPROM_CFG_PROT_KEY_M 0x00FFFF00 /* Mask for EEPROM protection key */ +#define AR_EEPROM_CFG_PROT_KEY_S 8 /* Shift for EEPROM protection key */ +#define AR_EEPROM_CFG_EN_L 0x01000000 /* EPRM_EN_L setting */ + + /* MAC PCU Registers */ +#define AR_STA_ID1_SADH_MASK 0x0000FFFF /* Mask for upper 16 bits of MAC addr */ +#define AR_STA_ID1_STA_AP 0x00010000 /* Device is AP */ +#define AR_STA_ID1_ADHOC 0x00020000 /* Device is ad-hoc */ +#define AR_STA_ID1_PWR_SAV 0x00040000 /* Power save reporting in self-generated frames */ +#define AR_STA_ID1_KSRCHDIS 0x00080000 /* Key search disable */ +#define AR_STA_ID1_PCF 0x00100000 /* Observe PCF */ +#define AR_STA_ID1_DEFAULT_ANTENNA 0x00200000 /* Use default antenna */ +#define AR_STA_ID1_DESC_ANTENNA 0x00400000 /* Update default antenna w/ TX antenna */ +#define AR_STA_ID1_RTS_USE_DEF 0x00800000 /* Use default antenna to send RTS */ +#define AR_STA_ID1_ACKCTS_6MB 0x01000000 /* Use 6Mb/s rate for ACK & CTS */ +#define AR_STA_ID1_BASE_RATE_11B 0x02000000 /* Use 11b base rate for ACK & CTS */ +#define AR_STA_ID1_BITS \ + "\20\20AP\21ADHOC\22PWR_SAV\23KSRCHDIS\25PCF" + +#define AR_BSS_ID1_U16_M 0x0000FFFF /* Mask for upper 16 bits of BSSID */ +#define AR_BSS_ID1_AID_M 0xFFFF0000 /* Mask for association ID */ +#define AR_BSS_ID1_AID_S 16 /* Shift for association ID */ + +#define AR_SLOT_TIME_MASK 0x000007FF /* Slot time mask */ + +#define AR_TIME_OUT_ACK 0x00001FFF /* Mask for ACK time-out */ +#define AR_TIME_OUT_ACK_S 0 /* Shift for ACK time-out */ +#define AR_TIME_OUT_CTS 0x1FFF0000 /* Mask for CTS time-out */ +#define AR_TIME_OUT_CTS_S 16 /* Shift for CTS time-out */ + +#define AR_RSSI_THR_MASK 0x000000FF /* Mask for Beacon RSSI warning threshold */ +#define AR_RSSI_THR_BM_THR 0x0000FF00 /* Mask for Missed beacon threshold */ +#define AR_RSSI_THR_BM_THR_S 8 /* Shift for Missed beacon threshold */ + +#define AR_USEC_M 0x0000007F /* Mask for clock cycles in 1 usec */ +#define AR_USEC_32_M 0x00003F80 /* Mask for number of 32MHz clock cycles in 1 usec */ +#define AR_USEC_32_S 7 /* Shift for number of 32MHz clock cycles in 1 usec */ +/* + * Tx/Rx latencies are to signal start and are in usecs. + * + * NOTE: AR5211/AR5311 difference: on Oahu, the TX latency field + * has increased from 6 bits to 9 bits. The RX latency field + * is unchanged, but is shifted over 3 bits. + */ +#define AR5311_USEC_TX_LAT_M 0x000FC000 /* Tx latency */ +#define AR5311_USEC_TX_LAT_S 14 +#define AR5311_USEC_RX_LAT_M 0x03F00000 /* Rx latency */ +#define AR5311_USEC_RX_LAT_S 20 + +#define AR5211_USEC_TX_LAT_M 0x007FC000 /* Tx latency */ +#define AR5211_USEC_TX_LAT_S 14 +#define AR5211_USEC_RX_LAT_M 0x1F800000 /* Rx latency */ +#define AR5211_USEC_RX_LAT_S 23 + + +#define AR_BEACON_PERIOD 0x0000FFFF /* Beacon period in TU/msec */ +#define AR_BEACON_PERIOD_S 0 /* Byte offset of PERIOD start*/ +#define AR_BEACON_TIM 0x007F0000 /* Byte offset of TIM start */ +#define AR_BEACON_TIM_S 16 /* Byte offset of TIM start */ +#define AR_BEACON_EN 0x00800000 /* beacon enable */ +#define AR_BEACON_RESET_TSF 0x01000000 /* Clears TSF to 0 */ +#define AR_BEACON_BITS "\20\27ENABLE\30RESET_TSF" + +#define AR_RX_FILTER_ALL 0x00000000 /* Disallow all frames */ +#define AR_RX_UCAST 0x00000001 /* Allow unicast frames */ +#define AR_RX_MCAST 0x00000002 /* Allow multicast frames */ +#define AR_RX_BCAST 0x00000004 /* Allow broadcast frames */ +#define AR_RX_CONTROL 0x00000008 /* Allow control frames */ +#define AR_RX_BEACON 0x00000010 /* Allow beacon frames */ +#define AR_RX_PROM 0x00000020 /* Promiscuous mode */ +#define AR_RX_PHY_ERR 0x00000040 /* Allow all phy errors */ +#define AR_RX_PHY_RADAR 0x00000080 /* Allow radar phy errors */ +#define AR_RX_FILTER_BITS \ + "\20\1UCAST\2MCAST\3BCAST\4CONTROL\5BEACON\6PROMISC\7PHY_ERR\10PHY_RADAR" + +#define AR_DIAG_SW_CACHE_ACK 0x00000001 /* disable ACK if no valid key*/ +#define AR_DIAG_SW_DIS_ACK 0x00000002 /* disable ACK generation */ +#define AR_DIAG_SW_DIS_CTS 0x00000004 /* disable CTS generation */ +#define AR_DIAG_SW_DIS_ENCRYPT 0x00000008 /* disable encryption */ +#define AR_DIAG_SW_DIS_DECRYPT 0x00000010 /* disable decryption */ +#define AR_DIAG_SW_DIS_RX 0x00000020 /* disable receive */ +#define AR_DIAG_SW_CORR_FCS 0x00000080 /* corrupt FCS */ +#define AR_DIAG_SW_CHAN_INFO 0x00000100 /* dump channel info */ +#define AR_DIAG_SW_EN_SCRAMSD 0x00000200 /* enable fixed scrambler seed*/ +#define AR5311_DIAG_SW_USE_ECO 0x00000400 /* "super secret" use ECO enable bit */ +#define AR_DIAG_SW_SCRAM_SEED_M 0x0001FC00 /* Fixed scrambler seed mask */ +#define AR_DIAG_SW_SCRAM_SEED_S 10 /* Fixed scrambler seed shfit */ +#define AR_DIAG_SW_FRAME_NV0 0x00020000 /* accept frames of non-zero protocol version */ +#define AR_DIAG_SW_OBS_PT_SEL_M 0x000C0000 /* Observation point select */ +#define AR_DIAG_SW_OBS_PT_SEL_S 18 /* Observation point select */ +#define AR_DIAG_SW_BITS \ + "\20\1DIS_CACHE_ACK\2DIS_ACK\3DIS_CTS\4DIS_ENC\5DIS_DEC\6DIS_RX"\ + "\11CORR_FCS\12CHAN_INFO\13EN_SCRAM_SEED\14USE_ECO\24FRAME_NV0" + +#define AR_KEYTABLE_KEY0(n) (AR_KEYTABLE(n) + 0) /* key bit 0-31 */ +#define AR_KEYTABLE_KEY1(n) (AR_KEYTABLE(n) + 4) /* key bit 32-47 */ +#define AR_KEYTABLE_KEY2(n) (AR_KEYTABLE(n) + 8) /* key bit 48-79 */ +#define AR_KEYTABLE_KEY3(n) (AR_KEYTABLE(n) + 12) /* key bit 80-95 */ +#define AR_KEYTABLE_KEY4(n) (AR_KEYTABLE(n) + 16) /* key bit 96-127 */ +#define AR_KEYTABLE_TYPE(n) (AR_KEYTABLE(n) + 20) /* key type */ +#define AR_KEYTABLE_TYPE_40 0x00000000 /* WEP 40 bit key */ +#define AR_KEYTABLE_TYPE_104 0x00000001 /* WEP 104 bit key */ +#define AR_KEYTABLE_TYPE_128 0x00000003 /* WEP 128 bit key */ +#define AR_KEYTABLE_TYPE_AES 0x00000005 /* AES 128 bit key */ +#define AR_KEYTABLE_TYPE_CLR 0x00000007 /* no encryption */ +#define AR_KEYTABLE_MAC0(n) (AR_KEYTABLE(n) + 24) /* MAC address 1-32 */ +#define AR_KEYTABLE_MAC1(n) (AR_KEYTABLE(n) + 28) /* MAC address 33-47 */ +#define AR_KEYTABLE_VALID 0x00008000 /* key and MAC address valid */ + +#endif /* _DEV_ATH_AR5211REG_H */ --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5211/boss.ini 2009-03-23 17:36:55.000000000 +0000 @@ -0,0 +1,358 @@ +/* + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2006 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: boss.ini,v 1.1 2009/03/23 17:14:47 sborrill Exp $ + */ +/* Auto Generated PCI Register Writes. Created: 09/12/02 */ + +static const uint32_t ar5211Modes[][5] = { + { 0x00000030, 0x00000015, 0x00000015, 0x0000001d, 0x00000015 }, + { 0x00001040, 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f }, + { 0x00001044, 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f }, + { 0x00001048, 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f }, + { 0x0000104c, 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f }, + { 0x00001050, 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f }, + { 0x00001054, 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f }, + { 0x00001058, 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f }, + { 0x0000105c, 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f }, + { 0x00001060, 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f }, + { 0x00001064, 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f }, + { 0x00001070, 0x00000168, 0x000001e0, 0x000001b8, 0x00000168 }, + { 0x00001030, 0x00000230, 0x000001e0, 0x000000b0, 0x00000230 }, + { 0x000010b0, 0x00000d98, 0x00001180, 0x00001f48, 0x00000d98 }, + { 0x000010f0, 0x0000a0e0, 0x00014068, 0x00005880, 0x0000a0e0 }, + { 0x00008014, 0x04000400, 0x08000800, 0x20003000, 0x04000400 }, + { 0x0000801c, 0x0e8d8fa7, 0x0e8d8fcf, 0x01608f95, 0x0e8d8fa7 }, + { 0x00009804, 0x00000000, 0x00000003, 0x00000000, 0x00000000 }, + { 0x00009820, 0x02020200, 0x02020200, 0x02010200, 0x02020200 }, + { 0x00009824, 0x00000e0e, 0x00000e0e, 0x00000707, 0x00000e0e }, + { 0x00009828, 0x0a020001, 0x0a020001, 0x05010000, 0x0a020001 }, + { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, + { 0x00009838, 0x00000007, 0x00000007, 0x0000000b, 0x0000000b }, + { 0x00009844, 0x1372169c, 0x137216a5, 0x137216a8, 0x1372169c }, + { 0x00009848, 0x0018ba67, 0x0018ba67, 0x0018ba69, 0x0018ba69 }, + { 0x00009850, 0x0c28b4e0, 0x0c28b4e0, 0x0c28b4e0, 0x0c28b4e0 }, + { 0x00009858, 0x7e800d2e, 0x7e800d2e, 0x7ec00d2e, 0x7e800d2e }, + { 0x0000985c, 0x31375d5e, 0x31375d5e, 0x313a5d5e, 0x31375d5e }, + { 0x00009860, 0x0000bd10, 0x0000bd10, 0x0000bd38, 0x0000bd10 }, + { 0x00009864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 }, + { 0x00009914, 0x00002710, 0x00002710, 0x0000157c, 0x00002710 }, + { 0x00009918, 0x00000190, 0x00000190, 0x00000084, 0x00000190 }, + { 0x00009944, 0x6fe01020, 0x6fe01020, 0x6fe00920, 0x6fe01020 }, + { 0x0000a180, 0x05ff14ff, 0x05ff14ff, 0x05ff14ff, 0x05ff19ff }, + { 0x000098d4, 0x00000010, 0x00000014, 0x00000010, 0x00000010 }, +}; + +static const uint32_t ar5211Common[][2] = { + { 0x0000000c, 0x00000000 }, + { 0x00000028, 0x84849c9c }, + { 0x0000002c, 0x7c7c7c7c }, + { 0x00000034, 0x00000005 }, + { 0x00000040, 0x00000000 }, + { 0x00000044, 0x00000008 }, + { 0x00000048, 0x00000008 }, + { 0x0000004c, 0x00000010 }, + { 0x00000050, 0x00000000 }, + { 0x00000054, 0x0000001f }, + { 0x00000800, 0x00000000 }, + { 0x00000804, 0x00000000 }, + { 0x00000808, 0x00000000 }, + { 0x0000080c, 0x00000000 }, + { 0x00000810, 0x00000000 }, + { 0x00000814, 0x00000000 }, + { 0x00000818, 0x00000000 }, + { 0x0000081c, 0x00000000 }, + { 0x00000820, 0x00000000 }, + { 0x00000824, 0x00000000 }, + { 0x00001230, 0x00000000 }, + { 0x00008004, 0x00000000 }, + { 0x00008008, 0x00000000 }, + { 0x0000800c, 0x00000000 }, + { 0x00008018, 0x00000000 }, + { 0x00008024, 0x00000000 }, + { 0x00008028, 0x00000030 }, + { 0x0000802c, 0x0007ffff }, + { 0x00008030, 0x01ffffff }, + { 0x00008034, 0x00000031 }, + { 0x00008038, 0x00000000 }, + { 0x0000803c, 0x00000000 }, + { 0x00008040, 0x00000000 }, + { 0x00008044, 0x00000002 }, + { 0x00008048, 0x00000000 }, + { 0x00008054, 0x00000000 }, + { 0x00008058, 0x00000000 }, + { 0x00009808, 0x00000000 }, + { 0x0000980c, 0x2d849093 }, + { 0x00009810, 0x7d32e000 }, + { 0x00009814, 0x00000f6b }, + { 0x0000981c, 0x00000000 }, + { 0x0000982c, 0x00026ffe }, + { 0x00009830, 0x00000000 }, + { 0x0000983c, 0x00020100 }, + { 0x00009840, 0x206a017a }, + { 0x0000984c, 0x1284613c }, + { 0x00009854, 0x00000859 }, + { 0x00009868, 0x409a4190 }, + { 0x0000986c, 0x050cb081 }, + { 0x00009870, 0x0000000f }, + { 0x00009874, 0x00000080 }, + { 0x00009878, 0x0000000c }, + { 0x00009900, 0x00000000 }, + { 0x00009904, 0x00000000 }, + { 0x00009908, 0x00000000 }, + { 0x0000990c, 0x00800000 }, + { 0x00009910, 0x00000001 }, + { 0x0000991c, 0x0000092a }, + { 0x00009920, 0x00000000 }, + { 0x00009924, 0x00058a05 }, + { 0x00009928, 0x00000001 }, + { 0x0000992c, 0x00000000 }, + { 0x00009930, 0x00000000 }, + { 0x00009934, 0x00000000 }, + { 0x00009938, 0x00000000 }, + { 0x0000993c, 0x0000003f }, + { 0x00009940, 0x00000004 }, + { 0x00009948, 0x00000000 }, + { 0x0000994c, 0x00000000 }, + { 0x00009950, 0x00000000 }, + { 0x00009954, 0x5d50f14c }, + { 0x00009958, 0x00000018 }, + { 0x0000995c, 0x004b6a8e }, + { 0x0000a184, 0x06ff05ff }, + { 0x0000a188, 0x07ff07ff }, + { 0x0000a18c, 0x08ff08ff }, + { 0x0000a190, 0x09ff09ff }, + { 0x0000a194, 0x0aff0aff }, + { 0x0000a198, 0x0bff0bff }, + { 0x0000a19c, 0x0cff0cff }, + { 0x0000a1a0, 0x0dff0dff }, + { 0x0000a1a4, 0x0fff0eff }, + { 0x0000a1a8, 0x12ff12ff }, + { 0x0000a1ac, 0x14ff13ff }, + { 0x0000a1b0, 0x16ff15ff }, + { 0x0000a1b4, 0x19ff17ff }, + { 0x0000a1b8, 0x1bff1aff }, + { 0x0000a1bc, 0x1eff1dff }, + { 0x0000a1c0, 0x23ff20ff }, + { 0x0000a1c4, 0x27ff25ff }, + { 0x0000a1c8, 0x2cff29ff }, + { 0x0000a1cc, 0x31ff2fff }, + { 0x0000a1d0, 0x37ff34ff }, + { 0x0000a1d4, 0x3aff3aff }, + { 0x0000a1d8, 0x3aff3aff }, + { 0x0000a1dc, 0x3aff3aff }, + { 0x0000a1e0, 0x3aff3aff }, + { 0x0000a1e4, 0x3aff3aff }, + { 0x0000a1e8, 0x3aff3aff }, + { 0x0000a1ec, 0x3aff3aff }, + { 0x0000a1f0, 0x3aff3aff }, + { 0x0000a1f4, 0x3aff3aff }, + { 0x0000a1f8, 0x3aff3aff }, + { 0x0000a1fc, 0x3aff3aff }, + { 0x00009b00, 0x00000000 }, + { 0x00009b04, 0x00000020 }, + { 0x00009b08, 0x00000010 }, + { 0x00009b0c, 0x00000030 }, + { 0x00009b10, 0x00000008 }, + { 0x00009b14, 0x00000028 }, + { 0x00009b18, 0x00000004 }, + { 0x00009b1c, 0x00000024 }, + { 0x00009b20, 0x00000014 }, + { 0x00009b24, 0x00000034 }, + { 0x00009b28, 0x0000000c }, + { 0x00009b2c, 0x0000002c }, + { 0x00009b30, 0x00000002 }, + { 0x00009b34, 0x00000022 }, + { 0x00009b38, 0x00000012 }, + { 0x00009b3c, 0x00000032 }, + { 0x00009b40, 0x0000000a }, + { 0x00009b44, 0x0000002a }, + { 0x00009b48, 0x00000006 }, + { 0x00009b4c, 0x00000026 }, + { 0x00009b50, 0x00000016 }, + { 0x00009b54, 0x00000036 }, + { 0x00009b58, 0x0000000e }, + { 0x00009b5c, 0x0000002e }, + { 0x00009b60, 0x00000001 }, + { 0x00009b64, 0x00000021 }, + { 0x00009b68, 0x00000011 }, + { 0x00009b6c, 0x00000031 }, + { 0x00009b70, 0x00000009 }, + { 0x00009b74, 0x00000029 }, + { 0x00009b78, 0x00000005 }, + { 0x00009b7c, 0x00000025 }, + { 0x00009b80, 0x00000015 }, + { 0x00009b84, 0x00000035 }, + { 0x00009b88, 0x0000000d }, + { 0x00009b8c, 0x0000002d }, + { 0x00009b90, 0x00000003 }, + { 0x00009b94, 0x00000023 }, + { 0x00009b98, 0x00000013 }, + { 0x00009b9c, 0x00000033 }, + { 0x00009ba0, 0x0000000b }, + { 0x00009ba4, 0x0000002b }, + { 0x00009ba8, 0x0000002b }, + { 0x00009bac, 0x0000002b }, + { 0x00009bb0, 0x0000002b }, + { 0x00009bb4, 0x0000002b }, + { 0x00009bb8, 0x0000002b }, + { 0x00009bbc, 0x0000002b }, + { 0x00009bc0, 0x0000002b }, + { 0x00009bc4, 0x0000002b }, + { 0x00009bc8, 0x0000002b }, + { 0x00009bcc, 0x0000002b }, + { 0x00009bd0, 0x0000002b }, + { 0x00009bd4, 0x0000002b }, + { 0x00009bd8, 0x0000002b }, + { 0x00009bdc, 0x0000002b }, + { 0x00009be0, 0x0000002b }, + { 0x00009be4, 0x0000002b }, + { 0x00009be8, 0x0000002b }, + { 0x00009bec, 0x0000002b }, + { 0x00009bf0, 0x0000002b }, + { 0x00009bf4, 0x0000002b }, + { 0x00009bf8, 0x00000002 }, + { 0x00009bfc, 0x00000016 }, + { 0x000098d4, 0x00000020 }, + { 0x000098d8, 0x00601068 }, +}; + +static uint32_t ar5211Mode2_4[][3] = { + { 0x0000a204, 0x00000000, 0x00000000 }, + { 0x0000a208, 0x503e4646, 0x503e4646 }, + { 0x0000a20c, 0x6480416c, 0x6480416c }, + { 0x0000a210, 0x0199a003, 0x0199a003 }, + { 0x0000a214, 0x044cd610, 0x044cd610 }, + { 0x0000a218, 0x13800040, 0x13800040 }, + { 0x0000a21c, 0x1be00060, 0x1be00060 }, + { 0x0000a220, 0x0c53800a, 0x0c53800a }, + { 0x0000a224, 0x0014df3b, 0x0014df3b }, + { 0x0000a228, 0x000001b5, 0x000001b5 }, + { 0x0000a22c, 0x00000020, 0x00000020 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00380000, 0x00380000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x000400f9, 0x000400f9 }, + { 0x000098d4, 0x00000000, 0x00000004 }, +}; + +static const uint32_t ar5211BB_RfGain[][3] = { + { 0x00009a00, 0x000001a9, 0x00000000 }, + { 0x00009a04, 0x000001e9, 0x00000040 }, + { 0x00009a08, 0x00000029, 0x00000080 }, + { 0x00009a0c, 0x00000069, 0x00000150 }, + { 0x00009a10, 0x00000199, 0x00000190 }, + { 0x00009a14, 0x000001d9, 0x000001d0 }, + { 0x00009a18, 0x00000019, 0x00000010 }, + { 0x00009a1c, 0x00000059, 0x00000044 }, + { 0x00009a20, 0x00000099, 0x00000084 }, + { 0x00009a24, 0x000001a5, 0x00000148 }, + { 0x00009a28, 0x000001e5, 0x00000188 }, + { 0x00009a2c, 0x00000025, 0x000001c8 }, + { 0x00009a30, 0x000001c8, 0x00000014 }, + { 0x00009a34, 0x00000008, 0x00000042 }, + { 0x00009a38, 0x00000048, 0x00000082 }, + { 0x00009a3c, 0x00000088, 0x00000178 }, + { 0x00009a40, 0x00000198, 0x000001b8 }, + { 0x00009a44, 0x000001d8, 0x000001f8 }, + { 0x00009a48, 0x00000018, 0x00000012 }, + { 0x00009a4c, 0x00000058, 0x00000052 }, + { 0x00009a50, 0x00000098, 0x00000092 }, + { 0x00009a54, 0x000001a4, 0x0000017c }, + { 0x00009a58, 0x000001e4, 0x000001bc }, + { 0x00009a5c, 0x00000024, 0x000001fc }, + { 0x00009a60, 0x00000064, 0x0000000a }, + { 0x00009a64, 0x000000a4, 0x0000004a }, + { 0x00009a68, 0x000000e4, 0x0000008a }, + { 0x00009a6c, 0x0000010a, 0x0000015a }, + { 0x00009a70, 0x0000014a, 0x0000019a }, + { 0x00009a74, 0x0000018a, 0x000001da }, + { 0x00009a78, 0x000001ca, 0x0000000e }, + { 0x00009a7c, 0x0000000a, 0x0000004e }, + { 0x00009a80, 0x0000004a, 0x0000008e }, + { 0x00009a84, 0x0000008a, 0x0000015e }, + { 0x00009a88, 0x000001ba, 0x0000019e }, + { 0x00009a8c, 0x000001fa, 0x000001de }, + { 0x00009a90, 0x0000003a, 0x00000009 }, + { 0x00009a94, 0x0000007a, 0x00000049 }, + { 0x00009a98, 0x00000186, 0x00000089 }, + { 0x00009a9c, 0x000001c6, 0x00000179 }, + { 0x00009aa0, 0x00000006, 0x000001b9 }, + { 0x00009aa4, 0x00000046, 0x000001f9 }, + { 0x00009aa8, 0x00000086, 0x00000039 }, + { 0x00009aac, 0x000000c6, 0x00000079 }, + { 0x00009ab0, 0x000000c6, 0x000000b9 }, + { 0x00009ab4, 0x000000c6, 0x000001bd }, + { 0x00009ab8, 0x000000c6, 0x000001fd }, + { 0x00009abc, 0x000000c6, 0x0000003d }, + { 0x00009ac0, 0x000000c6, 0x0000007d }, + { 0x00009ac4, 0x000000c6, 0x000000bd }, + { 0x00009ac8, 0x000000c6, 0x000000fd }, + { 0x00009acc, 0x000000c6, 0x000000fd }, + { 0x00009ad0, 0x000000c6, 0x000000fd }, + { 0x00009ad4, 0x000000c6, 0x000000fd }, + { 0x00009ad8, 0x000000c6, 0x000000fd }, + { 0x00009adc, 0x000000c6, 0x000000fd }, + { 0x00009ae0, 0x000000c6, 0x000000fd }, + { 0x00009ae4, 0x000000c6, 0x000000fd }, + { 0x00009ae8, 0x000000c6, 0x000000fd }, + { 0x00009aec, 0x000000c6, 0x000000fd }, + { 0x00009af0, 0x000000c6, 0x000000fd }, + { 0x00009af4, 0x000000c6, 0x000000fd }, + { 0x00009af8, 0x000000c6, 0x000000fd }, + { 0x00009afc, 0x000000c6, 0x000000fd }, +}; + +static uint32_t ar5211Rf6n7[][3] = { + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x10000000, 0x10000000 }, + { 0x0000989c, 0x04000000, 0x04000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x0a000000 }, + { 0x0000989c, 0x00380080, 0x02380080 }, + { 0x0000989c, 0x00020006, 0x00000006 }, + { 0x0000989c, 0x00000092, 0x00000092 }, + { 0x0000989c, 0x000000a0, 0x000000a0 }, + { 0x0000989c, 0x00040007, 0x00040007 }, + { 0x000098d4, 0x0000001a, 0x0000001a }, + { 0x0000989c, 0x00000048, 0x00000048 }, + { 0x0000989c, 0x00000010, 0x00000010 }, + { 0x0000989c, 0x00000008, 0x00000008 }, + { 0x0000989c, 0x0000000f, 0x0000000f }, + { 0x0000989c, 0x000000f2, 0x00000062 }, + { 0x0000989c, 0x0000904f, 0x0000904c }, + { 0x0000989c, 0x0000125a, 0x0000129a }, + { 0x000098cc, 0x0000000e, 0x0000000f }, +}; + --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5312/ar5312.h 2009-03-23 17:36:55.000000000 +0000 @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2008 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ar5312.h,v 1.1 2009/03/23 17:14:48 sborrill Exp $ + */ +#ifndef _ATH_AR5312_H_ +#define _ATH_AR5312_H_ + +#include "ah_soc.h" +#include "ar5212/ar5212.h" + +#define AR5312_UNIT(_ah) \ + (((const struct ar531x_config *)((_ah)->ah_st))->unit) +#define AR5312_BOARDCONFIG(_ah) \ + (((const struct ar531x_config *)((_ah)->ah_st))->board) +#define AR5312_RADIOCONFIG(_ah) \ + (((const struct ar531x_config *)((_ah)->ah_st))->radio) + +#define IS_5312_2_X(ah) \ + (AH_PRIVATE(ah)->ah_macVersion == AR_SREV_VERSION_VENICE && \ + (AH_PRIVATE(ah)->ah_macRev == 2 || AH_PRIVATE(ah)->ah_macRev == 7)) +#define IS_5315(ah) \ + (AH_PRIVATE(ah)->ah_devid == AR5212_AR2315_REV6 || \ + AH_PRIVATE(ah)->ah_devid == AR5212_AR2315_REV7 || \ + AH_PRIVATE(ah)->ah_devid == AR5212_AR2317_REV1 || \ + AH_PRIVATE(ah)->ah_devid == AR5212_AR2317_REV2) + +extern HAL_BOOL ar5312IsInterruptPending(struct ath_hal *ah); + +/* AR5312 */ +extern HAL_BOOL ar5312GpioCfgOutput(struct ath_hal *, uint32_t gpio); +extern HAL_BOOL ar5312GpioCfgInput(struct ath_hal *, uint32_t gpio); +extern HAL_BOOL ar5312GpioSet(struct ath_hal *, uint32_t gpio, uint32_t val); +extern uint32_t ar5312GpioGet(struct ath_hal *ah, uint32_t gpio); +extern void ar5312GpioSetIntr(struct ath_hal *ah, u_int, uint32_t ilevel); + +/* AR2315+ */ +extern HAL_BOOL ar5315GpioCfgOutput(struct ath_hal *, uint32_t gpio); +extern HAL_BOOL ar5315GpioCfgInput(struct ath_hal *, uint32_t gpio); +extern HAL_BOOL ar5315GpioSet(struct ath_hal *, uint32_t gpio, uint32_t val); +extern uint32_t ar5315GpioGet(struct ath_hal *ah, uint32_t gpio); +extern void ar5315GpioSetIntr(struct ath_hal *ah, u_int, uint32_t ilevel); + +extern void ar5312SetLedState(struct ath_hal *ah, HAL_LED_STATE state); +extern HAL_BOOL ar5312DetectCardPresent(struct ath_hal *ah); +extern void ar5312SetupClock(struct ath_hal *ah, HAL_OPMODE opmode); +extern void ar5312RestoreClock(struct ath_hal *ah, HAL_OPMODE opmode); +extern void ar5312DumpState(struct ath_hal *ah); +extern HAL_BOOL ar5312Reset(struct ath_hal *ah, HAL_OPMODE opmode, + HAL_CHANNEL *chan, HAL_BOOL bChannelChange, HAL_STATUS *status); +extern HAL_BOOL ar5312ChipReset(struct ath_hal *ah, HAL_CHANNEL *chan); +extern HAL_BOOL ar5312SetPowerMode(struct ath_hal *ah, HAL_POWER_MODE mode, + int setChip); +extern HAL_BOOL ar5312PhyDisable(struct ath_hal *ah); +extern HAL_BOOL ar5312Disable(struct ath_hal *ah); +extern HAL_BOOL ar5312MacReset(struct ath_hal *ah, unsigned int RCMask); +extern uint32_t ar5312GetPowerMode(struct ath_hal *ah); +extern HAL_BOOL ar5312GetPowerStatus(struct ath_hal *ah); + +/* BSP functions */ +extern HAL_BOOL ar5312EepromRead(struct ath_hal *, u_int off, uint16_t *data); +extern HAL_BOOL ar5312EepromWrite(struct ath_hal *, u_int off, uint16_t data); + +#endif /* _ATH_AR3212_H_ */ --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5312/ar5312_attach.c 2009-03-23 17:36:55.000000000 +0000 @@ -0,0 +1,333 @@ +/* + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2008 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ar5312_attach.c,v 1.1 2009/03/23 17:14:48 sborrill Exp $ + */ +#include "opt_ah.h" + +#include "ah.h" +#include "ah_internal.h" +#include "ah_devid.h" + +#include "ar5312/ar5312.h" +#include "ar5312/ar5312reg.h" +#include "ar5312/ar5312phy.h" + +/* Add static register initialization vectors */ +#define AH_5212_COMMON +#include "ar5212/ar5212.ini" + +static HAL_BOOL ar5312GetMacAddr(struct ath_hal *ah); + +static void +ar5312AniSetup(struct ath_hal *ah) +{ + static const struct ar5212AniParams aniparams = { + .maxNoiseImmunityLevel = 4, /* levels 0..4 */ + .totalSizeDesired = { -41, -41, -48, -48, -48 }, + .coarseHigh = { -18, -18, -16, -14, -12 }, + .coarseLow = { -56, -56, -60, -60, -60 }, + .firpwr = { -72, -72, -75, -78, -80 }, + .maxSpurImmunityLevel = 2, + .cycPwrThr1 = { 2, 4, 6 }, + .maxFirstepLevel = 2, /* levels 0..2 */ + .firstep = { 0, 4, 8 }, + .ofdmTrigHigh = 500, + .ofdmTrigLow = 200, + .cckTrigHigh = 200, + .cckTrigLow = 100, + .rssiThrHigh = 40, + .rssiThrLow = 7, + .period = 100, + }; + ar5212AniAttach(ah, &aniparams, &aniparams, AH_TRUE); +} + +/* + * Attach for an AR5312 part. + */ +static struct ath_hal * +ar5312Attach(uint16_t devid, HAL_SOFTC sc, + HAL_BUS_TAG st, HAL_BUS_HANDLE sh, HAL_STATUS *status) +{ + struct ath_hal_5212 *ahp = AH_NULL; + struct ath_hal *ah; + struct ath_hal_rf *rf; + uint32_t val; + uint16_t eeval; + HAL_STATUS ecode; + + HALDEBUG(AH_NULL, HAL_DEBUG_ATTACH, "%s: sc %p st %p sh %p\n", + __func__, sc, st, (void*) sh); + + /* NB: memory is returned zero'd */ + ahp = ath_hal_malloc(sizeof (struct ath_hal_5212)); + if (ahp == AH_NULL) { + HALDEBUG(AH_NULL, HAL_DEBUG_ANY, + "%s: cannot allocate memory for state block\n", __func__); + *status = HAL_ENOMEM; + return AH_NULL; + } + ar5212InitState(ahp, devid, sc, st, sh, status); + ah = &ahp->ah_priv.h; + + /* override 5212 methods for our needs */ + ah->ah_reset = ar5312Reset; + ah->ah_phyDisable = ar5312PhyDisable; + ah->ah_setLedState = ar5312SetLedState; + ah->ah_detectCardPresent = ar5312DetectCardPresent; + ah->ah_setPowerMode = ar5312SetPowerMode; + ah->ah_getPowerMode = ar5312GetPowerMode; + ah->ah_isInterruptPending = ar5312IsInterruptPending; + + ahp->ah_priv.ah_eepromRead = ar5312EepromRead; +#ifdef AH_SUPPORT_WRITE_EEPROM + ahp->ah_priv.ah_eepromWrite = ar5312EepromWrite; +#endif +#if ( AH_SUPPORT_2316 || AH_SUPPORT_2317) + if (IS_5315(ah)) { + ahp->ah_priv.ah_gpioCfgOutput = ar5315GpioCfgOutput; + ahp->ah_priv.ah_gpioCfgInput = ar5315GpioCfgInput; + ahp->ah_priv.ah_gpioGet = ar5315GpioGet; + ahp->ah_priv.ah_gpioSet = ar5315GpioSet; + ahp->ah_priv.ah_gpioSetIntr = ar5315GpioSetIntr; + } else +#endif + { + ahp->ah_priv.ah_gpioCfgOutput = ar5312GpioCfgOutput; + ahp->ah_priv.ah_gpioCfgInput = ar5312GpioCfgInput; + ahp->ah_priv.ah_gpioGet = ar5312GpioGet; + ahp->ah_priv.ah_gpioSet = ar5312GpioSet; + ahp->ah_priv.ah_gpioSetIntr = ar5312GpioSetIntr; + } + + ah->ah_gpioCfgInput = ahp->ah_priv.ah_gpioCfgInput; + ah->ah_gpioCfgOutput = ahp->ah_priv.ah_gpioCfgOutput; + ah->ah_gpioGet = ahp->ah_priv.ah_gpioGet; + ah->ah_gpioSet = ahp->ah_priv.ah_gpioSet; + ah->ah_gpioSetIntr = ahp->ah_priv.ah_gpioSetIntr; + + /* setup common ini data; rf backends handle remainder */ + HAL_INI_INIT(&ahp->ah_ini_modes, ar5212Modes, 6); + HAL_INI_INIT(&ahp->ah_ini_common, ar5212Common, 6); + + if (!ar5312ChipReset(ah, AH_NULL)) { /* reset chip */ + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: chip reset failed\n", __func__); + ecode = HAL_EIO; + goto bad; + } + +#if ( AH_SUPPORT_2316 || AH_SUPPORT_2317) + if ((devid == AR5212_AR2315_REV6) || + (devid == AR5212_AR2315_REV7) || + (devid == AR5212_AR2317_REV1) || + (devid == AR5212_AR2317_REV2) ) { + val = ((OS_REG_READ(ah, (AR5315_RSTIMER_BASE -((uint32_t) sh)) + AR5315_WREV)) >> AR5315_WREV_S) + & AR5315_WREV_ID; + AH_PRIVATE(ah)->ah_macVersion = val >> AR5315_WREV_ID_S; + AH_PRIVATE(ah)->ah_macRev = val & AR5315_WREV_REVISION; + HALDEBUG(ah, HAL_DEBUG_ATTACH, + "%s: Mac Chip Rev 0x%02x.%x\n" , __func__, + AH_PRIVATE(ah)->ah_macVersion, AH_PRIVATE(ah)->ah_macRev); + } else +#endif + { + val = OS_REG_READ(ah, (AR5312_RSTIMER_BASE - ((uint32_t) sh)) + 0x0020); + val = OS_REG_READ(ah, (AR5312_RSTIMER_BASE - ((uint32_t) sh)) + 0x0080); + /* Read Revisions from Chips */ + val = ((OS_REG_READ(ah, (AR5312_RSTIMER_BASE - ((uint32_t) sh)) + AR5312_WREV)) >> AR5312_WREV_S) & AR5312_WREV_ID; + AH_PRIVATE(ah)->ah_macVersion = val >> AR5312_WREV_ID_S; + AH_PRIVATE(ah)->ah_macRev = val & AR5312_WREV_REVISION; + } + /* XXX - THIS IS WRONG. NEEDS TO BE FIXED */ + if (((AH_PRIVATE(ah)->ah_macVersion != AR_SREV_VERSION_VENICE && + AH_PRIVATE(ah)->ah_macVersion != AR_SREV_VERSION_VENICE) || + AH_PRIVATE(ah)->ah_macRev < AR_SREV_D2PLUS) && + AH_PRIVATE(ah)->ah_macVersion != AR_SREV_VERSION_COBRA) { +#ifdef AH_DEBUG + ath_hal_printf(ah, "%s: Mac Chip Rev 0x%02x.%x is not supported by " + "this driver\n", __func__, + AH_PRIVATE(ah)->ah_macVersion, + AH_PRIVATE(ah)->ah_macRev); +#endif + ecode = HAL_ENOTSUPP; + goto bad; + } + + AH_PRIVATE(ah)->ah_phyRev = OS_REG_READ(ah, AR_PHY_CHIP_ID); + + if (!ar5212ChipTest(ah)) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: hardware self-test failed\n", + __func__); + ecode = HAL_ESELFTEST; + goto bad; + } + + /* + * Set correct Baseband to analog shift + * setting to access analog chips. + */ + OS_REG_WRITE(ah, AR_PHY(0), 0x00000007); + + /* Read Radio Chip Rev Extract */ + AH_PRIVATE(ah)->ah_analog5GhzRev = ar5212GetRadioRev(ah); + + rf = ath_hal_rfprobe(ah, &ecode); + if (rf == AH_NULL) + goto bad; + if (IS_RAD5112(ah) && !IS_RADX112_REV2(ah)) { +#ifdef AH_DEBUG + ath_hal_printf(ah, "%s: 5112 Rev 1 is not supported by this " + "driver (analog5GhzRev 0x%x)\n", __func__, + AH_PRIVATE(ah)->ah_analog5GhzRev); +#endif + ecode = HAL_ENOTSUPP; + goto bad; + } + + ecode = ath_hal_legacyEepromAttach(ah); + if (ecode != HAL_OK) { + goto bad; + } + + /* + * If Bmode and AR5212, verify 2.4 analog exists + */ + if (ath_hal_eepromGetFlag(ah, AR_EEP_BMODE) && + (AH_PRIVATE(ah)->ah_analog5GhzRev & 0xF0) == AR_RAD5111_SREV_MAJOR) { + /* + * Set correct Baseband to analog shift + * setting to access analog chips. + */ + OS_REG_WRITE(ah, AR_PHY(0), 0x00004007); + OS_DELAY(2000); + AH_PRIVATE(ah)->ah_analog2GhzRev = ar5212GetRadioRev(ah); + + /* Set baseband for 5GHz chip */ + OS_REG_WRITE(ah, AR_PHY(0), 0x00000007); + OS_DELAY(2000); + if ((AH_PRIVATE(ah)->ah_analog2GhzRev & 0xF0) != AR_RAD2111_SREV_MAJOR) { +#ifdef AH_DEBUG + ath_hal_printf(ah, "%s: 2G Radio Chip Rev 0x%02X is not " + "supported by this driver\n", __func__, + AH_PRIVATE(ah)->ah_analog2GhzRev); +#endif + ecode = HAL_ENOTSUPP; + goto bad; + } + } + + ecode = ath_hal_eepromGet(ah, AR_EEP_REGDMN_0, &eeval); + if (ecode != HAL_OK) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: cannot read regulatory domain from EEPROM\n", + __func__); + goto bad; + } + AH_PRIVATE(ah)->ah_currentRD = eeval; + /* XXX record serial number */ + + /* XXX other capabilities */ + /* + * Got everything we need now to setup the capabilities. + */ + if (!ar5212FillCapabilityInfo(ah)) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: failed ar5212FillCapabilityInfo\n", __func__); + ecode = HAL_EEREAD; + goto bad; + } + + if (!rf->attach(ah, &ecode)) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: RF setup failed, status %u\n", + __func__, ecode); + goto bad; + } + /* arrange a direct call instead of thunking */ + AH_PRIVATE(ah)->ah_getNfAdjust = ahp->ah_rfHal->getNfAdjust; + + /* Initialize gain ladder thermal calibration structure */ + ar5212InitializeGainValues(ah); + + /* BSP specific call for MAC address of this WMAC device */ + if (!ar5312GetMacAddr(ah)) { + ecode = HAL_EEBADMAC; + goto bad; + } + + ar5312AniSetup(ah); + ar5212InitNfCalHistBuffer(ah); + + /* XXX EAR stuff goes here */ + return ah; + +bad: + if (ahp) + ar5212Detach((struct ath_hal *) ahp); + if (status) + *status = ecode; + return AH_NULL; +} + +static HAL_BOOL +ar5312GetMacAddr(struct ath_hal *ah) +{ + const struct ar531x_boarddata *board = AR5312_BOARDCONFIG(ah); + int wlanNum = AR5312_UNIT(ah); + const uint8_t *macAddr; + + switch (wlanNum) { + case 0: + macAddr = board->wlan0Mac; + break; + case 1: + macAddr = board->wlan1Mac; + break; + default: +#ifdef AH_DEBUG + ath_hal_printf(ah, "Invalid WLAN wmac index (%d)\n", + wlanNum); +#endif + return AH_FALSE; + } + OS_MEMCPY(AH5212(ah)->ah_macaddr, macAddr, 6); + return AH_TRUE; +} + +static const char* +ar5312Probe(uint16_t vendorid, uint16_t devid) +{ + if (vendorid == ATHEROS_VENDOR_ID) { + switch (devid) { + case AR5212_AR5312_REV2: + case AR5212_AR5312_REV7: + return "Atheros 5312 WiSoC"; + case AR5212_AR2313_REV8: + return "Atheros 2313 WiSoC"; + case AR5212_AR2315_REV6: + case AR5212_AR2315_REV7: + return "Atheros 2315 WiSoC"; + case AR5212_AR2317_REV1: + return "Atheros 2317 WiSoC"; + case AR5212_AR2413: + return "Atheros 2413"; + case AR5212_AR2417: + return "Atheros 2417"; + } + } + return AH_NULL; +} +AH_CHIP(AR5312, ar5312Probe, ar5312Attach); --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5312/ar5312_eeprom.c 2009-03-23 17:36:55.000000000 +0000 @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2008 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ar5312_eeprom.c,v 1.1 2009/03/23 17:14:48 sborrill Exp $ + */ +#include "opt_ah.h" + + +#ifdef AH_SUPPORT_AR5312 + +#include "ah.h" +#include "ah_internal.h" + +#include "ar5312/ar5312.h" +#include "ar5312/ar5312reg.h" +#include "ar5212/ar5212desc.h" + +/* + * Read 16 bits of data from offset into *data + */ +HAL_BOOL +ar5312EepromRead(struct ath_hal *ah, u_int off, uint16_t *dataIn) +{ + int i,offset; + const char *eepromAddr = AR5312_RADIOCONFIG(ah); + uint8_t *data; + + data = (uint8_t *) dataIn; + for (i=0,offset=2*off; i<2; i++,offset++) { + data[i] = eepromAddr[offset]; + } + return AH_TRUE; +} +#endif /* AH_SUPPORT_AR5312 */ --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5312/ar5312_gpio.c 2009-03-23 17:36:55.000000000 +0000 @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2008 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ar5312_gpio.c,v 1.1 2009/03/23 17:14:48 sborrill Exp $ + */ +#include "opt_ah.h" + +#ifdef AH_SUPPORT_AR5312 + +#include "ah.h" +#include "ah_internal.h" +#include "ah_devid.h" + +#include "ar5312/ar5312.h" +#include "ar5312/ar5312reg.h" +#include "ar5312/ar5312phy.h" + +#define AR_NUM_GPIO 6 /* 6 GPIO pins */ +#define AR5312_GPIOD_MASK 0x0000002F /* GPIO data reg r/w mask */ + +/* + * Configure GPIO Output lines + */ +HAL_BOOL +ar5312GpioCfgOutput(struct ath_hal *ah, uint32_t gpio) +{ + uint32_t gpioOffset = (AR5312_GPIO_BASE - ((uint32_t) ah->ah_sh)); + + HALASSERT(gpio < AR_NUM_GPIO); + + OS_REG_WRITE(ah, gpioOffset+AR5312_GPIOCR, + (OS_REG_READ(ah, gpioOffset+AR5312_GPIOCR) &~ AR_GPIOCR_CR_A(gpio)) + | AR_GPIOCR_CR_A(gpio)); + + return AH_TRUE; +} + +/* + * Configure GPIO Input lines + */ +HAL_BOOL +ar5312GpioCfgInput(struct ath_hal *ah, uint32_t gpio) +{ + uint32_t gpioOffset = (AR5312_GPIO_BASE - ((uint32_t) ah->ah_sh)); + + HALASSERT(gpio < AR_NUM_GPIO); + + OS_REG_WRITE(ah, gpioOffset+AR5312_GPIOCR, + (OS_REG_READ(ah, gpioOffset+AR5312_GPIOCR) &~ AR_GPIOCR_CR_A(gpio)) + | AR_GPIOCR_CR_N(gpio)); + + return AH_TRUE; +} + +/* + * Once configured for I/O - set output lines + */ +HAL_BOOL +ar5312GpioSet(struct ath_hal *ah, uint32_t gpio, uint32_t val) +{ + uint32_t reg; + uint32_t gpioOffset = (AR5312_GPIO_BASE - ((uint32_t) ah->ah_sh)); + + HALASSERT(gpio < AR_NUM_GPIO); + + reg = OS_REG_READ(ah, gpioOffset+AR5312_GPIODO); + reg &= ~(1 << gpio); + reg |= (val&1) << gpio; + + OS_REG_WRITE(ah, gpioOffset+AR5312_GPIODO, reg); + return AH_TRUE; +} + +/* + * Once configured for I/O - get input lines + */ +uint32_t +ar5312GpioGet(struct ath_hal *ah, uint32_t gpio) +{ + uint32_t gpioOffset = (AR5312_GPIO_BASE - ((uint32_t) ah->ah_sh)); + + if (gpio < AR_NUM_GPIO) { + uint32_t val = OS_REG_READ(ah, gpioOffset+AR5312_GPIODI); + val = ((val & AR5312_GPIOD_MASK) >> gpio) & 0x1; + return val; + } else { + return 0xffffffff; + } +} + +/* + * Set the GPIO Interrupt + */ +void +ar5312GpioSetIntr(struct ath_hal *ah, u_int gpio, uint32_t ilevel) +{ + uint32_t val; + uint32_t gpioOffset = (AR5312_GPIO_BASE - ((uint32_t) ah->ah_sh)); + + /* XXX bounds check gpio */ + val = OS_REG_READ(ah, gpioOffset+AR5312_GPIOCR); + val &= ~(AR_GPIOCR_CR_A(gpio) | + AR_GPIOCR_INT_MASK | AR_GPIOCR_INT_ENA | AR_GPIOCR_INT_SEL); + val |= AR_GPIOCR_CR_N(gpio) | AR_GPIOCR_INT(gpio) | AR_GPIOCR_INT_ENA; + if (ilevel) + val |= AR_GPIOCR_INT_SELH; /* interrupt on pin high */ + else + val |= AR_GPIOCR_INT_SELL; /* interrupt on pin low */ + + /* Don't need to change anything for low level interrupt. */ + OS_REG_WRITE(ah, gpioOffset+AR5312_GPIOCR, val); + + /* Change the interrupt mask. */ + (void) ar5212SetInterrupts(ah, AH5212(ah)->ah_maskReg | HAL_INT_GPIO); +} + + +#endif /* AH_SUPPORT_AR5312 */ --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5312/ar5312_interrupts.c 2009-03-23 17:36:55.000000000 +0000 @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2008 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ar5312_interrupts.c,v 1.1 2009/03/23 17:14:48 sborrill Exp $ + */ +#include "opt_ah.h" + +#ifdef AH_SUPPORT_AR5312 + +#include "ah.h" +#include "ah_internal.h" + +#include "ar5312/ar5312.h" +#include "ar5312/ar5312reg.h" +#include "ar5312/ar5312phy.h" + + +/* + * Checks to see if an interrupt is pending on our NIC + * + * Returns: TRUE if an interrupt is pending + * FALSE if not + */ +HAL_BOOL +ar5312IsInterruptPending(struct ath_hal *ah) +{ + /* + * Some platforms trigger our ISR before applying power to + * the card. For the 5312, this is always true. + */ + + return(AH_TRUE); +} +#endif /* AH_SUPPORT_AR5312 */ --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5312/ar5312_misc.c 2009-03-23 17:36:56.000000000 +0000 @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2008 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ar5312_misc.c,v 1.1 2009/03/23 17:14:48 sborrill Exp $ + */ +#include "opt_ah.h" + +#ifdef AH_SUPPORT_AR5312 + +#include "ah.h" +#include "ah_internal.h" +#include "ah_devid.h" + +#include "ar5312/ar5312.h" +#include "ar5312/ar5312reg.h" +#include "ar5312/ar5312phy.h" + +#define AR_NUM_GPIO 6 /* 6 GPIO pins */ +#define AR_GPIOD_MASK 0x0000002F /* GPIO data reg r/w mask */ + +/* + * Change the LED blinking pattern to correspond to the connectivity + */ +void +ar5312SetLedState(struct ath_hal *ah, HAL_LED_STATE state) +{ + uint32_t val; + uint32_t resOffset = (AR5312_RSTIMER_BASE - ((uint32_t) ah->ah_sh)); + if(IS_2316(ah)) return; /* not yet */ + val = SM(AR5312_PCICFG_LEDSEL0, AR5312_PCICFG_LEDSEL) | + SM(AR5312_PCICFG_LEDMOD0, AR5312_PCICFG_LEDMODE) | + 2; + OS_REG_WRITE(ah, resOffset+AR5312_PCICFG, + (OS_REG_READ(ah, AR5312_PCICFG) &~ + (AR5312_PCICFG_LEDSEL | AR5312_PCICFG_LEDMODE | + AR5312_PCICFG_LEDSBR)) + | val); +} + +/* + * Detect if our wireless mac is present. + */ +HAL_BOOL +ar5312DetectCardPresent(struct ath_hal *ah) +{ + uint16_t macVersion, macRev; + uint32_t v; + + /* + * Read the Silicon Revision register and compare that + * to what we read at attach time. If the same, we say + * a card/device is present. + */ +#if (AH_SUPPORT_2316 || AH_SUPPORT_2317) + if(IS_5315(ah)) + { + v = (OS_REG_READ(ah, + (AR5315_RSTIMER_BASE-((uint32_t) ah->ah_sh)) + AR5315_WREV)) + & AR_SREV_ID; + macVersion = v >> AR_SREV_ID_S; + macRev = v & AR_SREV_REVISION; + return (AH_PRIVATE(ah)->ah_macVersion == macVersion && + AH_PRIVATE(ah)->ah_macRev == macRev); + } + else +#endif + { + v = (OS_REG_READ(ah, + (AR5312_RSTIMER_BASE-((uint32_t) ah->ah_sh)) + AR5312_WREV)) + & AR_SREV_ID; + macVersion = v >> AR_SREV_ID_S; + macRev = v & AR_SREV_REVISION; + return (AH_PRIVATE(ah)->ah_macVersion == macVersion && + AH_PRIVATE(ah)->ah_macRev == macRev); + } +} + +/* + * If 32KHz clock exists, use it to lower power consumption during sleep + * + * Note: If clock is set to 32 KHz, delays on accessing certain + * baseband registers (27-31, 124-127) are required. + */ +void +ar5312SetupClock(struct ath_hal *ah, HAL_OPMODE opmode) +{ + if (ar5212Use32KHzclock(ah, opmode)) { + /* + * Enable clocks to be turned OFF in BB during sleep + * and also enable turning OFF 32MHz/40MHz Refclk + * from A2. + */ + OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_CONTROL, 0x1f); + OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_LIMIT, 0x0d); + OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0c); + OS_REG_WRITE(ah, AR_PHY_M_SLEEP, 0x03); + OS_REG_WRITE(ah, AR_PHY_REFCLKDLY, 0x05); + OS_REG_WRITE(ah, AR_PHY_REFCLKPD, + IS_RAD5112_ANY(ah) ? 0x14 : 0x18); + + OS_REG_RMW_FIELD(ah, AR_USEC, AR_USEC_USEC32, 1); + OS_REG_WRITE(ah, AR_TSF_PARM, 61); /* 32 KHz TSF incr */ + + } else { + OS_REG_WRITE(ah, AR_TSF_PARM, 1); /* 32 MHz TSF incr */ + OS_REG_RMW_FIELD(ah, AR_USEC, AR_USEC_USEC32, + IS_RAD5112_ANY(ah) ? 39 : 31); + + OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_CONTROL, 0x1f); + OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_LIMIT, 0x7f); + + if (IS_5312_2_X(ah)) { + /* Set ADC/DAC select values */ + OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x04); + } else { + OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0e); + OS_REG_WRITE(ah, AR_PHY_M_SLEEP, 0x0c); + OS_REG_WRITE(ah, AR_PHY_REFCLKDLY, 0xff); + OS_REG_WRITE(ah, AR_PHY_REFCLKPD, + IS_RAD5112_ANY(ah) ? 0x14 : 0x18); + } + } +} + +/* + * If 32KHz clock exists, turn it off and turn back on the 32Mhz + */ +void +ar5312RestoreClock(struct ath_hal *ah, HAL_OPMODE opmode) +{ + if (ar5212Use32KHzclock(ah, opmode)) { + /* # Set sleep clock rate back to 32 MHz. */ + OS_REG_WRITE(ah, AR_TSF_PARM, 1); /* 32 MHz TSF incr */ + OS_REG_RMW_FIELD(ah, AR_USEC, AR_USEC_USEC32, + IS_RAD5112_ANY(ah) ? 39 : 31); + + /* + * Restore BB registers to power-on defaults + */ + OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_CONTROL, 0x1f); + OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_LIMIT, 0x7f); + if (IS_5312_2_X(ah)) { + /* Set ADC/DAC select values */ + OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x04); + } else { + OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0e); + OS_REG_WRITE(ah, AR_PHY_M_SLEEP, 0x0c); + OS_REG_WRITE(ah, AR_PHY_REFCLKDLY, 0xff); + OS_REG_WRITE(ah, AR_PHY_REFCLKPD, + IS_RAD5112_ANY(ah) ? 0x14 : 0x18); + } + } +} + +#endif /* AH_SUPPORT_AR5312 */ --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5312/ar5312_power.c 2009-03-23 17:36:56.000000000 +0000 @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2008 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ar5312_power.c,v 1.1 2009/03/23 17:14:48 sborrill Exp $ + */ +#include "opt_ah.h" + +#ifdef AH_SUPPORT_AR5312 + +#include "ah.h" +#include "ah_internal.h" + +#include "ar5312/ar5312.h" +#include "ar5312/ar5312reg.h" +#include "ar5212/ar5212desc.h" + +/* + * Notify Power Mgt is enabled in self-generated frames. + * If requested, force chip awake. + * + * Returns A_OK if chip is awake or successfully forced awake. + * + * WARNING WARNING WARNING + * There is a problem with the chip where sometimes it will not wake up. + */ +static HAL_BOOL +ar5312SetPowerModeAwake(struct ath_hal *ah, int setChip) +{ + /* No need for this at the moment for APs */ + return AH_TRUE; +} + +/* + * Notify Power Mgt is disabled in self-generated frames. + * If requested, force chip to sleep. + */ +static void +ar5312SetPowerModeSleep(struct ath_hal *ah, int setChip) +{ + /* No need for this at the moment for APs */ +} + +/* + * Notify Power Management is enabled in self-generating + * fames. If request, set power mode of chip to + * auto/normal. Duration in units of 128us (1/8 TU). + */ +static void +ar5312SetPowerModeNetworkSleep(struct ath_hal *ah, int setChip) +{ + /* No need for this at the moment for APs */ +} + +/* + * Set power mgt to the requested mode, and conditionally set + * the chip as well + */ +HAL_BOOL +ar5312SetPowerMode(struct ath_hal *ah, HAL_POWER_MODE mode, int setChip) +{ + struct ath_hal_5212 *ahp = AH5212(ah); +#ifdef AH_DEBUG + static const char* modes[] = { + "AWAKE", + "FULL-SLEEP", + "NETWORK SLEEP", + "UNDEFINED" + }; +#endif + int status = AH_TRUE; + + HALDEBUG(ah, HAL_DEBUG_POWER, "%s: %s -> %s (%s)\n", __func__, + modes[ahp->ah_powerMode], modes[mode], + setChip ? "set chip " : ""); + switch (mode) { + case HAL_PM_AWAKE: + status = ar5312SetPowerModeAwake(ah, setChip); + break; + case HAL_PM_FULL_SLEEP: + ar5312SetPowerModeSleep(ah, setChip); + break; + case HAL_PM_NETWORK_SLEEP: + ar5312SetPowerModeNetworkSleep(ah, setChip); + break; + default: + HALDEBUG(ah, HAL_DEBUG_POWER, "%s: unknown power mode %u\n", + __func__, mode); + return AH_FALSE; + } + ahp->ah_powerMode = mode; + return status; +} + +/* + * Return the current sleep mode of the chip + */ +uint32_t +ar5312GetPowerMode(struct ath_hal *ah) +{ + return HAL_PM_AWAKE; +} + +/* + * Return the current sleep state of the chip + * TRUE = sleeping + */ +HAL_BOOL +ar5312GetPowerStatus(struct ath_hal *ah) +{ + return 0; /* Currently, 5312 is never in sleep mode. */ +} +#endif /* AH_SUPPORT_AR5312 */ --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5312/ar5312_reset.c 2009-03-23 17:36:56.000000000 +0000 @@ -0,0 +1,919 @@ +/* + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2008 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ar5312_reset.c,v 1.1 2009/03/23 17:14:48 sborrill Exp $ + */ +#include "opt_ah.h" + +#ifdef AH_SUPPORT_AR5312 + +#include "ah.h" +#include "ah_internal.h" +#include "ah_devid.h" + +#include "ar5312/ar5312.h" +#include "ar5312/ar5312reg.h" +#include "ar5312/ar5312phy.h" + +#include "ah_eeprom_v3.h" + +/* Additional Time delay to wait after activiting the Base band */ +#define BASE_ACTIVATE_DELAY 100 /* 100 usec */ +#define PLL_SETTLE_DELAY 300 /* 300 usec */ + +extern int16_t ar5212GetNf(struct ath_hal *, HAL_CHANNEL_INTERNAL *); +extern void ar5212SetRateDurationTable(struct ath_hal *, HAL_CHANNEL *); +extern HAL_BOOL ar5212SetTransmitPower(struct ath_hal *ah, + HAL_CHANNEL_INTERNAL *chan, uint16_t *rfXpdGain); +extern void ar5212SetDeltaSlope(struct ath_hal *, HAL_CHANNEL *); +extern HAL_BOOL ar5212SetBoardValues(struct ath_hal *, HAL_CHANNEL_INTERNAL *); +extern void ar5212SetIFSTiming(struct ath_hal *, HAL_CHANNEL *); +extern HAL_BOOL ar5212IsSpurChannel(struct ath_hal *, HAL_CHANNEL *); +extern HAL_BOOL ar5212ChannelChange(struct ath_hal *, HAL_CHANNEL *); + +static HAL_BOOL ar5312SetResetReg(struct ath_hal *, uint32_t resetMask); + +static int +write_common(struct ath_hal *ah, const HAL_INI_ARRAY *ia, + HAL_BOOL bChannelChange, int writes) +{ +#define IS_NO_RESET_TIMER_ADDR(x) \ + ( (((x) >= AR_BEACON) && ((x) <= AR_CFP_DUR)) || \ + (((x) >= AR_SLEEP1) && ((x) <= AR_SLEEP3))) +#define V(r, c) (ia)->data[((r)*(ia)->cols) + (c)] + int i; + + /* Write Common Array Parameters */ + for (i = 0; i < ia->rows; i++) { + uint32_t reg = V(i, 0); + /* XXX timer/beacon setup registers? */ + /* On channel change, don't reset the PCU registers */ + if (!(bChannelChange && IS_NO_RESET_TIMER_ADDR(reg))) { + OS_REG_WRITE(ah, reg, V(i, 1)); + DMA_YIELD(writes); + } + } + return writes; +#undef IS_NO_RESET_TIMER_ADDR +#undef V +} + +/* + * Places the device in and out of reset and then places sane + * values in the registers based on EEPROM config, initialization + * vectors (as determined by the mode), and station configuration + * + * bChannelChange is used to preserve DMA/PCU registers across + * a HW Reset during channel change. + */ +HAL_BOOL +ar5312Reset(struct ath_hal *ah, HAL_OPMODE opmode, + HAL_CHANNEL *chan, HAL_BOOL bChannelChange, HAL_STATUS *status) +{ +#define N(a) (sizeof (a) / sizeof (a[0])) +#define FAIL(_code) do { ecode = _code; goto bad; } while (0) + struct ath_hal_5212 *ahp = AH5212(ah); + HAL_CHANNEL_INTERNAL *ichan; + const HAL_EEPROM *ee; + uint32_t saveFrameSeqCount, saveDefAntenna; + uint32_t macStaId1, synthDelay, txFrm2TxDStart; + uint16_t rfXpdGain[MAX_NUM_PDGAINS_PER_CHANNEL]; + int16_t cckOfdmPwrDelta = 0; + u_int modesIndex, freqIndex; + HAL_STATUS ecode; + int i, regWrites = 0; + uint32_t testReg; + uint32_t saveLedState = 0; + + HALASSERT(ah->ah_magic == AR5212_MAGIC); + ee = AH_PRIVATE(ah)->ah_eeprom; + + OS_MARK(ah, AH_MARK_RESET, bChannelChange); +#define IS(_c,_f) (((_c)->channelFlags & _f) || 0) + if ((IS(chan, CHANNEL_2GHZ) ^ IS(chan, CHANNEL_5GHZ)) == 0) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: invalid channel %u/0x%x; not marked as 2GHz or 5GHz\n", + __func__, chan->channel, chan->channelFlags); + FAIL(HAL_EINVAL); + } + if ((IS(chan, CHANNEL_OFDM) ^ IS(chan, CHANNEL_CCK)) == 0) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: invalid channel %u/0x%x; not marked as OFDM or CCK\n", + __func__, chan->channel, chan->channelFlags); + FAIL(HAL_EINVAL); + } +#undef IS + /* + * Map public channel to private. + */ + ichan = ath_hal_checkchannel(ah, chan); + if (ichan == AH_NULL) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: invalid channel %u/0x%x; no mapping\n", + __func__, chan->channel, chan->channelFlags); + FAIL(HAL_EINVAL); + } + switch (opmode) { + case HAL_M_STA: + case HAL_M_IBSS: + case HAL_M_HOSTAP: + case HAL_M_MONITOR: + break; + default: + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid operating mode %u\n", + __func__, opmode); + FAIL(HAL_EINVAL); + break; + } + HALASSERT(ahp->ah_eeversion >= AR_EEPROM_VER3); + + /* Preserve certain DMA hardware registers on a channel change */ + if (bChannelChange) { + /* + * On Venice, the TSF is almost preserved across a reset; + * it requires the doubling writes to the RESET_TSF + * bit in the AR_BEACON register; it also has the quirk + * of the TSF going back in time on the station (station + * latches onto the last beacon's tsf during a reset 50% + * of the times); the latter is not a problem for adhoc + * stations since as long as the TSF is behind, it will + * get resynchronized on receiving the next beacon; the + * TSF going backwards in time could be a problem for the + * sleep operation (supported on infrastructure stations + * only) - the best and most general fix for this situation + * is to resynchronize the various sleep/beacon timers on + * the receipt of the next beacon i.e. when the TSF itself + * gets resynchronized to the AP's TSF - power save is + * needed to be temporarily disabled until that time + * + * Need to save the sequence number to restore it after + * the reset! + */ + saveFrameSeqCount = OS_REG_READ(ah, AR_D_SEQNUM); + } else + saveFrameSeqCount = 0; /* NB: silence compiler */ + + /* If the channel change is across the same mode - perform a fast channel change */ + if ((IS_2413(ah) || IS_5413(ah))) { + /* + * Channel change can only be used when: + * -channel change requested - so it's not the initial reset. + * -it's not a change to the current channel - often called when switching modes + * on a channel + * -the modes of the previous and requested channel are the same - some ugly code for XR + */ + if (bChannelChange && + (AH_PRIVATE(ah)->ah_curchan != AH_NULL) && + (chan->channel != AH_PRIVATE(ah)->ah_curchan->channel) && + ((chan->channelFlags & CHANNEL_ALL) == + (AH_PRIVATE(ah)->ah_curchan->channelFlags & CHANNEL_ALL))) { + if (ar5212ChannelChange(ah, chan)) + /* If ChannelChange completed - skip the rest of reset */ + return AH_TRUE; + } + } + + /* + * Preserve the antenna on a channel change + */ + saveDefAntenna = OS_REG_READ(ah, AR_DEF_ANTENNA); + if (saveDefAntenna == 0) /* XXX magic constants */ + saveDefAntenna = 1; + + /* Save hardware flag before chip reset clears the register */ + macStaId1 = OS_REG_READ(ah, AR_STA_ID1) & + (AR_STA_ID1_BASE_RATE_11B | AR_STA_ID1_USE_DEFANT); + + /* Save led state from pci config register */ + if (!IS_5315(ah)) + saveLedState = OS_REG_READ(ah, AR5312_PCICFG) & + (AR_PCICFG_LEDCTL | AR_PCICFG_LEDMODE | AR_PCICFG_LEDBLINK | + AR_PCICFG_LEDSLOW); + + ar5312RestoreClock(ah, opmode); /* move to refclk operation */ + + /* + * Adjust gain parameters before reset if + * there's an outstanding gain updated. + */ + (void) ar5212GetRfgain(ah); + + if (!ar5312ChipReset(ah, chan)) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: chip reset failed\n", __func__); + FAIL(HAL_EIO); + } + + /* Setup the indices for the next set of register array writes */ + switch (chan->channelFlags & CHANNEL_ALL) { + case CHANNEL_A: + modesIndex = 1; + freqIndex = 1; + break; + case CHANNEL_T: + modesIndex = 2; + freqIndex = 1; + break; + case CHANNEL_B: + modesIndex = 3; + freqIndex = 2; + break; + case CHANNEL_PUREG: + modesIndex = 4; + freqIndex = 2; + break; + case CHANNEL_108G: + modesIndex = 5; + freqIndex = 2; + break; + default: + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel flags 0x%x\n", + __func__, chan->channelFlags); + FAIL(HAL_EINVAL); + } + + OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__); + + /* Set correct Baseband to analog shift setting to access analog chips. */ + OS_REG_WRITE(ah, AR_PHY(0), 0x00000007); + + regWrites = ath_hal_ini_write(ah, &ahp->ah_ini_modes, modesIndex, 0); + regWrites = write_common(ah, &ahp->ah_ini_common, bChannelChange, + regWrites); + ahp->ah_rfHal->writeRegs(ah, modesIndex, freqIndex, regWrites); + + OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__); + + if (IS_CHAN_HALF_RATE(chan) || IS_CHAN_QUARTER_RATE(chan)) { + ar5212SetIFSTiming(ah, chan); + } + + /* Overwrite INI values for revised chipsets */ + if (AH_PRIVATE(ah)->ah_phyRev >= AR_PHY_CHIP_ID_REV_2) { + /* ADC_CTL */ + OS_REG_WRITE(ah, AR_PHY_ADC_CTL, + SM(2, AR_PHY_ADC_CTL_OFF_INBUFGAIN) | + SM(2, AR_PHY_ADC_CTL_ON_INBUFGAIN) | + AR_PHY_ADC_CTL_OFF_PWDDAC | + AR_PHY_ADC_CTL_OFF_PWDADC); + + /* TX_PWR_ADJ */ + if (chan->channel == 2484) { + cckOfdmPwrDelta = SCALE_OC_DELTA(ee->ee_cckOfdmPwrDelta - ee->ee_scaledCh14FilterCckDelta); + } else { + cckOfdmPwrDelta = SCALE_OC_DELTA(ee->ee_cckOfdmPwrDelta); + } + + if (IS_CHAN_G(chan)) { + OS_REG_WRITE(ah, AR_PHY_TXPWRADJ, + SM((ee->ee_cckOfdmPwrDelta*-1), AR_PHY_TXPWRADJ_CCK_GAIN_DELTA) | + SM((cckOfdmPwrDelta*-1), AR_PHY_TXPWRADJ_CCK_PCDAC_INDEX)); + } else { + OS_REG_WRITE(ah, AR_PHY_TXPWRADJ, 0); + } + + /* Add barker RSSI thresh enable as disabled */ + OS_REG_CLR_BIT(ah, AR_PHY_DAG_CTRLCCK, + AR_PHY_DAG_CTRLCCK_EN_RSSI_THR); + OS_REG_RMW_FIELD(ah, AR_PHY_DAG_CTRLCCK, + AR_PHY_DAG_CTRLCCK_RSSI_THR, 2); + + /* Set the mute mask to the correct default */ + OS_REG_WRITE(ah, AR_SEQ_MASK, 0x0000000F); + } + + if (AH_PRIVATE(ah)->ah_phyRev >= AR_PHY_CHIP_ID_REV_3) { + /* Clear reg to alllow RX_CLEAR line debug */ + OS_REG_WRITE(ah, AR_PHY_BLUETOOTH, 0); + } + if (AH_PRIVATE(ah)->ah_phyRev >= AR_PHY_CHIP_ID_REV_4) { +#ifdef notyet + /* Enable burst prefetch for the data queues */ + OS_REG_RMW_FIELD(ah, AR_D_FPCTL, ... ); + /* Enable double-buffering */ + OS_REG_CLR_BIT(ah, AR_TXCFG, AR_TXCFG_DBL_BUF_DIS); +#endif + } + + if (IS_5312_2_X(ah)) { + /* ADC_CTRL */ + OS_REG_WRITE(ah, AR_PHY_SIGMA_DELTA, + SM(2, AR_PHY_SIGMA_DELTA_ADC_SEL) | + SM(4, AR_PHY_SIGMA_DELTA_FILT2) | + SM(0x16, AR_PHY_SIGMA_DELTA_FILT1) | + SM(0, AR_PHY_SIGMA_DELTA_ADC_CLIP)); + + if (IS_CHAN_2GHZ(chan)) + OS_REG_RMW_FIELD(ah, AR_PHY_RXGAIN, AR_PHY_RXGAIN_TXRX_RF_MAX, 0x0F); + + /* CCK Short parameter adjustment in 11B mode */ + if (IS_CHAN_B(chan)) + OS_REG_RMW_FIELD(ah, AR_PHY_CCK_RXCTRL4, AR_PHY_CCK_RXCTRL4_FREQ_EST_SHORT, 12); + + /* Set ADC/DAC select values */ + OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x04); + + /* Increase 11A AGC Settling */ + if ((chan->channelFlags & CHANNEL_ALL) == CHANNEL_A) + OS_REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_AGC, 32); + } else { + /* Set ADC/DAC select values */ + OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0e); + } + + /* Setup the transmit power values. */ + if (!ar5212SetTransmitPower(ah, ichan, rfXpdGain)) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: error init'ing transmit power\n", __func__); + FAIL(HAL_EIO); + } + + /* Write the analog registers */ + if (!ahp->ah_rfHal->setRfRegs(ah, ichan, modesIndex, rfXpdGain)) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: ar5212SetRfRegs failed\n", + __func__); + FAIL(HAL_EIO); + } + + /* Write delta slope for OFDM enabled modes (A, G, Turbo) */ + if (IS_CHAN_OFDM(chan)) { + if ((IS_5413(ah) || (AH_PRIVATE(ah)->ah_eeversion >= AR_EEPROM_VER5_3)) && + (!IS_CHAN_B(chan))) + ar5212SetSpurMitigation(ah, ichan); + ar5212SetDeltaSlope(ah, chan); + } + + /* Setup board specific options for EEPROM version 3 */ + if (!ar5212SetBoardValues(ah, ichan)) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: error setting board options\n", __func__); + FAIL(HAL_EIO); + } + + /* Restore certain DMA hardware registers on a channel change */ + if (bChannelChange) + OS_REG_WRITE(ah, AR_D_SEQNUM, saveFrameSeqCount); + + OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__); + + OS_REG_WRITE(ah, AR_STA_ID0, LE_READ_4(ahp->ah_macaddr)); + OS_REG_WRITE(ah, AR_STA_ID1, LE_READ_2(ahp->ah_macaddr + 4) + | macStaId1 + | AR_STA_ID1_RTS_USE_DEF + | ahp->ah_staId1Defaults + ); + ar5212SetOperatingMode(ah, opmode); + + /* Set Venice BSSID mask according to current state */ + OS_REG_WRITE(ah, AR_BSSMSKL, LE_READ_4(ahp->ah_bssidmask)); + OS_REG_WRITE(ah, AR_BSSMSKU, LE_READ_2(ahp->ah_bssidmask + 4)); + + /* Restore previous led state */ + if (!IS_5315(ah)) + OS_REG_WRITE(ah, AR5312_PCICFG, OS_REG_READ(ah, AR_PCICFG) | saveLedState); + + /* Restore previous antenna */ + OS_REG_WRITE(ah, AR_DEF_ANTENNA, saveDefAntenna); + + /* then our BSSID */ + OS_REG_WRITE(ah, AR_BSS_ID0, LE_READ_4(ahp->ah_bssid)); + OS_REG_WRITE(ah, AR_BSS_ID1, LE_READ_2(ahp->ah_bssid + 4)); + + /* Restore bmiss rssi & count thresholds */ + OS_REG_WRITE(ah, AR_RSSI_THR, ahp->ah_rssiThr); + + OS_REG_WRITE(ah, AR_ISR, ~0); /* cleared on write */ + + if (!ar5212SetChannel(ah, ichan)) + FAIL(HAL_EIO); + + OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__); + + ar5212SetCoverageClass(ah, AH_PRIVATE(ah)->ah_coverageClass, 1); + + ar5212SetRateDurationTable(ah, chan); + + /* Set Tx frame start to tx data start delay */ + if (IS_RAD5112_ANY(ah) && + (IS_CHAN_HALF_RATE(AH_PRIVATE(ah)->ah_curchan) || + IS_CHAN_QUARTER_RATE(AH_PRIVATE(ah)->ah_curchan))) { + txFrm2TxDStart = + (IS_CHAN_HALF_RATE(AH_PRIVATE(ah)->ah_curchan)) ? + TX_FRAME_D_START_HALF_RATE: + TX_FRAME_D_START_QUARTER_RATE; + OS_REG_RMW_FIELD(ah, AR_PHY_TX_CTL, + AR_PHY_TX_FRAME_TO_TX_DATA_START, txFrm2TxDStart); + } + + /* + * Setup fast diversity. + * Fast diversity can be enabled or disabled via regadd.txt. + * Default is enabled. + * For reference, + * Disable: reg val + * 0x00009860 0x00009d18 (if 11a / 11g, else no change) + * 0x00009970 0x192bb514 + * 0x0000a208 0xd03e4648 + * + * Enable: 0x00009860 0x00009d10 (if 11a / 11g, else no change) + * 0x00009970 0x192fb514 + * 0x0000a208 0xd03e6788 + */ + + /* XXX Setup pre PHY ENABLE EAR additions */ + + /* flush SCAL reg */ + if (IS_5312_2_X(ah)) { + (void) OS_REG_READ(ah, AR_PHY_SLEEP_SCAL); + } + + /* + * Wait for the frequency synth to settle (synth goes on + * via AR_PHY_ACTIVE_EN). Read the phy active delay register. + * Value is in 100ns increments. + */ + synthDelay = OS_REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY; + if (IS_CHAN_CCK(chan)) { + synthDelay = (4 * synthDelay) / 22; + } else { + synthDelay /= 10; + } + + /* Activate the PHY (includes baseband activate and synthesizer on) */ + OS_REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); + + /* + * There is an issue if the AP starts the calibration before + * the base band timeout completes. This could result in the + * rx_clear false triggering. As a workaround we add delay an + * extra BASE_ACTIVATE_DELAY usecs to ensure this condition + * does not happen. + */ + if (IS_CHAN_HALF_RATE(AH_PRIVATE(ah)->ah_curchan)) { + OS_DELAY((synthDelay << 1) + BASE_ACTIVATE_DELAY); + } else if (IS_CHAN_QUARTER_RATE(AH_PRIVATE(ah)->ah_curchan)) { + OS_DELAY((synthDelay << 2) + BASE_ACTIVATE_DELAY); + } else { + OS_DELAY(synthDelay + BASE_ACTIVATE_DELAY); + } + + /* + * The udelay method is not reliable with notebooks. + * Need to check to see if the baseband is ready + */ + testReg = OS_REG_READ(ah, AR_PHY_TESTCTRL); + /* Selects the Tx hold */ + OS_REG_WRITE(ah, AR_PHY_TESTCTRL, AR_PHY_TESTCTRL_TXHOLD); + i = 0; + while ((i++ < 20) && + (OS_REG_READ(ah, 0x9c24) & 0x10)) /* test if baseband not ready */ OS_DELAY(200); + OS_REG_WRITE(ah, AR_PHY_TESTCTRL, testReg); + + /* Calibrate the AGC and start a NF calculation */ + OS_REG_WRITE(ah, AR_PHY_AGC_CONTROL, + OS_REG_READ(ah, AR_PHY_AGC_CONTROL) + | AR_PHY_AGC_CONTROL_CAL + | AR_PHY_AGC_CONTROL_NF); + + if (!IS_CHAN_B(chan) && ahp->ah_bIQCalibration != IQ_CAL_DONE) { + /* Start IQ calibration w/ 2^(INIT_IQCAL_LOG_COUNT_MAX+1) samples */ + OS_REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4, + AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX, + INIT_IQCAL_LOG_COUNT_MAX); + OS_REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4, + AR_PHY_TIMING_CTRL4_DO_IQCAL); + ahp->ah_bIQCalibration = IQ_CAL_RUNNING; + } else + ahp->ah_bIQCalibration = IQ_CAL_INACTIVE; + + /* Setup compression registers */ + ar5212SetCompRegs(ah); + + /* Set 1:1 QCU to DCU mapping for all queues */ + for (i = 0; i < AR_NUM_DCU; i++) + OS_REG_WRITE(ah, AR_DQCUMASK(i), 1 << i); + + ahp->ah_intrTxqs = 0; + for (i = 0; i < AH_PRIVATE(ah)->ah_caps.halTotalQueues; i++) + ar5212ResetTxQueue(ah, i); + + /* + * Setup interrupt handling. Note that ar5212ResetTxQueue + * manipulates the secondary IMR's as queues are enabled + * and disabled. This is done with RMW ops to insure the + * settings we make here are preserved. + */ + ahp->ah_maskReg = AR_IMR_TXOK | AR_IMR_TXERR | AR_IMR_TXURN + | AR_IMR_RXOK | AR_IMR_RXERR | AR_IMR_RXORN + | AR_IMR_HIUERR + ; + if (opmode == HAL_M_HOSTAP) + ahp->ah_maskReg |= AR_IMR_MIB; + OS_REG_WRITE(ah, AR_IMR, ahp->ah_maskReg); + /* Enable bus errors that are OR'd to set the HIUERR bit */ + OS_REG_WRITE(ah, AR_IMR_S2, + OS_REG_READ(ah, AR_IMR_S2) + | AR_IMR_S2_MCABT | AR_IMR_S2_SSERR | AR_IMR_S2_DPERR); + + if (AH_PRIVATE(ah)->ah_rfkillEnabled) + ar5212EnableRfKill(ah); + + if (!ath_hal_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0)) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: offset calibration failed to complete in 1ms;" + " noisy environment?\n", __func__); + } + + /* + * Set clocks back to 32kHz if they had been using refClk, then + * use an external 32kHz crystal when sleeping, if one exists. + */ + ar5312SetupClock(ah, opmode); + + /* + * Writing to AR_BEACON will start timers. Hence it should + * be the last register to be written. Do not reset tsf, do + * not enable beacons at this point, but preserve other values + * like beaconInterval. + */ + OS_REG_WRITE(ah, AR_BEACON, + (OS_REG_READ(ah, AR_BEACON) &~ (AR_BEACON_EN | AR_BEACON_RESET_TSF))); + + /* XXX Setup post reset EAR additions */ + + /* QoS support */ + if (AH_PRIVATE(ah)->ah_macVersion > AR_SREV_VERSION_VENICE || + (AH_PRIVATE(ah)->ah_macVersion == AR_SREV_VERSION_VENICE && + AH_PRIVATE(ah)->ah_macRev >= AR_SREV_GRIFFIN_LITE)) { + OS_REG_WRITE(ah, AR_QOS_CONTROL, 0x100aa); /* XXX magic */ + OS_REG_WRITE(ah, AR_QOS_SELECT, 0x3210); /* XXX magic */ + } + + /* Turn on NOACK Support for QoS packets */ + OS_REG_WRITE(ah, AR_NOACK, + SM(2, AR_NOACK_2BIT_VALUE) | + SM(5, AR_NOACK_BIT_OFFSET) | + SM(0, AR_NOACK_BYTE_OFFSET)); + + /* Restore user-specified settings */ + if (ahp->ah_miscMode != 0) + OS_REG_WRITE(ah, AR_MISC_MODE, ahp->ah_miscMode); + if (ahp->ah_slottime != (u_int) -1) + ar5212SetSlotTime(ah, ahp->ah_slottime); + if (ahp->ah_acktimeout != (u_int) -1) + ar5212SetAckTimeout(ah, ahp->ah_acktimeout); + if (ahp->ah_ctstimeout != (u_int) -1) + ar5212SetCTSTimeout(ah, ahp->ah_ctstimeout); + if (ahp->ah_sifstime != (u_int) -1) + ar5212SetSifsTime(ah, ahp->ah_sifstime); + if (AH_PRIVATE(ah)->ah_diagreg != 0) + OS_REG_WRITE(ah, AR_DIAG_SW, AH_PRIVATE(ah)->ah_diagreg); + + AH_PRIVATE(ah)->ah_opmode = opmode; /* record operating mode */ + + if (bChannelChange) { + if (!(ichan->privFlags & CHANNEL_DFS)) + ichan->privFlags &= ~CHANNEL_INTERFERENCE; + chan->channelFlags = ichan->channelFlags; + chan->privFlags = ichan->privFlags; + } + + HALDEBUG(ah, HAL_DEBUG_RESET, "%s: done\n", __func__); + + OS_MARK(ah, AH_MARK_RESET_DONE, 0); + + return AH_TRUE; +bad: + OS_MARK(ah, AH_MARK_RESET_DONE, ecode); + if (*status) + *status = ecode; + return AH_FALSE; +#undef FAIL +#undef N +} + +/* + * Places the PHY and Radio chips into reset. A full reset + * must be called to leave this state. The PCI/MAC/PCU are + * not placed into reset as we must receive interrupt to + * re-enable the hardware. + */ +HAL_BOOL +ar5312PhyDisable(struct ath_hal *ah) +{ + return ar5312SetResetReg(ah, AR_RC_BB); +} + +/* + * Places all of hardware into reset + */ +HAL_BOOL +ar5312Disable(struct ath_hal *ah) +{ + if (!ar5312SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE)) + return AH_FALSE; + /* + * Reset the HW - PCI must be reset after the rest of the + * device has been reset. + */ + return ar5312SetResetReg(ah, AR_RC_MAC | AR_RC_BB); +} + +/* + * Places the hardware into reset and then pulls it out of reset + * + * TODO: Only write the PLL if we're changing to or from CCK mode + * + * WARNING: The order of the PLL and mode registers must be correct. + */ +HAL_BOOL +ar5312ChipReset(struct ath_hal *ah, HAL_CHANNEL *chan) +{ + + OS_MARK(ah, AH_MARK_CHIPRESET, chan ? chan->channel : 0); + + /* + * Reset the HW + */ + if (!ar5312SetResetReg(ah, AR_RC_MAC | AR_RC_BB)) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: ar5312SetResetReg failed\n", + __func__); + return AH_FALSE; + } + + /* Bring out of sleep mode (AGAIN) */ + if (!ar5312SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE)) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: ar5312SetPowerMode failed\n", + __func__); + return AH_FALSE; + } + + /* Clear warm reset register */ + if (!ar5312SetResetReg(ah, 0)) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: ar5312SetResetReg failed\n", + __func__); + return AH_FALSE; + } + + /* + * Perform warm reset before the mode/PLL/turbo registers + * are changed in order to deactivate the radio. Mode changes + * with an active radio can result in corrupted shifts to the + * radio device. + */ + + /* + * Set CCK and Turbo modes correctly. + */ + if (chan != AH_NULL) { /* NB: can be null during attach */ + uint32_t rfMode, phyPLL = 0, curPhyPLL, turbo; + + if (IS_RAD5112_ANY(ah)) { + rfMode = AR_PHY_MODE_AR5112; + if (!IS_5315(ah)) { + if (IS_CHAN_CCK(chan) || IS_CHAN_G(chan)) { + phyPLL = AR_PHY_PLL_CTL_44_5312; + } else { + if (IS_CHAN_HALF_RATE(chan)) { + phyPLL = AR_PHY_PLL_CTL_40_5312_HALF; + } else if (IS_CHAN_QUARTER_RATE(chan)) { + phyPLL = AR_PHY_PLL_CTL_40_5312_QUARTER; + } else { + phyPLL = AR_PHY_PLL_CTL_40_5312; + } + } + } else { + if (IS_CHAN_CCK(chan) || IS_CHAN_G(chan)) + phyPLL = AR_PHY_PLL_CTL_44_5112; + else + phyPLL = AR_PHY_PLL_CTL_40_5112; + if (IS_CHAN_HALF_RATE(chan)) + phyPLL |= AR_PHY_PLL_CTL_HALF; + else if (IS_CHAN_QUARTER_RATE(chan)) + phyPLL |= AR_PHY_PLL_CTL_QUARTER; + } + } else { + rfMode = AR_PHY_MODE_AR5111; + if (IS_CHAN_CCK(chan) || IS_CHAN_G(chan)) + phyPLL = AR_PHY_PLL_CTL_44; + else + phyPLL = AR_PHY_PLL_CTL_40; + if (IS_CHAN_HALF_RATE(chan)) + phyPLL = AR_PHY_PLL_CTL_HALF; + else if (IS_CHAN_QUARTER_RATE(chan)) + phyPLL = AR_PHY_PLL_CTL_QUARTER; + } + if (IS_CHAN_OFDM(chan) && (IS_CHAN_CCK(chan) || + IS_CHAN_G(chan))) + rfMode |= AR_PHY_MODE_DYNAMIC; + else if (IS_CHAN_OFDM(chan)) + rfMode |= AR_PHY_MODE_OFDM; + else + rfMode |= AR_PHY_MODE_CCK; + if (IS_CHAN_5GHZ(chan)) + rfMode |= AR_PHY_MODE_RF5GHZ; + else + rfMode |= AR_PHY_MODE_RF2GHZ; + turbo = IS_CHAN_TURBO(chan) ? + (AR_PHY_FC_TURBO_MODE | AR_PHY_FC_TURBO_SHORT) : 0; + curPhyPLL = OS_REG_READ(ah, AR_PHY_PLL_CTL); + /* + * PLL, Mode, and Turbo values must be written in the correct + * order to ensure: + * - The PLL cannot be set to 44 unless the CCK or DYNAMIC + * mode bit is set + * - Turbo cannot be set at the same time as CCK or DYNAMIC + */ + if (IS_CHAN_CCK(chan) || IS_CHAN_G(chan)) { + OS_REG_WRITE(ah, AR_PHY_TURBO, turbo); + OS_REG_WRITE(ah, AR_PHY_MODE, rfMode); + if (curPhyPLL != phyPLL) { + OS_REG_WRITE(ah, AR_PHY_PLL_CTL, phyPLL); + /* Wait for the PLL to settle */ + OS_DELAY(PLL_SETTLE_DELAY); + } + } else { + if (curPhyPLL != phyPLL) { + OS_REG_WRITE(ah, AR_PHY_PLL_CTL, phyPLL); + /* Wait for the PLL to settle */ + OS_DELAY(PLL_SETTLE_DELAY); + } + OS_REG_WRITE(ah, AR_PHY_TURBO, turbo); + OS_REG_WRITE(ah, AR_PHY_MODE, rfMode); + } + } + return AH_TRUE; +} + +/* + * Write the given reset bit mask into the reset register + */ +static HAL_BOOL +ar5312SetResetReg(struct ath_hal *ah, uint32_t resetMask) +{ + uint32_t mask = resetMask ? resetMask : ~0; + HAL_BOOL rt; + + if ((rt = ar5312MacReset(ah, mask)) == AH_FALSE) { + return rt; + } + if ((resetMask & AR_RC_MAC) == 0) { + if (isBigEndian()) { + /* + * Set CFG, little-endian for register + * and descriptor accesses. + */ +#ifdef AH_NEED_DESC_SWAP + mask = INIT_CONFIG_STATUS | AR_CFG_SWRD; +#else + mask = INIT_CONFIG_STATUS | + AR_CFG_SWTD | AR_CFG_SWRD; +#endif + OS_REG_WRITE(ah, AR_CFG, mask); + } else + OS_REG_WRITE(ah, AR_CFG, INIT_CONFIG_STATUS); + } + return rt; +} + +/* + * ar5312MacReset resets (and then un-resets) the specified + * wireless components. + * Note: The RCMask cannot be zero on entering from ar5312SetResetReg. + */ + +HAL_BOOL +ar5312MacReset(struct ath_hal *ah, unsigned int RCMask) +{ + int wlanNum = AR5312_UNIT(ah); + uint32_t resetBB, resetBits, regMask; + uint32_t reg; + + if (RCMask == 0) + return(AH_FALSE); +#if ( AH_SUPPORT_2316 || AH_SUPPORT_2317 ) + if (IS_5315(ah)) { + switch(wlanNum) { + case 0: + resetBB = AR5315_RC_BB0_CRES | AR5315_RC_WBB0_RES; + /* Warm and cold reset bits for wbb */ + resetBits = AR5315_RC_WMAC0_RES; + break; + case 1: + resetBB = AR5315_RC_BB1_CRES | AR5315_RC_WBB1_RES; + /* Warm and cold reset bits for wbb */ + resetBits = AR5315_RC_WMAC1_RES; + break; + default: + return(AH_FALSE); + } + regMask = ~(resetBB | resetBits); + + /* read before */ + reg = OS_REG_READ(ah, + (AR5315_RSTIMER_BASE - ((uint32_t) ah->ah_sh) + AR5315_RESET)); + + if (RCMask == AR_RC_BB) { + /* Put baseband in reset */ + reg |= resetBB; /* Cold and warm reset the baseband bits */ + } else { + /* + * Reset the MAC and baseband. This is a bit different than + * the PCI version, but holding in reset causes problems. + */ + reg &= regMask; + reg |= (resetBits | resetBB) ; + } + OS_REG_WRITE(ah, + (AR5315_RSTIMER_BASE - ((uint32_t) ah->ah_sh)+AR5315_RESET), + reg); + /* read after */ + OS_REG_READ(ah, + (AR5315_RSTIMER_BASE - ((uint32_t) ah->ah_sh) +AR5315_RESET)); + OS_DELAY(100); + + /* Bring MAC and baseband out of reset */ + reg &= regMask; + /* read before */ + OS_REG_READ(ah, + (AR5315_RSTIMER_BASE- ((uint32_t) ah->ah_sh) +AR5315_RESET)); + OS_REG_WRITE(ah, + (AR5315_RSTIMER_BASE - ((uint32_t) ah->ah_sh)+AR5315_RESET), + reg); + /* read after */ + OS_REG_READ(ah, + (AR5315_RSTIMER_BASE- ((uint32_t) ah->ah_sh) +AR5315_RESET)); + + + } + else +#endif + { + + switch(wlanNum) { + case 0: + resetBB = AR5312_RC_BB0_CRES | AR5312_RC_WBB0_RES; + /* Warm and cold reset bits for wbb */ + resetBits = AR5312_RC_WMAC0_RES; + break; + case 1: + resetBB = AR5312_RC_BB1_CRES | AR5312_RC_WBB1_RES; + /* Warm and cold reset bits for wbb */ + resetBits = AR5312_RC_WMAC1_RES; + break; + default: + return(AH_FALSE); + } + regMask = ~(resetBB | resetBits); + + /* read before */ + reg = OS_REG_READ(ah, + (AR5312_RSTIMER_BASE - ((uint32_t) ah->ah_sh) + AR5312_RESET)); + + if (RCMask == AR_RC_BB) { + /* Put baseband in reset */ + reg |= resetBB; /* Cold and warm reset the baseband bits */ + } else { + /* + * Reset the MAC and baseband. This is a bit different than + * the PCI version, but holding in reset causes problems. + */ + reg &= regMask; + reg |= (resetBits | resetBB) ; + } + OS_REG_WRITE(ah, + (AR5312_RSTIMER_BASE - ((uint32_t) ah->ah_sh)+AR5312_RESET), + reg); + /* read after */ + OS_REG_READ(ah, + (AR5312_RSTIMER_BASE - ((uint32_t) ah->ah_sh) +AR5312_RESET)); + OS_DELAY(100); + + /* Bring MAC and baseband out of reset */ + reg &= regMask; + /* read before */ + OS_REG_READ(ah, + (AR5312_RSTIMER_BASE- ((uint32_t) ah->ah_sh) +AR5312_RESET)); + OS_REG_WRITE(ah, + (AR5312_RSTIMER_BASE - ((uint32_t) ah->ah_sh)+AR5312_RESET), + reg); + /* read after */ + OS_REG_READ(ah, + (AR5312_RSTIMER_BASE- ((uint32_t) ah->ah_sh) +AR5312_RESET)); + } + return(AH_TRUE); +} + +#endif /* AH_SUPPORT_AR5312 */ --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5312/ar5312phy.h 2009-03-23 17:36:56.000000000 +0000 @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2008 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ar5312phy.h,v 1.1 2009/03/23 17:14:48 sborrill Exp $ + */ +#ifndef _DEV_ATH_AR5312PHY_H_ +#define _DEV_ATH_AR5312PHY_H_ + +#include "ar5212/ar5212phy.h" + +/* PHY registers */ + +#define AR_PHY_PLL_CTL_44_5312 0x14d6 /* 44 MHz for 11b, 11g */ +#define AR_PHY_PLL_CTL_40_5312 0x14d4 /* 40 MHz for 11a, turbos */ +#define AR_PHY_PLL_CTL_40_5312_HALF 0x15d4 /* 40 MHz for 11a, turbos (Half)*/ +#define AR_PHY_PLL_CTL_40_5312_QUARTER 0x16d4 /* 40 MHz for 11a, turbos (Quarter)*/ + +#endif /* _DEV_ATH_AR5312PHY_H_ */ --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5312/ar5312reg.h 2009-03-23 17:36:56.000000000 +0000 @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2008 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ar5312reg.h,v 1.1 2009/03/23 17:14:48 sborrill Exp $ + */ +#ifndef _DEV_ATH_AR5312REG_H_ +#define _DEV_ATH_AR5312REG_H_ + +#include "ar5212/ar5212reg.h" +/* + * Definitions for the Atheros 5312 chipset. + */ + +/* Register base addresses for modules which are not wmac modules */ +/* 531X has a fixed memory map */ + + +#define REG_WRITE(_reg,_val) *((volatile uint32_t *)(_reg)) = (_val); +#define REG_READ(_reg) *((volatile uint32_t *)(_reg)) +/* + * PCI-MAC Configuration registers (AR2315+) + */ +#define AR5315_RSTIMER_BASE 0xb1000000 /* Address for reset/timer registers */ +#define AR5315_GPIO_BASE 0xb1000000 /* Address for GPIO registers */ +#define AR5315_WLAN0 0xb0000000 + +#define AR5315_RESET 0x0004 /* Offset of reset control register */ +#define AR5315_SREV 0x0014 /* Offset of reset control register */ +#define AR5315_ENDIAN_CTL 0x000c /* offset of the endian control register */ +#define AR5315_CONFIG_WLAN 0x00000002 /* WLAN byteswap */ + +#define AR5315_REV_MAJ 0x00f0 +#define AR5315_REV_MIN 0x000f + +#define AR5315_GPIODIR 0x0098 /* GPIO direction register */ +#define AR5315_GPIODO 0x0090 /* GPIO data output access reg */ +#define AR5315_GPIODI 0x0088 /* GPIO data input access reg*/ +#define AR5315_GPIOINT 0x00a0 /* GPIO interrupt control */ + +#define AR5315_GPIODIR_M(x) (1 << (x)) /* mask for i/o */ +#define AR5315_GPIODIR_O(x) (1 << (x)) /* output */ +#define AR5315_GPIODIR_I(x) 0 /* input */ + +#define AR5315_GPIOINT_S 0 +#define AR5315_GPIOINT_M 0x3F +#define AR5315_GPIOINTLVL_S 6 +#define AR5315_GPIOINTLVL_M (3 << AR5315_GPIOINTLVL_S) + +#define AR5315_WREV (-0xefbfe0) /* Revision ID register offset */ +#define AR5315_WREV_S 0 /* Shift for WMAC revision info */ +#define AR5315_WREV_ID 0x000000FF /* Mask for WMAC revision info */ +#define AR5315_WREV_ID_S 4 /* Shift for WMAC Rev ID */ +#define AR5315_WREV_REVISION 0x0000000F /* Mask for WMAN Revsion version */ + +#define AR5315_RC_BB0_CRES 0x00000002 /* Cold reset to WMAC0 & WBB0 */ +#define AR5315_RC_BB1_CRES 0x00000200 /* Cold reset to WMAC1 & WBB1n */ +#define AR5315_RC_WMAC0_RES 0x00000001 /* Warm reset to WMAC 0 */ +#define AR5315_RC_WBB0_RES 0x00000002 /* Warm reset to WBB0 */ +#define AR5315_RC_WMAC1_RES 0x00020000 /* Warm reset to WMAC1 */ +#define AR5315_RC_WBB1_RES 0x00040000 /* Warm reset to WBB */ + +/* + * PCI-MAC Configuration registers (AR5312) + */ +#define AR5312_RSTIMER_BASE 0xbc003000 /* Address for reset/timer registers */ +#define AR5312_GPIO_BASE 0xbc002000 /* Address for GPIO registers */ +#define AR5312_WLAN0 0xb8000000 +#define AR5312_WLAN1 0xb8500000 + +#define AR5312_RESET 0x0020 /* Offset of reset control register */ +#define AR5312_PCICFG 0x00B0 /* MAC/PCI configuration reg (LEDs) */ + +#define AR5312_PCICFG_LEDMODE 0x0000001c /* LED Mode mask */ +#define AR5312_PCICFG_LEDMODE_S 2 /* LED Mode shift */ +#define AR5312_PCICFG_LEDMOD0 0 /* Blnk prop to Tx and filtered Rx */ +#define AR5312_PCICFG_LEDMOD1 1 /* Blnk prop to all Tx and Rx */ +#define AR5312_PCICFG_LEDMOD2 2 /* DEBG flash */ +#define AR5312_PCICFG_LEDMOD3 3 /* BLNK Randomly */ + +#define AR5312_PCICFG_LEDSEL 0x000000e0 /* LED Throughput select */ +#define AR5312_PCICFG_LEDSEL_S 5 +#define AR5312_PCICFG_LEDSEL0 0 /* See blink rate table on p. 143 */ +#define AR5312_PCICFG_LEDSEL1 1 /* of AR5212 data sheet */ +#define AR5312_PCICFG_LEDSEL2 2 +#define AR5312_PCICFG_LEDSEL3 3 +#define AR5312_PCICFG_LEDSEL4 4 +#define AR5312_PCICFG_LEDSEL5 5 +#define AR5312_PCICFG_LEDSEL6 6 +#define AR5312_PCICFG_LEDSEL7 7 + +#define AR5312_PCICFG_LEDSBR 0x00000100 /* Slow blink rate if no + activity. 0 = blink @ lowest + rate */ + +#undef AR_GPIOCR +#undef AR_GPIODO /* Undefine the 5212 defs */ +#undef AR_GPIODI + +#define AR5312_GPIOCR 0x0008 /* GPIO Control register */ +#define AR5312_GPIODO 0x0000 /* GPIO data output access reg */ +#define AR5312_GPIODI 0x0004 /* GPIO data input access reg*/ +/* NB: AR5312 uses AR5212 defines for GPIOCR definitions */ + +#define AR5312_WREV 0x0090 /* Revision ID register offset */ +#define AR5312_WREV_S 8 /* Shift for WMAC revision info */ +#define AR5312_WREV_ID 0x000000FF /* Mask for WMAC revision info */ +#define AR5312_WREV_ID_S 4 /* Shift for WMAC Rev ID */ +#define AR5312_WREV_REVISION 0x0000000F /* Mask for WMAN Revsion version */ + +#define AR5312_RC_BB0_CRES 0x00000004 /* Cold reset to WMAC0 & WBB0 */ +#define AR5312_RC_BB1_CRES 0x00000200 /* Cold reset to WMAC1 & WBB1n */ +#define AR5312_RC_WMAC0_RES 0x00002000 /* Warm reset to WMAC 0 */ +#define AR5312_RC_WBB0_RES 0x00004000 /* Warm reset to WBB0 */ +#define AR5312_RC_WMAC1_RES 0x00020000 /* Warm reset to WMAC1 */ +#define AR5312_RC_WBB1_RES 0x00040000 /* Warm reset to WBB */ + + +#define AR_RAD2112_SREV_MAJOR 0x40 /* 2112 Major Rev */ + +enum AR5312PowerMode { + AR5312_POWER_MODE_FORCE_SLEEP = 0, + AR5312_POWER_MODE_FORCE_WAKE = 1, + AR5312_POWER_MODE_NORMAL = 2, +}; + +#endif /* _DEV_AR5312REG_H_ */ --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5312/ar5315_gpio.c 2009-03-23 17:36:56.000000000 +0000 @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2008 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ar5315_gpio.c,v 1.1 2009/03/23 17:14:48 sborrill Exp $ + */ +#include "opt_ah.h" + +#if (AH_SUPPORT_2316 || AH_SUPPORT_2317) + +#include "ah.h" +#include "ah_internal.h" +#include "ah_devid.h" + +#include "ar5312/ar5312.h" +#include "ar5312/ar5312reg.h" +#include "ar5312/ar5312phy.h" + +#define AR_NUM_GPIO 7 /* 6 GPIO pins */ +#define AR5315_GPIOD_MASK 0x0000007F /* GPIO data reg r/w mask */ + +/* + * Configure GPIO Output lines + */ +HAL_BOOL +ar5315GpioCfgOutput(struct ath_hal *ah, uint32_t gpio) +{ + uint32_t gpioOffset = (AR5315_GPIO_BASE - ((uint32_t) ah->ah_sh)); + + HALASSERT(gpio < AR_NUM_GPIO); + + OS_REG_WRITE(ah, gpioOffset+AR5315_GPIODIR, + (OS_REG_READ(ah, gpioOffset+AR5315_GPIODIR) &~ AR5315_GPIODIR_M(gpio)) + | AR5315_GPIODIR_O(gpio)); + + return AH_TRUE; +} + +/* + * Configure GPIO Input lines + */ +HAL_BOOL +ar5315GpioCfgInput(struct ath_hal *ah, uint32_t gpio) +{ + uint32_t gpioOffset = (AR5315_GPIO_BASE - ((uint32_t) ah->ah_sh)); + + HALASSERT(gpio < AR_NUM_GPIO); + + OS_REG_WRITE(ah, gpioOffset+AR5315_GPIODIR, + (OS_REG_READ(ah, gpioOffset+AR5315_GPIODIR) &~ AR5315_GPIODIR_M(gpio)) + | AR5315_GPIODIR_I(gpio)); + + return AH_TRUE; +} + +/* + * Once configured for I/O - set output lines + */ +HAL_BOOL +ar5315GpioSet(struct ath_hal *ah, uint32_t gpio, uint32_t val) +{ + uint32_t reg; + uint32_t gpioOffset = (AR5315_GPIO_BASE - ((uint32_t) ah->ah_sh)); + + HALASSERT(gpio < AR_NUM_GPIO); + + reg = OS_REG_READ(ah, gpioOffset+AR5315_GPIODO); + reg &= ~(1 << gpio); + reg |= (val&1) << gpio; + + OS_REG_WRITE(ah, gpioOffset+AR5315_GPIODO, reg); + return AH_TRUE; +} + +/* + * Once configured for I/O - get input lines + */ +uint32_t +ar5315GpioGet(struct ath_hal *ah, uint32_t gpio) +{ + uint32_t gpioOffset = (AR5315_GPIO_BASE - ((uint32_t) ah->ah_sh)); + + if (gpio < AR_NUM_GPIO) { + uint32_t val = OS_REG_READ(ah, gpioOffset+AR5315_GPIODI); + val = ((val & AR5315_GPIOD_MASK) >> gpio) & 0x1; + return val; + } else { + return 0xffffffff; + } +} + +/* + * Set the GPIO Interrupt + */ +void +ar5315GpioSetIntr(struct ath_hal *ah, u_int gpio, uint32_t ilevel) +{ + uint32_t val; + uint32_t gpioOffset = (AR5315_GPIO_BASE - ((uint32_t) ah->ah_sh)); + + /* XXX bounds check gpio */ + val = OS_REG_READ(ah, gpioOffset+AR5315_GPIOINT); + val &= ~(AR5315_GPIOINT_M | AR5315_GPIOINTLVL_M); + val |= gpio << AR5315_GPIOINT_S; + if (ilevel) + val |= 2 << AR5315_GPIOINTLVL_S; /* interrupt on pin high */ + else + val |= 1 << AR5315_GPIOINTLVL_S; /* interrupt on pin low */ + + /* Don't need to change anything for low level interrupt. */ + OS_REG_WRITE(ah, gpioOffset+AR5315_GPIOINT, val); + + /* Change the interrupt mask. */ + (void) ar5212SetInterrupts(ah, AH5212(ah)->ah_maskReg | HAL_INT_GPIO); +} + + +#endif /* AH_SUPPORT_2316 || AH_SUPPORT_2317 */ --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5212/ar2316.c 2009-03-23 17:36:55.000000000 +0000 @@ -0,0 +1,767 @@ +/* + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2008 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ar2316.c,v 1.1 2009/03/23 17:14:47 sborrill Exp $ + */ +#include "opt_ah.h" + +#include "ah.h" +#include "ah_internal.h" + +#include "ar5212/ar5212.h" +#include "ar5212/ar5212reg.h" +#include "ar5212/ar5212phy.h" + +#include "ah_eeprom_v3.h" + +#define AH_5212_2316 +#include "ar5212/ar5212.ini" + +#define N(a) (sizeof(a)/sizeof(a[0])) + +typedef RAW_DATA_STRUCT_2413 RAW_DATA_STRUCT_2316; +typedef RAW_DATA_PER_CHANNEL_2413 RAW_DATA_PER_CHANNEL_2316; +#define PWR_TABLE_SIZE_2316 PWR_TABLE_SIZE_2413 + +struct ar2316State { + RF_HAL_FUNCS base; /* public state, must be first */ + uint16_t pcdacTable[PWR_TABLE_SIZE_2316]; + + uint32_t Bank1Data[N(ar5212Bank1_2316)]; + uint32_t Bank2Data[N(ar5212Bank2_2316)]; + uint32_t Bank3Data[N(ar5212Bank3_2316)]; + uint32_t Bank6Data[N(ar5212Bank6_2316)]; + uint32_t Bank7Data[N(ar5212Bank7_2316)]; + + /* + * Private state for reduced stack usage. + */ + /* filled out Vpd table for all pdGains (chanL) */ + uint16_t vpdTable_L[MAX_NUM_PDGAINS_PER_CHANNEL] + [MAX_PWR_RANGE_IN_HALF_DB]; + /* filled out Vpd table for all pdGains (chanR) */ + uint16_t vpdTable_R[MAX_NUM_PDGAINS_PER_CHANNEL] + [MAX_PWR_RANGE_IN_HALF_DB]; + /* filled out Vpd table for all pdGains (interpolated) */ + uint16_t vpdTable_I[MAX_NUM_PDGAINS_PER_CHANNEL] + [MAX_PWR_RANGE_IN_HALF_DB]; +}; +#define AR2316(ah) ((struct ar2316State *) AH5212(ah)->ah_rfHal) + +extern void ar5212ModifyRfBuffer(uint32_t *rfBuf, uint32_t reg32, + uint32_t numBits, uint32_t firstBit, uint32_t column); + +static void +ar2316WriteRegs(struct ath_hal *ah, u_int modesIndex, u_int freqIndex, + int regWrites) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + + HAL_INI_WRITE_ARRAY(ah, ar5212Modes_2316, modesIndex, regWrites); + HAL_INI_WRITE_ARRAY(ah, ar5212Common_2316, 1, regWrites); + HAL_INI_WRITE_ARRAY(ah, ar5212BB_RfGain_2316, freqIndex, regWrites); + + /* For AP51 */ + if (!ahp->ah_cwCalRequire) { + OS_REG_WRITE(ah, 0xa358, (OS_REG_READ(ah, 0xa358) & ~0x2)); + } else { + ahp->ah_cwCalRequire = AH_FALSE; + } +} + +/* + * Take the MHz channel value and set the Channel value + * + * ASSUMES: Writes enabled to analog bus + */ +static HAL_BOOL +ar2316SetChannel(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan) +{ + uint32_t channelSel = 0; + uint32_t bModeSynth = 0; + uint32_t aModeRefSel = 0; + uint32_t reg32 = 0; + + OS_MARK(ah, AH_MARK_SETCHANNEL, chan->channel); + + if (chan->channel < 4800) { + uint32_t txctl; + + if (((chan->channel - 2192) % 5) == 0) { + channelSel = ((chan->channel - 672) * 2 - 3040)/10; + bModeSynth = 0; + } else if (((chan->channel - 2224) % 5) == 0) { + channelSel = ((chan->channel - 704) * 2 - 3040) / 10; + bModeSynth = 1; + } else { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: invalid channel %u MHz\n", + __func__, chan->channel); + return AH_FALSE; + } + + channelSel = (channelSel << 2) & 0xff; + channelSel = ath_hal_reverseBits(channelSel, 8); + + txctl = OS_REG_READ(ah, AR_PHY_CCK_TX_CTRL); + if (chan->channel == 2484) { + /* Enable channel spreading for channel 14 */ + OS_REG_WRITE(ah, AR_PHY_CCK_TX_CTRL, + txctl | AR_PHY_CCK_TX_CTRL_JAPAN); + } else { + OS_REG_WRITE(ah, AR_PHY_CCK_TX_CTRL, + txctl &~ AR_PHY_CCK_TX_CTRL_JAPAN); + } + } else if ((chan->channel % 20) == 0 && chan->channel >= 5120) { + channelSel = ath_hal_reverseBits( + ((chan->channel - 4800) / 20 << 2), 8); + aModeRefSel = ath_hal_reverseBits(3, 2); + } else if ((chan->channel % 10) == 0) { + channelSel = ath_hal_reverseBits( + ((chan->channel - 4800) / 10 << 1), 8); + aModeRefSel = ath_hal_reverseBits(2, 2); + } else if ((chan->channel % 5) == 0) { + channelSel = ath_hal_reverseBits( + (chan->channel - 4800) / 5, 8); + aModeRefSel = ath_hal_reverseBits(1, 2); + } else { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel %u MHz\n", + __func__, chan->channel); + return AH_FALSE; + } + + reg32 = (channelSel << 4) | (aModeRefSel << 2) | (bModeSynth << 1) | + (1 << 12) | 0x1; + OS_REG_WRITE(ah, AR_PHY(0x27), reg32 & 0xff); + + reg32 >>= 8; + OS_REG_WRITE(ah, AR_PHY(0x36), reg32 & 0x7f); + + AH_PRIVATE(ah)->ah_curchan = chan; + return AH_TRUE; +} + +/* + * Reads EEPROM header info from device structure and programs + * all rf registers + * + * REQUIRES: Access to the analog rf device + */ +static HAL_BOOL +ar2316SetRfRegs(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan, uint16_t modesIndex, uint16_t *rfXpdGain) +{ +#define RF_BANK_SETUP(_priv, _ix, _col) do { \ + int i; \ + for (i = 0; i < N(ar5212Bank##_ix##_2316); i++) \ + (_priv)->Bank##_ix##Data[i] = ar5212Bank##_ix##_2316[i][_col];\ +} while (0) + struct ath_hal_5212 *ahp = AH5212(ah); + const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom; + uint16_t ob2GHz = 0, db2GHz = 0; + struct ar2316State *priv = AR2316(ah); + int regWrites = 0; + + HALDEBUG(ah, HAL_DEBUG_RFPARAM, + "%s: chan 0x%x flag 0x%x modesIndex 0x%x\n", + __func__, chan->channel, chan->channelFlags, modesIndex); + + HALASSERT(priv != AH_NULL); + + /* Setup rf parameters */ + switch (chan->channelFlags & CHANNEL_ALL) { + case CHANNEL_B: + ob2GHz = ee->ee_obFor24; + db2GHz = ee->ee_dbFor24; + break; + case CHANNEL_G: + case CHANNEL_108G: + ob2GHz = ee->ee_obFor24g; + db2GHz = ee->ee_dbFor24g; + break; + default: + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel flags 0x%x\n", + __func__, chan->channelFlags); + return AH_FALSE; + } + + /* Bank 1 Write */ + RF_BANK_SETUP(priv, 1, 1); + + /* Bank 2 Write */ + RF_BANK_SETUP(priv, 2, modesIndex); + + /* Bank 3 Write */ + RF_BANK_SETUP(priv, 3, modesIndex); + + /* Bank 6 Write */ + RF_BANK_SETUP(priv, 6, modesIndex); + + ar5212ModifyRfBuffer(priv->Bank6Data, ob2GHz, 3, 178, 0); + ar5212ModifyRfBuffer(priv->Bank6Data, db2GHz, 3, 175, 0); + + /* Bank 7 Setup */ + RF_BANK_SETUP(priv, 7, modesIndex); + + /* Write Analog registers */ + HAL_INI_WRITE_BANK(ah, ar5212Bank1_2316, priv->Bank1Data, regWrites); + HAL_INI_WRITE_BANK(ah, ar5212Bank2_2316, priv->Bank2Data, regWrites); + HAL_INI_WRITE_BANK(ah, ar5212Bank3_2316, priv->Bank3Data, regWrites); + HAL_INI_WRITE_BANK(ah, ar5212Bank6_2316, priv->Bank6Data, regWrites); + HAL_INI_WRITE_BANK(ah, ar5212Bank7_2316, priv->Bank7Data, regWrites); + + /* Now that we have reprogrammed rfgain value, clear the flag. */ + ahp->ah_rfgainState = HAL_RFGAIN_INACTIVE; + + return AH_TRUE; +#undef RF_BANK_SETUP +} + +/* + * Return a reference to the requested RF Bank. + */ +static uint32_t * +ar2316GetRfBank(struct ath_hal *ah, int bank) +{ + struct ar2316State *priv = AR2316(ah); + + HALASSERT(priv != AH_NULL); + switch (bank) { + case 1: return priv->Bank1Data; + case 2: return priv->Bank2Data; + case 3: return priv->Bank3Data; + case 6: return priv->Bank6Data; + case 7: return priv->Bank7Data; + } + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unknown RF Bank %d requested\n", + __func__, bank); + return AH_NULL; +} + +/* + * Return indices surrounding the value in sorted integer lists. + * + * NB: the input list is assumed to be sorted in ascending order + */ +static void +GetLowerUpperIndex(int16_t v, const uint16_t *lp, uint16_t listSize, + uint32_t *vlo, uint32_t *vhi) +{ + int16_t target = v; + const int16_t *ep = lp+listSize; + const int16_t *tp; + + /* + * Check first and last elements for out-of-bounds conditions. + */ + if (target < lp[0]) { + *vlo = *vhi = 0; + return; + } + if (target >= ep[-1]) { + *vlo = *vhi = listSize - 1; + return; + } + + /* look for value being near or between 2 values in list */ + for (tp = lp; tp < ep; tp++) { + /* + * If value is close to the current value of the list + * then target is not between values, it is one of the values + */ + if (*tp == target) { + *vlo = *vhi = tp - (const int16_t *) lp; + return; + } + /* + * Look for value being between current value and next value + * if so return these 2 values + */ + if (target < tp[1]) { + *vlo = tp - (const int16_t *) lp; + *vhi = *vlo + 1; + return; + } + } +} + +/* + * Fill the Vpdlist for indices Pmax-Pmin + */ +static HAL_BOOL +ar2316FillVpdTable(uint32_t pdGainIdx, int16_t Pmin, int16_t Pmax, + const int16_t *pwrList, const int16_t *VpdList, + uint16_t numIntercepts, uint16_t retVpdList[][64]) +{ + uint16_t ii, jj, kk; + int16_t currPwr = (int16_t)(2*Pmin); + /* since Pmin is pwr*2 and pwrList is 4*pwr */ + uint32_t idxL = 0, idxR = 0; + + ii = 0; + jj = 0; + + if (numIntercepts < 2) + return AH_FALSE; + + while (ii <= (uint16_t)(Pmax - Pmin)) { + GetLowerUpperIndex(currPwr, pwrList, numIntercepts, + &(idxL), &(idxR)); + if (idxR < 1) + idxR = 1; /* extrapolate below */ + if (idxL == (uint32_t)(numIntercepts - 1)) + idxL = numIntercepts - 2; /* extrapolate above */ + if (pwrList[idxL] == pwrList[idxR]) + kk = VpdList[idxL]; + else + kk = (uint16_t) + (((currPwr - pwrList[idxL])*VpdList[idxR]+ + (pwrList[idxR] - currPwr)*VpdList[idxL])/ + (pwrList[idxR] - pwrList[idxL])); + retVpdList[pdGainIdx][ii] = kk; + ii++; + currPwr += 2; /* half dB steps */ + } + + return AH_TRUE; +} + +/* + * Returns interpolated or the scaled up interpolated value + */ +static int16_t +interpolate_signed(uint16_t target, uint16_t srcLeft, uint16_t srcRight, + int16_t targetLeft, int16_t targetRight) +{ + int16_t rv; + + if (srcRight != srcLeft) { + rv = ((target - srcLeft)*targetRight + + (srcRight - target)*targetLeft) / (srcRight - srcLeft); + } else { + rv = targetLeft; + } + return rv; +} + +/* + * Uses the data points read from EEPROM to reconstruct the pdadc power table + * Called by ar2316SetPowerTable() + */ +static int +ar2316getGainBoundariesAndPdadcsForPowers(struct ath_hal *ah, uint16_t channel, + const RAW_DATA_STRUCT_2316 *pRawDataset, + uint16_t pdGainOverlap_t2, + int16_t *pMinCalPower, uint16_t pPdGainBoundaries[], + uint16_t pPdGainValues[], uint16_t pPDADCValues[]) +{ + struct ar2316State *priv = AR2316(ah); +#define VpdTable_L priv->vpdTable_L +#define VpdTable_R priv->vpdTable_R +#define VpdTable_I priv->vpdTable_I + uint32_t ii, jj, kk; + int32_t ss;/* potentially -ve index for taking care of pdGainOverlap */ + uint32_t idxL = 0, idxR = 0; + uint32_t numPdGainsUsed = 0; + /* + * If desired to support -ve power levels in future, just + * change pwr_I_0 to signed 5-bits. + */ + int16_t Pmin_t2[MAX_NUM_PDGAINS_PER_CHANNEL]; + /* to accomodate -ve power levels later on. */ + int16_t Pmax_t2[MAX_NUM_PDGAINS_PER_CHANNEL]; + /* to accomodate -ve power levels later on */ + uint16_t numVpd = 0; + uint16_t Vpd_step; + int16_t tmpVal ; + uint32_t sizeCurrVpdTable, maxIndex, tgtIndex; + + /* Get upper lower index */ + GetLowerUpperIndex(channel, pRawDataset->pChannels, + pRawDataset->numChannels, &(idxL), &(idxR)); + + for (ii = 0; ii < MAX_NUM_PDGAINS_PER_CHANNEL; ii++) { + jj = MAX_NUM_PDGAINS_PER_CHANNEL - ii - 1; + /* work backwards 'cause highest pdGain for lowest power */ + numVpd = pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].numVpd; + if (numVpd > 0) { + pPdGainValues[numPdGainsUsed] = pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].pd_gain; + Pmin_t2[numPdGainsUsed] = pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].pwr_t4[0]; + if (Pmin_t2[numPdGainsUsed] >pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].pwr_t4[0]) { + Pmin_t2[numPdGainsUsed] = pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].pwr_t4[0]; + } + Pmin_t2[numPdGainsUsed] = (int16_t) + (Pmin_t2[numPdGainsUsed] / 2); + Pmax_t2[numPdGainsUsed] = pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].pwr_t4[numVpd-1]; + if (Pmax_t2[numPdGainsUsed] > pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].pwr_t4[numVpd-1]) + Pmax_t2[numPdGainsUsed] = + pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].pwr_t4[numVpd-1]; + Pmax_t2[numPdGainsUsed] = (int16_t)(Pmax_t2[numPdGainsUsed] / 2); + ar2316FillVpdTable( + numPdGainsUsed, Pmin_t2[numPdGainsUsed], Pmax_t2[numPdGainsUsed], + &(pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].pwr_t4[0]), + &(pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].Vpd[0]), numVpd, VpdTable_L + ); + ar2316FillVpdTable( + numPdGainsUsed, Pmin_t2[numPdGainsUsed], Pmax_t2[numPdGainsUsed], + &(pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].pwr_t4[0]), + &(pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].Vpd[0]), numVpd, VpdTable_R + ); + for (kk = 0; kk < (uint16_t)(Pmax_t2[numPdGainsUsed] - Pmin_t2[numPdGainsUsed]); kk++) { + VpdTable_I[numPdGainsUsed][kk] = + interpolate_signed( + channel, pRawDataset->pChannels[idxL], pRawDataset->pChannels[idxR], + (int16_t)VpdTable_L[numPdGainsUsed][kk], (int16_t)VpdTable_R[numPdGainsUsed][kk]); + } + /* fill VpdTable_I for this pdGain */ + numPdGainsUsed++; + } + /* if this pdGain is used */ + } + + *pMinCalPower = Pmin_t2[0]; + kk = 0; /* index for the final table */ + for (ii = 0; ii < numPdGainsUsed; ii++) { + if (ii == (numPdGainsUsed - 1)) + pPdGainBoundaries[ii] = Pmax_t2[ii] + + PD_GAIN_BOUNDARY_STRETCH_IN_HALF_DB; + else + pPdGainBoundaries[ii] = (uint16_t) + ((Pmax_t2[ii] + Pmin_t2[ii+1]) / 2 ); + if (pPdGainBoundaries[ii] > 63) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: clamp pPdGainBoundaries[%d] %d\n", + __func__, ii, pPdGainBoundaries[ii]);/*XXX*/ + pPdGainBoundaries[ii] = 63; + } + + /* Find starting index for this pdGain */ + if (ii == 0) + ss = 0; /* for the first pdGain, start from index 0 */ + else + ss = (pPdGainBoundaries[ii-1] - Pmin_t2[ii]) - + pdGainOverlap_t2; + Vpd_step = (uint16_t)(VpdTable_I[ii][1] - VpdTable_I[ii][0]); + Vpd_step = (uint16_t)((Vpd_step < 1) ? 1 : Vpd_step); + /* + *-ve ss indicates need to extrapolate data below for this pdGain + */ + while (ss < 0) { + tmpVal = (int16_t)(VpdTable_I[ii][0] + ss*Vpd_step); + pPDADCValues[kk++] = (uint16_t)((tmpVal < 0) ? 0 : tmpVal); + ss++; + } + + sizeCurrVpdTable = Pmax_t2[ii] - Pmin_t2[ii]; + tgtIndex = pPdGainBoundaries[ii] + pdGainOverlap_t2 - Pmin_t2[ii]; + maxIndex = (tgtIndex < sizeCurrVpdTable) ? tgtIndex : sizeCurrVpdTable; + + while (ss < (int16_t)maxIndex) + pPDADCValues[kk++] = VpdTable_I[ii][ss++]; + + Vpd_step = (uint16_t)(VpdTable_I[ii][sizeCurrVpdTable-1] - + VpdTable_I[ii][sizeCurrVpdTable-2]); + Vpd_step = (uint16_t)((Vpd_step < 1) ? 1 : Vpd_step); + /* + * for last gain, pdGainBoundary == Pmax_t2, so will + * have to extrapolate + */ + if (tgtIndex > maxIndex) { /* need to extrapolate above */ + while(ss < (int16_t)tgtIndex) { + tmpVal = (uint16_t) + (VpdTable_I[ii][sizeCurrVpdTable-1] + + (ss-maxIndex)*Vpd_step); + pPDADCValues[kk++] = (tmpVal > 127) ? + 127 : tmpVal; + ss++; + } + } /* extrapolated above */ + } /* for all pdGainUsed */ + + while (ii < MAX_NUM_PDGAINS_PER_CHANNEL) { + pPdGainBoundaries[ii] = pPdGainBoundaries[ii-1]; + ii++; + } + while (kk < 128) { + pPDADCValues[kk] = pPDADCValues[kk-1]; + kk++; + } + + return numPdGainsUsed; +#undef VpdTable_L +#undef VpdTable_R +#undef VpdTable_I +} + +static HAL_BOOL +ar2316SetPowerTable(struct ath_hal *ah, + int16_t *minPower, int16_t *maxPower, HAL_CHANNEL_INTERNAL *chan, + uint16_t *rfXpdGain) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom; + const RAW_DATA_STRUCT_2316 *pRawDataset = AH_NULL; + uint16_t pdGainOverlap_t2; + int16_t minCalPower2316_t2; + uint16_t *pdadcValues = ahp->ah_pcdacTable; + uint16_t gainBoundaries[4]; + uint32_t reg32, regoffset; + int i, numPdGainsUsed; +#ifndef AH_USE_INIPDGAIN + uint32_t tpcrg1; +#endif + + HALDEBUG(ah, HAL_DEBUG_RFPARAM, "%s: chan 0x%x flag 0x%x\n", + __func__, chan->channel,chan->channelFlags); + + if (IS_CHAN_G(chan) || IS_CHAN_108G(chan)) + pRawDataset = &ee->ee_rawDataset2413[headerInfo11G]; + else if (IS_CHAN_B(chan)) + pRawDataset = &ee->ee_rawDataset2413[headerInfo11B]; + else { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: illegal mode\n", __func__); + return AH_FALSE; + } + + pdGainOverlap_t2 = (uint16_t) SM(OS_REG_READ(ah, AR_PHY_TPCRG5), + AR_PHY_TPCRG5_PD_GAIN_OVERLAP); + + numPdGainsUsed = ar2316getGainBoundariesAndPdadcsForPowers(ah, + chan->channel, pRawDataset, pdGainOverlap_t2, + &minCalPower2316_t2,gainBoundaries, rfXpdGain, pdadcValues); + HALASSERT(1 <= numPdGainsUsed && numPdGainsUsed <= 3); + +#ifdef AH_USE_INIPDGAIN + /* + * Use pd_gains curve from eeprom; Atheros always uses + * the default curve from the ini file but some vendors + * (e.g. Zcomax) want to override this curve and not + * honoring their settings results in tx power 5dBm low. + */ + OS_REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN, + (pRawDataset->pDataPerChannel[0].numPdGains - 1)); +#else + tpcrg1 = OS_REG_READ(ah, AR_PHY_TPCRG1); + tpcrg1 = (tpcrg1 &~ AR_PHY_TPCRG1_NUM_PD_GAIN) + | SM(numPdGainsUsed-1, AR_PHY_TPCRG1_NUM_PD_GAIN); + switch (numPdGainsUsed) { + case 3: + tpcrg1 &= ~AR_PHY_TPCRG1_PDGAIN_SETTING3; + tpcrg1 |= SM(rfXpdGain[2], AR_PHY_TPCRG1_PDGAIN_SETTING3); + /* fall thru... */ + case 2: + tpcrg1 &= ~AR_PHY_TPCRG1_PDGAIN_SETTING2; + tpcrg1 |= SM(rfXpdGain[1], AR_PHY_TPCRG1_PDGAIN_SETTING2); + /* fall thru... */ + case 1: + tpcrg1 &= ~AR_PHY_TPCRG1_PDGAIN_SETTING1; + tpcrg1 |= SM(rfXpdGain[0], AR_PHY_TPCRG1_PDGAIN_SETTING1); + break; + } +#ifdef AH_DEBUG + if (tpcrg1 != OS_REG_READ(ah, AR_PHY_TPCRG1)) + HALDEBUG(ah, HAL_DEBUG_RFPARAM, "%s: using non-default " + "pd_gains (default 0x%x, calculated 0x%x)\n", + __func__, OS_REG_READ(ah, AR_PHY_TPCRG1), tpcrg1); +#endif + OS_REG_WRITE(ah, AR_PHY_TPCRG1, tpcrg1); +#endif + + /* + * Note the pdadc table may not start at 0 dBm power, could be + * negative or greater than 0. Need to offset the power + * values by the amount of minPower for griffin + */ + if (minCalPower2316_t2 != 0) + ahp->ah_txPowerIndexOffset = (int16_t)(0 - minCalPower2316_t2); + else + ahp->ah_txPowerIndexOffset = 0; + + /* Finally, write the power values into the baseband power table */ + regoffset = 0x9800 + (672 <<2); /* beginning of pdadc table in griffin */ + for (i = 0; i < 32; i++) { + reg32 = ((pdadcValues[4*i + 0] & 0xFF) << 0) | + ((pdadcValues[4*i + 1] & 0xFF) << 8) | + ((pdadcValues[4*i + 2] & 0xFF) << 16) | + ((pdadcValues[4*i + 3] & 0xFF) << 24) ; + OS_REG_WRITE(ah, regoffset, reg32); + regoffset += 4; + } + + OS_REG_WRITE(ah, AR_PHY_TPCRG5, + SM(pdGainOverlap_t2, AR_PHY_TPCRG5_PD_GAIN_OVERLAP) | + SM(gainBoundaries[0], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1) | + SM(gainBoundaries[1], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2) | + SM(gainBoundaries[2], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3) | + SM(gainBoundaries[3], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4)); + + return AH_TRUE; +} + +static int16_t +ar2316GetMinPower(struct ath_hal *ah, const RAW_DATA_PER_CHANNEL_2316 *data) +{ + uint32_t ii,jj; + uint16_t Pmin=0,numVpd; + + for (ii = 0; ii < MAX_NUM_PDGAINS_PER_CHANNEL; ii++) { + jj = MAX_NUM_PDGAINS_PER_CHANNEL - ii - 1; + /* work backwards 'cause highest pdGain for lowest power */ + numVpd = data->pDataPerPDGain[jj].numVpd; + if (numVpd > 0) { + Pmin = data->pDataPerPDGain[jj].pwr_t4[0]; + return(Pmin); + } + } + return(Pmin); +} + +static int16_t +ar2316GetMaxPower(struct ath_hal *ah, const RAW_DATA_PER_CHANNEL_2316 *data) +{ + uint32_t ii; + uint16_t Pmax=0,numVpd; + + for (ii=0; ii< MAX_NUM_PDGAINS_PER_CHANNEL; ii++) { + /* work forwards cuase lowest pdGain for highest power */ + numVpd = data->pDataPerPDGain[ii].numVpd; + if (numVpd > 0) { + Pmax = data->pDataPerPDGain[ii].pwr_t4[numVpd-1]; + return(Pmax); + } + } + return(Pmax); +} + +static HAL_BOOL +ar2316GetChannelMaxMinPower(struct ath_hal *ah, HAL_CHANNEL *chan, + int16_t *maxPow, int16_t *minPow) +{ + const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom; + const RAW_DATA_STRUCT_2316 *pRawDataset = AH_NULL; + const RAW_DATA_PER_CHANNEL_2316 *data=AH_NULL; + uint16_t numChannels; + int totalD,totalF, totalMin,last, i; + + *maxPow = 0; + + if (IS_CHAN_G(chan) || IS_CHAN_108G(chan)) + pRawDataset = &ee->ee_rawDataset2413[headerInfo11G]; + else if (IS_CHAN_B(chan)) + pRawDataset = &ee->ee_rawDataset2413[headerInfo11B]; + else + return(AH_FALSE); + + numChannels = pRawDataset->numChannels; + data = pRawDataset->pDataPerChannel; + + /* Make sure the channel is in the range of the TP values + * (freq piers) + */ + if (numChannels < 1) + return(AH_FALSE); + + if ((chan->channel < data[0].channelValue) || + (chan->channel > data[numChannels-1].channelValue)) { + if (chan->channel < data[0].channelValue) { + *maxPow = ar2316GetMaxPower(ah, &data[0]); + *minPow = ar2316GetMinPower(ah, &data[0]); + return(AH_TRUE); + } else { + *maxPow = ar2316GetMaxPower(ah, &data[numChannels - 1]); + *minPow = ar2316GetMinPower(ah, &data[numChannels - 1]); + return(AH_TRUE); + } + } + + /* Linearly interpolate the power value now */ + for (last=0,i=0; (ichannel > data[i].channelValue); + last = i++); + totalD = data[i].channelValue - data[last].channelValue; + if (totalD > 0) { + totalF = ar2316GetMaxPower(ah, &data[i]) - ar2316GetMaxPower(ah, &data[last]); + *maxPow = (int8_t) ((totalF*(chan->channel-data[last].channelValue) + + ar2316GetMaxPower(ah, &data[last])*totalD)/totalD); + totalMin = ar2316GetMinPower(ah, &data[i]) - ar2316GetMinPower(ah, &data[last]); + *minPow = (int8_t) ((totalMin*(chan->channel-data[last].channelValue) + + ar2316GetMinPower(ah, &data[last])*totalD)/totalD); + return(AH_TRUE); + } else { + if (chan->channel == data[i].channelValue) { + *maxPow = ar2316GetMaxPower(ah, &data[i]); + *minPow = ar2316GetMinPower(ah, &data[i]); + return(AH_TRUE); + } else + return(AH_FALSE); + } +} + +/* + * Free memory for analog bank scratch buffers + */ +static void +ar2316RfDetach(struct ath_hal *ah) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + + HALASSERT(ahp->ah_rfHal != AH_NULL); + ath_hal_free(ahp->ah_rfHal); + ahp->ah_rfHal = AH_NULL; +} + +/* + * Allocate memory for private state. + * Scratch Buffer will be reinitialized every reset so no need to zero now + */ +static HAL_BOOL +ar2316RfAttach(struct ath_hal *ah, HAL_STATUS *status) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + struct ar2316State *priv; + + HALASSERT(ah->ah_magic == AR5212_MAGIC); + + HALASSERT(ahp->ah_rfHal == AH_NULL); + priv = ath_hal_malloc(sizeof(struct ar2316State)); + if (priv == AH_NULL) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: cannot allocate private state\n", __func__); + *status = HAL_ENOMEM; /* XXX */ + return AH_FALSE; + } + priv->base.rfDetach = ar2316RfDetach; + priv->base.writeRegs = ar2316WriteRegs; + priv->base.getRfBank = ar2316GetRfBank; + priv->base.setChannel = ar2316SetChannel; + priv->base.setRfRegs = ar2316SetRfRegs; + priv->base.setPowerTable = ar2316SetPowerTable; + priv->base.getChannelMaxMinPower = ar2316GetChannelMaxMinPower; + priv->base.getNfAdjust = ar5212GetNfAdjust; + + ahp->ah_pcdacTable = priv->pcdacTable; + ahp->ah_pcdacTableSize = sizeof(priv->pcdacTable); + ahp->ah_rfHal = &priv->base; + + ahp->ah_cwCalRequire = AH_TRUE; /* force initial cal */ + + return AH_TRUE; +} + +static HAL_BOOL +ar2316Probe(struct ath_hal *ah) +{ + return IS_2316(ah); +} +AH_RF(RF2316, ar2316Probe, ar2316RfAttach); --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5212/ar2317.c 2009-03-23 17:36:55.000000000 +0000 @@ -0,0 +1,745 @@ +/* + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2008 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ar2317.c,v 1.1 2009/03/23 17:14:47 sborrill Exp $ + */ +#include "opt_ah.h" + +#include "ah.h" +#include "ah_devid.h" +#include "ah_internal.h" + +#include "ar5212/ar5212.h" +#include "ar5212/ar5212reg.h" +#include "ar5212/ar5212phy.h" + +#include "ah_eeprom_v3.h" + +#define AH_5212_2317 +#include "ar5212/ar5212.ini" + +#define N(a) (sizeof(a)/sizeof(a[0])) + +typedef RAW_DATA_STRUCT_2413 RAW_DATA_STRUCT_2317; +typedef RAW_DATA_PER_CHANNEL_2413 RAW_DATA_PER_CHANNEL_2317; +#define PWR_TABLE_SIZE_2317 PWR_TABLE_SIZE_2413 + +struct ar2317State { + RF_HAL_FUNCS base; /* public state, must be first */ + uint16_t pcdacTable[PWR_TABLE_SIZE_2317]; + + uint32_t Bank1Data[N(ar5212Bank1_2317)]; + uint32_t Bank2Data[N(ar5212Bank2_2317)]; + uint32_t Bank3Data[N(ar5212Bank3_2317)]; + uint32_t Bank6Data[N(ar5212Bank6_2317)]; + uint32_t Bank7Data[N(ar5212Bank7_2317)]; + + /* + * Private state for reduced stack usage. + */ + /* filled out Vpd table for all pdGains (chanL) */ + uint16_t vpdTable_L[MAX_NUM_PDGAINS_PER_CHANNEL] + [MAX_PWR_RANGE_IN_HALF_DB]; + /* filled out Vpd table for all pdGains (chanR) */ + uint16_t vpdTable_R[MAX_NUM_PDGAINS_PER_CHANNEL] + [MAX_PWR_RANGE_IN_HALF_DB]; + /* filled out Vpd table for all pdGains (interpolated) */ + uint16_t vpdTable_I[MAX_NUM_PDGAINS_PER_CHANNEL] + [MAX_PWR_RANGE_IN_HALF_DB]; +}; +#define AR2317(ah) ((struct ar2317State *) AH5212(ah)->ah_rfHal) + +extern void ar5212ModifyRfBuffer(uint32_t *rfBuf, uint32_t reg32, + uint32_t numBits, uint32_t firstBit, uint32_t column); + +static void +ar2317WriteRegs(struct ath_hal *ah, u_int modesIndex, u_int freqIndex, + int writes) +{ + HAL_INI_WRITE_ARRAY(ah, ar5212Modes_2317, modesIndex, writes); + HAL_INI_WRITE_ARRAY(ah, ar5212Common_2317, 1, writes); + HAL_INI_WRITE_ARRAY(ah, ar5212BB_RfGain_2317, freqIndex, writes); +} + +/* + * Take the MHz channel value and set the Channel value + * + * ASSUMES: Writes enabled to analog bus + */ +static HAL_BOOL +ar2317SetChannel(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan) +{ + uint32_t channelSel = 0; + uint32_t bModeSynth = 0; + uint32_t aModeRefSel = 0; + uint32_t reg32 = 0; + + OS_MARK(ah, AH_MARK_SETCHANNEL, chan->channel); + + if (chan->channel < 4800) { + uint32_t txctl; + channelSel = chan->channel - 2272 ; + channelSel = ath_hal_reverseBits(channelSel, 8); + + txctl = OS_REG_READ(ah, AR_PHY_CCK_TX_CTRL); + if (chan->channel == 2484) { + /* Enable channel spreading for channel 14 */ + OS_REG_WRITE(ah, AR_PHY_CCK_TX_CTRL, + txctl | AR_PHY_CCK_TX_CTRL_JAPAN); + } else { + OS_REG_WRITE(ah, AR_PHY_CCK_TX_CTRL, + txctl &~ AR_PHY_CCK_TX_CTRL_JAPAN); + } + } else if ((chan->channel % 20) == 0 && chan->channel >= 5120) { + channelSel = ath_hal_reverseBits( + ((chan->channel - 4800) / 20 << 2), 8); + aModeRefSel = ath_hal_reverseBits(3, 2); + } else if ((chan->channel % 10) == 0) { + channelSel = ath_hal_reverseBits( + ((chan->channel - 4800) / 10 << 1), 8); + aModeRefSel = ath_hal_reverseBits(2, 2); + } else if ((chan->channel % 5) == 0) { + channelSel = ath_hal_reverseBits( + (chan->channel - 4800) / 5, 8); + aModeRefSel = ath_hal_reverseBits(1, 2); + } else { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel %u MHz\n", + __func__, chan->channel); + return AH_FALSE; + } + + reg32 = (channelSel << 4) | (aModeRefSel << 2) | (bModeSynth << 1) | + (1 << 12) | 0x1; + OS_REG_WRITE(ah, AR_PHY(0x27), reg32 & 0xff); + + reg32 >>= 8; + OS_REG_WRITE(ah, AR_PHY(0x36), reg32 & 0x7f); + + AH_PRIVATE(ah)->ah_curchan = chan; + return AH_TRUE; +} + +/* + * Reads EEPROM header info from device structure and programs + * all rf registers + * + * REQUIRES: Access to the analog rf device + */ +static HAL_BOOL +ar2317SetRfRegs(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan, uint16_t modesIndex, uint16_t *rfXpdGain) +{ +#define RF_BANK_SETUP(_priv, _ix, _col) do { \ + int i; \ + for (i = 0; i < N(ar5212Bank##_ix##_2317); i++) \ + (_priv)->Bank##_ix##Data[i] = ar5212Bank##_ix##_2317[i][_col];\ +} while (0) + struct ath_hal_5212 *ahp = AH5212(ah); + const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom; + uint16_t ob2GHz = 0, db2GHz = 0; + struct ar2317State *priv = AR2317(ah); + int regWrites = 0; + + HALDEBUG(ah, HAL_DEBUG_RFPARAM, + "%s: chan 0x%x flag 0x%x modesIndex 0x%x\n", + __func__, chan->channel, chan->channelFlags, modesIndex); + + HALASSERT(priv); + + /* Setup rf parameters */ + switch (chan->channelFlags & CHANNEL_ALL) { + case CHANNEL_B: + ob2GHz = ee->ee_obFor24; + db2GHz = ee->ee_dbFor24; + break; + case CHANNEL_G: + case CHANNEL_108G: + ob2GHz = ee->ee_obFor24g; + db2GHz = ee->ee_dbFor24g; + break; + default: + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel flags 0x%x\n", + __func__, chan->channelFlags); + return AH_FALSE; + } + + /* Bank 1 Write */ + RF_BANK_SETUP(priv, 1, 1); + + /* Bank 2 Write */ + RF_BANK_SETUP(priv, 2, modesIndex); + + /* Bank 3 Write */ + RF_BANK_SETUP(priv, 3, modesIndex); + + /* Bank 6 Write */ + RF_BANK_SETUP(priv, 6, modesIndex); + + ar5212ModifyRfBuffer(priv->Bank6Data, ob2GHz, 3, 193, 0); + ar5212ModifyRfBuffer(priv->Bank6Data, db2GHz, 3, 190, 0); + + /* Bank 7 Setup */ + RF_BANK_SETUP(priv, 7, modesIndex); + + /* Write Analog registers */ + HAL_INI_WRITE_BANK(ah, ar5212Bank1_2317, priv->Bank1Data, regWrites); + HAL_INI_WRITE_BANK(ah, ar5212Bank2_2317, priv->Bank2Data, regWrites); + HAL_INI_WRITE_BANK(ah, ar5212Bank3_2317, priv->Bank3Data, regWrites); + HAL_INI_WRITE_BANK(ah, ar5212Bank6_2317, priv->Bank6Data, regWrites); + HAL_INI_WRITE_BANK(ah, ar5212Bank7_2317, priv->Bank7Data, regWrites); + /* Now that we have reprogrammed rfgain value, clear the flag. */ + ahp->ah_rfgainState = HAL_RFGAIN_INACTIVE; + + return AH_TRUE; +#undef RF_BANK_SETUP +} + +/* + * Return a reference to the requested RF Bank. + */ +static uint32_t * +ar2317GetRfBank(struct ath_hal *ah, int bank) +{ + struct ar2317State *priv = AR2317(ah); + + HALASSERT(priv != AH_NULL); + switch (bank) { + case 1: return priv->Bank1Data; + case 2: return priv->Bank2Data; + case 3: return priv->Bank3Data; + case 6: return priv->Bank6Data; + case 7: return priv->Bank7Data; + } + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unknown RF Bank %d requested\n", + __func__, bank); + return AH_NULL; +} + +/* + * Return indices surrounding the value in sorted integer lists. + * + * NB: the input list is assumed to be sorted in ascending order + */ +static void +GetLowerUpperIndex(int16_t v, const uint16_t *lp, uint16_t listSize, + uint32_t *vlo, uint32_t *vhi) +{ + int16_t target = v; + const int16_t *ep = lp+listSize; + const int16_t *tp; + + /* + * Check first and last elements for out-of-bounds conditions. + */ + if (target < lp[0]) { + *vlo = *vhi = 0; + return; + } + if (target >= ep[-1]) { + *vlo = *vhi = listSize - 1; + return; + } + + /* look for value being near or between 2 values in list */ + for (tp = lp; tp < ep; tp++) { + /* + * If value is close to the current value of the list + * then target is not between values, it is one of the values + */ + if (*tp == target) { + *vlo = *vhi = tp - (const int16_t *) lp; + return; + } + /* + * Look for value being between current value and next value + * if so return these 2 values + */ + if (target < tp[1]) { + *vlo = tp - (const int16_t *) lp; + *vhi = *vlo + 1; + return; + } + } +} + +/* + * Fill the Vpdlist for indices Pmax-Pmin + */ +static HAL_BOOL +ar2317FillVpdTable(uint32_t pdGainIdx, int16_t Pmin, int16_t Pmax, + const int16_t *pwrList, const int16_t *VpdList, + uint16_t numIntercepts, uint16_t retVpdList[][64]) +{ + uint16_t ii, jj, kk; + int16_t currPwr = (int16_t)(2*Pmin); + /* since Pmin is pwr*2 and pwrList is 4*pwr */ + uint32_t idxL = 0, idxR = 0; + + ii = 0; + jj = 0; + + if (numIntercepts < 2) + return AH_FALSE; + + while (ii <= (uint16_t)(Pmax - Pmin)) { + GetLowerUpperIndex(currPwr, pwrList, numIntercepts, + &(idxL), &(idxR)); + if (idxR < 1) + idxR = 1; /* extrapolate below */ + if (idxL == (uint32_t)(numIntercepts - 1)) + idxL = numIntercepts - 2; /* extrapolate above */ + if (pwrList[idxL] == pwrList[idxR]) + kk = VpdList[idxL]; + else + kk = (uint16_t) + (((currPwr - pwrList[idxL])*VpdList[idxR]+ + (pwrList[idxR] - currPwr)*VpdList[idxL])/ + (pwrList[idxR] - pwrList[idxL])); + retVpdList[pdGainIdx][ii] = kk; + ii++; + currPwr += 2; /* half dB steps */ + } + + return AH_TRUE; +} + +/* + * Returns interpolated or the scaled up interpolated value + */ +static int16_t +interpolate_signed(uint16_t target, uint16_t srcLeft, uint16_t srcRight, + int16_t targetLeft, int16_t targetRight) +{ + int16_t rv; + + if (srcRight != srcLeft) { + rv = ((target - srcLeft)*targetRight + + (srcRight - target)*targetLeft) / (srcRight - srcLeft); + } else { + rv = targetLeft; + } + return rv; +} + +/* + * Uses the data points read from EEPROM to reconstruct the pdadc power table + * Called by ar2317SetPowerTable() + */ +static int +ar2317getGainBoundariesAndPdadcsForPowers(struct ath_hal *ah, uint16_t channel, + const RAW_DATA_STRUCT_2317 *pRawDataset, + uint16_t pdGainOverlap_t2, + int16_t *pMinCalPower, uint16_t pPdGainBoundaries[], + uint16_t pPdGainValues[], uint16_t pPDADCValues[]) +{ + struct ar2317State *priv = AR2317(ah); +#define VpdTable_L priv->vpdTable_L +#define VpdTable_R priv->vpdTable_R +#define VpdTable_I priv->vpdTable_I + /* XXX excessive stack usage? */ + uint32_t ii, jj, kk; + int32_t ss;/* potentially -ve index for taking care of pdGainOverlap */ + uint32_t idxL = 0, idxR = 0; + uint32_t numPdGainsUsed = 0; + /* + * If desired to support -ve power levels in future, just + * change pwr_I_0 to signed 5-bits. + */ + int16_t Pmin_t2[MAX_NUM_PDGAINS_PER_CHANNEL]; + /* to accomodate -ve power levels later on. */ + int16_t Pmax_t2[MAX_NUM_PDGAINS_PER_CHANNEL]; + /* to accomodate -ve power levels later on */ + uint16_t numVpd = 0; + uint16_t Vpd_step; + int16_t tmpVal ; + uint32_t sizeCurrVpdTable, maxIndex, tgtIndex; + + /* Get upper lower index */ + GetLowerUpperIndex(channel, pRawDataset->pChannels, + pRawDataset->numChannels, &(idxL), &(idxR)); + + for (ii = 0; ii < MAX_NUM_PDGAINS_PER_CHANNEL; ii++) { + jj = MAX_NUM_PDGAINS_PER_CHANNEL - ii - 1; + /* work backwards 'cause highest pdGain for lowest power */ + numVpd = pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].numVpd; + if (numVpd > 0) { + pPdGainValues[numPdGainsUsed] = pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].pd_gain; + Pmin_t2[numPdGainsUsed] = pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].pwr_t4[0]; + if (Pmin_t2[numPdGainsUsed] >pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].pwr_t4[0]) { + Pmin_t2[numPdGainsUsed] = pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].pwr_t4[0]; + } + Pmin_t2[numPdGainsUsed] = (int16_t) + (Pmin_t2[numPdGainsUsed] / 2); + Pmax_t2[numPdGainsUsed] = pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].pwr_t4[numVpd-1]; + if (Pmax_t2[numPdGainsUsed] > pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].pwr_t4[numVpd-1]) + Pmax_t2[numPdGainsUsed] = + pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].pwr_t4[numVpd-1]; + Pmax_t2[numPdGainsUsed] = (int16_t)(Pmax_t2[numPdGainsUsed] / 2); + ar2317FillVpdTable( + numPdGainsUsed, Pmin_t2[numPdGainsUsed], Pmax_t2[numPdGainsUsed], + &(pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].pwr_t4[0]), + &(pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].Vpd[0]), numVpd, VpdTable_L + ); + ar2317FillVpdTable( + numPdGainsUsed, Pmin_t2[numPdGainsUsed], Pmax_t2[numPdGainsUsed], + &(pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].pwr_t4[0]), + &(pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].Vpd[0]), numVpd, VpdTable_R + ); + for (kk = 0; kk < (uint16_t)(Pmax_t2[numPdGainsUsed] - Pmin_t2[numPdGainsUsed]); kk++) { + VpdTable_I[numPdGainsUsed][kk] = + interpolate_signed( + channel, pRawDataset->pChannels[idxL], pRawDataset->pChannels[idxR], + (int16_t)VpdTable_L[numPdGainsUsed][kk], (int16_t)VpdTable_R[numPdGainsUsed][kk]); + } + /* fill VpdTable_I for this pdGain */ + numPdGainsUsed++; + } + /* if this pdGain is used */ + } + + *pMinCalPower = Pmin_t2[0]; + kk = 0; /* index for the final table */ + for (ii = 0; ii < numPdGainsUsed; ii++) { + if (ii == (numPdGainsUsed - 1)) + pPdGainBoundaries[ii] = Pmax_t2[ii] + + PD_GAIN_BOUNDARY_STRETCH_IN_HALF_DB; + else + pPdGainBoundaries[ii] = (uint16_t) + ((Pmax_t2[ii] + Pmin_t2[ii+1]) / 2 ); + if (pPdGainBoundaries[ii] > 63) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: clamp pPdGainBoundaries[%d] %d\n", + __func__, ii, pPdGainBoundaries[ii]);/*XXX*/ + pPdGainBoundaries[ii] = 63; + } + + /* Find starting index for this pdGain */ + if (ii == 0) + ss = 0; /* for the first pdGain, start from index 0 */ + else + ss = (pPdGainBoundaries[ii-1] - Pmin_t2[ii]) - + pdGainOverlap_t2; + Vpd_step = (uint16_t)(VpdTable_I[ii][1] - VpdTable_I[ii][0]); + Vpd_step = (uint16_t)((Vpd_step < 1) ? 1 : Vpd_step); + /* + *-ve ss indicates need to extrapolate data below for this pdGain + */ + while (ss < 0) { + tmpVal = (int16_t)(VpdTable_I[ii][0] + ss*Vpd_step); + pPDADCValues[kk++] = (uint16_t)((tmpVal < 0) ? 0 : tmpVal); + ss++; + } + + sizeCurrVpdTable = Pmax_t2[ii] - Pmin_t2[ii]; + tgtIndex = pPdGainBoundaries[ii] + pdGainOverlap_t2 - Pmin_t2[ii]; + maxIndex = (tgtIndex < sizeCurrVpdTable) ? tgtIndex : sizeCurrVpdTable; + + while (ss < (int16_t)maxIndex) + pPDADCValues[kk++] = VpdTable_I[ii][ss++]; + + Vpd_step = (uint16_t)(VpdTable_I[ii][sizeCurrVpdTable-1] - + VpdTable_I[ii][sizeCurrVpdTable-2]); + Vpd_step = (uint16_t)((Vpd_step < 1) ? 1 : Vpd_step); + /* + * for last gain, pdGainBoundary == Pmax_t2, so will + * have to extrapolate + */ + if (tgtIndex > maxIndex) { /* need to extrapolate above */ + while(ss < (int16_t)tgtIndex) { + tmpVal = (uint16_t) + (VpdTable_I[ii][sizeCurrVpdTable-1] + + (ss-maxIndex)*Vpd_step); + pPDADCValues[kk++] = (tmpVal > 127) ? + 127 : tmpVal; + ss++; + } + } /* extrapolated above */ + } /* for all pdGainUsed */ + + while (ii < MAX_NUM_PDGAINS_PER_CHANNEL) { + pPdGainBoundaries[ii] = pPdGainBoundaries[ii-1]; + ii++; + } + while (kk < 128) { + pPDADCValues[kk] = pPDADCValues[kk-1]; + kk++; + } + + return numPdGainsUsed; +#undef VpdTable_L +#undef VpdTable_R +#undef VpdTable_I +} + +static HAL_BOOL +ar2317SetPowerTable(struct ath_hal *ah, + int16_t *minPower, int16_t *maxPower, HAL_CHANNEL_INTERNAL *chan, + uint16_t *rfXpdGain) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom; + const RAW_DATA_STRUCT_2317 *pRawDataset = AH_NULL; + uint16_t pdGainOverlap_t2; + int16_t minCalPower2317_t2; + uint16_t *pdadcValues = ahp->ah_pcdacTable; + uint16_t gainBoundaries[4]; + uint32_t reg32, regoffset; + int i, numPdGainsUsed; +#ifndef AH_USE_INIPDGAIN + uint32_t tpcrg1; +#endif + + HALDEBUG(ah, HAL_DEBUG_RFPARAM, "%s: chan 0x%x flag 0x%x\n", + __func__, chan->channel,chan->channelFlags); + + if (IS_CHAN_G(chan) || IS_CHAN_108G(chan)) + pRawDataset = &ee->ee_rawDataset2413[headerInfo11G]; + else if (IS_CHAN_B(chan)) + pRawDataset = &ee->ee_rawDataset2413[headerInfo11B]; + else { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: illegal mode\n", __func__); + return AH_FALSE; + } + + pdGainOverlap_t2 = (uint16_t) SM(OS_REG_READ(ah, AR_PHY_TPCRG5), + AR_PHY_TPCRG5_PD_GAIN_OVERLAP); + + numPdGainsUsed = ar2317getGainBoundariesAndPdadcsForPowers(ah, + chan->channel, pRawDataset, pdGainOverlap_t2, + &minCalPower2317_t2,gainBoundaries, rfXpdGain, pdadcValues); + HALASSERT(1 <= numPdGainsUsed && numPdGainsUsed <= 3); + +#ifdef AH_USE_INIPDGAIN + /* + * Use pd_gains curve from eeprom; Atheros always uses + * the default curve from the ini file but some vendors + * (e.g. Zcomax) want to override this curve and not + * honoring their settings results in tx power 5dBm low. + */ + OS_REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN, + (pRawDataset->pDataPerChannel[0].numPdGains - 1)); +#else + tpcrg1 = OS_REG_READ(ah, AR_PHY_TPCRG1); + tpcrg1 = (tpcrg1 &~ AR_PHY_TPCRG1_NUM_PD_GAIN) + | SM(numPdGainsUsed-1, AR_PHY_TPCRG1_NUM_PD_GAIN); + switch (numPdGainsUsed) { + case 3: + tpcrg1 &= ~AR_PHY_TPCRG1_PDGAIN_SETTING3; + tpcrg1 |= SM(rfXpdGain[2], AR_PHY_TPCRG1_PDGAIN_SETTING3); + /* fall thru... */ + case 2: + tpcrg1 &= ~AR_PHY_TPCRG1_PDGAIN_SETTING2; + tpcrg1 |= SM(rfXpdGain[1], AR_PHY_TPCRG1_PDGAIN_SETTING2); + /* fall thru... */ + case 1: + tpcrg1 &= ~AR_PHY_TPCRG1_PDGAIN_SETTING1; + tpcrg1 |= SM(rfXpdGain[0], AR_PHY_TPCRG1_PDGAIN_SETTING1); + break; + } +#ifdef AH_DEBUG + if (tpcrg1 != OS_REG_READ(ah, AR_PHY_TPCRG1)) + HALDEBUG(ah, HAL_DEBUG_RFPARAM, "%s: using non-default " + "pd_gains (default 0x%x, calculated 0x%x)\n", + __func__, OS_REG_READ(ah, AR_PHY_TPCRG1), tpcrg1); +#endif + OS_REG_WRITE(ah, AR_PHY_TPCRG1, tpcrg1); +#endif + + /* + * Note the pdadc table may not start at 0 dBm power, could be + * negative or greater than 0. Need to offset the power + * values by the amount of minPower for griffin + */ + if (minCalPower2317_t2 != 0) + ahp->ah_txPowerIndexOffset = (int16_t)(0 - minCalPower2317_t2); + else + ahp->ah_txPowerIndexOffset = 0; + + /* Finally, write the power values into the baseband power table */ + regoffset = 0x9800 + (672 <<2); /* beginning of pdadc table in griffin */ + for (i = 0; i < 32; i++) { + reg32 = ((pdadcValues[4*i + 0] & 0xFF) << 0) | + ((pdadcValues[4*i + 1] & 0xFF) << 8) | + ((pdadcValues[4*i + 2] & 0xFF) << 16) | + ((pdadcValues[4*i + 3] & 0xFF) << 24) ; + OS_REG_WRITE(ah, regoffset, reg32); + regoffset += 4; + } + + OS_REG_WRITE(ah, AR_PHY_TPCRG5, + SM(pdGainOverlap_t2, AR_PHY_TPCRG5_PD_GAIN_OVERLAP) | + SM(gainBoundaries[0], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1) | + SM(gainBoundaries[1], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2) | + SM(gainBoundaries[2], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3) | + SM(gainBoundaries[3], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4)); + + return AH_TRUE; +} + +static int16_t +ar2317GetMinPower(struct ath_hal *ah, const RAW_DATA_PER_CHANNEL_2317 *data) +{ + uint32_t ii,jj; + uint16_t Pmin=0,numVpd; + + for (ii = 0; ii < MAX_NUM_PDGAINS_PER_CHANNEL; ii++) { + jj = MAX_NUM_PDGAINS_PER_CHANNEL - ii - 1; + /* work backwards 'cause highest pdGain for lowest power */ + numVpd = data->pDataPerPDGain[jj].numVpd; + if (numVpd > 0) { + Pmin = data->pDataPerPDGain[jj].pwr_t4[0]; + return(Pmin); + } + } + return(Pmin); +} + +static int16_t +ar2317GetMaxPower(struct ath_hal *ah, const RAW_DATA_PER_CHANNEL_2317 *data) +{ + uint32_t ii; + uint16_t Pmax=0,numVpd; + uint16_t vpdmax; + + for (ii=0; ii< MAX_NUM_PDGAINS_PER_CHANNEL; ii++) { + /* work forwards cuase lowest pdGain for highest power */ + numVpd = data->pDataPerPDGain[ii].numVpd; + if (numVpd > 0) { + Pmax = data->pDataPerPDGain[ii].pwr_t4[numVpd-1]; + vpdmax = data->pDataPerPDGain[ii].Vpd[numVpd-1]; + return(Pmax); + } + } + return(Pmax); +} + +static HAL_BOOL +ar2317GetChannelMaxMinPower(struct ath_hal *ah, HAL_CHANNEL *chan, + int16_t *maxPow, int16_t *minPow) +{ + const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom; + const RAW_DATA_STRUCT_2317 *pRawDataset = AH_NULL; + const RAW_DATA_PER_CHANNEL_2317 *data=AH_NULL; + uint16_t numChannels; + int totalD,totalF, totalMin,last, i; + + *maxPow = 0; + + if (IS_CHAN_G(chan) || IS_CHAN_108G(chan)) + pRawDataset = &ee->ee_rawDataset2413[headerInfo11G]; + else if (IS_CHAN_B(chan)) + pRawDataset = &ee->ee_rawDataset2413[headerInfo11B]; + else + return(AH_FALSE); + + numChannels = pRawDataset->numChannels; + data = pRawDataset->pDataPerChannel; + + /* Make sure the channel is in the range of the TP values + * (freq piers) + */ + if (numChannels < 1) + return(AH_FALSE); + + if ((chan->channel < data[0].channelValue) || + (chan->channel > data[numChannels-1].channelValue)) { + if (chan->channel < data[0].channelValue) { + *maxPow = ar2317GetMaxPower(ah, &data[0]); + *minPow = ar2317GetMinPower(ah, &data[0]); + return(AH_TRUE); + } else { + *maxPow = ar2317GetMaxPower(ah, &data[numChannels - 1]); + *minPow = ar2317GetMinPower(ah, &data[numChannels - 1]); + return(AH_TRUE); + } + } + + /* Linearly interpolate the power value now */ + for (last=0,i=0; (ichannel > data[i].channelValue); + last = i++); + totalD = data[i].channelValue - data[last].channelValue; + if (totalD > 0) { + totalF = ar2317GetMaxPower(ah, &data[i]) - ar2317GetMaxPower(ah, &data[last]); + *maxPow = (int8_t) ((totalF*(chan->channel-data[last].channelValue) + + ar2317GetMaxPower(ah, &data[last])*totalD)/totalD); + totalMin = ar2317GetMinPower(ah, &data[i]) - ar2317GetMinPower(ah, &data[last]); + *minPow = (int8_t) ((totalMin*(chan->channel-data[last].channelValue) + + ar2317GetMinPower(ah, &data[last])*totalD)/totalD); + return(AH_TRUE); + } else { + if (chan->channel == data[i].channelValue) { + *maxPow = ar2317GetMaxPower(ah, &data[i]); + *minPow = ar2317GetMinPower(ah, &data[i]); + return(AH_TRUE); + } else + return(AH_FALSE); + } +} + +/* + * Free memory for analog bank scratch buffers + */ +static void +ar2317RfDetach(struct ath_hal *ah) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + + HALASSERT(ahp->ah_rfHal != AH_NULL); + ath_hal_free(ahp->ah_rfHal); + ahp->ah_rfHal = AH_NULL; +} + +/* + * Allocate memory for analog bank scratch buffers + * Scratch Buffer will be reinitialized every reset so no need to zero now + */ +static HAL_BOOL +ar2317RfAttach(struct ath_hal *ah, HAL_STATUS *status) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + struct ar2317State *priv; + + HALASSERT(ah->ah_magic == AR5212_MAGIC); + + HALASSERT(ahp->ah_rfHal == AH_NULL); + priv = ath_hal_malloc(sizeof(struct ar2317State)); + if (priv == AH_NULL) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: cannot allocate private state\n", __func__); + *status = HAL_ENOMEM; /* XXX */ + return AH_FALSE; + } + priv->base.rfDetach = ar2317RfDetach; + priv->base.writeRegs = ar2317WriteRegs; + priv->base.getRfBank = ar2317GetRfBank; + priv->base.setChannel = ar2317SetChannel; + priv->base.setRfRegs = ar2317SetRfRegs; + priv->base.setPowerTable = ar2317SetPowerTable; + priv->base.getChannelMaxMinPower = ar2317GetChannelMaxMinPower; + priv->base.getNfAdjust = ar5212GetNfAdjust; + + ahp->ah_pcdacTable = priv->pcdacTable; + ahp->ah_pcdacTableSize = sizeof(priv->pcdacTable); + ahp->ah_rfHal = &priv->base; + + return AH_TRUE; +} + +static HAL_BOOL +ar2317Probe(struct ath_hal *ah) +{ + return IS_2317(ah); +} +AH_RF(RF2317, ar2317Probe, ar2317RfAttach); --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5212/ar2413.c 2009-03-23 17:36:55.000000000 +0000 @@ -0,0 +1,759 @@ +/* + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2008 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ar2413.c,v 1.1 2009/03/23 17:14:47 sborrill Exp $ + */ +#include "opt_ah.h" + +#include "ah.h" +#include "ah_internal.h" + +#include "ar5212/ar5212.h" +#include "ar5212/ar5212reg.h" +#include "ar5212/ar5212phy.h" + +#include "ah_eeprom_v3.h" + +#define AH_5212_2413 +#include "ar5212/ar5212.ini" + +#define N(a) (sizeof(a)/sizeof(a[0])) + +struct ar2413State { + RF_HAL_FUNCS base; /* public state, must be first */ + uint16_t pcdacTable[PWR_TABLE_SIZE_2413]; + + uint32_t Bank1Data[N(ar5212Bank1_2413)]; + uint32_t Bank2Data[N(ar5212Bank2_2413)]; + uint32_t Bank3Data[N(ar5212Bank3_2413)]; + uint32_t Bank6Data[N(ar5212Bank6_2413)]; + uint32_t Bank7Data[N(ar5212Bank7_2413)]; + + /* + * Private state for reduced stack usage. + */ + /* filled out Vpd table for all pdGains (chanL) */ + uint16_t vpdTable_L[MAX_NUM_PDGAINS_PER_CHANNEL] + [MAX_PWR_RANGE_IN_HALF_DB]; + /* filled out Vpd table for all pdGains (chanR) */ + uint16_t vpdTable_R[MAX_NUM_PDGAINS_PER_CHANNEL] + [MAX_PWR_RANGE_IN_HALF_DB]; + /* filled out Vpd table for all pdGains (interpolated) */ + uint16_t vpdTable_I[MAX_NUM_PDGAINS_PER_CHANNEL] + [MAX_PWR_RANGE_IN_HALF_DB]; +}; +#define AR2413(ah) ((struct ar2413State *) AH5212(ah)->ah_rfHal) + +extern void ar5212ModifyRfBuffer(uint32_t *rfBuf, uint32_t reg32, + uint32_t numBits, uint32_t firstBit, uint32_t column); + +static void +ar2413WriteRegs(struct ath_hal *ah, u_int modesIndex, u_int freqIndex, + int writes) +{ + HAL_INI_WRITE_ARRAY(ah, ar5212Modes_2413, modesIndex, writes); + HAL_INI_WRITE_ARRAY(ah, ar5212Common_2413, 1, writes); + HAL_INI_WRITE_ARRAY(ah, ar5212BB_RfGain_2413, freqIndex, writes); +} + +/* + * Take the MHz channel value and set the Channel value + * + * ASSUMES: Writes enabled to analog bus + */ +static HAL_BOOL +ar2413SetChannel(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan) +{ + uint32_t channelSel = 0; + uint32_t bModeSynth = 0; + uint32_t aModeRefSel = 0; + uint32_t reg32 = 0; + uint16_t freq; + + OS_MARK(ah, AH_MARK_SETCHANNEL, chan->channel); + + if (chan->channel < 4800) { + uint32_t txctl; + + if (((chan->channel - 2192) % 5) == 0) { + channelSel = ((chan->channel - 672) * 2 - 3040)/10; + bModeSynth = 0; + } else if (((chan->channel - 2224) % 5) == 0) { + channelSel = ((chan->channel - 704) * 2 - 3040) / 10; + bModeSynth = 1; + } else { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: invalid channel %u MHz\n", + __func__, chan->channel); + return AH_FALSE; + } + + channelSel = (channelSel << 2) & 0xff; + channelSel = ath_hal_reverseBits(channelSel, 8); + + txctl = OS_REG_READ(ah, AR_PHY_CCK_TX_CTRL); + if (chan->channel == 2484) { + /* Enable channel spreading for channel 14 */ + OS_REG_WRITE(ah, AR_PHY_CCK_TX_CTRL, + txctl | AR_PHY_CCK_TX_CTRL_JAPAN); + } else { + OS_REG_WRITE(ah, AR_PHY_CCK_TX_CTRL, + txctl &~ AR_PHY_CCK_TX_CTRL_JAPAN); + } + } else if (((chan->channel % 5) == 2) && (chan->channel <= 5435)) { + freq = chan->channel - 2; /* Align to even 5MHz raster */ + channelSel = ath_hal_reverseBits( + (uint32_t)(((freq - 4800)*10)/25 + 1), 8); + aModeRefSel = ath_hal_reverseBits(0, 2); + } else if ((chan->channel % 20) == 0 && chan->channel >= 5120) { + channelSel = ath_hal_reverseBits( + ((chan->channel - 4800) / 20 << 2), 8); + aModeRefSel = ath_hal_reverseBits(3, 2); + } else if ((chan->channel % 10) == 0) { + channelSel = ath_hal_reverseBits( + ((chan->channel - 4800) / 10 << 1), 8); + aModeRefSel = ath_hal_reverseBits(2, 2); + } else if ((chan->channel % 5) == 0) { + channelSel = ath_hal_reverseBits( + (chan->channel - 4800) / 5, 8); + aModeRefSel = ath_hal_reverseBits(1, 2); + } else { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel %u MHz\n", + __func__, chan->channel); + return AH_FALSE; + } + + reg32 = (channelSel << 4) | (aModeRefSel << 2) | (bModeSynth << 1) | + (1 << 12) | 0x1; + OS_REG_WRITE(ah, AR_PHY(0x27), reg32 & 0xff); + + reg32 >>= 8; + OS_REG_WRITE(ah, AR_PHY(0x36), reg32 & 0x7f); + + AH_PRIVATE(ah)->ah_curchan = chan; + + return AH_TRUE; +} + +/* + * Reads EEPROM header info from device structure and programs + * all rf registers + * + * REQUIRES: Access to the analog rf device + */ +static HAL_BOOL +ar2413SetRfRegs(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan, uint16_t modesIndex, uint16_t *rfXpdGain) +{ +#define RF_BANK_SETUP(_priv, _ix, _col) do { \ + int i; \ + for (i = 0; i < N(ar5212Bank##_ix##_2413); i++) \ + (_priv)->Bank##_ix##Data[i] = ar5212Bank##_ix##_2413[i][_col];\ +} while (0) + struct ath_hal_5212 *ahp = AH5212(ah); + const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom; + uint16_t ob2GHz = 0, db2GHz = 0; + struct ar2413State *priv = AR2413(ah); + int regWrites = 0; + + HALDEBUG(ah, HAL_DEBUG_RFPARAM, + "%s: chan 0x%x flag 0x%x modesIndex 0x%x\n", + __func__, chan->channel, chan->channelFlags, modesIndex); + + HALASSERT(priv); + + /* Setup rf parameters */ + switch (chan->channelFlags & CHANNEL_ALL) { + case CHANNEL_B: + ob2GHz = ee->ee_obFor24; + db2GHz = ee->ee_dbFor24; + break; + case CHANNEL_G: + case CHANNEL_108G: + ob2GHz = ee->ee_obFor24g; + db2GHz = ee->ee_dbFor24g; + break; + default: + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel flags 0x%x\n", + __func__, chan->channelFlags); + return AH_FALSE; + } + + /* Bank 1 Write */ + RF_BANK_SETUP(priv, 1, 1); + + /* Bank 2 Write */ + RF_BANK_SETUP(priv, 2, modesIndex); + + /* Bank 3 Write */ + RF_BANK_SETUP(priv, 3, modesIndex); + + /* Bank 6 Write */ + RF_BANK_SETUP(priv, 6, modesIndex); + + ar5212ModifyRfBuffer(priv->Bank6Data, ob2GHz, 3, 168, 0); + ar5212ModifyRfBuffer(priv->Bank6Data, db2GHz, 3, 165, 0); + + /* Bank 7 Setup */ + RF_BANK_SETUP(priv, 7, modesIndex); + + /* Write Analog registers */ + HAL_INI_WRITE_BANK(ah, ar5212Bank1_2413, priv->Bank1Data, regWrites); + HAL_INI_WRITE_BANK(ah, ar5212Bank2_2413, priv->Bank2Data, regWrites); + HAL_INI_WRITE_BANK(ah, ar5212Bank3_2413, priv->Bank3Data, regWrites); + HAL_INI_WRITE_BANK(ah, ar5212Bank6_2413, priv->Bank6Data, regWrites); + HAL_INI_WRITE_BANK(ah, ar5212Bank7_2413, priv->Bank7Data, regWrites); + + /* Now that we have reprogrammed rfgain value, clear the flag. */ + ahp->ah_rfgainState = HAL_RFGAIN_INACTIVE; + + return AH_TRUE; +#undef RF_BANK_SETUP +} + +/* + * Return a reference to the requested RF Bank. + */ +static uint32_t * +ar2413GetRfBank(struct ath_hal *ah, int bank) +{ + struct ar2413State *priv = AR2413(ah); + + HALASSERT(priv != AH_NULL); + switch (bank) { + case 1: return priv->Bank1Data; + case 2: return priv->Bank2Data; + case 3: return priv->Bank3Data; + case 6: return priv->Bank6Data; + case 7: return priv->Bank7Data; + } + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unknown RF Bank %d requested\n", + __func__, bank); + return AH_NULL; +} + +/* + * Return indices surrounding the value in sorted integer lists. + * + * NB: the input list is assumed to be sorted in ascending order + */ +static void +GetLowerUpperIndex(int16_t v, const uint16_t *lp, uint16_t listSize, + uint32_t *vlo, uint32_t *vhi) +{ + int16_t target = v; + const uint16_t *ep = lp+listSize; + const uint16_t *tp; + + /* + * Check first and last elements for out-of-bounds conditions. + */ + if (target < lp[0]) { + *vlo = *vhi = 0; + return; + } + if (target >= ep[-1]) { + *vlo = *vhi = listSize - 1; + return; + } + + /* look for value being near or between 2 values in list */ + for (tp = lp; tp < ep; tp++) { + /* + * If value is close to the current value of the list + * then target is not between values, it is one of the values + */ + if (*tp == target) { + *vlo = *vhi = tp - (const uint16_t *) lp; + return; + } + /* + * Look for value being between current value and next value + * if so return these 2 values + */ + if (target < tp[1]) { + *vlo = tp - (const uint16_t *) lp; + *vhi = *vlo + 1; + return; + } + } +} + +/* + * Fill the Vpdlist for indices Pmax-Pmin + */ +static HAL_BOOL +ar2413FillVpdTable(uint32_t pdGainIdx, int16_t Pmin, int16_t Pmax, + const int16_t *pwrList, const uint16_t *VpdList, + uint16_t numIntercepts, uint16_t retVpdList[][64]) +{ + uint16_t ii, jj, kk; + int16_t currPwr = (int16_t)(2*Pmin); + /* since Pmin is pwr*2 and pwrList is 4*pwr */ + uint32_t idxL = 0, idxR = 0; + + ii = 0; + jj = 0; + + if (numIntercepts < 2) + return AH_FALSE; + + while (ii <= (uint16_t)(Pmax - Pmin)) { + GetLowerUpperIndex(currPwr, (const uint16_t *) pwrList, + numIntercepts, &(idxL), &(idxR)); + if (idxR < 1) + idxR = 1; /* extrapolate below */ + if (idxL == (uint32_t)(numIntercepts - 1)) + idxL = numIntercepts - 2; /* extrapolate above */ + if (pwrList[idxL] == pwrList[idxR]) + kk = VpdList[idxL]; + else + kk = (uint16_t) + (((currPwr - pwrList[idxL])*VpdList[idxR]+ + (pwrList[idxR] - currPwr)*VpdList[idxL])/ + (pwrList[idxR] - pwrList[idxL])); + retVpdList[pdGainIdx][ii] = kk; + ii++; + currPwr += 2; /* half dB steps */ + } + + return AH_TRUE; +} + +/* + * Returns interpolated or the scaled up interpolated value + */ +static int16_t +interpolate_signed(uint16_t target, uint16_t srcLeft, uint16_t srcRight, + int16_t targetLeft, int16_t targetRight) +{ + int16_t rv; + + if (srcRight != srcLeft) { + rv = ((target - srcLeft)*targetRight + + (srcRight - target)*targetLeft) / (srcRight - srcLeft); + } else { + rv = targetLeft; + } + return rv; +} + +/* + * Uses the data points read from EEPROM to reconstruct the pdadc power table + * Called by ar2413SetPowerTable() + */ +static int +ar2413getGainBoundariesAndPdadcsForPowers(struct ath_hal *ah, uint16_t channel, + const RAW_DATA_STRUCT_2413 *pRawDataset, + uint16_t pdGainOverlap_t2, + int16_t *pMinCalPower, uint16_t pPdGainBoundaries[], + uint16_t pPdGainValues[], uint16_t pPDADCValues[]) +{ + struct ar2413State *priv = AR2413(ah); +#define VpdTable_L priv->vpdTable_L +#define VpdTable_R priv->vpdTable_R +#define VpdTable_I priv->vpdTable_I + uint32_t ii, jj, kk; + int32_t ss;/* potentially -ve index for taking care of pdGainOverlap */ + uint32_t idxL = 0, idxR = 0; + uint32_t numPdGainsUsed = 0; + /* + * If desired to support -ve power levels in future, just + * change pwr_I_0 to signed 5-bits. + */ + int16_t Pmin_t2[MAX_NUM_PDGAINS_PER_CHANNEL]; + /* to accomodate -ve power levels later on. */ + int16_t Pmax_t2[MAX_NUM_PDGAINS_PER_CHANNEL]; + /* to accomodate -ve power levels later on */ + uint16_t numVpd = 0; + uint16_t Vpd_step; + int16_t tmpVal ; + uint32_t sizeCurrVpdTable, maxIndex, tgtIndex; + + /* Get upper lower index */ + GetLowerUpperIndex(channel, pRawDataset->pChannels, + pRawDataset->numChannels, &(idxL), &(idxR)); + + for (ii = 0; ii < MAX_NUM_PDGAINS_PER_CHANNEL; ii++) { + jj = MAX_NUM_PDGAINS_PER_CHANNEL - ii - 1; + /* work backwards 'cause highest pdGain for lowest power */ + numVpd = pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].numVpd; + if (numVpd > 0) { + pPdGainValues[numPdGainsUsed] = pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].pd_gain; + Pmin_t2[numPdGainsUsed] = pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].pwr_t4[0]; + if (Pmin_t2[numPdGainsUsed] >pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].pwr_t4[0]) { + Pmin_t2[numPdGainsUsed] = pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].pwr_t4[0]; + } + Pmin_t2[numPdGainsUsed] = (int16_t) + (Pmin_t2[numPdGainsUsed] / 2); + Pmax_t2[numPdGainsUsed] = pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].pwr_t4[numVpd-1]; + if (Pmax_t2[numPdGainsUsed] > pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].pwr_t4[numVpd-1]) + Pmax_t2[numPdGainsUsed] = + pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].pwr_t4[numVpd-1]; + Pmax_t2[numPdGainsUsed] = (int16_t)(Pmax_t2[numPdGainsUsed] / 2); + ar2413FillVpdTable( + numPdGainsUsed, Pmin_t2[numPdGainsUsed], Pmax_t2[numPdGainsUsed], + &(pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].pwr_t4[0]), + &(pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].Vpd[0]), numVpd, VpdTable_L + ); + ar2413FillVpdTable( + numPdGainsUsed, Pmin_t2[numPdGainsUsed], Pmax_t2[numPdGainsUsed], + &(pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].pwr_t4[0]), + &(pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].Vpd[0]), numVpd, VpdTable_R + ); + for (kk = 0; kk < (uint16_t)(Pmax_t2[numPdGainsUsed] - Pmin_t2[numPdGainsUsed]); kk++) { + VpdTable_I[numPdGainsUsed][kk] = + interpolate_signed( + channel, pRawDataset->pChannels[idxL], pRawDataset->pChannels[idxR], + (int16_t)VpdTable_L[numPdGainsUsed][kk], (int16_t)VpdTable_R[numPdGainsUsed][kk]); + } + /* fill VpdTable_I for this pdGain */ + numPdGainsUsed++; + } + /* if this pdGain is used */ + } + + *pMinCalPower = Pmin_t2[0]; + kk = 0; /* index for the final table */ + for (ii = 0; ii < numPdGainsUsed; ii++) { + if (ii == (numPdGainsUsed - 1)) + pPdGainBoundaries[ii] = Pmax_t2[ii] + + PD_GAIN_BOUNDARY_STRETCH_IN_HALF_DB; + else + pPdGainBoundaries[ii] = (uint16_t) + ((Pmax_t2[ii] + Pmin_t2[ii+1]) / 2 ); + if (pPdGainBoundaries[ii] > 63) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: clamp pPdGainBoundaries[%d] %d\n", + __func__, ii, pPdGainBoundaries[ii]);/*XXX*/ + pPdGainBoundaries[ii] = 63; + } + + /* Find starting index for this pdGain */ + if (ii == 0) + ss = 0; /* for the first pdGain, start from index 0 */ + else + ss = (pPdGainBoundaries[ii-1] - Pmin_t2[ii]) - + pdGainOverlap_t2; + Vpd_step = (uint16_t)(VpdTable_I[ii][1] - VpdTable_I[ii][0]); + Vpd_step = (uint16_t)((Vpd_step < 1) ? 1 : Vpd_step); + /* + *-ve ss indicates need to extrapolate data below for this pdGain + */ + while (ss < 0) { + tmpVal = (int16_t)(VpdTable_I[ii][0] + ss*Vpd_step); + pPDADCValues[kk++] = (uint16_t)((tmpVal < 0) ? 0 : tmpVal); + ss++; + } + + sizeCurrVpdTable = Pmax_t2[ii] - Pmin_t2[ii]; + tgtIndex = pPdGainBoundaries[ii] + pdGainOverlap_t2 - Pmin_t2[ii]; + maxIndex = (tgtIndex < sizeCurrVpdTable) ? tgtIndex : sizeCurrVpdTable; + + while (ss < (int16_t)maxIndex) + pPDADCValues[kk++] = VpdTable_I[ii][ss++]; + + Vpd_step = (uint16_t)(VpdTable_I[ii][sizeCurrVpdTable-1] - + VpdTable_I[ii][sizeCurrVpdTable-2]); + Vpd_step = (uint16_t)((Vpd_step < 1) ? 1 : Vpd_step); + /* + * for last gain, pdGainBoundary == Pmax_t2, so will + * have to extrapolate + */ + if (tgtIndex > maxIndex) { /* need to extrapolate above */ + while(ss < (int16_t)tgtIndex) { + tmpVal = (uint16_t) + (VpdTable_I[ii][sizeCurrVpdTable-1] + + (ss-maxIndex)*Vpd_step); + pPDADCValues[kk++] = (tmpVal > 127) ? + 127 : tmpVal; + ss++; + } + } /* extrapolated above */ + } /* for all pdGainUsed */ + + while (ii < MAX_NUM_PDGAINS_PER_CHANNEL) { + pPdGainBoundaries[ii] = pPdGainBoundaries[ii-1]; + ii++; + } + while (kk < 128) { + pPDADCValues[kk] = pPDADCValues[kk-1]; + kk++; + } + + return numPdGainsUsed; +#undef VpdTable_L +#undef VpdTable_R +#undef VpdTable_I +} + +static HAL_BOOL +ar2413SetPowerTable(struct ath_hal *ah, + int16_t *minPower, int16_t *maxPower, HAL_CHANNEL_INTERNAL *chan, + uint16_t *rfXpdGain) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom; + const RAW_DATA_STRUCT_2413 *pRawDataset = AH_NULL; + uint16_t pdGainOverlap_t2; + int16_t minCalPower2413_t2; + uint16_t *pdadcValues = ahp->ah_pcdacTable; + uint16_t gainBoundaries[4]; + uint32_t reg32, regoffset; + int i, numPdGainsUsed; +#ifndef AH_USE_INIPDGAIN + uint32_t tpcrg1; +#endif + + HALDEBUG(ah, HAL_DEBUG_RFPARAM, "%s: chan 0x%x flag 0x%x\n", + __func__, chan->channel,chan->channelFlags); + + if (IS_CHAN_G(chan) || IS_CHAN_108G(chan)) + pRawDataset = &ee->ee_rawDataset2413[headerInfo11G]; + else if (IS_CHAN_B(chan)) + pRawDataset = &ee->ee_rawDataset2413[headerInfo11B]; + else { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: illegal mode\n", __func__); + return AH_FALSE; + } + + pdGainOverlap_t2 = (uint16_t) SM(OS_REG_READ(ah, AR_PHY_TPCRG5), + AR_PHY_TPCRG5_PD_GAIN_OVERLAP); + + numPdGainsUsed = ar2413getGainBoundariesAndPdadcsForPowers(ah, + chan->channel, pRawDataset, pdGainOverlap_t2, + &minCalPower2413_t2,gainBoundaries, rfXpdGain, pdadcValues); + HALASSERT(1 <= numPdGainsUsed && numPdGainsUsed <= 3); + +#ifdef AH_USE_INIPDGAIN + /* + * Use pd_gains curve from eeprom; Atheros always uses + * the default curve from the ini file but some vendors + * (e.g. Zcomax) want to override this curve and not + * honoring their settings results in tx power 5dBm low. + */ + OS_REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN, + (pRawDataset->pDataPerChannel[0].numPdGains - 1)); +#else + tpcrg1 = OS_REG_READ(ah, AR_PHY_TPCRG1); + tpcrg1 = (tpcrg1 &~ AR_PHY_TPCRG1_NUM_PD_GAIN) + | SM(numPdGainsUsed-1, AR_PHY_TPCRG1_NUM_PD_GAIN); + switch (numPdGainsUsed) { + case 3: + tpcrg1 &= ~AR_PHY_TPCRG1_PDGAIN_SETTING3; + tpcrg1 |= SM(rfXpdGain[2], AR_PHY_TPCRG1_PDGAIN_SETTING3); + /* fall thru... */ + case 2: + tpcrg1 &= ~AR_PHY_TPCRG1_PDGAIN_SETTING2; + tpcrg1 |= SM(rfXpdGain[1], AR_PHY_TPCRG1_PDGAIN_SETTING2); + /* fall thru... */ + case 1: + tpcrg1 &= ~AR_PHY_TPCRG1_PDGAIN_SETTING1; + tpcrg1 |= SM(rfXpdGain[0], AR_PHY_TPCRG1_PDGAIN_SETTING1); + break; + } +#ifdef AH_DEBUG + if (tpcrg1 != OS_REG_READ(ah, AR_PHY_TPCRG1)) + HALDEBUG(ah, HAL_DEBUG_RFPARAM, "%s: using non-default " + "pd_gains (default 0x%x, calculated 0x%x)\n", + __func__, OS_REG_READ(ah, AR_PHY_TPCRG1), tpcrg1); +#endif + OS_REG_WRITE(ah, AR_PHY_TPCRG1, tpcrg1); +#endif + + /* + * Note the pdadc table may not start at 0 dBm power, could be + * negative or greater than 0. Need to offset the power + * values by the amount of minPower for griffin + */ + if (minCalPower2413_t2 != 0) + ahp->ah_txPowerIndexOffset = (int16_t)(0 - minCalPower2413_t2); + else + ahp->ah_txPowerIndexOffset = 0; + + /* Finally, write the power values into the baseband power table */ + regoffset = 0x9800 + (672 <<2); /* beginning of pdadc table in griffin */ + for (i = 0; i < 32; i++) { + reg32 = ((pdadcValues[4*i + 0] & 0xFF) << 0) | + ((pdadcValues[4*i + 1] & 0xFF) << 8) | + ((pdadcValues[4*i + 2] & 0xFF) << 16) | + ((pdadcValues[4*i + 3] & 0xFF) << 24) ; + OS_REG_WRITE(ah, regoffset, reg32); + regoffset += 4; + } + + OS_REG_WRITE(ah, AR_PHY_TPCRG5, + SM(pdGainOverlap_t2, AR_PHY_TPCRG5_PD_GAIN_OVERLAP) | + SM(gainBoundaries[0], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1) | + SM(gainBoundaries[1], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2) | + SM(gainBoundaries[2], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3) | + SM(gainBoundaries[3], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4)); + + return AH_TRUE; +} + +static int16_t +ar2413GetMinPower(struct ath_hal *ah, const RAW_DATA_PER_CHANNEL_2413 *data) +{ + uint32_t ii,jj; + uint16_t Pmin=0,numVpd; + + for (ii = 0; ii < MAX_NUM_PDGAINS_PER_CHANNEL; ii++) { + jj = MAX_NUM_PDGAINS_PER_CHANNEL - ii - 1; + /* work backwards 'cause highest pdGain for lowest power */ + numVpd = data->pDataPerPDGain[jj].numVpd; + if (numVpd > 0) { + Pmin = data->pDataPerPDGain[jj].pwr_t4[0]; + return(Pmin); + } + } + return(Pmin); +} + +static int16_t +ar2413GetMaxPower(struct ath_hal *ah, const RAW_DATA_PER_CHANNEL_2413 *data) +{ + uint32_t ii; + uint16_t Pmax=0,numVpd; + + for (ii=0; ii< MAX_NUM_PDGAINS_PER_CHANNEL; ii++) { + /* work forwards cuase lowest pdGain for highest power */ + numVpd = data->pDataPerPDGain[ii].numVpd; + if (numVpd > 0) { + Pmax = data->pDataPerPDGain[ii].pwr_t4[numVpd-1]; + return(Pmax); + } + } + return(Pmax); +} + +static HAL_BOOL +ar2413GetChannelMaxMinPower(struct ath_hal *ah, HAL_CHANNEL *chan, + int16_t *maxPow, int16_t *minPow) +{ + const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom; + const RAW_DATA_STRUCT_2413 *pRawDataset = AH_NULL; + const RAW_DATA_PER_CHANNEL_2413 *data = AH_NULL; + uint16_t numChannels; + int totalD,totalF, totalMin,last, i; + + *maxPow = 0; + + if (IS_CHAN_G(chan) || IS_CHAN_108G(chan)) + pRawDataset = &ee->ee_rawDataset2413[headerInfo11G]; + else if (IS_CHAN_B(chan)) + pRawDataset = &ee->ee_rawDataset2413[headerInfo11B]; + else + return(AH_FALSE); + + numChannels = pRawDataset->numChannels; + data = pRawDataset->pDataPerChannel; + + /* Make sure the channel is in the range of the TP values + * (freq piers) + */ + if (numChannels < 1) + return(AH_FALSE); + + if ((chan->channel < data[0].channelValue) || + (chan->channel > data[numChannels-1].channelValue)) { + if (chan->channel < data[0].channelValue) { + *maxPow = ar2413GetMaxPower(ah, &data[0]); + *minPow = ar2413GetMinPower(ah, &data[0]); + return(AH_TRUE); + } else { + *maxPow = ar2413GetMaxPower(ah, &data[numChannels - 1]); + *minPow = ar2413GetMinPower(ah, &data[numChannels - 1]); + return(AH_TRUE); + } + } + + /* Linearly interpolate the power value now */ + for (last=0,i=0; (ichannel > data[i].channelValue); + last = i++); + totalD = data[i].channelValue - data[last].channelValue; + if (totalD > 0) { + totalF = ar2413GetMaxPower(ah, &data[i]) - ar2413GetMaxPower(ah, &data[last]); + *maxPow = (int8_t) ((totalF*(chan->channel-data[last].channelValue) + + ar2413GetMaxPower(ah, &data[last])*totalD)/totalD); + totalMin = ar2413GetMinPower(ah, &data[i]) - ar2413GetMinPower(ah, &data[last]); + *minPow = (int8_t) ((totalMin*(chan->channel-data[last].channelValue) + + ar2413GetMinPower(ah, &data[last])*totalD)/totalD); + return(AH_TRUE); + } else { + if (chan->channel == data[i].channelValue) { + *maxPow = ar2413GetMaxPower(ah, &data[i]); + *minPow = ar2413GetMinPower(ah, &data[i]); + return(AH_TRUE); + } else + return(AH_FALSE); + } +} + +/* + * Free memory for analog bank scratch buffers + */ +static void +ar2413RfDetach(struct ath_hal *ah) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + + HALASSERT(ahp->ah_rfHal != AH_NULL); + ath_hal_free(ahp->ah_rfHal); + ahp->ah_rfHal = AH_NULL; +} + +/* + * Allocate memory for analog bank scratch buffers + * Scratch Buffer will be reinitialized every reset so no need to zero now + */ +static HAL_BOOL +ar2413RfAttach(struct ath_hal *ah, HAL_STATUS *status) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + struct ar2413State *priv; + + HALASSERT(ah->ah_magic == AR5212_MAGIC); + + HALASSERT(ahp->ah_rfHal == AH_NULL); + priv = ath_hal_malloc(sizeof(struct ar2413State)); + if (priv == AH_NULL) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: cannot allocate private state\n", __func__); + *status = HAL_ENOMEM; /* XXX */ + return AH_FALSE; + } + priv->base.rfDetach = ar2413RfDetach; + priv->base.writeRegs = ar2413WriteRegs; + priv->base.getRfBank = ar2413GetRfBank; + priv->base.setChannel = ar2413SetChannel; + priv->base.setRfRegs = ar2413SetRfRegs; + priv->base.setPowerTable = ar2413SetPowerTable; + priv->base.getChannelMaxMinPower = ar2413GetChannelMaxMinPower; + priv->base.getNfAdjust = ar5212GetNfAdjust; + + ahp->ah_pcdacTable = priv->pcdacTable; + ahp->ah_pcdacTableSize = sizeof(priv->pcdacTable); + ahp->ah_rfHal = &priv->base; + + return AH_TRUE; +} + +static HAL_BOOL +ar2413Probe(struct ath_hal *ah) +{ + return IS_2413(ah); +} +AH_RF(RF2413, ar2413Probe, ar2413RfAttach); --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5212/ar2425.c 2009-03-23 17:36:55.000000000 +0000 @@ -0,0 +1,722 @@ +/* + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2008 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ar2425.c,v 1.1 2009/03/23 17:14:47 sborrill Exp $ + */ +#include "opt_ah.h" + +#include "ah.h" +#include "ah_internal.h" + +#include "ar5212/ar5212.h" +#include "ar5212/ar5212reg.h" +#include "ar5212/ar5212phy.h" + +#include "ah_eeprom_v3.h" + +#define AH_5212_2425 +#define AH_5212_2417 +#include "ar5212/ar5212.ini" + +#define N(a) (sizeof(a)/sizeof(a[0])) + +struct ar2425State { + RF_HAL_FUNCS base; /* public state, must be first */ + uint16_t pcdacTable[PWR_TABLE_SIZE_2413]; + + uint32_t Bank1Data[N(ar5212Bank1_2425)]; + uint32_t Bank2Data[N(ar5212Bank2_2425)]; + uint32_t Bank3Data[N(ar5212Bank3_2425)]; + uint32_t Bank6Data[N(ar5212Bank6_2425)]; /* 2417 is same size */ + uint32_t Bank7Data[N(ar5212Bank7_2425)]; +}; +#define AR2425(ah) ((struct ar2425State *) AH5212(ah)->ah_rfHal) + +extern void ar5212ModifyRfBuffer(uint32_t *rfBuf, uint32_t reg32, + uint32_t numBits, uint32_t firstBit, uint32_t column); + +static void +ar2425WriteRegs(struct ath_hal *ah, u_int modesIndex, u_int freqIndex, + int writes) +{ + HAL_INI_WRITE_ARRAY(ah, ar5212Modes_2425, modesIndex, writes); + HAL_INI_WRITE_ARRAY(ah, ar5212Common_2425, 1, writes); + HAL_INI_WRITE_ARRAY(ah, ar5212BB_RfGain_2425, freqIndex, writes); +#if 0 + /* + * for SWAN similar to Condor + * Bit 0 enables link to go to L1 when MAC goes to sleep. + * Bit 3 enables the loop back the link down to reset. + */ + if (IS_PCIE(ah) && ath_hal_pcieL1SKPEnable) { + OS_REG_WRITE(ah, AR_PCIE_PMC, + AR_PCIE_PMC_ENA_L1 | AR_PCIE_PMC_ENA_RESET); + } + /* + * for Standby issue in Swan/Condor. + * Bit 9 (MAC_WOW_PWR_STATE_MASK_D2)to be set to avoid skips + * before last Training Sequence 2 (TS2) + * Bit 8 (MAC_WOW_PWR_STATE_MASK_D1)to be unset to assert + * Power Reset along with PCI Reset + */ + OS_REG_SET_BIT(ah, AR_PCIE_PMC, MAC_WOW_PWR_STATE_MASK_D2); +#endif +} + +/* + * Take the MHz channel value and set the Channel value + * + * ASSUMES: Writes enabled to analog bus + */ +static HAL_BOOL +ar2425SetChannel(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan) +{ + uint32_t channelSel = 0; + uint32_t bModeSynth = 0; + uint32_t aModeRefSel = 0; + uint32_t reg32 = 0; + uint16_t freq; + + OS_MARK(ah, AH_MARK_SETCHANNEL, chan->channel); + + if (chan->channel < 4800) { + uint32_t txctl; + + channelSel = chan->channel - 2272; + channelSel = ath_hal_reverseBits(channelSel, 8); + + txctl = OS_REG_READ(ah, AR_PHY_CCK_TX_CTRL); + if (chan->channel == 2484) { + // Enable channel spreading for channel 14 + OS_REG_WRITE(ah, AR_PHY_CCK_TX_CTRL, + txctl | AR_PHY_CCK_TX_CTRL_JAPAN); + } else { + OS_REG_WRITE(ah, AR_PHY_CCK_TX_CTRL, + txctl &~ AR_PHY_CCK_TX_CTRL_JAPAN); + } + + } else if (((chan->channel % 5) == 2) && (chan->channel <= 5435)) { + freq = chan->channel - 2; /* Align to even 5MHz raster */ + channelSel = ath_hal_reverseBits( + (uint32_t)(((freq - 4800)*10)/25 + 1), 8); + aModeRefSel = ath_hal_reverseBits(0, 2); + } else if ((chan->channel % 20) == 0 && chan->channel >= 5120) { + channelSel = ath_hal_reverseBits( + ((chan->channel - 4800) / 20 << 2), 8); + aModeRefSel = ath_hal_reverseBits(1, 2); + } else if ((chan->channel % 10) == 0) { + channelSel = ath_hal_reverseBits( + ((chan->channel - 4800) / 10 << 1), 8); + aModeRefSel = ath_hal_reverseBits(1, 2); + } else if ((chan->channel % 5) == 0) { + channelSel = ath_hal_reverseBits( + (chan->channel - 4800) / 5, 8); + aModeRefSel = ath_hal_reverseBits(1, 2); + } else { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel %u MHz\n", + __func__, chan->channel); + return AH_FALSE; + } + + reg32 = (channelSel << 4) | (aModeRefSel << 2) | (bModeSynth << 1) | + (1 << 12) | 0x1; + OS_REG_WRITE(ah, AR_PHY(0x27), reg32 & 0xff); + + reg32 >>= 8; + OS_REG_WRITE(ah, AR_PHY(0x36), reg32 & 0x7f); + + AH_PRIVATE(ah)->ah_curchan = chan; + return AH_TRUE; +} + +/* + * Reads EEPROM header info from device structure and programs + * all rf registers + * + * REQUIRES: Access to the analog rf device + */ +static HAL_BOOL +ar2425SetRfRegs(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan, uint16_t modesIndex, uint16_t *rfXpdGain) +{ +#define RF_BANK_SETUP(_priv, _ix, _col) do { \ + int i; \ + for (i = 0; i < N(ar5212Bank##_ix##_2425); i++) \ + (_priv)->Bank##_ix##Data[i] = ar5212Bank##_ix##_2425[i][_col];\ +} while (0) + struct ath_hal_5212 *ahp = AH5212(ah); + const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom; + struct ar2425State *priv = AR2425(ah); + uint16_t ob2GHz = 0, db2GHz = 0; + int regWrites = 0; + + HALDEBUG(ah, HAL_DEBUG_RFPARAM, + "==>%s:chan 0x%x flag 0x%x modesIndex 0x%x\n", + __func__, chan->channel, chan->channelFlags, modesIndex); + + HALASSERT(priv); + + /* Setup rf parameters */ + switch (chan->channelFlags & CHANNEL_ALL) { + case CHANNEL_B: + ob2GHz = ee->ee_obFor24; + db2GHz = ee->ee_dbFor24; + break; + case CHANNEL_G: + case CHANNEL_108G: + ob2GHz = ee->ee_obFor24g; + db2GHz = ee->ee_dbFor24g; + break; + default: + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel flags 0x%x\n", + __func__, chan->channelFlags); + return AH_FALSE; + } + + /* Bank 1 Write */ + RF_BANK_SETUP(priv, 1, 1); + + /* Bank 2 Write */ + RF_BANK_SETUP(priv, 2, modesIndex); + + /* Bank 3 Write */ + RF_BANK_SETUP(priv, 3, modesIndex); + + /* Bank 6 Write */ + RF_BANK_SETUP(priv, 6, modesIndex); + + ar5212ModifyRfBuffer(priv->Bank6Data, ob2GHz, 3, 193, 0); + ar5212ModifyRfBuffer(priv->Bank6Data, db2GHz, 3, 190, 0); + + /* Bank 7 Setup */ + RF_BANK_SETUP(priv, 7, modesIndex); + + /* Write Analog registers */ + HAL_INI_WRITE_BANK(ah, ar5212Bank1_2425, priv->Bank1Data, regWrites); + HAL_INI_WRITE_BANK(ah, ar5212Bank2_2425, priv->Bank2Data, regWrites); + HAL_INI_WRITE_BANK(ah, ar5212Bank3_2425, priv->Bank3Data, regWrites); + if (IS_2417(ah)) { + HALASSERT(N(ar5212Bank6_2425) == N(ar5212Bank6_2417)); + HAL_INI_WRITE_BANK(ah, ar5212Bank6_2417, priv->Bank6Data, + regWrites); + } else + HAL_INI_WRITE_BANK(ah, ar5212Bank6_2425, priv->Bank6Data, + regWrites); + HAL_INI_WRITE_BANK(ah, ar5212Bank7_2425, priv->Bank7Data, regWrites); + + /* Now that we have reprogrammed rfgain value, clear the flag. */ + ahp->ah_rfgainState = HAL_RFGAIN_INACTIVE; + + HALDEBUG(ah, HAL_DEBUG_RFPARAM, "<==%s\n", __func__); + return AH_TRUE; +#undef RF_BANK_SETUP +} + +/* + * Return a reference to the requested RF Bank. + */ +static uint32_t * +ar2425GetRfBank(struct ath_hal *ah, int bank) +{ + struct ar2425State *priv = AR2425(ah); + + HALASSERT(priv != AH_NULL); + switch (bank) { + case 1: return priv->Bank1Data; + case 2: return priv->Bank2Data; + case 3: return priv->Bank3Data; + case 6: return priv->Bank6Data; + case 7: return priv->Bank7Data; + } + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unknown RF Bank %d requested\n", + __func__, bank); + return AH_NULL; +} + +/* + * Return indices surrounding the value in sorted integer lists. + * + * NB: the input list is assumed to be sorted in ascending order + */ +static void +GetLowerUpperIndex(int16_t v, const uint16_t *lp, uint16_t listSize, + uint32_t *vlo, uint32_t *vhi) +{ + int16_t target = v; + const uint16_t *ep = lp+listSize; + const uint16_t *tp; + + /* + * Check first and last elements for out-of-bounds conditions. + */ + if (target < lp[0]) { + *vlo = *vhi = 0; + return; + } + if (target >= ep[-1]) { + *vlo = *vhi = listSize - 1; + return; + } + + /* look for value being near or between 2 values in list */ + for (tp = lp; tp < ep; tp++) { + /* + * If value is close to the current value of the list + * then target is not between values, it is one of the values + */ + if (*tp == target) { + *vlo = *vhi = tp - (const uint16_t *) lp; + return; + } + /* + * Look for value being between current value and next value + * if so return these 2 values + */ + if (target < tp[1]) { + *vlo = tp - (const uint16_t *) lp; + *vhi = *vlo + 1; + return; + } + } +} + +/* + * Fill the Vpdlist for indices Pmax-Pmin + */ +static HAL_BOOL +ar2425FillVpdTable(uint32_t pdGainIdx, int16_t Pmin, int16_t Pmax, + const int16_t *pwrList, const uint16_t *VpdList, + uint16_t numIntercepts, + uint16_t retVpdList[][64]) +{ + uint16_t ii, jj, kk; + int16_t currPwr = (int16_t)(2*Pmin); + /* since Pmin is pwr*2 and pwrList is 4*pwr */ + uint32_t idxL = 0, idxR = 0; + + ii = 0; + jj = 0; + + if (numIntercepts < 2) + return AH_FALSE; + + while (ii <= (uint16_t)(Pmax - Pmin)) { + GetLowerUpperIndex(currPwr, (const uint16_t *) pwrList, + numIntercepts, &(idxL), &(idxR)); + if (idxR < 1) + idxR = 1; /* extrapolate below */ + if (idxL == (uint32_t)(numIntercepts - 1)) + idxL = numIntercepts - 2; /* extrapolate above */ + if (pwrList[idxL] == pwrList[idxR]) + kk = VpdList[idxL]; + else + kk = (uint16_t) + (((currPwr - pwrList[idxL])*VpdList[idxR]+ + (pwrList[idxR] - currPwr)*VpdList[idxL])/ + (pwrList[idxR] - pwrList[idxL])); + retVpdList[pdGainIdx][ii] = kk; + ii++; + currPwr += 2; /* half dB steps */ + } + + return AH_TRUE; +} + +/* + * Returns interpolated or the scaled up interpolated value + */ +static int16_t +interpolate_signed(uint16_t target, uint16_t srcLeft, uint16_t srcRight, + int16_t targetLeft, int16_t targetRight) +{ + int16_t rv; + + if (srcRight != srcLeft) { + rv = ((target - srcLeft)*targetRight + + (srcRight - target)*targetLeft) / (srcRight - srcLeft); + } else { + rv = targetLeft; + } + return rv; +} + +/* + * Uses the data points read from EEPROM to reconstruct the pdadc power table + * Called by ar2425SetPowerTable() + */ +static void +ar2425getGainBoundariesAndPdadcsForPowers(struct ath_hal *ah, uint16_t channel, + const RAW_DATA_STRUCT_2413 *pRawDataset, + uint16_t pdGainOverlap_t2, + int16_t *pMinCalPower, uint16_t pPdGainBoundaries[], + uint16_t pPdGainValues[], uint16_t pPDADCValues[]) +{ + /* Note the items statically allocated below are to reduce stack usage */ + uint32_t ii, jj, kk; + int32_t ss;/* potentially -ve index for taking care of pdGainOverlap */ + uint32_t idxL = 0, idxR = 0; + uint32_t numPdGainsUsed = 0; + static uint16_t VpdTable_L[MAX_NUM_PDGAINS_PER_CHANNEL][MAX_PWR_RANGE_IN_HALF_DB]; + /* filled out Vpd table for all pdGains (chanL) */ + static uint16_t VpdTable_R[MAX_NUM_PDGAINS_PER_CHANNEL][MAX_PWR_RANGE_IN_HALF_DB]; + /* filled out Vpd table for all pdGains (chanR) */ + static uint16_t VpdTable_I[MAX_NUM_PDGAINS_PER_CHANNEL][MAX_PWR_RANGE_IN_HALF_DB]; + /* filled out Vpd table for all pdGains (interpolated) */ + /* + * If desired to support -ve power levels in future, just + * change pwr_I_0 to signed 5-bits. + */ + static int16_t Pmin_t2[MAX_NUM_PDGAINS_PER_CHANNEL]; + /* to accomodate -ve power levels later on. */ + static int16_t Pmax_t2[MAX_NUM_PDGAINS_PER_CHANNEL]; + /* to accomodate -ve power levels later on */ + uint16_t numVpd = 0; + uint16_t Vpd_step; + int16_t tmpVal ; + uint32_t sizeCurrVpdTable, maxIndex, tgtIndex; + + HALDEBUG(ah, HAL_DEBUG_RFPARAM, "==>%s:\n", __func__); + + /* Get upper lower index */ + GetLowerUpperIndex(channel, pRawDataset->pChannels, + pRawDataset->numChannels, &(idxL), &(idxR)); + + for (ii = 0; ii < MAX_NUM_PDGAINS_PER_CHANNEL; ii++) { + jj = MAX_NUM_PDGAINS_PER_CHANNEL - ii - 1; + /* work backwards 'cause highest pdGain for lowest power */ + numVpd = pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].numVpd; + if (numVpd > 0) { + pPdGainValues[numPdGainsUsed] = pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].pd_gain; + Pmin_t2[numPdGainsUsed] = pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].pwr_t4[0]; + if (Pmin_t2[numPdGainsUsed] >pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].pwr_t4[0]) { + Pmin_t2[numPdGainsUsed] = pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].pwr_t4[0]; + } + Pmin_t2[numPdGainsUsed] = (int16_t) + (Pmin_t2[numPdGainsUsed] / 2); + Pmax_t2[numPdGainsUsed] = pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].pwr_t4[numVpd-1]; + if (Pmax_t2[numPdGainsUsed] > pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].pwr_t4[numVpd-1]) + Pmax_t2[numPdGainsUsed] = + pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].pwr_t4[numVpd-1]; + Pmax_t2[numPdGainsUsed] = (int16_t)(Pmax_t2[numPdGainsUsed] / 2); + ar2425FillVpdTable( + numPdGainsUsed, Pmin_t2[numPdGainsUsed], Pmax_t2[numPdGainsUsed], + &(pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].pwr_t4[0]), + &(pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].Vpd[0]), numVpd, VpdTable_L + ); + ar2425FillVpdTable( + numPdGainsUsed, Pmin_t2[numPdGainsUsed], Pmax_t2[numPdGainsUsed], + &(pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].pwr_t4[0]), + &(pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].Vpd[0]), numVpd, VpdTable_R + ); + for (kk = 0; kk < (uint16_t)(Pmax_t2[numPdGainsUsed] - Pmin_t2[numPdGainsUsed]); kk++) { + VpdTable_I[numPdGainsUsed][kk] = + interpolate_signed( + channel, pRawDataset->pChannels[idxL], pRawDataset->pChannels[idxR], + (int16_t)VpdTable_L[numPdGainsUsed][kk], (int16_t)VpdTable_R[numPdGainsUsed][kk]); + } + /* fill VpdTable_I for this pdGain */ + numPdGainsUsed++; + } + /* if this pdGain is used */ + } + + *pMinCalPower = Pmin_t2[0]; + kk = 0; /* index for the final table */ + for (ii = 0; ii < numPdGainsUsed; ii++) { + if (ii == (numPdGainsUsed - 1)) + pPdGainBoundaries[ii] = Pmax_t2[ii] + + PD_GAIN_BOUNDARY_STRETCH_IN_HALF_DB; + else + pPdGainBoundaries[ii] = (uint16_t) + ((Pmax_t2[ii] + Pmin_t2[ii+1]) / 2 ); + + /* Find starting index for this pdGain */ + if (ii == 0) + ss = 0; /* for the first pdGain, start from index 0 */ + else + ss = (pPdGainBoundaries[ii-1] - Pmin_t2[ii]) - + pdGainOverlap_t2; + Vpd_step = (uint16_t)(VpdTable_I[ii][1] - VpdTable_I[ii][0]); + Vpd_step = (uint16_t)((Vpd_step < 1) ? 1 : Vpd_step); + /* + *-ve ss indicates need to extrapolate data below for this pdGain + */ + while (ss < 0) { + tmpVal = (int16_t)(VpdTable_I[ii][0] + ss*Vpd_step); + pPDADCValues[kk++] = (uint16_t)((tmpVal < 0) ? 0 : tmpVal); + ss++; + } + + sizeCurrVpdTable = Pmax_t2[ii] - Pmin_t2[ii]; + tgtIndex = pPdGainBoundaries[ii] + pdGainOverlap_t2 - Pmin_t2[ii]; + maxIndex = (tgtIndex < sizeCurrVpdTable) ? tgtIndex : sizeCurrVpdTable; + + while (ss < (int16_t)maxIndex) + pPDADCValues[kk++] = VpdTable_I[ii][ss++]; + + Vpd_step = (uint16_t)(VpdTable_I[ii][sizeCurrVpdTable-1] - + VpdTable_I[ii][sizeCurrVpdTable-2]); + Vpd_step = (uint16_t)((Vpd_step < 1) ? 1 : Vpd_step); + /* + * for last gain, pdGainBoundary == Pmax_t2, so will + * have to extrapolate + */ + if (tgtIndex > maxIndex) { /* need to extrapolate above */ + while(ss < (int16_t)tgtIndex) { + tmpVal = (uint16_t) + (VpdTable_I[ii][sizeCurrVpdTable-1] + + (ss-maxIndex)*Vpd_step); + pPDADCValues[kk++] = (tmpVal > 127) ? + 127 : tmpVal; + ss++; + } + } /* extrapolated above */ + } /* for all pdGainUsed */ + + while (ii < MAX_NUM_PDGAINS_PER_CHANNEL) { + pPdGainBoundaries[ii] = pPdGainBoundaries[ii-1]; + ii++; + } + while (kk < 128) { + pPDADCValues[kk] = pPDADCValues[kk-1]; + kk++; + } + + HALDEBUG(ah, HAL_DEBUG_RFPARAM, "<==%s\n", __func__); +} + + +/* Same as 2413 set power table */ +static HAL_BOOL +ar2425SetPowerTable(struct ath_hal *ah, + int16_t *minPower, int16_t *maxPower, HAL_CHANNEL_INTERNAL *chan, + uint16_t *rfXpdGain) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom; + const RAW_DATA_STRUCT_2413 *pRawDataset = AH_NULL; + uint16_t pdGainOverlap_t2; + int16_t minCalPower2413_t2; + uint16_t *pdadcValues = ahp->ah_pcdacTable; + uint16_t gainBoundaries[4]; + uint32_t i, reg32, regoffset; + + HALDEBUG(ah, HAL_DEBUG_RFPARAM, "%s:chan 0x%x flag 0x%x\n", + __func__, chan->channel,chan->channelFlags); + + if (IS_CHAN_G(chan) || IS_CHAN_108G(chan)) + pRawDataset = &ee->ee_rawDataset2413[headerInfo11G]; + else if (IS_CHAN_B(chan)) + pRawDataset = &ee->ee_rawDataset2413[headerInfo11B]; + else { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s:illegal mode\n", __func__); + return AH_FALSE; + } + + pdGainOverlap_t2 = (uint16_t) SM(OS_REG_READ(ah, AR_PHY_TPCRG5), + AR_PHY_TPCRG5_PD_GAIN_OVERLAP); + + ar2425getGainBoundariesAndPdadcsForPowers(ah, chan->channel, + pRawDataset, pdGainOverlap_t2,&minCalPower2413_t2,gainBoundaries, + rfXpdGain, pdadcValues); + + OS_REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN, + (pRawDataset->pDataPerChannel[0].numPdGains - 1)); + + /* + * Note the pdadc table may not start at 0 dBm power, could be + * negative or greater than 0. Need to offset the power + * values by the amount of minPower for griffin + */ + if (minCalPower2413_t2 != 0) + ahp->ah_txPowerIndexOffset = (int16_t)(0 - minCalPower2413_t2); + else + ahp->ah_txPowerIndexOffset = 0; + + /* Finally, write the power values into the baseband power table */ + regoffset = 0x9800 + (672 <<2); /* beginning of pdadc table in griffin */ + for (i = 0; i < 32; i++) { + reg32 = ((pdadcValues[4*i + 0] & 0xFF) << 0) | + ((pdadcValues[4*i + 1] & 0xFF) << 8) | + ((pdadcValues[4*i + 2] & 0xFF) << 16) | + ((pdadcValues[4*i + 3] & 0xFF) << 24) ; + OS_REG_WRITE(ah, regoffset, reg32); + regoffset += 4; + } + + OS_REG_WRITE(ah, AR_PHY_TPCRG5, + SM(pdGainOverlap_t2, AR_PHY_TPCRG5_PD_GAIN_OVERLAP) | + SM(gainBoundaries[0], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1) | + SM(gainBoundaries[1], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2) | + SM(gainBoundaries[2], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3) | + SM(gainBoundaries[3], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4)); + + return AH_TRUE; +} + +static int16_t +ar2425GetMinPower(struct ath_hal *ah, const RAW_DATA_PER_CHANNEL_2413 *data) +{ + uint32_t ii,jj; + uint16_t Pmin=0,numVpd; + + for (ii = 0; ii < MAX_NUM_PDGAINS_PER_CHANNEL; ii++) { + jj = MAX_NUM_PDGAINS_PER_CHANNEL - ii - 1; + /* work backwards 'cause highest pdGain for lowest power */ + numVpd = data->pDataPerPDGain[jj].numVpd; + if (numVpd > 0) { + Pmin = data->pDataPerPDGain[jj].pwr_t4[0]; + return(Pmin); + } + } + return(Pmin); +} + +static int16_t +ar2425GetMaxPower(struct ath_hal *ah, const RAW_DATA_PER_CHANNEL_2413 *data) +{ + uint32_t ii; + uint16_t Pmax=0,numVpd; + + for (ii=0; ii< MAX_NUM_PDGAINS_PER_CHANNEL; ii++) { + /* work forwards cuase lowest pdGain for highest power */ + numVpd = data->pDataPerPDGain[ii].numVpd; + if (numVpd > 0) { + Pmax = data->pDataPerPDGain[ii].pwr_t4[numVpd-1]; + return(Pmax); + } + } + return(Pmax); +} + +static +HAL_BOOL +ar2425GetChannelMaxMinPower(struct ath_hal *ah, HAL_CHANNEL *chan, + int16_t *maxPow, int16_t *minPow) +{ + const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom; + const RAW_DATA_STRUCT_2413 *pRawDataset = AH_NULL; + const RAW_DATA_PER_CHANNEL_2413 *data = AH_NULL; + uint16_t numChannels; + int totalD,totalF, totalMin,last, i; + + *maxPow = 0; + + if (IS_CHAN_G(chan) || IS_CHAN_108G(chan)) + pRawDataset = &ee->ee_rawDataset2413[headerInfo11G]; + else if (IS_CHAN_B(chan)) + pRawDataset = &ee->ee_rawDataset2413[headerInfo11B]; + else + return(AH_FALSE); + + numChannels = pRawDataset->numChannels; + data = pRawDataset->pDataPerChannel; + + /* Make sure the channel is in the range of the TP values + * (freq piers) + */ + if (numChannels < 1) + return(AH_FALSE); + + if ((chan->channel < data[0].channelValue) || + (chan->channel > data[numChannels-1].channelValue)) { + if (chan->channel < data[0].channelValue) { + *maxPow = ar2425GetMaxPower(ah, &data[0]); + *minPow = ar2425GetMinPower(ah, &data[0]); + return(AH_TRUE); + } else { + *maxPow = ar2425GetMaxPower(ah, &data[numChannels - 1]); + *minPow = ar2425GetMinPower(ah, &data[numChannels - 1]); + return(AH_TRUE); + } + } + + /* Linearly interpolate the power value now */ + for (last=0,i=0; (ichannel > data[i].channelValue); + last = i++); + totalD = data[i].channelValue - data[last].channelValue; + if (totalD > 0) { + totalF = ar2425GetMaxPower(ah, &data[i]) - ar2425GetMaxPower(ah, &data[last]); + *maxPow = (int8_t) ((totalF*(chan->channel-data[last].channelValue) + + ar2425GetMaxPower(ah, &data[last])*totalD)/totalD); + totalMin = ar2425GetMinPower(ah, &data[i]) - ar2425GetMinPower(ah, &data[last]); + *minPow = (int8_t) ((totalMin*(chan->channel-data[last].channelValue) + + ar2425GetMinPower(ah, &data[last])*totalD)/totalD); + return(AH_TRUE); + } else { + if (chan->channel == data[i].channelValue) { + *maxPow = ar2425GetMaxPower(ah, &data[i]); + *minPow = ar2425GetMinPower(ah, &data[i]); + return(AH_TRUE); + } else + return(AH_FALSE); + } +} + +/* + * Free memory for analog bank scratch buffers + */ +static void +ar2425RfDetach(struct ath_hal *ah) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + + HALASSERT(ahp->ah_rfHal != AH_NULL); + ath_hal_free(ahp->ah_rfHal); + ahp->ah_rfHal = AH_NULL; +} + +/* + * Allocate memory for analog bank scratch buffers + * Scratch Buffer will be reinitialized every reset so no need to zero now + */ +static HAL_BOOL +ar2425RfAttach(struct ath_hal *ah, HAL_STATUS *status) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + struct ar2425State *priv; + + HALASSERT(ah->ah_magic == AR5212_MAGIC); + + HALASSERT(ahp->ah_rfHal == AH_NULL); + priv = ath_hal_malloc(sizeof(struct ar2425State)); + if (priv == AH_NULL) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: cannot allocate private state\n", __func__); + *status = HAL_ENOMEM; /* XXX */ + return AH_FALSE; + } + priv->base.rfDetach = ar2425RfDetach; + priv->base.writeRegs = ar2425WriteRegs; + priv->base.getRfBank = ar2425GetRfBank; + priv->base.setChannel = ar2425SetChannel; + priv->base.setRfRegs = ar2425SetRfRegs; + priv->base.setPowerTable = ar2425SetPowerTable; + priv->base.getChannelMaxMinPower = ar2425GetChannelMaxMinPower; + priv->base.getNfAdjust = ar5212GetNfAdjust; + + ahp->ah_pcdacTable = priv->pcdacTable; + ahp->ah_pcdacTableSize = sizeof(priv->pcdacTable); + ahp->ah_rfHal = &priv->base; + + return AH_TRUE; +} + +static HAL_BOOL +ar2425Probe(struct ath_hal *ah) +{ + return IS_2425(ah) || IS_2417(ah); +} +AH_RF(RF2425, ar2425Probe, ar2425RfAttach); --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5212/ar5111.c 2009-03-23 17:36:55.000000000 +0000 @@ -0,0 +1,711 @@ +/* + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2008 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ar5111.c,v 1.1 2009/03/23 17:14:47 sborrill Exp $ + */ +#include "opt_ah.h" + +#include "ah.h" +#include "ah_internal.h" + +#include "ah_eeprom_v3.h" + +#include "ar5212/ar5212.h" +#include "ar5212/ar5212reg.h" +#include "ar5212/ar5212phy.h" + +#define AH_5212_5111 +#include "ar5212/ar5212.ini" + +#define N(a) (sizeof(a)/sizeof(a[0])) + +struct ar5111State { + RF_HAL_FUNCS base; /* public state, must be first */ + uint16_t pcdacTable[PWR_TABLE_SIZE]; + + uint32_t Bank0Data[N(ar5212Bank0_5111)]; + uint32_t Bank1Data[N(ar5212Bank1_5111)]; + uint32_t Bank2Data[N(ar5212Bank2_5111)]; + uint32_t Bank3Data[N(ar5212Bank3_5111)]; + uint32_t Bank6Data[N(ar5212Bank6_5111)]; + uint32_t Bank7Data[N(ar5212Bank7_5111)]; +}; +#define AR5111(ah) ((struct ar5111State *) AH5212(ah)->ah_rfHal) + +static uint16_t ar5212GetScaledPower(uint16_t channel, uint16_t pcdacValue, + const PCDACS_EEPROM *pSrcStruct); +static HAL_BOOL ar5212FindValueInList(uint16_t channel, uint16_t pcdacValue, + const PCDACS_EEPROM *pSrcStruct, uint16_t *powerValue); +static void ar5212GetLowerUpperPcdacs(uint16_t pcdac, uint16_t channel, + const PCDACS_EEPROM *pSrcStruct, + uint16_t *pLowerPcdac, uint16_t *pUpperPcdac); + +extern void ar5212GetLowerUpperValues(uint16_t value, + const uint16_t *pList, uint16_t listSize, + uint16_t *pLowerValue, uint16_t *pUpperValue); +extern void ar5212ModifyRfBuffer(uint32_t *rfBuf, uint32_t reg32, + uint32_t numBits, uint32_t firstBit, uint32_t column); + +static void +ar5111WriteRegs(struct ath_hal *ah, u_int modesIndex, u_int freqIndex, + int writes) +{ + HAL_INI_WRITE_ARRAY(ah, ar5212Modes_5111, modesIndex, writes); + HAL_INI_WRITE_ARRAY(ah, ar5212Common_5111, 1, writes); + HAL_INI_WRITE_ARRAY(ah, ar5212BB_RfGain_5111, freqIndex, writes); +} + +/* + * Take the MHz channel value and set the Channel value + * + * ASSUMES: Writes enabled to analog bus + */ +static HAL_BOOL +ar5111SetChannel(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan) +{ +#define CI_2GHZ_INDEX_CORRECTION 19 + uint32_t refClk, reg32, data2111; + int16_t chan5111, chanIEEE; + + /* + * Structure to hold 11b tuning information for 5111/2111 + * 16 MHz mode, divider ratio = 198 = NP+S. N=16, S=4 or 6, P=12 + */ + typedef struct { + uint32_t refClkSel; /* reference clock, 1 for 16 MHz */ + uint32_t channelSelect; /* P[7:4]S[3:0] bits */ + uint16_t channel5111; /* 11a channel for 5111 */ + } CHAN_INFO_2GHZ; + + static const CHAN_INFO_2GHZ chan2GHzData[] = { + { 1, 0x46, 96 }, /* 2312 -19 */ + { 1, 0x46, 97 }, /* 2317 -18 */ + { 1, 0x46, 98 }, /* 2322 -17 */ + { 1, 0x46, 99 }, /* 2327 -16 */ + { 1, 0x46, 100 }, /* 2332 -15 */ + { 1, 0x46, 101 }, /* 2337 -14 */ + { 1, 0x46, 102 }, /* 2342 -13 */ + { 1, 0x46, 103 }, /* 2347 -12 */ + { 1, 0x46, 104 }, /* 2352 -11 */ + { 1, 0x46, 105 }, /* 2357 -10 */ + { 1, 0x46, 106 }, /* 2362 -9 */ + { 1, 0x46, 107 }, /* 2367 -8 */ + { 1, 0x46, 108 }, /* 2372 -7 */ + /* index -6 to 0 are pad to make this a nolookup table */ + { 1, 0x46, 116 }, /* -6 */ + { 1, 0x46, 116 }, /* -5 */ + { 1, 0x46, 116 }, /* -4 */ + { 1, 0x46, 116 }, /* -3 */ + { 1, 0x46, 116 }, /* -2 */ + { 1, 0x46, 116 }, /* -1 */ + { 1, 0x46, 116 }, /* 0 */ + { 1, 0x46, 116 }, /* 2412 1 */ + { 1, 0x46, 117 }, /* 2417 2 */ + { 1, 0x46, 118 }, /* 2422 3 */ + { 1, 0x46, 119 }, /* 2427 4 */ + { 1, 0x46, 120 }, /* 2432 5 */ + { 1, 0x46, 121 }, /* 2437 6 */ + { 1, 0x46, 122 }, /* 2442 7 */ + { 1, 0x46, 123 }, /* 2447 8 */ + { 1, 0x46, 124 }, /* 2452 9 */ + { 1, 0x46, 125 }, /* 2457 10 */ + { 1, 0x46, 126 }, /* 2462 11 */ + { 1, 0x46, 127 }, /* 2467 12 */ + { 1, 0x46, 128 }, /* 2472 13 */ + { 1, 0x44, 124 }, /* 2484 14 */ + { 1, 0x46, 136 }, /* 2512 15 */ + { 1, 0x46, 140 }, /* 2532 16 */ + { 1, 0x46, 144 }, /* 2552 17 */ + { 1, 0x46, 148 }, /* 2572 18 */ + { 1, 0x46, 152 }, /* 2592 19 */ + { 1, 0x46, 156 }, /* 2612 20 */ + { 1, 0x46, 160 }, /* 2632 21 */ + { 1, 0x46, 164 }, /* 2652 22 */ + { 1, 0x46, 168 }, /* 2672 23 */ + { 1, 0x46, 172 }, /* 2692 24 */ + { 1, 0x46, 176 }, /* 2712 25 */ + { 1, 0x46, 180 } /* 2732 26 */ + }; + + OS_MARK(ah, AH_MARK_SETCHANNEL, chan->channel); + + chanIEEE = ath_hal_mhz2ieee(ah, chan->channel, chan->channelFlags); + if (IS_CHAN_2GHZ(chan)) { + const CHAN_INFO_2GHZ* ci = + &chan2GHzData[chanIEEE + CI_2GHZ_INDEX_CORRECTION]; + uint32_t txctl; + + data2111 = ((ath_hal_reverseBits(ci->channelSelect, 8) & 0xff) + << 5) + | (ci->refClkSel << 4); + chan5111 = ci->channel5111; + txctl = OS_REG_READ(ah, AR_PHY_CCK_TX_CTRL); + if (chan->channel == 2484) { + /* Enable channel spreading for channel 14 */ + OS_REG_WRITE(ah, AR_PHY_CCK_TX_CTRL, + txctl | AR_PHY_CCK_TX_CTRL_JAPAN); + } else { + OS_REG_WRITE(ah, AR_PHY_CCK_TX_CTRL, + txctl &~ AR_PHY_CCK_TX_CTRL_JAPAN); + } + } else { + chan5111 = chanIEEE; /* no conversion needed */ + data2111 = 0; + } + + /* Rest of the code is common for 5 GHz and 2.4 GHz. */ + if (chan5111 >= 145 || (chan5111 & 0x1)) { + reg32 = ath_hal_reverseBits(chan5111 - 24, 8) & 0xff; + refClk = 1; + } else { + reg32 = ath_hal_reverseBits(((chan5111 - 24)/2), 8) & 0xff; + refClk = 0; + } + + reg32 = (reg32 << 2) | (refClk << 1) | (1 << 10) | 0x1; + OS_REG_WRITE(ah, AR_PHY(0x27), ((data2111 & 0xff) << 8) | (reg32 & 0xff)); + reg32 >>= 8; + OS_REG_WRITE(ah, AR_PHY(0x34), (data2111 & 0xff00) | (reg32 & 0xff)); + + AH_PRIVATE(ah)->ah_curchan = chan; + return AH_TRUE; +#undef CI_2GHZ_INDEX_CORRECTION +} + +/* + * Return a reference to the requested RF Bank. + */ +static uint32_t * +ar5111GetRfBank(struct ath_hal *ah, int bank) +{ + struct ar5111State *priv = AR5111(ah); + + HALASSERT(priv != AH_NULL); + switch (bank) { + case 0: return priv->Bank0Data; + case 1: return priv->Bank1Data; + case 2: return priv->Bank2Data; + case 3: return priv->Bank3Data; + case 6: return priv->Bank6Data; + case 7: return priv->Bank7Data; + } + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unknown RF Bank %d requested\n", + __func__, bank); + return AH_NULL; +} + +/* + * Reads EEPROM header info from device structure and programs + * all rf registers + * + * REQUIRES: Access to the analog rf device + */ +static HAL_BOOL +ar5111SetRfRegs(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan, + uint16_t modesIndex, uint16_t *rfXpdGain) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom; + uint16_t rfXpdGainFixed, rfPloSel, rfPwdXpd, gainI; + uint16_t tempOB, tempDB; + uint32_t ob2GHz, db2GHz, rfReg[N(ar5212Bank6_5111)]; + int i, regWrites = 0; + + /* Setup rf parameters */ + switch (chan->channelFlags & CHANNEL_ALL) { + case CHANNEL_A: + case CHANNEL_T: + if (4000 < chan->channel && chan->channel < 5260) { + tempOB = ee->ee_ob1; + tempDB = ee->ee_db1; + } else if (5260 <= chan->channel && chan->channel < 5500) { + tempOB = ee->ee_ob2; + tempDB = ee->ee_db2; + } else if (5500 <= chan->channel && chan->channel < 5725) { + tempOB = ee->ee_ob3; + tempDB = ee->ee_db3; + } else if (chan->channel >= 5725) { + tempOB = ee->ee_ob4; + tempDB = ee->ee_db4; + } else { + /* XXX when does this happen??? */ + tempOB = tempDB = 0; + } + ob2GHz = db2GHz = 0; + + rfXpdGainFixed = ee->ee_xgain[headerInfo11A]; + rfPloSel = ee->ee_xpd[headerInfo11A]; + rfPwdXpd = !ee->ee_xpd[headerInfo11A]; + gainI = ee->ee_gainI[headerInfo11A]; + break; + case CHANNEL_B: + tempOB = ee->ee_obFor24; + tempDB = ee->ee_dbFor24; + ob2GHz = ee->ee_ob2GHz[0]; + db2GHz = ee->ee_db2GHz[0]; + + rfXpdGainFixed = ee->ee_xgain[headerInfo11B]; + rfPloSel = ee->ee_xpd[headerInfo11B]; + rfPwdXpd = !ee->ee_xpd[headerInfo11B]; + gainI = ee->ee_gainI[headerInfo11B]; + break; + case CHANNEL_G: + tempOB = ee->ee_obFor24g; + tempDB = ee->ee_dbFor24g; + ob2GHz = ee->ee_ob2GHz[1]; + db2GHz = ee->ee_db2GHz[1]; + + rfXpdGainFixed = ee->ee_xgain[headerInfo11G]; + rfPloSel = ee->ee_xpd[headerInfo11G]; + rfPwdXpd = !ee->ee_xpd[headerInfo11G]; + gainI = ee->ee_gainI[headerInfo11G]; + break; + default: + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel flags 0x%x\n", + __func__, chan->channelFlags); + return AH_FALSE; + } + + HALASSERT(1 <= tempOB && tempOB <= 5); + HALASSERT(1 <= tempDB && tempDB <= 5); + + /* Bank 0 Write */ + for (i = 0; i < N(ar5212Bank0_5111); i++) + rfReg[i] = ar5212Bank0_5111[i][modesIndex]; + if (IS_CHAN_2GHZ(chan)) { + ar5212ModifyRfBuffer(rfReg, ob2GHz, 3, 119, 0); + ar5212ModifyRfBuffer(rfReg, db2GHz, 3, 122, 0); + } + HAL_INI_WRITE_BANK(ah, ar5212Bank0_5111, rfReg, regWrites); + + /* Bank 1 Write */ + HAL_INI_WRITE_ARRAY(ah, ar5212Bank1_5111, 1, regWrites); + + /* Bank 2 Write */ + HAL_INI_WRITE_ARRAY(ah, ar5212Bank2_5111, modesIndex, regWrites); + + /* Bank 3 Write */ + HAL_INI_WRITE_ARRAY(ah, ar5212Bank3_5111, modesIndex, regWrites); + + /* Bank 6 Write */ + for (i = 0; i < N(ar5212Bank6_5111); i++) + rfReg[i] = ar5212Bank6_5111[i][modesIndex]; + if (IS_CHAN_A(chan)) { /* NB: CHANNEL_A | CHANNEL_T */ + ar5212ModifyRfBuffer(rfReg, ee->ee_cornerCal.pd84, 1, 51, 3); + ar5212ModifyRfBuffer(rfReg, ee->ee_cornerCal.pd90, 1, 45, 3); + } + ar5212ModifyRfBuffer(rfReg, rfPwdXpd, 1, 95, 0); + ar5212ModifyRfBuffer(rfReg, rfXpdGainFixed, 4, 96, 0); + /* Set 5212 OB & DB */ + ar5212ModifyRfBuffer(rfReg, tempOB, 3, 104, 0); + ar5212ModifyRfBuffer(rfReg, tempDB, 3, 107, 0); + HAL_INI_WRITE_BANK(ah, ar5212Bank6_5111, rfReg, regWrites); + + /* Bank 7 Write */ + for (i = 0; i < N(ar5212Bank7_5111); i++) + rfReg[i] = ar5212Bank7_5111[i][modesIndex]; + ar5212ModifyRfBuffer(rfReg, gainI, 6, 29, 0); + ar5212ModifyRfBuffer(rfReg, rfPloSel, 1, 4, 0); + + if (IS_CHAN_QUARTER_RATE(chan) || IS_CHAN_HALF_RATE(chan)) { + uint32_t rfWaitI, rfWaitS, rfMaxTime; + + rfWaitS = 0x1f; + rfWaitI = (IS_CHAN_HALF_RATE(chan)) ? 0x10 : 0x1f; + rfMaxTime = 3; + ar5212ModifyRfBuffer(rfReg, rfWaitS, 5, 19, 0); + ar5212ModifyRfBuffer(rfReg, rfWaitI, 5, 24, 0); + ar5212ModifyRfBuffer(rfReg, rfMaxTime, 2, 49, 0); + + } + + HAL_INI_WRITE_BANK(ah, ar5212Bank7_5111, rfReg, regWrites); + + /* Now that we have reprogrammed rfgain value, clear the flag. */ + ahp->ah_rfgainState = HAL_RFGAIN_INACTIVE; + + return AH_TRUE; +} + +/* + * Returns interpolated or the scaled up interpolated value + */ +static uint16_t +interpolate(uint16_t target, uint16_t srcLeft, uint16_t srcRight, + uint16_t targetLeft, uint16_t targetRight) +{ + uint16_t rv; + int16_t lRatio; + + /* to get an accurate ratio, always scale, if want to scale, then don't scale back down */ + if ((targetLeft * targetRight) == 0) + return 0; + + if (srcRight != srcLeft) { + /* + * Note the ratio always need to be scaled, + * since it will be a fraction. + */ + lRatio = (target - srcLeft) * EEP_SCALE / (srcRight - srcLeft); + if (lRatio < 0) { + /* Return as Left target if value would be negative */ + rv = targetLeft; + } else if (lRatio > EEP_SCALE) { + /* Return as Right target if Ratio is greater than 100% (SCALE) */ + rv = targetRight; + } else { + rv = (lRatio * targetRight + (EEP_SCALE - lRatio) * + targetLeft) / EEP_SCALE; + } + } else { + rv = targetLeft; + } + return rv; +} + +/* + * Read the transmit power levels from the structures taken from EEPROM + * Interpolate read transmit power values for this channel + * Organize the transmit power values into a table for writing into the hardware + */ +static HAL_BOOL +ar5111SetPowerTable(struct ath_hal *ah, + int16_t *pMinPower, int16_t *pMaxPower, HAL_CHANNEL_INTERNAL *chan, + uint16_t *rfXpdGain) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom; + FULL_PCDAC_STRUCT pcdacStruct; + int i, j; + + uint16_t *pPcdacValues; + int16_t *pScaledUpDbm; + int16_t minScaledPwr; + int16_t maxScaledPwr; + int16_t pwr; + uint16_t pcdacMin = 0; + uint16_t pcdacMax = PCDAC_STOP; + uint16_t pcdacTableIndex; + uint16_t scaledPcdac; + PCDACS_EEPROM *pSrcStruct; + PCDACS_EEPROM eepromPcdacs; + + /* setup the pcdac struct to point to the correct info, based on mode */ + switch (chan->channelFlags & CHANNEL_ALL) { + case CHANNEL_A: + case CHANNEL_T: + eepromPcdacs.numChannels = ee->ee_numChannels11a; + eepromPcdacs.pChannelList = ee->ee_channels11a; + eepromPcdacs.pDataPerChannel = ee->ee_dataPerChannel11a; + break; + case CHANNEL_B: + eepromPcdacs.numChannels = ee->ee_numChannels2_4; + eepromPcdacs.pChannelList = ee->ee_channels11b; + eepromPcdacs.pDataPerChannel = ee->ee_dataPerChannel11b; + break; + case CHANNEL_G: + case CHANNEL_108G: + eepromPcdacs.numChannels = ee->ee_numChannels2_4; + eepromPcdacs.pChannelList = ee->ee_channels11g; + eepromPcdacs.pDataPerChannel = ee->ee_dataPerChannel11g; + break; + default: + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel flags 0x%x\n", + __func__, chan->channelFlags); + return AH_FALSE; + } + + pSrcStruct = &eepromPcdacs; + + OS_MEMZERO(&pcdacStruct, sizeof(pcdacStruct)); + pPcdacValues = pcdacStruct.PcdacValues; + pScaledUpDbm = pcdacStruct.PwrValues; + + /* Initialize the pcdacs to dBM structs pcdacs to be 1 to 63 */ + for (i = PCDAC_START, j = 0; i <= PCDAC_STOP; i+= PCDAC_STEP, j++) + pPcdacValues[j] = i; + + pcdacStruct.numPcdacValues = j; + pcdacStruct.pcdacMin = PCDAC_START; + pcdacStruct.pcdacMax = PCDAC_STOP; + + /* Fill out the power values for this channel */ + for (j = 0; j < pcdacStruct.numPcdacValues; j++ ) + pScaledUpDbm[j] = ar5212GetScaledPower(chan->channel, + pPcdacValues[j], pSrcStruct); + + /* Now scale the pcdac values to fit in the 64 entry power table */ + minScaledPwr = pScaledUpDbm[0]; + maxScaledPwr = pScaledUpDbm[pcdacStruct.numPcdacValues - 1]; + + /* find minimum and make monotonic */ + for (j = 0; j < pcdacStruct.numPcdacValues; j++) { + if (minScaledPwr >= pScaledUpDbm[j]) { + minScaledPwr = pScaledUpDbm[j]; + pcdacMin = j; + } + /* + * Make the full_hsh monotonically increasing otherwise + * interpolation algorithm will get fooled gotta start + * working from the top, hence i = 63 - j. + */ + i = (uint16_t)(pcdacStruct.numPcdacValues - 1 - j); + if (i == 0) + break; + if (pScaledUpDbm[i-1] > pScaledUpDbm[i]) { + /* + * It could be a glitch, so make the power for + * this pcdac the same as the power from the + * next highest pcdac. + */ + pScaledUpDbm[i - 1] = pScaledUpDbm[i]; + } + } + + for (j = 0; j < pcdacStruct.numPcdacValues; j++) + if (maxScaledPwr < pScaledUpDbm[j]) { + maxScaledPwr = pScaledUpDbm[j]; + pcdacMax = j; + } + + /* Find the first power level with a pcdac */ + pwr = (uint16_t)(PWR_STEP * + ((minScaledPwr - PWR_MIN + PWR_STEP / 2) / PWR_STEP) + PWR_MIN); + + /* Write all the first pcdac entries based off the pcdacMin */ + pcdacTableIndex = 0; + for (i = 0; i < (2 * (pwr - PWR_MIN) / EEP_SCALE + 1); i++) { + HALASSERT(pcdacTableIndex < PWR_TABLE_SIZE); + ahp->ah_pcdacTable[pcdacTableIndex++] = pcdacMin; + } + + i = 0; + while (pwr < pScaledUpDbm[pcdacStruct.numPcdacValues - 1] && + pcdacTableIndex < PWR_TABLE_SIZE) { + pwr += PWR_STEP; + /* stop if dbM > max_power_possible */ + while (pwr < pScaledUpDbm[pcdacStruct.numPcdacValues - 1] && + (pwr - pScaledUpDbm[i])*(pwr - pScaledUpDbm[i+1]) > 0) + i++; + /* scale by 2 and add 1 to enable round up or down as needed */ + scaledPcdac = (uint16_t)(interpolate(pwr, + pScaledUpDbm[i], pScaledUpDbm[i + 1], + (uint16_t)(pPcdacValues[i] * 2), + (uint16_t)(pPcdacValues[i + 1] * 2)) + 1); + + HALASSERT(pcdacTableIndex < PWR_TABLE_SIZE); + ahp->ah_pcdacTable[pcdacTableIndex] = scaledPcdac / 2; + if (ahp->ah_pcdacTable[pcdacTableIndex] > pcdacMax) + ahp->ah_pcdacTable[pcdacTableIndex] = pcdacMax; + pcdacTableIndex++; + } + + /* Write all the last pcdac entries based off the last valid pcdac */ + while (pcdacTableIndex < PWR_TABLE_SIZE) { + ahp->ah_pcdacTable[pcdacTableIndex] = + ahp->ah_pcdacTable[pcdacTableIndex - 1]; + pcdacTableIndex++; + } + + /* No power table adjustment for 5111 */ + ahp->ah_txPowerIndexOffset = 0; + + return AH_TRUE; +} + +/* + * Get or interpolate the pcdac value from the calibrated data. + */ +static uint16_t +ar5212GetScaledPower(uint16_t channel, uint16_t pcdacValue, + const PCDACS_EEPROM *pSrcStruct) +{ + uint16_t powerValue; + uint16_t lFreq, rFreq; /* left and right frequency values */ + uint16_t llPcdac, ulPcdac; /* lower and upper left pcdac values */ + uint16_t lrPcdac, urPcdac; /* lower and upper right pcdac values */ + uint16_t lPwr = 0, uPwr = 0; /* lower and upper temp pwr values */ + uint16_t lScaledPwr, rScaledPwr; /* left and right scaled power */ + + if (ar5212FindValueInList(channel, pcdacValue, pSrcStruct, &powerValue)) { + /* value was copied from srcStruct */ + return powerValue; + } + + ar5212GetLowerUpperValues(channel, + pSrcStruct->pChannelList, pSrcStruct->numChannels, + &lFreq, &rFreq); + ar5212GetLowerUpperPcdacs(pcdacValue, + lFreq, pSrcStruct, &llPcdac, &ulPcdac); + ar5212GetLowerUpperPcdacs(pcdacValue, + rFreq, pSrcStruct, &lrPcdac, &urPcdac); + + /* get the power index for the pcdac value */ + ar5212FindValueInList(lFreq, llPcdac, pSrcStruct, &lPwr); + ar5212FindValueInList(lFreq, ulPcdac, pSrcStruct, &uPwr); + lScaledPwr = interpolate(pcdacValue, llPcdac, ulPcdac, lPwr, uPwr); + + ar5212FindValueInList(rFreq, lrPcdac, pSrcStruct, &lPwr); + ar5212FindValueInList(rFreq, urPcdac, pSrcStruct, &uPwr); + rScaledPwr = interpolate(pcdacValue, lrPcdac, urPcdac, lPwr, uPwr); + + return interpolate(channel, lFreq, rFreq, lScaledPwr, rScaledPwr); +} + +/* + * Find the value from the calibrated source data struct + */ +static HAL_BOOL +ar5212FindValueInList(uint16_t channel, uint16_t pcdacValue, + const PCDACS_EEPROM *pSrcStruct, uint16_t *powerValue) +{ + const DATA_PER_CHANNEL *pChannelData = pSrcStruct->pDataPerChannel; + int i; + + for (i = 0; i < pSrcStruct->numChannels; i++ ) { + if (pChannelData->channelValue == channel) { + const uint16_t* pPcdac = pChannelData->PcdacValues; + int j; + + for (j = 0; j < pChannelData->numPcdacValues; j++ ) { + if (*pPcdac == pcdacValue) { + *powerValue = pChannelData->PwrValues[j]; + return AH_TRUE; + } + pPcdac++; + } + } + pChannelData++; + } + return AH_FALSE; +} + +/* + * Get the upper and lower pcdac given the channel and the pcdac + * used in the search + */ +static void +ar5212GetLowerUpperPcdacs(uint16_t pcdac, uint16_t channel, + const PCDACS_EEPROM *pSrcStruct, + uint16_t *pLowerPcdac, uint16_t *pUpperPcdac) +{ + const DATA_PER_CHANNEL *pChannelData = pSrcStruct->pDataPerChannel; + int i; + + /* Find the channel information */ + for (i = 0; i < pSrcStruct->numChannels; i++) { + if (pChannelData->channelValue == channel) + break; + pChannelData++; + } + ar5212GetLowerUpperValues(pcdac, pChannelData->PcdacValues, + pChannelData->numPcdacValues, + pLowerPcdac, pUpperPcdac); +} + +static HAL_BOOL +ar5111GetChannelMaxMinPower(struct ath_hal *ah, HAL_CHANNEL *chan, + int16_t *maxPow, int16_t *minPow) +{ + /* XXX - Get 5111 power limits! */ + /* NB: caller will cope */ + return AH_FALSE; +} + +/* + * Adjust NF based on statistical values for 5GHz frequencies. + */ +static int16_t +ar5111GetNfAdjust(struct ath_hal *ah, const HAL_CHANNEL_INTERNAL *c) +{ + static const struct { + uint16_t freqLow; + int16_t adjust; + } adjust5111[] = { + { 5790, 6 }, /* NB: ordered high -> low */ + { 5730, 4 }, + { 5690, 3 }, + { 5660, 2 }, + { 5610, 1 }, + { 5530, 0 }, + { 5450, 0 }, + { 5379, 1 }, + { 5209, 3 }, + { 3000, 5 }, + { 0, 0 }, + }; + int i; + + for (i = 0; c->channel <= adjust5111[i].freqLow; i++) + ; + return adjust5111[i].adjust; +} + +/* + * Free memory for analog bank scratch buffers + */ +static void +ar5111RfDetach(struct ath_hal *ah) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + + HALASSERT(ahp->ah_rfHal != AH_NULL); + ath_hal_free(ahp->ah_rfHal); + ahp->ah_rfHal = AH_NULL; +} + +/* + * Allocate memory for analog bank scratch buffers + * Scratch Buffer will be reinitialized every reset so no need to zero now + */ +static HAL_BOOL +ar5111RfAttach(struct ath_hal *ah, HAL_STATUS *status) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + struct ar5111State *priv; + + HALASSERT(ah->ah_magic == AR5212_MAGIC); + + HALASSERT(ahp->ah_rfHal == AH_NULL); + priv = ath_hal_malloc(sizeof(struct ar5111State)); + if (priv == AH_NULL) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: cannot allocate private state\n", __func__); + *status = HAL_ENOMEM; /* XXX */ + return AH_FALSE; + } + priv->base.rfDetach = ar5111RfDetach; + priv->base.writeRegs = ar5111WriteRegs; + priv->base.getRfBank = ar5111GetRfBank; + priv->base.setChannel = ar5111SetChannel; + priv->base.setRfRegs = ar5111SetRfRegs; + priv->base.setPowerTable = ar5111SetPowerTable; + priv->base.getChannelMaxMinPower = ar5111GetChannelMaxMinPower; + priv->base.getNfAdjust = ar5111GetNfAdjust; + + ahp->ah_pcdacTable = priv->pcdacTable; + ahp->ah_pcdacTableSize = sizeof(priv->pcdacTable); + ahp->ah_rfHal = &priv->base; + + return AH_TRUE; +} + +static HAL_BOOL +ar5111Probe(struct ath_hal *ah) +{ + return IS_RAD5111(ah); +} +AH_RF(RF5111, ar5111Probe, ar5111RfAttach); --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5212/ar5112.c 2009-03-23 17:36:55.000000000 +0000 @@ -0,0 +1,881 @@ +/* + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2008 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ar5112.c,v 1.1 2009/03/23 17:14:47 sborrill Exp $ + */ +#include "opt_ah.h" + +#include "ah.h" +#include "ah_internal.h" + +#include "ah_eeprom_v3.h" + +#include "ar5212/ar5212.h" +#include "ar5212/ar5212reg.h" +#include "ar5212/ar5212phy.h" + +#define AH_5212_5112 +#include "ar5212/ar5212.ini" + +#define N(a) (sizeof(a)/sizeof(a[0])) + +struct ar5112State { + RF_HAL_FUNCS base; /* public state, must be first */ + uint16_t pcdacTable[PWR_TABLE_SIZE]; + + uint32_t Bank1Data[N(ar5212Bank1_5112)]; + uint32_t Bank2Data[N(ar5212Bank2_5112)]; + uint32_t Bank3Data[N(ar5212Bank3_5112)]; + uint32_t Bank6Data[N(ar5212Bank6_5112)]; + uint32_t Bank7Data[N(ar5212Bank7_5112)]; +}; +#define AR5112(ah) ((struct ar5112State *) AH5212(ah)->ah_rfHal) + +static void ar5212GetLowerUpperIndex(uint16_t v, + uint16_t *lp, uint16_t listSize, + uint32_t *vlo, uint32_t *vhi); +static HAL_BOOL getFullPwrTable(uint16_t numPcdacs, uint16_t *pcdacs, + int16_t *power, int16_t maxPower, int16_t *retVals); +static int16_t getPminAndPcdacTableFromPowerTable(int16_t *pwrTableT4, + uint16_t retVals[]); +static int16_t getPminAndPcdacTableFromTwoPowerTables(int16_t *pwrTableLXpdT4, + int16_t *pwrTableHXpdT4, uint16_t retVals[], int16_t *pMid); +static int16_t interpolate_signed(uint16_t target, + uint16_t srcLeft, uint16_t srcRight, + int16_t targetLeft, int16_t targetRight); + +extern void ar5212ModifyRfBuffer(uint32_t *rfBuf, uint32_t reg32, + uint32_t numBits, uint32_t firstBit, uint32_t column); + +static void +ar5112WriteRegs(struct ath_hal *ah, u_int modesIndex, u_int freqIndex, + int writes) +{ + HAL_INI_WRITE_ARRAY(ah, ar5212Modes_5112, modesIndex, writes); + HAL_INI_WRITE_ARRAY(ah, ar5212Common_5112, 1, writes); + HAL_INI_WRITE_ARRAY(ah, ar5212BB_RfGain_5112, freqIndex, writes); +} + +/* + * Take the MHz channel value and set the Channel value + * + * ASSUMES: Writes enabled to analog bus + */ +static HAL_BOOL +ar5112SetChannel(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan) +{ + uint32_t channelSel = 0; + uint32_t bModeSynth = 0; + uint32_t aModeRefSel = 0; + uint32_t reg32 = 0; + uint16_t freq; + + OS_MARK(ah, AH_MARK_SETCHANNEL, chan->channel); + + if (chan->channel < 4800) { + uint32_t txctl; + + if (((chan->channel - 2192) % 5) == 0) { + channelSel = ((chan->channel - 672) * 2 - 3040)/10; + bModeSynth = 0; + } else if (((chan->channel - 2224) % 5) == 0) { + channelSel = ((chan->channel - 704) * 2 - 3040) / 10; + bModeSynth = 1; + } else { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: invalid channel %u MHz\n", + __func__, chan->channel); + return AH_FALSE; + } + + channelSel = (channelSel << 2) & 0xff; + channelSel = ath_hal_reverseBits(channelSel, 8); + + txctl = OS_REG_READ(ah, AR_PHY_CCK_TX_CTRL); + if (chan->channel == 2484) { + /* Enable channel spreading for channel 14 */ + OS_REG_WRITE(ah, AR_PHY_CCK_TX_CTRL, + txctl | AR_PHY_CCK_TX_CTRL_JAPAN); + } else { + OS_REG_WRITE(ah, AR_PHY_CCK_TX_CTRL, + txctl &~ AR_PHY_CCK_TX_CTRL_JAPAN); + } + } else if (((chan->channel % 5) == 2) && (chan->channel <= 5435)) { + freq = chan->channel - 2; /* Align to even 5MHz raster */ + channelSel = ath_hal_reverseBits( + (uint32_t)(((freq - 4800)*10)/25 + 1), 8); + aModeRefSel = ath_hal_reverseBits(0, 2); + } else if ((chan->channel % 20) == 0 && chan->channel >= 5120) { + channelSel = ath_hal_reverseBits( + ((chan->channel - 4800) / 20 << 2), 8); + aModeRefSel = ath_hal_reverseBits(3, 2); + } else if ((chan->channel % 10) == 0) { + channelSel = ath_hal_reverseBits( + ((chan->channel - 4800) / 10 << 1), 8); + aModeRefSel = ath_hal_reverseBits(2, 2); + } else if ((chan->channel % 5) == 0) { + channelSel = ath_hal_reverseBits( + (chan->channel - 4800) / 5, 8); + aModeRefSel = ath_hal_reverseBits(1, 2); + } else { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel %u MHz\n", + __func__, chan->channel); + return AH_FALSE; + } + + reg32 = (channelSel << 4) | (aModeRefSel << 2) | (bModeSynth << 1) | + (1 << 12) | 0x1; + OS_REG_WRITE(ah, AR_PHY(0x27), reg32 & 0xff); + + reg32 >>= 8; + OS_REG_WRITE(ah, AR_PHY(0x36), reg32 & 0x7f); + + AH_PRIVATE(ah)->ah_curchan = chan; + return AH_TRUE; +} + +/* + * Return a reference to the requested RF Bank. + */ +static uint32_t * +ar5112GetRfBank(struct ath_hal *ah, int bank) +{ + struct ar5112State *priv = AR5112(ah); + + HALASSERT(priv != AH_NULL); + switch (bank) { + case 1: return priv->Bank1Data; + case 2: return priv->Bank2Data; + case 3: return priv->Bank3Data; + case 6: return priv->Bank6Data; + case 7: return priv->Bank7Data; + } + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unknown RF Bank %d requested\n", + __func__, bank); + return AH_NULL; +} + +/* + * Reads EEPROM header info from device structure and programs + * all rf registers + * + * REQUIRES: Access to the analog rf device + */ +static HAL_BOOL +ar5112SetRfRegs(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan, + uint16_t modesIndex, uint16_t *rfXpdGain) +{ +#define RF_BANK_SETUP(_priv, _ix, _col) do { \ + int i; \ + for (i = 0; i < N(ar5212Bank##_ix##_5112); i++) \ + (_priv)->Bank##_ix##Data[i] = ar5212Bank##_ix##_5112[i][_col];\ +} while (0) + struct ath_hal_5212 *ahp = AH5212(ah); + const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom; + uint16_t rfXpdSel, gainI; + uint16_t ob5GHz = 0, db5GHz = 0; + uint16_t ob2GHz = 0, db2GHz = 0; + struct ar5112State *priv = AR5112(ah); + GAIN_VALUES *gv = &ahp->ah_gainValues; + int regWrites = 0; + + HALASSERT(priv); + + /* Setup rf parameters */ + switch (chan->channelFlags & CHANNEL_ALL) { + case CHANNEL_A: + case CHANNEL_T: + if (chan->channel > 4000 && chan->channel < 5260) { + ob5GHz = ee->ee_ob1; + db5GHz = ee->ee_db1; + } else if (chan->channel >= 5260 && chan->channel < 5500) { + ob5GHz = ee->ee_ob2; + db5GHz = ee->ee_db2; + } else if (chan->channel >= 5500 && chan->channel < 5725) { + ob5GHz = ee->ee_ob3; + db5GHz = ee->ee_db3; + } else if (chan->channel >= 5725) { + ob5GHz = ee->ee_ob4; + db5GHz = ee->ee_db4; + } else { + /* XXX else */ + } + rfXpdSel = ee->ee_xpd[headerInfo11A]; + gainI = ee->ee_gainI[headerInfo11A]; + break; + case CHANNEL_B: + ob2GHz = ee->ee_ob2GHz[0]; + db2GHz = ee->ee_db2GHz[0]; + rfXpdSel = ee->ee_xpd[headerInfo11B]; + gainI = ee->ee_gainI[headerInfo11B]; + break; + case CHANNEL_G: + case CHANNEL_108G: + ob2GHz = ee->ee_ob2GHz[1]; + db2GHz = ee->ee_ob2GHz[1]; + rfXpdSel = ee->ee_xpd[headerInfo11G]; + gainI = ee->ee_gainI[headerInfo11G]; + break; + default: + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel flags 0x%x\n", + __func__, chan->channelFlags); + return AH_FALSE; + } + + /* Setup Bank 1 Write */ + RF_BANK_SETUP(priv, 1, 1); + + /* Setup Bank 2 Write */ + RF_BANK_SETUP(priv, 2, modesIndex); + + /* Setup Bank 3 Write */ + RF_BANK_SETUP(priv, 3, modesIndex); + + /* Setup Bank 6 Write */ + RF_BANK_SETUP(priv, 6, modesIndex); + + ar5212ModifyRfBuffer(priv->Bank6Data, rfXpdSel, 1, 302, 0); + + ar5212ModifyRfBuffer(priv->Bank6Data, rfXpdGain[0], 2, 270, 0); + ar5212ModifyRfBuffer(priv->Bank6Data, rfXpdGain[1], 2, 257, 0); + + if (IS_CHAN_OFDM(chan)) { + ar5212ModifyRfBuffer(priv->Bank6Data, + gv->currStep->paramVal[GP_PWD_138], 1, 168, 3); + ar5212ModifyRfBuffer(priv->Bank6Data, + gv->currStep->paramVal[GP_PWD_137], 1, 169, 3); + ar5212ModifyRfBuffer(priv->Bank6Data, + gv->currStep->paramVal[GP_PWD_136], 1, 170, 3); + ar5212ModifyRfBuffer(priv->Bank6Data, + gv->currStep->paramVal[GP_PWD_132], 1, 174, 3); + ar5212ModifyRfBuffer(priv->Bank6Data, + gv->currStep->paramVal[GP_PWD_131], 1, 175, 3); + ar5212ModifyRfBuffer(priv->Bank6Data, + gv->currStep->paramVal[GP_PWD_130], 1, 176, 3); + } + + /* Only the 5 or 2 GHz OB/DB need to be set for a mode */ + if (IS_CHAN_2GHZ(chan)) { + ar5212ModifyRfBuffer(priv->Bank6Data, ob2GHz, 3, 287, 0); + ar5212ModifyRfBuffer(priv->Bank6Data, db2GHz, 3, 290, 0); + } else { + ar5212ModifyRfBuffer(priv->Bank6Data, ob5GHz, 3, 279, 0); + ar5212ModifyRfBuffer(priv->Bank6Data, db5GHz, 3, 282, 0); + } + + /* Lower synth voltage for X112 Rev 2.0 only */ + if (IS_RADX112_REV2(ah)) { + /* Non-Reversed analyg registers - so values are pre-reversed */ + ar5212ModifyRfBuffer(priv->Bank6Data, 2, 2, 90, 2); + ar5212ModifyRfBuffer(priv->Bank6Data, 2, 2, 92, 2); + ar5212ModifyRfBuffer(priv->Bank6Data, 2, 2, 94, 2); + ar5212ModifyRfBuffer(priv->Bank6Data, 2, 1, 254, 2); + } + + /* Decrease Power Consumption for 5312/5213 and up */ + if (AH_PRIVATE(ah)->ah_phyRev >= AR_PHY_CHIP_ID_REV_2) { + ar5212ModifyRfBuffer(priv->Bank6Data, 1, 1, 281, 1); + ar5212ModifyRfBuffer(priv->Bank6Data, 1, 2, 1, 3); + ar5212ModifyRfBuffer(priv->Bank6Data, 1, 2, 3, 3); + ar5212ModifyRfBuffer(priv->Bank6Data, 1, 1, 139, 3); + ar5212ModifyRfBuffer(priv->Bank6Data, 1, 1, 140, 3); + } + + /* Setup Bank 7 Setup */ + RF_BANK_SETUP(priv, 7, modesIndex); + if (IS_CHAN_OFDM(chan)) + ar5212ModifyRfBuffer(priv->Bank7Data, + gv->currStep->paramVal[GP_MIXGAIN_OVR], 2, 37, 0); + + ar5212ModifyRfBuffer(priv->Bank7Data, gainI, 6, 14, 0); + + /* Adjust params for Derby TX power control */ + if (IS_CHAN_HALF_RATE(chan) || IS_CHAN_QUARTER_RATE(chan)) { + uint32_t rfDelay, rfPeriod; + + rfDelay = 0xf; + rfPeriod = (IS_CHAN_HALF_RATE(chan)) ? 0x8 : 0xf; + ar5212ModifyRfBuffer(priv->Bank7Data, rfDelay, 4, 58, 0); + ar5212ModifyRfBuffer(priv->Bank7Data, rfPeriod, 4, 70, 0); + } + +#ifdef notyet + /* Analog registers are setup - EAR can modify */ + if (ar5212IsEarEngaged(pDev, chan)) + uint32_t modifier; + ar5212EarModify(pDev, EAR_LC_RF_WRITE, chan, &modifier); +#endif + /* Write Analog registers */ + HAL_INI_WRITE_BANK(ah, ar5212Bank1_5112, priv->Bank1Data, regWrites); + HAL_INI_WRITE_BANK(ah, ar5212Bank2_5112, priv->Bank2Data, regWrites); + HAL_INI_WRITE_BANK(ah, ar5212Bank3_5112, priv->Bank3Data, regWrites); + HAL_INI_WRITE_BANK(ah, ar5212Bank6_5112, priv->Bank6Data, regWrites); + HAL_INI_WRITE_BANK(ah, ar5212Bank7_5112, priv->Bank7Data, regWrites); + + /* Now that we have reprogrammed rfgain value, clear the flag. */ + ahp->ah_rfgainState = HAL_RFGAIN_INACTIVE; + return AH_TRUE; +#undef RF_BANK_SETUP +} + +/* + * Read the transmit power levels from the structures taken from EEPROM + * Interpolate read transmit power values for this channel + * Organize the transmit power values into a table for writing into the hardware + */ +static HAL_BOOL +ar5112SetPowerTable(struct ath_hal *ah, + int16_t *pPowerMin, int16_t *pPowerMax, HAL_CHANNEL_INTERNAL *chan, + uint16_t *rfXpdGain) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom; + uint32_t numXpdGain = IS_RADX112_REV2(ah) ? 2 : 1; + uint32_t xpdGainMask = 0; + int16_t powerMid, *pPowerMid = &powerMid; + + const EXPN_DATA_PER_CHANNEL_5112 *pRawCh; + const EEPROM_POWER_EXPN_5112 *pPowerExpn = AH_NULL; + + uint32_t ii, jj, kk; + int16_t minPwr_t4, maxPwr_t4, Pmin, Pmid; + + uint32_t chan_idx_L = 0, chan_idx_R = 0; + uint16_t chan_L, chan_R; + + int16_t pwr_table0[64]; + int16_t pwr_table1[64]; + uint16_t pcdacs[10]; + int16_t powers[10]; + uint16_t numPcd; + int16_t powTableLXPD[2][64]; + int16_t powTableHXPD[2][64]; + int16_t tmpPowerTable[64]; + uint16_t xgainList[2]; + uint16_t xpdMask; + + switch (chan->channelFlags & CHANNEL_ALL) { + case CHANNEL_A: + case CHANNEL_T: + pPowerExpn = &ee->ee_modePowerArray5112[headerInfo11A]; + xpdGainMask = ee->ee_xgain[headerInfo11A]; + break; + case CHANNEL_B: + pPowerExpn = &ee->ee_modePowerArray5112[headerInfo11B]; + xpdGainMask = ee->ee_xgain[headerInfo11B]; + break; + case CHANNEL_G: + case CHANNEL_108G: + pPowerExpn = &ee->ee_modePowerArray5112[headerInfo11G]; + xpdGainMask = ee->ee_xgain[headerInfo11G]; + break; + default: + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unknown channel flags 0x%x\n", + __func__, chan->channelFlags & CHANNEL_ALL); + return AH_FALSE; + } + + if ((xpdGainMask & pPowerExpn->xpdMask) < 1) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: desired xpdGainMask 0x%x not supported by " + "calibrated xpdMask 0x%x\n", __func__, + xpdGainMask, pPowerExpn->xpdMask); + return AH_FALSE; + } + + maxPwr_t4 = (int16_t)(2*(*pPowerMax)); /* pwr_t2 -> pwr_t4 */ + minPwr_t4 = (int16_t)(2*(*pPowerMin)); /* pwr_t2 -> pwr_t4 */ + + xgainList[0] = 0xDEAD; + xgainList[1] = 0xDEAD; + + kk = 0; + xpdMask = pPowerExpn->xpdMask; + for (jj = 0; jj < NUM_XPD_PER_CHANNEL; jj++) { + if (((xpdMask >> jj) & 1) > 0) { + if (kk > 1) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "A maximum of 2 xpdGains supported" + "in pExpnPower data\n"); + return AH_FALSE; + } + xgainList[kk++] = (uint16_t)jj; + } + } + + ar5212GetLowerUpperIndex(chan->channel, &pPowerExpn->pChannels[0], + pPowerExpn->numChannels, &chan_idx_L, &chan_idx_R); + + kk = 0; + for (ii = chan_idx_L; ii <= chan_idx_R; ii++) { + pRawCh = &(pPowerExpn->pDataPerChannel[ii]); + if (xgainList[1] == 0xDEAD) { + jj = xgainList[0]; + numPcd = pRawCh->pDataPerXPD[jj].numPcdacs; + OS_MEMCPY(&pcdacs[0], &pRawCh->pDataPerXPD[jj].pcdac[0], + numPcd * sizeof(uint16_t)); + OS_MEMCPY(&powers[0], &pRawCh->pDataPerXPD[jj].pwr_t4[0], + numPcd * sizeof(int16_t)); + if (!getFullPwrTable(numPcd, &pcdacs[0], &powers[0], + pRawCh->maxPower_t4, &tmpPowerTable[0])) { + return AH_FALSE; + } + OS_MEMCPY(&powTableLXPD[kk][0], &tmpPowerTable[0], + 64*sizeof(int16_t)); + } else { + jj = xgainList[0]; + numPcd = pRawCh->pDataPerXPD[jj].numPcdacs; + OS_MEMCPY(&pcdacs[0], &pRawCh->pDataPerXPD[jj].pcdac[0], + numPcd*sizeof(uint16_t)); + OS_MEMCPY(&powers[0], + &pRawCh->pDataPerXPD[jj].pwr_t4[0], + numPcd*sizeof(int16_t)); + if (!getFullPwrTable(numPcd, &pcdacs[0], &powers[0], + pRawCh->maxPower_t4, &tmpPowerTable[0])) { + return AH_FALSE; + } + OS_MEMCPY(&powTableLXPD[kk][0], &tmpPowerTable[0], + 64 * sizeof(int16_t)); + + jj = xgainList[1]; + numPcd = pRawCh->pDataPerXPD[jj].numPcdacs; + OS_MEMCPY(&pcdacs[0], &pRawCh->pDataPerXPD[jj].pcdac[0], + numPcd * sizeof(uint16_t)); + OS_MEMCPY(&powers[0], + &pRawCh->pDataPerXPD[jj].pwr_t4[0], + numPcd * sizeof(int16_t)); + if (!getFullPwrTable(numPcd, &pcdacs[0], &powers[0], + pRawCh->maxPower_t4, &tmpPowerTable[0])) { + return AH_FALSE; + } + OS_MEMCPY(&powTableHXPD[kk][0], &tmpPowerTable[0], + 64 * sizeof(int16_t)); + } + kk++; + } + + chan_L = pPowerExpn->pChannels[chan_idx_L]; + chan_R = pPowerExpn->pChannels[chan_idx_R]; + kk = chan_idx_R - chan_idx_L; + + if (xgainList[1] == 0xDEAD) { + for (jj = 0; jj < 64; jj++) { + pwr_table0[jj] = interpolate_signed( + chan->channel, chan_L, chan_R, + powTableLXPD[0][jj], powTableLXPD[kk][jj]); + } + Pmin = getPminAndPcdacTableFromPowerTable(&pwr_table0[0], + ahp->ah_pcdacTable); + *pPowerMin = (int16_t) (Pmin / 2); + *pPowerMid = (int16_t) (pwr_table0[63] / 2); + *pPowerMax = (int16_t) (pwr_table0[63] / 2); + rfXpdGain[0] = xgainList[0]; + rfXpdGain[1] = rfXpdGain[0]; + } else { + for (jj = 0; jj < 64; jj++) { + pwr_table0[jj] = interpolate_signed( + chan->channel, chan_L, chan_R, + powTableLXPD[0][jj], powTableLXPD[kk][jj]); + pwr_table1[jj] = interpolate_signed( + chan->channel, chan_L, chan_R, + powTableHXPD[0][jj], powTableHXPD[kk][jj]); + } + if (numXpdGain == 2) { + Pmin = getPminAndPcdacTableFromTwoPowerTables( + &pwr_table0[0], &pwr_table1[0], + ahp->ah_pcdacTable, &Pmid); + *pPowerMin = (int16_t) (Pmin / 2); + *pPowerMid = (int16_t) (Pmid / 2); + *pPowerMax = (int16_t) (pwr_table0[63] / 2); + rfXpdGain[0] = xgainList[0]; + rfXpdGain[1] = xgainList[1]; + } else if (minPwr_t4 <= pwr_table1[63] && + maxPwr_t4 <= pwr_table1[63]) { + Pmin = getPminAndPcdacTableFromPowerTable( + &pwr_table1[0], ahp->ah_pcdacTable); + rfXpdGain[0] = xgainList[1]; + rfXpdGain[1] = rfXpdGain[0]; + *pPowerMin = (int16_t) (Pmin / 2); + *pPowerMid = (int16_t) (pwr_table1[63] / 2); + *pPowerMax = (int16_t) (pwr_table1[63] / 2); + } else { + Pmin = getPminAndPcdacTableFromPowerTable( + &pwr_table0[0], ahp->ah_pcdacTable); + rfXpdGain[0] = xgainList[0]; + rfXpdGain[1] = rfXpdGain[0]; + *pPowerMin = (int16_t) (Pmin/2); + *pPowerMid = (int16_t) (pwr_table0[63] / 2); + *pPowerMax = (int16_t) (pwr_table0[63] / 2); + } + } + + /* + * Move 5112 rates to match power tables where the max + * power table entry corresponds with maxPower. + */ + HALASSERT(*pPowerMax <= PCDAC_STOP); + ahp->ah_txPowerIndexOffset = PCDAC_STOP - *pPowerMax; + + return AH_TRUE; +} + +/* + * Returns interpolated or the scaled up interpolated value + */ +static int16_t +interpolate_signed(uint16_t target, uint16_t srcLeft, uint16_t srcRight, + int16_t targetLeft, int16_t targetRight) +{ + int16_t rv; + + if (srcRight != srcLeft) { + rv = ((target - srcLeft)*targetRight + + (srcRight - target)*targetLeft) / (srcRight - srcLeft); + } else { + rv = targetLeft; + } + return rv; +} + +/* + * Return indices surrounding the value in sorted integer lists. + * + * NB: the input list is assumed to be sorted in ascending order + */ +static void +ar5212GetLowerUpperIndex(uint16_t v, uint16_t *lp, uint16_t listSize, + uint32_t *vlo, uint32_t *vhi) +{ + uint32_t target = v; + uint16_t *ep = lp+listSize; + uint16_t *tp; + + /* + * Check first and last elements for out-of-bounds conditions. + */ + if (target < lp[0]) { + *vlo = *vhi = 0; + return; + } + if (target >= ep[-1]) { + *vlo = *vhi = listSize - 1; + return; + } + + /* look for value being near or between 2 values in list */ + for (tp = lp; tp < ep; tp++) { + /* + * If value is close to the current value of the list + * then target is not between values, it is one of the values + */ + if (*tp == target) { + *vlo = *vhi = tp - lp; + return; + } + /* + * Look for value being between current value and next value + * if so return these 2 values + */ + if (target < tp[1]) { + *vlo = tp - lp; + *vhi = *vlo + 1; + return; + } + } +} + +static HAL_BOOL +getFullPwrTable(uint16_t numPcdacs, uint16_t *pcdacs, int16_t *power, int16_t maxPower, int16_t *retVals) +{ + uint16_t ii; + uint16_t idxL = 0; + uint16_t idxR = 1; + + if (numPcdacs < 2) { + HALDEBUG(AH_NULL, HAL_DEBUG_ANY, + "%s: at least 2 pcdac values needed [%d]\n", + __func__, numPcdacs); + return AH_FALSE; + } + for (ii = 0; ii < 64; ii++) { + if (ii>pcdacs[idxR] && idxR < numPcdacs-1) { + idxL++; + idxR++; + } + retVals[ii] = interpolate_signed(ii, + pcdacs[idxL], pcdacs[idxR], power[idxL], power[idxR]); + if (retVals[ii] >= maxPower) { + while (ii < 64) + retVals[ii++] = maxPower; + } + } + return AH_TRUE; +} + +/* + * Takes a single calibration curve and creates a power table. + * Adjusts the new power table so the max power is relative + * to the maximum index in the power table. + * + * WARNING: rates must be adjusted for this relative power table + */ +static int16_t +getPminAndPcdacTableFromPowerTable(int16_t *pwrTableT4, uint16_t retVals[]) +{ + int16_t ii, jj, jjMax; + int16_t pMin, currPower, pMax; + + /* If the spread is > 31.5dB, keep the upper 31.5dB range */ + if ((pwrTableT4[63] - pwrTableT4[0]) > 126) { + pMin = pwrTableT4[63] - 126; + } else { + pMin = pwrTableT4[0]; + } + + pMax = pwrTableT4[63]; + jjMax = 63; + + /* Search for highest pcdac 0.25dB below maxPower */ + while ((pwrTableT4[jjMax] > (pMax - 1) ) && (jjMax >= 0)) { + jjMax--; + } + + jj = jjMax; + currPower = pMax; + for (ii = 63; ii >= 0; ii--) { + while ((jj < 64) && (jj > 0) && (pwrTableT4[jj] >= currPower)) { + jj--; + } + if (jj == 0) { + while (ii >= 0) { + retVals[ii] = retVals[ii + 1]; + ii--; + } + break; + } + retVals[ii] = jj; + currPower -= 2; // corresponds to a 0.5dB step + } + return pMin; +} + +/* + * Combines the XPD curves from two calibration sets into a single + * power table and adjusts the power table so the max power is relative + * to the maximum index in the power table + * + * WARNING: rates must be adjusted for this relative power table + */ +static int16_t +getPminAndPcdacTableFromTwoPowerTables(int16_t *pwrTableLXpdT4, + int16_t *pwrTableHXpdT4, uint16_t retVals[], int16_t *pMid) +{ + int16_t ii, jj, jjMax; + int16_t pMin, pMax, currPower; + int16_t *pwrTableT4; + uint16_t msbFlag = 0x40; // turns on the 7th bit of the pcdac + + /* If the spread is > 31.5dB, keep the upper 31.5dB range */ + if ((pwrTableLXpdT4[63] - pwrTableHXpdT4[0]) > 126) { + pMin = pwrTableLXpdT4[63] - 126; + } else { + pMin = pwrTableHXpdT4[0]; + } + + pMax = pwrTableLXpdT4[63]; + jjMax = 63; + /* Search for highest pcdac 0.25dB below maxPower */ + while ((pwrTableLXpdT4[jjMax] > (pMax - 1) ) && (jjMax >= 0)){ + jjMax--; + } + + *pMid = pwrTableHXpdT4[63]; + jj = jjMax; + ii = 63; + currPower = pMax; + pwrTableT4 = &(pwrTableLXpdT4[0]); + while (ii >= 0) { + if ((currPower <= *pMid) || ( (jj == 0) && (msbFlag == 0x40))){ + msbFlag = 0x00; + pwrTableT4 = &(pwrTableHXpdT4[0]); + jj = 63; + } + while ((jj > 0) && (pwrTableT4[jj] >= currPower)) { + jj--; + } + if ((jj == 0) && (msbFlag == 0x00)) { + while (ii >= 0) { + retVals[ii] = retVals[ii+1]; + ii--; + } + break; + } + retVals[ii] = jj | msbFlag; + currPower -= 2; // corresponds to a 0.5dB step + ii--; + } + return pMin; +} + +static int16_t +ar5112GetMinPower(struct ath_hal *ah, const EXPN_DATA_PER_CHANNEL_5112 *data) +{ + int i, minIndex; + int16_t minGain,minPwr,minPcdac,retVal; + + /* Assume NUM_POINTS_XPD0 > 0 */ + minGain = data->pDataPerXPD[0].xpd_gain; + for (minIndex=0,i=1; ipDataPerXPD[i].xpd_gain < minGain) { + minIndex = i; + minGain = data->pDataPerXPD[i].xpd_gain; + } + } + minPwr = data->pDataPerXPD[minIndex].pwr_t4[0]; + minPcdac = data->pDataPerXPD[minIndex].pcdac[0]; + for (i=1; ipDataPerXPD[minIndex].pwr_t4[i] < minPwr) { + minPwr = data->pDataPerXPD[minIndex].pwr_t4[i]; + minPcdac = data->pDataPerXPD[minIndex].pcdac[i]; + } + } + retVal = minPwr - (minPcdac*2); + return(retVal); +} + +static HAL_BOOL +ar5112GetChannelMaxMinPower(struct ath_hal *ah, HAL_CHANNEL *chan, + int16_t *maxPow, int16_t *minPow) +{ + const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom; + int numChannels=0,i,last; + int totalD, totalF,totalMin; + const EXPN_DATA_PER_CHANNEL_5112 *data=AH_NULL; + const EEPROM_POWER_EXPN_5112 *powerArray=AH_NULL; + + *maxPow = 0; + if (IS_CHAN_A(chan)) { + powerArray = ee->ee_modePowerArray5112; + data = powerArray[headerInfo11A].pDataPerChannel; + numChannels = powerArray[headerInfo11A].numChannels; + } else if (IS_CHAN_G(chan) || IS_CHAN_108G(chan)) { + /* XXX - is this correct? Should we also use the same power for turbo G? */ + powerArray = ee->ee_modePowerArray5112; + data = powerArray[headerInfo11G].pDataPerChannel; + numChannels = powerArray[headerInfo11G].numChannels; + } else if (IS_CHAN_B(chan)) { + powerArray = ee->ee_modePowerArray5112; + data = powerArray[headerInfo11B].pDataPerChannel; + numChannels = powerArray[headerInfo11B].numChannels; + } else { + return (AH_TRUE); + } + /* Make sure the channel is in the range of the TP values + * (freq piers) + */ + if (numChannels < 1) + return(AH_FALSE); + + if ((chan->channel < data[0].channelValue) || + (chan->channel > data[numChannels-1].channelValue)) { + if (chan->channel < data[0].channelValue) { + *maxPow = data[0].maxPower_t4; + *minPow = ar5112GetMinPower(ah, &data[0]); + return(AH_TRUE); + } else { + *maxPow = data[numChannels - 1].maxPower_t4; + *minPow = ar5112GetMinPower(ah, &data[numChannels - 1]); + return(AH_TRUE); + } + } + + /* Linearly interpolate the power value now */ + for (last=0,i=0; + (ichannel > data[i].channelValue); + last=i++); + totalD = data[i].channelValue - data[last].channelValue; + if (totalD > 0) { + totalF = data[i].maxPower_t4 - data[last].maxPower_t4; + *maxPow = (int8_t) ((totalF*(chan->channel-data[last].channelValue) + data[last].maxPower_t4*totalD)/totalD); + + totalMin = ar5112GetMinPower(ah,&data[i]) - ar5112GetMinPower(ah, &data[last]); + *minPow = (int8_t) ((totalMin*(chan->channel-data[last].channelValue) + ar5112GetMinPower(ah, &data[last])*totalD)/totalD); + return (AH_TRUE); + } else { + if (chan->channel == data[i].channelValue) { + *maxPow = data[i].maxPower_t4; + *minPow = ar5112GetMinPower(ah, &data[i]); + return(AH_TRUE); + } else + return(AH_FALSE); + } +} + +/* + * Free memory for analog bank scratch buffers + */ +static void +ar5112RfDetach(struct ath_hal *ah) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + + HALASSERT(ahp->ah_rfHal != AH_NULL); + ath_hal_free(ahp->ah_rfHal); + ahp->ah_rfHal = AH_NULL; +} + +/* + * Allocate memory for analog bank scratch buffers + * Scratch Buffer will be reinitialized every reset so no need to zero now + */ +static HAL_BOOL +ar5112RfAttach(struct ath_hal *ah, HAL_STATUS *status) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + struct ar5112State *priv; + + HALASSERT(ah->ah_magic == AR5212_MAGIC); + + HALASSERT(ahp->ah_rfHal == AH_NULL); + priv = ath_hal_malloc(sizeof(struct ar5112State)); + if (priv == AH_NULL) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: cannot allocate private state\n", __func__); + *status = HAL_ENOMEM; /* XXX */ + return AH_FALSE; + } + priv->base.rfDetach = ar5112RfDetach; + priv->base.writeRegs = ar5112WriteRegs; + priv->base.getRfBank = ar5112GetRfBank; + priv->base.setChannel = ar5112SetChannel; + priv->base.setRfRegs = ar5112SetRfRegs; + priv->base.setPowerTable = ar5112SetPowerTable; + priv->base.getChannelMaxMinPower = ar5112GetChannelMaxMinPower; + priv->base.getNfAdjust = ar5212GetNfAdjust; + + ahp->ah_pcdacTable = priv->pcdacTable; + ahp->ah_pcdacTableSize = sizeof(priv->pcdacTable); + ahp->ah_rfHal = &priv->base; + + return AH_TRUE; +} + +static HAL_BOOL +ar5112Probe(struct ath_hal *ah) +{ + return IS_RAD5112(ah); +} +AH_RF(RF5112, ar5112Probe, ar5112RfAttach); --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5212/ar5212.h 2009-03-23 17:36:55.000000000 +0000 @@ -0,0 +1,603 @@ +/* + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2008 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ar5212.h,v 1.1 2009/03/23 17:14:47 sborrill Exp $ + */ +#ifndef _ATH_AR5212_H_ +#define _ATH_AR5212_H_ + +#include "ah_eeprom.h" + +#define AR5212_MAGIC 0x19541014 + +/* DCU Transmit Filter macros */ +#define CALC_MMR(dcu, idx) \ + ( (4 * dcu) + (idx < 32 ? 0 : (idx < 64 ? 1 : (idx < 96 ? 2 : 3))) ) +#define TXBLK_FROM_MMR(mmr) \ + (AR_D_TXBLK_BASE + ((mmr & 0x1f) << 6) + ((mmr & 0x20) >> 3)) +#define CALC_TXBLK_ADDR(dcu, idx) (TXBLK_FROM_MMR(CALC_MMR(dcu, idx))) +#define CALC_TXBLK_VALUE(idx) (1 << (idx & 0x1f)) + +/* MAC register values */ + +#define INIT_INTERRUPT_MASK \ + ( AR_IMR_TXERR | AR_IMR_TXOK | AR_IMR_RXORN | \ + AR_IMR_RXERR | AR_IMR_RXOK | AR_IMR_TXURN | \ + AR_IMR_HIUERR ) +#define INIT_BEACON_CONTROL \ + ((INIT_RESET_TSF << 24) | (INIT_BEACON_EN << 23) | \ + (INIT_TIM_OFFSET << 16) | INIT_BEACON_PERIOD) + +#define INIT_CONFIG_STATUS 0x00000000 +#define INIT_RSSI_THR 0x00000781 /* Missed beacon counter initialized to 0x7 (max is 0xff) */ +#define INIT_IQCAL_LOG_COUNT_MAX 0xF +#define INIT_BCON_CNTRL_REG 0x00000000 + +#define INIT_USEC 40 +#define HALF_RATE_USEC 19 /* ((40 / 2) - 1 ) */ +#define QUARTER_RATE_USEC 9 /* ((40 / 4) - 1 ) */ + +#define RX_NON_FULL_RATE_LATENCY 63 +#define TX_HALF_RATE_LATENCY 108 +#define TX_QUARTER_RATE_LATENCY 216 + +#define IFS_SLOT_FULL_RATE 0x168 /* 9 us half, 40 MHz core clock (9*40) */ +#define IFS_SLOT_HALF_RATE 0x104 /* 13 us half, 20 MHz core clock (13*20) */ +#define IFS_SLOT_QUARTER_RATE 0xD2 /* 21 us quarter, 10 MHz core clock (21*10) */ +#define IFS_EIFS_FULL_RATE 0xE60 /* (74 + (2 * 9)) * 40MHz core clock */ +#define IFS_EIFS_HALF_RATE 0xDAC /* (149 + (2 * 13)) * 20MHz core clock */ +#define IFS_EIFS_QUARTER_RATE 0xD48 /* (298 + (2 * 21)) * 10MHz core clock */ + +#define ACK_CTS_TIMEOUT_11A 0x3E8 /* ACK timeout in 11a core clocks */ + +/* Tx frame start to tx data start delay */ +#define TX_FRAME_D_START_HALF_RATE 0xc +#define TX_FRAME_D_START_QUARTER_RATE 0xd + +/* + * Various fifo fill before Tx start, in 64-byte units + * i.e. put the frame in the air while still DMAing + */ +#define MIN_TX_FIFO_THRESHOLD 0x1 +#define MAX_TX_FIFO_THRESHOLD ((IEEE80211_MAX_LEN / 64) + 1) +#define INIT_TX_FIFO_THRESHOLD MIN_TX_FIFO_THRESHOLD + +#define HAL_DECOMP_MASK_SIZE 128 /* 1 byte per key */ + +/* + * Gain support. + */ +#define NUM_CORNER_FIX_BITS 4 +#define NUM_CORNER_FIX_BITS_5112 7 +#define DYN_ADJ_UP_MARGIN 15 +#define DYN_ADJ_LO_MARGIN 20 +#define PHY_PROBE_CCK_CORRECTION 5 +#define CCK_OFDM_GAIN_DELTA 15 + +enum GAIN_PARAMS { + GP_TXCLIP, + GP_PD90, + GP_PD84, + GP_GSEL, +}; + +enum GAIN_PARAMS_5112 { + GP_MIXGAIN_OVR, + GP_PWD_138, + GP_PWD_137, + GP_PWD_136, + GP_PWD_132, + GP_PWD_131, + GP_PWD_130, +}; + +typedef struct _gainOptStep { + int16_t paramVal[NUM_CORNER_FIX_BITS_5112]; + int32_t stepGain; + int8_t stepName[16]; +} GAIN_OPTIMIZATION_STEP; + +typedef struct { + uint32_t numStepsInLadder; + uint32_t defaultStepNum; + GAIN_OPTIMIZATION_STEP optStep[10]; +} GAIN_OPTIMIZATION_LADDER; + +typedef struct { + uint32_t currStepNum; + uint32_t currGain; + uint32_t targetGain; + uint32_t loTrig; + uint32_t hiTrig; + uint32_t gainFCorrection; + uint32_t active; + const GAIN_OPTIMIZATION_STEP *currStep; +} GAIN_VALUES; + +/* RF HAL structures */ +typedef struct RfHalFuncs { + void *priv; /* private state */ + + void (*rfDetach)(struct ath_hal *ah); + void (*writeRegs)(struct ath_hal *, + u_int modeIndex, u_int freqIndex, int regWrites); + uint32_t *(*getRfBank)(struct ath_hal *ah, int bank); + HAL_BOOL (*setChannel)(struct ath_hal *, HAL_CHANNEL_INTERNAL *); + HAL_BOOL (*setRfRegs)(struct ath_hal *, + HAL_CHANNEL_INTERNAL *, uint16_t modesIndex, + uint16_t *rfXpdGain); + HAL_BOOL (*setPowerTable)(struct ath_hal *ah, + int16_t *minPower, int16_t *maxPower, + HAL_CHANNEL_INTERNAL *, uint16_t *rfXpdGain); + HAL_BOOL (*getChannelMaxMinPower)(struct ath_hal *ah, HAL_CHANNEL *, + int16_t *maxPow, int16_t *minPow); + int16_t (*getNfAdjust)(struct ath_hal *, const HAL_CHANNEL_INTERNAL*); +} RF_HAL_FUNCS; + +struct ar5212AniParams { + int maxNoiseImmunityLevel; /* [0..4] */ + int totalSizeDesired[5]; + int coarseHigh[5]; + int coarseLow[5]; + int firpwr[5]; + + int maxSpurImmunityLevel; /* [0..7] */ + int cycPwrThr1[8]; + + int maxFirstepLevel; /* [0..2] */ + int firstep[3]; + + uint32_t ofdmTrigHigh; + uint32_t ofdmTrigLow; + uint32_t cckTrigHigh; + uint32_t cckTrigLow; + int32_t rssiThrLow; + uint32_t rssiThrHigh; + + int period; /* update listen period */ + + /* NB: intentionally ordered so data exported to user space is first */ + uint32_t ofdmPhyErrBase; /* Base value for ofdm err counter */ + uint32_t cckPhyErrBase; /* Base value for cck err counters */ +}; + +/* + * Per-channel ANI state private to the driver. + */ +struct ar5212AniState { + uint8_t noiseImmunityLevel; + uint8_t spurImmunityLevel; + uint8_t firstepLevel; + uint8_t ofdmWeakSigDetectOff; + uint8_t cckWeakSigThreshold; + uint32_t listenTime; + + /* NB: intentionally ordered so data exported to user space is first */ + HAL_CHANNEL c; + HAL_BOOL isSetup; /* has state to do a restore */ + uint32_t txFrameCount; /* Last txFrameCount */ + uint32_t rxFrameCount; /* Last rx Frame count */ + uint32_t cycleCount; /* Last cycleCount + (to detect wrap-around) */ + uint32_t ofdmPhyErrCount;/* OFDM err count since last reset */ + uint32_t cckPhyErrCount; /* CCK err count since last reset */ + + const struct ar5212AniParams *params; +}; + +#define HAL_ANI_ENA 0x00000001 /* ANI operation enabled */ +#define HAL_RSSI_ANI_ENA 0x00000002 /* rssi-based processing ena'd*/ + +struct ar5212Stats { + uint32_t ast_ani_niup; /* ANI increased noise immunity */ + uint32_t ast_ani_nidown; /* ANI decreased noise immunity */ + uint32_t ast_ani_spurup; /* ANI increased spur immunity */ + uint32_t ast_ani_spurdown;/* ANI descreased spur immunity */ + uint32_t ast_ani_ofdmon; /* ANI OFDM weak signal detect on */ + uint32_t ast_ani_ofdmoff;/* ANI OFDM weak signal detect off */ + uint32_t ast_ani_cckhigh;/* ANI CCK weak signal threshold high */ + uint32_t ast_ani_ccklow; /* ANI CCK weak signal threshold low */ + uint32_t ast_ani_stepup; /* ANI increased first step level */ + uint32_t ast_ani_stepdown;/* ANI decreased first step level */ + uint32_t ast_ani_ofdmerrs;/* ANI cumulative ofdm phy err count */ + uint32_t ast_ani_cckerrs;/* ANI cumulative cck phy err count */ + uint32_t ast_ani_reset; /* ANI parameters zero'd for non-STA */ + uint32_t ast_ani_lzero; /* ANI listen time forced to zero */ + uint32_t ast_ani_lneg; /* ANI listen time calculated < 0 */ + HAL_MIB_STATS ast_mibstats; /* MIB counter stats */ + HAL_NODE_STATS ast_nodestats; /* Latest rssi stats from driver */ +}; + +/* + * NF Cal history buffer + */ +#define AR5212_CCA_MAX_GOOD_VALUE -95 +#define AR5212_CCA_MAX_HIGH_VALUE -62 +#define AR5212_CCA_MIN_BAD_VALUE -125 + +#define AR512_NF_CAL_HIST_MAX 5 + +struct ar5212NfCalHist { + int16_t nfCalBuffer[AR512_NF_CAL_HIST_MAX]; + int16_t privNF; + uint8_t currIndex; + uint8_t first_run; + uint8_t invalidNFcount; +}; + +struct ath_hal_5212 { + struct ath_hal_private ah_priv; /* base class */ + + /* + * Per-chip common Initialization data. + * NB: RF backends have their own ini data. + */ + HAL_INI_ARRAY ah_ini_modes; + HAL_INI_ARRAY ah_ini_common; + + GAIN_VALUES ah_gainValues; + + uint8_t ah_macaddr[IEEE80211_ADDR_LEN]; + uint8_t ah_bssid[IEEE80211_ADDR_LEN]; + uint8_t ah_bssidmask[IEEE80211_ADDR_LEN]; + + /* + * Runtime state. + */ + uint32_t ah_maskReg; /* copy of AR_IMR */ + struct ar5212Stats ah_stats; /* various statistics */ + RF_HAL_FUNCS *ah_rfHal; + uint32_t ah_txDescMask; /* mask for TXDESC */ + uint32_t ah_txOkInterruptMask; + uint32_t ah_txErrInterruptMask; + uint32_t ah_txDescInterruptMask; + uint32_t ah_txEolInterruptMask; + uint32_t ah_txUrnInterruptMask; + HAL_TX_QUEUE_INFO ah_txq[HAL_NUM_TX_QUEUES]; + uint32_t ah_intrTxqs; /* tx q interrupt state */ + /* decomp mask array */ + uint8_t ah_decompMask[HAL_DECOMP_MASK_SIZE]; + HAL_POWER_MODE ah_powerMode; + HAL_ANT_SETTING ah_antControl; /* antenna setting */ + HAL_BOOL ah_diversity; /* fast diversity setting */ + enum { + IQ_CAL_INACTIVE, + IQ_CAL_RUNNING, + IQ_CAL_DONE + } ah_bIQCalibration; /* IQ calibrate state */ + HAL_RFGAIN ah_rfgainState; /* RF gain calibrartion state */ + uint32_t ah_tx6PowerInHalfDbm; /* power output for 6Mb tx */ + uint32_t ah_staId1Defaults; /* STA_ID1 default settings */ + uint32_t ah_miscMode; /* MISC_MODE settings */ + uint32_t ah_rssiThr; /* RSSI_THR settings */ + HAL_BOOL ah_cwCalRequire; /* for ap51 */ + HAL_BOOL ah_tpcEnabled; /* per-packet tpc enabled */ + HAL_BOOL ah_phyPowerOn; /* PHY power state */ + HAL_BOOL ah_isHb63; /* cached HB63 check */ + uint32_t ah_macTPC; /* tpc register */ + uint32_t ah_beaconInterval; /* XXX */ + enum { + AUTO_32KHZ, /* use it if 32kHz crystal present */ + USE_32KHZ, /* do it regardless */ + DONT_USE_32KHZ, /* don't use it regardless */ + } ah_enable32kHzClock; /* whether to sleep at 32kHz */ + uint32_t ah_ofdmTxPower; + int16_t ah_txPowerIndexOffset; + /* + * Noise floor cal histogram support. + */ + struct ar5212NfCalHist ah_nfCalHist; + + u_int ah_slottime; /* user-specified slot time */ + u_int ah_acktimeout; /* user-specified ack timeout */ + u_int ah_ctstimeout; /* user-specified cts timeout */ + u_int ah_sifstime; /* user-specified sifs time */ + /* + * RF Silent handling; setup according to the EEPROM. + */ + uint32_t ah_gpioSelect; /* GPIO pin to use */ + uint32_t ah_polarity; /* polarity to disable RF */ + uint32_t ah_gpioBit; /* after init, prev value */ + /* + * ANI support. + */ + uint32_t ah_procPhyErr; /* Process Phy errs */ + HAL_BOOL ah_hasHwPhyCounters; /* Hardware has phy counters */ + struct ar5212AniParams ah_aniParams24; /* 2.4GHz parameters */ + struct ar5212AniParams ah_aniParams5; /* 5GHz parameters */ + struct ar5212AniState *ah_curani; /* cached last reference */ + struct ar5212AniState ah_ani[64]; /* per-channel state */ + + /* + * Transmit power state. Note these are maintained + * here so they can be retrieved by diagnostic tools. + */ + uint16_t *ah_pcdacTable; + u_int ah_pcdacTableSize; + uint16_t ah_ratesArray[16]; +}; +#define AH5212(_ah) ((struct ath_hal_5212 *)(_ah)) + +/* + * IS_XXXX macros test the MAC version + * IS_RADXXX macros test the radio/RF version (matching both 2G-only and 2/5G) + * + * Some single chip radios have equivalent radio/RF (e.g. 5112) + * for those use IS_RADXXX_ANY macros. + */ +#define IS_2317(ah) \ + ((AH_PRIVATE(ah)->ah_devid == AR5212_AR2317_REV1) || \ + (AH_PRIVATE(ah)->ah_devid == AR5212_AR2317_REV2)) +#define IS_2316(ah) \ + (AH_PRIVATE(ah)->ah_macVersion == AR_SREV_2415) +#define IS_2413(ah) \ + (AH_PRIVATE(ah)->ah_macVersion == AR_SREV_2413 || IS_2316(ah)) +#define IS_5424(ah) \ + (AH_PRIVATE(ah)->ah_macVersion == AR_SREV_5424 || \ + (AH_PRIVATE(ah)->ah_macVersion == AR_SREV_5413 && \ + AH_PRIVATE(ah)->ah_macRev <= AR_SREV_D2PLUS_MS)) +#define IS_5413(ah) \ + (AH_PRIVATE(ah)->ah_macVersion == AR_SREV_5413 || IS_5424(ah)) +#define IS_2425(ah) \ + (AH_PRIVATE(ah)->ah_macVersion == AR_SREV_2425) +#define IS_2417(ah) \ + ((AH_PRIVATE(ah)->ah_macVersion) == AR_SREV_2417) +#define IS_HB63(ah) (AH5212(ah)->ah_isHb63 == AH_TRUE) + +#define IS_PCIE(ah) (IS_5424(ah) || IS_2425(ah)) + +#define AH_RADIO_MAJOR(ah) \ + (AH_PRIVATE(ah)->ah_analog5GhzRev & AR_RADIO_SREV_MAJOR) +#define AH_RADIO_MINOR(ah) \ + (AH_PRIVATE(ah)->ah_analog5GhzRev & AR_RADIO_SREV_MINOR) +#define IS_RAD5111(ah) \ + (AH_RADIO_MAJOR(ah) == AR_RAD5111_SREV_MAJOR || \ + AH_RADIO_MAJOR(ah) == AR_RAD2111_SREV_MAJOR) +#define IS_RAD5112(ah) \ + (AH_RADIO_MAJOR(ah) == AR_RAD5112_SREV_MAJOR || \ + AH_RADIO_MAJOR(ah) == AR_RAD2112_SREV_MAJOR) +/* NB: does not include 5413 as Atheros' IS_5112 macro does */ +#define IS_RAD5112_ANY(ah) \ + (AR_RAD5112_SREV_MAJOR <= AH_RADIO_MAJOR(ah) && \ + AH_RADIO_MAJOR(ah) <= AR_RAD2413_SREV_MAJOR) +#define IS_RAD5112_REV1(ah) \ + (IS_RAD5112(ah) && \ + AH_RADIO_MINOR(ah) < (AR_RAD5112_SREV_2_0 & AR_RADIO_SREV_MINOR)) +#define IS_RADX112_REV2(ah) \ + (AH_PRIVATE(ah)->ah_analog5GhzRev == AR_RAD5112_SREV_2_0 || \ + AH_PRIVATE(ah)->ah_analog5GhzRev == AR_RAD2112_SREV_2_0 || \ + AH_PRIVATE(ah)->ah_analog5GhzRev == AR_RAD2112_SREV_2_1 || \ + AH_PRIVATE(ah)->ah_analog5GhzRev == AR_RAD5112_SREV_2_1) + +#define ar5212RfDetach(ah) do { \ + if (AH5212(ah)->ah_rfHal != AH_NULL) \ + AH5212(ah)->ah_rfHal->rfDetach(ah); \ +} while (0) +#define ar5212GetRfBank(ah, b) \ + AH5212(ah)->ah_rfHal->getRfBank(ah, b) + +/* + * Hack macros for Nala/San: 11b is handled + * using 11g; flip the channel flags to accomplish this. + */ +#define SAVE_CCK(_ah, _chan, _flag) do { \ + if ((IS_2425(_ah) || IS_2417(_ah)) && \ + (((_chan)->channelFlags) & CHANNEL_CCK)) { \ + (_chan)->channelFlags &= ~CHANNEL_CCK; \ + (_chan)->channelFlags |= CHANNEL_OFDM; \ + (_flag) = AH_TRUE; \ + } \ +} while (0) +#define RESTORE_CCK(_ah, _chan, _flag) do { \ + if ((IS_2425(_ah) || IS_2417(_ah)) && (_flag) == AH_TRUE) {\ + (_chan)->channelFlags &= ~CHANNEL_OFDM; \ + (_chan)->channelFlags |= CHANNEL_CCK; \ + } \ +} while (0) + +struct ath_hal; + +extern uint32_t ar5212GetRadioRev(struct ath_hal *ah); +extern void ar5212InitState(struct ath_hal_5212 *, uint16_t devid, HAL_SOFTC, + HAL_BUS_TAG st, HAL_BUS_HANDLE sh, HAL_STATUS *status); +extern void ar5212Detach(struct ath_hal *ah); +extern HAL_BOOL ar5212ChipTest(struct ath_hal *ah); +extern HAL_BOOL ar5212GetChannelEdges(struct ath_hal *ah, + uint16_t flags, uint16_t *low, uint16_t *high); +extern HAL_BOOL ar5212FillCapabilityInfo(struct ath_hal *ah); + +extern void ar5212SetBeaconTimers(struct ath_hal *ah, + const HAL_BEACON_TIMERS *); +extern void ar5212BeaconInit(struct ath_hal *ah, + uint32_t next_beacon, uint32_t beacon_period); +extern void ar5212ResetStaBeaconTimers(struct ath_hal *ah); +extern void ar5212SetStaBeaconTimers(struct ath_hal *ah, + const HAL_BEACON_STATE *); + +extern HAL_BOOL ar5212IsInterruptPending(struct ath_hal *ah); +extern HAL_BOOL ar5212GetPendingInterrupts(struct ath_hal *ah, HAL_INT *); +extern HAL_INT ar5212GetInterrupts(struct ath_hal *ah); +extern HAL_INT ar5212SetInterrupts(struct ath_hal *ah, HAL_INT ints); + +extern uint32_t ar5212GetKeyCacheSize(struct ath_hal *); +extern HAL_BOOL ar5212IsKeyCacheEntryValid(struct ath_hal *, uint16_t entry); +extern HAL_BOOL ar5212ResetKeyCacheEntry(struct ath_hal *ah, uint16_t entry); +extern HAL_BOOL ar5212SetKeyCacheEntryMac(struct ath_hal *, + uint16_t entry, const uint8_t *mac); +extern HAL_BOOL ar5212SetKeyCacheEntry(struct ath_hal *ah, uint16_t entry, + const HAL_KEYVAL *k, const uint8_t *mac, int xorKey); + +extern void ar5212GetMacAddress(struct ath_hal *ah, uint8_t *mac); +extern HAL_BOOL ar5212SetMacAddress(struct ath_hal *ah, const uint8_t *); +extern void ar5212GetBssIdMask(struct ath_hal *ah, uint8_t *mac); +extern HAL_BOOL ar5212SetBssIdMask(struct ath_hal *, const uint8_t *); +extern HAL_BOOL ar5212EepromRead(struct ath_hal *, u_int off, uint16_t *data); +extern HAL_BOOL ar5212EepromWrite(struct ath_hal *, u_int off, uint16_t data); +extern HAL_BOOL ar5212SetRegulatoryDomain(struct ath_hal *ah, + uint16_t regDomain, HAL_STATUS *stats); +extern u_int ar5212GetWirelessModes(struct ath_hal *ah); +extern void ar5212EnableRfKill(struct ath_hal *); +extern HAL_BOOL ar5212GpioCfgOutput(struct ath_hal *, uint32_t gpio); +extern HAL_BOOL ar5212GpioCfgInput(struct ath_hal *, uint32_t gpio); +extern HAL_BOOL ar5212GpioSet(struct ath_hal *, uint32_t gpio, uint32_t val); +extern uint32_t ar5212GpioGet(struct ath_hal *ah, uint32_t gpio); +extern void ar5212GpioSetIntr(struct ath_hal *ah, u_int, uint32_t ilevel); +extern void ar5212SetLedState(struct ath_hal *ah, HAL_LED_STATE state); +extern void ar5212WriteAssocid(struct ath_hal *ah, const uint8_t *bssid, + uint16_t assocId); +extern uint32_t ar5212GetTsf32(struct ath_hal *ah); +extern uint64_t ar5212GetTsf64(struct ath_hal *ah); +extern void ar5212ResetTsf(struct ath_hal *ah); +extern void ar5212SetBasicRate(struct ath_hal *ah, HAL_RATE_SET *pSet); +extern uint32_t ar5212GetRandomSeed(struct ath_hal *ah); +extern HAL_BOOL ar5212DetectCardPresent(struct ath_hal *ah); +extern void ar5212EnableMibCounters(struct ath_hal *); +extern void ar5212DisableMibCounters(struct ath_hal *); +extern void ar5212UpdateMibCounters(struct ath_hal *ah, HAL_MIB_STATS* stats); +extern HAL_BOOL ar5212IsJapanChannelSpreadSupported(struct ath_hal *ah); +extern uint32_t ar5212GetCurRssi(struct ath_hal *ah); +extern u_int ar5212GetDefAntenna(struct ath_hal *ah); +extern void ar5212SetDefAntenna(struct ath_hal *ah, u_int antenna); +extern HAL_ANT_SETTING ar5212GetAntennaSwitch(struct ath_hal *); +extern HAL_BOOL ar5212SetAntennaSwitch(struct ath_hal *, HAL_ANT_SETTING); +extern HAL_BOOL ar5212IsSleepAfterBeaconBroken(struct ath_hal *ah); +extern HAL_BOOL ar5212SetSifsTime(struct ath_hal *, u_int); +extern u_int ar5212GetSifsTime(struct ath_hal *); +extern HAL_BOOL ar5212SetSlotTime(struct ath_hal *, u_int); +extern u_int ar5212GetSlotTime(struct ath_hal *); +extern HAL_BOOL ar5212SetAckTimeout(struct ath_hal *, u_int); +extern u_int ar5212GetAckTimeout(struct ath_hal *); +extern HAL_BOOL ar5212SetAckCTSRate(struct ath_hal *, u_int); +extern u_int ar5212GetAckCTSRate(struct ath_hal *); +extern HAL_BOOL ar5212SetCTSTimeout(struct ath_hal *, u_int); +extern u_int ar5212GetCTSTimeout(struct ath_hal *); +extern HAL_BOOL ar5212SetDecompMask(struct ath_hal *, uint16_t, int); +void ar5212SetCoverageClass(struct ath_hal *, uint8_t, int); +extern void ar5212SetPCUConfig(struct ath_hal *); +extern HAL_BOOL ar5212Use32KHzclock(struct ath_hal *ah, HAL_OPMODE opmode); +extern void ar5212SetupClock(struct ath_hal *ah, HAL_OPMODE opmode); +extern void ar5212RestoreClock(struct ath_hal *ah, HAL_OPMODE opmode); +extern int16_t ar5212GetNfAdjust(struct ath_hal *, + const HAL_CHANNEL_INTERNAL *); +extern void ar5212SetCompRegs(struct ath_hal *ah); +extern HAL_STATUS ar5212GetCapability(struct ath_hal *, HAL_CAPABILITY_TYPE, + uint32_t, uint32_t *); +extern HAL_BOOL ar5212SetCapability(struct ath_hal *, HAL_CAPABILITY_TYPE, + uint32_t, uint32_t, HAL_STATUS *); +extern HAL_BOOL ar5212GetDiagState(struct ath_hal *ah, int request, + const void *args, uint32_t argsize, + void **result, uint32_t *resultsize); + +extern HAL_BOOL ar5212SetPowerMode(struct ath_hal *ah, HAL_POWER_MODE mode, + int setChip); +extern HAL_POWER_MODE ar5212GetPowerMode(struct ath_hal *ah); +extern HAL_BOOL ar5212GetPowerStatus(struct ath_hal *ah); + +extern uint32_t ar5212GetRxDP(struct ath_hal *ath); +extern void ar5212SetRxDP(struct ath_hal *ah, uint32_t rxdp); +extern void ar5212EnableReceive(struct ath_hal *ah); +extern HAL_BOOL ar5212StopDmaReceive(struct ath_hal *ah); +extern void ar5212StartPcuReceive(struct ath_hal *ah); +extern void ar5212StopPcuReceive(struct ath_hal *ah); +extern void ar5212SetMulticastFilter(struct ath_hal *ah, + uint32_t filter0, uint32_t filter1); +extern HAL_BOOL ar5212ClrMulticastFilterIndex(struct ath_hal *, uint32_t ix); +extern HAL_BOOL ar5212SetMulticastFilterIndex(struct ath_hal *, uint32_t ix); +extern uint32_t ar5212GetRxFilter(struct ath_hal *ah); +extern void ar5212SetRxFilter(struct ath_hal *ah, uint32_t bits); +extern HAL_BOOL ar5212SetupRxDesc(struct ath_hal *, + struct ath_desc *, uint32_t size, u_int flags); +extern HAL_STATUS ar5212ProcRxDesc(struct ath_hal *ah, struct ath_desc *, + uint32_t, struct ath_desc *, uint64_t, + struct ath_rx_status *); + +extern HAL_BOOL ar5212Reset(struct ath_hal *ah, HAL_OPMODE opmode, + HAL_CHANNEL *chan, HAL_BOOL bChannelChange, HAL_STATUS *status); +extern HAL_BOOL ar5212SetChannel(struct ath_hal *, HAL_CHANNEL_INTERNAL *); +extern void ar5212SetOperatingMode(struct ath_hal *ah, int opmode); +extern HAL_BOOL ar5212PhyDisable(struct ath_hal *ah); +extern HAL_BOOL ar5212Disable(struct ath_hal *ah); +extern HAL_BOOL ar5212ChipReset(struct ath_hal *ah, HAL_CHANNEL *); +extern HAL_BOOL ar5212PerCalibration(struct ath_hal *ah, HAL_CHANNEL *chan, + HAL_BOOL *isIQdone); +extern HAL_BOOL ar5212PerCalibrationN(struct ath_hal *ah, HAL_CHANNEL *chan, + u_int chainMask, HAL_BOOL longCal, HAL_BOOL *isCalDone); +extern HAL_BOOL ar5212ResetCalValid(struct ath_hal *ah, HAL_CHANNEL *chan); +extern int16_t ar5212GetNoiseFloor(struct ath_hal *ah); +extern void ar5212InitNfCalHistBuffer(struct ath_hal *); +extern int16_t ar5212GetNfHistMid(const int16_t calData[]); +extern void ar5212SetSpurMitigation(struct ath_hal *, HAL_CHANNEL_INTERNAL *); +extern HAL_BOOL ar5212SetAntennaSwitchInternal(struct ath_hal *ah, + HAL_ANT_SETTING settings, const HAL_CHANNEL_INTERNAL *ichan); +extern HAL_BOOL ar5212SetTxPowerLimit(struct ath_hal *ah, uint32_t limit); +extern HAL_BOOL ar5212GetChipPowerLimits(struct ath_hal *ah, + HAL_CHANNEL *chans, uint32_t nchans); +extern void ar5212InitializeGainValues(struct ath_hal *); +extern HAL_RFGAIN ar5212GetRfgain(struct ath_hal *ah); +extern void ar5212RequestRfgain(struct ath_hal *); + +extern HAL_BOOL ar5212UpdateTxTrigLevel(struct ath_hal *, + HAL_BOOL IncTrigLevel); +extern HAL_BOOL ar5212SetTxQueueProps(struct ath_hal *ah, int q, + const HAL_TXQ_INFO *qInfo); +extern HAL_BOOL ar5212GetTxQueueProps(struct ath_hal *ah, int q, + HAL_TXQ_INFO *qInfo); +extern int ar5212SetupTxQueue(struct ath_hal *ah, HAL_TX_QUEUE type, + const HAL_TXQ_INFO *qInfo); +extern HAL_BOOL ar5212ReleaseTxQueue(struct ath_hal *ah, u_int q); +extern HAL_BOOL ar5212ResetTxQueue(struct ath_hal *ah, u_int q); +extern uint32_t ar5212GetTxDP(struct ath_hal *ah, u_int q); +extern HAL_BOOL ar5212SetTxDP(struct ath_hal *ah, u_int q, uint32_t txdp); +extern HAL_BOOL ar5212StartTxDma(struct ath_hal *ah, u_int q); +extern uint32_t ar5212NumTxPending(struct ath_hal *ah, u_int q); +extern HAL_BOOL ar5212StopTxDma(struct ath_hal *ah, u_int q); +extern HAL_BOOL ar5212SetupTxDesc(struct ath_hal *ah, struct ath_desc *ds, + u_int pktLen, u_int hdrLen, HAL_PKT_TYPE type, u_int txPower, + u_int txRate0, u_int txTries0, + u_int keyIx, u_int antMode, u_int flags, + u_int rtsctsRate, u_int rtsctsDuration, + u_int compicvLen, u_int compivLen, u_int comp); +extern HAL_BOOL ar5212SetupXTxDesc(struct ath_hal *, struct ath_desc *, + u_int txRate1, u_int txRetries1, + u_int txRate2, u_int txRetries2, + u_int txRate3, u_int txRetries3); +extern HAL_BOOL ar5212FillTxDesc(struct ath_hal *ah, struct ath_desc *ds, + u_int segLen, HAL_BOOL firstSeg, HAL_BOOL lastSeg, + const struct ath_desc *ds0); +extern HAL_STATUS ar5212ProcTxDesc(struct ath_hal *ah, + struct ath_desc *, struct ath_tx_status *); +extern void ar5212GetTxIntrQueue(struct ath_hal *ah, uint32_t *); +extern void ar5212IntrReqTxDesc(struct ath_hal *ah, struct ath_desc *); + +extern const HAL_RATE_TABLE *ar5212GetRateTable(struct ath_hal *, u_int mode); + +extern void ar5212AniAttach(struct ath_hal *, const struct ar5212AniParams *, + const struct ar5212AniParams *, HAL_BOOL ena); +extern void ar5212AniDetach(struct ath_hal *); +extern struct ar5212AniState *ar5212AniGetCurrentState(struct ath_hal *); +extern struct ar5212Stats *ar5212AniGetCurrentStats(struct ath_hal *); +extern HAL_BOOL ar5212AniControl(struct ath_hal *, HAL_ANI_CMD cmd, int param); +extern HAL_BOOL ar5212AniSetParams(struct ath_hal *, + const struct ar5212AniParams *, const struct ar5212AniParams *); +struct ath_rx_status; +extern void ar5212AniPhyErrReport(struct ath_hal *ah, + const struct ath_rx_status *rs); +extern void ar5212ProcessMibIntr(struct ath_hal *, const HAL_NODE_STATS *); +extern void ar5212AniPoll(struct ath_hal *, const HAL_NODE_STATS *, + HAL_CHANNEL *); +extern void ar5212AniReset(struct ath_hal *, HAL_CHANNEL_INTERNAL *, + HAL_OPMODE, int); +#endif /* _ATH_AR5212_H_ */ --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5212/ar5212.ini 2009-03-23 17:36:55.000000000 +0000 @@ -0,0 +1,2171 @@ +/* + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2008 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ar5212.ini,v 1.1 2009/03/23 17:14:47 sborrill Exp $ + */ +/* Auto Generated PCI Register Writes. Created: 09/01/04 */ + +#ifdef AH_5212_COMMON +static const uint32_t ar5212Modes[][6] = { + { 0x00001040, 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f }, + { 0x00001044, 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f }, + { 0x00001048, 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f }, + { 0x0000104c, 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f }, + { 0x00001050, 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f }, + { 0x00001054, 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f }, + { 0x00001058, 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f }, + { 0x0000105c, 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f }, + { 0x00001060, 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f }, + { 0x00001064, 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f }, + { 0x00001030, 0x00000230, 0x000001e0, 0x000000b0, 0x00000160, 0x000001e0 }, + { 0x00001070, 0x00000168, 0x000001e0, 0x000001b8, 0x0000018c, 0x000001e0 }, + { 0x000010b0, 0x00000e60, 0x00001180, 0x00001f1c, 0x00003e38, 0x00001180 }, + { 0x000010f0, 0x0000a0e0, 0x00014068, 0x00005880, 0x0000b0e0, 0x00014068 }, + { 0x00008014, 0x03e803e8, 0x06e006e0, 0x04200420, 0x08400840, 0x06e006e0 }, + { 0x00009804, 0x00000000, 0x00000003, 0x00000000, 0x00000000, 0x00000003 }, + { 0x00009820, 0x02020200, 0x02020200, 0x02010200, 0x02020200, 0x02020200 }, + { 0x00009824, 0x00000e0e, 0x00000e0e, 0x00000707, 0x00000e0e, 0x00000e0e }, + { 0x00009844, 0x1372161c, 0x13721c25, 0x13721722, 0x137216a2, 0x13721c25 }, + { 0x00009860, 0x00009d10, 0x00009d10, 0x00009d18, 0x00009d18, 0x00009d10 }, + { 0x00009864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 }, + { 0x00009868, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190 }, + { 0x00009918, 0x000001b8, 0x000001b8, 0x00000084, 0x00000108, 0x000001b8 }, + { 0x00009924, 0x10058a05, 0x10058a05, 0x10058a05, 0x10058a05, 0x10058a05 }, + { 0x0000a230, 0x00000000, 0x00000000, 0x00000000, 0x00000108, 0x00000000 }, +}; +#endif /* AH_5212_COMMON */ + +#ifdef AH_5212_5111 +static const uint32_t ar5212Modes_5111[][6] = { + { 0x00000030, 0x00008015, 0x00008015, 0x00008015, 0x00008015, 0x00008015 }, + { 0x0000801c, 0x128d8fa7, 0x09880fcf, 0x04e00f95, 0x12e00fab, 0x09880fcf }, + { 0x00009828, 0x0a020001, 0x0a020001, 0x05010100, 0x0a020001, 0x0a020001 }, + { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, + { 0x00009838, 0x00000007, 0x00000007, 0x0000000b, 0x0000000b, 0x0000000b }, + { 0x00009848, 0x0018da5a, 0x0018da5a, 0x0018ca69, 0x0018ca69, 0x0018ca69 }, + { 0x00009850, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0 }, + { 0x00009858, 0x7e800d2e, 0x7e800d2e, 0x7ee84d2e, 0x7ee84d2e, 0x7e800d2e }, + { 0x0000985c, 0x3137665e, 0x3137665e, 0x3137665e, 0x3137665e, 0x3137615e }, + { 0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb080, 0x050cb080 }, + { 0x00009914, 0x00002710, 0x00002710, 0x0000157c, 0x00002af8, 0x00002710 }, + { 0x00009944, 0xf7b81020, 0xf7b81020, 0xf7b80d20, 0xf7b81020, 0xf7b81020 }, + { 0x0000a20c, 0x642c416a, 0x642c416a, 0x6440416a, 0x6440416a, 0x6440416a }, + { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1873800a, 0x1883800a, 0x1883800a }, +}; +#endif /* AH_5212_5111 */ + +#ifdef AH_5212_5112 +static const uint32_t ar5212Modes_5112[][6] = { + { 0x00000030, 0x00008015, 0x00008015, 0x00008015, 0x00008015, 0x00008015 }, + { 0x0000801c, 0x128d93a7, 0x098813cf, 0x04e01395, 0x12e013ab, 0x098813cf }, + { 0x00009828, 0x0a020001, 0x0a020001, 0x05020100, 0x0a020001, 0x0a020001 }, + { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, + { 0x00009838, 0x00000007, 0x00000007, 0x0000000b, 0x0000000b, 0x0000000b }, + { 0x00009848, 0x0018da6d, 0x0018da6d, 0x0018ca75, 0x0018ca75, 0x0018ca75 }, + { 0x00009850, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0 }, + { 0x00009858, 0x7e800d2e, 0x7e800d2e, 0x7ee80d2e, 0x7ee80d2e, 0x7e800d2e }, + { 0x0000985c, 0x3137665e, 0x3137665e, 0x3137665e, 0x3137665e, 0x3137665e }, + { 0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 }, + { 0x00009914, 0x000007d0, 0x000007d0, 0x0000044c, 0x00000898, 0x000007d0 }, + { 0x00009944, 0xf7b81020, 0xf7b81020, 0xf7b80d10, 0xf7b81010, 0xf7b81010 }, + { 0x0000a204, 0x00000000, 0x00000000, 0x00000008, 0x00000008, 0x00000008 }, + { 0x0000a208, 0xd6be6788, 0xd6be6788, 0xd03e6788, 0xd03e6788, 0xd03e6788 }, + { 0x0000a20c, 0x642c0140, 0x642c0140, 0x6442c160, 0x6442c160, 0x6442c160 }, + { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1873800a, 0x1883800a, 0x1883800a }, +}; +#endif /* AH_5212_5112 */ + +#ifdef AH_5212_2413 +static const uint32_t ar5212Modes_2413[][6] = { + { 0x00000030, 0x00000015, 0x00000015, 0x00000015, 0x00000015, 0x00000015 }, + { 0x0000801c, 0x128d93a7, 0x098813cf, 0x04e01395, 0x12e013ab, 0x098813cf }, + { 0x00009828, 0x0a020001, 0x0a020001, 0x05020000, 0x0a020001, 0x0a020001 }, + { 0x00009834, 0x00000e00, 0x00000e00, 0x00000e00, 0x00000e00, 0x00000e00 }, + { 0x00009838, 0x00000002, 0x00000002, 0x0000000a, 0x0000000a, 0x0000000a }, + { 0x00009848, 0x0018da6d, 0x0018da6d, 0x001a6a64, 0x001a6a64, 0x001a6a64 }, + { 0x00009850, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b0da, 0x0c98b0da, 0x0de8b0da }, + { 0x00009858, 0x7e800d2e, 0x7e800d2e, 0x7ee80d2e, 0x7ec80d2e, 0x7e800d2e }, + { 0x0000985c, 0x3137665e, 0x3137665e, 0x3137665e, 0x3139605e, 0x3137665e }, + { 0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 }, + { 0x00009914, 0x000007d0, 0x000007d0, 0x0000044c, 0x00000898, 0x000007d0 }, + { 0x00009944, 0xf7b81000, 0xf7b81000, 0xf7b80d00, 0xf7b81000, 0xf7b81000 }, + { 0x0000a204, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a208, 0xd6be6788, 0xd6be6788, 0xd03e6788, 0xd03e6788, 0xd03e6788 }, + { 0x0000a20c, 0x002c0140, 0x002c0140, 0x0042c140, 0x0042c140, 0x0042c140 }, + { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1863800a, 0x1883800a, 0x1883800a }, +}; +#endif /* AH_5212_2413 */ + +#ifdef AH_5212_2316 +static const uint32_t ar5212Modes_2316[][6] = { + { 0x00000030, 0x00000015, 0x00000015, 0x00000015, 0x00000015, 0x00000015 }, + { 0x0000801c, 0x128d93a7, 0x098813cf, 0x04e01395, 0x12e013ab, 0x098813cf }, + { 0x00009828, 0x0a020001, 0x0a020001, 0x05020000, 0x0a020001, 0x0a020001 }, + { 0x00009834, 0x00000e00, 0x00000e00, 0x00000e00, 0x00000e00, 0x00000e00 }, + { 0x00009838, 0x00000002, 0x00000002, 0x0000000a, 0x0000000a, 0x0000000a }, + { 0x00009848, 0x0018da6d, 0x0018da6d, 0x001a6a64, 0x001a6a64, 0x001a6a64 }, + { 0x00009850, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b0da, 0x0c98b0da, 0x0de8b0da }, + { 0x00009858, 0x7e800d2e, 0x7e800d2e, 0x7ee80d2e, 0x7ec80d2e, 0x7e800d2e }, + { 0x0000985c, 0x3137665e, 0x3137665e, 0x3137665e, 0x3139605e, 0x3137665e }, + { 0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 }, + { 0x00009914, 0x000007d0, 0x000007d0, 0x0000044c, 0x00000898, 0x000007d0 }, + { 0x00009944, 0xf7b81000, 0xf7b81000, 0xf7b80d00, 0xf7b81000, 0xf7b81000 }, + { 0x0000a204, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a208, 0xd6be6788, 0xd6be6788, 0xd03e6788, 0xd03e6788, 0xd03e6788 }, + { 0x0000a20c, 0x002c0140, 0x002c0140, 0x0042c140, 0x0042c140, 0x0042c140 }, + { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1863800a, 0x1883800a, 0x1883800a }, +}; +#endif + +#ifdef AH_5212_5413 +static const uint32_t ar5212Modes_5413[][6] = { + { 0x00000030, 0x00000015, 0x00000015, 0x00000015, 0x00000015, 0x00000015 }, + { 0x0000801c, 0x128d93a7, 0x098813cf, 0x04e01395, 0x12e013ab, 0x098813cf }, + { 0x00009828, 0x0a020001, 0x0a020001, 0x05020100, 0x0a020001, 0x0a020001 }, + { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, + { 0x00009838, 0x00000007, 0x00000007, 0x0000000b, 0x0000000b, 0x0000000b }, + { 0x00009848, 0x0018fa61, 0x0018fa61, 0x001a1a63, 0x001a1a63, 0x001a1a63 }, + { 0x00009850, 0x0c98b4e0, 0x0c98b4e0, 0x0c98b0da, 0x0c98b0da, 0x0c98b0da }, + { 0x00009858, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e }, + { 0x0000985c, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e }, + { 0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 }, + { 0x00009914, 0x000007d0, 0x000007d0, 0x0000044c, 0x00000898, 0x000007d0 }, + { 0x00009944, 0xf7b81000, 0xf7b81000, 0xf7b80d00, 0xf7b81000, 0xf7b81000 }, + { 0x0000a204, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a208, 0xd6be6788, 0xd6be6788, 0xd03e6788, 0xd03e6788, 0xd03e6788 }, + { 0x0000a20c, 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120, 0x002ac120 }, + { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1863800a, 0x1883800a, 0x1883800a }, + { 0x0000a300, 0x18010000, 0x18010000, 0x18010000, 0x18010000, 0x18010000 }, + { 0x0000a304, 0x30032602, 0x30032602, 0x30032602, 0x30032602, 0x30032602 }, + { 0x0000a308, 0x48073e06, 0x48073e06, 0x48073e06, 0x48073e06, 0x48073e06 }, + { 0x0000a30c, 0x560b4c0a, 0x560b4c0a, 0x560b4c0a, 0x560b4c0a, 0x560b4c0a }, + { 0x0000a310, 0x641a600f, 0x641a600f, 0x641a600f, 0x641a600f, 0x641a600f }, + { 0x0000a314, 0x784f6e1b, 0x784f6e1b, 0x784f6e1b, 0x784f6e1b, 0x784f6e1b }, + { 0x0000a318, 0x868f7c5a, 0x868f7c5a, 0x868f7c5a, 0x868f7c5a, 0x868f7c5a }, + { 0x0000a31c, 0x90cf865b, 0x90cf865b, 0x8ecf865b, 0x8ecf865b, 0x8ecf865b }, + { 0x0000a320, 0x9d4f970f, 0x9d4f970f, 0x9b4f970f, 0x9b4f970f, 0x9b4f970f }, + { 0x0000a324, 0xa7cfa38f, 0xa7cfa38f, 0xa3cf9f8f, 0xa3cf9f8f, 0xa3cf9f8f }, + { 0x0000a328, 0xb55faf1f, 0xb55faf1f, 0xb35faf1f, 0xb35faf1f, 0xb35faf1f }, + { 0x0000a32c, 0xbddfb99f, 0xbddfb99f, 0xbbdfb99f, 0xbbdfb99f, 0xbbdfb99f }, + { 0x0000a330, 0xcb7fc53f, 0xcb7fc53f, 0xcb7fc73f, 0xcb7fc73f, 0xcb7fc73f }, + { 0x0000a334, 0xd5ffd1bf, 0xd5ffd1bf, 0xd3ffd1bf, 0xd3ffd1bf, 0xd3ffd1bf }, +}; +#endif /* AH_5212_5413 */ + +#ifdef AH_5212_2425 +static const uint32_t ar5212Modes_2425[][6] = { + { 0x00000030, 0x00000015, 0x00000015, 0x00000015, 0x00000015, 0x00000015 }, + { 0x0000801c, 0x128d93a7, 0x098813cf, 0x04e01395, 0x12e013ab, 0x098813cf }, + { 0x00009804, 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000001 }, + { 0x00009828, 0x0a020001, 0x0a020001, 0x05020100, 0x0a020001, 0x0a020001 }, + { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, + { 0x00009838, 0x00000003, 0x00000003, 0x0000000b, 0x0000000b, 0x0000000b }, + { 0x00009844, 0x1372161c, 0x13721c25, 0x13721722, 0x13721422, 0x13721c25 }, + { 0x00009848, 0x0018fa61, 0x0018fa61, 0x00199a65, 0x00199a65, 0x00199a65 }, + { 0x00009850, 0x0c98b4e0, 0x0c98b4e0, 0x0c98b0da, 0x0c98b0da, 0x0c98b0da }, + { 0x00009858, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e }, + { 0x0000985c, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e }, + { 0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 }, + { 0x00009914, 0x000007d0, 0x000007d0, 0x0000044c, 0x00000898, 0x000007d0 }, + { 0x00009944, 0xf7b81000, 0xf7b81000, 0xf7b80d00, 0xf7b81000, 0xf7b81000 }, + { 0x0000a204, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a208, 0xd6be6788, 0xd6be6788, 0xd03e6788, 0xd03e6788, 0xd03e6788 }, + { 0x0000a20c, 0x00000140, 0x00000140, 0x0052c140, 0x0052c140, 0x0052c140 }, + { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1863800a, 0x1883800a, 0x1883800a }, + { 0x0000a324, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf }, + { 0x0000a328, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf }, + { 0x0000a32c, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf }, + { 0x0000a330, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf }, + { 0x0000a334, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf }, +}; +#endif /* AH_5212_2425 */ + +#ifdef AH_5212_COMMON +static const uint32_t ar5212Common[][2] = { + { 0x0000000c, 0x00000000 }, + { 0x00000034, 0x00000005 }, + { 0x00000040, 0x00000000 }, + { 0x00000044, 0x00000008 }, + { 0x00000048, 0x00000008 }, + { 0x0000004c, 0x00000010 }, + { 0x00000050, 0x00000000 }, + { 0x00000054, 0x0000001f }, + { 0x00000800, 0x00000000 }, + { 0x00000804, 0x00000000 }, + { 0x00000808, 0x00000000 }, + { 0x0000080c, 0x00000000 }, + { 0x00000810, 0x00000000 }, + { 0x00000814, 0x00000000 }, + { 0x00000818, 0x00000000 }, + { 0x0000081c, 0x00000000 }, + { 0x00000820, 0x00000000 }, + { 0x00000824, 0x00000000 }, + { 0x00001270, 0x00000000 }, + { 0x00001038, 0x00000000 }, + { 0x00001078, 0x00000000 }, + { 0x000010b8, 0x00000000 }, + { 0x000010f8, 0x00000000 }, + { 0x00001138, 0x00000000 }, + { 0x00001178, 0x00000000 }, + { 0x000011b8, 0x00000000 }, + { 0x000011f8, 0x00000000 }, + { 0x00001238, 0x00000000 }, + { 0x00001278, 0x00000000 }, + { 0x000012b8, 0x00000000 }, + { 0x000012f8, 0x00000000 }, + { 0x00001338, 0x00000000 }, + { 0x00001378, 0x00000000 }, + { 0x000013b8, 0x00000000 }, + { 0x000013f8, 0x00000000 }, + { 0x00001438, 0x00000000 }, + { 0x00001478, 0x00000000 }, + { 0x000014b8, 0x00000000 }, + { 0x000014f8, 0x00000000 }, + { 0x00001538, 0x00000000 }, + { 0x00001578, 0x00000000 }, + { 0x000015b8, 0x00000000 }, + { 0x000015f8, 0x00000000 }, + { 0x00001638, 0x00000000 }, + { 0x00001678, 0x00000000 }, + { 0x000016b8, 0x00000000 }, + { 0x000016f8, 0x00000000 }, + { 0x00001738, 0x00000000 }, + { 0x00001778, 0x00000000 }, + { 0x000017b8, 0x00000000 }, + { 0x000017f8, 0x00000000 }, + { 0x0000103c, 0x00000000 }, + { 0x0000107c, 0x00000000 }, + { 0x000010bc, 0x00000000 }, + { 0x000010fc, 0x00000000 }, + { 0x0000113c, 0x00000000 }, + { 0x0000117c, 0x00000000 }, + { 0x000011bc, 0x00000000 }, + { 0x000011fc, 0x00000000 }, + { 0x0000123c, 0x00000000 }, + { 0x0000127c, 0x00000000 }, + { 0x000012bc, 0x00000000 }, + { 0x000012fc, 0x00000000 }, + { 0x0000133c, 0x00000000 }, + { 0x0000137c, 0x00000000 }, + { 0x000013bc, 0x00000000 }, + { 0x000013fc, 0x00000000 }, + { 0x0000143c, 0x00000000 }, + { 0x0000147c, 0x00000000 }, + { 0x00008004, 0x00000000 }, + { 0x00008008, 0x00000000 }, + { 0x0000800c, 0x00000000 }, + { 0x00008020, 0x00000000 }, + { 0x00008024, 0x00000000 }, + { 0x00008028, 0x00000030 }, + { 0x0000802c, 0x0007ffff }, + { 0x00008030, 0x01ffffff }, + { 0x00008034, 0x00000031 }, + { 0x00008038, 0x00000000 }, + { 0x0000803c, 0x00000000 }, + { 0x00008048, 0x00000000 }, + { 0x00008054, 0x00000000 }, + { 0x00008058, 0x00000000 }, + { 0x0000805c, 0x000fc78f }, + { 0x000080c0, 0x2a82301a }, + { 0x000080c4, 0x05dc01e0 }, + { 0x000080c8, 0x1f402710 }, + { 0x000080cc, 0x01f40000 }, + { 0x000080d0, 0x00001e1c }, + { 0x000080d4, 0x0002aaaa }, + { 0x000080d8, 0x02005555 }, + { 0x000080dc, 0x00000000 }, + { 0x000080e0, 0xffffffff }, + { 0x000080e4, 0x0000ffff }, + { 0x000080e8, 0x00000000 }, + { 0x000080ec, 0x00000000 }, + { 0x000080f0, 0x00000000 }, + { 0x000080f4, 0x00000000 }, + { 0x000080f8, 0x00000000 }, + { 0x000080fc, 0x00000088 }, + { 0x00008700, 0x00000000 }, + { 0x00008704, 0x0000008c }, + { 0x00008708, 0x000000e4 }, + { 0x0000870c, 0x000002d5 }, + { 0x00008710, 0x00000000 }, + { 0x00008714, 0x00000000 }, + { 0x00008718, 0x000000a0 }, + { 0x0000871c, 0x000001c9 }, + { 0x00008720, 0x0000002c }, + { 0x00008724, 0x0000002c }, + { 0x00008728, 0x00000030 }, + { 0x0000872c, 0x0000003c }, + { 0x00008730, 0x0000002c }, + { 0x00008734, 0x0000002c }, + { 0x00008738, 0x00000030 }, + { 0x0000873c, 0x0000003c }, + { 0x00008740, 0x00000000 }, + { 0x00008744, 0x00000000 }, + { 0x00008748, 0x00000000 }, + { 0x0000874c, 0x00000000 }, + { 0x00008750, 0x00000000 }, + { 0x00008754, 0x00000000 }, + { 0x00008758, 0x00000000 }, + { 0x0000875c, 0x00000000 }, + { 0x00008760, 0x000000d5 }, + { 0x00008764, 0x000000df }, + { 0x00008768, 0x00000102 }, + { 0x0000876c, 0x0000013a }, + { 0x00008770, 0x00000075 }, + { 0x00008774, 0x0000007f }, + { 0x00008778, 0x000000a2 }, + { 0x0000877c, 0x00000000 }, + { 0x00008100, 0x00010002 }, + { 0x00008104, 0x00000001 }, + { 0x00008108, 0x000000c0 }, + { 0x0000810c, 0x00000000 }, + { 0x00008110, 0x00000168 }, + { 0x00008114, 0x00000000 }, + { 0x000087c0, 0x03020100 }, + { 0x000087c4, 0x07060504 }, + { 0x000087c8, 0x0b0a0908 }, + { 0x000087cc, 0x0f0e0d0c }, + { 0x000087d0, 0x13121110 }, + { 0x000087d4, 0x17161514 }, + { 0x000087d8, 0x1b1a1918 }, + { 0x000087dc, 0x1f1e1d1c }, + { 0x000087e0, 0x03020100 }, + { 0x000087e4, 0x07060504 }, + { 0x000087e8, 0x0b0a0908 }, + { 0x000087ec, 0x0f0e0d0c }, + { 0x000087f0, 0x13121110 }, + { 0x000087f4, 0x17161514 }, + { 0x000087f8, 0x1b1a1918 }, + { 0x000087fc, 0x1f1e1d1c }, + { 0x0000980c, 0xad848e19 }, + { 0x00009810, 0x7d28e000 }, + { 0x00009814, 0x9c0a9f6b }, + { 0x0000981c, 0x00000000 }, + { 0x00009840, 0x206a017a }, + { 0x00009854, 0x00000859 }, + { 0x00009900, 0x00000000 }, + { 0x00009904, 0x00000000 }, + { 0x00009908, 0x00000000 }, + { 0x0000990c, 0x00800000 }, + { 0x00009910, 0x00000001 }, + { 0x0000991c, 0x00000c80 }, + { 0x00009920, 0x05100000 }, + { 0x00009928, 0x00000001 }, + { 0x0000992c, 0x00000004 }, + { 0x00009934, 0x1e1f2022 }, + { 0x00009938, 0x0a0b0c0d }, + { 0x0000993c, 0x0000003f }, + { 0x00009948, 0x9280b212 }, + { 0x00009954, 0x5d50e188 }, + { 0x0000995c, 0x004b6a8e }, + { 0x00009968, 0x000003ce }, + { 0x00009970, 0x192fb515 }, + { 0x00009978, 0x00000001 }, + { 0x0000997c, 0x00000000 }, + { 0x0000a210, 0x00806333 }, + { 0x0000a214, 0x00106c10 }, + { 0x0000a218, 0x009c4060 }, + { 0x0000a220, 0x018830c6 }, + { 0x0000a224, 0x00000400 }, + { 0x0000a22c, 0x00000000 }, + { 0x0000a234, 0x20202020 }, + { 0x0000a238, 0x20202020 }, + { 0x0000a240, 0x38490a20 }, + { 0x0000a244, 0x00007bb6 }, + { 0x0000a248, 0x0fff3ffc }, + { 0x00009b00, 0x00000000 }, + { 0x00009b28, 0x0000000c }, + { 0x00009b38, 0x00000012 }, + { 0x00009b64, 0x00000021 }, + { 0x00009b8c, 0x0000002d }, + { 0x00009b9c, 0x00000033 }, +}; +#endif /* AH_5212_COMMON */ + +#ifdef AH_5212_5111 +static const uint32_t ar5212Common_5111[][2] = { + { 0x00001230, 0x00000000 }, + { 0x00009808, 0x00000000 }, + { 0x0000982c, 0x00022ffe }, + { 0x0000983c, 0x00020100 }, + { 0x0000984c, 0x1284613c }, + { 0x00009930, 0x00004883 }, + { 0x00009940, 0x00000004 }, + { 0x00009958, 0x000000ff }, + { 0x00009974, 0x00000000 }, + { 0x000099f8, 0x00000018 }, + { 0x0000a204, 0x00000000 }, + { 0x0000a208, 0xd03e6788 }, + { 0x0000a228, 0x000001b5 }, + { 0x0000a23c, 0x13c889af }, + { 0x00009b04, 0x00000020 }, + { 0x00009b08, 0x00000010 }, + { 0x00009b0c, 0x00000030 }, + { 0x00009b10, 0x00000008 }, + { 0x00009b14, 0x00000028 }, + { 0x00009b18, 0x00000004 }, + { 0x00009b1c, 0x00000024 }, + { 0x00009b20, 0x00000014 }, + { 0x00009b24, 0x00000034 }, + { 0x00009b2c, 0x0000002c }, + { 0x00009b30, 0x00000002 }, + { 0x00009b34, 0x00000022 }, + { 0x00009b3c, 0x00000032 }, + { 0x00009b40, 0x0000000a }, + { 0x00009b44, 0x0000002a }, + { 0x00009b48, 0x00000006 }, + { 0x00009b4c, 0x00000026 }, + { 0x00009b50, 0x00000016 }, + { 0x00009b54, 0x00000036 }, + { 0x00009b58, 0x0000000e }, + { 0x00009b5c, 0x0000002e }, + { 0x00009b60, 0x00000001 }, + { 0x00009b68, 0x00000011 }, + { 0x00009b6c, 0x00000031 }, + { 0x00009b70, 0x00000009 }, + { 0x00009b74, 0x00000029 }, + { 0x00009b78, 0x00000005 }, + { 0x00009b7c, 0x00000025 }, + { 0x00009b80, 0x00000015 }, + { 0x00009b84, 0x00000035 }, + { 0x00009b88, 0x0000000d }, + { 0x00009b90, 0x00000003 }, + { 0x00009b94, 0x00000023 }, + { 0x00009b98, 0x00000013 }, + { 0x00009ba0, 0x0000000b }, + { 0x00009ba4, 0x0000002b }, + { 0x00009ba8, 0x0000002b }, + { 0x00009bac, 0x0000002b }, + { 0x00009bb0, 0x0000002b }, + { 0x00009bb4, 0x0000002b }, + { 0x00009bb8, 0x0000002b }, + { 0x00009bbc, 0x0000002b }, + { 0x00009bc0, 0x0000002b }, + { 0x00009bc4, 0x0000002b }, + { 0x00009bc8, 0x0000002b }, + { 0x00009bcc, 0x0000002b }, + { 0x00009bd0, 0x0000002b }, + { 0x00009bd4, 0x0000002b }, + { 0x00009bd8, 0x0000002b }, + { 0x00009bdc, 0x0000002b }, + { 0x00009be0, 0x0000002b }, + { 0x00009be4, 0x0000002b }, + { 0x00009be8, 0x0000002b }, + { 0x00009bec, 0x0000002b }, + { 0x00009bf0, 0x0000002b }, + { 0x00009bf4, 0x0000002b }, + { 0x00009bf8, 0x00000002 }, + { 0x00009bfc, 0x00000016 }, +}; +#endif /* AH_5212_5111 */ + +#ifdef AH_5212_5112 +static const uint32_t ar5212Common_5112[][2] = { + { 0x00001230, 0x00000000 }, + { 0x00009808, 0x00000000 }, + { 0x0000982c, 0x00022ffe }, + { 0x0000983c, 0x00020100 }, + { 0x0000984c, 0x1284613c }, + { 0x00009930, 0x00004882 }, + { 0x00009940, 0x00000004 }, + { 0x00009958, 0x000000ff }, + { 0x00009974, 0x00000000 }, + { 0x0000a228, 0x000001b5 }, + { 0x0000a23c, 0x13c889af }, + { 0x00009b04, 0x00000001 }, + { 0x00009b08, 0x00000002 }, + { 0x00009b0c, 0x00000003 }, + { 0x00009b10, 0x00000004 }, + { 0x00009b14, 0x00000005 }, + { 0x00009b18, 0x00000008 }, + { 0x00009b1c, 0x00000009 }, + { 0x00009b20, 0x0000000a }, + { 0x00009b24, 0x0000000b }, + { 0x00009b2c, 0x0000000d }, + { 0x00009b30, 0x00000010 }, + { 0x00009b34, 0x00000011 }, + { 0x00009b3c, 0x00000013 }, + { 0x00009b40, 0x00000014 }, + { 0x00009b44, 0x00000015 }, + { 0x00009b48, 0x00000018 }, + { 0x00009b4c, 0x00000019 }, + { 0x00009b50, 0x0000001a }, + { 0x00009b54, 0x0000001b }, + { 0x00009b58, 0x0000001c }, + { 0x00009b5c, 0x0000001d }, + { 0x00009b60, 0x00000020 }, + { 0x00009b68, 0x00000022 }, + { 0x00009b6c, 0x00000023 }, + { 0x00009b70, 0x00000024 }, + { 0x00009b74, 0x00000025 }, + { 0x00009b78, 0x00000028 }, + { 0x00009b7c, 0x00000029 }, + { 0x00009b80, 0x0000002a }, + { 0x00009b84, 0x0000002b }, + { 0x00009b88, 0x0000002c }, + { 0x00009b90, 0x00000030 }, + { 0x00009b94, 0x00000031 }, + { 0x00009b98, 0x00000032 }, + { 0x00009ba0, 0x00000034 }, + { 0x00009ba4, 0x00000035 }, + { 0x00009ba8, 0x00000035 }, + { 0x00009bac, 0x00000035 }, + { 0x00009bb0, 0x00000035 }, + { 0x00009bb4, 0x00000035 }, + { 0x00009bb8, 0x00000035 }, + { 0x00009bbc, 0x00000035 }, + { 0x00009bc0, 0x00000035 }, + { 0x00009bc4, 0x00000035 }, + { 0x00009bc8, 0x00000035 }, + { 0x00009bcc, 0x00000035 }, + { 0x00009bd0, 0x00000035 }, + { 0x00009bd4, 0x00000035 }, + { 0x00009bd8, 0x00000035 }, + { 0x00009bdc, 0x00000035 }, + { 0x00009be0, 0x00000035 }, + { 0x00009be4, 0x00000035 }, + { 0x00009be8, 0x00000035 }, + { 0x00009bec, 0x00000035 }, + { 0x00009bf0, 0x00000035 }, + { 0x00009bf4, 0x00000035 }, + { 0x00009bf8, 0x00000010 }, + { 0x00009bfc, 0x0000001a }, +}; +#endif /* AH_5212_5112 */ + +#ifdef AH_5212_2413 +static const uint32_t ar5212Common_2413[][2] = { + { 0x00001230, 0x000003e0 }, + { 0x00008060, 0x0000000f }, + { 0x00008118, 0x00000000 }, + { 0x0000811c, 0x00000000 }, + { 0x00008120, 0x00000000 }, + { 0x00008124, 0x00000000 }, + { 0x00008128, 0x00000000 }, + { 0x0000812c, 0x00000000 }, + { 0x00008130, 0x00000000 }, + { 0x00008134, 0x00000000 }, + { 0x00008138, 0x00000000 }, + { 0x0000813c, 0x00000000 }, + { 0x00008140, 0x800000a8 }, + { 0x00008144, 0x00000000 }, + { 0x00009808, 0x00000000 }, + { 0x0000982c, 0x0000a000 }, + { 0x0000983c, 0x00200400 }, + { 0x0000984c, 0x1284233c }, + { 0x00009870, 0x0000001f }, + { 0x00009874, 0x00000080 }, + { 0x00009878, 0x0000000e }, + { 0x00009958, 0x000000ff }, + { 0x00009980, 0x00000000 }, + { 0x00009984, 0x02800000 }, + { 0x000099a0, 0x00000000 }, + { 0x000099e0, 0x00000000 }, + { 0x000099e4, 0xaaaaaaaa }, + { 0x000099e8, 0x3c466478 }, + { 0x000099ec, 0x000000aa }, + { 0x000099f0, 0x0000000c }, + { 0x000099f4, 0x000000ff }, + { 0x000099f8, 0x00000014 }, + { 0x0000a228, 0x000009b5 }, + { 0x0000a23c, 0x93c889af }, + { 0x0000a24c, 0x00000001 }, + { 0x0000a250, 0x0000a000 }, + { 0x0000a254, 0x00000000 }, + { 0x0000a258, 0x0cc75380 }, + { 0x0000a25c, 0x0f0f0f01 }, + { 0x0000a260, 0x5f690f01 }, + { 0x0000a264, 0x00418a11 }, + { 0x0000a268, 0x00000000 }, + { 0x0000a26c, 0x0c30c16a }, + { 0x0000a270, 0x00820820 }, + { 0x0000a274, 0x001b7caa }, + { 0x0000a278, 0x1ce739ce }, + { 0x0000a27c, 0x051701ce }, + { 0x0000a300, 0x18010000 }, + { 0x0000a304, 0x30032602 }, + { 0x0000a308, 0x48073e06 }, + { 0x0000a30c, 0x560b4c0a }, + { 0x0000a310, 0x641a600f }, + { 0x0000a314, 0x784f6e1b }, + { 0x0000a318, 0x868f7c5a }, + { 0x0000a31c, 0x8ecf865b }, + { 0x0000a320, 0x9d4f970f }, + { 0x0000a324, 0xa5cfa18f }, + { 0x0000a328, 0xb55faf1f }, + { 0x0000a32c, 0xbddfb99f }, + { 0x0000a330, 0xcd7fc73f }, + { 0x0000a334, 0xd5ffd1bf }, + { 0x0000a338, 0x00000000 }, + { 0x0000a33c, 0x00000000 }, + { 0x0000a340, 0x00000000 }, + { 0x0000a344, 0x00000000 }, + { 0x0000a348, 0x3fffffff }, + { 0x0000a34c, 0x3fffffff }, + { 0x0000a350, 0x3fffffff }, + { 0x0000a354, 0x0003ffff }, + { 0x0000a358, 0x79a8aa1f }, + { 0x0000a35c, 0x066c420f }, + { 0x0000a360, 0x0f282207 }, + { 0x0000a364, 0x17601685 }, + { 0x0000a368, 0x1f801104 }, + { 0x0000a36c, 0x37a00c03 }, + { 0x0000a370, 0x3fc40883 }, + { 0x0000a374, 0x57c00803 }, + { 0x0000a378, 0x5fd80682 }, + { 0x0000a37c, 0x7fe00482 }, + { 0x0000a380, 0x7f3c7bba }, + { 0x0000a384, 0xf3307ff0 }, + { 0x00009b04, 0x00000001 }, + { 0x00009b08, 0x00000002 }, + { 0x00009b0c, 0x00000003 }, + { 0x00009b10, 0x00000004 }, + { 0x00009b14, 0x00000005 }, + { 0x00009b18, 0x00000008 }, + { 0x00009b1c, 0x00000009 }, + { 0x00009b20, 0x0000000a }, + { 0x00009b24, 0x0000000b }, + { 0x00009b2c, 0x0000000d }, + { 0x00009b30, 0x00000010 }, + { 0x00009b34, 0x00000011 }, + { 0x00009b3c, 0x00000013 }, + { 0x00009b40, 0x00000014 }, + { 0x00009b44, 0x00000015 }, + { 0x00009b48, 0x00000018 }, + { 0x00009b4c, 0x00000019 }, + { 0x00009b50, 0x0000001a }, + { 0x00009b54, 0x0000001b }, + { 0x00009b58, 0x0000001c }, + { 0x00009b5c, 0x0000001d }, + { 0x00009b60, 0x00000020 }, + { 0x00009b68, 0x00000022 }, + { 0x00009b6c, 0x00000023 }, + { 0x00009b70, 0x00000024 }, + { 0x00009b74, 0x00000025 }, + { 0x00009b78, 0x00000028 }, + { 0x00009b7c, 0x00000029 }, + { 0x00009b80, 0x0000002a }, + { 0x00009b84, 0x0000002b }, + { 0x00009b88, 0x0000002c }, + { 0x00009b90, 0x00000030 }, + { 0x00009b94, 0x00000031 }, + { 0x00009b98, 0x00000032 }, + { 0x00009ba0, 0x00000034 }, + { 0x00009ba4, 0x00000035 }, + { 0x00009ba8, 0x00000035 }, + { 0x00009bac, 0x00000035 }, + { 0x00009bb0, 0x00000035 }, + { 0x00009bb4, 0x00000035 }, + { 0x00009bb8, 0x00000035 }, + { 0x00009bbc, 0x00000035 }, + { 0x00009bc0, 0x00000035 }, + { 0x00009bc4, 0x00000035 }, + { 0x00009bc8, 0x00000035 }, + { 0x00009bcc, 0x00000035 }, + { 0x00009bd0, 0x00000035 }, + { 0x00009bd4, 0x00000035 }, + { 0x00009bd8, 0x00000035 }, + { 0x00009bdc, 0x00000035 }, + { 0x00009be0, 0x00000035 }, + { 0x00009be4, 0x00000035 }, + { 0x00009be8, 0x00000035 }, + { 0x00009bec, 0x00000035 }, + { 0x00009bf0, 0x00000035 }, + { 0x00009bf4, 0x00000035 }, + { 0x00009bf8, 0x00000010 }, + { 0x00009bfc, 0x0000001a }, +}; +#endif /* AH_5212_2413 */ + +#ifdef AH_5212_2316 +static const uint32_t ar5212Common_2316[][2] = { + { 0x00001230, 0x000003e0 }, + { 0x00008060, 0x0000000f }, + { 0x00008118, 0x00000000 }, + { 0x0000811c, 0x00000000 }, + { 0x00008120, 0x00000000 }, + { 0x00008124, 0x00000000 }, + { 0x00008128, 0x00000000 }, + { 0x0000812c, 0x00000000 }, + { 0x00008130, 0x00000000 }, + { 0x00008134, 0x00000000 }, + { 0x00008138, 0x00000000 }, + { 0x0000813c, 0x00000000 }, + { 0x00008140, 0x800000a8 }, + { 0x00008144, 0x00000000 }, + { 0x00009808, 0x00004000 }, + { 0x0000982c, 0x0000a000 }, + { 0x0000983c, 0x00200400 }, + { 0x0000984c, 0x1284233c }, + { 0x00009870, 0x0000001f }, + { 0x00009874, 0x00000080 }, + { 0x00009878, 0x0000000e }, + { 0x00009958, 0x000000ff }, + { 0x00009980, 0x00000000 }, + { 0x00009984, 0x02800000 }, + { 0x000099a0, 0x00000000 }, + { 0x000099e0, 0x00000000 }, + { 0x000099e4, 0xaaaaaaaa }, + { 0x000099e8, 0x3c466478 }, + { 0x000099ec, 0x000000aa }, + { 0x000099f0, 0x0000000c }, + { 0x000099f4, 0x000000ff }, + { 0x000099f8, 0x00000014 }, + { 0x0000a228, 0x000009b5 }, + { 0x0000a23c, 0x93c889af }, + { 0x0000a24c, 0x00000001 }, + { 0x0000a250, 0x0000a000 }, + { 0x0000a254, 0x00000000 }, + { 0x0000a258, 0x0cc75380 }, + { 0x0000a25c, 0x0f0f0f01 }, + { 0x0000a260, 0x5f690f01 }, + { 0x0000a264, 0x00418a11 }, + { 0x0000a268, 0x00000000 }, + { 0x0000a26c, 0x0c30c16a }, + { 0x0000a270, 0x00820820 }, + { 0x0000a274, 0x081b7caa }, + { 0x0000a278, 0x1ce739ce }, + { 0x0000a27c, 0x051701ce }, + { 0x0000a300, 0x18010000 }, + { 0x0000a304, 0x30032602 }, + { 0x0000a308, 0x48073e06 }, + { 0x0000a30c, 0x560b4c0a }, + { 0x0000a310, 0x641a600f }, + { 0x0000a314, 0x784f6e1b }, + { 0x0000a318, 0x868f7c5a }, + { 0x0000a31c, 0x8ecf865b }, + { 0x0000a320, 0x9d4f970f }, + { 0x0000a324, 0xa5cfa18f }, + { 0x0000a328, 0xb55faf1f }, + { 0x0000a32c, 0xbddfb99f }, + { 0x0000a330, 0xcd7fc73f }, + { 0x0000a334, 0xd5ffd1bf }, + { 0x0000a338, 0x00000000 }, + { 0x0000a33c, 0x00000000 }, + { 0x0000a340, 0x00000000 }, + { 0x0000a344, 0x00000000 }, + { 0x0000a348, 0x3fffffff }, + { 0x0000a34c, 0x3fffffff }, + { 0x0000a350, 0x3fffffff }, + { 0x0000a354, 0x0003ffff }, + { 0x0000a358, 0x79a8aa1f }, + { 0x0000a35c, 0x066c420f }, + { 0x0000a360, 0x0f282207 }, + { 0x0000a364, 0x17601685 }, + { 0x0000a368, 0x1f801104 }, + { 0x0000a36c, 0x37a00c03 }, + { 0x0000a370, 0x3fc40883 }, + { 0x0000a374, 0x57c00803 }, + { 0x0000a378, 0x5fd80682 }, + { 0x0000a37c, 0x7fe00482 }, + { 0x0000a380, 0x7f3c7bba }, + { 0x0000a384, 0xf3307ff0 }, + { 0x00009b04, 0x00000001 }, + { 0x00009b08, 0x00000002 }, + { 0x00009b0c, 0x00000003 }, + { 0x00009b10, 0x00000004 }, + { 0x00009b14, 0x00000005 }, + { 0x00009b18, 0x00000008 }, + { 0x00009b1c, 0x00000009 }, + { 0x00009b20, 0x0000000a }, + { 0x00009b24, 0x0000000b }, + { 0x00009b2c, 0x0000000d }, + { 0x00009b30, 0x00000010 }, + { 0x00009b34, 0x00000011 }, + { 0x00009b3c, 0x00000013 }, + { 0x00009b40, 0x00000014 }, + { 0x00009b44, 0x00000015 }, + { 0x00009b48, 0x00000018 }, + { 0x00009b4c, 0x00000019 }, + { 0x00009b50, 0x0000001a }, + { 0x00009b54, 0x0000001b }, + { 0x00009b58, 0x0000001c }, + { 0x00009b5c, 0x0000001d }, + { 0x00009b60, 0x00000020 }, + { 0x00009b68, 0x00000022 }, + { 0x00009b6c, 0x00000023 }, + { 0x00009b70, 0x00000024 }, + { 0x00009b74, 0x00000025 }, + { 0x00009b78, 0x00000028 }, + { 0x00009b7c, 0x00000029 }, + { 0x00009b80, 0x0000002a }, + { 0x00009b84, 0x0000002b }, + { 0x00009b88, 0x0000002c }, + { 0x00009b90, 0x00000030 }, + { 0x00009b94, 0x00000031 }, + { 0x00009b98, 0x00000032 }, + { 0x00009ba0, 0x00000034 }, + { 0x00009ba4, 0x00000035 }, + { 0x00009ba8, 0x00000035 }, + { 0x00009bac, 0x00000035 }, + { 0x00009bb0, 0x00000035 }, + { 0x00009bb4, 0x00000035 }, + { 0x00009bb8, 0x00000035 }, + { 0x00009bbc, 0x00000035 }, + { 0x00009bc0, 0x00000035 }, + { 0x00009bc4, 0x00000035 }, + { 0x00009bc8, 0x00000035 }, + { 0x00009bcc, 0x00000035 }, + { 0x00009bd0, 0x00000035 }, + { 0x00009bd4, 0x00000035 }, + { 0x00009bd8, 0x00000035 }, + { 0x00009bdc, 0x00000035 }, + { 0x00009be0, 0x00000035 }, + { 0x00009be4, 0x00000035 }, + { 0x00009be8, 0x00000035 }, + { 0x00009bec, 0x00000035 }, + { 0x00009bf0, 0x00000035 }, + { 0x00009bf4, 0x00000035 }, + { 0x00009bf8, 0x00000010 }, + { 0x00009bfc, 0x0000001a }, +}; +#endif + +#ifdef AH_5212_5413 +static const uint32_t ar5212Common_5413[][2] = { + { 0x00001230, 0x000003e0 }, + { 0x00004068, 0x00000010 }, + { 0x00008060, 0x0000000f }, + { 0x0000809c, 0x00000000 }, + { 0x000080a0, 0x00000000 }, + { 0x00008118, 0x00000000 }, + { 0x0000811c, 0x00000000 }, + { 0x00008120, 0x00000000 }, + { 0x00008124, 0x00000000 }, + { 0x00008128, 0x00000000 }, + { 0x0000812c, 0x00000000 }, + { 0x00008130, 0x00000000 }, + { 0x00008134, 0x00000000 }, + { 0x00008138, 0x00000000 }, + { 0x0000813c, 0x00000000 }, + { 0x00008140, 0x800003f9 }, + { 0x00008144, 0x00000000 }, + { 0x00009808, 0x00000000 }, + { 0x0000982c, 0x0000a000 }, + { 0x0000983c, 0x00200400 }, + { 0x0000984c, 0x1284233c }, + { 0x00009870, 0x0000001f }, + { 0x00009874, 0x00000080 }, + { 0x00009878, 0x0000000e }, + { 0x00009958, 0x00081fff }, + { 0x00009980, 0x00000000 }, + { 0x00009984, 0x02800000 }, + { 0x000099a0, 0x00000000 }, + { 0x000099e0, 0x00000000 }, + { 0x000099e4, 0xaaaaaaaa }, + { 0x000099e8, 0x3c466478 }, + { 0x000099ec, 0x000000aa }, + { 0x000099f0, 0x0000000c }, + { 0x000099f4, 0x000000ff }, + { 0x000099f8, 0x00000014 }, + { 0x0000a228, 0x000009b5 }, + { 0x0000a23c, 0x93c889af }, + { 0x0000a24c, 0x00000001 }, + { 0x0000a250, 0x0000a000 }, + { 0x0000a254, 0x00000000 }, + { 0x0000a258, 0x0cc75380 }, + { 0x0000a25c, 0x0f0f0f01 }, + { 0x0000a260, 0x5f690f01 }, + { 0x0000a264, 0x00418a11 }, + { 0x0000a268, 0x00000000 }, + { 0x0000a26c, 0x0c30c16a }, + { 0x0000a270, 0x00820820 }, + { 0x0000a274, 0x081b7caa }, + { 0x0000a278, 0x1ce739ce }, + { 0x0000a27c, 0x051701ce }, + { 0x0000a338, 0x00000000 }, + { 0x0000a33c, 0x00000000 }, + { 0x0000a340, 0x00000000 }, + { 0x0000a344, 0x00000000 }, + { 0x0000a348, 0x3fffffff }, + { 0x0000a34c, 0x3fffffff }, + { 0x0000a350, 0x3fffffff }, + { 0x0000a354, 0x0003ffff }, + { 0x0000a358, 0x79a8aa1f }, + { 0x0000a35c, 0x066c420f }, + { 0x0000a360, 0x0f282207 }, + { 0x0000a364, 0x17601685 }, + { 0x0000a368, 0x1f801104 }, + { 0x0000a36c, 0x37a00c03 }, + { 0x0000a370, 0x3fc40883 }, + { 0x0000a374, 0x57c00803 }, + { 0x0000a378, 0x5fd80682 }, + { 0x0000a37c, 0x7fe00482 }, + { 0x0000a380, 0x7f3c7bba }, + { 0x0000a384, 0xf3307ff0 }, + { 0x00009b04, 0x00000001 }, + { 0x00009b08, 0x00000002 }, + { 0x00009b0c, 0x00000003 }, + { 0x00009b10, 0x00000004 }, + { 0x00009b14, 0x00000005 }, + { 0x00009b18, 0x00000008 }, + { 0x00009b1c, 0x00000009 }, + { 0x00009b20, 0x0000000a }, + { 0x00009b24, 0x0000000b }, + { 0x00009b2c, 0x0000000d }, + { 0x00009b30, 0x00000010 }, + { 0x00009b34, 0x00000011 }, + { 0x00009b3c, 0x00000013 }, + { 0x00009b40, 0x00000014 }, + { 0x00009b44, 0x00000015 }, + { 0x00009b48, 0x00000018 }, + { 0x00009b4c, 0x00000019 }, + { 0x00009b50, 0x0000001a }, + { 0x00009b54, 0x0000001b }, + { 0x00009b58, 0x0000001c }, + { 0x00009b5c, 0x0000001d }, + { 0x00009b60, 0x00000020 }, + { 0x00009b68, 0x00000022 }, + { 0x00009b6c, 0x00000023 }, + { 0x00009b70, 0x00000024 }, + { 0x00009b74, 0x00000025 }, + { 0x00009b78, 0x00000028 }, + { 0x00009b7c, 0x00000029 }, + { 0x00009b80, 0x0000002a }, + { 0x00009b84, 0x0000002b }, + { 0x00009b88, 0x0000002c }, + { 0x00009b90, 0x00000030 }, + { 0x00009b94, 0x00000031 }, + { 0x00009b98, 0x00000032 }, + { 0x00009ba0, 0x00000034 }, + { 0x00009ba4, 0x00000035 }, + { 0x00009ba8, 0x00000035 }, + { 0x00009bac, 0x00000035 }, + { 0x00009bb0, 0x00000035 }, + { 0x00009bb4, 0x00000035 }, + { 0x00009bb8, 0x00000035 }, + { 0x00009bbc, 0x00000035 }, + { 0x00009bc0, 0x00000035 }, + { 0x00009bc4, 0x00000035 }, + { 0x00009bc8, 0x00000035 }, + { 0x00009bcc, 0x00000035 }, + { 0x00009bd0, 0x00000035 }, + { 0x00009bd4, 0x00000035 }, + { 0x00009bd8, 0x00000035 }, + { 0x00009bdc, 0x00000035 }, + { 0x00009be0, 0x00000035 }, + { 0x00009be4, 0x00000035 }, + { 0x00009be8, 0x00000035 }, + { 0x00009bec, 0x00000035 }, + { 0x00009bf0, 0x00000035 }, + { 0x00009bf4, 0x00000035 }, + { 0x00009bf8, 0x00000010 }, + { 0x00009bfc, 0x0000001a }, +}; +#endif /* AH_5212_5413 */ + +#ifdef AH_5212_2425 +static const uint32_t ar5212Common_2425[][2] = { + { 0x00001230, 0x000003e0 }, + { 0x00008060, 0x0000000f }, + { 0x0000809c, 0x00000000 }, + { 0x000080a0, 0x00000000 }, + { 0x00008118, 0x00000000 }, + { 0x0000811c, 0x00000000 }, + { 0x00008120, 0x00000000 }, + { 0x00008124, 0x00000000 }, + { 0x00008128, 0x00000000 }, + { 0x0000812c, 0x00000000 }, + { 0x00008130, 0x00000000 }, + { 0x00008134, 0x00000000 }, + { 0x00008138, 0x00000000 }, + { 0x0000813c, 0x00000000 }, + { 0x00008140, 0x800003f9 }, + { 0x00008144, 0x00000000 }, + { 0x00009808, 0x00000000 }, + { 0x0000982c, 0x0000a000 }, + { 0x0000983c, 0x00200400 }, + { 0x0000984c, 0x1284233c }, + { 0x00009870, 0x0000001f }, + { 0x00009874, 0x00000080 }, + { 0x00009878, 0x0000000e }, + { 0x00009958, 0x00081fff }, + { 0x00009980, 0x00000000 }, + { 0x00009984, 0x02800000 }, + { 0x000099a0, 0x00000000 }, + { 0x000099dc, 0xfebadbe8 }, + { 0x000099e0, 0x00000000 }, + { 0x000099e4, 0xaaaaaaaa }, + { 0x000099e8, 0x3c466478 }, + { 0x000099ec, 0x000000aa }, + { 0x000099f0, 0x0000000c }, + { 0x000099f4, 0x000000ff }, + { 0x000099f8, 0x00000014 }, + { 0x0000a228, 0x000009b5 }, + { 0x0000a234, 0x20202020 }, + { 0x0000a238, 0x20202020 }, + { 0x0000a23c, 0x93c889af }, + { 0x0000a24c, 0x00000001 }, + { 0x0000a250, 0x0000a000 }, + { 0x0000a254, 0x00000000 }, + { 0x0000a258, 0x0cc75380 }, + { 0x0000a25c, 0x0f0f0f01 }, + { 0x0000a260, 0x5f690f01 }, + { 0x0000a264, 0x00418a11 }, + { 0x0000a268, 0x00000000 }, + { 0x0000a26c, 0x0c30c166 }, + { 0x0000a270, 0x00820820 }, + { 0x0000a274, 0x081a3caa }, + { 0x0000a278, 0x1ce739ce }, + { 0x0000a27c, 0x051701ce }, + { 0x0000a300, 0x16010000 }, + { 0x0000a304, 0x2c032402 }, + { 0x0000a308, 0x48433e42 }, + { 0x0000a30c, 0x5a0f500b }, + { 0x0000a310, 0x6c4b624a }, + { 0x0000a314, 0x7e8b748a }, + { 0x0000a318, 0x96cf8ccb }, + { 0x0000a31c, 0xa34f9d0f }, + { 0x0000a320, 0xa7cfa58f }, + { 0x0000a348, 0x3fffffff }, + { 0x0000a34c, 0x3fffffff }, + { 0x0000a350, 0x3fffffff }, + { 0x0000a354, 0x0003ffff }, + { 0x0000a358, 0x79a8aa1f }, + { 0x0000a35c, 0x066c420f }, + { 0x0000a360, 0x0f282207 }, + { 0x0000a364, 0x17601685 }, + { 0x0000a368, 0x1f801104 }, + { 0x0000a36c, 0x37a00c03 }, + { 0x0000a370, 0x3fc40883 }, + { 0x0000a374, 0x57c00803 }, + { 0x0000a378, 0x5fd80682 }, + { 0x0000a37c, 0x7fe00482 }, + { 0x0000a380, 0x7f3c7bba }, + { 0x0000a384, 0xf3307ff0 }, +}; +#endif /* AH_5212_2425 */ + +#ifdef AH_5212_5111 +static const uint32_t ar5212Bank0_5111[][6] = { + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00380000, 0x00380000, 0x00380000, 0x00380000, 0x00380000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x000000c0, 0x00000080, 0x00000080 }, + { 0x0000989c, 0x000400f9, 0x000400f9, 0x000400ff, 0x000400fd, 0x000400fd }, + { 0x000098d4, 0x00000000, 0x00000000, 0x00000004, 0x00000004, 0x00000004 }, +}; + +static const uint32_t ar5212BB_RfGain_5111[][3] = { + { 0x00009a00, 0x000001a9, 0x00000000 }, + { 0x00009a04, 0x000001e9, 0x00000040 }, + { 0x00009a08, 0x00000029, 0x00000080 }, + { 0x00009a0c, 0x00000069, 0x00000150 }, + { 0x00009a10, 0x00000199, 0x00000190 }, + { 0x00009a14, 0x000001d9, 0x000001d0 }, + { 0x00009a18, 0x00000019, 0x00000010 }, + { 0x00009a1c, 0x00000059, 0x00000044 }, + { 0x00009a20, 0x00000099, 0x00000084 }, + { 0x00009a24, 0x000001a5, 0x00000148 }, + { 0x00009a28, 0x000001e5, 0x00000188 }, + { 0x00009a2c, 0x00000025, 0x000001c8 }, + { 0x00009a30, 0x000001c8, 0x00000014 }, + { 0x00009a34, 0x00000008, 0x00000042 }, + { 0x00009a38, 0x00000048, 0x00000082 }, + { 0x00009a3c, 0x00000088, 0x00000178 }, + { 0x00009a40, 0x00000198, 0x000001b8 }, + { 0x00009a44, 0x000001d8, 0x000001f8 }, + { 0x00009a48, 0x00000018, 0x00000012 }, + { 0x00009a4c, 0x00000058, 0x00000052 }, + { 0x00009a50, 0x00000098, 0x00000092 }, + { 0x00009a54, 0x000001a4, 0x0000017c }, + { 0x00009a58, 0x000001e4, 0x000001bc }, + { 0x00009a5c, 0x00000024, 0x000001fc }, + { 0x00009a60, 0x00000064, 0x0000000a }, + { 0x00009a64, 0x000000a4, 0x0000004a }, + { 0x00009a68, 0x000000e4, 0x0000008a }, + { 0x00009a6c, 0x0000010a, 0x0000015a }, + { 0x00009a70, 0x0000014a, 0x0000019a }, + { 0x00009a74, 0x0000018a, 0x000001da }, + { 0x00009a78, 0x000001ca, 0x0000000e }, + { 0x00009a7c, 0x0000000a, 0x0000004e }, + { 0x00009a80, 0x0000004a, 0x0000008e }, + { 0x00009a84, 0x0000008a, 0x0000015e }, + { 0x00009a88, 0x000001ba, 0x0000019e }, + { 0x00009a8c, 0x000001fa, 0x000001de }, + { 0x00009a90, 0x0000003a, 0x00000009 }, + { 0x00009a94, 0x0000007a, 0x00000049 }, + { 0x00009a98, 0x00000186, 0x00000089 }, + { 0x00009a9c, 0x000001c6, 0x00000179 }, + { 0x00009aa0, 0x00000006, 0x000001b9 }, + { 0x00009aa4, 0x00000046, 0x000001f9 }, + { 0x00009aa8, 0x00000086, 0x00000039 }, + { 0x00009aac, 0x000000c6, 0x00000079 }, + { 0x00009ab0, 0x000000c6, 0x000000b9 }, + { 0x00009ab4, 0x000000c6, 0x000001bd }, + { 0x00009ab8, 0x000000c6, 0x000001fd }, + { 0x00009abc, 0x000000c6, 0x0000003d }, + { 0x00009ac0, 0x000000c6, 0x0000007d }, + { 0x00009ac4, 0x000000c6, 0x000000bd }, + { 0x00009ac8, 0x000000c6, 0x000000fd }, + { 0x00009acc, 0x000000c6, 0x000000fd }, + { 0x00009ad0, 0x000000c6, 0x000000fd }, + { 0x00009ad4, 0x000000c6, 0x000000fd }, + { 0x00009ad8, 0x000000c6, 0x000000fd }, + { 0x00009adc, 0x000000c6, 0x000000fd }, + { 0x00009ae0, 0x000000c6, 0x000000fd }, + { 0x00009ae4, 0x000000c6, 0x000000fd }, + { 0x00009ae8, 0x000000c6, 0x000000fd }, + { 0x00009aec, 0x000000c6, 0x000000fd }, + { 0x00009af0, 0x000000c6, 0x000000fd }, + { 0x00009af4, 0x000000c6, 0x000000fd }, + { 0x00009af8, 0x000000c6, 0x000000fd }, + { 0x00009afc, 0x000000c6, 0x000000fd }, +}; +#endif /* AH_5212_5111 */ + +#ifdef AH_5212_5112 +static const uint32_t ar5212BB_RfGain_5112[][3] = { + { 0x00009a00, 0x00000007, 0x00000007 }, + { 0x00009a04, 0x00000047, 0x00000047 }, + { 0x00009a08, 0x00000087, 0x00000087 }, + { 0x00009a0c, 0x000001a0, 0x000001a0 }, + { 0x00009a10, 0x000001e0, 0x000001e0 }, + { 0x00009a14, 0x00000020, 0x00000020 }, + { 0x00009a18, 0x00000060, 0x00000060 }, + { 0x00009a1c, 0x000001a1, 0x000001a1 }, + { 0x00009a20, 0x000001e1, 0x000001e1 }, + { 0x00009a24, 0x00000021, 0x00000021 }, + { 0x00009a28, 0x00000061, 0x00000061 }, + { 0x00009a2c, 0x00000162, 0x00000162 }, + { 0x00009a30, 0x000001a2, 0x000001a2 }, + { 0x00009a34, 0x000001e2, 0x000001e2 }, + { 0x00009a38, 0x00000022, 0x00000022 }, + { 0x00009a3c, 0x00000062, 0x00000062 }, + { 0x00009a40, 0x00000163, 0x00000163 }, + { 0x00009a44, 0x000001a3, 0x000001a3 }, + { 0x00009a48, 0x000001e3, 0x000001e3 }, + { 0x00009a4c, 0x00000023, 0x00000023 }, + { 0x00009a50, 0x00000063, 0x00000063 }, + { 0x00009a54, 0x00000184, 0x00000184 }, + { 0x00009a58, 0x000001c4, 0x000001c4 }, + { 0x00009a5c, 0x00000004, 0x00000004 }, + { 0x00009a60, 0x000001ea, 0x0000000b }, + { 0x00009a64, 0x0000002a, 0x0000004b }, + { 0x00009a68, 0x0000006a, 0x0000008b }, + { 0x00009a6c, 0x000000aa, 0x000001ac }, + { 0x00009a70, 0x000001ab, 0x000001ec }, + { 0x00009a74, 0x000001eb, 0x0000002c }, + { 0x00009a78, 0x0000002b, 0x00000012 }, + { 0x00009a7c, 0x0000006b, 0x00000052 }, + { 0x00009a80, 0x000000ab, 0x00000092 }, + { 0x00009a84, 0x000001ac, 0x00000193 }, + { 0x00009a88, 0x000001ec, 0x000001d3 }, + { 0x00009a8c, 0x0000002c, 0x00000013 }, + { 0x00009a90, 0x0000003a, 0x00000053 }, + { 0x00009a94, 0x0000007a, 0x00000093 }, + { 0x00009a98, 0x000000ba, 0x00000194 }, + { 0x00009a9c, 0x000001bb, 0x000001d4 }, + { 0x00009aa0, 0x000001fb, 0x00000014 }, + { 0x00009aa4, 0x0000003b, 0x0000003a }, + { 0x00009aa8, 0x0000007b, 0x0000007a }, + { 0x00009aac, 0x000000bb, 0x000000ba }, + { 0x00009ab0, 0x000001bc, 0x000001bb }, + { 0x00009ab4, 0x000001fc, 0x000001fb }, + { 0x00009ab8, 0x0000003c, 0x0000003b }, + { 0x00009abc, 0x0000007c, 0x0000007b }, + { 0x00009ac0, 0x000000bc, 0x000000bb }, + { 0x00009ac4, 0x000000fc, 0x000001bc }, + { 0x00009ac8, 0x000000fc, 0x000001fc }, + { 0x00009acc, 0x000000fc, 0x0000003c }, + { 0x00009ad0, 0x000000fc, 0x0000007c }, + { 0x00009ad4, 0x000000fc, 0x000000bc }, + { 0x00009ad8, 0x000000fc, 0x000000fc }, + { 0x00009adc, 0x000000fc, 0x000000fc }, + { 0x00009ae0, 0x000000fc, 0x000000fc }, + { 0x00009ae4, 0x000000fc, 0x000000fc }, + { 0x00009ae8, 0x000000fc, 0x000000fc }, + { 0x00009aec, 0x000000fc, 0x000000fc }, + { 0x00009af0, 0x000000fc, 0x000000fc }, + { 0x00009af4, 0x000000fc, 0x000000fc }, + { 0x00009af8, 0x000000fc, 0x000000fc }, + { 0x00009afc, 0x000000fc, 0x000000fc }, +}; +#endif /* AH_5212_5112 */ + +#ifdef AH_5212_2413 +static const uint32_t ar5212BB_RfGain_2413[][3] = { + { 0x00009a00, 0x00000000, 0x00000000 }, + { 0x00009a04, 0x00000000, 0x00000040 }, + { 0x00009a08, 0x00000000, 0x00000080 }, + { 0x00009a0c, 0x00000000, 0x00000181 }, + { 0x00009a10, 0x00000000, 0x000001c1 }, + { 0x00009a14, 0x00000000, 0x00000001 }, + { 0x00009a18, 0x00000000, 0x00000041 }, + { 0x00009a1c, 0x00000000, 0x00000081 }, + { 0x00009a20, 0x00000000, 0x00000168 }, + { 0x00009a24, 0x00000000, 0x000001a8 }, + { 0x00009a28, 0x00000000, 0x000001e8 }, + { 0x00009a2c, 0x00000000, 0x00000028 }, + { 0x00009a30, 0x00000000, 0x00000068 }, + { 0x00009a34, 0x00000000, 0x00000189 }, + { 0x00009a38, 0x00000000, 0x000001c9 }, + { 0x00009a3c, 0x00000000, 0x00000009 }, + { 0x00009a40, 0x00000000, 0x00000049 }, + { 0x00009a44, 0x00000000, 0x00000089 }, + { 0x00009a48, 0x00000000, 0x00000190 }, + { 0x00009a4c, 0x00000000, 0x000001d0 }, + { 0x00009a50, 0x00000000, 0x00000010 }, + { 0x00009a54, 0x00000000, 0x00000050 }, + { 0x00009a58, 0x00000000, 0x00000090 }, + { 0x00009a5c, 0x00000000, 0x00000191 }, + { 0x00009a60, 0x00000000, 0x000001d1 }, + { 0x00009a64, 0x00000000, 0x00000011 }, + { 0x00009a68, 0x00000000, 0x00000051 }, + { 0x00009a6c, 0x00000000, 0x00000091 }, + { 0x00009a70, 0x00000000, 0x00000178 }, + { 0x00009a74, 0x00000000, 0x000001b8 }, + { 0x00009a78, 0x00000000, 0x000001f8 }, + { 0x00009a7c, 0x00000000, 0x00000038 }, + { 0x00009a80, 0x00000000, 0x00000078 }, + { 0x00009a84, 0x00000000, 0x00000199 }, + { 0x00009a88, 0x00000000, 0x000001d9 }, + { 0x00009a8c, 0x00000000, 0x00000019 }, + { 0x00009a90, 0x00000000, 0x00000059 }, + { 0x00009a94, 0x00000000, 0x00000099 }, + { 0x00009a98, 0x00000000, 0x000000d9 }, + { 0x00009a9c, 0x00000000, 0x000000f9 }, + { 0x00009aa0, 0x00000000, 0x000000f9 }, + { 0x00009aa4, 0x00000000, 0x000000f9 }, + { 0x00009aa8, 0x00000000, 0x000000f9 }, + { 0x00009aac, 0x00000000, 0x000000f9 }, + { 0x00009ab0, 0x00000000, 0x000000f9 }, + { 0x00009ab4, 0x00000000, 0x000000f9 }, + { 0x00009ab8, 0x00000000, 0x000000f9 }, + { 0x00009abc, 0x00000000, 0x000000f9 }, + { 0x00009ac0, 0x00000000, 0x000000f9 }, + { 0x00009ac4, 0x00000000, 0x000000f9 }, + { 0x00009ac8, 0x00000000, 0x000000f9 }, + { 0x00009acc, 0x00000000, 0x000000f9 }, + { 0x00009ad0, 0x00000000, 0x000000f9 }, + { 0x00009ad4, 0x00000000, 0x000000f9 }, + { 0x00009ad8, 0x00000000, 0x000000f9 }, + { 0x00009adc, 0x00000000, 0x000000f9 }, + { 0x00009ae0, 0x00000000, 0x000000f9 }, + { 0x00009ae4, 0x00000000, 0x000000f9 }, + { 0x00009ae8, 0x00000000, 0x000000f9 }, + { 0x00009aec, 0x00000000, 0x000000f9 }, + { 0x00009af0, 0x00000000, 0x000000f9 }, + { 0x00009af4, 0x00000000, 0x000000f9 }, + { 0x00009af8, 0x00000000, 0x000000f9 }, + { 0x00009afc, 0x00000000, 0x000000f9 }, +}; +#endif /* AH_5212_2413 */ + +#ifdef AH_5212_2316 +static const uint32_t ar5212BB_RfGain_2316[][3] = { + { 0x00009a00, 0x00000000, 0x00000000 }, + { 0x00009a04, 0x00000000, 0x00000040 }, + { 0x00009a08, 0x00000000, 0x00000080 }, + { 0x00009a0c, 0x00000000, 0x00000161 }, + { 0x00009a10, 0x00000000, 0x000001a1 }, + { 0x00009a14, 0x00000000, 0x000001e1 }, + { 0x00009a18, 0x00000000, 0x00000021 }, + { 0x00009a1c, 0x00000000, 0x00000061 }, + { 0x00009a20, 0x00000000, 0x000000a1 }, + { 0x00009a24, 0x00000000, 0x00000168 }, + { 0x00009a28, 0x00000000, 0x000001a8 }, + { 0x00009a2c, 0x00000000, 0x000001e8 }, + { 0x00009a30, 0x00000000, 0x00000028 }, + { 0x00009a34, 0x00000000, 0x00000068 }, + { 0x00009a38, 0x00000000, 0x000000a8 }, + { 0x00009a3c, 0x00000000, 0x00000189 }, + { 0x00009a40, 0x00000000, 0x000001c9 }, + { 0x00009a44, 0x00000000, 0x00000009 }, + { 0x00009a48, 0x00000000, 0x00000049 }, + { 0x00009a4c, 0x00000000, 0x00000089 }, + { 0x00009a50, 0x00000000, 0x000001b0 }, + { 0x00009a54, 0x00000000, 0x000001f0 }, + { 0x00009a58, 0x00000000, 0x00000030 }, + { 0x00009a5c, 0x00000000, 0x00000070 }, + { 0x00009a60, 0x00000000, 0x000000b0 }, + { 0x00009a64, 0x00000000, 0x000001b1 }, + { 0x00009a68, 0x00000000, 0x000001f1 }, + { 0x00009a6c, 0x00000000, 0x00000031 }, + { 0x00009a70, 0x00000000, 0x00000071 }, + { 0x00009a74, 0x00000000, 0x00000198 }, + { 0x00009a78, 0x00000000, 0x000001d8 }, + { 0x00009a7c, 0x00000000, 0x00000018 }, + { 0x00009a80, 0x00000000, 0x00000058 }, + { 0x00009a84, 0x00000000, 0x00000098 }, + { 0x00009a88, 0x00000000, 0x00000199 }, + { 0x00009a8c, 0x00000000, 0x000001d9 }, + { 0x00009a90, 0x00000000, 0x00000019 }, + { 0x00009a94, 0x00000000, 0x00000059 }, + { 0x00009a98, 0x00000000, 0x00000099 }, + { 0x00009a9c, 0x00000000, 0x000000d9 }, + { 0x00009aa0, 0x00000000, 0x000000f9 }, + { 0x00009aa4, 0x00000000, 0x000000f9 }, + { 0x00009aa8, 0x00000000, 0x000000f9 }, + { 0x00009aac, 0x00000000, 0x000000f9 }, + { 0x00009ab0, 0x00000000, 0x000000f9 }, + { 0x00009ab4, 0x00000000, 0x000000f9 }, + { 0x00009ab8, 0x00000000, 0x000000f9 }, + { 0x00009abc, 0x00000000, 0x000000f9 }, + { 0x00009ac0, 0x00000000, 0x000000f9 }, + { 0x00009ac4, 0x00000000, 0x000000f9 }, + { 0x00009ac8, 0x00000000, 0x000000f9 }, + { 0x00009acc, 0x00000000, 0x000000f9 }, + { 0x00009ad0, 0x00000000, 0x000000f9 }, + { 0x00009ad4, 0x00000000, 0x000000f9 }, + { 0x00009ad8, 0x00000000, 0x000000f9 }, + { 0x00009adc, 0x00000000, 0x000000f9 }, + { 0x00009ae0, 0x00000000, 0x000000f9 }, + { 0x00009ae4, 0x00000000, 0x000000f9 }, + { 0x00009ae8, 0x00000000, 0x000000f9 }, + { 0x00009aec, 0x00000000, 0x000000f9 }, + { 0x00009af0, 0x00000000, 0x000000f9 }, + { 0x00009af4, 0x00000000, 0x000000f9 }, + { 0x00009af8, 0x00000000, 0x000000f9 }, + { 0x00009afc, 0x00000000, 0x000000f9 }, +}; +#endif + +#ifdef AH_5212_5413 +static const uint32_t ar5212BB_RfGain_5413[][3] = { + { 0x00009a00, 0x00000000, 0x00000000 }, + { 0x00009a04, 0x00000040, 0x00000040 }, + { 0x00009a08, 0x00000080, 0x00000080 }, + { 0x00009a0c, 0x000001a1, 0x00000161 }, + { 0x00009a10, 0x000001e1, 0x000001a1 }, + { 0x00009a14, 0x00000021, 0x000001e1 }, + { 0x00009a18, 0x00000061, 0x00000021 }, + { 0x00009a1c, 0x00000188, 0x00000061 }, + { 0x00009a20, 0x000001c8, 0x00000188 }, + { 0x00009a24, 0x00000008, 0x000001c8 }, + { 0x00009a28, 0x00000048, 0x00000008 }, + { 0x00009a2c, 0x00000088, 0x00000048 }, + { 0x00009a30, 0x000001a9, 0x00000088 }, + { 0x00009a34, 0x000001e9, 0x00000169 }, + { 0x00009a38, 0x00000029, 0x000001a9 }, + { 0x00009a3c, 0x00000069, 0x000001e9 }, + { 0x00009a40, 0x000001d0, 0x00000029 }, + { 0x00009a44, 0x00000010, 0x00000069 }, + { 0x00009a48, 0x00000050, 0x00000190 }, + { 0x00009a4c, 0x00000090, 0x000001d0 }, + { 0x00009a50, 0x000001b1, 0x00000010 }, + { 0x00009a54, 0x000001f1, 0x00000050 }, + { 0x00009a58, 0x00000031, 0x00000090 }, + { 0x00009a5c, 0x00000071, 0x00000171 }, + { 0x00009a60, 0x000001b8, 0x000001b1 }, + { 0x00009a64, 0x000001f8, 0x000001f1 }, + { 0x00009a68, 0x00000038, 0x00000031 }, + { 0x00009a6c, 0x00000078, 0x00000071 }, + { 0x00009a70, 0x00000199, 0x00000198 }, + { 0x00009a74, 0x000001d9, 0x000001d8 }, + { 0x00009a78, 0x00000019, 0x00000018 }, + { 0x00009a7c, 0x00000059, 0x00000058 }, + { 0x00009a80, 0x00000099, 0x00000098 }, + { 0x00009a84, 0x000000d9, 0x00000179 }, + { 0x00009a88, 0x000000f9, 0x000001b9 }, + { 0x00009a8c, 0x000000f9, 0x000001f9 }, + { 0x00009a90, 0x000000f9, 0x00000039 }, + { 0x00009a94, 0x000000f9, 0x00000079 }, + { 0x00009a98, 0x000000f9, 0x000000b9 }, + { 0x00009a9c, 0x000000f9, 0x000000f9 }, + { 0x00009aa0, 0x000000f9, 0x000000f9 }, + { 0x00009aa4, 0x000000f9, 0x000000f9 }, + { 0x00009aa8, 0x000000f9, 0x000000f9 }, + { 0x00009aac, 0x000000f9, 0x000000f9 }, + { 0x00009ab0, 0x000000f9, 0x000000f9 }, + { 0x00009ab4, 0x000000f9, 0x000000f9 }, + { 0x00009ab8, 0x000000f9, 0x000000f9 }, + { 0x00009abc, 0x000000f9, 0x000000f9 }, + { 0x00009ac0, 0x000000f9, 0x000000f9 }, + { 0x00009ac4, 0x000000f9, 0x000000f9 }, + { 0x00009ac8, 0x000000f9, 0x000000f9 }, + { 0x00009acc, 0x000000f9, 0x000000f9 }, + { 0x00009ad0, 0x000000f9, 0x000000f9 }, + { 0x00009ad4, 0x000000f9, 0x000000f9 }, + { 0x00009ad8, 0x000000f9, 0x000000f9 }, + { 0x00009adc, 0x000000f9, 0x000000f9 }, + { 0x00009ae0, 0x000000f9, 0x000000f9 }, + { 0x00009ae4, 0x000000f9, 0x000000f9 }, + { 0x00009ae8, 0x000000f9, 0x000000f9 }, + { 0x00009aec, 0x000000f9, 0x000000f9 }, + { 0x00009af0, 0x000000f9, 0x000000f9 }, + { 0x00009af4, 0x000000f9, 0x000000f9 }, + { 0x00009af8, 0x000000f9, 0x000000f9 }, + { 0x00009afc, 0x000000f9, 0x000000f9 }, +}; +#endif /* AH_5212_5413 */ + +#ifdef AH_5212_2425 +static const uint32_t ar5212BB_RfGain_2425[][3] = { + { 0x00009a00, 0x00000000, 0x00000000 }, + { 0x00009a04, 0x00000000, 0x00000040 }, + { 0x00009a08, 0x00000000, 0x00000080 }, + { 0x00009a0c, 0x00000000, 0x00000181 }, + { 0x00009a10, 0x00000000, 0x000001c1 }, + { 0x00009a14, 0x00000000, 0x00000001 }, + { 0x00009a18, 0x00000000, 0x00000041 }, + { 0x00009a1c, 0x00000000, 0x00000081 }, + { 0x00009a20, 0x00000000, 0x00000188 }, + { 0x00009a24, 0x00000000, 0x000001c8 }, + { 0x00009a28, 0x00000000, 0x00000008 }, + { 0x00009a2c, 0x00000000, 0x00000048 }, + { 0x00009a30, 0x00000000, 0x00000088 }, + { 0x00009a34, 0x00000000, 0x00000189 }, + { 0x00009a38, 0x00000000, 0x000001c9 }, + { 0x00009a3c, 0x00000000, 0x00000009 }, + { 0x00009a40, 0x00000000, 0x00000049 }, + { 0x00009a44, 0x00000000, 0x00000089 }, + { 0x00009a48, 0x00000000, 0x000001b0 }, + { 0x00009a4c, 0x00000000, 0x000001f0 }, + { 0x00009a50, 0x00000000, 0x00000030 }, + { 0x00009a54, 0x00000000, 0x00000070 }, + { 0x00009a58, 0x00000000, 0x00000171 }, + { 0x00009a5c, 0x00000000, 0x000001b1 }, + { 0x00009a60, 0x00000000, 0x000001f1 }, + { 0x00009a64, 0x00000000, 0x00000031 }, + { 0x00009a68, 0x00000000, 0x00000071 }, + { 0x00009a6c, 0x00000000, 0x000001b8 }, + { 0x00009a70, 0x00000000, 0x000001f8 }, + { 0x00009a74, 0x00000000, 0x00000038 }, + { 0x00009a78, 0x00000000, 0x00000078 }, + { 0x00009a7c, 0x00000000, 0x000000b8 }, + { 0x00009a80, 0x00000000, 0x000001b9 }, + { 0x00009a84, 0x00000000, 0x000001f9 }, + { 0x00009a88, 0x00000000, 0x00000039 }, + { 0x00009a8c, 0x00000000, 0x00000079 }, + { 0x00009a90, 0x00000000, 0x000000b9 }, + { 0x00009a94, 0x00000000, 0x000000f9 }, + { 0x00009a98, 0x00000000, 0x000000f9 }, + { 0x00009a9c, 0x00000000, 0x000000f9 }, + { 0x00009aa0, 0x00000000, 0x000000f9 }, + { 0x00009aa4, 0x00000000, 0x000000f9 }, + { 0x00009aa8, 0x00000000, 0x000000f9 }, + { 0x00009aac, 0x00000000, 0x000000f9 }, + { 0x00009ab0, 0x00000000, 0x000000f9 }, + { 0x00009ab4, 0x00000000, 0x000000f9 }, + { 0x00009ab8, 0x00000000, 0x000000f9 }, + { 0x00009abc, 0x00000000, 0x000000f9 }, + { 0x00009ac0, 0x00000000, 0x000000f9 }, + { 0x00009ac4, 0x00000000, 0x000000f9 }, + { 0x00009ac8, 0x00000000, 0x000000f9 }, + { 0x00009acc, 0x00000000, 0x000000f9 }, + { 0x00009ad0, 0x00000000, 0x000000f9 }, + { 0x00009ad4, 0x00000000, 0x000000f9 }, + { 0x00009ad8, 0x00000000, 0x000000f9 }, + { 0x00009adc, 0x00000000, 0x000000f9 }, + { 0x00009ae0, 0x00000000, 0x000000f9 }, + { 0x00009ae4, 0x00000000, 0x000000f9 }, + { 0x00009ae8, 0x00000000, 0x000000f9 }, + { 0x00009aec, 0x00000000, 0x000000f9 }, + { 0x00009af0, 0x00000000, 0x000000f9 }, + { 0x00009af4, 0x00000000, 0x000000f9 }, + { 0x00009af8, 0x00000000, 0x000000f9 }, + { 0x00009afc, 0x00000000, 0x000000f9 }, +}; +#endif /* AH_5212_2425 */ + +#ifdef AH_5212_5111 +static const uint32_t ar5212Bank1_5111[][2] = { + { 0x000098d4, 0x00000020 }, +}; +#endif /* AH_5212_5111 */ + +#ifdef AH_5212_5112 +static const uint32_t ar5212Bank1_5112[][2] = { + { 0x000098d4, 0x00000020 }, +}; +#endif /* AH_5212_5112 */ + +#ifdef AH_5212_2413 +static const uint32_t ar5212Bank1_2413[][2] = { + { 0x000098d4, 0x00000020 }, +}; +#endif /* AH_5212_2413 */ + +#ifdef AH_5212_2316 +static const uint32_t ar5212Bank1_2316[][2] = { + { 0x000098d4, 0x00000020 }, +}; +#endif + +#ifdef AH_5212_5413 +static const uint32_t ar5212Bank1_5413[][2] = { + { 0x000098d4, 0x00000020 }, +}; +#endif /* AH_5212_5413 */ + +#ifdef AH_5212_2425 +static const uint32_t ar5212Bank1_2425[][2] = { + { 0x000098d4, 0x00000020 }, +}; +#endif /* AH_5212_2425 */ + +#ifdef AH_5212_5111 +static const uint32_t ar5212Bank2_5111[][6] = { + { 0x000098d4, 0x00000010, 0x00000014, 0x00000010, 0x00000010, 0x00000014 }, +}; +#endif /* AH_5212_5111 */ + +#ifdef AH_5212_5112 +static const uint32_t ar5212Bank2_5112[][6] = { + { 0x000098d0, 0x03060408, 0x03070408, 0x03060408, 0x03060408, 0x03070408 }, +}; +#endif /* AH_5212_5112 */ + +#ifdef AH_5212_2413 +static const uint32_t ar5212Bank2_2413[][6] = { + { 0x000098d0, 0x02001408, 0x02011408, 0x02001408, 0x02001408, 0x02011408 }, +}; +#endif /* AH_5212_2413 */ + +#ifdef AH_5212_2316 +static const uint32_t ar5212Bank2_2316[][6] = { + { 0x000098d0, 0x02001408, 0x02011408, 0x02001408, 0x02001408, 0x02011408 }, +}; +#endif + +#ifdef AH_5212_5413 +static const uint32_t ar5212Bank2_5413[][6] = { + { 0x000098d0, 0x00000008, 0x00000008, 0x00000008, 0x00000008, 0x00000008 }, +}; +#endif /* AH_5212_5413 */ + +#ifdef AH_5212_2425 +static const uint32_t ar5212Bank2_2425[][6] = { + { 0x000098d0, 0x02001408, 0x02001408, 0x02001408, 0x02001408, 0x02001408 }, +}; +#endif /* AH_5212_2425 */ + +#ifdef AH_5212_5111 +static const uint32_t ar5212Bank3_5111[][6] = { + { 0x000098d8, 0x00601068, 0x00601068, 0x00601068, 0x00601068, 0x00601068 }, +}; +#endif /* AH_5212_5111 */ + +#ifdef AH_5212_5112 +static const uint32_t ar5212Bank3_5112[][6] = { + { 0x000098dc, 0x00a020c0, 0x00a020c0, 0x00e020c0, 0x00e020c0, 0x00e020c0 }, +}; +#endif /* AH_5212_5112 */ + +#ifdef AH_5212_2413 +static const uint32_t ar5212Bank3_2413[][6] = { + { 0x000098dc, 0x00a020c0, 0x00a020c0, 0x00e020c0, 0x00e020c0, 0x00e020c0 }, +}; +#endif /* AH_5212_2413 */ + +#ifdef AH_5212_2316 +static const uint32_t ar5212Bank3_2316[][6] = { + { 0x000098dc, 0x00a020c0, 0x00a020c0, 0x00e020c0, 0x00e020c0, 0x00e020c0 }, +}; +#endif + +#ifdef AH_5212_5413 +static const uint32_t ar5212Bank3_5413[][6] = { + { 0x000098dc, 0x00a000c0, 0x00a000c0, 0x00e000c0, 0x00e000c0, 0x00e000c0 }, +}; +#endif /* AH_5212_5413 */ + +#ifdef AH_5212_2425 +static const uint32_t ar5212Bank3_2425[][6] = { + { 0x000098dc, 0x00a020c0, 0x00a020c0, 0x00e020c0, 0x00e020c0, 0x00e020c0 }, +}; +#endif /* AH_5212_2425 */ + +#ifdef AH_5212_5111 +static const uint32_t ar5212Bank6_5111[][6] = { + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x10000000, 0x10000000, 0x10000000, 0x10000000, 0x10000000 }, + { 0x0000989c, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x0a000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x003800c0, 0x00380080, 0x023800c0, 0x003800c0, 0x003800c0 }, + { 0x0000989c, 0x00020006, 0x00020006, 0x00000006, 0x00020006, 0x00020006 }, + { 0x0000989c, 0x00000089, 0x00000089, 0x00000089, 0x00000089, 0x00000089 }, + { 0x0000989c, 0x000000a0, 0x000000a0, 0x000000a0, 0x000000a0, 0x000000a0 }, + { 0x0000989c, 0x00040007, 0x00040007, 0x00040007, 0x00040007, 0x00040007 }, + { 0x000098d4, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a }, +}; +#endif /* AH_5212_5111 */ + +#ifdef AH_5212_5112 +static const uint32_t ar5212Bank6_5112[][6] = { + { 0x0000989c, 0x0f000000, 0x0f000000, 0x0f000000, 0x0f000000, 0x0f000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00800000, 0x00800000, 0x00800000, 0x00800000, 0x00800000 }, + { 0x0000989c, 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000 }, + { 0x0000989c, 0x00010000, 0x00010000, 0x00010000, 0x00010000, 0x00010000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00180000, 0x00180000, 0x00180000, 0x00180000, 0x00180000 }, + { 0x0000989c, 0x00600000, 0x00600000, 0x006e0000, 0x006e0000, 0x006e0000 }, + { 0x0000989c, 0x00c70000, 0x00c70000, 0x00c70000, 0x00c70000, 0x00c70000 }, + { 0x0000989c, 0x004b0000, 0x004b0000, 0x004b0000, 0x004b0000, 0x004b0000 }, + { 0x0000989c, 0x04480000, 0x04480000, 0x04480000, 0x04480000, 0x04480000 }, + { 0x0000989c, 0x004c0000, 0x004c0000, 0x004c0000, 0x004c0000, 0x004c0000 }, + { 0x0000989c, 0x00e40000, 0x00e40000, 0x00e40000, 0x00e40000, 0x00e40000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00fc0000, 0x00fc0000, 0x00fc0000, 0x00fc0000, 0x00fc0000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x043f0000, 0x043f0000, 0x043f0000, 0x043f0000, 0x043f0000 }, + { 0x0000989c, 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000 }, + { 0x0000989c, 0x02190000, 0x02190000, 0x02190000, 0x02190000, 0x02190000 }, + { 0x0000989c, 0x00240000, 0x00240000, 0x00240000, 0x00240000, 0x00240000 }, + { 0x0000989c, 0x00b40000, 0x00b40000, 0x00b40000, 0x00b40000, 0x00b40000 }, + { 0x0000989c, 0x00990000, 0x00990000, 0x00990000, 0x00990000, 0x00990000 }, + { 0x0000989c, 0x00500000, 0x00500000, 0x00500000, 0x00500000, 0x00500000 }, + { 0x0000989c, 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000 }, + { 0x0000989c, 0x00120000, 0x00120000, 0x00120000, 0x00120000, 0x00120000 }, + { 0x0000989c, 0xc0320000, 0xc0320000, 0xc0320000, 0xc0320000, 0xc0320000 }, + { 0x0000989c, 0x01740000, 0x01740000, 0x01740000, 0x01740000, 0x01740000 }, + { 0x0000989c, 0x00110000, 0x00110000, 0x00110000, 0x00110000, 0x00110000 }, + { 0x0000989c, 0x86280000, 0x86280000, 0x86280000, 0x86280000, 0x86280000 }, + { 0x0000989c, 0x31840000, 0x31840000, 0x31840000, 0x31840000, 0x31840000 }, + { 0x0000989c, 0x00f20080, 0x00f20080, 0x00f20080, 0x00f20080, 0x00f20080 }, + { 0x0000989c, 0x00270019, 0x00270019, 0x00270019, 0x00270019, 0x00270019 }, + { 0x0000989c, 0x00000003, 0x00000003, 0x00000003, 0x00000003, 0x00000003 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x000000b2, 0x000000b2, 0x000000b2, 0x000000b2, 0x000000b2 }, + { 0x0000989c, 0x00b02084, 0x00b02084, 0x00b02084, 0x00b02084, 0x00b02084 }, + { 0x0000989c, 0x004125a4, 0x004125a4, 0x004125a4, 0x004125a4, 0x004125a4 }, + { 0x0000989c, 0x00119220, 0x00119220, 0x00119220, 0x00119220, 0x00119220 }, + { 0x0000989c, 0x001a4800, 0x001a4800, 0x001a4800, 0x001a4800, 0x001a4800 }, + { 0x000098d8, 0x000b0230, 0x000b0230, 0x000b0230, 0x000b0230, 0x000b0230 }, +}; +#endif /* AH_5212_5112 */ + +#ifdef AH_5212_2413 +static const uint32_t ar5212Bank6_2413[][6] = { + { 0x0000989c, 0xf0000000, 0xf0000000, 0xf0000000, 0xf0000000, 0xf0000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x03000000, 0x03000000, 0x03000000, 0x03000000, 0x03000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x40400000, 0x40400000, 0x40400000, 0x40400000, 0x40400000 }, + { 0x0000989c, 0x65050000, 0x65050000, 0x65050000, 0x65050000, 0x65050000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00420000, 0x00420000, 0x00420000, 0x00420000, 0x00420000 }, + { 0x0000989c, 0x00b50000, 0x00b50000, 0x00b50000, 0x00b50000, 0x00b50000 }, + { 0x0000989c, 0x00030000, 0x00030000, 0x00030000, 0x00030000, 0x00030000 }, + { 0x0000989c, 0x00f70000, 0x00f70000, 0x00f70000, 0x00f70000, 0x00f70000 }, + { 0x0000989c, 0x009d0000, 0x009d0000, 0x009d0000, 0x009d0000, 0x009d0000 }, + { 0x0000989c, 0x00220000, 0x00220000, 0x00220000, 0x00220000, 0x00220000 }, + { 0x0000989c, 0x04220000, 0x04220000, 0x04220000, 0x04220000, 0x04220000 }, + { 0x0000989c, 0x00230018, 0x00230018, 0x00230018, 0x00230018, 0x00230018 }, + { 0x0000989c, 0x00280000, 0x00280000, 0x00280060, 0x00280060, 0x00280060 }, + { 0x0000989c, 0x005000c0, 0x005000c0, 0x005000c3, 0x005000c3, 0x005000c3 }, + { 0x0000989c, 0x0004007f, 0x0004007f, 0x0004007f, 0x0004007f, 0x0004007f }, + { 0x0000989c, 0x00000458, 0x00000458, 0x00000458, 0x00000458, 0x00000458 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x0000c000, 0x0000c000, 0x0000c000, 0x0000c000, 0x0000c000 }, + { 0x000098d8, 0x00400230, 0x00400230, 0x00400230, 0x00400230, 0x00400230 }, +}; +#endif /* AH_5212_2413 */ + +#ifdef AH_5212_2316 +static const uint32_t ar5212Bank6_2316[][6] = { + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0xc0000000, 0xc0000000, 0xc0000000, 0xc0000000, 0xc0000000 }, + { 0x0000989c, 0x0f000000, 0x0f000000, 0x0f000000, 0x0f000000, 0x0f000000 }, + { 0x0000989c, 0x02000000, 0x02000000, 0x02000000, 0x02000000, 0x02000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0xf8000000, 0xf8000000, 0xf8000000, 0xf8000000, 0xf8000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x95150000, 0x95150000, 0x95150000, 0x95150000, 0x95150000 }, + { 0x0000989c, 0xc1000000, 0xc1000000, 0xc1000000, 0xc1000000, 0xc1000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00080000, 0x00080000, 0x00080000, 0x00080000, 0x00080000 }, + { 0x0000989c, 0x00d50000, 0x00d50000, 0x00d50000, 0x00d50000, 0x00d50000 }, + { 0x0000989c, 0x000e0000, 0x000e0000, 0x000e0000, 0x000e0000, 0x000e0000 }, + { 0x0000989c, 0x00dc0000, 0x00dc0000, 0x00dc0000, 0x00dc0000, 0x00dc0000 }, + { 0x0000989c, 0x00770000, 0x00770000, 0x00770000, 0x00770000, 0x00770000 }, + { 0x0000989c, 0x008a0000, 0x008a0000, 0x008a0000, 0x008a0000, 0x008a0000 }, + { 0x0000989c, 0x10880000, 0x10880000, 0x10880000, 0x10880000, 0x10880000 }, + { 0x0000989c, 0x008c0060, 0x008c0060, 0x008c0060, 0x008c0060, 0x008c0060 }, + { 0x0000989c, 0x00a00000, 0x00a00000, 0x00a00080, 0x00a00080, 0x00a00080 }, + { 0x0000989c, 0x00400000, 0x00400000, 0x0040000d, 0x0040000d, 0x0040000d }, + { 0x0000989c, 0x00110400, 0x00110400, 0x00110400, 0x00110400, 0x00110400 }, + { 0x0000989c, 0x00000060, 0x00000060, 0x00000060, 0x00000060, 0x00000060 }, + { 0x0000989c, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001 }, + { 0x0000989c, 0x00000b00, 0x00000b00, 0x00000b00, 0x00000b00, 0x00000b00 }, + { 0x0000989c, 0x00000be8, 0x00000be8, 0x00000be8, 0x00000be8, 0x00000be8 }, + { 0x000098c0, 0x00010000, 0x00010000, 0x00010000, 0x00010000, 0x00010000 }, +}; +#endif + +#ifdef AH_5212_5413 +static const uint32_t ar5212Bank6_5413[][6] = { + { 0x0000989c, 0x33000000, 0x33000000, 0x33000000, 0x33000000, 0x33000000 }, + { 0x0000989c, 0x01000000, 0x01000000, 0x01000000, 0x01000000, 0x01000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x1f000000, 0x1f000000, 0x1f000000, 0x1f000000, 0x1f000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00b80000, 0x00b80000, 0x00b80000, 0x00b80000, 0x00b80000 }, + { 0x0000989c, 0x00b70000, 0x00b70000, 0x00b70000, 0x00b70000, 0x00b70000 }, + { 0x0000989c, 0x00840000, 0x00840000, 0x00840000, 0x00840000, 0x00840000 }, + { 0x0000989c, 0x00980000, 0x00980000, 0x00980000, 0x00980000, 0x00980000 }, + { 0x0000989c, 0x00c00000, 0x00c00000, 0x00c00000, 0x00c00000, 0x00c00000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x00d70000, 0x00d70000, 0x00d70000, 0x00d70000, 0x00d70000 }, + { 0x0000989c, 0x00610000, 0x00610000, 0x00610000, 0x00610000, 0x00610000 }, + { 0x0000989c, 0x00fe0000, 0x00fe0000, 0x00fe0000, 0x00fe0000, 0x00fe0000 }, + { 0x0000989c, 0x00de0000, 0x00de0000, 0x00de0000, 0x00de0000, 0x00de0000 }, + { 0x0000989c, 0x007f0000, 0x007f0000, 0x007f0000, 0x007f0000, 0x007f0000 }, + { 0x0000989c, 0x043d0000, 0x043d0000, 0x043d0000, 0x043d0000, 0x043d0000 }, + { 0x0000989c, 0x00770000, 0x00770000, 0x00770000, 0x00770000, 0x00770000 }, + { 0x0000989c, 0x00440000, 0x00440000, 0x00440000, 0x00440000, 0x00440000 }, + { 0x0000989c, 0x00980000, 0x00980000, 0x00980000, 0x00980000, 0x00980000 }, + { 0x0000989c, 0x00100080, 0x00100080, 0x00100080, 0x00100080, 0x00100080 }, + { 0x0000989c, 0x0005c034, 0x0005c034, 0x0005c034, 0x0005c034, 0x0005c034 }, + { 0x0000989c, 0x003100f0, 0x003100f0, 0x003100f0, 0x003100f0, 0x003100f0 }, + { 0x0000989c, 0x000c011f, 0x000c011f, 0x000c011f, 0x000c011f, 0x000c011f }, + { 0x0000989c, 0x00510040, 0x00510040, 0x00510040, 0x00510040, 0x00510040 }, + { 0x0000989c, 0x005000da, 0x005000da, 0x005000da, 0x005000da, 0x005000da }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00004044, 0x00004044, 0x00004044, 0x00004044, 0x00004044 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x000060c0, 0x000060c0, 0x000060c0, 0x000060c0, 0x000060c0 }, + { 0x0000989c, 0x00002c00, 0x00002c00, 0x00003600, 0x00003600, 0x00002c00 }, + { 0x000098c8, 0x00000403, 0x00000403, 0x00000403, 0x00000403, 0x00000403 }, +}; +#endif /* AH_5212_5413 */ + +#ifdef AH_5212_2425 +static const uint32_t ar5212Bank6_2425[][6] = { + { 0x0000989c, 0x10000000, 0x10000000, 0x10000000, 0x10000000, 0x10000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00100000, 0x00100000, 0x00100000, 0x00100000, 0x00100000 }, + { 0x0000989c, 0x00020000, 0x00020000, 0x00020000, 0x00020000, 0x00020000 }, + { 0x0000989c, 0x00730000, 0x00730000, 0x00730000, 0x00730000, 0x00730000 }, + { 0x0000989c, 0x00f80000, 0x00f80000, 0x00f80000, 0x00f80000, 0x00f80000 }, + { 0x0000989c, 0x00e70000, 0x00e70000, 0x00e70000, 0x00e70000, 0x00e70000 }, + { 0x0000989c, 0x00140000, 0x00140000, 0x00140000, 0x00140000, 0x00140000 }, + { 0x0000989c, 0x00910040, 0x00910040, 0x00910040, 0x00910040, 0x00910040 }, + { 0x0000989c, 0x0007001a, 0x0007001a, 0x0007001a, 0x0007001a, 0x0007001a }, + { 0x0000989c, 0x00410000, 0x00410000, 0x00410000, 0x00410000, 0x00410000 }, + { 0x0000989c, 0x00810000, 0x00810000, 0x00810060, 0x00810060, 0x00810060 }, + { 0x0000989c, 0x00020800, 0x00020800, 0x00020803, 0x00020803, 0x00020803 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00001660, 0x00001660, 0x00001660, 0x00001660, 0x00001660 }, + { 0x0000989c, 0x00001688, 0x00001688, 0x00001688, 0x00001688, 0x00001688 }, + { 0x000098c4, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001 }, +}; +#endif /* AH_5212_2425 */ + +#ifdef AH_5212_2417 +static const uint32_t ar5212Bank6_2417[][6] = { + { 0x0000989c, 0x10000000, 0x10000000, 0x10000000, 0x10000000, 0x10000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00100000, 0x00100000, 0x00100000, 0x00100000, 0x00100000 }, + { 0x0000989c, 0x00020000, 0x00020000, 0x00020000, 0x00020000, 0x00020000 }, + { 0x0000989c, 0x00730000, 0x00730000, 0x00730000, 0x00730000, 0x00730000 }, + { 0x0000989c, 0x00f80000, 0x00f80000, 0x00f80000, 0x00f80000, 0x00f80000 }, + { 0x0000989c, 0x00e70000, 0x00e70000, 0x80e70000, 0x80e70000, 0x00e70000 }, + { 0x0000989c, 0x00140000, 0x00140000, 0x00140000, 0x00140000, 0x00140000 }, + { 0x0000989c, 0x00910040, 0x00910040, 0x00910040, 0x00910040, 0x00910040 }, + { 0x0000989c, 0x0007001a, 0x0007001a, 0x0207001a, 0x0207001a, 0x0007001a }, + { 0x0000989c, 0x00410000, 0x00410000, 0x00410000, 0x00410000, 0x00410000 }, + { 0x0000989c, 0x00810000, 0x00810000, 0x00810060, 0x00810060, 0x00810060 }, + { 0x0000989c, 0x00020800, 0x00020800, 0x00020803, 0x00020803, 0x00020803 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00001660, 0x00001660, 0x00001660, 0x00001660, 0x00001660 }, + { 0x0000989c, 0x00001688, 0x00001688, 0x00001688, 0x00001688, 0x00001688 }, + { 0x000098c4, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001 }, +}; +#endif /* AH_5212_2417 */ + +#ifdef AH_5212_5111 +static const uint32_t ar5212Bank7_5111[][6] = { + { 0x0000989c, 0x00000040, 0x00000048, 0x00000040, 0x00000040, 0x00000040 }, + { 0x0000989c, 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010 }, + { 0x0000989c, 0x00000008, 0x00000008, 0x00000008, 0x00000008, 0x00000008 }, + { 0x0000989c, 0x0000004f, 0x0000004f, 0x0000004f, 0x0000004f, 0x0000004f }, + { 0x0000989c, 0x000000f1, 0x000000f1, 0x00000061, 0x000000f1, 0x000000f1 }, + { 0x0000989c, 0x0000904f, 0x0000904f, 0x0000904c, 0x0000904f, 0x0000904f }, + { 0x0000989c, 0x0000125a, 0x0000125a, 0x0000129a, 0x0000125a, 0x0000125a }, + { 0x000098cc, 0x0000000e, 0x0000000e, 0x0000000f, 0x0000000e, 0x0000000e }, +}; +#endif /* AH_5212_5111 */ + +#ifdef AH_5212_5112 +static const uint32_t ar5212Bank7_5112[][6] = { + { 0x0000989c, 0x00000094, 0x00000094, 0x00000094, 0x00000094, 0x00000094 }, + { 0x0000989c, 0x00000091, 0x00000091, 0x00000091, 0x00000091, 0x00000091 }, + { 0x0000989c, 0x00000012, 0x00000012, 0x00000012, 0x00000012, 0x00000012 }, + { 0x0000989c, 0x00000080, 0x00000080, 0x00000080, 0x00000080, 0x00000080 }, + { 0x0000989c, 0x000000d9, 0x000000d9, 0x000000d9, 0x000000d9, 0x000000d9 }, + { 0x0000989c, 0x00000060, 0x00000060, 0x00000060, 0x00000060, 0x00000060 }, + { 0x0000989c, 0x000000f0, 0x000000f0, 0x000000f0, 0x000000f0, 0x000000f0 }, + { 0x0000989c, 0x000000a2, 0x000000a2, 0x000000a2, 0x000000a2, 0x000000a2 }, + { 0x0000989c, 0x00000052, 0x00000052, 0x00000052, 0x00000052, 0x00000052 }, + { 0x0000989c, 0x000000d4, 0x000000d4, 0x000000d4, 0x000000d4, 0x000000d4 }, + { 0x0000989c, 0x000014cc, 0x000014cc, 0x000014cc, 0x000014cc, 0x000014cc }, + { 0x0000989c, 0x0000048c, 0x0000048c, 0x0000048c, 0x0000048c, 0x0000048c }, + { 0x000098c4, 0x00000003, 0x00000003, 0x00000003, 0x00000003, 0x00000003 }, +}; +#endif /* AH_5212_5112 */ + +#ifdef AH_5212_2413 +static const uint32_t ar5212Bank7_2413[][6] = { + { 0x0000989c, 0x00006400, 0x00006400, 0x00006400, 0x00006400, 0x00006400 }, + { 0x0000989c, 0x00000800, 0x00000800, 0x00000800, 0x00000800, 0x00000800 }, + { 0x000098cc, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e }, +}; +#endif /* AH_5212_2413 */ + +#ifdef AH_5212_2316 +static const uint32_t ar5212Bank7_2316[][6] = { + { 0x0000989c, 0x00006400, 0x00006400, 0x00006400, 0x00006400, 0x00006400 }, + { 0x0000989c, 0x00000800, 0x00000800, 0x00000800, 0x00000800, 0x00000800 }, + { 0x000098cc, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e }, +}; +#endif + +#ifdef AH_5212_5413 +static const uint32_t ar5212Bank7_5413[][6] = { + { 0x0000989c, 0x00006400, 0x00006400, 0x00006400, 0x00006400, 0x00006400 }, + { 0x0000989c, 0x00000800, 0x00000800, 0x00000800, 0x00000800, 0x00000800 }, + { 0x000098cc, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e }, +}; +#endif /* AH_5212_5413 */ + +#ifdef AH_5212_2317 +static const uint32_t ar5212Modes_2317[][6] = { + { 0x00000030, 0x00000015, 0x00000015, 0x00000015, 0x00000015, 0x00000015 }, + { 0x0000801c, 0x128d93a7, 0x098813cf, 0x04e01395, 0x12e013ab, 0x098813cf }, + { 0x00009828, 0x0a020001, 0x0a020001, 0x05020000, 0x0a020001, 0x0a020001 }, + { 0x00009834, 0x00000e00, 0x00000e00, 0x00000e00, 0x00000e00, 0x00000e00 }, + { 0x00009838, 0x00000002, 0x00000002, 0x0000000a, 0x0000000a, 0x0000000a }, + { 0x00009848, 0x0018da6d, 0x0018da6d, 0x001a6a67, 0x001a6a67, 0x001a6a67 }, + { 0x00009850, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b0da, 0x0c98b0da, 0x0de8b0da }, + { 0x00009858, 0x7e800d2e, 0x7e800d2e, 0x7ee80d2e, 0x7ec80d2e, 0x7e800d2e }, + { 0x0000985c, 0x3137665e, 0x3137665e, 0x3137665e, 0x3139605e, 0x3137665e }, + { 0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 }, + { 0x00009914, 0x000007d0, 0x000007d0, 0x0000044c, 0x00000898, 0x000007d0 }, + { 0x00009944, 0xf7b81000, 0xf7b81000, 0xf7b80d00, 0xf7b81000, 0xf7b81000 }, + { 0x0000a204, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a208, 0xd6be6788, 0xd6be6788, 0xd03e6788, 0xd03e6788, 0xd03e6788 }, + { 0x0000a20c, 0x002c0140, 0x002c0140, 0x0042c140, 0x0042c140, 0x0042c140 }, + { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1863800a, 0x1883800a, 0x1883800a }, +}; + +static const uint32_t ar5212Common_2317[][2] = { + { 0x00001230, 0x000003e0 }, + { 0x00008060, 0x0000000f }, + { 0x00008118, 0x00000000 }, + { 0x0000811c, 0x00000000 }, + { 0x00008120, 0x00000000 }, + { 0x00008124, 0x00000000 }, + { 0x00008128, 0x00000000 }, + { 0x0000812c, 0x00000000 }, + { 0x00008130, 0x00000000 }, + { 0x00008134, 0x00000000 }, + { 0x00008138, 0x00000000 }, + { 0x0000813c, 0x00000000 }, + { 0x00008140, 0x800000a8 }, + { 0x00008144, 0x00000000 }, + { 0x00009808, 0x00004000 }, + { 0x0000982c, 0x0000a000 }, + { 0x0000983c, 0x00200400 }, + { 0x0000984c, 0x1284233c }, + { 0x00009870, 0x0000001f }, + { 0x00009874, 0x00000080 }, + { 0x00009878, 0x0000000e }, + { 0x00009958, 0x000000ff }, + { 0x00009980, 0x00000000 }, + { 0x00009984, 0x02800000 }, + { 0x000099a0, 0x00000000 }, + { 0x000099e0, 0x00000001 }, + { 0x000099e4, 0xaaaaaaaa }, + { 0x000099e8, 0x3c466478 }, + { 0x000099ec, 0x000000aa }, + { 0x000099f0, 0x0000000c }, + { 0x000099f4, 0x000000ff }, + { 0x000099f8, 0x00000014 }, + { 0x0000a228, 0x000009b5 }, + { 0x0000a23c, 0x93c889af }, + { 0x0000a24c, 0x00000001 }, + { 0x0000a250, 0x0000a000 }, + { 0x0000a254, 0x00000000 }, + { 0x0000a258, 0x0cc75380 }, + { 0x0000a25c, 0x0f0f0f01 }, + { 0x0000a260, 0x5f690f01 }, + { 0x0000a264, 0x00418a11 }, + { 0x0000a268, 0x00000000 }, + { 0x0000a26c, 0x0c30c16a }, + { 0x0000a270, 0x00820820 }, + { 0x0000a274, 0x081a3caa }, + { 0x0000a278, 0x1ce739ce }, + { 0x0000a27c, 0x051701ce }, + { 0x0000a300, 0x16010000 }, + { 0x0000a304, 0x2c032402 }, + { 0x0000a308, 0x48433e42 }, + { 0x0000a30c, 0x5a0f500b }, + { 0x0000a310, 0x6c4b624a }, + { 0x0000a314, 0x7e8b748a }, + { 0x0000a318, 0x96cf8ccb }, + { 0x0000a31c, 0xa34f9d0f }, + { 0x0000a320, 0xa7cfa58f }, + { 0x0000a348, 0x3fffffff }, + { 0x0000a34c, 0x3fffffff }, + { 0x0000a350, 0x3fffffff }, + { 0x0000a354, 0x0003ffff }, + { 0x0000a358, 0x79a8aa1f }, + { 0x0000a35c, 0x066c420f }, + { 0x0000a360, 0x0f282207 }, + { 0x0000a364, 0x17601685 }, + { 0x0000a368, 0x1f801104 }, + { 0x0000a36c, 0x37a00c03 }, + { 0x0000a370, 0x3fc40883 }, + { 0x0000a374, 0x57c00803 }, + { 0x0000a378, 0x5fd80682 }, + { 0x0000a37c, 0x7fe00482 }, + { 0x0000a380, 0x7f3c7bba }, + { 0x0000a384, 0xf3307ff0 }, + { 0x00009b04, 0x00000001 }, + { 0x00009b08, 0x00000002 }, + { 0x00009b0c, 0x00000003 }, + { 0x00009b10, 0x00000004 }, + { 0x00009b14, 0x00000005 }, + { 0x00009b18, 0x00000008 }, + { 0x00009b1c, 0x00000009 }, + { 0x00009b20, 0x0000000a }, + { 0x00009b24, 0x0000000b }, + { 0x00009b2c, 0x0000000d }, + { 0x00009b30, 0x00000010 }, + { 0x00009b34, 0x00000011 }, + { 0x00009b3c, 0x00000013 }, + { 0x00009b40, 0x00000014 }, + { 0x00009b44, 0x00000015 }, + { 0x00009b48, 0x00000018 }, + { 0x00009b4c, 0x00000019 }, + { 0x00009b50, 0x0000001a }, + { 0x00009b54, 0x0000001b }, + { 0x00009b58, 0x0000001c }, + { 0x00009b5c, 0x0000001d }, + { 0x00009b60, 0x00000020 }, + { 0x00009b68, 0x00000022 }, + { 0x00009b6c, 0x00000023 }, + { 0x00009b70, 0x00000024 }, + { 0x00009b74, 0x00000025 }, + { 0x00009b78, 0x00000028 }, + { 0x00009b7c, 0x00000029 }, + { 0x00009b80, 0x0000002a }, + { 0x00009b84, 0x0000002b }, + { 0x00009b88, 0x0000002c }, + { 0x00009b90, 0x00000030 }, + { 0x00009b94, 0x00000031 }, + { 0x00009b98, 0x00000032 }, + { 0x00009ba0, 0x00000034 }, + { 0x00009ba4, 0x00000035 }, + { 0x00009ba8, 0x00000035 }, + { 0x00009bac, 0x00000035 }, + { 0x00009bb0, 0x00000035 }, + { 0x00009bb4, 0x00000035 }, + { 0x00009bb8, 0x00000035 }, + { 0x00009bbc, 0x00000035 }, + { 0x00009bc0, 0x00000035 }, + { 0x00009bc4, 0x00000035 }, + { 0x00009bc8, 0x00000035 }, + { 0x00009bcc, 0x00000035 }, + { 0x00009bd0, 0x00000035 }, + { 0x00009bd4, 0x00000035 }, + { 0x00009bd8, 0x00000035 }, + { 0x00009bdc, 0x00000035 }, + { 0x00009be0, 0x00000035 }, + { 0x00009be4, 0x00000035 }, + { 0x00009be8, 0x00000035 }, + { 0x00009bec, 0x00000035 }, + { 0x00009bf0, 0x00000035 }, + { 0x00009bf4, 0x00000035 }, + { 0x00009bf8, 0x00000010 }, + { 0x00009bfc, 0x0000001a }, +}; + +static const uint32_t ar5212BB_RfGain_2317[][3] = { + { 0x00009a00, 0x00000000, 0x00000000 }, + { 0x00009a04, 0x00000000, 0x00000040 }, + { 0x00009a08, 0x00000000, 0x00000080 }, + { 0x00009a0c, 0x00000000, 0x00000181 }, + { 0x00009a10, 0x00000000, 0x000001c1 }, + { 0x00009a14, 0x00000000, 0x00000001 }, + { 0x00009a18, 0x00000000, 0x00000041 }, + { 0x00009a1c, 0x00000000, 0x00000081 }, + { 0x00009a20, 0x00000000, 0x00000188 }, + { 0x00009a24, 0x00000000, 0x000001c8 }, + { 0x00009a28, 0x00000000, 0x00000008 }, + { 0x00009a2c, 0x00000000, 0x00000048 }, + { 0x00009a30, 0x00000000, 0x00000088 }, + { 0x00009a34, 0x00000000, 0x00000189 }, + { 0x00009a38, 0x00000000, 0x000001c9 }, + { 0x00009a3c, 0x00000000, 0x00000009 }, + { 0x00009a40, 0x00000000, 0x00000049 }, + { 0x00009a44, 0x00000000, 0x00000089 }, + { 0x00009a48, 0x00000000, 0x00000190 }, + { 0x00009a4c, 0x00000000, 0x000001d0 }, + { 0x00009a50, 0x00000000, 0x00000010 }, + { 0x00009a54, 0x00000000, 0x00000050 }, + { 0x00009a58, 0x00000000, 0x00000090 }, + { 0x00009a5c, 0x00000000, 0x00000191 }, + { 0x00009a60, 0x00000000, 0x000001d1 }, + { 0x00009a64, 0x00000000, 0x00000011 }, + { 0x00009a68, 0x00000000, 0x00000051 }, + { 0x00009a6c, 0x00000000, 0x00000091 }, + { 0x00009a70, 0x00000000, 0x00000178 }, + { 0x00009a74, 0x00000000, 0x000001b8 }, + { 0x00009a78, 0x00000000, 0x000001f8 }, + { 0x00009a7c, 0x00000000, 0x00000038 }, + { 0x00009a80, 0x00000000, 0x00000078 }, + { 0x00009a84, 0x00000000, 0x00000179 }, + { 0x00009a88, 0x00000000, 0x000001b9 }, + { 0x00009a8c, 0x00000000, 0x000001f9 }, + { 0x00009a90, 0x00000000, 0x00000039 }, + { 0x00009a94, 0x00000000, 0x00000079 }, + { 0x00009a98, 0x00000000, 0x000000b9 }, + { 0x00009a9c, 0x00000000, 0x000000f9 }, + { 0x00009aa0, 0x00000000, 0x000000f9 }, + { 0x00009aa4, 0x00000000, 0x000000f9 }, + { 0x00009aa8, 0x00000000, 0x000000f9 }, + { 0x00009aac, 0x00000000, 0x000000f9 }, + { 0x00009ab0, 0x00000000, 0x000000f9 }, + { 0x00009ab4, 0x00000000, 0x000000f9 }, + { 0x00009ab8, 0x00000000, 0x000000f9 }, + { 0x00009abc, 0x00000000, 0x000000f9 }, + { 0x00009ac0, 0x00000000, 0x000000f9 }, + { 0x00009ac4, 0x00000000, 0x000000f9 }, + { 0x00009ac8, 0x00000000, 0x000000f9 }, + { 0x00009acc, 0x00000000, 0x000000f9 }, + { 0x00009ad0, 0x00000000, 0x000000f9 }, + { 0x00009ad4, 0x00000000, 0x000000f9 }, + { 0x00009ad8, 0x00000000, 0x000000f9 }, + { 0x00009adc, 0x00000000, 0x000000f9 }, + { 0x00009ae0, 0x00000000, 0x000000f9 }, + { 0x00009ae4, 0x00000000, 0x000000f9 }, + { 0x00009ae8, 0x00000000, 0x000000f9 }, + { 0x00009aec, 0x00000000, 0x000000f9 }, + { 0x00009af0, 0x00000000, 0x000000f9 }, + { 0x00009af4, 0x00000000, 0x000000f9 }, + { 0x00009af8, 0x00000000, 0x000000f9 }, + { 0x00009afc, 0x00000000, 0x000000f9 }, +}; + +static const uint32_t ar5212Bank1_2317[][2] = { + { 0x000098d4, 0x00000020 }, +}; + +static const uint32_t ar5212Bank2_2317[][6] = { + { 0x000098d0, 0x02001408, 0x02011408, 0x02001408, 0x02001408, 0x02011408 }, +}; + +static const uint32_t ar5212Bank3_2317[][6] = { + { 0x000098dc, 0x00a020c0, 0x00a020c0, 0x00e020c0, 0x00e020c0, 0x00e020c0 }, +}; + +static const uint32_t ar5212Bank6_2317[][6] = { + { 0x0000989c, 0x10000000, 0x10000000, 0x10000000, 0x10000000, 0x10000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00100000, 0x00100000, 0x00100000, 0x00100000, 0x00100000 }, + { 0x0000989c, 0x00020000, 0x00020000, 0x00020000, 0x00020000, 0x00020000 }, + { 0x0000989c, 0x00730000, 0x00730000, 0x00730000, 0x00730000, 0x00730000 }, + { 0x0000989c, 0x00f80000, 0x00f80000, 0x00f80000, 0x00f80000, 0x00f80000 }, + { 0x0000989c, 0x00e70000, 0x00e70000, 0x00e70000, 0x00e70000, 0x00e70000 }, + { 0x0000989c, 0x00140100, 0x00140100, 0x00140100, 0x00140100, 0x00140100 }, + { 0x0000989c, 0x00910040, 0x00910040, 0x00910040, 0x00910040, 0x00910040 }, + { 0x0000989c, 0x0007001a, 0x0007001a, 0x0007001a, 0x0007001a, 0x0007001a }, + { 0x0000989c, 0x00410000, 0x00410000, 0x00410000, 0x00410000, 0x00410000 }, + { 0x0000989c, 0x00810000, 0x00810000, 0x00810060, 0x00810060, 0x00810060 }, + { 0x0000989c, 0x00020800, 0x00020800, 0x00020803, 0x00020803, 0x00020803 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00001660, 0x00001660, 0x00001660, 0x00001660, 0x00001660 }, + { 0x0000989c, 0x00001688, 0x00001688, 0x00001688, 0x00001688, 0x00001688 }, + { 0x000098c4, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001 }, +}; + +static const uint32_t ar5212Bank7_2317[][6] = { + { 0x0000989c, 0x00006400, 0x00006400, 0x00006400, 0x00006400, 0x00006400 }, + { 0x0000989c, 0x00000800, 0x00000800, 0x00000800, 0x00000800, 0x00000800 }, + { 0x000098cc, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e }, +}; +#endif /* AH_5212_2317 */ + +#ifdef AH_5212_2425 +static const uint32_t ar5212Bank7_2425[][6] = { + { 0x0000989c, 0x00006400, 0x00006400, 0x00006400, 0x00006400, 0x00006400 }, + { 0x0000989c, 0x00000800, 0x00000800, 0x00000800, 0x00000800, 0x00000800 }, + { 0x000098cc, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e }, +}; +#endif /* AH_5212_2425 */ --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5212/ar5212_ani.c 2009-03-23 17:36:55.000000000 +0000 @@ -0,0 +1,1016 @@ +/* + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2008 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ar5212_ani.c,v 1.1 2009/03/23 17:14:47 sborrill Exp $ + */ +#include "opt_ah.h" + +#include "ah.h" +#include "ah_internal.h" +#include "ah_desc.h" + +#include "ar5212/ar5212.h" +#include "ar5212/ar5212reg.h" +#include "ar5212/ar5212phy.h" + +/* + * Anti noise immunity support. We track phy errors and react + * to excessive errors by adjusting the noise immunity parameters. + */ + +#define HAL_EP_RND(x, mul) \ + ((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul)) +#define BEACON_RSSI(ahp) \ + HAL_EP_RND(ahp->ah_stats.ast_nodestats.ns_avgbrssi, \ + HAL_RSSI_EP_MULTIPLIER) + +/* + * ANI processing tunes radio parameters according to PHY errors + * and related information. This is done for for noise and spur + * immunity in all operating modes if the device indicates it's + * capable at attach time. In addition, when there is a reference + * rssi value (e.g. beacon frames from an ap in station mode) + * further tuning is done. + * + * ANI_ENA indicates whether any ANI processing should be done; + * this is specified at attach time. + * + * ANI_ENA_RSSI indicates whether rssi-based processing should + * done, this is enabled based on operating mode and is meaningful + * only if ANI_ENA is true. + * + * ANI parameters are typically controlled only by the hal. The + * AniControl interface however permits manual tuning through the + * diagnostic api. + */ +#define ANI_ENA(ah) \ + (AH5212(ah)->ah_procPhyErr & HAL_ANI_ENA) +#define ANI_ENA_RSSI(ah) \ + (AH5212(ah)->ah_procPhyErr & HAL_RSSI_ANI_ENA) + +#define ah_mibStats ah_stats.ast_mibstats + +static void +enableAniMIBCounters(struct ath_hal *ah, const struct ar5212AniParams *params) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + + HALDEBUG(ah, HAL_DEBUG_ANI, "%s: Enable mib counters: " + "OfdmPhyErrBase 0x%x cckPhyErrBase 0x%x\n", + __func__, params->ofdmPhyErrBase, params->cckPhyErrBase); + + OS_REG_WRITE(ah, AR_FILTOFDM, 0); + OS_REG_WRITE(ah, AR_FILTCCK, 0); + + OS_REG_WRITE(ah, AR_PHYCNT1, params->ofdmPhyErrBase); + OS_REG_WRITE(ah, AR_PHYCNT2, params->cckPhyErrBase); + OS_REG_WRITE(ah, AR_PHYCNTMASK1, AR_PHY_ERR_OFDM_TIMING); + OS_REG_WRITE(ah, AR_PHYCNTMASK2, AR_PHY_ERR_CCK_TIMING); + + ar5212UpdateMibCounters(ah, &ahp->ah_mibStats); /* save+clear counters*/ + ar5212EnableMibCounters(ah); /* enable everything */ +} + +static void +disableAniMIBCounters(struct ath_hal *ah) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + + HALDEBUG(ah, HAL_DEBUG_ANI, "Disable MIB counters\n"); + + ar5212UpdateMibCounters(ah, &ahp->ah_mibStats); /* save stats */ + ar5212DisableMibCounters(ah); /* disable everything */ + + OS_REG_WRITE(ah, AR_PHYCNTMASK1, 0); + OS_REG_WRITE(ah, AR_PHYCNTMASK2, 0); +} + +/* + * This routine returns the index into the aniState array that + * corresponds to the channel in *chan. If no match is found and the + * array is still not fully utilized, a new entry is created for the + * channel. We assume the attach function has already initialized the + * ah_ani values and only the channel field needs to be set. + */ +static int +ar5212GetAniChannelIndex(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan) +{ +#define N(a) (sizeof(a) / sizeof(a[0])) + struct ath_hal_5212 *ahp = AH5212(ah); + int i; + + for (i = 0; i < N(ahp->ah_ani); i++) { + struct ar5212AniState *asp = &ahp->ah_ani[i]; + if (asp->c.channel == chan->channel) + return i; + if (asp->c.channel == 0) { + asp->c.channel = chan->channel; + asp->c.channelFlags = chan->channelFlags; + asp->c.privFlags = chan->privFlags; + asp->isSetup = AH_FALSE; + if (IS_CHAN_2GHZ(chan)) + asp->params = &ahp->ah_aniParams24; + else + asp->params = &ahp->ah_aniParams5; + return i; + } + } + /* XXX statistic */ + HALDEBUG(ah, HAL_DEBUG_ANY, + "No more channel states left. Using channel 0\n"); + return 0; /* XXX gotta return something valid */ +#undef N +} + +/* + * Return the current ANI state of the channel we're on + */ +struct ar5212AniState * +ar5212AniGetCurrentState(struct ath_hal *ah) +{ + return AH5212(ah)->ah_curani; +} + +/* + * Return the current statistics. + */ +struct ar5212Stats * +ar5212AniGetCurrentStats(struct ath_hal *ah) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + + /* update mib stats so we return current data */ + /* XXX? side-effects to doing this here? */ + ar5212UpdateMibCounters(ah, &ahp->ah_mibStats); + return &ahp->ah_stats; +} + +static void +setPhyErrBase(struct ath_hal *ah, struct ar5212AniParams *params) +{ + if (params->ofdmTrigHigh >= AR_PHY_COUNTMAX) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "OFDM Trigger %d is too high for hw counters, using max\n", + params->ofdmTrigHigh); + params->ofdmPhyErrBase = 0; + } else + params->ofdmPhyErrBase = AR_PHY_COUNTMAX - params->ofdmTrigHigh; + if (params->cckTrigHigh >= AR_PHY_COUNTMAX) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "CCK Trigger %d is too high for hw counters, using max\n", + params->cckTrigHigh); + params->cckPhyErrBase = 0; + } else + params->cckPhyErrBase = AR_PHY_COUNTMAX - params->cckTrigHigh; +} + +/* + * Setup ANI handling. Sets all thresholds and reset the + * channel statistics. Note that ar5212AniReset should be + * called by ar5212Reset before anything else happens and + * that's where we force initial settings. + */ +void +ar5212AniAttach(struct ath_hal *ah, const struct ar5212AniParams *params24, + const struct ar5212AniParams *params5, HAL_BOOL enable) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + + ahp->ah_hasHwPhyCounters = + AH_PRIVATE(ah)->ah_caps.halHwPhyCounterSupport; + + if (params24 != AH_NULL) { + OS_MEMCPY(&ahp->ah_aniParams24, params24, sizeof(*params24)); + setPhyErrBase(ah, &ahp->ah_aniParams24); + } + if (params5 != AH_NULL) { + OS_MEMCPY(&ahp->ah_aniParams5, params5, sizeof(*params5)); + setPhyErrBase(ah, &ahp->ah_aniParams5); + } + + OS_MEMZERO(ahp->ah_ani, sizeof(ahp->ah_ani)); + if (ahp->ah_hasHwPhyCounters) { + /* Enable MIB Counters */ + enableAniMIBCounters(ah, &ahp->ah_aniParams24 /*XXX*/); + } + if (enable) { /* Enable ani now */ + HALASSERT(params24 != AH_NULL && params5 != AH_NULL); + ahp->ah_procPhyErr |= HAL_ANI_ENA; + } else { + ahp->ah_procPhyErr &= ~HAL_ANI_ENA; + } +} + +HAL_BOOL +ar5212AniSetParams(struct ath_hal *ah, const struct ar5212AniParams *params24, + const struct ar5212AniParams *params5) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + HAL_BOOL ena = (ahp->ah_procPhyErr & HAL_ANI_ENA) != 0; + + ar5212AniControl(ah, HAL_ANI_MODE, AH_FALSE); + + OS_MEMCPY(&ahp->ah_aniParams24, params24, sizeof(*params24)); + setPhyErrBase(ah, &ahp->ah_aniParams24); + OS_MEMCPY(&ahp->ah_aniParams5, params5, sizeof(*params5)); + setPhyErrBase(ah, &ahp->ah_aniParams5); + + OS_MEMZERO(ahp->ah_ani, sizeof(ahp->ah_ani)); + ar5212AniReset(ah, AH_PRIVATE(ah)->ah_curchan, + AH_PRIVATE(ah)->ah_opmode, AH_FALSE); + + ar5212AniControl(ah, HAL_ANI_MODE, ena); + + return AH_TRUE; +} + +/* + * Cleanup any ANI state setup. + */ +void +ar5212AniDetach(struct ath_hal *ah) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + + HALDEBUG(ah, HAL_DEBUG_ANI, "Detaching Ani\n"); + if (ahp->ah_hasHwPhyCounters) + disableAniMIBCounters(ah); +} + +/* + * Control Adaptive Noise Immunity Parameters + */ +HAL_BOOL +ar5212AniControl(struct ath_hal *ah, HAL_ANI_CMD cmd, int param) +{ + typedef int TABLE[]; + struct ath_hal_5212 *ahp = AH5212(ah); + struct ar5212AniState *aniState = ahp->ah_curani; + const struct ar5212AniParams *params = aniState->params; + + OS_MARK(ah, AH_MARK_ANI_CONTROL, cmd); + + switch (cmd) { + case HAL_ANI_NOISE_IMMUNITY_LEVEL: { + u_int level = param; + + if (level >= params->maxNoiseImmunityLevel) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: level out of range (%u > %u)\n", + __func__, level, params->maxNoiseImmunityLevel); + return AH_FALSE; + } + + OS_REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, + AR_PHY_DESIRED_SZ_TOT_DES, params->totalSizeDesired[level]); + OS_REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1, + AR_PHY_AGC_CTL1_COARSE_LOW, params->coarseLow[level]); + OS_REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1, + AR_PHY_AGC_CTL1_COARSE_HIGH, params->coarseHigh[level]); + OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, + AR_PHY_FIND_SIG_FIRPWR, params->firpwr[level]); + + if (level > aniState->noiseImmunityLevel) + ahp->ah_stats.ast_ani_niup++; + else if (level < aniState->noiseImmunityLevel) + ahp->ah_stats.ast_ani_nidown++; + aniState->noiseImmunityLevel = level; + break; + } + case HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION: { + static const TABLE m1ThreshLow = { 127, 50 }; + static const TABLE m2ThreshLow = { 127, 40 }; + static const TABLE m1Thresh = { 127, 0x4d }; + static const TABLE m2Thresh = { 127, 0x40 }; + static const TABLE m2CountThr = { 31, 16 }; + static const TABLE m2CountThrLow = { 63, 48 }; + u_int on = param ? 1 : 0; + + OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, + AR_PHY_SFCORR_LOW_M1_THRESH_LOW, m1ThreshLow[on]); + OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, + AR_PHY_SFCORR_LOW_M2_THRESH_LOW, m2ThreshLow[on]); + OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, + AR_PHY_SFCORR_M1_THRESH, m1Thresh[on]); + OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, + AR_PHY_SFCORR_M2_THRESH, m2Thresh[on]); + OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, + AR_PHY_SFCORR_M2COUNT_THR, m2CountThr[on]); + OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, + AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW, m2CountThrLow[on]); + + if (on) { + OS_REG_SET_BIT(ah, AR_PHY_SFCORR_LOW, + AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); + } else { + OS_REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW, + AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); + } + if (on) + ahp->ah_stats.ast_ani_ofdmon++; + else + ahp->ah_stats.ast_ani_ofdmoff++; + aniState->ofdmWeakSigDetectOff = !on; + break; + } + case HAL_ANI_CCK_WEAK_SIGNAL_THR: { + static const TABLE weakSigThrCck = { 8, 6 }; + u_int high = param ? 1 : 0; + + OS_REG_RMW_FIELD(ah, AR_PHY_CCK_DETECT, + AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK, weakSigThrCck[high]); + if (high) + ahp->ah_stats.ast_ani_cckhigh++; + else + ahp->ah_stats.ast_ani_ccklow++; + aniState->cckWeakSigThreshold = high; + break; + } + case HAL_ANI_FIRSTEP_LEVEL: { + u_int level = param; + + if (level >= params->maxFirstepLevel) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: level out of range (%u > %u)\n", + __func__, level, params->maxFirstepLevel); + return AH_FALSE; + } + OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, + AR_PHY_FIND_SIG_FIRSTEP, params->firstep[level]); + if (level > aniState->firstepLevel) + ahp->ah_stats.ast_ani_stepup++; + else if (level < aniState->firstepLevel) + ahp->ah_stats.ast_ani_stepdown++; + aniState->firstepLevel = level; + break; + } + case HAL_ANI_SPUR_IMMUNITY_LEVEL: { + u_int level = param; + + if (level >= params->maxSpurImmunityLevel) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: level out of range (%u > %u)\n", + __func__, level, params->maxSpurImmunityLevel); + return AH_FALSE; + } + OS_REG_RMW_FIELD(ah, AR_PHY_TIMING5, + AR_PHY_TIMING5_CYCPWR_THR1, params->cycPwrThr1[level]); + if (level > aniState->spurImmunityLevel) + ahp->ah_stats.ast_ani_spurup++; + else if (level < aniState->spurImmunityLevel) + ahp->ah_stats.ast_ani_spurdown++; + aniState->spurImmunityLevel = level; + break; + } + case HAL_ANI_PRESENT: + break; + case HAL_ANI_MODE: + if (param == 0) { + ahp->ah_procPhyErr &= ~HAL_ANI_ENA; + /* Turn off HW counters if we have them */ + ar5212AniDetach(ah); + ar5212SetRxFilter(ah, + ar5212GetRxFilter(ah) &~ HAL_RX_FILTER_PHYERR); + } else { /* normal/auto mode */ + /* don't mess with state if already enabled */ + if (ahp->ah_procPhyErr & HAL_ANI_ENA) + break; + if (ahp->ah_hasHwPhyCounters) { + ar5212SetRxFilter(ah, + ar5212GetRxFilter(ah) &~ HAL_RX_FILTER_PHYERR); + /* Enable MIB Counters */ + enableAniMIBCounters(ah, + ahp->ah_curani != AH_NULL ? + ahp->ah_curani->params: + &ahp->ah_aniParams24 /*XXX*/); + } else { + ar5212SetRxFilter(ah, + ar5212GetRxFilter(ah) | HAL_RX_FILTER_PHYERR); + } + ahp->ah_procPhyErr |= HAL_ANI_ENA; + } + break; +#ifdef AH_PRIVATE_DIAG + case HAL_ANI_PHYERR_RESET: + ahp->ah_stats.ast_ani_ofdmerrs = 0; + ahp->ah_stats.ast_ani_cckerrs = 0; + break; +#endif /* AH_PRIVATE_DIAG */ + default: + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid cmd %u\n", + __func__, cmd); + return AH_FALSE; + } + return AH_TRUE; +} + +static void +ar5212AniOfdmErrTrigger(struct ath_hal *ah) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + HAL_CHANNEL_INTERNAL *chan = AH_PRIVATE(ah)->ah_curchan; + struct ar5212AniState *aniState; + const struct ar5212AniParams *params; + + HALASSERT(chan != AH_NULL); + + if (!ANI_ENA(ah)) + return; + + aniState = ahp->ah_curani; + params = aniState->params; + /* First, raise noise immunity level, up to max */ + if (aniState->noiseImmunityLevel+1 < params->maxNoiseImmunityLevel) { + HALDEBUG(ah, HAL_DEBUG_ANI, "%s: raise NI to %u\n", __func__, + aniState->noiseImmunityLevel + 1); + ar5212AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL, + aniState->noiseImmunityLevel + 1); + return; + } + /* then, raise spur immunity level, up to max */ + if (aniState->spurImmunityLevel+1 < params->maxSpurImmunityLevel) { + HALDEBUG(ah, HAL_DEBUG_ANI, "%s: raise SI to %u\n", __func__, + aniState->spurImmunityLevel + 1); + ar5212AniControl(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL, + aniState->spurImmunityLevel + 1); + return; + } + + if (ANI_ENA_RSSI(ah)) { + int32_t rssi = BEACON_RSSI(ahp); + if (rssi > params->rssiThrHigh) { + /* + * Beacon rssi is high, can turn off ofdm + * weak sig detect. + */ + if (!aniState->ofdmWeakSigDetectOff) { + HALDEBUG(ah, HAL_DEBUG_ANI, + "%s: rssi %d OWSD off\n", __func__, rssi); + ar5212AniControl(ah, + HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, + AH_FALSE); + ar5212AniControl(ah, + HAL_ANI_SPUR_IMMUNITY_LEVEL, 0); + return; + } + /* + * If weak sig detect is already off, as last resort, + * raise firstep level + */ + if (aniState->firstepLevel+1 < params->maxFirstepLevel) { + HALDEBUG(ah, HAL_DEBUG_ANI, + "%s: rssi %d raise ST %u\n", __func__, rssi, + aniState->firstepLevel+1); + ar5212AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, + aniState->firstepLevel + 1); + return; + } + } else if (rssi > params->rssiThrLow) { + /* + * Beacon rssi in mid range, need ofdm weak signal + * detect, but we can raise firststepLevel. + */ + if (aniState->ofdmWeakSigDetectOff) { + HALDEBUG(ah, HAL_DEBUG_ANI, + "%s: rssi %d OWSD on\n", __func__, rssi); + ar5212AniControl(ah, + HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, + AH_TRUE); + } + if (aniState->firstepLevel+1 < params->maxFirstepLevel) { + HALDEBUG(ah, HAL_DEBUG_ANI, + "%s: rssi %d raise ST %u\n", __func__, rssi, + aniState->firstepLevel+1); + ar5212AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, + aniState->firstepLevel + 1); + } + return; + } else { + /* + * Beacon rssi is low, if in 11b/g mode, turn off ofdm + * weak signal detection and zero firstepLevel to + * maximize CCK sensitivity + */ + /* XXX can optimize */ + if (IS_CHAN_B(chan) || IS_CHAN_G(chan)) { + if (!aniState->ofdmWeakSigDetectOff) { + HALDEBUG(ah, HAL_DEBUG_ANI, + "%s: rssi %d OWSD off\n", + __func__, rssi); + ar5212AniControl(ah, + HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, + AH_FALSE); + } + if (aniState->firstepLevel > 0) { + HALDEBUG(ah, HAL_DEBUG_ANI, + "%s: rssi %d zero ST (was %u)\n", + __func__, rssi, + aniState->firstepLevel); + ar5212AniControl(ah, + HAL_ANI_FIRSTEP_LEVEL, 0); + } + return; + } + } + } +} + +static void +ar5212AniCckErrTrigger(struct ath_hal *ah) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + HAL_CHANNEL_INTERNAL *chan = AH_PRIVATE(ah)->ah_curchan; + struct ar5212AniState *aniState; + const struct ar5212AniParams *params; + + HALASSERT(chan != AH_NULL); + + if (!ANI_ENA(ah)) + return; + + /* first, raise noise immunity level, up to max */ + aniState = ahp->ah_curani; + params = aniState->params; + if (aniState->noiseImmunityLevel+1 < params->maxNoiseImmunityLevel) { + HALDEBUG(ah, HAL_DEBUG_ANI, "%s: raise NI to %u\n", __func__, + aniState->noiseImmunityLevel + 1); + ar5212AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL, + aniState->noiseImmunityLevel + 1); + return; + } + + if (ANI_ENA_RSSI(ah)) { + int32_t rssi = BEACON_RSSI(ahp); + if (rssi > params->rssiThrLow) { + /* + * Beacon signal in mid and high range, + * raise firstep level. + */ + if (aniState->firstepLevel+1 < params->maxFirstepLevel) { + HALDEBUG(ah, HAL_DEBUG_ANI, + "%s: rssi %d raise ST %u\n", __func__, rssi, + aniState->firstepLevel+1); + ar5212AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, + aniState->firstepLevel + 1); + } + } else { + /* + * Beacon rssi is low, zero firstep level to maximize + * CCK sensitivity in 11b/g mode. + */ + /* XXX can optimize */ + if (IS_CHAN_B(chan) || IS_CHAN_G(chan)) { + if (aniState->firstepLevel > 0) { + HALDEBUG(ah, HAL_DEBUG_ANI, + "%s: rssi %d zero ST (was %u)\n", + __func__, rssi, + aniState->firstepLevel); + ar5212AniControl(ah, + HAL_ANI_FIRSTEP_LEVEL, 0); + } + } + } + } +} + +static void +ar5212AniRestart(struct ath_hal *ah, struct ar5212AniState *aniState) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + + aniState->listenTime = 0; + if (ahp->ah_hasHwPhyCounters) { + const struct ar5212AniParams *params = aniState->params; + /* + * NB: these are written on reset based on the + * ini so we must re-write them! + */ + OS_REG_WRITE(ah, AR_PHYCNT1, params->ofdmPhyErrBase); + OS_REG_WRITE(ah, AR_PHYCNT2, params->cckPhyErrBase); + OS_REG_WRITE(ah, AR_PHYCNTMASK1, AR_PHY_ERR_OFDM_TIMING); + OS_REG_WRITE(ah, AR_PHYCNTMASK2, AR_PHY_ERR_CCK_TIMING); + + /* Clear the mib counters and save them in the stats */ + ar5212UpdateMibCounters(ah, &ahp->ah_mibStats); + } + aniState->ofdmPhyErrCount = 0; + aniState->cckPhyErrCount = 0; +} + +/* + * Restore/reset the ANI parameters and reset the statistics. + * This routine must be called for every channel change. + * + * NOTE: This is where ah_curani is set; other ani code assumes + * it is setup to reflect the current channel. + */ +void +ar5212AniReset(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan, + HAL_OPMODE opmode, int restore) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + struct ar5212AniState *aniState; + uint32_t rxfilter; + int index; + + index = ar5212GetAniChannelIndex(ah, chan); + aniState = &ahp->ah_ani[index]; + ahp->ah_curani = aniState; +#if 0 + ath_hal_printf(ah,"%s: chan %u/0x%x restore %d setup %d opmode %u\n", + __func__, chan->channel, chan->channelFlags, restore, + aniState->isSetup, opmode); +#else + HALDEBUG(ah, HAL_DEBUG_ANI, + "%s: chan %u/0x%x restore %d setup %d opmode %u\n", + __func__, chan->channel, chan->channelFlags, restore, + aniState->isSetup, opmode); +#endif + OS_MARK(ah, AH_MARK_ANI_RESET, opmode); + + /* + * Turn off PHY error frame delivery while we futz with settings. + */ + rxfilter = ar5212GetRxFilter(ah); + ar5212SetRxFilter(ah, rxfilter &~ HAL_RX_FILTER_PHYERR); + /* + * Automatic processing is done only in station mode right now. + */ + if (opmode == HAL_M_STA) + ahp->ah_procPhyErr |= HAL_RSSI_ANI_ENA; + else + ahp->ah_procPhyErr &= ~HAL_RSSI_ANI_ENA; + /* + * Set all ani parameters. We either set them to initial + * values or restore the previous ones for the channel. + * XXX if ANI follows hardware, we don't care what mode we're + * XXX in, we should keep the ani parameters + */ + if (restore && aniState->isSetup) { + ar5212AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL, + aniState->noiseImmunityLevel); + ar5212AniControl(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL, + aniState->spurImmunityLevel); + ar5212AniControl(ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, + !aniState->ofdmWeakSigDetectOff); + ar5212AniControl(ah, HAL_ANI_CCK_WEAK_SIGNAL_THR, + aniState->cckWeakSigThreshold); + ar5212AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, + aniState->firstepLevel); + } else { + ar5212AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL, 0); + ar5212AniControl(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL, 0); + ar5212AniControl(ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, + AH_TRUE); + ar5212AniControl(ah, HAL_ANI_CCK_WEAK_SIGNAL_THR, AH_FALSE); + ar5212AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, 0); + aniState->isSetup = AH_TRUE; + } + ar5212AniRestart(ah, aniState); + + /* restore RX filter mask */ + ar5212SetRxFilter(ah, rxfilter); +} + +/* + * Process a MIB interrupt. We may potentially be invoked because + * any of the MIB counters overflow/trigger so don't assume we're + * here because a PHY error counter triggered. + */ +void +ar5212ProcessMibIntr(struct ath_hal *ah, const HAL_NODE_STATS *stats) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + uint32_t phyCnt1, phyCnt2; + + HALDEBUG(ah, HAL_DEBUG_ANI, "%s: mibc 0x%x phyCnt1 0x%x phyCnt2 0x%x " + "filtofdm 0x%x filtcck 0x%x\n", + __func__, OS_REG_READ(ah, AR_MIBC), + OS_REG_READ(ah, AR_PHYCNT1), OS_REG_READ(ah, AR_PHYCNT2), + OS_REG_READ(ah, AR_FILTOFDM), OS_REG_READ(ah, AR_FILTCCK)); + + /* + * First order of business is to clear whatever caused + * the interrupt so we don't keep getting interrupted. + * We have the usual mib counters that are reset-on-read + * and the additional counters that appeared starting in + * Hainan. We collect the mib counters and explicitly + * zero additional counters we are not using. Anything + * else is reset only if it caused the interrupt. + */ + /* NB: these are not reset-on-read */ + phyCnt1 = OS_REG_READ(ah, AR_PHYCNT1); + phyCnt2 = OS_REG_READ(ah, AR_PHYCNT2); + /* not used, always reset them in case they are the cause */ + OS_REG_WRITE(ah, AR_FILTOFDM, 0); + OS_REG_WRITE(ah, AR_FILTCCK, 0); + + /* Clear the mib counters and save them in the stats */ + ar5212UpdateMibCounters(ah, &ahp->ah_mibStats); + ahp->ah_stats.ast_nodestats = *stats; + + /* + * Check for an ani stat hitting the trigger threshold. + * When this happens we get a MIB interrupt and the top + * 2 bits of the counter register will be 0b11, hence + * the mask check of phyCnt?. + */ + if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) || + ((phyCnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) { + struct ar5212AniState *aniState = ahp->ah_curani; + const struct ar5212AniParams *params = aniState->params; + uint32_t ofdmPhyErrCnt, cckPhyErrCnt; + + ofdmPhyErrCnt = phyCnt1 - params->ofdmPhyErrBase; + ahp->ah_stats.ast_ani_ofdmerrs += + ofdmPhyErrCnt - aniState->ofdmPhyErrCount; + aniState->ofdmPhyErrCount = ofdmPhyErrCnt; + + cckPhyErrCnt = phyCnt2 - params->cckPhyErrBase; + ahp->ah_stats.ast_ani_cckerrs += + cckPhyErrCnt - aniState->cckPhyErrCount; + aniState->cckPhyErrCount = cckPhyErrCnt; + + /* + * NB: figure out which counter triggered. If both + * trigger we'll only deal with one as the processing + * clobbers the error counter so the trigger threshold + * check will never be true. + */ + if (aniState->ofdmPhyErrCount > params->ofdmTrigHigh) + ar5212AniOfdmErrTrigger(ah); + if (aniState->cckPhyErrCount > params->cckTrigHigh) + ar5212AniCckErrTrigger(ah); + /* NB: always restart to insure the h/w counters are reset */ + ar5212AniRestart(ah, aniState); + } +} + +void +ar5212AniPhyErrReport(struct ath_hal *ah, const struct ath_rx_status *rs) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + struct ar5212AniState *aniState; + const struct ar5212AniParams *params; + + HALASSERT(!ahp->ah_hasHwPhyCounters && rs != AH_NULL); + + aniState = ahp->ah_curani; + params = aniState->params; + if (rs->rs_phyerr == HAL_PHYERR_OFDM_TIMING) { + aniState->ofdmPhyErrCount++; + ahp->ah_stats.ast_ani_ofdmerrs++; + if (aniState->ofdmPhyErrCount > params->ofdmTrigHigh) { + ar5212AniOfdmErrTrigger(ah); + ar5212AniRestart(ah, aniState); + } + } else if (rs->rs_phyerr == HAL_PHYERR_CCK_TIMING) { + aniState->cckPhyErrCount++; + ahp->ah_stats.ast_ani_cckerrs++; + if (aniState->cckPhyErrCount > params->cckTrigHigh) { + ar5212AniCckErrTrigger(ah); + ar5212AniRestart(ah, aniState); + } + } +} + +static void +ar5212AniLowerImmunity(struct ath_hal *ah) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + struct ar5212AniState *aniState; + const struct ar5212AniParams *params; + + HALASSERT(ANI_ENA(ah)); + + aniState = ahp->ah_curani; + params = aniState->params; + if (ANI_ENA_RSSI(ah)) { + int32_t rssi = BEACON_RSSI(ahp); + if (rssi > params->rssiThrHigh) { + /* + * Beacon signal is high, leave ofdm weak signal + * detection off or it may oscillate. Let it fall + * through. + */ + } else if (rssi > params->rssiThrLow) { + /* + * Beacon rssi in mid range, turn on ofdm weak signal + * detection or lower firstep level. + */ + if (aniState->ofdmWeakSigDetectOff) { + HALDEBUG(ah, HAL_DEBUG_ANI, + "%s: rssi %d OWSD on\n", __func__, rssi); + ar5212AniControl(ah, + HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, + AH_TRUE); + return; + } + if (aniState->firstepLevel > 0) { + HALDEBUG(ah, HAL_DEBUG_ANI, + "%s: rssi %d lower ST %u\n", __func__, rssi, + aniState->firstepLevel-1); + ar5212AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, + aniState->firstepLevel - 1); + return; + } + } else { + /* + * Beacon rssi is low, reduce firstep level. + */ + if (aniState->firstepLevel > 0) { + HALDEBUG(ah, HAL_DEBUG_ANI, + "%s: rssi %d lower ST %u\n", __func__, rssi, + aniState->firstepLevel-1); + ar5212AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, + aniState->firstepLevel - 1); + return; + } + } + } + /* then lower spur immunity level, down to zero */ + if (aniState->spurImmunityLevel > 0) { + HALDEBUG(ah, HAL_DEBUG_ANI, "%s: lower SI %u\n", + __func__, aniState->spurImmunityLevel-1); + ar5212AniControl(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL, + aniState->spurImmunityLevel - 1); + return; + } + /* + * if all else fails, lower noise immunity level down to a min value + * zero for now + */ + if (aniState->noiseImmunityLevel > 0) { + HALDEBUG(ah, HAL_DEBUG_ANI, "%s: lower NI %u\n", + __func__, aniState->noiseImmunityLevel-1); + ar5212AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL, + aniState->noiseImmunityLevel - 1); + return; + } +} + +#define CLOCK_RATE 44000 /* XXX use mac_usec or similar */ +/* convert HW counter values to ms using 11g clock rate, goo9d enough + for 11a and Turbo */ + +/* + * Return an approximation of the time spent ``listening'' by + * deducting the cycles spent tx'ing and rx'ing from the total + * cycle count since our last call. A return value <0 indicates + * an invalid/inconsistent time. + */ +static int32_t +ar5212AniGetListenTime(struct ath_hal *ah) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + struct ar5212AniState *aniState; + uint32_t txFrameCount, rxFrameCount, cycleCount; + int32_t listenTime; + + txFrameCount = OS_REG_READ(ah, AR_TFCNT); + rxFrameCount = OS_REG_READ(ah, AR_RFCNT); + cycleCount = OS_REG_READ(ah, AR_CCCNT); + + aniState = ahp->ah_curani; + if (aniState->cycleCount == 0 || aniState->cycleCount > cycleCount) { + /* + * Cycle counter wrap (or initial call); it's not possible + * to accurately calculate a value because the registers + * right shift rather than wrap--so punt and return 0. + */ + listenTime = 0; + ahp->ah_stats.ast_ani_lzero++; + } else { + int32_t ccdelta = cycleCount - aniState->cycleCount; + int32_t rfdelta = rxFrameCount - aniState->rxFrameCount; + int32_t tfdelta = txFrameCount - aniState->txFrameCount; + listenTime = (ccdelta - rfdelta - tfdelta) / CLOCK_RATE; + } + aniState->cycleCount = cycleCount; + aniState->txFrameCount = txFrameCount; + aniState->rxFrameCount = rxFrameCount; + return listenTime; +} + +/* + * Update ani stats in preparation for listen time processing. + */ +static void +updateMIBStats(struct ath_hal *ah, struct ar5212AniState *aniState) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + const struct ar5212AniParams *params = aniState->params; + uint32_t phyCnt1, phyCnt2; + int32_t ofdmPhyErrCnt, cckPhyErrCnt; + + HALASSERT(ahp->ah_hasHwPhyCounters); + + /* Clear the mib counters and save them in the stats */ + ar5212UpdateMibCounters(ah, &ahp->ah_mibStats); + + /* NB: these are not reset-on-read */ + phyCnt1 = OS_REG_READ(ah, AR_PHYCNT1); + phyCnt2 = OS_REG_READ(ah, AR_PHYCNT2); + + /* NB: these are spec'd to never roll-over */ + ofdmPhyErrCnt = phyCnt1 - params->ofdmPhyErrBase; + if (ofdmPhyErrCnt < 0) { + HALDEBUG(ah, HAL_DEBUG_ANI, "OFDM phyErrCnt %d phyCnt1 0x%x\n", + ofdmPhyErrCnt, phyCnt1); + ofdmPhyErrCnt = AR_PHY_COUNTMAX; + } + ahp->ah_stats.ast_ani_ofdmerrs += + ofdmPhyErrCnt - aniState->ofdmPhyErrCount; + aniState->ofdmPhyErrCount = ofdmPhyErrCnt; + + cckPhyErrCnt = phyCnt2 - params->cckPhyErrBase; + if (cckPhyErrCnt < 0) { + HALDEBUG(ah, HAL_DEBUG_ANI, "CCK phyErrCnt %d phyCnt2 0x%x\n", + cckPhyErrCnt, phyCnt2); + cckPhyErrCnt = AR_PHY_COUNTMAX; + } + ahp->ah_stats.ast_ani_cckerrs += + cckPhyErrCnt - aniState->cckPhyErrCount; + aniState->cckPhyErrCount = cckPhyErrCnt; +} + +/* + * Do periodic processing. This routine is called from the + * driver's rx interrupt handler after processing frames. + */ +void +ar5212AniPoll(struct ath_hal *ah, const HAL_NODE_STATS *stats, + HAL_CHANNEL *chan) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + struct ar5212AniState *aniState = ahp->ah_curani; + const struct ar5212AniParams *params; + int32_t listenTime; + + ahp->ah_stats.ast_nodestats.ns_avgbrssi = stats->ns_avgbrssi; + + /* XXX can aniState be null? */ + if (aniState == AH_NULL) + return; + if (!ANI_ENA(ah)) + return; + + listenTime = ar5212AniGetListenTime(ah); + if (listenTime < 0) { + ahp->ah_stats.ast_ani_lneg++; + /* restart ANI period if listenTime is invalid */ + ar5212AniRestart(ah, aniState); + } + /* XXX beware of overflow? */ + aniState->listenTime += listenTime; + + OS_MARK(ah, AH_MARK_ANI_POLL, aniState->listenTime); + + params = aniState->params; + if (aniState->listenTime > 5*params->period) { + /* + * Check to see if need to lower immunity if + * 5 aniPeriods have passed + */ + if (ahp->ah_hasHwPhyCounters) + updateMIBStats(ah, aniState); + if (aniState->ofdmPhyErrCount <= aniState->listenTime * + params->ofdmTrigLow/1000 && + aniState->cckPhyErrCount <= aniState->listenTime * + params->cckTrigLow/1000) + ar5212AniLowerImmunity(ah); + ar5212AniRestart(ah, aniState); + } else if (aniState->listenTime > params->period) { + if (ahp->ah_hasHwPhyCounters) + updateMIBStats(ah, aniState); + /* check to see if need to raise immunity */ + if (aniState->ofdmPhyErrCount > aniState->listenTime * + params->ofdmTrigHigh / 1000) { + HALDEBUG(ah, HAL_DEBUG_ANI, + "%s: OFDM err %u listenTime %u\n", __func__, + aniState->ofdmPhyErrCount, aniState->listenTime); + ar5212AniOfdmErrTrigger(ah); + ar5212AniRestart(ah, aniState); + } else if (aniState->cckPhyErrCount > aniState->listenTime * + params->cckTrigHigh / 1000) { + HALDEBUG(ah, HAL_DEBUG_ANI, + "%s: CCK err %u listenTime %u\n", __func__, + aniState->cckPhyErrCount, aniState->listenTime); + ar5212AniCckErrTrigger(ah); + ar5212AniRestart(ah, aniState); + } + } +} --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5212/ar5212_attach.c 2009-03-23 17:36:55.000000000 +0000 @@ -0,0 +1,870 @@ +/* + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2008 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ar5212_attach.c,v 1.1 2009/03/23 17:14:47 sborrill Exp $ + */ +#include "opt_ah.h" + +#include "ah.h" +#include "ah_internal.h" +#include "ah_devid.h" + +#include "ar5212/ar5212.h" +#include "ar5212/ar5212reg.h" +#include "ar5212/ar5212phy.h" + +#define AH_5212_COMMON +#include "ar5212/ar5212.ini" + +static const struct ath_hal_private ar5212hal = {{ + .ah_magic = AR5212_MAGIC, + .ah_abi = HAL_ABI_VERSION, + .ah_countryCode = CTRY_DEFAULT, + + .ah_getRateTable = ar5212GetRateTable, + .ah_detach = ar5212Detach, + + /* Reset Functions */ + .ah_reset = ar5212Reset, + .ah_phyDisable = ar5212PhyDisable, + .ah_disable = ar5212Disable, + .ah_setPCUConfig = ar5212SetPCUConfig, + .ah_perCalibration = ar5212PerCalibration, + .ah_perCalibrationN = ar5212PerCalibrationN, + .ah_resetCalValid = ar5212ResetCalValid, + .ah_setTxPowerLimit = ar5212SetTxPowerLimit, + .ah_getChanNoise = ath_hal_getChanNoise, + + /* Transmit functions */ + .ah_updateTxTrigLevel = ar5212UpdateTxTrigLevel, + .ah_setupTxQueue = ar5212SetupTxQueue, + .ah_setTxQueueProps = ar5212SetTxQueueProps, + .ah_getTxQueueProps = ar5212GetTxQueueProps, + .ah_releaseTxQueue = ar5212ReleaseTxQueue, + .ah_resetTxQueue = ar5212ResetTxQueue, + .ah_getTxDP = ar5212GetTxDP, + .ah_setTxDP = ar5212SetTxDP, + .ah_numTxPending = ar5212NumTxPending, + .ah_startTxDma = ar5212StartTxDma, + .ah_stopTxDma = ar5212StopTxDma, + .ah_setupTxDesc = ar5212SetupTxDesc, + .ah_setupXTxDesc = ar5212SetupXTxDesc, + .ah_fillTxDesc = ar5212FillTxDesc, + .ah_procTxDesc = ar5212ProcTxDesc, + .ah_getTxIntrQueue = ar5212GetTxIntrQueue, + .ah_reqTxIntrDesc = ar5212IntrReqTxDesc, + + /* RX Functions */ + .ah_getRxDP = ar5212GetRxDP, + .ah_setRxDP = ar5212SetRxDP, + .ah_enableReceive = ar5212EnableReceive, + .ah_stopDmaReceive = ar5212StopDmaReceive, + .ah_startPcuReceive = ar5212StartPcuReceive, + .ah_stopPcuReceive = ar5212StopPcuReceive, + .ah_setMulticastFilter = ar5212SetMulticastFilter, + .ah_setMulticastFilterIndex = ar5212SetMulticastFilterIndex, + .ah_clrMulticastFilterIndex = ar5212ClrMulticastFilterIndex, + .ah_getRxFilter = ar5212GetRxFilter, + .ah_setRxFilter = ar5212SetRxFilter, + .ah_setupRxDesc = ar5212SetupRxDesc, + .ah_procRxDesc = ar5212ProcRxDesc, + .ah_rxMonitor = ar5212AniPoll, + .ah_procMibEvent = ar5212ProcessMibIntr, + + /* Misc Functions */ + .ah_getCapability = ar5212GetCapability, + .ah_setCapability = ar5212SetCapability, + .ah_getDiagState = ar5212GetDiagState, + .ah_getMacAddress = ar5212GetMacAddress, + .ah_setMacAddress = ar5212SetMacAddress, + .ah_getBssIdMask = ar5212GetBssIdMask, + .ah_setBssIdMask = ar5212SetBssIdMask, + .ah_setRegulatoryDomain = ar5212SetRegulatoryDomain, + .ah_setLedState = ar5212SetLedState, + .ah_writeAssocid = ar5212WriteAssocid, + .ah_gpioCfgInput = ar5212GpioCfgInput, + .ah_gpioCfgOutput = ar5212GpioCfgOutput, + .ah_gpioGet = ar5212GpioGet, + .ah_gpioSet = ar5212GpioSet, + .ah_gpioSetIntr = ar5212GpioSetIntr, + .ah_getTsf32 = ar5212GetTsf32, + .ah_getTsf64 = ar5212GetTsf64, + .ah_resetTsf = ar5212ResetTsf, + .ah_detectCardPresent = ar5212DetectCardPresent, + .ah_updateMibCounters = ar5212UpdateMibCounters, + .ah_getRfGain = ar5212GetRfgain, + .ah_getDefAntenna = ar5212GetDefAntenna, + .ah_setDefAntenna = ar5212SetDefAntenna, + .ah_getAntennaSwitch = ar5212GetAntennaSwitch, + .ah_setAntennaSwitch = ar5212SetAntennaSwitch, + .ah_setSifsTime = ar5212SetSifsTime, + .ah_getSifsTime = ar5212GetSifsTime, + .ah_setSlotTime = ar5212SetSlotTime, + .ah_getSlotTime = ar5212GetSlotTime, + .ah_setAckTimeout = ar5212SetAckTimeout, + .ah_getAckTimeout = ar5212GetAckTimeout, + .ah_setAckCTSRate = ar5212SetAckCTSRate, + .ah_getAckCTSRate = ar5212GetAckCTSRate, + .ah_setCTSTimeout = ar5212SetCTSTimeout, + .ah_getCTSTimeout = ar5212GetCTSTimeout, + .ah_setDecompMask = ar5212SetDecompMask, + .ah_setCoverageClass = ar5212SetCoverageClass, + + /* Key Cache Functions */ + .ah_getKeyCacheSize = ar5212GetKeyCacheSize, + .ah_resetKeyCacheEntry = ar5212ResetKeyCacheEntry, + .ah_isKeyCacheEntryValid = ar5212IsKeyCacheEntryValid, + .ah_setKeyCacheEntry = ar5212SetKeyCacheEntry, + .ah_setKeyCacheEntryMac = ar5212SetKeyCacheEntryMac, + + /* Power Management Functions */ + .ah_setPowerMode = ar5212SetPowerMode, + .ah_getPowerMode = ar5212GetPowerMode, + + /* Beacon Functions */ + .ah_setBeaconTimers = ar5212SetBeaconTimers, + .ah_beaconInit = ar5212BeaconInit, + .ah_setStationBeaconTimers = ar5212SetStaBeaconTimers, + .ah_resetStationBeaconTimers = ar5212ResetStaBeaconTimers, + + /* Interrupt Functions */ + .ah_isInterruptPending = ar5212IsInterruptPending, + .ah_getPendingInterrupts = ar5212GetPendingInterrupts, + .ah_getInterrupts = ar5212GetInterrupts, + .ah_setInterrupts = ar5212SetInterrupts }, + + .ah_getChannelEdges = ar5212GetChannelEdges, + .ah_getWirelessModes = ar5212GetWirelessModes, + .ah_eepromRead = ar5212EepromRead, +#ifdef AH_SUPPORT_WRITE_EEPROM + .ah_eepromWrite = ar5212EepromWrite, +#endif + .ah_gpioCfgOutput = ar5212GpioCfgOutput, + .ah_gpioCfgInput = ar5212GpioCfgInput, + .ah_gpioGet = ar5212GpioGet, + .ah_gpioSet = ar5212GpioSet, + .ah_gpioSetIntr = ar5212GpioSetIntr, + .ah_getChipPowerLimits = ar5212GetChipPowerLimits, +}; + +/* + * Disable PLL when in L0s as well as receiver clock when in L1. + * This power saving option must be enabled through the Serdes. + * + * Programming the Serdes must go through the same 288 bit serial shift + * register as the other analog registers. Hence the 9 writes. + * + * XXX Clean up the magic numbers. + */ +static void +configurePciePowerSave(struct ath_hal *ah) +{ + OS_REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fc00); + OS_REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924); + + /* RX shut off when elecidle is asserted */ + OS_REG_WRITE(ah, AR_PCIE_SERDES, 0x28000039); + OS_REG_WRITE(ah, AR_PCIE_SERDES, 0x53160824); + OS_REG_WRITE(ah, AR_PCIE_SERDES, 0xe5980579); + + /* Shut off PLL and CLKREQ active in L1 */ + OS_REG_WRITE(ah, AR_PCIE_SERDES, 0x001defff); + OS_REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40); + OS_REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554); + OS_REG_WRITE(ah, AR_PCIE_SERDES, 0x000e3007); + + /* Load the new settings */ + OS_REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000); +} + +uint32_t +ar5212GetRadioRev(struct ath_hal *ah) +{ + uint32_t val; + int i; + + /* Read Radio Chip Rev Extract */ + OS_REG_WRITE(ah, AR_PHY(0x34), 0x00001c16); + for (i = 0; i < 8; i++) + OS_REG_WRITE(ah, AR_PHY(0x20), 0x00010000); + val = (OS_REG_READ(ah, AR_PHY(256)) >> 24) & 0xff; + val = ((val & 0xf0) >> 4) | ((val & 0x0f) << 4); + return ath_hal_reverseBits(val, 8); +} + +static void +ar5212AniSetup(struct ath_hal *ah) +{ + static const struct ar5212AniParams aniparams = { + .maxNoiseImmunityLevel = 4, /* levels 0..4 */ + .totalSizeDesired = { -55, -55, -55, -55, -62 }, + .coarseHigh = { -14, -14, -14, -14, -12 }, + .coarseLow = { -64, -64, -64, -64, -70 }, + .firpwr = { -78, -78, -78, -78, -80 }, + .maxSpurImmunityLevel = 2, /* NB: depends on chip rev */ + .cycPwrThr1 = { 2, 4, 6, 8, 10, 12, 14, 16 }, + .maxFirstepLevel = 2, /* levels 0..2 */ + .firstep = { 0, 4, 8 }, + .ofdmTrigHigh = 500, + .ofdmTrigLow = 200, + .cckTrigHigh = 200, + .cckTrigLow = 100, + .rssiThrHigh = 40, + .rssiThrLow = 7, + .period = 100, + }; + if (AH_PRIVATE(ah)->ah_macVersion < AR_SREV_VERSION_GRIFFIN) { + struct ar5212AniParams tmp; + OS_MEMCPY(&tmp, &aniparams, sizeof(struct ar5212AniParams)); + tmp.maxSpurImmunityLevel = 7; /* Venice and earlier */ + ar5212AniAttach(ah, &tmp, &tmp, AH_TRUE); + } else + ar5212AniAttach(ah, &aniparams, &aniparams, AH_TRUE); +} + +/* + * Attach for an AR5212 part. + */ +void +ar5212InitState(struct ath_hal_5212 *ahp, uint16_t devid, HAL_SOFTC sc, + HAL_BUS_TAG st, HAL_BUS_HANDLE sh, HAL_STATUS *status) +{ +#define N(a) (sizeof(a)/sizeof(a[0])) + static const uint8_t defbssidmask[IEEE80211_ADDR_LEN] = + { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + struct ath_hal *ah; + + ah = &ahp->ah_priv.h; + /* set initial values */ + OS_MEMCPY(&ahp->ah_priv, &ar5212hal, sizeof(struct ath_hal_private)); + ah->ah_sc = sc; + ah->ah_st = st; + ah->ah_sh = sh; + + ah->ah_devid = devid; /* NB: for alq */ + AH_PRIVATE(ah)->ah_devid = devid; + AH_PRIVATE(ah)->ah_subvendorid = 0; /* XXX */ + + AH_PRIVATE(ah)->ah_powerLimit = MAX_RATE_POWER; + AH_PRIVATE(ah)->ah_tpScale = HAL_TP_SCALE_MAX; /* no scaling */ + + ahp->ah_antControl = HAL_ANT_VARIABLE; + ahp->ah_diversity = AH_TRUE; + ahp->ah_bIQCalibration = AH_FALSE; + /* + * Enable MIC handling. + */ + ahp->ah_staId1Defaults = AR_STA_ID1_CRPT_MIC_ENABLE; + ahp->ah_rssiThr = INIT_RSSI_THR; + ahp->ah_tpcEnabled = AH_FALSE; /* disabled by default */ + ahp->ah_phyPowerOn = AH_FALSE; + ahp->ah_macTPC = SM(MAX_RATE_POWER, AR_TPC_ACK) + | SM(MAX_RATE_POWER, AR_TPC_CTS) + | SM(MAX_RATE_POWER, AR_TPC_CHIRP); + ahp->ah_beaconInterval = 100; /* XXX [20..1000] */ + ahp->ah_enable32kHzClock = DONT_USE_32KHZ;/* XXX */ + ahp->ah_slottime = (u_int) -1; + ahp->ah_acktimeout = (u_int) -1; + ahp->ah_ctstimeout = (u_int) -1; + ahp->ah_sifstime = (u_int) -1; + OS_MEMCPY(&ahp->ah_bssidmask, defbssidmask, IEEE80211_ADDR_LEN); +#undef N +} + +/* + * Validate MAC version and revision. + */ +static HAL_BOOL +ar5212IsMacSupported(uint8_t macVersion, uint8_t macRev) +{ +#define N(a) (sizeof(a)/sizeof(a[0])) + static const struct { + uint8_t version; + uint8_t revMin, revMax; + } macs[] = { + { AR_SREV_VERSION_VENICE, + AR_SREV_D2PLUS, AR_SREV_REVISION_MAX }, + { AR_SREV_VERSION_GRIFFIN, + AR_SREV_D2PLUS, AR_SREV_REVISION_MAX }, + { AR_SREV_5413, + AR_SREV_REVISION_MIN, AR_SREV_REVISION_MAX }, + { AR_SREV_5424, + AR_SREV_REVISION_MIN, AR_SREV_REVISION_MAX }, + { AR_SREV_2425, + AR_SREV_REVISION_MIN, AR_SREV_REVISION_MAX }, + { AR_SREV_2417, + AR_SREV_REVISION_MIN, AR_SREV_REVISION_MAX }, + }; + int i; + + for (i = 0; i < N(macs); i++) + if (macs[i].version == macVersion && + macs[i].revMin <= macRev && macRev <= macs[i].revMax) + return AH_TRUE; + return AH_FALSE; +#undef N +} + +/* + * Attach for an AR5212 part. + */ +static struct ath_hal * +ar5212Attach(uint16_t devid, HAL_SOFTC sc, + HAL_BUS_TAG st, HAL_BUS_HANDLE sh, HAL_STATUS *status) +{ +#define AH_EEPROM_PROTECT(ah) \ + (IS_PCIE(ah) ? AR_EEPROM_PROTECT_PCIE : AR_EEPROM_PROTECT) + struct ath_hal_5212 *ahp; + struct ath_hal *ah; + struct ath_hal_rf *rf; + uint32_t val; + uint16_t eeval; + HAL_STATUS ecode; + + HALDEBUG(AH_NULL, HAL_DEBUG_ATTACH, "%s: sc %p st %p sh %p\n", + __func__, sc, (void*) st, (void*) sh); + + /* NB: memory is returned zero'd */ + ahp = ath_hal_malloc(sizeof (struct ath_hal_5212)); + if (ahp == AH_NULL) { + HALDEBUG(AH_NULL, HAL_DEBUG_ANY, + "%s: cannot allocate memory for state block\n", __func__); + *status = HAL_ENOMEM; + return AH_NULL; + } + ar5212InitState(ahp, devid, sc, st, sh, status); + ah = &ahp->ah_priv.h; + + if (!ar5212SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE)) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: couldn't wakeup chip\n", + __func__); + ecode = HAL_EIO; + goto bad; + } + /* Read Revisions from Chips before taking out of reset */ + val = OS_REG_READ(ah, AR_SREV) & AR_SREV_ID; + AH_PRIVATE(ah)->ah_macVersion = val >> AR_SREV_ID_S; + AH_PRIVATE(ah)->ah_macRev = val & AR_SREV_REVISION; + + if (!ar5212IsMacSupported(AH_PRIVATE(ah)->ah_macVersion, AH_PRIVATE(ah)->ah_macRev)) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: Mac Chip Rev 0x%02x.%x not supported\n" , + __func__, AH_PRIVATE(ah)->ah_macVersion, + AH_PRIVATE(ah)->ah_macRev); + ecode = HAL_ENOTSUPP; + goto bad; + } + + /* setup common ini data; rf backends handle remainder */ + HAL_INI_INIT(&ahp->ah_ini_modes, ar5212Modes, 6); + HAL_INI_INIT(&ahp->ah_ini_common, ar5212Common, 2); + + if (!ar5212ChipReset(ah, AH_NULL)) { /* reset chip */ + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: chip reset failed\n", __func__); + ecode = HAL_EIO; + goto bad; + } + + AH_PRIVATE(ah)->ah_phyRev = OS_REG_READ(ah, AR_PHY_CHIP_ID); + + if (IS_PCIE(ah)) { + /* XXX: build flag to disable this? */ + configurePciePowerSave(ah); + } + + if (!ar5212ChipTest(ah)) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: hardware self-test failed\n", + __func__); + ecode = HAL_ESELFTEST; + goto bad; + } + + /* Enable PCI core retry fix in software for Hainan and up */ + if (AH_PRIVATE(ah)->ah_macVersion >= AR_SREV_VERSION_VENICE) + OS_REG_SET_BIT(ah, AR_PCICFG, AR_PCICFG_RETRYFIXEN); + + /* + * Set correct Baseband to analog shift + * setting to access analog chips. + */ + OS_REG_WRITE(ah, AR_PHY(0), 0x00000007); + + /* Read Radio Chip Rev Extract */ + AH_PRIVATE(ah)->ah_analog5GhzRev = ar5212GetRadioRev(ah); + + rf = ath_hal_rfprobe(ah, &ecode); + if (rf == AH_NULL) + goto bad; + + /* NB: silently accept anything in release code per Atheros */ + switch (AH_PRIVATE(ah)->ah_analog5GhzRev & AR_RADIO_SREV_MAJOR) { + case AR_RAD5111_SREV_MAJOR: + case AR_RAD5112_SREV_MAJOR: + case AR_RAD2112_SREV_MAJOR: + case AR_RAD2111_SREV_MAJOR: + case AR_RAD2413_SREV_MAJOR: + case AR_RAD5413_SREV_MAJOR: + case AR_RAD5424_SREV_MAJOR: + break; + default: + if (AH_PRIVATE(ah)->ah_analog5GhzRev == 0) { + /* + * When RF_Silent is used, the + * analog chip is reset. So when the system boots + * up with the radio switch off we cannot determine + * the RF chip rev. To workaround this check the + * mac+phy revs and if Hainan, set the radio rev + * to Derby. + */ + if (AH_PRIVATE(ah)->ah_macVersion == AR_SREV_VERSION_VENICE && + AH_PRIVATE(ah)->ah_macRev == AR_SREV_HAINAN && + AH_PRIVATE(ah)->ah_phyRev == AR_PHYREV_HAINAN) { + AH_PRIVATE(ah)->ah_analog5GhzRev = AR_ANALOG5REV_HAINAN; + break; + } + if (IS_2413(ah)) { /* Griffin */ + AH_PRIVATE(ah)->ah_analog5GhzRev = + AR_RAD2413_SREV_MAJOR | 0x1; + break; + } + if (IS_5413(ah)) { /* Eagle */ + AH_PRIVATE(ah)->ah_analog5GhzRev = + AR_RAD5413_SREV_MAJOR | 0x2; + break; + } + if (IS_2425(ah) || IS_2417(ah)) {/* Swan or Nala */ + AH_PRIVATE(ah)->ah_analog5GhzRev = + AR_RAD5424_SREV_MAJOR | 0x2; + break; + } + } +#ifdef AH_DEBUG + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: 5G Radio Chip Rev 0x%02X is not supported by " + "this driver\n", + __func__, AH_PRIVATE(ah)->ah_analog5GhzRev); + ecode = HAL_ENOTSUPP; + goto bad; +#endif + } + if (IS_RAD5112_REV1(ah)) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: 5112 Rev 1 is not supported by this " + "driver (analog5GhzRev 0x%x)\n", __func__, + AH_PRIVATE(ah)->ah_analog5GhzRev); + ecode = HAL_ENOTSUPP; + goto bad; + } + + val = OS_REG_READ(ah, AR_PCICFG); + val = MS(val, AR_PCICFG_EEPROM_SIZE); + if (val == 0) { + if (!IS_PCIE(ah)) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: unsupported EEPROM size %u (0x%x) found\n", + __func__, val, val); + ecode = HAL_EESIZE; + goto bad; + } + /* XXX AH_PRIVATE(ah)->ah_isPciExpress = AH_TRUE; */ + } else if (val != AR_PCICFG_EEPROM_SIZE_16K) { + if (AR_PCICFG_EEPROM_SIZE_FAILED == val) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: unsupported EEPROM size %u (0x%x) found\n", + __func__, val, val); + ecode = HAL_EESIZE; + goto bad; + } + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: EEPROM size = %d. Must be %d (16k).\n", + __func__, val, AR_PCICFG_EEPROM_SIZE_16K); + ecode = HAL_EESIZE; + goto bad; + } + ecode = ath_hal_legacyEepromAttach(ah); + if (ecode != HAL_OK) { + goto bad; + } + ahp->ah_isHb63 = IS_2425(ah) && ath_hal_eepromGetFlag(ah, AR_EEP_ISTALON); + + /* + * If Bmode and AR5212, verify 2.4 analog exists + */ + if (ath_hal_eepromGetFlag(ah, AR_EEP_BMODE) && + (AH_PRIVATE(ah)->ah_analog5GhzRev & 0xF0) == AR_RAD5111_SREV_MAJOR) { + /* + * Set correct Baseband to analog shift + * setting to access analog chips. + */ + OS_REG_WRITE(ah, AR_PHY(0), 0x00004007); + OS_DELAY(2000); + AH_PRIVATE(ah)->ah_analog2GhzRev = ar5212GetRadioRev(ah); + + /* Set baseband for 5GHz chip */ + OS_REG_WRITE(ah, AR_PHY(0), 0x00000007); + OS_DELAY(2000); + if ((AH_PRIVATE(ah)->ah_analog2GhzRev & 0xF0) != AR_RAD2111_SREV_MAJOR) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: 2G Radio Chip Rev 0x%02X is not " + "supported by this driver\n", __func__, + AH_PRIVATE(ah)->ah_analog2GhzRev); + ecode = HAL_ENOTSUPP; + goto bad; + } + } + + ecode = ath_hal_eepromGet(ah, AR_EEP_REGDMN_0, &eeval); + if (ecode != HAL_OK) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: cannot read regulatory domain from EEPROM\n", + __func__); + goto bad; + } + AH_PRIVATE(ah)->ah_currentRD = eeval; + /* XXX record serial number */ + + /* + * Got everything we need now to setup the capabilities. + */ + if (!ar5212FillCapabilityInfo(ah)) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: failed ar5212FillCapabilityInfo\n", __func__); + ecode = HAL_EEREAD; + goto bad; + } + + if (!rf->attach(ah, &ecode)) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: RF setup failed, status %u\n", + __func__, ecode); + goto bad; + } + /* + * Set noise floor adjust method; we arrange a + * direct call instead of thunking. + */ + AH_PRIVATE(ah)->ah_getNfAdjust = ahp->ah_rfHal->getNfAdjust; + + /* Initialize gain ladder thermal calibration structure */ + ar5212InitializeGainValues(ah); + + ecode = ath_hal_eepromGet(ah, AR_EEP_MACADDR, ahp->ah_macaddr); + if (ecode != HAL_OK) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: error getting mac address from EEPROM\n", __func__); + goto bad; + } + + ar5212AniSetup(ah); + /* Setup of Radar/AR structures happens in ath_hal_initchannels*/ + ar5212InitNfCalHistBuffer(ah); + + /* XXX EAR stuff goes here */ + + HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s: return\n", __func__); + + return ah; + +bad: + if (ahp) + ar5212Detach((struct ath_hal *) ahp); + if (status) + *status = ecode; + return AH_NULL; +#undef AH_EEPROM_PROTECT +} + +void +ar5212Detach(struct ath_hal *ah) +{ + HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s:\n", __func__); + + HALASSERT(ah != AH_NULL); + HALASSERT(ah->ah_magic == AR5212_MAGIC); + + ar5212AniDetach(ah); + ar5212RfDetach(ah); + ar5212Disable(ah); + ar5212SetPowerMode(ah, HAL_PM_FULL_SLEEP, AH_TRUE); + + ath_hal_eepromDetach(ah); + ath_hal_free(ah); +} + +HAL_BOOL +ar5212ChipTest(struct ath_hal *ah) +{ + uint32_t regAddr[2] = { AR_STA_ID0, AR_PHY_BASE+(8 << 2) }; + uint32_t regHold[2]; + uint32_t patternData[4] = + { 0x55555555, 0xaaaaaaaa, 0x66666666, 0x99999999 }; + int i, j; + + /* Test PHY & MAC registers */ + for (i = 0; i < 2; i++) { + uint32_t addr = regAddr[i]; + uint32_t wrData, rdData; + + regHold[i] = OS_REG_READ(ah, addr); + for (j = 0; j < 0x100; j++) { + wrData = (j << 16) | j; + OS_REG_WRITE(ah, addr, wrData); + rdData = OS_REG_READ(ah, addr); + if (rdData != wrData) { + HALDEBUG(ah, HAL_DEBUG_ANY, +"%s: address test failed addr: 0x%08x - wr:0x%08x != rd:0x%08x\n", + __func__, addr, wrData, rdData); + return AH_FALSE; + } + } + for (j = 0; j < 4; j++) { + wrData = patternData[j]; + OS_REG_WRITE(ah, addr, wrData); + rdData = OS_REG_READ(ah, addr); + if (wrData != rdData) { + HALDEBUG(ah, HAL_DEBUG_ANY, +"%s: address test failed addr: 0x%08x - wr:0x%08x != rd:0x%08x\n", + __func__, addr, wrData, rdData); + return AH_FALSE; + } + } + OS_REG_WRITE(ah, regAddr[i], regHold[i]); + } + OS_DELAY(100); + return AH_TRUE; +} + +/* + * Store the channel edges for the requested operational mode + */ +HAL_BOOL +ar5212GetChannelEdges(struct ath_hal *ah, + uint16_t flags, uint16_t *low, uint16_t *high) +{ + if (flags & CHANNEL_5GHZ) { + *low = 4915; + *high = 6100; + return AH_TRUE; + } + if ((flags & CHANNEL_2GHZ) && + (ath_hal_eepromGetFlag(ah, AR_EEP_BMODE) || + ath_hal_eepromGetFlag(ah, AR_EEP_GMODE))) { + *low = 2312; + *high = 2732; + return AH_TRUE; + } + return AH_FALSE; +} + +/* + * Fill all software cached or static hardware state information. + * Return failure if capabilities are to come from EEPROM and + * cannot be read. + */ +HAL_BOOL +ar5212FillCapabilityInfo(struct ath_hal *ah) +{ +#define AR_KEYTABLE_SIZE 128 +#define IS_GRIFFIN_LITE(ah) \ + (AH_PRIVATE(ah)->ah_macVersion == AR_SREV_VERSION_GRIFFIN && \ + AH_PRIVATE(ah)->ah_macRev == AR_SREV_GRIFFIN_LITE) +#define IS_COBRA(ah) \ + (AH_PRIVATE(ah)->ah_macVersion == AR_SREV_VERSION_COBRA) +#define IS_2112(ah) \ + ((AH_PRIVATE(ah)->ah_analog5GhzRev & 0xF0) == AR_RAD2112_SREV_MAJOR) + + struct ath_hal_private *ahpriv = AH_PRIVATE(ah); + HAL_CAPABILITIES *pCap = &ahpriv->ah_caps; + uint16_t capField, val; + + /* Read the capability EEPROM location */ + if (ath_hal_eepromGet(ah, AR_EEP_OPCAP, &capField) != HAL_OK) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: unable to read caps from eeprom\n", __func__); + return AH_FALSE; + } + if (IS_2112(ah)) + ath_hal_eepromSet(ah, AR_EEP_AMODE, AH_FALSE); + if (capField == 0 && IS_GRIFFIN_LITE(ah)) { + /* + * For griffin-lite cards with unprogrammed capabilities. + */ + ath_hal_eepromSet(ah, AR_EEP_COMPRESS, AH_FALSE); + ath_hal_eepromSet(ah, AR_EEP_FASTFRAME, AH_FALSE); + ath_hal_eepromSet(ah, AR_EEP_TURBO5DISABLE, AH_TRUE); + ath_hal_eepromSet(ah, AR_EEP_TURBO2DISABLE, AH_TRUE); + HALDEBUG(ah, HAL_DEBUG_ATTACH, + "%s: override caps for griffin-lite, now 0x%x (+!turbo)\n", + __func__, capField); + } + + /* Modify reg domain on newer cards that need to work with older sw */ + if (ahpriv->ah_opmode != HAL_M_HOSTAP && + ahpriv->ah_subvendorid == AR_SUBVENDOR_ID_NEW_A) { + if (ahpriv->ah_currentRD == 0x64 || + ahpriv->ah_currentRD == 0x65) + ahpriv->ah_currentRD += 5; + else if (ahpriv->ah_currentRD == 0x41) + ahpriv->ah_currentRD = 0x43; + HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s: regdomain mapped to 0x%x\n", + __func__, ahpriv->ah_currentRD); + } + + if (AH_PRIVATE(ah)->ah_macVersion == AR_SREV_2417 || + AH_PRIVATE(ah)->ah_macVersion == AR_SREV_2425) { + HALDEBUG(ah, HAL_DEBUG_ATTACH, + "%s: enable Bmode and disable turbo for Swan/Nala\n", + __func__); + ath_hal_eepromSet(ah, AR_EEP_BMODE, AH_TRUE); + ath_hal_eepromSet(ah, AR_EEP_COMPRESS, AH_FALSE); + ath_hal_eepromSet(ah, AR_EEP_FASTFRAME, AH_FALSE); + ath_hal_eepromSet(ah, AR_EEP_TURBO5DISABLE, AH_TRUE); + ath_hal_eepromSet(ah, AR_EEP_TURBO2DISABLE, AH_TRUE); + } + + /* Construct wireless mode from EEPROM */ + pCap->halWirelessModes = 0; + if (ath_hal_eepromGetFlag(ah, AR_EEP_AMODE)) { + pCap->halWirelessModes |= HAL_MODE_11A; + if (!ath_hal_eepromGetFlag(ah, AR_EEP_TURBO5DISABLE)) + pCap->halWirelessModes |= HAL_MODE_TURBO; + } + if (ath_hal_eepromGetFlag(ah, AR_EEP_BMODE)) + pCap->halWirelessModes |= HAL_MODE_11B; + if (ath_hal_eepromGetFlag(ah, AR_EEP_GMODE) && + ahpriv->ah_subvendorid != AR_SUBVENDOR_ID_NOG) { + pCap->halWirelessModes |= HAL_MODE_11G; + if (!ath_hal_eepromGetFlag(ah, AR_EEP_TURBO2DISABLE)) + pCap->halWirelessModes |= HAL_MODE_108G; + } + + pCap->halLow2GhzChan = 2312; + /* XXX 2417 too? */ + if (IS_RAD5112_ANY(ah) || IS_5413(ah) || IS_2425(ah) || IS_2417(ah)) + pCap->halHigh2GhzChan = 2500; + else + pCap->halHigh2GhzChan = 2732; + + pCap->halLow5GhzChan = 4915; + pCap->halHigh5GhzChan = 6100; + + pCap->halCipherCkipSupport = AH_FALSE; + pCap->halCipherTkipSupport = AH_TRUE; + pCap->halCipherAesCcmSupport = + (ath_hal_eepromGetFlag(ah, AR_EEP_AES) && + ((AH_PRIVATE(ah)->ah_macVersion > AR_SREV_VERSION_VENICE) || + ((AH_PRIVATE(ah)->ah_macVersion == AR_SREV_VERSION_VENICE) && + (AH_PRIVATE(ah)->ah_macRev >= AR_SREV_VERSION_OAHU)))); + + pCap->halMicCkipSupport = AH_FALSE; + pCap->halMicTkipSupport = AH_TRUE; + pCap->halMicAesCcmSupport = ath_hal_eepromGetFlag(ah, AR_EEP_AES); + /* + * Starting with Griffin TX+RX mic keys can be combined + * in one key cache slot. + */ + if (AH_PRIVATE(ah)->ah_macVersion >= AR_SREV_VERSION_GRIFFIN) + pCap->halTkipMicTxRxKeySupport = AH_TRUE; + else + pCap->halTkipMicTxRxKeySupport = AH_FALSE; + pCap->halChanSpreadSupport = AH_TRUE; + pCap->halSleepAfterBeaconBroken = AH_TRUE; + + if (ahpriv->ah_macRev > 1 || IS_COBRA(ah)) { + pCap->halCompressSupport = + ath_hal_eepromGetFlag(ah, AR_EEP_COMPRESS) && + (pCap->halWirelessModes & (HAL_MODE_11A|HAL_MODE_11G)) != 0; + pCap->halBurstSupport = ath_hal_eepromGetFlag(ah, AR_EEP_BURST); + pCap->halFastFramesSupport = + ath_hal_eepromGetFlag(ah, AR_EEP_FASTFRAME) && + (pCap->halWirelessModes & (HAL_MODE_11A|HAL_MODE_11G)) != 0; + pCap->halChapTuningSupport = AH_TRUE; + pCap->halTurboPrimeSupport = AH_TRUE; + } + pCap->halTurboGSupport = pCap->halWirelessModes & HAL_MODE_108G; + + pCap->halPSPollBroken = AH_TRUE; /* XXX fixed in later revs? */ + pCap->halVEOLSupport = AH_TRUE; + pCap->halBssIdMaskSupport = AH_TRUE; + pCap->halMcastKeySrchSupport = AH_TRUE; + if ((ahpriv->ah_macVersion == AR_SREV_VERSION_VENICE && + ahpriv->ah_macRev == 8) || + ahpriv->ah_macVersion > AR_SREV_VERSION_VENICE) + pCap->halTsfAddSupport = AH_TRUE; + + if (ath_hal_eepromGet(ah, AR_EEP_MAXQCU, &val) == HAL_OK) + pCap->halTotalQueues = val; + else + pCap->halTotalQueues = HAL_NUM_TX_QUEUES; + + if (ath_hal_eepromGet(ah, AR_EEP_KCENTRIES, &val) == HAL_OK) + pCap->halKeyCacheSize = val; + else + pCap->halKeyCacheSize = AR_KEYTABLE_SIZE; + + pCap->halChanHalfRate = AH_TRUE; + pCap->halChanQuarterRate = AH_TRUE; + + if (ath_hal_eepromGetFlag(ah, AR_EEP_RFKILL) && + ath_hal_eepromGet(ah, AR_EEP_RFSILENT, &ahpriv->ah_rfsilent) == HAL_OK) { + /* NB: enabled by default */ + ahpriv->ah_rfkillEnabled = AH_TRUE; + pCap->halRfSilentSupport = AH_TRUE; + } + + /* NB: this is a guess, noone seems to know the answer */ + ahpriv->ah_rxornIsFatal = + (AH_PRIVATE(ah)->ah_macVersion < AR_SREV_VERSION_VENICE); + + /* h/w phy counters first appeared in Hainan */ + pCap->halHwPhyCounterSupport = + (AH_PRIVATE(ah)->ah_macVersion == AR_SREV_VERSION_VENICE && + AH_PRIVATE(ah)->ah_macRev == AR_SREV_HAINAN) || + AH_PRIVATE(ah)->ah_macVersion > AR_SREV_VERSION_VENICE; + + pCap->halTstampPrecision = 15; + + return AH_TRUE; +#undef IS_COBRA +#undef IS_GRIFFIN_LITE +#undef AR_KEYTABLE_SIZE +} + +static const char* +ar5212Probe(uint16_t vendorid, uint16_t devid) +{ + if (vendorid == ATHEROS_VENDOR_ID || + vendorid == ATHEROS_3COM_VENDOR_ID || + vendorid == ATHEROS_3COM2_VENDOR_ID) { + switch (devid) { + case AR5212_FPGA: + return "Atheros 5212 (FPGA)"; + case AR5212_DEVID: + case AR5212_DEVID_IBM: + case AR5212_DEFAULT: + return "Atheros 5212"; + case AR5212_AR2413: + return "Atheros 2413"; + case AR5212_AR2417: + return "Atheros 2417"; + case AR5212_AR5413: + return "Atheros 5413"; + case AR5212_AR5424: + return "Atheros 5424/2424"; + } + } + return AH_NULL; +} +AH_CHIP(AR5212, ar5212Probe, ar5212Attach); --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5212/ar5212_beacon.c 2009-03-23 17:36:55.000000000 +0000 @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2008 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ar5212_beacon.c,v 1.1 2009/03/23 17:14:47 sborrill Exp $ + */ +#include "opt_ah.h" + +#include "ah.h" +#include "ah_internal.h" + +#include "ar5212/ar5212.h" +#include "ar5212/ar5212reg.h" +#include "ar5212/ar5212desc.h" + +/* + * Initialize all of the hardware registers used to + * send beacons. Note that for station operation the + * driver calls ar5212SetStaBeaconTimers instead. + */ +void +ar5212SetBeaconTimers(struct ath_hal *ah, const HAL_BEACON_TIMERS *bt) +{ + + OS_REG_WRITE(ah, AR_TIMER0, bt->bt_nexttbtt); + OS_REG_WRITE(ah, AR_TIMER1, bt->bt_nextdba); + OS_REG_WRITE(ah, AR_TIMER2, bt->bt_nextswba); + OS_REG_WRITE(ah, AR_TIMER3, bt->bt_nextatim); + /* + * Set the Beacon register after setting all timers. + */ + if (bt->bt_intval & AR_BEACON_RESET_TSF) { + /* + * When resetting the TSF, + * write twice to the corresponding register; each + * write to the RESET_TSF bit toggles the internal + * signal to cause a reset of the TSF - but if the signal + * is left high, it will reset the TSF on the next + * chip reset also! writing the bit an even number + * of times fixes this issue + */ + OS_REG_WRITE(ah, AR_BEACON, AR_BEACON_RESET_TSF); + } + OS_REG_WRITE(ah, AR_BEACON, bt->bt_intval); +} + +/* + * Old api for setting up beacon timer registers when + * operating in !station mode. Note the fixed constants + * adjusting the DBA and SWBA timers and the fixed ATIM + * window. + */ +void +ar5212BeaconInit(struct ath_hal *ah, + uint32_t next_beacon, uint32_t beacon_period) +{ + HAL_BEACON_TIMERS bt; + + bt.bt_nexttbtt = next_beacon; + /* + * TIMER1: in AP/adhoc mode this controls the DMA beacon + * alert timer; otherwise it controls the next wakeup time. + * TIMER2: in AP mode, it controls the SBA beacon alert + * interrupt; otherwise it sets the start of the next CFP. + */ + switch (AH_PRIVATE(ah)->ah_opmode) { + case HAL_M_STA: + case HAL_M_MONITOR: + bt.bt_nextdba = 0xffff; + bt.bt_nextswba = 0x7ffff; + break; + case HAL_M_HOSTAP: + case HAL_M_IBSS: + bt.bt_nextdba = (next_beacon - + ath_hal_dma_beacon_response_time) << 3; /* 1/8 TU */ + bt.bt_nextswba = (next_beacon - + ath_hal_sw_beacon_response_time) << 3; /* 1/8 TU */ + break; + } + /* + * Set the ATIM window + * Our hardware does not support an ATIM window of 0 + * (beacons will not work). If the ATIM windows is 0, + * force it to 1. + */ + bt.bt_nextatim = next_beacon + 1; + bt.bt_intval = beacon_period & + (AR_BEACON_PERIOD | AR_BEACON_RESET_TSF | AR_BEACON_EN); + ar5212SetBeaconTimers(ah, &bt); +} + +void +ar5212ResetStaBeaconTimers(struct ath_hal *ah) +{ + uint32_t val; + + OS_REG_WRITE(ah, AR_TIMER0, 0); /* no beacons */ + val = OS_REG_READ(ah, AR_STA_ID1); + val |= AR_STA_ID1_PWR_SAV; /* XXX */ + /* tell the h/w that the associated AP is not PCF capable */ + OS_REG_WRITE(ah, AR_STA_ID1, + val & ~(AR_STA_ID1_USE_DEFANT | AR_STA_ID1_PCF)); + OS_REG_WRITE(ah, AR_BEACON, AR_BEACON_PERIOD); +} + +/* + * Set all the beacon related bits on the h/w for stations + * i.e. initializes the corresponding h/w timers; + * also tells the h/w whether to anticipate PCF beacons + */ +void +ar5212SetStaBeaconTimers(struct ath_hal *ah, const HAL_BEACON_STATE *bs) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + uint32_t nextTbtt, nextdtim,beaconintval, dtimperiod; + + HALASSERT(bs->bs_intval != 0); + /* if the AP will do PCF */ + if (bs->bs_cfpmaxduration != 0) { + /* tell the h/w that the associated AP is PCF capable */ + OS_REG_WRITE(ah, AR_STA_ID1, + OS_REG_READ(ah, AR_STA_ID1) | AR_STA_ID1_PCF); + + /* set CFP_PERIOD(1.024ms) register */ + OS_REG_WRITE(ah, AR_CFP_PERIOD, bs->bs_cfpperiod); + + /* set CFP_DUR(1.024ms) register to max cfp duration */ + OS_REG_WRITE(ah, AR_CFP_DUR, bs->bs_cfpmaxduration); + + /* set TIMER2(128us) to anticipated time of next CFP */ + OS_REG_WRITE(ah, AR_TIMER2, bs->bs_cfpnext << 3); + } else { + /* tell the h/w that the associated AP is not PCF capable */ + OS_REG_WRITE(ah, AR_STA_ID1, + OS_REG_READ(ah, AR_STA_ID1) &~ AR_STA_ID1_PCF); + } + + /* + * Set TIMER0(1.024ms) to the anticipated time of the next beacon. + */ + OS_REG_WRITE(ah, AR_TIMER0, bs->bs_nexttbtt); + + /* + * Start the beacon timers by setting the BEACON register + * to the beacon interval; also write the tim offset which + * we should know by now. The code, in ar5211WriteAssocid, + * also sets the tim offset once the AID is known which can + * be left as such for now. + */ + OS_REG_WRITE(ah, AR_BEACON, + (OS_REG_READ(ah, AR_BEACON) &~ (AR_BEACON_PERIOD|AR_BEACON_TIM)) + | SM(bs->bs_intval, AR_BEACON_PERIOD) + | SM(bs->bs_timoffset ? bs->bs_timoffset + 4 : 0, AR_BEACON_TIM) + ); + + /* + * Configure the BMISS interrupt. Note that we + * assume the caller blocks interrupts while enabling + * the threshold. + */ + HALASSERT(bs->bs_bmissthreshold <= MS(0xffffffff, AR_RSSI_THR_BM_THR)); + ahp->ah_rssiThr = (ahp->ah_rssiThr &~ AR_RSSI_THR_BM_THR) + | SM(bs->bs_bmissthreshold, AR_RSSI_THR_BM_THR); + OS_REG_WRITE(ah, AR_RSSI_THR, ahp->ah_rssiThr); + + /* + * Program the sleep registers to correlate with the beacon setup. + */ + + /* + * Oahu beacons timers on the station were used for power + * save operation (waking up in anticipation of a beacon) + * and any CFP function; Venice does sleep/power-save timers + * differently - so this is the right place to set them up; + * don't think the beacon timers are used by venice sta hw + * for any useful purpose anymore + * Setup venice's sleep related timers + * Current implementation assumes sw processing of beacons - + * assuming an interrupt is generated every beacon which + * causes the hardware to become awake until the sw tells + * it to go to sleep again; beacon timeout is to allow for + * beacon jitter; cab timeout is max time to wait for cab + * after seeing the last DTIM or MORE CAB bit + */ +#define CAB_TIMEOUT_VAL 10 /* in TU */ +#define BEACON_TIMEOUT_VAL 10 /* in TU */ +#define SLEEP_SLOP 3 /* in TU */ + + /* + * For max powersave mode we may want to sleep for longer than a + * beacon period and not want to receive all beacons; modify the + * timers accordingly; make sure to align the next TIM to the + * next DTIM if we decide to wake for DTIMs only + */ + beaconintval = bs->bs_intval & HAL_BEACON_PERIOD; + HALASSERT(beaconintval != 0); + if (bs->bs_sleepduration > beaconintval) { + HALASSERT(roundup(bs->bs_sleepduration, beaconintval) == + bs->bs_sleepduration); + beaconintval = bs->bs_sleepduration; + } + dtimperiod = bs->bs_dtimperiod; + if (bs->bs_sleepduration > dtimperiod) { + HALASSERT(dtimperiod == 0 || + roundup(bs->bs_sleepduration, dtimperiod) == + bs->bs_sleepduration); + dtimperiod = bs->bs_sleepduration; + } + HALASSERT(beaconintval <= dtimperiod); + if (beaconintval == dtimperiod) + nextTbtt = bs->bs_nextdtim; + else + nextTbtt = bs->bs_nexttbtt; + nextdtim = bs->bs_nextdtim; + + OS_REG_WRITE(ah, AR_SLEEP1, + SM((nextdtim - SLEEP_SLOP) << 3, AR_SLEEP1_NEXT_DTIM) + | SM(CAB_TIMEOUT_VAL, AR_SLEEP1_CAB_TIMEOUT) + | AR_SLEEP1_ASSUME_DTIM + | AR_SLEEP1_ENH_SLEEP_ENA + ); + OS_REG_WRITE(ah, AR_SLEEP2, + SM((nextTbtt - SLEEP_SLOP) << 3, AR_SLEEP2_NEXT_TIM) + | SM(BEACON_TIMEOUT_VAL, AR_SLEEP2_BEACON_TIMEOUT) + ); + OS_REG_WRITE(ah, AR_SLEEP3, + SM(beaconintval, AR_SLEEP3_TIM_PERIOD) + | SM(dtimperiod, AR_SLEEP3_DTIM_PERIOD) + ); + HALDEBUG(ah, HAL_DEBUG_BEACON, "%s: next DTIM %d\n", + __func__, bs->bs_nextdtim); + HALDEBUG(ah, HAL_DEBUG_BEACON, "%s: next beacon %d\n", + __func__, nextTbtt); + HALDEBUG(ah, HAL_DEBUG_BEACON, "%s: beacon period %d\n", + __func__, beaconintval); + HALDEBUG(ah, HAL_DEBUG_BEACON, "%s: DTIM period %d\n", + __func__, dtimperiod); +#undef CAB_TIMEOUT_VAL +#undef BEACON_TIMEOUT_VAL +#undef SLEEP_SLOP +} --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5212/ar5212_eeprom.c 2009-03-23 17:36:55.000000000 +0000 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2008 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ar5212_eeprom.c,v 1.1 2009/03/23 17:14:47 sborrill Exp $ + */ +#include "opt_ah.h" + +#include "ah.h" +#include "ah_internal.h" +#include "ah_devid.h" +#ifdef AH_DEBUG +#include "ah_desc.h" /* NB: for HAL_PHYERR* */ +#endif + +#include "ar5212/ar5212.h" +#include "ar5212/ar5212reg.h" +#include "ar5212/ar5212phy.h" + +/* + * Read 16 bits of data from offset into *data + */ +HAL_BOOL +ar5212EepromRead(struct ath_hal *ah, u_int off, uint16_t *data) +{ + OS_REG_WRITE(ah, AR_EEPROM_ADDR, off); + OS_REG_WRITE(ah, AR_EEPROM_CMD, AR_EEPROM_CMD_READ); + + if (!ath_hal_wait(ah, AR_EEPROM_STS, + AR_EEPROM_STS_READ_COMPLETE | AR_EEPROM_STS_READ_ERROR, + AR_EEPROM_STS_READ_COMPLETE)) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: read failed for entry 0x%x\n", + __func__, off); + return AH_FALSE; + } + *data = OS_REG_READ(ah, AR_EEPROM_DATA) & 0xffff; + return AH_TRUE; +} --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5212/ar5212_gpio.c 2009-03-23 17:36:55.000000000 +0000 @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2008 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ar5212_gpio.c,v 1.1 2009/03/23 17:14:48 sborrill Exp $ + */ +#include "opt_ah.h" + +#include "ah.h" +#include "ah_internal.h" +#include "ah_devid.h" +#ifdef AH_DEBUG +#include "ah_desc.h" /* NB: for HAL_PHYERR* */ +#endif + +#include "ar5212/ar5212.h" +#include "ar5212/ar5212reg.h" +#include "ar5212/ar5212phy.h" + +#define AR_NUM_GPIO 6 /* 6 GPIO pins */ +#define AR_GPIOD_MASK 0x0000002F /* GPIO data reg r/w mask */ + +/* + * Configure GPIO Output lines + */ +HAL_BOOL +ar5212GpioCfgOutput(struct ath_hal *ah, uint32_t gpio) +{ + HALASSERT(gpio < AR_NUM_GPIO); + + /* + * NB: AR_GPIOCR_CR_A(pin) is all 1's so there's no need + * to clear the field before or'ing in the new value. + */ + OS_REG_WRITE(ah, AR_GPIOCR, + OS_REG_READ(ah, AR_GPIOCR) | AR_GPIOCR_CR_A(gpio)); + + return AH_TRUE; +} + +/* + * Configure GPIO Input lines + */ +HAL_BOOL +ar5212GpioCfgInput(struct ath_hal *ah, uint32_t gpio) +{ + HALASSERT(gpio < AR_NUM_GPIO); + + OS_REG_WRITE(ah, AR_GPIOCR, + (OS_REG_READ(ah, AR_GPIOCR) &~ AR_GPIOCR_CR_A(gpio)) + | AR_GPIOCR_CR_N(gpio)); + + return AH_TRUE; +} + +/* + * Once configured for I/O - set output lines + */ +HAL_BOOL +ar5212GpioSet(struct ath_hal *ah, uint32_t gpio, uint32_t val) +{ + uint32_t reg; + + HALASSERT(gpio < AR_NUM_GPIO); + + reg = OS_REG_READ(ah, AR_GPIODO); + reg &= ~(1 << gpio); + reg |= (val&1) << gpio; + + OS_REG_WRITE(ah, AR_GPIODO, reg); + return AH_TRUE; +} + +/* + * Once configured for I/O - get input lines + */ +uint32_t +ar5212GpioGet(struct ath_hal *ah, uint32_t gpio) +{ + if (gpio < AR_NUM_GPIO) { + uint32_t val = OS_REG_READ(ah, AR_GPIODI); + val = ((val & AR_GPIOD_MASK) >> gpio) & 0x1; + return val; + } else { + return 0xffffffff; + } +} + +/* + * Set the GPIO Interrupt + */ +void +ar5212GpioSetIntr(struct ath_hal *ah, u_int gpio, uint32_t ilevel) +{ + uint32_t val; + + /* XXX bounds check gpio */ + val = OS_REG_READ(ah, AR_GPIOCR); + val &= ~(AR_GPIOCR_CR_A(gpio) | + AR_GPIOCR_INT_MASK | AR_GPIOCR_INT_ENA | AR_GPIOCR_INT_SEL); + val |= AR_GPIOCR_CR_N(gpio) | AR_GPIOCR_INT(gpio) | AR_GPIOCR_INT_ENA; + if (ilevel) + val |= AR_GPIOCR_INT_SELH; /* interrupt on pin high */ + else + val |= AR_GPIOCR_INT_SELL; /* interrupt on pin low */ + + /* Don't need to change anything for low level interrupt. */ + OS_REG_WRITE(ah, AR_GPIOCR, val); + + /* Change the interrupt mask. */ + (void) ar5212SetInterrupts(ah, AH5212(ah)->ah_maskReg | HAL_INT_GPIO); +} --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5212/ar5212_interrupts.c 2009-03-23 17:36:55.000000000 +0000 @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2008 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ar5212_interrupts.c,v 1.1 2009/03/23 17:14:48 sborrill Exp $ + */ +#include "opt_ah.h" + +#include "ah.h" +#include "ah_internal.h" + +#include "ar5212/ar5212.h" +#include "ar5212/ar5212reg.h" +#include "ar5212/ar5212phy.h" + + +/* + * Checks to see if an interrupt is pending on our NIC + * + * Returns: TRUE if an interrupt is pending + * FALSE if not + */ +HAL_BOOL +ar5212IsInterruptPending(struct ath_hal *ah) +{ + /* + * Some platforms trigger our ISR before applying power to + * the card, so make sure the INTPEND is really 1, not 0xffffffff. + */ + return (OS_REG_READ(ah, AR_INTPEND) == AR_INTPEND_TRUE); +} + +/* + * Reads the Interrupt Status Register value from the NIC, thus deasserting + * the interrupt line, and returns both the masked and unmasked mapped ISR + * values. The value returned is mapped to abstract the hw-specific bit + * locations in the Interrupt Status Register. + * + * Returns: A hardware-abstracted bitmap of all non-masked-out + * interrupts pending, as well as an unmasked value + */ +HAL_BOOL +ar5212GetPendingInterrupts(struct ath_hal *ah, HAL_INT *masked) +{ + uint32_t isr, isr0, isr1; + uint32_t mask2=0; + struct ath_hal_5212 *ahp = AH5212(ah); + + isr = OS_REG_READ(ah, AR_ISR); + if (isr & AR_ISR_BCNMISC) { + uint32_t isr2; + isr2 = OS_REG_READ(ah, AR_ISR_S2); + if (isr2 & AR_ISR_S2_TIM) + mask2 |= HAL_INT_TIM; + if (isr2 & AR_ISR_S2_DTIM) + mask2 |= HAL_INT_DTIM; + if (isr2 & AR_ISR_S2_DTIMSYNC) + mask2 |= HAL_INT_DTIMSYNC; + if (isr2 & (AR_ISR_S2_CABEND )) + mask2 |= HAL_INT_CABEND; + } + isr = OS_REG_READ(ah, AR_ISR_RAC); + if (isr == 0xffffffff) { + *masked = 0; + return AH_FALSE;; + } + + *masked = isr & HAL_INT_COMMON; + + if (isr & AR_ISR_HIUERR) + *masked |= HAL_INT_FATAL; + if (isr & (AR_ISR_RXOK | AR_ISR_RXERR)) + *masked |= HAL_INT_RX; + if (isr & (AR_ISR_TXOK | AR_ISR_TXDESC | AR_ISR_TXERR | AR_ISR_TXEOL)) { + *masked |= HAL_INT_TX; + isr0 = OS_REG_READ(ah, AR_ISR_S0_S); + ahp->ah_intrTxqs |= MS(isr0, AR_ISR_S0_QCU_TXOK); + ahp->ah_intrTxqs |= MS(isr0, AR_ISR_S0_QCU_TXDESC); + isr1 = OS_REG_READ(ah, AR_ISR_S1_S); + ahp->ah_intrTxqs |= MS(isr1, AR_ISR_S1_QCU_TXERR); + ahp->ah_intrTxqs |= MS(isr1, AR_ISR_S1_QCU_TXEOL); + } + + /* + * Receive overrun is usually non-fatal on Oahu/Spirit. + * BUT on some parts rx could fail and the chip must be reset. + * So we force a hardware reset in all cases. + */ + if ((isr & AR_ISR_RXORN) && AH_PRIVATE(ah)->ah_rxornIsFatal) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: receive FIFO overrun interrupt\n", __func__); + *masked |= HAL_INT_FATAL; + } + *masked |= mask2; + + /* + * On fatal errors collect ISR state for debugging. + */ + if (*masked & HAL_INT_FATAL) { + AH_PRIVATE(ah)->ah_fatalState[0] = isr; + AH_PRIVATE(ah)->ah_fatalState[1] = OS_REG_READ(ah, AR_ISR_S0_S); + AH_PRIVATE(ah)->ah_fatalState[2] = OS_REG_READ(ah, AR_ISR_S1_S); + AH_PRIVATE(ah)->ah_fatalState[3] = OS_REG_READ(ah, AR_ISR_S2_S); + AH_PRIVATE(ah)->ah_fatalState[4] = OS_REG_READ(ah, AR_ISR_S3_S); + AH_PRIVATE(ah)->ah_fatalState[5] = OS_REG_READ(ah, AR_ISR_S4_S); + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: fatal error, ISR_RAC=0x%x ISR_S2_S=0x%x\n", + __func__, isr, AH_PRIVATE(ah)->ah_fatalState[3]); + } + return AH_TRUE; +} + +HAL_INT +ar5212GetInterrupts(struct ath_hal *ah) +{ + return AH5212(ah)->ah_maskReg; +} + +/* + * Atomically enables NIC interrupts. Interrupts are passed in + * via the enumerated bitmask in ints. + */ +HAL_INT +ar5212SetInterrupts(struct ath_hal *ah, HAL_INT ints) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + uint32_t omask = ahp->ah_maskReg; + uint32_t mask,mask2; + + HALDEBUG(ah, HAL_DEBUG_INTERRUPT, "%s: 0x%x => 0x%x\n", + __func__, omask, ints); + + if (omask & HAL_INT_GLOBAL) { + HALDEBUG(ah, HAL_DEBUG_INTERRUPT, "%s: disable IER\n", __func__); + OS_REG_WRITE(ah, AR_IER, AR_IER_DISABLE); + (void) OS_REG_READ(ah, AR_IER); /* flush write to HW */ + } + + mask = ints & HAL_INT_COMMON; + mask2 = 0; + if (ints & HAL_INT_TX) { + if (ahp->ah_txOkInterruptMask) + mask |= AR_IMR_TXOK; + if (ahp->ah_txErrInterruptMask) + mask |= AR_IMR_TXERR; + if (ahp->ah_txDescInterruptMask) + mask |= AR_IMR_TXDESC; + if (ahp->ah_txEolInterruptMask) + mask |= AR_IMR_TXEOL; + } + if (ints & HAL_INT_RX) + mask |= AR_IMR_RXOK | AR_IMR_RXERR | AR_IMR_RXDESC; + if (ints & (HAL_INT_BMISC)) { + mask |= AR_IMR_BCNMISC; + if (ints & HAL_INT_TIM) + mask2 |= AR_IMR_S2_TIM; + if (ints & HAL_INT_DTIM) + mask2 |= AR_IMR_S2_DTIM; + if (ints & HAL_INT_DTIMSYNC) + mask2 |= AR_IMR_S2_DTIMSYNC; + if (ints & HAL_INT_CABEND) + mask2 |= (AR_IMR_S2_CABEND ); + } + if (ints & HAL_INT_FATAL) { + /* + * NB: ar5212Reset sets MCABT+SSERR+DPERR in AR_IMR_S2 + * so enabling HIUERR enables delivery. + */ + mask |= AR_IMR_HIUERR; + } + + /* Write the new IMR and store off our SW copy. */ + HALDEBUG(ah, HAL_DEBUG_INTERRUPT, "%s: new IMR 0x%x\n", __func__, mask); + OS_REG_WRITE(ah, AR_IMR, mask); + OS_REG_WRITE(ah, AR_IMR_S2, + (OS_REG_READ(ah, AR_IMR_S2) & + ~(AR_IMR_S2_TIM | + AR_IMR_S2_DTIM | + AR_IMR_S2_DTIMSYNC | + AR_IMR_S2_CABEND | + AR_IMR_S2_CABTO | + AR_IMR_S2_TSFOOR ) ) + | mask2); + ahp->ah_maskReg = ints; + + /* Re-enable interrupts if they were enabled before. */ + if (ints & HAL_INT_GLOBAL) { + HALDEBUG(ah, HAL_DEBUG_INTERRUPT, "%s: enable IER\n", __func__); + OS_REG_WRITE(ah, AR_IER, AR_IER_ENABLE); + } + + + return omask; +} --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5212/ar5212_keycache.c 2009-03-23 17:36:55.000000000 +0000 @@ -0,0 +1,285 @@ +/* + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2008 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ar5212_keycache.c,v 1.1 2009/03/23 17:14:48 sborrill Exp $ + */ +#include "opt_ah.h" + +#include "ah.h" +#include "ah_internal.h" + +#include "ar5212/ar5212.h" +#include "ar5212/ar5212reg.h" +#include "ar5212/ar5212desc.h" + +/* + * Note: The key cache hardware requires that each double-word + * pair be written in even/odd order (since the destination is + * a 64-bit register). Don't reorder the writes in this code + * w/o considering this! + */ +#define KEY_XOR 0xaa + +#define IS_MIC_ENABLED(ah) \ + (AH5212(ah)->ah_staId1Defaults & AR_STA_ID1_CRPT_MIC_ENABLE) + +/* + * Return the size of the hardware key cache. + */ +uint32_t +ar5212GetKeyCacheSize(struct ath_hal *ah) +{ + return AH_PRIVATE(ah)->ah_caps.halKeyCacheSize; +} + +/* + * Return true if the specific key cache entry is valid. + */ +HAL_BOOL +ar5212IsKeyCacheEntryValid(struct ath_hal *ah, uint16_t entry) +{ + if (entry < AH_PRIVATE(ah)->ah_caps.halKeyCacheSize) { + uint32_t val = OS_REG_READ(ah, AR_KEYTABLE_MAC1(entry)); + if (val & AR_KEYTABLE_VALID) + return AH_TRUE; + } + return AH_FALSE; +} + +/* + * Clear the specified key cache entry and any associated MIC entry. + */ +HAL_BOOL +ar5212ResetKeyCacheEntry(struct ath_hal *ah, uint16_t entry) +{ + uint32_t keyType; + + if (entry >= AH_PRIVATE(ah)->ah_caps.halKeyCacheSize) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: entry %u out of range\n", + __func__, entry); + return AH_FALSE; + } + keyType = OS_REG_READ(ah, AR_KEYTABLE_TYPE(entry)); + + /* XXX why not clear key type/valid bit first? */ + OS_REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), 0); + OS_REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), 0); + OS_REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), 0); + OS_REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), 0); + OS_REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), 0); + OS_REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), AR_KEYTABLE_TYPE_CLR); + OS_REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), 0); + OS_REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), 0); + if (keyType == AR_KEYTABLE_TYPE_TKIP && IS_MIC_ENABLED(ah)) { + uint16_t micentry = entry+64; /* MIC goes at slot+64 */ + + HALASSERT(micentry < AH_PRIVATE(ah)->ah_caps.halKeyCacheSize); + OS_REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), 0); + OS_REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0); + OS_REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), 0); + OS_REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), 0); + /* NB: key type and MAC are known to be ok */ + } + return AH_TRUE; +} + +/* + * Sets the mac part of the specified key cache entry (and any + * associated MIC entry) and mark them valid. + */ +HAL_BOOL +ar5212SetKeyCacheEntryMac(struct ath_hal *ah, uint16_t entry, const uint8_t *mac) +{ + uint32_t macHi, macLo; + + if (entry >= AH_PRIVATE(ah)->ah_caps.halKeyCacheSize) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: entry %u out of range\n", + __func__, entry); + return AH_FALSE; + } + /* + * Set MAC address -- shifted right by 1. MacLo is + * the 4 MSBs, and MacHi is the 2 LSBs. + */ + if (mac != AH_NULL) { + macHi = (mac[5] << 8) | mac[4]; + macLo = (mac[3] << 24)| (mac[2] << 16) + | (mac[1] << 8) | mac[0]; + macLo >>= 1; + macLo |= (macHi & 1) << 31; /* carry */ + macHi >>= 1; + } else { + macLo = macHi = 0; + } + OS_REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), macLo); + OS_REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), macHi | AR_KEYTABLE_VALID); + return AH_TRUE; +} + +/* + * Sets the contents of the specified key cache entry + * and any associated MIC entry. + */ +HAL_BOOL +ar5212SetKeyCacheEntry(struct ath_hal *ah, uint16_t entry, + const HAL_KEYVAL *k, const uint8_t *mac, + int xorKey) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + const HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps; + uint32_t key0, key1, key2, key3, key4; + uint32_t keyType; + uint32_t xorMask = xorKey ? + (KEY_XOR << 24 | KEY_XOR << 16 | KEY_XOR << 8 | KEY_XOR) : 0; + + if (entry >= pCap->halKeyCacheSize) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: entry %u out of range\n", + __func__, entry); + return AH_FALSE; + } + switch (k->kv_type) { + case HAL_CIPHER_AES_OCB: + keyType = AR_KEYTABLE_TYPE_AES; + break; + case HAL_CIPHER_AES_CCM: + if (!pCap->halCipherAesCcmSupport) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: AES-CCM not supported by mac rev 0x%x\n", + __func__, AH_PRIVATE(ah)->ah_macRev); + return AH_FALSE; + } + keyType = AR_KEYTABLE_TYPE_CCM; + break; + case HAL_CIPHER_TKIP: + keyType = AR_KEYTABLE_TYPE_TKIP; + if (IS_MIC_ENABLED(ah) && entry+64 >= pCap->halKeyCacheSize) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: entry %u inappropriate for TKIP\n", + __func__, entry); + return AH_FALSE; + } + break; + case HAL_CIPHER_WEP: + if (k->kv_len < 40 / NBBY) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: WEP key length %u too small\n", + __func__, k->kv_len); + return AH_FALSE; + } + if (k->kv_len <= 40 / NBBY) + keyType = AR_KEYTABLE_TYPE_40; + else if (k->kv_len <= 104 / NBBY) + keyType = AR_KEYTABLE_TYPE_104; + else + keyType = AR_KEYTABLE_TYPE_128; + break; + case HAL_CIPHER_CLR: + keyType = AR_KEYTABLE_TYPE_CLR; + break; + default: + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: cipher %u not supported\n", + __func__, k->kv_type); + return AH_FALSE; + } + + key0 = LE_READ_4(k->kv_val+0) ^ xorMask; + key1 = (LE_READ_2(k->kv_val+4) ^ xorMask) & 0xffff; + key2 = LE_READ_4(k->kv_val+6) ^ xorMask; + key3 = (LE_READ_2(k->kv_val+10) ^ xorMask) & 0xffff; + key4 = LE_READ_4(k->kv_val+12) ^ xorMask; + if (k->kv_len <= 104 / NBBY) + key4 &= 0xff; + + /* + * Note: key cache hardware requires that each double-word + * pair be written in even/odd order (since the destination is + * a 64-bit register). Don't reorder these writes w/o + * considering this! + */ + if (keyType == AR_KEYTABLE_TYPE_TKIP && IS_MIC_ENABLED(ah)) { + uint16_t micentry = entry+64; /* MIC goes at slot+64 */ + uint32_t mic0, mic1, mic2, mic3, mic4; + + /* + * Invalidate the encrypt/decrypt key until the MIC + * key is installed so pending rx frames will fail + * with decrypt errors rather than a MIC error. + */ + OS_REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), ~key0); + OS_REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), ~key1); + OS_REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2); + OS_REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3); + OS_REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4); + OS_REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType); + (void) ar5212SetKeyCacheEntryMac(ah, entry, mac); + + + /* + * Write MIC entry according to new or old key layout. + * The MISC_MODE register is assumed already set so + * these writes will be handled properly (happens on + * attach and at every reset). + */ + /* RX mic */ + mic0 = LE_READ_4(k->kv_mic+0); + mic2 = LE_READ_4(k->kv_mic+4); + if (ahp->ah_miscMode & AR_MISC_MODE_MIC_NEW_LOC_ENABLE) { + /* + * Both RX and TX mic values can be combined into + * one cache slot entry: + * 8*N + 800 31:0 RX Michael key 0 + * 8*N + 804 15:0 TX Michael key 0 [31:16] + * 8*N + 808 31:0 RX Michael key 1 + * 8*N + 80C 15:0 TX Michael key 0 [15:0] + * 8*N + 810 31:0 TX Michael key 1 + * 8*N + 814 15:0 reserved + * 8*N + 818 31:0 reserved + * 8*N + 81C 14:0 reserved + * 15 key valid == 0 + */ + /* TX mic */ + mic1 = LE_READ_2(k->kv_txmic+2) & 0xffff; + mic3 = LE_READ_2(k->kv_txmic+0) & 0xffff; + mic4 = LE_READ_4(k->kv_txmic+4); + } else { + mic1 = mic3 = mic4 = 0; + } + OS_REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0); + OS_REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), mic1); + OS_REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2); + OS_REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), mic3); + OS_REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), mic4); + OS_REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry), + AR_KEYTABLE_TYPE_CLR); + /* NB: MIC key is not marked valid and has no MAC address */ + OS_REG_WRITE(ah, AR_KEYTABLE_MAC0(micentry), 0); + OS_REG_WRITE(ah, AR_KEYTABLE_MAC1(micentry), 0); + + /* correct intentionally corrupted key */ + OS_REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0); + OS_REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1); + } else { + OS_REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0); + OS_REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1); + OS_REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2); + OS_REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3); + OS_REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4); + OS_REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType); + + (void) ar5212SetKeyCacheEntryMac(ah, entry, mac); + } + return AH_TRUE; +} --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5212/ar5212_misc.c 2009-03-23 17:36:55.000000000 +0000 @@ -0,0 +1,1074 @@ +/* + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2008 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ar5212_misc.c,v 1.1 2009/03/23 17:14:48 sborrill Exp $ + */ +#include "opt_ah.h" + +#include "ah.h" +#include "ah_internal.h" +#include "ah_devid.h" +#ifdef AH_DEBUG +#include "ah_desc.h" /* NB: for HAL_PHYERR* */ +#endif + +#include "ar5212/ar5212.h" +#include "ar5212/ar5212reg.h" +#include "ar5212/ar5212phy.h" + +#include "ah_eeprom_v3.h" + +#define AR_NUM_GPIO 6 /* 6 GPIO pins */ +#define AR_GPIOD_MASK 0x0000002F /* GPIO data reg r/w mask */ + +extern void ar5212SetRateDurationTable(struct ath_hal *, HAL_CHANNEL *); + +void +ar5212GetMacAddress(struct ath_hal *ah, uint8_t *mac) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + + OS_MEMCPY(mac, ahp->ah_macaddr, IEEE80211_ADDR_LEN); +} + +HAL_BOOL +ar5212SetMacAddress(struct ath_hal *ah, const uint8_t *mac) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + + OS_MEMCPY(ahp->ah_macaddr, mac, IEEE80211_ADDR_LEN); + return AH_TRUE; +} + +void +ar5212GetBssIdMask(struct ath_hal *ah, uint8_t *mask) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + + OS_MEMCPY(mask, ahp->ah_bssidmask, IEEE80211_ADDR_LEN); +} + +HAL_BOOL +ar5212SetBssIdMask(struct ath_hal *ah, const uint8_t *mask) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + + /* save it since it must be rewritten on reset */ + OS_MEMCPY(ahp->ah_bssidmask, mask, IEEE80211_ADDR_LEN); + + OS_REG_WRITE(ah, AR_BSSMSKL, LE_READ_4(ahp->ah_bssidmask)); + OS_REG_WRITE(ah, AR_BSSMSKU, LE_READ_2(ahp->ah_bssidmask + 4)); + return AH_TRUE; +} + +/* + * Attempt to change the cards operating regulatory domain to the given value + */ +HAL_BOOL +ar5212SetRegulatoryDomain(struct ath_hal *ah, + uint16_t regDomain, HAL_STATUS *status) +{ + HAL_STATUS ecode; + + if (AH_PRIVATE(ah)->ah_currentRD == regDomain) { + ecode = HAL_EINVAL; + goto bad; + } + if (ath_hal_eepromGetFlag(ah, AR_EEP_WRITEPROTECT)) { + ecode = HAL_EEWRITE; + goto bad; + } +#ifdef AH_SUPPORT_WRITE_REGDOMAIN + if (ath_hal_eepromWrite(ah, AR_EEPROM_REG_DOMAIN, regDomain)) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: set regulatory domain to %u (0x%x)\n", + __func__, regDomain, regDomain); + AH_PRIVATE(ah)->ah_currentRD = regDomain; + return AH_TRUE; + } +#endif + ecode = HAL_EIO; +bad: + if (status) + *status = ecode; + return AH_FALSE; +} + +/* + * Return the wireless modes (a,b,g,t) supported by hardware. + * + * This value is what is actually supported by the hardware + * and is unaffected by regulatory/country code settings. + */ +u_int +ar5212GetWirelessModes(struct ath_hal *ah) +{ + u_int mode = 0; + + if (ath_hal_eepromGetFlag(ah, AR_EEP_AMODE)) { + mode = HAL_MODE_11A; + if (!ath_hal_eepromGetFlag(ah, AR_EEP_TURBO5DISABLE)) + mode |= HAL_MODE_TURBO | HAL_MODE_108A; + if (AH_PRIVATE(ah)->ah_caps.halChanHalfRate) + mode |= HAL_MODE_11A_HALF_RATE; + if (AH_PRIVATE(ah)->ah_caps.halChanQuarterRate) + mode |= HAL_MODE_11A_QUARTER_RATE; + } + if (ath_hal_eepromGetFlag(ah, AR_EEP_BMODE)) + mode |= HAL_MODE_11B; + if (ath_hal_eepromGetFlag(ah, AR_EEP_GMODE) && + AH_PRIVATE(ah)->ah_subvendorid != AR_SUBVENDOR_ID_NOG) { + mode |= HAL_MODE_11G; + if (!ath_hal_eepromGetFlag(ah, AR_EEP_TURBO2DISABLE)) + mode |= HAL_MODE_108G; + if (AH_PRIVATE(ah)->ah_caps.halChanHalfRate) + mode |= HAL_MODE_11G_HALF_RATE; + if (AH_PRIVATE(ah)->ah_caps.halChanQuarterRate) + mode |= HAL_MODE_11G_QUARTER_RATE; + } + return mode; +} + +/* + * Set the interrupt and GPIO values so the ISR can disable RF + * on a switch signal. Assumes GPIO port and interrupt polarity + * are set prior to call. + */ +void +ar5212EnableRfKill(struct ath_hal *ah) +{ + uint16_t rfsilent = AH_PRIVATE(ah)->ah_rfsilent; + int select = MS(rfsilent, AR_EEPROM_RFSILENT_GPIO_SEL); + int polarity = MS(rfsilent, AR_EEPROM_RFSILENT_POLARITY); + + /* + * Configure the desired GPIO port for input + * and enable baseband rf silence. + */ + ath_hal_gpioCfgInput(ah, select); + OS_REG_SET_BIT(ah, AR_PHY(0), 0x00002000); + /* + * If radio disable switch connection to GPIO bit x is enabled + * program GPIO interrupt. + * If rfkill bit on eeprom is 1, setupeeprommap routine has already + * verified that it is a later version of eeprom, it has a place for + * rfkill bit and it is set to 1, indicating that GPIO bit x hardware + * connection is present. + */ + ath_hal_gpioSetIntr(ah, select, + (ath_hal_gpioGet(ah, select) == polarity ? !polarity : polarity)); +} + +/* + * Change the LED blinking pattern to correspond to the connectivity + */ +void +ar5212SetLedState(struct ath_hal *ah, HAL_LED_STATE state) +{ + static const uint32_t ledbits[8] = { + AR_PCICFG_LEDCTL_NONE, /* HAL_LED_INIT */ + AR_PCICFG_LEDCTL_PEND, /* HAL_LED_SCAN */ + AR_PCICFG_LEDCTL_PEND, /* HAL_LED_AUTH */ + AR_PCICFG_LEDCTL_ASSOC, /* HAL_LED_ASSOC*/ + AR_PCICFG_LEDCTL_ASSOC, /* HAL_LED_RUN */ + AR_PCICFG_LEDCTL_NONE, + AR_PCICFG_LEDCTL_NONE, + AR_PCICFG_LEDCTL_NONE, + }; + uint32_t bits; + + bits = OS_REG_READ(ah, AR_PCICFG); + if (IS_2417(ah)) { + /* + * Enable LED for Nala. There is a bit marked reserved + * that must be set and we also turn on the power led. + * Because we mark s/w LED control setting the control + * status bits below is meangless (the driver must flash + * the LED(s) using the GPIO lines). + */ + bits = (bits &~ AR_PCICFG_LEDMODE) + | SM(AR_PCICFG_LEDMODE_POWON, AR_PCICFG_LEDMODE) +#if 0 + | SM(AR_PCICFG_LEDMODE_NETON, AR_PCICFG_LEDMODE) +#endif + | 0x08000000; + } + bits = (bits &~ AR_PCICFG_LEDCTL) + | SM(ledbits[state & 0x7], AR_PCICFG_LEDCTL); + OS_REG_WRITE(ah, AR_PCICFG, bits); +} + +/* + * Change association related fields programmed into the hardware. + * Writing a valid BSSID to the hardware effectively enables the hardware + * to synchronize its TSF to the correct beacons and receive frames coming + * from that BSSID. It is called by the SME JOIN operation. + */ +void +ar5212WriteAssocid(struct ath_hal *ah, const uint8_t *bssid, uint16_t assocId) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + + /* XXX save bssid for possible re-use on reset */ + OS_MEMCPY(ahp->ah_bssid, bssid, IEEE80211_ADDR_LEN); + OS_REG_WRITE(ah, AR_BSS_ID0, LE_READ_4(ahp->ah_bssid)); + OS_REG_WRITE(ah, AR_BSS_ID1, LE_READ_2(ahp->ah_bssid+4) | + ((assocId & 0x3fff)<ah_curchan; + uint32_t reg; + uint8_t xset; + int i; + + if (chan == AH_NULL || !IS_CHAN_CCK(chan)) + return; + xset = 0; + for (i = 0; i < rs->rs_count; i++) { + uint8_t rset = rs->rs_rates[i]; + /* Basic rate defined? */ + if ((rset & 0x80) && (rset &= 0x7f) >= xset) + xset = rset; + } + /* + * Set the h/w bit to reflect whether or not the basic + * rate is found to be equal or less than 2Mbps. + */ + reg = OS_REG_READ(ah, AR_STA_ID1); + if (xset && xset/2 <= 2) + OS_REG_WRITE(ah, AR_STA_ID1, reg | AR_STA_ID1_BASE_RATE_11B); + else + OS_REG_WRITE(ah, AR_STA_ID1, reg &~ AR_STA_ID1_BASE_RATE_11B); +} + +/* + * Grab a semi-random value from hardware registers - may not + * change often + */ +uint32_t +ar5212GetRandomSeed(struct ath_hal *ah) +{ + uint32_t nf; + + nf = (OS_REG_READ(ah, AR_PHY(25)) >> 19) & 0x1ff; + if (nf & 0x100) + nf = 0 - ((nf ^ 0x1ff) + 1); + return (OS_REG_READ(ah, AR_TSF_U32) ^ + OS_REG_READ(ah, AR_TSF_L32) ^ nf); +} + +/* + * Detect if our card is present + */ +HAL_BOOL +ar5212DetectCardPresent(struct ath_hal *ah) +{ + uint16_t macVersion, macRev; + uint32_t v; + + /* + * Read the Silicon Revision register and compare that + * to what we read at attach time. If the same, we say + * a card/device is present. + */ + v = OS_REG_READ(ah, AR_SREV) & AR_SREV_ID; + macVersion = v >> AR_SREV_ID_S; + macRev = v & AR_SREV_REVISION; + return (AH_PRIVATE(ah)->ah_macVersion == macVersion && + AH_PRIVATE(ah)->ah_macRev == macRev); +} + +void +ar5212EnableMibCounters(struct ath_hal *ah) +{ + /* NB: this just resets the mib counter machinery */ + OS_REG_WRITE(ah, AR_MIBC, + ~(AR_MIBC_COW | AR_MIBC_FMC | AR_MIBC_CMC | AR_MIBC_MCS) & 0x0f); +} + +void +ar5212DisableMibCounters(struct ath_hal *ah) +{ + OS_REG_WRITE(ah, AR_MIBC, AR_MIBC | AR_MIBC_CMC); +} + +/* + * Update MIB Counters + */ +void +ar5212UpdateMibCounters(struct ath_hal *ah, HAL_MIB_STATS* stats) +{ + stats->ackrcv_bad += OS_REG_READ(ah, AR_ACK_FAIL); + stats->rts_bad += OS_REG_READ(ah, AR_RTS_FAIL); + stats->fcs_bad += OS_REG_READ(ah, AR_FCS_FAIL); + stats->rts_good += OS_REG_READ(ah, AR_RTS_OK); + stats->beacons += OS_REG_READ(ah, AR_BEACON_CNT); +} + +/* + * Detect if the HW supports spreading a CCK signal on channel 14 + */ +HAL_BOOL +ar5212IsJapanChannelSpreadSupported(struct ath_hal *ah) +{ + return AH_TRUE; +} + +/* + * Get the rssi of frame curently being received. + */ +uint32_t +ar5212GetCurRssi(struct ath_hal *ah) +{ + return (OS_REG_READ(ah, AR_PHY_CURRENT_RSSI) & 0xff); +} + +u_int +ar5212GetDefAntenna(struct ath_hal *ah) +{ + return (OS_REG_READ(ah, AR_DEF_ANTENNA) & 0x7); +} + +void +ar5212SetDefAntenna(struct ath_hal *ah, u_int antenna) +{ + OS_REG_WRITE(ah, AR_DEF_ANTENNA, (antenna & 0x7)); +} + +HAL_ANT_SETTING +ar5212GetAntennaSwitch(struct ath_hal *ah) +{ + return AH5212(ah)->ah_antControl; +} + +HAL_BOOL +ar5212SetAntennaSwitch(struct ath_hal *ah, HAL_ANT_SETTING setting) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + const HAL_CHANNEL_INTERNAL *ichan = AH_PRIVATE(ah)->ah_curchan; + + if (!ahp->ah_phyPowerOn || ichan == AH_NULL) { + /* PHY powered off, just stash settings */ + ahp->ah_antControl = setting; + ahp->ah_diversity = (setting == HAL_ANT_VARIABLE); + return AH_TRUE; + } + return ar5212SetAntennaSwitchInternal(ah, setting, ichan); +} + +HAL_BOOL +ar5212IsSleepAfterBeaconBroken(struct ath_hal *ah) +{ + return AH_TRUE; +} + +HAL_BOOL +ar5212SetSifsTime(struct ath_hal *ah, u_int us) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + + if (us > ath_hal_mac_usec(ah, 0xffff)) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad SIFS time %u\n", + __func__, us); + ahp->ah_sifstime = (u_int) -1; /* restore default handling */ + return AH_FALSE; + } else { + /* convert to system clocks */ + OS_REG_WRITE(ah, AR_D_GBL_IFS_SIFS, ath_hal_mac_clks(ah, us)); + ahp->ah_slottime = us; + return AH_TRUE; + } +} + +u_int +ar5212GetSifsTime(struct ath_hal *ah) +{ + u_int clks = OS_REG_READ(ah, AR_D_GBL_IFS_SIFS) & 0xffff; + return ath_hal_mac_usec(ah, clks); /* convert from system clocks */ +} + +HAL_BOOL +ar5212SetSlotTime(struct ath_hal *ah, u_int us) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + + if (us < HAL_SLOT_TIME_6 || us > ath_hal_mac_usec(ah, 0xffff)) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad slot time %u\n", + __func__, us); + ahp->ah_slottime = (u_int) -1; /* restore default handling */ + return AH_FALSE; + } else { + /* convert to system clocks */ + OS_REG_WRITE(ah, AR_D_GBL_IFS_SLOT, ath_hal_mac_clks(ah, us)); + ahp->ah_slottime = us; + return AH_TRUE; + } +} + +u_int +ar5212GetSlotTime(struct ath_hal *ah) +{ + u_int clks = OS_REG_READ(ah, AR_D_GBL_IFS_SLOT) & 0xffff; + return ath_hal_mac_usec(ah, clks); /* convert from system clocks */ +} + +HAL_BOOL +ar5212SetAckTimeout(struct ath_hal *ah, u_int us) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + + if (us > ath_hal_mac_usec(ah, MS(0xffffffff, AR_TIME_OUT_ACK))) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad ack timeout %u\n", + __func__, us); + ahp->ah_acktimeout = (u_int) -1; /* restore default handling */ + return AH_FALSE; + } else { + /* convert to system clocks */ + OS_REG_RMW_FIELD(ah, AR_TIME_OUT, + AR_TIME_OUT_ACK, ath_hal_mac_clks(ah, us)); + ahp->ah_acktimeout = us; + return AH_TRUE; + } +} + +u_int +ar5212GetAckTimeout(struct ath_hal *ah) +{ + u_int clks = MS(OS_REG_READ(ah, AR_TIME_OUT), AR_TIME_OUT_ACK); + return ath_hal_mac_usec(ah, clks); /* convert from system clocks */ +} + +u_int +ar5212GetAckCTSRate(struct ath_hal *ah) +{ + return ((AH5212(ah)->ah_staId1Defaults & AR_STA_ID1_ACKCTS_6MB) == 0); +} + +HAL_BOOL +ar5212SetAckCTSRate(struct ath_hal *ah, u_int high) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + + if (high) { + OS_REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_ACKCTS_6MB); + ahp->ah_staId1Defaults &= ~AR_STA_ID1_ACKCTS_6MB; + } else { + OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_ACKCTS_6MB); + ahp->ah_staId1Defaults |= AR_STA_ID1_ACKCTS_6MB; + } + return AH_TRUE; +} + +HAL_BOOL +ar5212SetCTSTimeout(struct ath_hal *ah, u_int us) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + + if (us > ath_hal_mac_usec(ah, MS(0xffffffff, AR_TIME_OUT_CTS))) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad cts timeout %u\n", + __func__, us); + ahp->ah_ctstimeout = (u_int) -1; /* restore default handling */ + return AH_FALSE; + } else { + /* convert to system clocks */ + OS_REG_RMW_FIELD(ah, AR_TIME_OUT, + AR_TIME_OUT_CTS, ath_hal_mac_clks(ah, us)); + ahp->ah_ctstimeout = us; + return AH_TRUE; + } +} + +u_int +ar5212GetCTSTimeout(struct ath_hal *ah) +{ + u_int clks = MS(OS_REG_READ(ah, AR_TIME_OUT), AR_TIME_OUT_CTS); + return ath_hal_mac_usec(ah, clks); /* convert from system clocks */ +} + +/* Setup decompression for given key index */ +HAL_BOOL +ar5212SetDecompMask(struct ath_hal *ah, uint16_t keyidx, int en) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + + if (keyidx >= HAL_DECOMP_MASK_SIZE) + return HAL_EINVAL; + OS_REG_WRITE(ah, AR_DCM_A, keyidx); + OS_REG_WRITE(ah, AR_DCM_D, en ? AR_DCM_D_EN : 0); + ahp->ah_decompMask[keyidx] = en; + + return AH_TRUE; +} + +/* Setup coverage class */ +void +ar5212SetCoverageClass(struct ath_hal *ah, uint8_t coverageclass, int now) +{ + uint32_t slot, timeout, eifs; + u_int clkRate; + + AH_PRIVATE(ah)->ah_coverageClass = coverageclass; + + if (now) { + if (AH_PRIVATE(ah)->ah_coverageClass == 0) + return; + + /* Don't apply coverage class to non A channels */ + if (!IS_CHAN_A(AH_PRIVATE(ah)->ah_curchan)) + return; + + /* Get core clock rate */ + clkRate = ath_hal_mac_clks(ah, 1); + + /* Compute EIFS */ + slot = coverageclass * 3 * clkRate; + eifs = coverageclass * 6 * clkRate; + if (IS_CHAN_HALF_RATE(AH_PRIVATE(ah)->ah_curchan)) { + slot += IFS_SLOT_HALF_RATE; + eifs += IFS_EIFS_HALF_RATE; + } else if (IS_CHAN_QUARTER_RATE(AH_PRIVATE(ah)->ah_curchan)) { + slot += IFS_SLOT_QUARTER_RATE; + eifs += IFS_EIFS_QUARTER_RATE; + } else { /* full rate */ + slot += IFS_SLOT_FULL_RATE; + eifs += IFS_EIFS_FULL_RATE; + } + + /* + * Add additional time for air propagation for ACK and CTS + * timeouts. This value is in core clocks. + */ + timeout = ACK_CTS_TIMEOUT_11A + (coverageclass * 3 * clkRate); + + /* + * Write the values: slot, eifs, ack/cts timeouts. + */ + OS_REG_WRITE(ah, AR_D_GBL_IFS_SLOT, slot); + OS_REG_WRITE(ah, AR_D_GBL_IFS_EIFS, eifs); + OS_REG_WRITE(ah, AR_TIME_OUT, + SM(timeout, AR_TIME_OUT_CTS) + | SM(timeout, AR_TIME_OUT_ACK)); + } +} + +void +ar5212SetPCUConfig(struct ath_hal *ah) +{ + ar5212SetOperatingMode(ah, AH_PRIVATE(ah)->ah_opmode); +} + +/* + * Return whether an external 32KHz crystal should be used + * to reduce power consumption when sleeping. We do so if + * the crystal is present (obtained from EEPROM) and if we + * are not running as an AP and are configured to use it. + */ +HAL_BOOL +ar5212Use32KHzclock(struct ath_hal *ah, HAL_OPMODE opmode) +{ + if (opmode != HAL_M_HOSTAP) { + struct ath_hal_5212 *ahp = AH5212(ah); + return ath_hal_eepromGetFlag(ah, AR_EEP_32KHZCRYSTAL) && + (ahp->ah_enable32kHzClock == USE_32KHZ || + ahp->ah_enable32kHzClock == AUTO_32KHZ); + } else + return AH_FALSE; +} + +/* + * If 32KHz clock exists, use it to lower power consumption during sleep + * + * Note: If clock is set to 32 KHz, delays on accessing certain + * baseband registers (27-31, 124-127) are required. + */ +void +ar5212SetupClock(struct ath_hal *ah, HAL_OPMODE opmode) +{ + if (ar5212Use32KHzclock(ah, opmode)) { + /* + * Enable clocks to be turned OFF in BB during sleep + * and also enable turning OFF 32MHz/40MHz Refclk + * from A2. + */ + OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_CONTROL, 0x1f); + OS_REG_WRITE(ah, AR_PHY_REFCLKPD, + IS_RAD5112_ANY(ah) || IS_5413(ah) ? 0x14 : 0x18); + OS_REG_RMW_FIELD(ah, AR_USEC, AR_USEC_USEC32, 1); + OS_REG_WRITE(ah, AR_TSF_PARM, 61); /* 32 KHz TSF incr */ + OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_SEL, 1); + + if (IS_2413(ah) || IS_5413(ah) || IS_2417(ah)) { + OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_LIMIT, 0x26); + OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0d); + OS_REG_WRITE(ah, AR_PHY_M_SLEEP, 0x07); + OS_REG_WRITE(ah, AR_PHY_REFCLKDLY, 0x3f); + /* # Set sleep clock rate to 32 KHz. */ + OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_RATE_IND, 0x2); + } else { + OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_LIMIT, 0x0a); + OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0c); + OS_REG_WRITE(ah, AR_PHY_M_SLEEP, 0x03); + OS_REG_WRITE(ah, AR_PHY_REFCLKDLY, 0x20); + OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_RATE_IND, 0x3); + } + } else { + OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_RATE_IND, 0x0); + OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_SEL, 0); + + OS_REG_WRITE(ah, AR_TSF_PARM, 1); /* 32MHz TSF inc */ + + OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_CONTROL, 0x1f); + OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_LIMIT, 0x7f); + + if (IS_2417(ah)) + OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0a); + else if (IS_HB63(ah)) + OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x32); + else + OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0e); + OS_REG_WRITE(ah, AR_PHY_M_SLEEP, 0x0c); + OS_REG_WRITE(ah, AR_PHY_REFCLKDLY, 0xff); + OS_REG_WRITE(ah, AR_PHY_REFCLKPD, + IS_RAD5112_ANY(ah) || IS_5413(ah) || IS_2417(ah) ? 0x14 : 0x18); + OS_REG_RMW_FIELD(ah, AR_USEC, AR_USEC_USEC32, + IS_RAD5112_ANY(ah) || IS_5413(ah) ? 39 : 31); + } +} + +/* + * If 32KHz clock exists, turn it off and turn back on the 32Mhz + */ +void +ar5212RestoreClock(struct ath_hal *ah, HAL_OPMODE opmode) +{ + if (ar5212Use32KHzclock(ah, opmode)) { + /* # Set sleep clock rate back to 32 MHz. */ + OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_RATE_IND, 0); + OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_SEL, 0); + + OS_REG_WRITE(ah, AR_TSF_PARM, 1); /* 32 MHz TSF incr */ + OS_REG_RMW_FIELD(ah, AR_USEC, AR_USEC_USEC32, + IS_RAD5112_ANY(ah) || IS_5413(ah) ? 39 : 31); + + /* + * Restore BB registers to power-on defaults + */ + OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_CONTROL, 0x1f); + OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_LIMIT, 0x7f); + OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0e); + OS_REG_WRITE(ah, AR_PHY_M_SLEEP, 0x0c); + OS_REG_WRITE(ah, AR_PHY_REFCLKDLY, 0xff); + OS_REG_WRITE(ah, AR_PHY_REFCLKPD, + IS_RAD5112_ANY(ah) || IS_5413(ah) ? 0x14 : 0x18); + } +} + +/* + * Adjust NF based on statistical values for 5GHz frequencies. + * Default method: this may be overridden by the rf backend. + */ +int16_t +ar5212GetNfAdjust(struct ath_hal *ah, const HAL_CHANNEL_INTERNAL *c) +{ + static const struct { + uint16_t freqLow; + int16_t adjust; + } adjustDef[] = { + { 5790, 11 }, /* NB: ordered high -> low */ + { 5730, 10 }, + { 5690, 9 }, + { 5660, 8 }, + { 5610, 7 }, + { 5530, 5 }, + { 5450, 4 }, + { 5379, 2 }, + { 5209, 0 }, + { 3000, 1 }, + { 0, 0 }, + }; + int i; + + for (i = 0; c->channel <= adjustDef[i].freqLow; i++) + ; + return adjustDef[i].adjust; +} + +HAL_STATUS +ar5212GetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, + uint32_t capability, uint32_t *result) +{ +#define MACVERSION(ah) AH_PRIVATE(ah)->ah_macVersion + struct ath_hal_5212 *ahp = AH5212(ah); + const HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps; + const struct ar5212AniState *ani; + + switch (type) { + case HAL_CAP_CIPHER: /* cipher handled in hardware */ + switch (capability) { + case HAL_CIPHER_AES_CCM: + return pCap->halCipherAesCcmSupport ? + HAL_OK : HAL_ENOTSUPP; + case HAL_CIPHER_AES_OCB: + case HAL_CIPHER_TKIP: + case HAL_CIPHER_WEP: + case HAL_CIPHER_MIC: + case HAL_CIPHER_CLR: + return HAL_OK; + default: + return HAL_ENOTSUPP; + } + case HAL_CAP_TKIP_MIC: /* handle TKIP MIC in hardware */ + switch (capability) { + case 0: /* hardware capability */ + return HAL_OK; + case 1: + return (ahp->ah_staId1Defaults & + AR_STA_ID1_CRPT_MIC_ENABLE) ? HAL_OK : HAL_ENXIO; + } + case HAL_CAP_TKIP_SPLIT: /* hardware TKIP uses split keys */ + switch (capability) { + case 0: /* hardware capability */ + return pCap->halTkipMicTxRxKeySupport ? + HAL_ENXIO : HAL_OK; + case 1: /* current setting */ + return (ahp->ah_miscMode & + AR_MISC_MODE_MIC_NEW_LOC_ENABLE) ? HAL_ENXIO : HAL_OK; + } + return HAL_EINVAL; + case HAL_CAP_WME_TKIPMIC: /* hardware can do TKIP MIC w/ WMM */ + /* XXX move to capability bit */ + return MACVERSION(ah) > AR_SREV_VERSION_VENICE || + (MACVERSION(ah) == AR_SREV_VERSION_VENICE && + AH_PRIVATE(ah)->ah_macRev >= 8) ? HAL_OK : HAL_ENOTSUPP; + case HAL_CAP_DIVERSITY: /* hardware supports fast diversity */ + switch (capability) { + case 0: /* hardware capability */ + return HAL_OK; + case 1: /* current setting */ + return ahp->ah_diversity ? HAL_OK : HAL_ENXIO; + } + return HAL_EINVAL; + case HAL_CAP_DIAG: + *result = AH_PRIVATE(ah)->ah_diagreg; + return HAL_OK; + case HAL_CAP_TPC: + switch (capability) { + case 0: /* hardware capability */ + return HAL_OK; + case 1: + return ahp->ah_tpcEnabled ? HAL_OK : HAL_ENXIO; + } + return HAL_OK; + case HAL_CAP_PHYDIAG: /* radar pulse detection capability */ + switch (capability) { + case HAL_CAP_RADAR: + return ath_hal_eepromGetFlag(ah, AR_EEP_AMODE) ? + HAL_OK: HAL_ENXIO; + case HAL_CAP_AR: + return (ath_hal_eepromGetFlag(ah, AR_EEP_GMODE) || + ath_hal_eepromGetFlag(ah, AR_EEP_BMODE)) ? + HAL_OK: HAL_ENXIO; + } + return HAL_ENXIO; + case HAL_CAP_MCAST_KEYSRCH: /* multicast frame keycache search */ + switch (capability) { + case 0: /* hardware capability */ + return HAL_OK; + case 1: + return (ahp->ah_staId1Defaults & + AR_STA_ID1_MCAST_KSRCH) ? HAL_OK : HAL_ENXIO; + } + return HAL_EINVAL; + case HAL_CAP_TSF_ADJUST: /* hardware has beacon tsf adjust */ + switch (capability) { + case 0: /* hardware capability */ + return pCap->halTsfAddSupport ? HAL_OK : HAL_ENOTSUPP; + case 1: + return (ahp->ah_miscMode & AR_MISC_MODE_TX_ADD_TSF) ? + HAL_OK : HAL_ENXIO; + } + return HAL_EINVAL; + case HAL_CAP_TPC_ACK: + *result = MS(ahp->ah_macTPC, AR_TPC_ACK); + return HAL_OK; + case HAL_CAP_TPC_CTS: + *result = MS(ahp->ah_macTPC, AR_TPC_CTS); + return HAL_OK; + case HAL_CAP_INTMIT: /* interference mitigation */ + switch (capability) { + case 0: /* hardware capability */ + return HAL_OK; + case 1: + return (ahp->ah_procPhyErr & HAL_ANI_ENA) ? + HAL_OK : HAL_ENXIO; + case 2: /* HAL_ANI_NOISE_IMMUNITY_LEVEL */ + case 3: /* HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION */ + case 4: /* HAL_ANI_CCK_WEAK_SIGNAL_THR */ + case 5: /* HAL_ANI_FIRSTEP_LEVEL */ + case 6: /* HAL_ANI_SPUR_IMMUNITY_LEVEL */ + ani = ar5212AniGetCurrentState(ah); + if (ani == AH_NULL) + return HAL_ENXIO; + switch (capability) { + case 2: *result = ani->noiseImmunityLevel; break; + case 3: *result = !ani->ofdmWeakSigDetectOff; break; + case 4: *result = ani->cckWeakSigThreshold; break; + case 5: *result = ani->firstepLevel; break; + case 6: *result = ani->spurImmunityLevel; break; + } + return HAL_OK; + } + return HAL_EINVAL; + default: + return ath_hal_getcapability(ah, type, capability, result); + } +#undef MACVERSION +} + +HAL_BOOL +ar5212SetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, + uint32_t capability, uint32_t setting, HAL_STATUS *status) +{ +#define N(a) (sizeof(a)/sizeof(a[0])) + struct ath_hal_5212 *ahp = AH5212(ah); + const HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps; + uint32_t v; + + switch (type) { + case HAL_CAP_TKIP_MIC: /* handle TKIP MIC in hardware */ + if (setting) + ahp->ah_staId1Defaults |= AR_STA_ID1_CRPT_MIC_ENABLE; + else + ahp->ah_staId1Defaults &= ~AR_STA_ID1_CRPT_MIC_ENABLE; + return AH_TRUE; + case HAL_CAP_TKIP_SPLIT: /* hardware TKIP uses split keys */ + if (!pCap->halTkipMicTxRxKeySupport) + return AH_FALSE; + /* NB: true =>'s use split key cache layout */ + if (setting) + ahp->ah_miscMode &= ~AR_MISC_MODE_MIC_NEW_LOC_ENABLE; + else + ahp->ah_miscMode |= AR_MISC_MODE_MIC_NEW_LOC_ENABLE; + /* NB: write here so keys can be setup w/o a reset */ + OS_REG_WRITE(ah, AR_MISC_MODE, ahp->ah_miscMode); + return AH_TRUE; + case HAL_CAP_DIVERSITY: + if (ahp->ah_phyPowerOn) { + v = OS_REG_READ(ah, AR_PHY_CCK_DETECT); + if (setting) + v |= AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV; + else + v &= ~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV; + OS_REG_WRITE(ah, AR_PHY_CCK_DETECT, v); + } + ahp->ah_diversity = (setting != 0); + return AH_TRUE; + case HAL_CAP_DIAG: /* hardware diagnostic support */ + /* + * NB: could split this up into virtual capabilities, + * (e.g. 1 => ACK, 2 => CTS, etc.) but it hardly + * seems worth the additional complexity. + */ + AH_PRIVATE(ah)->ah_diagreg = setting; + OS_REG_WRITE(ah, AR_DIAG_SW, AH_PRIVATE(ah)->ah_diagreg); + return AH_TRUE; + case HAL_CAP_TPC: + ahp->ah_tpcEnabled = (setting != 0); + return AH_TRUE; + case HAL_CAP_MCAST_KEYSRCH: /* multicast frame keycache search */ + if (setting) + ahp->ah_staId1Defaults |= AR_STA_ID1_MCAST_KSRCH; + else + ahp->ah_staId1Defaults &= ~AR_STA_ID1_MCAST_KSRCH; + return AH_TRUE; + case HAL_CAP_TPC_ACK: + case HAL_CAP_TPC_CTS: + setting += ahp->ah_txPowerIndexOffset; + if (setting > 63) + setting = 63; + if (type == HAL_CAP_TPC_ACK) { + ahp->ah_macTPC &= AR_TPC_ACK; + ahp->ah_macTPC |= MS(setting, AR_TPC_ACK); + } else { + ahp->ah_macTPC &= AR_TPC_CTS; + ahp->ah_macTPC |= MS(setting, AR_TPC_CTS); + } + OS_REG_WRITE(ah, AR_TPC, ahp->ah_macTPC); + return AH_TRUE; + case HAL_CAP_INTMIT: { /* interference mitigation */ + static const HAL_ANI_CMD cmds[] = { + HAL_ANI_PRESENT, + HAL_ANI_MODE, + HAL_ANI_NOISE_IMMUNITY_LEVEL, + HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, + HAL_ANI_CCK_WEAK_SIGNAL_THR, + HAL_ANI_FIRSTEP_LEVEL, + HAL_ANI_SPUR_IMMUNITY_LEVEL, + }; + return capability < N(cmds) ? + ar5212AniControl(ah, cmds[capability], setting) : + AH_FALSE; + } + case HAL_CAP_TSF_ADJUST: /* hardware has beacon tsf adjust */ + if (pCap->halTsfAddSupport) { + if (setting) + ahp->ah_miscMode |= AR_MISC_MODE_TX_ADD_TSF; + else + ahp->ah_miscMode &= ~AR_MISC_MODE_TX_ADD_TSF; + return AH_TRUE; + } + /* fall thru... */ + default: + return ath_hal_setcapability(ah, type, capability, + setting, status); + } +#undef N +} + +HAL_BOOL +ar5212GetDiagState(struct ath_hal *ah, int request, + const void *args, uint32_t argsize, + void **result, uint32_t *resultsize) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + + (void) ahp; + if (ath_hal_getdiagstate(ah, request, args, argsize, result, resultsize)) + return AH_TRUE; + switch (request) { + case HAL_DIAG_EEPROM: + case HAL_DIAG_EEPROM_EXP_11A: + case HAL_DIAG_EEPROM_EXP_11B: + case HAL_DIAG_EEPROM_EXP_11G: + case HAL_DIAG_RFGAIN: + return ath_hal_eepromDiag(ah, request, + args, argsize, result, resultsize); + case HAL_DIAG_RFGAIN_CURSTEP: + *result = __DECONST(void *, ahp->ah_gainValues.currStep); + *resultsize = (*result == AH_NULL) ? + 0 : sizeof(GAIN_OPTIMIZATION_STEP); + return AH_TRUE; + case HAL_DIAG_PCDAC: + *result = ahp->ah_pcdacTable; + *resultsize = ahp->ah_pcdacTableSize; + return AH_TRUE; + case HAL_DIAG_TXRATES: + *result = &ahp->ah_ratesArray[0]; + *resultsize = sizeof(ahp->ah_ratesArray); + return AH_TRUE; + case HAL_DIAG_ANI_CURRENT: + *result = ar5212AniGetCurrentState(ah); + *resultsize = (*result == AH_NULL) ? + 0 : sizeof(struct ar5212AniState); + return AH_TRUE; + case HAL_DIAG_ANI_STATS: + *result = ar5212AniGetCurrentStats(ah); + *resultsize = (*result == AH_NULL) ? + 0 : sizeof(struct ar5212Stats); + return AH_TRUE; + case HAL_DIAG_ANI_CMD: + if (argsize != 2*sizeof(uint32_t)) + return AH_FALSE; + ar5212AniControl(ah, ((const uint32_t *)args)[0], + ((const uint32_t *)args)[1]); + return AH_TRUE; + case HAL_DIAG_ANI_PARAMS: + /* + * NB: We assume struct ar5212AniParams is identical + * to HAL_ANI_PARAMS; if they diverge then we'll need + * to handle it here + */ + if (argsize == 0 && args == AH_NULL) { + struct ar5212AniState *aniState = + ar5212AniGetCurrentState(ah); + if (aniState == AH_NULL) + return AH_FALSE; + *result = __DECONST(void *, aniState->params); + *resultsize = sizeof(struct ar5212AniParams); + return AH_TRUE; + } else { + if (argsize != sizeof(struct ar5212AniParams)) + return AH_FALSE; + return ar5212AniSetParams(ah, args, args); + } + } + return AH_FALSE; +} --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5212/ar5212_phy.c 2009-03-23 17:36:55.000000000 +0000 @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2008 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ar5212_phy.c,v 1.1 2009/03/23 17:14:48 sborrill Exp $ + */ +#include "opt_ah.h" + +#include "ah.h" +#include "ah_internal.h" + +#include "ar5212/ar5212.h" + +/* shorthands to compact tables for readability */ +#define OFDM IEEE80211_T_OFDM +#define CCK IEEE80211_T_CCK +#define TURBO IEEE80211_T_TURBO + +HAL_RATE_TABLE ar5212_11a_table = { + 8, /* number of rates */ + { 0 }, + { +/* short ctrl */ +/* valid rateCode Preamble dot11Rate Rate */ +/* 6 Mb */ { AH_TRUE, OFDM, 6000, 0x0b, 0x00, (0x80|12), 0, 0, 0 }, +/* 9 Mb */ { AH_TRUE, OFDM, 9000, 0x0f, 0x00, 18, 0, 0, 0 }, +/* 12 Mb */ { AH_TRUE, OFDM, 12000, 0x0a, 0x00, (0x80|24), 2, 0, 0 }, +/* 18 Mb */ { AH_TRUE, OFDM, 18000, 0x0e, 0x00, 36, 2, 0, 0 }, +/* 24 Mb */ { AH_TRUE, OFDM, 24000, 0x09, 0x00, (0x80|48), 4, 0, 0 }, +/* 36 Mb */ { AH_TRUE, OFDM, 36000, 0x0d, 0x00, 72, 4, 0, 0 }, +/* 48 Mb */ { AH_TRUE, OFDM, 48000, 0x08, 0x00, 96, 4, 0, 0 }, +/* 54 Mb */ { AH_TRUE, OFDM, 54000, 0x0c, 0x00, 108, 4, 0, 0 } + }, +}; + +HAL_RATE_TABLE ar5212_half_table = { + 8, /* number of rates */ + { 0 }, + { +/* short ctrl */ +/* valid rateCode Preamble dot11Rate Rate */ +/* 6 Mb */ { AH_TRUE, OFDM, 3000, 0x0b, 0x00, (0x80|6), 0, 0, 0 }, +/* 9 Mb */ { AH_TRUE, OFDM, 4500, 0x0f, 0x00, 9, 0, 0, 0 }, +/* 12 Mb */ { AH_TRUE, OFDM, 6000, 0x0a, 0x00, (0x80|12), 2, 0, 0 }, +/* 18 Mb */ { AH_TRUE, OFDM, 9000, 0x0e, 0x00, 18, 2, 0, 0 }, +/* 24 Mb */ { AH_TRUE, OFDM, 12000, 0x09, 0x00, (0x80|24), 4, 0, 0 }, +/* 36 Mb */ { AH_TRUE, OFDM, 18000, 0x0d, 0x00, 36, 4, 0, 0 }, +/* 48 Mb */ { AH_TRUE, OFDM, 24000, 0x08, 0x00, 48, 4, 0, 0 }, +/* 54 Mb */ { AH_TRUE, OFDM, 27000, 0x0c, 0x00, 54, 4, 0, 0 } + }, +}; + +HAL_RATE_TABLE ar5212_quarter_table = { + 8, /* number of rates */ + { 0 }, + { +/* short ctrl */ +/* valid rateCode Preamble dot11Rate Rate */ +/* 6 Mb */ { AH_TRUE, OFDM, 1500, 0x0b, 0x00, (0x80|3), 0, 0, 0 }, +/* 9 Mb */ { AH_TRUE, OFDM, 2250, 0x0f, 0x00, 4, 0, 0, 0 }, +/* 12 Mb */ { AH_TRUE, OFDM, 3000, 0x0a, 0x00, (0x80|6), 2, 0, 0 }, +/* 18 Mb */ { AH_TRUE, OFDM, 4500, 0x0e, 0x00, 9, 2, 0, 0 }, +/* 24 Mb */ { AH_TRUE, OFDM, 6000, 0x09, 0x00, (0x80|12), 4, 0, 0 }, +/* 36 Mb */ { AH_TRUE, OFDM, 9000, 0x0d, 0x00, 18, 4, 0, 0 }, +/* 48 Mb */ { AH_TRUE, OFDM, 12000, 0x08, 0x00, 24, 4, 0, 0 }, +/* 54 Mb */ { AH_TRUE, OFDM, 13500, 0x0c, 0x00, 27, 4, 0, 0 } + }, +}; + +HAL_RATE_TABLE ar5212_turbog_table = { + 7, /* number of rates */ + { 0 }, + { +/* short ctrl */ +/* valid rateCode Preamble dot11Rate Rate */ +/* 6 Mb */ { AH_TRUE, TURBO, 6000, 0x0b, 0x00, (0x80|12), 0, 0, 0 }, +/* 12 Mb */ { AH_TRUE, TURBO, 12000, 0x0a, 0x00, (0x80|24), 2, 0, 0 }, +/* 18 Mb */ { AH_TRUE, TURBO, 18000, 0x0e, 0x00, 36, 2, 0, 0 }, +/* 24 Mb */ { AH_TRUE, TURBO, 24000, 0x09, 0x00, (0x80|48), 3, 0, 0 }, +/* 36 Mb */ { AH_TRUE, TURBO, 36000, 0x0d, 0x00, 72, 3, 0, 0 }, +/* 48 Mb */ { AH_TRUE, TURBO, 48000, 0x08, 0x00, 96, 3, 0, 0 }, +/* 54 Mb */ { AH_TRUE, TURBO, 54000, 0x0c, 0x00, 108, 3, 0, 0 } + }, +}; + +HAL_RATE_TABLE ar5212_turboa_table = { + 8, /* number of rates */ + { 0 }, + { +/* short ctrl */ +/* valid rateCode Preamble dot11Rate Rate */ +/* 6 Mb */ { AH_TRUE, TURBO, 6000, 0x0b, 0x00, (0x80|12), 0, 0, 0 }, +/* 9 Mb */ { AH_TRUE, TURBO, 9000, 0x0f, 0x00, 18, 0, 0, 0 }, +/* 12 Mb */ { AH_TRUE, TURBO, 12000, 0x0a, 0x00, (0x80|24), 2, 0, 0 }, +/* 18 Mb */ { AH_TRUE, TURBO, 18000, 0x0e, 0x00, 36, 2, 0, 0 }, +/* 24 Mb */ { AH_TRUE, TURBO, 24000, 0x09, 0x00, (0x80|48), 4, 0, 0 }, +/* 36 Mb */ { AH_TRUE, TURBO, 36000, 0x0d, 0x00, 72, 4, 0, 0 }, +/* 48 Mb */ { AH_TRUE, TURBO, 48000, 0x08, 0x00, 96, 4, 0, 0 }, +/* 54 Mb */ { AH_TRUE, TURBO, 54000, 0x0c, 0x00, 108, 4, 0, 0 } + }, +}; + +HAL_RATE_TABLE ar5212_11b_table = { + 4, /* number of rates */ + { 0 }, + { +/* short ctrl */ +/* valid rateCode Preamble dot11Rate Rate */ +/* 1 Mb */ { AH_TRUE, CCK, 1000, 0x1b, 0x00, (0x80| 2), 0, 0, 0 }, +/* 2 Mb */ { AH_TRUE, CCK, 2000, 0x1a, 0x04, (0x80| 4), 1, 0, 0 }, +/* 5.5 Mb */ { AH_TRUE, CCK, 5500, 0x19, 0x04, (0x80|11), 1, 0, 0 }, +/* 11 Mb */ { AH_TRUE, CCK, 11000, 0x18, 0x04, (0x80|22), 1, 0, 0 } + }, +}; + + +/* Venice TODO: roundUpRate() is broken when the rate table does not represent rates + * in increasing order e.g. 5.5, 11, 6, 9. + * An average rate of 6 Mbps will currently map to 11 Mbps. + */ +HAL_RATE_TABLE ar5212_11g_table = { + 12, /* number of rates */ + { 0 }, + { +/* short ctrl */ +/* valid rateCode Preamble dot11Rate Rate */ +/* 1 Mb */ { AH_TRUE, CCK, 1000, 0x1b, 0x00, (0x80| 2), 0, 0, 0 }, +/* 2 Mb */ { AH_TRUE, CCK, 2000, 0x1a, 0x04, (0x80| 4), 1, 0, 0 }, +/* 5.5 Mb */ { AH_TRUE, CCK, 5500, 0x19, 0x04, (0x80|11), 2, 0, 0 }, +/* 11 Mb */ { AH_TRUE, CCK, 11000, 0x18, 0x04, (0x80|22), 3, 0, 0 }, +/* remove rates 6, 9 from rate ctrl */ +/* 6 Mb */ { AH_FALSE, OFDM, 6000, 0x0b, 0x00, 12, 4, 0, 0 }, +/* 9 Mb */ { AH_FALSE, OFDM, 9000, 0x0f, 0x00, 18, 4, 0, 0 }, +/* 12 Mb */ { AH_TRUE, OFDM, 12000, 0x0a, 0x00, 24, 6, 0, 0 }, +/* 18 Mb */ { AH_TRUE, OFDM, 18000, 0x0e, 0x00, 36, 6, 0, 0 }, +/* 24 Mb */ { AH_TRUE, OFDM, 24000, 0x09, 0x00, 48, 8, 0, 0 }, +/* 36 Mb */ { AH_TRUE, OFDM, 36000, 0x0d, 0x00, 72, 8, 0, 0 }, +/* 48 Mb */ { AH_TRUE, OFDM, 48000, 0x08, 0x00, 96, 8, 0, 0 }, +/* 54 Mb */ { AH_TRUE, OFDM, 54000, 0x0c, 0x00, 108, 8, 0, 0 } + }, +}; + +#undef OFDM +#undef CCK +#undef TURBO +#undef XR + +const HAL_RATE_TABLE * +ar5212GetRateTable(struct ath_hal *ah, u_int mode) +{ + HAL_RATE_TABLE *rt; + switch (mode) { + case HAL_MODE_11A: + rt = &ar5212_11a_table; + break; + case HAL_MODE_11B: + rt = &ar5212_11b_table; + break; + case HAL_MODE_11G: +#ifdef notdef + case HAL_MODE_PUREG: +#endif + rt = &ar5212_11g_table; + break; + case HAL_MODE_108A: + case HAL_MODE_TURBO: + rt = &ar5212_turboa_table; + break; + case HAL_MODE_108G: + rt = &ar5212_turbog_table; + break; + case HAL_MODE_11A_HALF_RATE: + case HAL_MODE_11G_HALF_RATE: + rt = &ar5212_half_table; + break; + case HAL_MODE_11A_QUARTER_RATE: + case HAL_MODE_11G_QUARTER_RATE: + rt = &ar5212_quarter_table; + break; + default: + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid mode 0x%x\n", + __func__, mode); + return AH_NULL; + } + ath_hal_setupratetable(ah, rt); + return rt; +} --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5212/ar5212_power.c 2009-03-23 17:36:55.000000000 +0000 @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2008 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ar5212_power.c,v 1.1 2009/03/23 17:14:48 sborrill Exp $ + */ +#include "opt_ah.h" + +#include "ah.h" +#include "ah_internal.h" + +#include "ar5212/ar5212.h" +#include "ar5212/ar5212reg.h" +#include "ar5212/ar5212desc.h" + +/* + * Notify Power Mgt is enabled in self-generated frames. + * If requested, force chip awake. + * + * Returns A_OK if chip is awake or successfully forced awake. + * + * WARNING WARNING WARNING + * There is a problem with the chip where sometimes it will not wake up. + */ +static HAL_BOOL +ar5212SetPowerModeAwake(struct ath_hal *ah, int setChip) +{ +#define AR_SCR_MASK \ + (AR_SCR_SLDUR|AR_SCR_SLE|AR_SCR_SLE|AR_SCR_SLDTP|AR_SCR_SLDWP|\ + AR_SCR_SLEPOL|AR_SCR_MIBIE) +#define POWER_UP_TIME 2000 + uint32_t scr, val; + int i; + + if (setChip) { + /* + * Be careful setting the AWAKE mode. When we are called + * with the chip powered down the read returns 0xffffffff + * which when blindly written back with OS_REG_RMW_FIELD + * enables the MIB interrupt for the sleep performance + * counters. This can result in an interrupt storm when + * ANI is in operation as noone knows to turn off the MIB + * interrupt cause. + */ + scr = OS_REG_READ(ah, AR_SCR); + if (scr & ~AR_SCR_MASK) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: bogus SCR 0x%x, PCICFG 0x%x\n", + __func__, scr, OS_REG_READ(ah, AR_PCICFG)); + scr = 0; + } + scr = (scr &~ AR_SCR_SLE) | AR_SCR_SLE_WAKE; + OS_REG_WRITE(ah, AR_SCR, scr); + OS_DELAY(10); /* Give chip the chance to awake */ + + for (i = POWER_UP_TIME / 50; i != 0; i--) { + val = OS_REG_READ(ah, AR_PCICFG); + if ((val & AR_PCICFG_SPWR_DN) == 0) + break; + OS_DELAY(50); + OS_REG_WRITE(ah, AR_SCR, scr); + } + if (i == 0) { +#ifdef AH_DEBUG + ath_hal_printf(ah, "%s: Failed to wakeup in %ums\n", + __func__, POWER_UP_TIME/50); +#endif + return AH_FALSE; + } + } + + OS_REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); + return AH_TRUE; +#undef POWER_UP_TIME +#undef AR_SCR_MASK +} + +/* + * Notify Power Mgt is disabled in self-generated frames. + * If requested, force chip to sleep. + */ +static void +ar5212SetPowerModeSleep(struct ath_hal *ah, int setChip) +{ + OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); + if (setChip) + OS_REG_RMW_FIELD(ah, AR_SCR, AR_SCR_SLE, AR_SCR_SLE_SLP); +} + +/* + * Notify Power Management is enabled in self-generating + * fames. If request, set power mode of chip to + * auto/normal. Duration in units of 128us (1/8 TU). + */ +static void +ar5212SetPowerModeNetworkSleep(struct ath_hal *ah, int setChip) +{ + OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); + if (setChip) + OS_REG_RMW_FIELD(ah, AR_SCR, AR_SCR_SLE, AR_SCR_SLE_NORM); +} + +/* + * Set power mgt to the requested mode, and conditionally set + * the chip as well + */ +HAL_BOOL +ar5212SetPowerMode(struct ath_hal *ah, HAL_POWER_MODE mode, int setChip) +{ + struct ath_hal_5212 *ahp = AH5212(ah); +#ifdef AH_DEBUG + static const char* modes[] = { + "AWAKE", + "FULL-SLEEP", + "NETWORK SLEEP", + "UNDEFINED" + }; +#endif + int status = AH_TRUE; + + HALDEBUG(ah, HAL_DEBUG_POWER, "%s: %s -> %s (%s)\n", __func__, + modes[ahp->ah_powerMode], modes[mode], + setChip ? "set chip " : ""); + switch (mode) { + case HAL_PM_AWAKE: + status = ar5212SetPowerModeAwake(ah, setChip); + break; + case HAL_PM_FULL_SLEEP: + ar5212SetPowerModeSleep(ah, setChip); + break; + case HAL_PM_NETWORK_SLEEP: + ar5212SetPowerModeNetworkSleep(ah, setChip); + break; + default: + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unknown power mode %u\n", + __func__, mode); + return AH_FALSE; + } + ahp->ah_powerMode = mode; + return status; +} + +/* + * Return the current sleep mode of the chip + */ +HAL_POWER_MODE +ar5212GetPowerMode(struct ath_hal *ah) +{ + /* Just so happens the h/w maps directly to the abstracted value */ + return MS(OS_REG_READ(ah, AR_SCR), AR_SCR_SLE); +} + +#if 0 +/* + * Return the current sleep state of the chip + * TRUE = sleeping + */ +HAL_BOOL +ar5212GetPowerStatus(struct ath_hal *ah) +{ + return (OS_REG_READ(ah, AR_PCICFG) & AR_PCICFG_SPWR_DN) != 0; +} +#endif --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5212/ar5212_recv.c 2009-03-23 17:36:55.000000000 +0000 @@ -0,0 +1,286 @@ +/* + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2008 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ar5212_recv.c,v 1.1 2009/03/23 17:14:48 sborrill Exp $ + */ +#include "opt_ah.h" + +#include "ah.h" +#include "ah_internal.h" + +#include "ar5212/ar5212.h" +#include "ar5212/ar5212reg.h" +#include "ar5212/ar5212desc.h" + +/* + * Get the RXDP. + */ +uint32_t +ar5212GetRxDP(struct ath_hal *ath) +{ + return OS_REG_READ(ath, AR_RXDP); +} + +/* + * Set the RxDP. + */ +void +ar5212SetRxDP(struct ath_hal *ah, uint32_t rxdp) +{ + OS_REG_WRITE(ah, AR_RXDP, rxdp); + HALASSERT(OS_REG_READ(ah, AR_RXDP) == rxdp); +} + +/* + * Set Receive Enable bits. + */ +void +ar5212EnableReceive(struct ath_hal *ah) +{ + OS_REG_WRITE(ah, AR_CR, AR_CR_RXE); +} + +/* + * Stop Receive at the DMA engine + */ +HAL_BOOL +ar5212StopDmaReceive(struct ath_hal *ah) +{ + OS_REG_WRITE(ah, AR_CR, AR_CR_RXD); /* Set receive disable bit */ + if (!ath_hal_wait(ah, AR_CR, AR_CR_RXE, 0)) { +#ifdef AH_DEBUG + ath_hal_printf(ah, "%s: dma failed to stop in 10ms\n" + "AR_CR=0x%08x\nAR_DIAG_SW=0x%08x\n", + __func__, + OS_REG_READ(ah, AR_CR), + OS_REG_READ(ah, AR_DIAG_SW)); +#endif + return AH_FALSE; + } else { + return AH_TRUE; + } +} + +/* + * Start Transmit at the PCU engine (unpause receive) + */ +void +ar5212StartPcuReceive(struct ath_hal *ah) +{ + struct ath_hal_private *ahp = AH_PRIVATE(ah); + + OS_REG_WRITE(ah, AR_DIAG_SW, + OS_REG_READ(ah, AR_DIAG_SW) &~ AR_DIAG_RX_DIS); + ar5212EnableMibCounters(ah); + /* NB: restore current settings */ + ar5212AniReset(ah, ahp->ah_curchan, ahp->ah_opmode, AH_TRUE); +} + +/* + * Stop Transmit at the PCU engine (pause receive) + */ +void +ar5212StopPcuReceive(struct ath_hal *ah) +{ + OS_REG_WRITE(ah, AR_DIAG_SW, + OS_REG_READ(ah, AR_DIAG_SW) | AR_DIAG_RX_DIS); + ar5212DisableMibCounters(ah); +} + +/* + * Set multicast filter 0 (lower 32-bits) + * filter 1 (upper 32-bits) + */ +void +ar5212SetMulticastFilter(struct ath_hal *ah, uint32_t filter0, uint32_t filter1) +{ + OS_REG_WRITE(ah, AR_MCAST_FIL0, filter0); + OS_REG_WRITE(ah, AR_MCAST_FIL1, filter1); +} + +/* + * Clear multicast filter by index + */ +HAL_BOOL +ar5212ClrMulticastFilterIndex(struct ath_hal *ah, uint32_t ix) +{ + uint32_t val; + + if (ix >= 64) + return AH_FALSE; + if (ix >= 32) { + val = OS_REG_READ(ah, AR_MCAST_FIL1); + OS_REG_WRITE(ah, AR_MCAST_FIL1, (val &~ (1<<(ix-32)))); + } else { + val = OS_REG_READ(ah, AR_MCAST_FIL0); + OS_REG_WRITE(ah, AR_MCAST_FIL0, (val &~ (1<= 64) + return AH_FALSE; + if (ix >= 32) { + val = OS_REG_READ(ah, AR_MCAST_FIL1); + OS_REG_WRITE(ah, AR_MCAST_FIL1, (val | (1<<(ix-32)))); + } else { + val = OS_REG_READ(ah, AR_MCAST_FIL0); + OS_REG_WRITE(ah, AR_MCAST_FIL0, (val | (1<ds_ctl0 = 0; + ads->ds_ctl1 = size & AR_BufLen; + + if (flags & HAL_RXDESC_INTREQ) + ads->ds_ctl1 |= AR_RxInterReq; + ads->ds_rxstatus0 = ads->ds_rxstatus1 = 0; + + return AH_TRUE; +} + +/* + * Process an RX descriptor, and return the status to the caller. + * Copy some hardware specific items into the software portion + * of the descriptor. + * + * NB: the caller is responsible for validating the memory contents + * of the descriptor (e.g. flushing any cached copy). + */ +HAL_STATUS +ar5212ProcRxDesc(struct ath_hal *ah, struct ath_desc *ds, + uint32_t pa, struct ath_desc *nds, uint64_t tsf, + struct ath_rx_status *rs) +{ + struct ar5212_desc *ads = AR5212DESC(ds); + struct ar5212_desc *ands = AR5212DESC(nds); + + if ((ads->ds_rxstatus1 & AR_Done) == 0) + return HAL_EINPROGRESS; + /* + * Given the use of a self-linked tail be very sure that the hw is + * done with this descriptor; the hw may have done this descriptor + * once and picked it up again...make sure the hw has moved on. + */ + if ((ands->ds_rxstatus1&AR_Done) == 0 && OS_REG_READ(ah, AR_RXDP) == pa) + return HAL_EINPROGRESS; + + rs->rs_datalen = ads->ds_rxstatus0 & AR_DataLen; + rs->rs_tstamp = MS(ads->ds_rxstatus1, AR_RcvTimestamp); + rs->rs_status = 0; + /* XXX what about KeyCacheMiss? */ + rs->rs_rssi = MS(ads->ds_rxstatus0, AR_RcvSigStrength); + /* discard invalid h/w rssi data */ + if (rs->rs_rssi == -128) + rs->rs_rssi = 0; + if (ads->ds_rxstatus1 & AR_KeyIdxValid) + rs->rs_keyix = MS(ads->ds_rxstatus1, AR_KeyIdx); + else + rs->rs_keyix = HAL_RXKEYIX_INVALID; + /* NB: caller expected to do rate table mapping */ + rs->rs_rate = MS(ads->ds_rxstatus0, AR_RcvRate); + rs->rs_antenna = MS(ads->ds_rxstatus0, AR_RcvAntenna); + rs->rs_more = (ads->ds_rxstatus0 & AR_More) ? 1 : 0; + + if ((ads->ds_rxstatus1 & AR_FrmRcvOK) == 0) { + /* + * These four bits should not be set together. The + * 5212 spec states a Michael error can only occur if + * DecryptCRCErr not set (and TKIP is used). Experience + * indicates however that you can also get Michael errors + * when a CRC error is detected, but these are specious. + * Consequently we filter them out here so we don't + * confuse and/or complicate drivers. + */ + if (ads->ds_rxstatus1 & AR_CRCErr) + rs->rs_status |= HAL_RXERR_CRC; + else if (ads->ds_rxstatus1 & AR_PHYErr) { + u_int phyerr; + + rs->rs_status |= HAL_RXERR_PHY; + phyerr = MS(ads->ds_rxstatus1, AR_PHYErrCode); + rs->rs_phyerr = phyerr; + if (!AH5212(ah)->ah_hasHwPhyCounters && + phyerr != HAL_PHYERR_RADAR) + ar5212AniPhyErrReport(ah, rs); + } else if (ads->ds_rxstatus1 & AR_DecryptCRCErr) + rs->rs_status |= HAL_RXERR_DECRYPT; + else if (ads->ds_rxstatus1 & AR_MichaelErr) + rs->rs_status |= HAL_RXERR_MIC; + } + return HAL_OK; +} --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5212/ar5212phy.h 2009-03-23 17:36:55.000000000 +0000 @@ -0,0 +1,347 @@ +/* + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2008 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ar5212phy.h,v 1.1 2009/03/23 17:14:48 sborrill Exp $ + */ +#ifndef _DEV_ATH_AR5212PHY_H_ +#define _DEV_ATH_AR5212PHY_H_ + +/* PHY registers */ +#define AR_PHY_BASE 0x9800 /* base address of phy regs */ +#define AR_PHY(_n) (AR_PHY_BASE + ((_n)<<2)) + +#define AR_PHY_TEST 0x9800 /* PHY test control */ +#define PHY_AGC_CLR 0x10000000 /* disable AGC to A2 */ + +#define AR_PHY_TESTCTRL 0x9808 /* PHY Test Control/Status */ +#define AR_PHY_TESTCTRL_TXHOLD 0x3800 /* Select Tx hold */ +#define AR_PHY_TESTCTRL_TXSRC_ALT 0x00000080 /* Select input to tsdac along with bit 1 */ +#define AR_PHY_TESTCTRL_TXSRC_ALT_S 7 +#define AR_PHY_TESTCTRL_TXSRC_SRC 0x00000002 /* Used with bit 7 */ +#define AR_PHY_TESTCTRL_TXSRC_SRC_S 1 + +#define AR_PHY_TURBO 0x9804 /* frame control register */ +#define AR_PHY_FC_TURBO_MODE 0x00000001 /* Set turbo mode bits */ +#define AR_PHY_FC_TURBO_SHORT 0x00000002 /* Set short symbols to turbo mode setting */ +#define AR_PHY_FC_TURBO_MIMO 0x00000004 /* Set turbo for mimo mode */ + +#define AR_PHY_TIMING3 0x9814 /* Timing control 3 */ +#define AR_PHY_TIMING3_DSC_MAN 0xFFFE0000 +#define AR_PHY_TIMING3_DSC_MAN_S 17 +#define AR_PHY_TIMING3_DSC_EXP 0x0001E000 +#define AR_PHY_TIMING3_DSC_EXP_S 13 + +#define AR_PHY_CHIP_ID 0x9818 /* PHY chip revision ID */ +#define AR_PHY_CHIP_ID_REV_2 0x42 /* 5212 Rev 2 BB w. TPC fix */ +#define AR_PHY_CHIP_ID_REV_3 0x43 /* 5212 Rev 3 5213 */ +#define AR_PHY_CHIP_ID_REV_4 0x44 /* 5212 Rev 4 2313 and up */ + +#define AR_PHY_ACTIVE 0x981C /* activation register */ +#define AR_PHY_ACTIVE_EN 0x00000001 /* Activate PHY chips */ +#define AR_PHY_ACTIVE_DIS 0x00000000 /* Deactivate PHY chips */ + +#define AR_PHY_TX_CTL 0x9824 +#define AR_PHY_TX_FRAME_TO_TX_DATA_START 0x0000000f +#define AR_PHY_TX_FRAME_TO_TX_DATA_START_S 0 + +#define AR_PHY_ADC_CTL 0x982C +#define AR_PHY_ADC_CTL_OFF_INBUFGAIN 0x00000003 +#define AR_PHY_ADC_CTL_OFF_INBUFGAIN_S 0 +#define AR_PHY_ADC_CTL_OFF_PWDDAC 0x00002000 +#define AR_PHY_ADC_CTL_OFF_PWDBANDGAP 0x00004000 /* BB Rev 4.2+ only */ +#define AR_PHY_ADC_CTL_OFF_PWDADC 0x00008000 /* BB Rev 4.2+ only */ +#define AR_PHY_ADC_CTL_ON_INBUFGAIN 0x00030000 +#define AR_PHY_ADC_CTL_ON_INBUFGAIN_S 16 + +#define AR_PHY_BB_XP_PA_CTL 0x9838 +#define AR_PHY_BB_XPAA_ACTIVE_HIGH 0x00000001 +#define AR_PHY_BB_XPAB_ACTIVE_HIGH 0x00000002 +#define AR_PHY_BB_XPAB_ACTIVE_HIGH_S 1 + +#define AR_PHY_TSTDAC_CONST 0x983C +#define AR_PHY_TSTDAC_CONST_Q 0x0003FE00 +#define AR_PHY_TSTDAC_CONST_Q_S 9 +#define AR_PHY_TSTDAC_CONST_I 0x000001FF + + +#define AR_PHY_SETTLING 0x9844 +#define AR_PHY_SETTLING_AGC 0x0000007F +#define AR_PHY_SETTLING_AGC_S 0 +#define AR_PHY_SETTLING_SWITCH 0x00003F80 +#define AR_PHY_SETTLING_SWITCH_S 7 + +#define AR_PHY_RXGAIN 0x9848 +#define AR_PHY_RXGAIN_TXRX_ATTEN 0x0003F000 +#define AR_PHY_RXGAIN_TXRX_ATTEN_S 12 +#define AR_PHY_RXGAIN_TXRX_RF_MAX 0x007C0000 +#define AR_PHY_RXGAIN_TXRX_RF_MAX_S 18 + +#define AR_PHY_DESIRED_SZ 0x9850 +#define AR_PHY_DESIRED_SZ_ADC 0x000000FF +#define AR_PHY_DESIRED_SZ_ADC_S 0 +#define AR_PHY_DESIRED_SZ_PGA 0x0000FF00 +#define AR_PHY_DESIRED_SZ_PGA_S 8 +#define AR_PHY_DESIRED_SZ_TOT_DES 0x0FF00000 +#define AR_PHY_DESIRED_SZ_TOT_DES_S 20 + +#define AR_PHY_FIND_SIG 0x9858 +#define AR_PHY_FIND_SIG_FIRSTEP 0x0003F000 +#define AR_PHY_FIND_SIG_FIRSTEP_S 12 +#define AR_PHY_FIND_SIG_FIRPWR 0x03FC0000 +#define AR_PHY_FIND_SIG_FIRPWR_S 18 + +#define AR_PHY_AGC_CTL1 0x985C +#define AR_PHY_AGC_CTL1_COARSE_LOW 0x00007F80 +#define AR_PHY_AGC_CTL1_COARSE_LOW_S 7 +#define AR_PHY_AGC_CTL1_COARSE_HIGH 0x003F8000 +#define AR_PHY_AGC_CTL1_COARSE_HIGH_S 15 + +#define AR_PHY_AGC_CONTROL 0x9860 /* chip calibration and noise floor setting */ +#define AR_PHY_AGC_CONTROL_CAL 0x00000001 /* do internal calibration */ +#define AR_PHY_AGC_CONTROL_NF 0x00000002 /* do noise-floor calculation */ +#define AR_PHY_AGC_CONTROL_ENABLE_NF 0x00008000 /* Enable noise floor calibration to happen */ +#define AR_PHY_AGC_CONTROL_FLTR_CAL 0x00010000 /* Allow Filter calibration */ +#define AR_PHY_AGC_CONTROL_NO_UPDATE_NF 0x00020000 /* Don't update noise floor automatically */ + +#define AR_PHY_SFCORR_LOW 0x986C +#define AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW 0x00000001 +#define AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW 0x00003F00 +#define AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW_S 8 +#define AR_PHY_SFCORR_LOW_M1_THRESH_LOW 0x001FC000 +#define AR_PHY_SFCORR_LOW_M1_THRESH_LOW_S 14 +#define AR_PHY_SFCORR_LOW_M2_THRESH_LOW 0x0FE00000 +#define AR_PHY_SFCORR_LOW_M2_THRESH_LOW_S 21 + +#define AR_PHY_SFCORR 0x9868 +#define AR_PHY_SFCORR_M2COUNT_THR 0x0000001F +#define AR_PHY_SFCORR_M2COUNT_THR_S 0 +#define AR_PHY_SFCORR_M1_THRESH 0x00FE0000 +#define AR_PHY_SFCORR_M1_THRESH_S 17 +#define AR_PHY_SFCORR_M2_THRESH 0x7F000000 +#define AR_PHY_SFCORR_M2_THRESH_S 24 + +#define AR_PHY_SLEEP_CTR_CONTROL 0x9870 +#define AR_PHY_SLEEP_CTR_LIMIT 0x9874 +#define AR_PHY_SLEEP_SCAL 0x9878 + +#define AR_PHY_PLL_CTL 0x987c /* PLL control register */ +#define AR_PHY_PLL_CTL_40 0xaa /* 40 MHz */ +#define AR_PHY_PLL_CTL_44 0xab /* 44 MHz for 11b, 11g */ +#define AR_PHY_PLL_CTL_44_5112 0xeb /* 44 MHz for 11b, 11g */ +#define AR_PHY_PLL_CTL_40_5112 0xea /* 40 MHz for 11a, turbos */ +#define AR_PHY_PLL_CTL_40_5413 0x04 /* 40 MHz for 11a, turbos with 5413 */ +#define AR_PHY_PLL_CTL_HALF 0x100 /* Half clock for 1/2 chan width */ +#define AR_PHY_PLL_CTL_QUARTER 0x200 /* Quarter clock for 1/4 chan width */ + +#define AR_PHY_BIN_MASK_1 0x9900 +#define AR_PHY_BIN_MASK_2 0x9904 +#define AR_PHY_BIN_MASK_3 0x9908 + +#define AR_PHY_MASK_CTL 0x990c /* What are these for?? */ +#define AR_PHY_MASK_CTL_MASK_4 0x00003FFF +#define AR_PHY_MASK_CTL_MASK_4_S 0 +#define AR_PHY_MASK_CTL_RATE 0xFF000000 +#define AR_PHY_MASK_CTL_RATE_S 24 + +#define AR_PHY_RX_DELAY 0x9914 /* analog pow-on time (100ns) */ +#define AR_PHY_RX_DELAY_DELAY 0x00003FFF /* delay from wakeup to rx ena */ + +#define AR_PHY_TIMING_CTRL4 0x9920 /* timing control */ +#define AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF 0x01F /* Mask for kcos_theta-1 for q correction */ +#define AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF_S 0 /* shift for Q_COFF */ +#define AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF 0x7E0 /* Mask for sin_theta for i correction */ +#define AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF_S 5 /* Shift for sin_theta for i correction */ +#define AR_PHY_TIMING_CTRL4_IQCORR_ENABLE 0x800 /* enable IQ correction */ +#define AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX 0xF000 /* Mask for max number of samples (logarithmic) */ +#define AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX_S 12 /* Shift for max number of samples */ +#define AR_PHY_TIMING_CTRL4_DO_IQCAL 0x10000 /* perform IQ calibration */ +#define AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER 0x40000000 /* Enable spur filter */ +#define AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK 0x20000000 +#define AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK 0x10000000 + +#define AR_PHY_TIMING5 0x9924 +#define AR_PHY_TIMING5_CYCPWR_THR1 0x000000FE +#define AR_PHY_TIMING5_CYCPWR_THR1_S 1 + +#define AR_PHY_PAPD_PROBE 0x9930 +#define AR_PHY_PAPD_PROBE_POWERTX 0x00007E00 +#define AR_PHY_PAPD_PROBE_POWERTX_S 9 +#define AR_PHY_PAPD_PROBE_NEXT_TX 0x00008000 /* command to take next reading */ +#define AR_PHY_PAPD_PROBE_TYPE 0x01800000 +#define AR_PHY_PAPD_PROBE_TYPE_S 23 +#define AR_PHY_PAPD_PROBE_TYPE_OFDM 0 +#define AR_PHY_PAPD_PROBE_TYPE_CCK 2 +#define AR_PHY_PAPD_PROBE_GAINF 0xFE000000 +#define AR_PHY_PAPD_PROBE_GAINF_S 25 + +#define AR_PHY_POWER_TX_RATE1 0x9934 +#define AR_PHY_POWER_TX_RATE2 0x9938 +#define AR_PHY_POWER_TX_RATE_MAX 0x993c +#define AR_PHY_POWER_TX_RATE_MAX_TPC_ENABLE 0x00000040 + +#define AR_PHY_FRAME_CTL 0x9944 +#define AR_PHY_FRAME_CTL_TX_CLIP 0x00000038 +#define AR_PHY_FRAME_CTL_TX_CLIP_S 3 +#define AR_PHY_FRAME_CTL_ERR_SERV 0x20000000 +#define AR_PHY_FRAME_CTL_ERR_SERV_S 29 +#define AR_PHY_FRAME_CTL_EMU_M 0x80000000 +#define AR_PHY_FRAME_CTL_EMU_S 31 +#define AR_PHY_FRAME_CTL_WINLEN 0x00000003 +#define AR_PHY_FRAME_CTL_WINLEN_S 0 + +#define AR_PHY_TXPWRADJ 0x994C /* BB Rev 4.2+ only */ +#define AR_PHY_TXPWRADJ_CCK_GAIN_DELTA 0x00000FC0 +#define AR_PHY_TXPWRADJ_CCK_GAIN_DELTA_S 6 +#define AR_PHY_TXPWRADJ_CCK_PCDAC_INDEX 0x00FC0000 +#define AR_PHY_TXPWRADJ_CCK_PCDAC_INDEX_S 18 + +#define AR_PHY_RADAR_0 0x9954 /* radar detection settings */ +#define AR_PHY_RADAR_0_ENA 0x00000001 /* Enable radar detection */ +#define AR_PHY_RADAR_0_INBAND 0x0000003e /* Inband pulse threshold */ +#define AR_PHY_RADAR_0_INBAND_S 1 +#define AR_PHY_RADAR_0_PRSSI 0x00000FC0 /* Pulse rssi threshold */ +#define AR_PHY_RADAR_0_PRSSI_S 6 +#define AR_PHY_RADAR_0_HEIGHT 0x0003F000 /* Pulse height threshold */ +#define AR_PHY_RADAR_0_HEIGHT_S 12 +#define AR_PHY_RADAR_0_RRSSI 0x00FC0000 /* Radar rssi threshold */ +#define AR_PHY_RADAR_0_RRSSI_S 18 +#define AR_PHY_RADAR_0_FIRPWR 0x7F000000 /* Radar firpwr threshold */ +#define AR_PHY_RADAR_0_FIRPWR_S 24 + + +#define AR_PHY_SIGMA_DELTA 0x996C /* AR5312 only */ +#define AR_PHY_SIGMA_DELTA_ADC_SEL 0x00000003 +#define AR_PHY_SIGMA_DELTA_ADC_SEL_S 0 +#define AR_PHY_SIGMA_DELTA_FILT2 0x000000F8 +#define AR_PHY_SIGMA_DELTA_FILT2_S 3 +#define AR_PHY_SIGMA_DELTA_FILT1 0x00001F00 +#define AR_PHY_SIGMA_DELTA_FILT1_S 8 +#define AR_PHY_SIGMA_DELTA_ADC_CLIP 0x01FFE000 +#define AR_PHY_SIGMA_DELTA_ADC_CLIP_S 13 + +#define AR_PHY_RESTART 0x9970 /* restart */ +#define AR_PHY_RESTART_DIV_GC 0x001C0000 /* bb_ant_fast_div_gc_limit */ +#define AR_PHY_RESTART_DIV_GC_S 18 + +#define AR_PHY_RFBUS_REQ 0x997C +#define AR_PHY_RFBUS_REQ_REQUEST 0x00000001 + +#define AR_PHY_TIMING7 0x9980 /* Spur mitigation masks */ +#define AR_PHY_TIMING8 0x9984 +#define AR_PHY_TIMING8_PILOT_MASK_2 0x000FFFFF +#define AR_PHY_TIMING8_PILOT_MASK_2_S 0 + +#define AR_PHY_BIN_MASK2_1 0x9988 +#define AR_PHY_BIN_MASK2_2 0x998c +#define AR_PHY_BIN_MASK2_3 0x9990 +#define AR_PHY_BIN_MASK2_4 0x9994 +#define AR_PHY_BIN_MASK2_4_MASK_4 0x00003FFF +#define AR_PHY_BIN_MASK2_4_MASK_4_S 0 + +#define AR_PHY_TIMING9 0x9998 +#define AR_PHY_TIMING10 0x999c +#define AR_PHY_TIMING10_PILOT_MASK_2 0x000FFFFF +#define AR_PHY_TIMING10_PILOT_MASK_2_S 0 + +#define AR_PHY_TIMING11 0x99a0 /* Spur Mitigation control */ +#define AR_PHY_TIMING11_SPUR_DELTA_PHASE 0x000FFFFF +#define AR_PHY_TIMING11_SPUR_DELTA_PHASE_S 0 +#define AR_PHY_TIMING11_SPUR_FREQ_SD 0x3FF00000 +#define AR_PHY_TIMING11_SPUR_FREQ_SD_S 20 +#define AR_PHY_TIMING11_USE_SPUR_IN_AGC 0x40000000 +#define AR_PHY_TIMING11_USE_SPUR_IN_SELFCOR 0x80000000 + +#define AR_PHY_HEAVY_CLIP_ENABLE 0x99E0 + +#define AR_PHY_M_SLEEP 0x99f0 /* sleep control registers */ +#define AR_PHY_REFCLKDLY 0x99f4 +#define AR_PHY_REFCLKPD 0x99f8 + +/* PHY IQ calibration results */ +#define AR_PHY_IQCAL_RES_PWR_MEAS_I 0x9c10 /* power measurement for I */ +#define AR_PHY_IQCAL_RES_PWR_MEAS_Q 0x9c14 /* power measurement for Q */ +#define AR_PHY_IQCAL_RES_IQ_CORR_MEAS 0x9c18 /* IQ correlation measurement */ + +#define AR_PHY_CURRENT_RSSI 0x9c1c /* rssi of current frame rx'd */ + +#define AR_PHY_RFBUS_GNT 0x9c20 +#define AR_PHY_RFBUS_GNT_GRANT 0x1 + +#define AR_PHY_PCDAC_TX_POWER_0 0xA180 +#define AR_PHY_PCDAC_TX_POWER(_n) (AR_PHY_PCDAC_TX_POWER_0 + ((_n)<<2)) + +#define AR_PHY_MODE 0xA200 /* Mode register */ +#define AR_PHY_MODE_QUARTER 0x40 /* Quarter Rate */ +#define AR_PHY_MODE_HALF 0x20 /* Half Rate */ +#define AR_PHY_MODE_AR5112 0x08 /* AR5112 */ +#define AR_PHY_MODE_AR5111 0x00 /* AR5111/AR2111 */ +#define AR_PHY_MODE_DYNAMIC 0x04 /* dynamic CCK/OFDM mode */ +#define AR_PHY_MODE_RF2GHZ 0x02 /* 2.4 GHz */ +#define AR_PHY_MODE_RF5GHZ 0x00 /* 5 GHz */ +#define AR_PHY_MODE_CCK 0x01 /* CCK */ +#define AR_PHY_MODE_OFDM 0x00 /* OFDM */ +#define AR_PHY_MODE_DYN_CCK_DISABLE 0x100 /* Disable dynamic CCK detection */ + +#define AR_PHY_CCK_TX_CTRL 0xA204 +#define AR_PHY_CCK_TX_CTRL_JAPAN 0x00000010 + +#define AR_PHY_CCK_DETECT 0xA208 +#define AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK 0x0000003F +#define AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK_S 0 +#define AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV 0x2000 + +#define AR_PHY_GAIN_2GHZ 0xA20C +#define AR_PHY_GAIN_2GHZ_RXTX_MARGIN 0x00FC0000 +#define AR_PHY_GAIN_2GHZ_RXTX_MARGIN_S 18 + +#define AR_PHY_CCK_RXCTRL4 0xA21C +#define AR_PHY_CCK_RXCTRL4_FREQ_EST_SHORT 0x01F80000 +#define AR_PHY_CCK_RXCTRL4_FREQ_EST_SHORT_S 19 + +#define AR_PHY_DAG_CTRLCCK 0xA228 +#define AR_PHY_DAG_CTRLCCK_EN_RSSI_THR 0x00000200 /* BB Rev 4.2+ only */ +#define AR_PHY_DAG_CTRLCCK_RSSI_THR 0x0001FC00 /* BB Rev 4.2+ only */ +#define AR_PHY_DAG_CTRLCCK_RSSI_THR_S 10 /* BB Rev 4.2+ only */ + +#define AR_PHY_POWER_TX_RATE3 0xA234 +#define AR_PHY_POWER_TX_RATE4 0xA238 + +#define AR_PHY_FAST_ADC 0xA24C +#define AR_PHY_BLUETOOTH 0xA254 + +#define AR_PHY_TPCRG1 0xA258 /* ar2413 power control */ +#define AR_PHY_TPCRG1_NUM_PD_GAIN 0x0000c000 +#define AR_PHY_TPCRG1_NUM_PD_GAIN_S 14 +#define AR_PHY_TPCRG1_PDGAIN_SETTING1 0x00030000 +#define AR_PHY_TPCRG1_PDGAIN_SETTING1_S 16 +#define AR_PHY_TPCRG1_PDGAIN_SETTING2 0x000c0000 +#define AR_PHY_TPCRG1_PDGAIN_SETTING2_S 18 +#define AR_PHY_TPCRG1_PDGAIN_SETTING3 0x00300000 +#define AR_PHY_TPCRG1_PDGAIN_SETTING3_S 20 + +#define AR_PHY_TPCRG5 0xA26C /* ar2413 power control */ +#define AR_PHY_TPCRG5_PD_GAIN_OVERLAP 0x0000000F +#define AR_PHY_TPCRG5_PD_GAIN_OVERLAP_S 0 +#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1 0x000003F0 +#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1_S 4 +#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2 0x0000FC00 +#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2_S 10 +#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3 0x003F0000 +#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3_S 16 +#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4 0x0FC00000 +#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4_S 22 + +#endif /* _DEV_ATH_AR5212PHY_H_ */ --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5212/ar5212_reset.c 2009-03-23 17:36:55.000000000 +0000 @@ -0,0 +1,2659 @@ +/* + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2008 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ar5212_reset.c,v 1.1 2009/03/23 17:14:48 sborrill Exp $ + */ +#include "opt_ah.h" + +#include "ah.h" +#include "ah_internal.h" +#include "ah_devid.h" + +#include "ar5212/ar5212.h" +#include "ar5212/ar5212reg.h" +#include "ar5212/ar5212phy.h" + +#include "ah_eeprom_v3.h" + +/* Additional Time delay to wait after activiting the Base band */ +#define BASE_ACTIVATE_DELAY 100 /* 100 usec */ +#define PLL_SETTLE_DELAY 300 /* 300 usec */ + +static HAL_BOOL ar5212SetResetReg(struct ath_hal *, uint32_t resetMask); +/* NB: public for 5312 use */ +HAL_BOOL ar5212IsSpurChannel(struct ath_hal *, HAL_CHANNEL *); +HAL_BOOL ar5212ChannelChange(struct ath_hal *, HAL_CHANNEL *); +int16_t ar5212GetNf(struct ath_hal *, HAL_CHANNEL_INTERNAL *); +HAL_BOOL ar5212SetBoardValues(struct ath_hal *, HAL_CHANNEL_INTERNAL *); +void ar5212SetDeltaSlope(struct ath_hal *, HAL_CHANNEL *); +HAL_BOOL ar5212SetTransmitPower(struct ath_hal *ah, + HAL_CHANNEL_INTERNAL *chan, uint16_t *rfXpdGain); +static HAL_BOOL ar5212SetRateTable(struct ath_hal *, + HAL_CHANNEL *, int16_t tpcScaleReduction, int16_t powerLimit, + HAL_BOOL commit, int16_t *minPower, int16_t *maxPower); +static void ar5212CorrectGainDelta(struct ath_hal *, int twiceOfdmCckDelta); +static void ar5212GetTargetPowers(struct ath_hal *, HAL_CHANNEL *, + const TRGT_POWER_INFO *pPowerInfo, uint16_t numChannels, + TRGT_POWER_INFO *pNewPower); +static uint16_t ar5212GetMaxEdgePower(uint16_t channel, + const RD_EDGES_POWER *pRdEdgesPower); +void ar5212SetRateDurationTable(struct ath_hal *, HAL_CHANNEL *); +void ar5212SetIFSTiming(struct ath_hal *, HAL_CHANNEL *); + +/* NB: public for RF backend use */ +void ar5212GetLowerUpperValues(uint16_t value, + uint16_t *pList, uint16_t listSize, + uint16_t *pLowerValue, uint16_t *pUpperValue); +void ar5212ModifyRfBuffer(uint32_t *rfBuf, uint32_t reg32, + uint32_t numBits, uint32_t firstBit, uint32_t column); + +static int +write_common(struct ath_hal *ah, const HAL_INI_ARRAY *ia, + HAL_BOOL bChannelChange, int writes) +{ +#define IS_NO_RESET_TIMER_ADDR(x) \ + ( (((x) >= AR_BEACON) && ((x) <= AR_CFP_DUR)) || \ + (((x) >= AR_SLEEP1) && ((x) <= AR_SLEEP3))) +#define V(r, c) (ia)->data[((r)*(ia)->cols) + (c)] + int r; + + /* Write Common Array Parameters */ + for (r = 0; r < ia->rows; r++) { + uint32_t reg = V(r, 0); + /* XXX timer/beacon setup registers? */ + /* On channel change, don't reset the PCU registers */ + if (!(bChannelChange && IS_NO_RESET_TIMER_ADDR(reg))) { + OS_REG_WRITE(ah, reg, V(r, 1)); + DMA_YIELD(writes); + } + } + return writes; +#undef IS_NO_RESET_TIMER_ADDR +#undef V +} + +#define IS_DISABLE_FAST_ADC_CHAN(x) (((x) == 2462) || ((x) == 2467)) + +/* + * Places the device in and out of reset and then places sane + * values in the registers based on EEPROM config, initialization + * vectors (as determined by the mode), and station configuration + * + * bChannelChange is used to preserve DMA/PCU registers across + * a HW Reset during channel change. + */ +HAL_BOOL +ar5212Reset(struct ath_hal *ah, HAL_OPMODE opmode, + HAL_CHANNEL *chan, HAL_BOOL bChannelChange, HAL_STATUS *status) +{ +#define N(a) (sizeof (a) / sizeof (a[0])) +#define FAIL(_code) do { ecode = _code; goto bad; } while (0) + struct ath_hal_5212 *ahp = AH5212(ah); + HAL_CHANNEL_INTERNAL *ichan = AH_NULL; + const HAL_EEPROM *ee; + uint32_t softLedCfg, softLedState; + uint32_t saveFrameSeqCount, saveDefAntenna, saveLedState; + uint32_t macStaId1, synthDelay, txFrm2TxDStart; + uint16_t rfXpdGain[MAX_NUM_PDGAINS_PER_CHANNEL]; + int16_t cckOfdmPwrDelta = 0; + u_int modesIndex, freqIndex; + HAL_STATUS ecode; + int i, regWrites; + uint32_t testReg, powerVal; + int8_t twiceAntennaGain, twiceAntennaReduction; + uint32_t ackTpcPow, ctsTpcPow, chirpTpcPow; + HAL_BOOL isBmode = AH_FALSE; + HAL_BOOL ichan_isBmode = AH_FALSE; + + HALASSERT(ah->ah_magic == AR5212_MAGIC); + ee = AH_PRIVATE(ah)->ah_eeprom; + + OS_MARK(ah, AH_MARK_RESET, bChannelChange); +#define IS(_c,_f) (((_c)->channelFlags & _f) || 0) + if ((IS(chan, CHANNEL_2GHZ) ^ IS(chan, CHANNEL_5GHZ)) == 0) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: invalid channel %u/0x%x; not marked as 2GHz or 5GHz\n", + __func__, chan->channel, chan->channelFlags); + FAIL(HAL_EINVAL); + } + if ((IS(chan, CHANNEL_OFDM) ^ IS(chan, CHANNEL_CCK)) == 0) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: invalid channel %u/0x%x; not marked as OFDM or CCK\n", + __func__, chan->channel, chan->channelFlags); + FAIL(HAL_EINVAL); + } +#undef IS + + /* Bring out of sleep mode */ + if (!ar5212SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE)) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: chip did not wakeup\n", + __func__); + FAIL(HAL_EIO); + } + + /* + * Map public channel to private. + */ + ichan = ath_hal_checkchannel(ah, chan); + if (ichan == AH_NULL) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: invalid channel %u/0x%x; no mapping\n", + __func__, chan->channel, chan->channelFlags); + FAIL(HAL_EINVAL); + } + switch (opmode) { + case HAL_M_STA: + case HAL_M_IBSS: + case HAL_M_HOSTAP: + case HAL_M_MONITOR: + break; + default: + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid operating mode %u\n", + __func__, opmode); + FAIL(HAL_EINVAL); + break; + } + HALASSERT(AH_PRIVATE(ah)->ah_eeversion >= AR_EEPROM_VER3); + + SAVE_CCK(ah, ichan, ichan_isBmode); + SAVE_CCK(ah, chan, isBmode); + + /* Preserve certain DMA hardware registers on a channel change */ + if (bChannelChange) { + /* + * On Venice, the TSF is almost preserved across a reset; + * it requires doubling writes to the RESET_TSF + * bit in the AR_BEACON register; it also has the quirk + * of the TSF going back in time on the station (station + * latches onto the last beacon's tsf during a reset 50% + * of the times); the latter is not a problem for adhoc + * stations since as long as the TSF is behind, it will + * get resynchronized on receiving the next beacon; the + * TSF going backwards in time could be a problem for the + * sleep operation (supported on infrastructure stations + * only) - the best and most general fix for this situation + * is to resynchronize the various sleep/beacon timers on + * the receipt of the next beacon i.e. when the TSF itself + * gets resynchronized to the AP's TSF - power save is + * needed to be temporarily disabled until that time + * + * Need to save the sequence number to restore it after + * the reset! + */ + saveFrameSeqCount = OS_REG_READ(ah, AR_D_SEQNUM); + } else + saveFrameSeqCount = 0; /* NB: silence compiler */ +#if 0 + /* + * XXX disable for now; this appears to sometimes cause OFDM + * XXX timing error floods when ani is enabled and bg scanning + * XXX kicks in + */ + /* If the channel change is across the same mode - perform a fast channel change */ + if (IS_2413(ah) || IS_5413(ah)) { + /* + * Fast channel change can only be used when: + * -channel change requested - so it's not the initial reset. + * -it's not a change to the current channel - + * often called when switching modes on a channel + * -the modes of the previous and requested channel are the + * same + * XXX opmode shouldn't change either? + */ + if (bChannelChange && + (AH_PRIVATE(ah)->ah_curchan != AH_NULL) && + (chan->channel != AH_PRIVATE(ah)->ah_curchan->channel) && + ((chan->channelFlags & CHANNEL_ALL) == + (AH_PRIVATE(ah)->ah_curchan->channelFlags & CHANNEL_ALL))) { + if (ar5212ChannelChange(ah, chan)) { + /* If ChannelChange completed - skip the rest of reset */ + /* XXX ani? */ + return AH_TRUE; + } + } + } +#endif + /* + * Preserve the antenna on a channel change + */ + saveDefAntenna = OS_REG_READ(ah, AR_DEF_ANTENNA); + if (saveDefAntenna == 0) /* XXX magic constants */ + saveDefAntenna = 1; + + /* Save hardware flag before chip reset clears the register */ + macStaId1 = OS_REG_READ(ah, AR_STA_ID1) & + (AR_STA_ID1_BASE_RATE_11B | AR_STA_ID1_USE_DEFANT); + + /* Save led state from pci config register */ + saveLedState = OS_REG_READ(ah, AR_PCICFG) & + (AR_PCICFG_LEDCTL | AR_PCICFG_LEDMODE | AR_PCICFG_LEDBLINK | + AR_PCICFG_LEDSLOW); + softLedCfg = OS_REG_READ(ah, AR_GPIOCR); + softLedState = OS_REG_READ(ah, AR_GPIODO); + + ar5212RestoreClock(ah, opmode); /* move to refclk operation */ + + /* + * Adjust gain parameters before reset if + * there's an outstanding gain updated. + */ + (void) ar5212GetRfgain(ah); + + if (!ar5212ChipReset(ah, chan)) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: chip reset failed\n", __func__); + FAIL(HAL_EIO); + } + + /* Setup the indices for the next set of register array writes */ + switch (chan->channelFlags & CHANNEL_ALL) { + case CHANNEL_A: + modesIndex = 1; + freqIndex = 1; + break; + case CHANNEL_T: + modesIndex = 2; + freqIndex = 1; + break; + case CHANNEL_B: + modesIndex = 3; + freqIndex = 2; + break; + case CHANNEL_PUREG: + modesIndex = 4; + freqIndex = 2; + break; + case CHANNEL_108G: + modesIndex = 5; + freqIndex = 2; + break; + default: + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel flags 0x%x\n", + __func__, chan->channelFlags); + FAIL(HAL_EINVAL); + } + + OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__); + + /* Set correct Baseband to analog shift setting to access analog chips. */ + OS_REG_WRITE(ah, AR_PHY(0), 0x00000007); + + regWrites = ath_hal_ini_write(ah, &ahp->ah_ini_modes, modesIndex, 0); + regWrites = write_common(ah, &ahp->ah_ini_common, bChannelChange, + regWrites); + ahp->ah_rfHal->writeRegs(ah, modesIndex, freqIndex, regWrites); + + OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__); + + if (IS_CHAN_HALF_RATE(chan) || IS_CHAN_QUARTER_RATE(chan)) { + ar5212SetIFSTiming(ah, chan); + if (IS_5413(ah)) { + /* + * Force window_length for 1/2 and 1/4 rate channels, + * the ini file sets this to zero otherwise. + */ + OS_REG_RMW_FIELD(ah, AR_PHY_FRAME_CTL, + AR_PHY_FRAME_CTL_WINLEN, 3); + } + } + + /* Overwrite INI values for revised chipsets */ + if (AH_PRIVATE(ah)->ah_phyRev >= AR_PHY_CHIP_ID_REV_2) { + /* ADC_CTL */ + OS_REG_WRITE(ah, AR_PHY_ADC_CTL, + SM(2, AR_PHY_ADC_CTL_OFF_INBUFGAIN) | + SM(2, AR_PHY_ADC_CTL_ON_INBUFGAIN) | + AR_PHY_ADC_CTL_OFF_PWDDAC | + AR_PHY_ADC_CTL_OFF_PWDADC); + + /* TX_PWR_ADJ */ + if (chan->channel == 2484) { + cckOfdmPwrDelta = SCALE_OC_DELTA( + ee->ee_cckOfdmPwrDelta - + ee->ee_scaledCh14FilterCckDelta); + } else { + cckOfdmPwrDelta = SCALE_OC_DELTA( + ee->ee_cckOfdmPwrDelta); + } + + if (IS_CHAN_G(chan)) { + OS_REG_WRITE(ah, AR_PHY_TXPWRADJ, + SM((ee->ee_cckOfdmPwrDelta*-1), + AR_PHY_TXPWRADJ_CCK_GAIN_DELTA) | + SM((cckOfdmPwrDelta*-1), + AR_PHY_TXPWRADJ_CCK_PCDAC_INDEX)); + } else { + OS_REG_WRITE(ah, AR_PHY_TXPWRADJ, 0); + } + + /* Add barker RSSI thresh enable as disabled */ + OS_REG_CLR_BIT(ah, AR_PHY_DAG_CTRLCCK, + AR_PHY_DAG_CTRLCCK_EN_RSSI_THR); + OS_REG_RMW_FIELD(ah, AR_PHY_DAG_CTRLCCK, + AR_PHY_DAG_CTRLCCK_RSSI_THR, 2); + + /* Set the mute mask to the correct default */ + OS_REG_WRITE(ah, AR_SEQ_MASK, 0x0000000F); + } + + if (AH_PRIVATE(ah)->ah_phyRev >= AR_PHY_CHIP_ID_REV_3) { + /* Clear reg to alllow RX_CLEAR line debug */ + OS_REG_WRITE(ah, AR_PHY_BLUETOOTH, 0); + } + if (AH_PRIVATE(ah)->ah_phyRev >= AR_PHY_CHIP_ID_REV_4) { +#ifdef notyet + /* Enable burst prefetch for the data queues */ + OS_REG_RMW_FIELD(ah, AR_D_FPCTL, ... ); + /* Enable double-buffering */ + OS_REG_CLR_BIT(ah, AR_TXCFG, AR_TXCFG_DBL_BUF_DIS); +#endif + } + + /* Set ADC/DAC select values */ + OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0e); + + if (IS_5413(ah) || IS_2417(ah)) { + uint32_t newReg=1; + if (IS_DISABLE_FAST_ADC_CHAN(chan->channel)) + newReg = 0; + /* As it's a clock changing register, only write when the value needs to be changed */ + if (OS_REG_READ(ah, AR_PHY_FAST_ADC) != newReg) + OS_REG_WRITE(ah, AR_PHY_FAST_ADC, newReg); + } + + /* Setup the transmit power values. */ + if (!ar5212SetTransmitPower(ah, ichan, rfXpdGain)) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: error init'ing transmit power\n", __func__); + FAIL(HAL_EIO); + } + + /* Write the analog registers */ + if (!ahp->ah_rfHal->setRfRegs(ah, ichan, modesIndex, rfXpdGain)) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: ar5212SetRfRegs failed\n", + __func__); + FAIL(HAL_EIO); + } + + /* Write delta slope for OFDM enabled modes (A, G, Turbo) */ + if (IS_CHAN_OFDM(chan)) { + if ((IS_5413(ah) || (AH_PRIVATE(ah)->ah_eeversion >= AR_EEPROM_VER5_3)) && + (!IS_CHAN_B(chan))) + ar5212SetSpurMitigation(ah, ichan); + ar5212SetDeltaSlope(ah, chan); + } + + /* Setup board specific options for EEPROM version 3 */ + if (!ar5212SetBoardValues(ah, ichan)) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: error setting board options\n", __func__); + FAIL(HAL_EIO); + } + + /* Restore certain DMA hardware registers on a channel change */ + if (bChannelChange) + OS_REG_WRITE(ah, AR_D_SEQNUM, saveFrameSeqCount); + + OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__); + + OS_REG_WRITE(ah, AR_STA_ID0, LE_READ_4(ahp->ah_macaddr)); + OS_REG_WRITE(ah, AR_STA_ID1, LE_READ_2(ahp->ah_macaddr + 4) + | macStaId1 + | AR_STA_ID1_RTS_USE_DEF + | ahp->ah_staId1Defaults + ); + ar5212SetOperatingMode(ah, opmode); + + /* Set Venice BSSID mask according to current state */ + OS_REG_WRITE(ah, AR_BSSMSKL, LE_READ_4(ahp->ah_bssidmask)); + OS_REG_WRITE(ah, AR_BSSMSKU, LE_READ_2(ahp->ah_bssidmask + 4)); + + /* Restore previous led state */ + OS_REG_WRITE(ah, AR_PCICFG, OS_REG_READ(ah, AR_PCICFG) | saveLedState); + + /* Restore soft Led state to GPIO */ + OS_REG_WRITE(ah, AR_GPIOCR, softLedCfg); + OS_REG_WRITE(ah, AR_GPIODO, softLedState); + + /* Restore previous antenna */ + OS_REG_WRITE(ah, AR_DEF_ANTENNA, saveDefAntenna); + + /* then our BSSID */ + OS_REG_WRITE(ah, AR_BSS_ID0, LE_READ_4(ahp->ah_bssid)); + OS_REG_WRITE(ah, AR_BSS_ID1, LE_READ_2(ahp->ah_bssid + 4)); + + /* Restore bmiss rssi & count thresholds */ + OS_REG_WRITE(ah, AR_RSSI_THR, ahp->ah_rssiThr); + + OS_REG_WRITE(ah, AR_ISR, ~0); /* cleared on write */ + + if (!ar5212SetChannel(ah, ichan)) + FAIL(HAL_EIO); + + OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__); + + ar5212SetCoverageClass(ah, AH_PRIVATE(ah)->ah_coverageClass, 1); + + ar5212SetRateDurationTable(ah, chan); + + /* Set Tx frame start to tx data start delay */ + if (IS_RAD5112_ANY(ah) && + (IS_CHAN_HALF_RATE(AH_PRIVATE(ah)->ah_curchan) || + IS_CHAN_QUARTER_RATE(AH_PRIVATE(ah)->ah_curchan))) { + txFrm2TxDStart = + (IS_CHAN_HALF_RATE(AH_PRIVATE(ah)->ah_curchan)) ? + TX_FRAME_D_START_HALF_RATE: + TX_FRAME_D_START_QUARTER_RATE; + OS_REG_RMW_FIELD(ah, AR_PHY_TX_CTL, + AR_PHY_TX_FRAME_TO_TX_DATA_START, txFrm2TxDStart); + } + + /* + * Setup fast diversity. + * Fast diversity can be enabled or disabled via regadd.txt. + * Default is enabled. + * For reference, + * Disable: reg val + * 0x00009860 0x00009d18 (if 11a / 11g, else no change) + * 0x00009970 0x192bb514 + * 0x0000a208 0xd03e4648 + * + * Enable: 0x00009860 0x00009d10 (if 11a / 11g, else no change) + * 0x00009970 0x192fb514 + * 0x0000a208 0xd03e6788 + */ + + /* XXX Setup pre PHY ENABLE EAR additions */ + /* + * Wait for the frequency synth to settle (synth goes on + * via AR_PHY_ACTIVE_EN). Read the phy active delay register. + * Value is in 100ns increments. + */ + synthDelay = OS_REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY; + if (IS_CHAN_CCK(chan)) { + synthDelay = (4 * synthDelay) / 22; + } else { + synthDelay /= 10; + } + + /* Activate the PHY (includes baseband activate and synthesizer on) */ + OS_REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); + + /* + * There is an issue if the AP starts the calibration before + * the base band timeout completes. This could result in the + * rx_clear false triggering. As a workaround we add delay an + * extra BASE_ACTIVATE_DELAY usecs to ensure this condition + * does not happen. + */ + if (IS_CHAN_HALF_RATE(AH_PRIVATE(ah)->ah_curchan)) { + OS_DELAY((synthDelay << 1) + BASE_ACTIVATE_DELAY); + } else if (IS_CHAN_QUARTER_RATE(AH_PRIVATE(ah)->ah_curchan)) { + OS_DELAY((synthDelay << 2) + BASE_ACTIVATE_DELAY); + } else { + OS_DELAY(synthDelay + BASE_ACTIVATE_DELAY); + } + + /* + * The udelay method is not reliable with notebooks. + * Need to check to see if the baseband is ready + */ + testReg = OS_REG_READ(ah, AR_PHY_TESTCTRL); + /* Selects the Tx hold */ + OS_REG_WRITE(ah, AR_PHY_TESTCTRL, AR_PHY_TESTCTRL_TXHOLD); + i = 0; + while ((i++ < 20) && + (OS_REG_READ(ah, 0x9c24) & 0x10)) /* test if baseband not ready */ OS_DELAY(200); + OS_REG_WRITE(ah, AR_PHY_TESTCTRL, testReg); + + /* Calibrate the AGC and start a NF calculation */ + OS_REG_WRITE(ah, AR_PHY_AGC_CONTROL, + OS_REG_READ(ah, AR_PHY_AGC_CONTROL) + | AR_PHY_AGC_CONTROL_CAL + | AR_PHY_AGC_CONTROL_NF); + + if (!IS_CHAN_B(chan) && ahp->ah_bIQCalibration != IQ_CAL_DONE) { + /* Start IQ calibration w/ 2^(INIT_IQCAL_LOG_COUNT_MAX+1) samples */ + OS_REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4, + AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX, + INIT_IQCAL_LOG_COUNT_MAX); + OS_REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4, + AR_PHY_TIMING_CTRL4_DO_IQCAL); + ahp->ah_bIQCalibration = IQ_CAL_RUNNING; + } else + ahp->ah_bIQCalibration = IQ_CAL_INACTIVE; + + /* Setup compression registers */ + ar5212SetCompRegs(ah); + + /* Set 1:1 QCU to DCU mapping for all queues */ + for (i = 0; i < AR_NUM_DCU; i++) + OS_REG_WRITE(ah, AR_DQCUMASK(i), 1 << i); + + ahp->ah_intrTxqs = 0; + for (i = 0; i < AH_PRIVATE(ah)->ah_caps.halTotalQueues; i++) + ar5212ResetTxQueue(ah, i); + + /* + * Setup interrupt handling. Note that ar5212ResetTxQueue + * manipulates the secondary IMR's as queues are enabled + * and disabled. This is done with RMW ops to insure the + * settings we make here are preserved. + */ + ahp->ah_maskReg = AR_IMR_TXOK | AR_IMR_TXERR | AR_IMR_TXURN + | AR_IMR_RXOK | AR_IMR_RXERR | AR_IMR_RXORN + | AR_IMR_HIUERR + ; + if (opmode == HAL_M_HOSTAP) + ahp->ah_maskReg |= AR_IMR_MIB; + OS_REG_WRITE(ah, AR_IMR, ahp->ah_maskReg); + /* Enable bus errors that are OR'd to set the HIUERR bit */ + OS_REG_WRITE(ah, AR_IMR_S2, + OS_REG_READ(ah, AR_IMR_S2) + | AR_IMR_S2_MCABT | AR_IMR_S2_SSERR | AR_IMR_S2_DPERR); + + if (AH_PRIVATE(ah)->ah_rfkillEnabled) + ar5212EnableRfKill(ah); + + if (!ath_hal_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0)) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: offset calibration failed to complete in 1ms;" + " noisy environment?\n", __func__); + } + + /* + * Set clocks back to 32kHz if they had been using refClk, then + * use an external 32kHz crystal when sleeping, if one exists. + */ + ar5212SetupClock(ah, opmode); + + /* + * Writing to AR_BEACON will start timers. Hence it should + * be the last register to be written. Do not reset tsf, do + * not enable beacons at this point, but preserve other values + * like beaconInterval. + */ + OS_REG_WRITE(ah, AR_BEACON, + (OS_REG_READ(ah, AR_BEACON) &~ (AR_BEACON_EN | AR_BEACON_RESET_TSF))); + + /* XXX Setup post reset EAR additions */ + + /* QoS support */ + if (AH_PRIVATE(ah)->ah_macVersion > AR_SREV_VERSION_VENICE || + (AH_PRIVATE(ah)->ah_macVersion == AR_SREV_VERSION_VENICE && + AH_PRIVATE(ah)->ah_macRev >= AR_SREV_GRIFFIN_LITE)) { + OS_REG_WRITE(ah, AR_QOS_CONTROL, 0x100aa); /* XXX magic */ + OS_REG_WRITE(ah, AR_QOS_SELECT, 0x3210); /* XXX magic */ + } + + /* Turn on NOACK Support for QoS packets */ + OS_REG_WRITE(ah, AR_NOACK, + SM(2, AR_NOACK_2BIT_VALUE) | + SM(5, AR_NOACK_BIT_OFFSET) | + SM(0, AR_NOACK_BYTE_OFFSET)); + + /* Get Antenna Gain reduction */ + if (IS_CHAN_5GHZ(chan)) { + ath_hal_eepromGet(ah, AR_EEP_ANTGAINMAX_5, &twiceAntennaGain); + } else { + ath_hal_eepromGet(ah, AR_EEP_ANTGAINMAX_2, &twiceAntennaGain); + } + twiceAntennaReduction = + ath_hal_getantennareduction(ah, chan, twiceAntennaGain); + + /* TPC for self-generated frames */ + + ackTpcPow = MS(ahp->ah_macTPC, AR_TPC_ACK); + if ((ackTpcPow-ahp->ah_txPowerIndexOffset) > ichan->maxTxPower) + ackTpcPow = ichan->maxTxPower+ahp->ah_txPowerIndexOffset; + + if (ackTpcPow > (2*ichan->maxRegTxPower - twiceAntennaReduction)) + ackTpcPow = (2*ichan->maxRegTxPower - twiceAntennaReduction) + + ahp->ah_txPowerIndexOffset; + + ctsTpcPow = MS(ahp->ah_macTPC, AR_TPC_CTS); + if ((ctsTpcPow-ahp->ah_txPowerIndexOffset) > ichan->maxTxPower) + ctsTpcPow = ichan->maxTxPower+ahp->ah_txPowerIndexOffset; + + if (ctsTpcPow > (2*ichan->maxRegTxPower - twiceAntennaReduction)) + ctsTpcPow = (2*ichan->maxRegTxPower - twiceAntennaReduction) + + ahp->ah_txPowerIndexOffset; + + chirpTpcPow = MS(ahp->ah_macTPC, AR_TPC_CHIRP); + if ((chirpTpcPow-ahp->ah_txPowerIndexOffset) > ichan->maxTxPower) + chirpTpcPow = ichan->maxTxPower+ahp->ah_txPowerIndexOffset; + + if (chirpTpcPow > (2*ichan->maxRegTxPower - twiceAntennaReduction)) + chirpTpcPow = (2*ichan->maxRegTxPower - twiceAntennaReduction) + + ahp->ah_txPowerIndexOffset; + + if (ackTpcPow > 63) + ackTpcPow = 63; + if (ctsTpcPow > 63) + ctsTpcPow = 63; + if (chirpTpcPow > 63) + chirpTpcPow = 63; + + powerVal = SM(ackTpcPow, AR_TPC_ACK) | + SM(ctsTpcPow, AR_TPC_CTS) | + SM(chirpTpcPow, AR_TPC_CHIRP); + + OS_REG_WRITE(ah, AR_TPC, powerVal); + + /* Restore user-specified settings */ + if (ahp->ah_miscMode != 0) + OS_REG_WRITE(ah, AR_MISC_MODE, ahp->ah_miscMode); + if (ahp->ah_sifstime != (u_int) -1) + ar5212SetSifsTime(ah, ahp->ah_sifstime); + if (ahp->ah_slottime != (u_int) -1) + ar5212SetSlotTime(ah, ahp->ah_slottime); + if (ahp->ah_acktimeout != (u_int) -1) + ar5212SetAckTimeout(ah, ahp->ah_acktimeout); + if (ahp->ah_ctstimeout != (u_int) -1) + ar5212SetCTSTimeout(ah, ahp->ah_ctstimeout); + if (AH_PRIVATE(ah)->ah_diagreg != 0) + OS_REG_WRITE(ah, AR_DIAG_SW, AH_PRIVATE(ah)->ah_diagreg); + + AH_PRIVATE(ah)->ah_opmode = opmode; /* record operating mode */ + + if (bChannelChange) { + if (!(ichan->privFlags & CHANNEL_DFS)) + ichan->privFlags &= ~CHANNEL_INTERFERENCE; + chan->channelFlags = ichan->channelFlags; + chan->privFlags = ichan->privFlags; + chan->maxRegTxPower = ichan->maxRegTxPower; + chan->maxTxPower = ichan->maxTxPower; + chan->minTxPower = ichan->minTxPower; + } + + HALDEBUG(ah, HAL_DEBUG_RESET, "%s: done\n", __func__); + + RESTORE_CCK(ah, ichan, ichan_isBmode); + RESTORE_CCK(ah, chan, isBmode); + + OS_MARK(ah, AH_MARK_RESET_DONE, 0); + + return AH_TRUE; +bad: + if (ichan != AH_NULL) + RESTORE_CCK(ah, ichan, ichan_isBmode); + RESTORE_CCK(ah, chan, isBmode); + + OS_MARK(ah, AH_MARK_RESET_DONE, ecode); + if (*status) + *status = ecode; + return AH_FALSE; +#undef FAIL +#undef N +} + +/* + * Call the rf backend to change the channel. + */ +HAL_BOOL +ar5212SetChannel(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + + /* Change the synth */ + if (!ahp->ah_rfHal->setChannel(ah, chan)) + return AH_FALSE; + return AH_TRUE; +} + +/* + * This channel change evaluates whether the selected hardware can + * perform a synthesizer-only channel change (no reset). If the + * TX is not stopped, or the RFBus cannot be granted in the given + * time, the function returns false as a reset is necessary + */ +HAL_BOOL +ar5212ChannelChange(struct ath_hal *ah, HAL_CHANNEL *chan) +{ + uint32_t ulCount; + uint32_t data, synthDelay, qnum; + uint16_t rfXpdGain[MAX_NUM_PDGAINS_PER_CHANNEL]; + HAL_BOOL txStopped = AH_TRUE; + HAL_CHANNEL_INTERNAL *ichan; + + /* + * Map public channel to private. + */ + ichan = ath_hal_checkchannel(ah, chan); + + /* TX must be stopped or RF Bus grant will not work */ + for (qnum = 0; qnum < AH_PRIVATE(ah)->ah_caps.halTotalQueues; qnum++) { + if (ar5212NumTxPending(ah, qnum)) { + txStopped = AH_FALSE; + break; + } + } + if (!txStopped) + return AH_FALSE; + + /* Kill last Baseband Rx Frame */ + OS_REG_WRITE(ah, AR_PHY_RFBUS_REQ, AR_PHY_RFBUS_REQ_REQUEST); /* Request analog bus grant */ + for (ulCount = 0; ulCount < 100; ulCount++) { + if (OS_REG_READ(ah, AR_PHY_RFBUS_GNT)) + break; + OS_DELAY(5); + } + if (ulCount >= 100) + return AH_FALSE; + + /* Change the synth */ + if (!ar5212SetChannel(ah, ichan)) + return AH_FALSE; + + /* + * Wait for the frequency synth to settle (synth goes on via PHY_ACTIVE_EN). + * Read the phy active delay register. Value is in 100ns increments. + */ + data = OS_REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY; + if (IS_CHAN_CCK(ichan)) { + synthDelay = (4 * data) / 22; + } else { + synthDelay = data / 10; + } + OS_DELAY(synthDelay + BASE_ACTIVATE_DELAY); + + /* Setup the transmit power values. */ + if (!ar5212SetTransmitPower(ah, ichan, rfXpdGain)) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: error init'ing transmit power\n", __func__); + return AH_FALSE; + } + + /* Write delta slope for OFDM enabled modes (A, G, Turbo) */ + if (IS_CHAN_OFDM(ichan)) { + if ((IS_5413(ah) || (AH_PRIVATE(ah)->ah_eeversion >= AR_EEPROM_VER5_3)) && + (!IS_CHAN_B(chan))) + ar5212SetSpurMitigation(ah, ichan); + ar5212SetDeltaSlope(ah, chan); + } + + /* Release the RFBus Grant */ + OS_REG_WRITE(ah, AR_PHY_RFBUS_REQ, 0); + + /* Start Noise Floor Cal */ + OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); + + if (!(ichan->privFlags & CHANNEL_DFS)) + ichan->privFlags &= ~CHANNEL_INTERFERENCE; + chan->channelFlags = ichan->channelFlags; + chan->privFlags = ichan->privFlags; + chan->maxRegTxPower = ichan->maxRegTxPower; + chan->maxTxPower = ichan->maxTxPower; + chan->minTxPower = ichan->minTxPower; + return AH_TRUE; +} + +void +ar5212SetOperatingMode(struct ath_hal *ah, int opmode) +{ + uint32_t val; + + val = OS_REG_READ(ah, AR_STA_ID1); + val &= ~(AR_STA_ID1_STA_AP | AR_STA_ID1_ADHOC); + switch (opmode) { + case HAL_M_HOSTAP: + OS_REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_STA_AP + | AR_STA_ID1_KSRCH_MODE); + OS_REG_CLR_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION); + break; + case HAL_M_IBSS: + OS_REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_ADHOC + | AR_STA_ID1_KSRCH_MODE); + OS_REG_SET_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION); + break; + case HAL_M_STA: + case HAL_M_MONITOR: + OS_REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_KSRCH_MODE); + break; + } +} + +/* + * Places the PHY and Radio chips into reset. A full reset + * must be called to leave this state. The PCI/MAC/PCU are + * not placed into reset as we must receive interrupt to + * re-enable the hardware. + */ +HAL_BOOL +ar5212PhyDisable(struct ath_hal *ah) +{ + return ar5212SetResetReg(ah, AR_RC_BB); +} + +/* + * Places all of hardware into reset + */ +HAL_BOOL +ar5212Disable(struct ath_hal *ah) +{ + if (!ar5212SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE)) + return AH_FALSE; + /* + * Reset the HW - PCI must be reset after the rest of the + * device has been reset. + */ + return ar5212SetResetReg(ah, AR_RC_MAC | AR_RC_BB | AR_RC_PCI); +} + +/* + * Places the hardware into reset and then pulls it out of reset + * + * TODO: Only write the PLL if we're changing to or from CCK mode + * + * WARNING: The order of the PLL and mode registers must be correct. + */ +HAL_BOOL +ar5212ChipReset(struct ath_hal *ah, HAL_CHANNEL *chan) +{ + + OS_MARK(ah, AH_MARK_CHIPRESET, chan ? chan->channel : 0); + + /* + * Reset the HW - PCI must be reset after the rest of the + * device has been reset + */ + if (!ar5212SetResetReg(ah, AR_RC_MAC | AR_RC_BB | AR_RC_PCI)) + return AH_FALSE; + + /* Bring out of sleep mode (AGAIN) */ + if (!ar5212SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE)) + return AH_FALSE; + + /* Clear warm reset register */ + if (!ar5212SetResetReg(ah, 0)) + return AH_FALSE; + + /* + * Perform warm reset before the mode/PLL/turbo registers + * are changed in order to deactivate the radio. Mode changes + * with an active radio can result in corrupted shifts to the + * radio device. + */ + + /* + * Set CCK and Turbo modes correctly. + */ + if (chan != AH_NULL) { /* NB: can be null during attach */ + uint32_t rfMode, phyPLL = 0, curPhyPLL, turbo; + + if (IS_5413(ah)) { /* NB: =>'s 5424 also */ + rfMode = AR_PHY_MODE_AR5112; + if (IS_CHAN_HALF_RATE(chan)) + rfMode |= AR_PHY_MODE_HALF; + else if (IS_CHAN_QUARTER_RATE(chan)) + rfMode |= AR_PHY_MODE_QUARTER; + + if (IS_CHAN_CCK(chan) || IS_CHAN_G(chan)) + phyPLL = AR_PHY_PLL_CTL_44_5112; + else + phyPLL = AR_PHY_PLL_CTL_40_5413; + } else if (IS_RAD5111(ah)) { + rfMode = AR_PHY_MODE_AR5111; + if (IS_CHAN_CCK(chan) || IS_CHAN_G(chan)) + phyPLL = AR_PHY_PLL_CTL_44; + else + phyPLL = AR_PHY_PLL_CTL_40; + if (IS_CHAN_HALF_RATE(chan)) + phyPLL = AR_PHY_PLL_CTL_HALF; + else if (IS_CHAN_QUARTER_RATE(chan)) + phyPLL = AR_PHY_PLL_CTL_QUARTER; + } else { /* 5112, 2413, 2316, 2317 */ + rfMode = AR_PHY_MODE_AR5112; + if (IS_CHAN_CCK(chan) || IS_CHAN_G(chan)) + phyPLL = AR_PHY_PLL_CTL_44_5112; + else + phyPLL = AR_PHY_PLL_CTL_40_5112; + if (IS_CHAN_HALF_RATE(chan)) + phyPLL |= AR_PHY_PLL_CTL_HALF; + else if (IS_CHAN_QUARTER_RATE(chan)) + phyPLL |= AR_PHY_PLL_CTL_QUARTER; + } + if (IS_CHAN_OFDM(chan) && (IS_CHAN_CCK(chan) || + IS_CHAN_G(chan))) + rfMode |= AR_PHY_MODE_DYNAMIC; + else if (IS_CHAN_OFDM(chan)) + rfMode |= AR_PHY_MODE_OFDM; + else + rfMode |= AR_PHY_MODE_CCK; + if (IS_CHAN_5GHZ(chan)) + rfMode |= AR_PHY_MODE_RF5GHZ; + else + rfMode |= AR_PHY_MODE_RF2GHZ; + turbo = IS_CHAN_TURBO(chan) ? + (AR_PHY_FC_TURBO_MODE | AR_PHY_FC_TURBO_SHORT) : 0; + curPhyPLL = OS_REG_READ(ah, AR_PHY_PLL_CTL); + /* + * PLL, Mode, and Turbo values must be written in the correct + * order to ensure: + * - The PLL cannot be set to 44 unless the CCK or DYNAMIC + * mode bit is set + * - Turbo cannot be set at the same time as CCK or DYNAMIC + */ + if (IS_CHAN_CCK(chan) || IS_CHAN_G(chan)) { + OS_REG_WRITE(ah, AR_PHY_TURBO, turbo); + OS_REG_WRITE(ah, AR_PHY_MODE, rfMode); + if (curPhyPLL != phyPLL) { + OS_REG_WRITE(ah, AR_PHY_PLL_CTL, phyPLL); + /* Wait for the PLL to settle */ + OS_DELAY(PLL_SETTLE_DELAY); + } + } else { + if (curPhyPLL != phyPLL) { + OS_REG_WRITE(ah, AR_PHY_PLL_CTL, phyPLL); + /* Wait for the PLL to settle */ + OS_DELAY(PLL_SETTLE_DELAY); + } + OS_REG_WRITE(ah, AR_PHY_TURBO, turbo); + OS_REG_WRITE(ah, AR_PHY_MODE, rfMode); + } + } + return AH_TRUE; +} + +/* + * Recalibrate the lower PHY chips to account for temperature/environment + * changes. + */ +HAL_BOOL +ar5212PerCalibrationN(struct ath_hal *ah, HAL_CHANNEL *chan, u_int chainMask, + HAL_BOOL longCal, HAL_BOOL *isCalDone) +{ +#define IQ_CAL_TRIES 10 + struct ath_hal_5212 *ahp = AH5212(ah); + HAL_CHANNEL_INTERNAL *ichan; + int32_t qCoff, qCoffDenom; + int32_t iqCorrMeas, iCoff, iCoffDenom; + uint32_t powerMeasQ, powerMeasI; + HAL_BOOL ichan_isBmode = AH_FALSE; + HAL_BOOL isBmode = AH_FALSE; + + OS_MARK(ah, AH_MARK_PERCAL, chan->channel); + *isCalDone = AH_FALSE; + ichan = ath_hal_checkchannel(ah, chan); + if (ichan == AH_NULL) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: invalid channel %u/0x%x; no mapping\n", + __func__, chan->channel, chan->channelFlags); + return AH_FALSE; + } + SAVE_CCK(ah, ichan, ichan_isBmode); + SAVE_CCK(ah, chan, isBmode); + + if (ahp->ah_bIQCalibration == IQ_CAL_DONE || + ahp->ah_bIQCalibration == IQ_CAL_INACTIVE) + *isCalDone = AH_TRUE; + + /* IQ calibration in progress. Check to see if it has finished. */ + if (ahp->ah_bIQCalibration == IQ_CAL_RUNNING && + !(OS_REG_READ(ah, AR_PHY_TIMING_CTRL4) & AR_PHY_TIMING_CTRL4_DO_IQCAL)) { + int i; + + /* IQ Calibration has finished. */ + ahp->ah_bIQCalibration = IQ_CAL_INACTIVE; + *isCalDone = AH_TRUE; + + /* workaround for misgated IQ Cal results */ + i = 0; + do { + /* Read calibration results. */ + powerMeasI = OS_REG_READ(ah, AR_PHY_IQCAL_RES_PWR_MEAS_I); + powerMeasQ = OS_REG_READ(ah, AR_PHY_IQCAL_RES_PWR_MEAS_Q); + iqCorrMeas = OS_REG_READ(ah, AR_PHY_IQCAL_RES_IQ_CORR_MEAS); + if (powerMeasI && powerMeasQ) + break; + /* Do we really need this??? */ + OS_REG_WRITE (ah, AR_PHY_TIMING_CTRL4, + OS_REG_READ(ah, AR_PHY_TIMING_CTRL4) | + AR_PHY_TIMING_CTRL4_DO_IQCAL); + } while (++i < IQ_CAL_TRIES); + + /* + * Prescale these values to remove 64-bit operation + * requirement at the loss of a little precision. + */ + iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 128; + qCoffDenom = powerMeasQ / 128; + + /* Protect against divide-by-0 and loss of sign bits. */ + if (iCoffDenom != 0 && qCoffDenom >= 2) { + iCoff = (int8_t)(-iqCorrMeas) / iCoffDenom; + /* IQCORR_Q_I_COFF is a signed 6 bit number */ + if (iCoff < -32) { + iCoff = -32; + } else if (iCoff > 31) { + iCoff = 31; + } + + /* IQCORR_Q_Q_COFF is a signed 5 bit number */ + qCoff = (powerMeasI / qCoffDenom) - 128; + if (qCoff < -16) { + qCoff = -16; + } else if (qCoff > 15) { + qCoff = 15; + } + + HALDEBUG(ah, HAL_DEBUG_PERCAL, + "****************** MISGATED IQ CAL! *******************\n"); + HALDEBUG(ah, HAL_DEBUG_PERCAL, + "time = %d, i = %d, \n", OS_GETUPTIME(ah), i); + HALDEBUG(ah, HAL_DEBUG_PERCAL, + "powerMeasI = 0x%08x\n", powerMeasI); + HALDEBUG(ah, HAL_DEBUG_PERCAL, + "powerMeasQ = 0x%08x\n", powerMeasQ); + HALDEBUG(ah, HAL_DEBUG_PERCAL, + "iqCorrMeas = 0x%08x\n", iqCorrMeas); + HALDEBUG(ah, HAL_DEBUG_PERCAL, + "iCoff = %d\n", iCoff); + HALDEBUG(ah, HAL_DEBUG_PERCAL, + "qCoff = %d\n", qCoff); + + /* Write values and enable correction */ + OS_REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4, + AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF, iCoff); + OS_REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4, + AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF, qCoff); + OS_REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4, + AR_PHY_TIMING_CTRL4_IQCORR_ENABLE); + + ahp->ah_bIQCalibration = IQ_CAL_DONE; + ichan->iqCalValid = AH_TRUE; + ichan->iCoff = iCoff; + ichan->qCoff = qCoff; + } + } else if (!IS_CHAN_B(chan) && ahp->ah_bIQCalibration == IQ_CAL_DONE && + !ichan->iqCalValid) { + /* + * Start IQ calibration if configured channel has changed. + * Use a magic number of 15 based on default value. + */ + OS_REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4, + AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX, + INIT_IQCAL_LOG_COUNT_MAX); + OS_REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4, + AR_PHY_TIMING_CTRL4_DO_IQCAL); + ahp->ah_bIQCalibration = IQ_CAL_RUNNING; + } + /* XXX EAR */ + + if (longCal) { + /* Check noise floor results */ + ar5212GetNf(ah, ichan); + + if ((ichan->channelFlags & CHANNEL_CW_INT) == 0) { + /* Perform cal for 5Ghz channels and any OFDM on 5112 */ + if (IS_CHAN_5GHZ(chan) || + (IS_RAD5112(ah) && IS_CHAN_OFDM(chan))) + ar5212RequestRfgain(ah); + } else { + /* report up and clear internal state */ + chan->channelFlags |= CHANNEL_CW_INT; + ichan->channelFlags &= ~CHANNEL_CW_INT; + } + } + RESTORE_CCK(ah, ichan, ichan_isBmode); + RESTORE_CCK(ah, chan, isBmode); + + return AH_TRUE; +#undef IQ_CAL_TRIES +} + +HAL_BOOL +ar5212PerCalibration(struct ath_hal *ah, HAL_CHANNEL *chan, HAL_BOOL *isIQdone) +{ + return ar5212PerCalibrationN(ah, chan, 0x1, AH_TRUE, isIQdone); +} + +HAL_BOOL +ar5212ResetCalValid(struct ath_hal *ah, HAL_CHANNEL *chan) +{ + /* XXX */ + return AH_TRUE; +} + +/* + * Write the given reset bit mask into the reset register + */ +static HAL_BOOL +ar5212SetResetReg(struct ath_hal *ah, uint32_t resetMask) +{ + uint32_t mask = resetMask ? resetMask : ~0; + HAL_BOOL rt; + + /* XXX ar5212MacStop & co. */ + + if (IS_PCIE(ah)) { + resetMask &= ~AR_RC_PCI; + } + + (void) OS_REG_READ(ah, AR_RXDP);/* flush any pending MMR writes */ + OS_REG_WRITE(ah, AR_RC, resetMask); + OS_DELAY(15); /* need to wait at least 128 clocks + when reseting PCI before read */ + mask &= (AR_RC_MAC | AR_RC_BB); + resetMask &= (AR_RC_MAC | AR_RC_BB); + rt = ath_hal_wait(ah, AR_RC, mask, resetMask); + if ((resetMask & AR_RC_MAC) == 0) { + if (isBigEndian()) { + /* + * Set CFG, little-endian for register + * and descriptor accesses. + */ + mask = INIT_CONFIG_STATUS | AR_CFG_SWRD | AR_CFG_SWRG; +#ifndef AH_NEED_DESC_SWAP + mask |= AR_CFG_SWTD; +#endif + OS_REG_WRITE(ah, AR_CFG, LE_READ_4(&mask)); + } else + OS_REG_WRITE(ah, AR_CFG, INIT_CONFIG_STATUS); + if (ar5212SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE)) + (void) OS_REG_READ(ah, AR_ISR_RAC); + } + + /* track PHY power state so we don't try to r/w BB registers */ + AH5212(ah)->ah_phyPowerOn = ((resetMask & AR_RC_BB) == 0); + return rt; +} + +int16_t +ar5212GetNoiseFloor(struct ath_hal *ah) +{ + int16_t nf = (OS_REG_READ(ah, AR_PHY(25)) >> 19) & 0x1ff; + if (nf & 0x100) + nf = 0 - ((nf ^ 0x1ff) + 1); + return nf; +} + +static HAL_BOOL +getNoiseFloorThresh(struct ath_hal *ah, const HAL_CHANNEL_INTERNAL *chan, + int16_t *nft) +{ + const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom; + + HALASSERT(ah->ah_magic == AR5212_MAGIC); + + switch (chan->channelFlags & CHANNEL_ALL_NOTURBO) { + case CHANNEL_A: + *nft = ee->ee_noiseFloorThresh[headerInfo11A]; + break; + case CHANNEL_B: + *nft = ee->ee_noiseFloorThresh[headerInfo11B]; + break; + case CHANNEL_PUREG: + *nft = ee->ee_noiseFloorThresh[headerInfo11G]; + break; + default: + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel flags 0x%x\n", + __func__, chan->channelFlags); + return AH_FALSE; + } + return AH_TRUE; +} + +/* + * Setup the noise floor cal history buffer. + */ +void +ar5212InitNfCalHistBuffer(struct ath_hal *ah) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + int i; + + ahp->ah_nfCalHist.first_run = 1; + ahp->ah_nfCalHist.currIndex = 0; + ahp->ah_nfCalHist.privNF = AR5212_CCA_MAX_GOOD_VALUE; + ahp->ah_nfCalHist.invalidNFcount = AR512_NF_CAL_HIST_MAX; + for (i = 0; i < AR512_NF_CAL_HIST_MAX; i ++) + ahp->ah_nfCalHist.nfCalBuffer[i] = AR5212_CCA_MAX_GOOD_VALUE; +} + +/* + * Add a noise floor value to the ring buffer. + */ +static __inline void +updateNFHistBuff(struct ar5212NfCalHist *h, int16_t nf) +{ + h->nfCalBuffer[h->currIndex] = nf; + if (++h->currIndex >= AR512_NF_CAL_HIST_MAX) + h->currIndex = 0; +} + +/* + * Return the median noise floor value in the ring buffer. + */ +int16_t +ar5212GetNfHistMid(const int16_t calData[AR512_NF_CAL_HIST_MAX]) +{ + int16_t sort[AR512_NF_CAL_HIST_MAX]; + int i, j; + + OS_MEMCPY(sort, calData, AR512_NF_CAL_HIST_MAX*sizeof(int16_t)); + for (i = 0; i < AR512_NF_CAL_HIST_MAX-1; i ++) { + for (j = 1; j < AR512_NF_CAL_HIST_MAX-i; j ++) { + if (sort[j] > sort[j-1]) { + int16_t nf = sort[j]; + sort[j] = sort[j-1]; + sort[j-1] = nf; + } + } + } + return sort[(AR512_NF_CAL_HIST_MAX-1)>>1]; +} + +/* + * Read the NF and check it against the noise floor threshhold + */ +int16_t +ar5212GetNf(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + struct ar5212NfCalHist *h = &ahp->ah_nfCalHist; + int16_t nf, nfThresh; + int32_t val; + + if (OS_REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: NF did not complete in calibration window\n", __func__); + chan->rawNoiseFloor = h->privNF; /* most recent value */ + return chan->rawNoiseFloor; + } + + /* + * Finished NF cal, check against threshold. + */ + nf = ar5212GetNoiseFloor(ah); + if (getNoiseFloorThresh(ah, chan, &nfThresh)) { + if (nf > nfThresh) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: noise floor failed detected; detected %u, " + "threshold %u\n", __func__, nf, nfThresh); + /* + * NB: Don't discriminate 2.4 vs 5Ghz, if this + * happens it indicates a problem regardless + * of the band. + */ + chan->channelFlags |= CHANNEL_CW_INT; + nf = 0; + } + } else + nf = 0; + + /* + * Pass through histogram and write median value as + * calculated from the accrued window. We require a + * full window of in-range values to be seen before we + * start using the history. + */ + updateNFHistBuff(h, nf); + if (h->first_run) { + if (nf < AR5212_CCA_MIN_BAD_VALUE || + nf > AR5212_CCA_MAX_HIGH_VALUE) { + nf = AR5212_CCA_MAX_GOOD_VALUE; + h->invalidNFcount = AR512_NF_CAL_HIST_MAX; + } else if (--(h->invalidNFcount) == 0) { + h->first_run = 0; + h->privNF = nf = ar5212GetNfHistMid(h->nfCalBuffer); + } else { + nf = AR5212_CCA_MAX_GOOD_VALUE; + } + } else { + h->privNF = nf = ar5212GetNfHistMid(h->nfCalBuffer); + } + + val = OS_REG_READ(ah, AR_PHY(25)); + val &= 0xFFFFFE00; + val |= (((uint32_t)nf << 1) & 0x1FF); + OS_REG_WRITE(ah, AR_PHY(25), val); + OS_REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_ENABLE_NF); + OS_REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NO_UPDATE_NF); + OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); + + if (!ath_hal_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF, 0)) { +#ifdef AH_DEBUG + ath_hal_printf(ah, "%s: AGC not ready AGC_CONTROL 0x%x\n", + __func__, OS_REG_READ(ah, AR_PHY_AGC_CONTROL)); +#endif + } + + /* + * Now load a high maxCCAPower value again so that we're + * not capped by the median we just loaded + */ + val &= 0xFFFFFE00; + val |= (((uint32_t)(-50) << 1) & 0x1FF); + OS_REG_WRITE(ah, AR_PHY(25), val); + OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_ENABLE_NF); + OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NO_UPDATE_NF); + OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); + + return (chan->rawNoiseFloor = nf); +} + +/* + * Set up compression configuration registers + */ +void +ar5212SetCompRegs(struct ath_hal *ah) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + int i; + + /* Check if h/w supports compression */ + if (!AH_PRIVATE(ah)->ah_caps.halCompressSupport) + return; + + OS_REG_WRITE(ah, AR_DCCFG, 1); + + OS_REG_WRITE(ah, AR_CCFG, + (AR_COMPRESSION_WINDOW_SIZE >> 8) & AR_CCFG_WIN_M); + + OS_REG_WRITE(ah, AR_CCFG, + OS_REG_READ(ah, AR_CCFG) | AR_CCFG_MIB_INT_EN); + OS_REG_WRITE(ah, AR_CCUCFG, + AR_CCUCFG_RESET_VAL | AR_CCUCFG_CATCHUP_EN); + + OS_REG_WRITE(ah, AR_CPCOVF, 0); + + /* reset decompression mask */ + for (i = 0; i < HAL_DECOMP_MASK_SIZE; i++) { + OS_REG_WRITE(ah, AR_DCM_A, i); + OS_REG_WRITE(ah, AR_DCM_D, ahp->ah_decompMask[i]); + } +} + +HAL_BOOL +ar5212SetAntennaSwitchInternal(struct ath_hal *ah, HAL_ANT_SETTING settings, + const HAL_CHANNEL_INTERNAL *chan) +{ +#define ANT_SWITCH_TABLE1 AR_PHY(88) +#define ANT_SWITCH_TABLE2 AR_PHY(89) + struct ath_hal_5212 *ahp = AH5212(ah); + const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom; + uint32_t antSwitchA, antSwitchB; + int ix; + HAL_BOOL isBmode = AH_FALSE; + /* NB: need local copy for SAVE/RESTORE 'cuz chan is const */ + HAL_CHANNEL_INTERNAL ichan = *chan; + + HALASSERT(ah->ah_magic == AR5212_MAGIC); + HALASSERT(ahp->ah_phyPowerOn); + + SAVE_CCK(ah, &ichan, isBmode); + switch (ichan.channelFlags & CHANNEL_ALL_NOTURBO) { + case CHANNEL_A: ix = 0; break; + case CHANNEL_B: ix = 1; break; + case CHANNEL_PUREG: ix = 2; break; + default: + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel flags 0x%x\n", + __func__, ichan.channelFlags); + RESTORE_CCK(ah, &ichan, isBmode); + return AH_FALSE; + } + RESTORE_CCK(ah, &ichan, isBmode); + + antSwitchA = ee->ee_antennaControl[1][ix] + | (ee->ee_antennaControl[2][ix] << 6) + | (ee->ee_antennaControl[3][ix] << 12) + | (ee->ee_antennaControl[4][ix] << 18) + | (ee->ee_antennaControl[5][ix] << 24) + ; + antSwitchB = ee->ee_antennaControl[6][ix] + | (ee->ee_antennaControl[7][ix] << 6) + | (ee->ee_antennaControl[8][ix] << 12) + | (ee->ee_antennaControl[9][ix] << 18) + | (ee->ee_antennaControl[10][ix] << 24) + ; + /* + * For fixed antenna, give the same setting for both switch banks + */ + switch (settings) { + case HAL_ANT_FIXED_A: + antSwitchB = antSwitchA; + break; + case HAL_ANT_FIXED_B: + antSwitchA = antSwitchB; + break; + case HAL_ANT_VARIABLE: + break; + default: + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad antenna setting %u\n", + __func__, settings); + return AH_FALSE; + } + if (antSwitchB == antSwitchA) { + HALDEBUG(ah, HAL_DEBUG_RFPARAM, + "%s: Setting fast diversity off.\n", __func__); + OS_REG_CLR_BIT(ah,AR_PHY_CCK_DETECT, + AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV); + ahp->ah_diversity = AH_FALSE; + } else { + HALDEBUG(ah, HAL_DEBUG_RFPARAM, + "%s: Setting fast diversity on.\n", __func__); + OS_REG_SET_BIT(ah,AR_PHY_CCK_DETECT, + AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV); + ahp->ah_diversity = AH_TRUE; + } + ahp->ah_antControl = settings; + + OS_REG_WRITE(ah, ANT_SWITCH_TABLE1, antSwitchA); + OS_REG_WRITE(ah, ANT_SWITCH_TABLE2, antSwitchB); + + return AH_TRUE; +#undef ANT_SWITCH_TABLE2 +#undef ANT_SWITCH_TABLE1 +} + +HAL_BOOL +ar5212IsSpurChannel(struct ath_hal *ah, HAL_CHANNEL *chan) +{ + uint32_t clockFreq = + ((IS_5413(ah) || IS_RAD5112_ANY(ah) || IS_2417(ah)) ? 40 : 32); + return ( ((chan->channel % clockFreq) != 0) + && (((chan->channel % clockFreq) < 10) + || (((chan->channel) % clockFreq) > 22)) ); +} + +/* + * Read EEPROM header info and program the device for correct operation + * given the channel value. + */ +HAL_BOOL +ar5212SetBoardValues(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan) +{ +#define NO_FALSE_DETECT_BACKOFF 2 +#define CB22_FALSE_DETECT_BACKOFF 6 +#define AR_PHY_BIS(_ah, _reg, _mask, _val) \ + OS_REG_WRITE(_ah, AR_PHY(_reg), \ + (OS_REG_READ(_ah, AR_PHY(_reg)) & _mask) | (_val)); + struct ath_hal_5212 *ahp = AH5212(ah); + const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom; + int arrayMode, falseDectectBackoff; + int is2GHz = IS_CHAN_2GHZ(chan); + int8_t adcDesiredSize, pgaDesiredSize; + uint16_t switchSettling, txrxAtten, rxtxMargin; + int iCoff, qCoff; + + HALASSERT(ah->ah_magic == AR5212_MAGIC); + + switch (chan->channelFlags & CHANNEL_ALL) { + case CHANNEL_A: + case CHANNEL_T: + arrayMode = headerInfo11A; + if (!IS_RAD5112_ANY(ah) && !IS_2413(ah) && !IS_5413(ah)) + OS_REG_RMW_FIELD(ah, AR_PHY_FRAME_CTL, + AR_PHY_FRAME_CTL_TX_CLIP, + ahp->ah_gainValues.currStep->paramVal[GP_TXCLIP]); + break; + case CHANNEL_B: + arrayMode = headerInfo11B; + break; + case CHANNEL_G: + case CHANNEL_108G: + arrayMode = headerInfo11G; + break; + default: + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel flags 0x%x\n", + __func__, chan->channelFlags); + return AH_FALSE; + } + + /* Set the antenna register(s) correctly for the chip revision */ + AR_PHY_BIS(ah, 68, 0xFFFFFC06, + (ee->ee_antennaControl[0][arrayMode] << 4) | 0x1); + + ar5212SetAntennaSwitchInternal(ah, ahp->ah_antControl, chan); + + /* Set the Noise Floor Thresh on ar5211 devices */ + OS_REG_WRITE(ah, AR_PHY(90), + (ee->ee_noiseFloorThresh[arrayMode] & 0x1FF) + | (1 << 9)); + + if (ee->ee_version >= AR_EEPROM_VER5_0 && IS_CHAN_TURBO(chan)) { + switchSettling = ee->ee_switchSettlingTurbo[is2GHz]; + adcDesiredSize = ee->ee_adcDesiredSizeTurbo[is2GHz]; + pgaDesiredSize = ee->ee_pgaDesiredSizeTurbo[is2GHz]; + txrxAtten = ee->ee_txrxAttenTurbo[is2GHz]; + rxtxMargin = ee->ee_rxtxMarginTurbo[is2GHz]; + } else { + switchSettling = ee->ee_switchSettling[arrayMode]; + adcDesiredSize = ee->ee_adcDesiredSize[arrayMode]; + pgaDesiredSize = ee->ee_pgaDesiredSize[is2GHz]; + txrxAtten = ee->ee_txrxAtten[is2GHz]; + rxtxMargin = ee->ee_rxtxMargin[is2GHz]; + } + + OS_REG_RMW_FIELD(ah, AR_PHY_SETTLING, + AR_PHY_SETTLING_SWITCH, switchSettling); + OS_REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, + AR_PHY_DESIRED_SZ_ADC, adcDesiredSize); + OS_REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, + AR_PHY_DESIRED_SZ_PGA, pgaDesiredSize); + OS_REG_RMW_FIELD(ah, AR_PHY_RXGAIN, + AR_PHY_RXGAIN_TXRX_ATTEN, txrxAtten); + OS_REG_WRITE(ah, AR_PHY(13), + (ee->ee_txEndToXPAOff[arrayMode] << 24) + | (ee->ee_txEndToXPAOff[arrayMode] << 16) + | (ee->ee_txFrameToXPAOn[arrayMode] << 8) + | ee->ee_txFrameToXPAOn[arrayMode]); + AR_PHY_BIS(ah, 10, 0xFFFF00FF, + ee->ee_txEndToXLNAOn[arrayMode] << 8); + AR_PHY_BIS(ah, 25, 0xFFF80FFF, + (ee->ee_thresh62[arrayMode] << 12) & 0x7F000); + + /* + * False detect backoff - suspected 32 MHz spur causes false + * detects in OFDM, causing Tx Hangs. Decrease weak signal + * sensitivity for this card. + */ + falseDectectBackoff = NO_FALSE_DETECT_BACKOFF; + if (ee->ee_version < AR_EEPROM_VER3_3) { + /* XXX magic number */ + if (AH_PRIVATE(ah)->ah_subvendorid == 0x1022 && + IS_CHAN_OFDM(chan)) + falseDectectBackoff += CB22_FALSE_DETECT_BACKOFF; + } else { + if (ar5212IsSpurChannel(ah, (HAL_CHANNEL *)chan)) { + falseDectectBackoff += ee->ee_falseDetectBackoff[arrayMode]; + } + } + AR_PHY_BIS(ah, 73, 0xFFFFFF01, (falseDectectBackoff << 1) & 0xFE); + + if (chan->iqCalValid) { + iCoff = chan->iCoff; + qCoff = chan->qCoff; + } else { + iCoff = ee->ee_iqCalI[is2GHz]; + qCoff = ee->ee_iqCalQ[is2GHz]; + } + + /* write previous IQ results */ + OS_REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4, + AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF, iCoff); + OS_REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4, + AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF, qCoff); + OS_REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4, + AR_PHY_TIMING_CTRL4_IQCORR_ENABLE); + + if (ee->ee_version >= AR_EEPROM_VER4_1) { + if (!IS_CHAN_108G(chan) || ee->ee_version >= AR_EEPROM_VER5_0) + OS_REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ, + AR_PHY_GAIN_2GHZ_RXTX_MARGIN, rxtxMargin); + } + if (ee->ee_version >= AR_EEPROM_VER5_1) { + /* for now always disabled */ + OS_REG_WRITE(ah, AR_PHY_HEAVY_CLIP_ENABLE, 0); + } + + return AH_TRUE; +#undef AR_PHY_BIS +#undef NO_FALSE_DETECT_BACKOFF +#undef CB22_FALSE_DETECT_BACKOFF +} + +/* + * Apply Spur Immunity to Boards that require it. + * Applies only to OFDM RX operation. + */ + +void +ar5212SetSpurMitigation(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan) +{ + uint32_t pilotMask[2] = {0, 0}, binMagMask[4] = {0, 0, 0 , 0}; + uint16_t i, finalSpur, curChanAsSpur, binWidth = 0, spurDetectWidth, spurChan; + int32_t spurDeltaPhase = 0, spurFreqSd = 0, spurOffset, binOffsetNumT16, curBinOffset; + int16_t numBinOffsets; + static const uint16_t magMapFor4[4] = {1, 2, 2, 1}; + static const uint16_t magMapFor3[3] = {1, 2, 1}; + const uint16_t *pMagMap; + HAL_BOOL is2GHz = IS_CHAN_2GHZ(ichan); + uint32_t val; + +#define CHAN_TO_SPUR(_f, _freq) ( ((_freq) - ((_f) ? 2300 : 4900)) * 10 ) + if (IS_2417(ah)) { + HALDEBUG(ah, HAL_DEBUG_RFPARAM, "%s: no spur mitigation\n", + __func__); + return; + } + + curChanAsSpur = CHAN_TO_SPUR(is2GHz, ichan->channel); + + if (ichan->mainSpur) { + /* Pull out the saved spur value */ + finalSpur = ichan->mainSpur; + } else { + /* + * Check if spur immunity should be performed for this channel + * Should only be performed once per channel and then saved + */ + finalSpur = AR_NO_SPUR; + spurDetectWidth = HAL_SPUR_CHAN_WIDTH; + if (IS_CHAN_TURBO(ichan)) + spurDetectWidth *= 2; + + /* Decide if any spur affects the current channel */ + for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { + spurChan = ath_hal_getSpurChan(ah, i, is2GHz); + if (spurChan == AR_NO_SPUR) { + break; + } + if ((curChanAsSpur - spurDetectWidth <= (spurChan & HAL_SPUR_VAL_MASK)) && + (curChanAsSpur + spurDetectWidth >= (spurChan & HAL_SPUR_VAL_MASK))) { + finalSpur = spurChan & HAL_SPUR_VAL_MASK; + break; + } + } + /* Save detected spur (or no spur) for this channel */ + ichan->mainSpur = finalSpur; + } + + /* Write spur immunity data */ + if (finalSpur == AR_NO_SPUR) { + /* Disable Spur Immunity Regs if they appear set */ + if (OS_REG_READ(ah, AR_PHY_TIMING_CTRL4) & AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER) { + /* Clear Spur Delta Phase, Spur Freq, and enable bits */ + OS_REG_RMW_FIELD(ah, AR_PHY_MASK_CTL, AR_PHY_MASK_CTL_RATE, 0); + val = OS_REG_READ(ah, AR_PHY_TIMING_CTRL4); + val &= ~(AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER | + AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK | + AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK); + OS_REG_WRITE(ah, AR_PHY_MASK_CTL, val); + OS_REG_WRITE(ah, AR_PHY_TIMING11, 0); + + /* Clear pilot masks */ + OS_REG_WRITE(ah, AR_PHY_TIMING7, 0); + OS_REG_RMW_FIELD(ah, AR_PHY_TIMING8, AR_PHY_TIMING8_PILOT_MASK_2, 0); + OS_REG_WRITE(ah, AR_PHY_TIMING9, 0); + OS_REG_RMW_FIELD(ah, AR_PHY_TIMING10, AR_PHY_TIMING10_PILOT_MASK_2, 0); + + /* Clear magnitude masks */ + OS_REG_WRITE(ah, AR_PHY_BIN_MASK_1, 0); + OS_REG_WRITE(ah, AR_PHY_BIN_MASK_2, 0); + OS_REG_WRITE(ah, AR_PHY_BIN_MASK_3, 0); + OS_REG_RMW_FIELD(ah, AR_PHY_MASK_CTL, AR_PHY_MASK_CTL_MASK_4, 0); + OS_REG_WRITE(ah, AR_PHY_BIN_MASK2_1, 0); + OS_REG_WRITE(ah, AR_PHY_BIN_MASK2_2, 0); + OS_REG_WRITE(ah, AR_PHY_BIN_MASK2_3, 0); + OS_REG_RMW_FIELD(ah, AR_PHY_BIN_MASK2_4, AR_PHY_BIN_MASK2_4_MASK_4, 0); + } + } else { + spurOffset = finalSpur - curChanAsSpur; + /* + * Spur calculations: + * spurDeltaPhase is (spurOffsetIn100KHz / chipFrequencyIn100KHz) << 21 + * spurFreqSd is (spurOffsetIn100KHz / sampleFrequencyIn100KHz) << 11 + */ + switch (ichan->channelFlags & CHANNEL_ALL) { + case CHANNEL_A: /* Chip Frequency & sampleFrequency are 40 MHz */ + spurDeltaPhase = (spurOffset << 17) / 25; + spurFreqSd = spurDeltaPhase >> 10; + binWidth = HAL_BIN_WIDTH_BASE_100HZ; + break; + case CHANNEL_G: /* Chip Frequency is 44MHz, sampleFrequency is 40 MHz */ + spurFreqSd = (spurOffset << 8) / 55; + spurDeltaPhase = (spurOffset << 17) / 25; + binWidth = HAL_BIN_WIDTH_BASE_100HZ; + break; + case CHANNEL_T: /* Chip Frequency & sampleFrequency are 80 MHz */ + case CHANNEL_108G: + spurDeltaPhase = (spurOffset << 16) / 25; + spurFreqSd = spurDeltaPhase >> 10; + binWidth = HAL_BIN_WIDTH_TURBO_100HZ; + break; + } + + /* Compute Pilot Mask */ + binOffsetNumT16 = ((spurOffset * 1000) << 4) / binWidth; + /* The spur is on a bin if it's remainder at times 16 is 0 */ + if (binOffsetNumT16 & 0xF) { + numBinOffsets = 4; + pMagMap = magMapFor4; + } else { + numBinOffsets = 3; + pMagMap = magMapFor3; + } + for (i = 0; i < numBinOffsets; i++) { + if ((binOffsetNumT16 >> 4) > HAL_MAX_BINS_ALLOWED) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "Too man bins in spur mitigation\n"); + return; + } + + /* Get Pilot Mask values */ + curBinOffset = (binOffsetNumT16 >> 4) + i + 25; + if ((curBinOffset >= 0) && (curBinOffset <= 32)) { + if (curBinOffset <= 25) + pilotMask[0] |= 1 << curBinOffset; + else if (curBinOffset >= 27) + pilotMask[0] |= 1 << (curBinOffset - 1); + } else if ((curBinOffset >= 33) && (curBinOffset <= 52)) + pilotMask[1] |= 1 << (curBinOffset - 33); + + /* Get viterbi values */ + if ((curBinOffset >= -1) && (curBinOffset <= 14)) + binMagMask[0] |= pMagMap[i] << (curBinOffset + 1) * 2; + else if ((curBinOffset >= 15) && (curBinOffset <= 30)) + binMagMask[1] |= pMagMap[i] << (curBinOffset - 15) * 2; + else if ((curBinOffset >= 31) && (curBinOffset <= 46)) + binMagMask[2] |= pMagMap[i] << (curBinOffset -31) * 2; + else if((curBinOffset >= 47) && (curBinOffset <= 53)) + binMagMask[3] |= pMagMap[i] << (curBinOffset -47) * 2; + } + + /* Write Spur Delta Phase, Spur Freq, and enable bits */ + OS_REG_RMW_FIELD(ah, AR_PHY_MASK_CTL, AR_PHY_MASK_CTL_RATE, 0xFF); + val = OS_REG_READ(ah, AR_PHY_TIMING_CTRL4); + val |= (AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER | + AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK | + AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK); + OS_REG_WRITE(ah, AR_PHY_TIMING_CTRL4, val); + OS_REG_WRITE(ah, AR_PHY_TIMING11, AR_PHY_TIMING11_USE_SPUR_IN_AGC | + SM(spurFreqSd, AR_PHY_TIMING11_SPUR_FREQ_SD) | + SM(spurDeltaPhase, AR_PHY_TIMING11_SPUR_DELTA_PHASE)); + + /* Write pilot masks */ + OS_REG_WRITE(ah, AR_PHY_TIMING7, pilotMask[0]); + OS_REG_RMW_FIELD(ah, AR_PHY_TIMING8, AR_PHY_TIMING8_PILOT_MASK_2, pilotMask[1]); + OS_REG_WRITE(ah, AR_PHY_TIMING9, pilotMask[0]); + OS_REG_RMW_FIELD(ah, AR_PHY_TIMING10, AR_PHY_TIMING10_PILOT_MASK_2, pilotMask[1]); + + /* Write magnitude masks */ + OS_REG_WRITE(ah, AR_PHY_BIN_MASK_1, binMagMask[0]); + OS_REG_WRITE(ah, AR_PHY_BIN_MASK_2, binMagMask[1]); + OS_REG_WRITE(ah, AR_PHY_BIN_MASK_3, binMagMask[2]); + OS_REG_RMW_FIELD(ah, AR_PHY_MASK_CTL, AR_PHY_MASK_CTL_MASK_4, binMagMask[3]); + OS_REG_WRITE(ah, AR_PHY_BIN_MASK2_1, binMagMask[0]); + OS_REG_WRITE(ah, AR_PHY_BIN_MASK2_2, binMagMask[1]); + OS_REG_WRITE(ah, AR_PHY_BIN_MASK2_3, binMagMask[2]); + OS_REG_RMW_FIELD(ah, AR_PHY_BIN_MASK2_4, AR_PHY_BIN_MASK2_4_MASK_4, binMagMask[3]); + } +#undef CHAN_TO_SPUR +} + + +/* + * Delta slope coefficient computation. + * Required for OFDM operation. + */ +void +ar5212SetDeltaSlope(struct ath_hal *ah, HAL_CHANNEL *chan) +{ +#define COEF_SCALE_S 24 +#define INIT_CLOCKMHZSCALED 0x64000000 + unsigned long coef_scaled, coef_exp, coef_man, ds_coef_exp, ds_coef_man; + unsigned long clockMhzScaled = INIT_CLOCKMHZSCALED; + + if (IS_CHAN_TURBO(chan)) + clockMhzScaled *= 2; + /* half and quarter rate can divide the scaled clock by 2 or 4 respectively */ + /* scale for selected channel bandwidth */ + if (IS_CHAN_HALF_RATE(chan)) { + clockMhzScaled = clockMhzScaled >> 1; + } else if (IS_CHAN_QUARTER_RATE(chan)) { + clockMhzScaled = clockMhzScaled >> 2; + } + + /* + * ALGO -> coef = 1e8/fcarrier*fclock/40; + * scaled coef to provide precision for this floating calculation + */ + coef_scaled = clockMhzScaled / chan->channel; + + /* + * ALGO -> coef_exp = 14-floor(log2(coef)); + * floor(log2(x)) is the highest set bit position + */ + for (coef_exp = 31; coef_exp > 0; coef_exp--) + if ((coef_scaled >> coef_exp) & 0x1) + break; + /* A coef_exp of 0 is a legal bit position but an unexpected coef_exp */ + HALASSERT(coef_exp); + coef_exp = 14 - (coef_exp - COEF_SCALE_S); + + /* + * ALGO -> coef_man = floor(coef* 2^coef_exp+0.5); + * The coefficient is already shifted up for scaling + */ + coef_man = coef_scaled + (1 << (COEF_SCALE_S - coef_exp - 1)); + ds_coef_man = coef_man >> (COEF_SCALE_S - coef_exp); + ds_coef_exp = coef_exp - 16; + + OS_REG_RMW_FIELD(ah, AR_PHY_TIMING3, + AR_PHY_TIMING3_DSC_MAN, ds_coef_man); + OS_REG_RMW_FIELD(ah, AR_PHY_TIMING3, + AR_PHY_TIMING3_DSC_EXP, ds_coef_exp); +#undef INIT_CLOCKMHZSCALED +#undef COEF_SCALE_S +} + +/* + * Set a limit on the overall output power. Used for dynamic + * transmit power control and the like. + * + * NB: limit is in units of 0.5 dbM. + */ +HAL_BOOL +ar5212SetTxPowerLimit(struct ath_hal *ah, uint32_t limit) +{ + uint16_t dummyXpdGains[2]; + HAL_BOOL ret, isBmode = AH_FALSE; + + SAVE_CCK(ah, AH_PRIVATE(ah)->ah_curchan, isBmode); + AH_PRIVATE(ah)->ah_powerLimit = AH_MIN(limit, MAX_RATE_POWER); + ret = ar5212SetTransmitPower(ah, AH_PRIVATE(ah)->ah_curchan, + dummyXpdGains); + RESTORE_CCK(ah, AH_PRIVATE(ah)->ah_curchan, isBmode); + return ret; +} + +/* + * Set the transmit power in the baseband for the given + * operating channel and mode. + */ +HAL_BOOL +ar5212SetTransmitPower(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan, + uint16_t *rfXpdGain) +{ +#define POW_OFDM(_r, _s) (((0 & 1)<< ((_s)+6)) | (((_r) & 0x3f) << (_s))) +#define POW_CCK(_r, _s) (((_r) & 0x3f) << (_s)) +#define N(a) (sizeof (a) / sizeof (a[0])) + static const uint16_t tpcScaleReductionTable[5] = + { 0, 3, 6, 9, MAX_RATE_POWER }; + struct ath_hal_5212 *ahp = AH5212(ah); + const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom; + int16_t minPower, maxPower, tpcInDb, powerLimit; + int i; + + HALASSERT(ah->ah_magic == AR5212_MAGIC); + + OS_MEMZERO(ahp->ah_pcdacTable, ahp->ah_pcdacTableSize); + OS_MEMZERO(ahp->ah_ratesArray, sizeof(ahp->ah_ratesArray)); + + powerLimit = AH_MIN(MAX_RATE_POWER, AH_PRIVATE(ah)->ah_powerLimit); + if (powerLimit >= MAX_RATE_POWER || powerLimit == 0) + tpcInDb = tpcScaleReductionTable[AH_PRIVATE(ah)->ah_tpScale]; + else + tpcInDb = 0; + if (!ar5212SetRateTable(ah, (HAL_CHANNEL *) chan, tpcInDb, powerLimit, + AH_TRUE, &minPower, &maxPower)) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unable to set rate table\n", + __func__); + return AH_FALSE; + } + if (!ahp->ah_rfHal->setPowerTable(ah, + &minPower, &maxPower, chan, rfXpdGain)) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unable to set power table\n", + __func__); + return AH_FALSE; + } + + /* + * Adjust XR power/rate up by 2 dB to account for greater peak + * to avg ratio - except in newer avg power designs + */ + if (!IS_2413(ah) && !IS_5413(ah)) + ahp->ah_ratesArray[15] += 4; + /* + * txPowerIndexOffset is set by the SetPowerTable() call - + * adjust the rate table + */ + for (i = 0; i < N(ahp->ah_ratesArray); i++) { + ahp->ah_ratesArray[i] += ahp->ah_txPowerIndexOffset; + if (ahp->ah_ratesArray[i] > 63) + ahp->ah_ratesArray[i] = 63; + } + + if (ee->ee_eepMap < 2) { + /* + * Correct gain deltas for 5212 G operation - + * Removed with revised chipset + */ + if (AH_PRIVATE(ah)->ah_phyRev < AR_PHY_CHIP_ID_REV_2 && + IS_CHAN_G(chan)) { + uint16_t cckOfdmPwrDelta; + + if (chan->channel == 2484) + cckOfdmPwrDelta = SCALE_OC_DELTA( + ee->ee_cckOfdmPwrDelta - + ee->ee_scaledCh14FilterCckDelta); + else + cckOfdmPwrDelta = SCALE_OC_DELTA( + ee->ee_cckOfdmPwrDelta); + ar5212CorrectGainDelta(ah, cckOfdmPwrDelta); + } + /* + * Finally, write the power values into the + * baseband power table + */ + for (i = 0; i < (PWR_TABLE_SIZE/2); i++) { + OS_REG_WRITE(ah, AR_PHY_PCDAC_TX_POWER(i), + ((((ahp->ah_pcdacTable[2*i + 1] << 8) | 0xff) & 0xffff) << 16) + | (((ahp->ah_pcdacTable[2*i] << 8) | 0xff) & 0xffff) + ); + } + } + + /* Write the OFDM power per rate set */ + OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, + POW_OFDM(ahp->ah_ratesArray[3], 24) + | POW_OFDM(ahp->ah_ratesArray[2], 16) + | POW_OFDM(ahp->ah_ratesArray[1], 8) + | POW_OFDM(ahp->ah_ratesArray[0], 0) + ); + OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE2, + POW_OFDM(ahp->ah_ratesArray[7], 24) + | POW_OFDM(ahp->ah_ratesArray[6], 16) + | POW_OFDM(ahp->ah_ratesArray[5], 8) + | POW_OFDM(ahp->ah_ratesArray[4], 0) + ); + + /* Write the CCK power per rate set */ + OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, + POW_CCK(ahp->ah_ratesArray[10], 24) + | POW_CCK(ahp->ah_ratesArray[9], 16) + | POW_CCK(ahp->ah_ratesArray[15], 8) /* XR target power */ + | POW_CCK(ahp->ah_ratesArray[8], 0) + ); + OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, + POW_CCK(ahp->ah_ratesArray[14], 24) + | POW_CCK(ahp->ah_ratesArray[13], 16) + | POW_CCK(ahp->ah_ratesArray[12], 8) + | POW_CCK(ahp->ah_ratesArray[11], 0) + ); + + /* + * Set max power to 30 dBm and, optionally, + * enable TPC in tx descriptors. + */ + OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE_MAX, MAX_RATE_POWER | + (ahp->ah_tpcEnabled ? AR_PHY_POWER_TX_RATE_MAX_TPC_ENABLE : 0)); + + return AH_TRUE; +#undef N +#undef POW_CCK +#undef POW_OFDM +} + +/* + * Sets the transmit power in the baseband for the given + * operating channel and mode. + */ +static HAL_BOOL +ar5212SetRateTable(struct ath_hal *ah, HAL_CHANNEL *chan, + int16_t tpcScaleReduction, int16_t powerLimit, HAL_BOOL commit, + int16_t *pMinPower, int16_t *pMaxPower) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom; + uint16_t *rpow = ahp->ah_ratesArray; + uint16_t twiceMaxEdgePower = MAX_RATE_POWER; + uint16_t twiceMaxEdgePowerCck = MAX_RATE_POWER; + uint16_t twiceMaxRDPower = MAX_RATE_POWER; + int i; + uint8_t cfgCtl; + int8_t twiceAntennaGain, twiceAntennaReduction; + const RD_EDGES_POWER *rep; + TRGT_POWER_INFO targetPowerOfdm, targetPowerCck; + int16_t scaledPower, maxAvailPower = 0; + int16_t r13, r9, r7, r0; + + HALASSERT(ah->ah_magic == AR5212_MAGIC); + + twiceMaxRDPower = chan->maxRegTxPower * 2; + *pMaxPower = -MAX_RATE_POWER; + *pMinPower = MAX_RATE_POWER; + + /* Get conformance test limit maximum for this channel */ + cfgCtl = ath_hal_getctl(ah, chan); + for (i = 0; i < ee->ee_numCtls; i++) { + uint16_t twiceMinEdgePower; + + if (ee->ee_ctl[i] == 0) + continue; + if (ee->ee_ctl[i] == cfgCtl || + cfgCtl == ((ee->ee_ctl[i] & CTL_MODE_M) | SD_NO_CTL)) { + rep = &ee->ee_rdEdgesPower[i * NUM_EDGES]; + twiceMinEdgePower = ar5212GetMaxEdgePower(chan->channel, rep); + if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) { + /* Find the minimum of all CTL edge powers that apply to this channel */ + twiceMaxEdgePower = AH_MIN(twiceMaxEdgePower, twiceMinEdgePower); + } else { + twiceMaxEdgePower = twiceMinEdgePower; + break; + } + } + } + + if (IS_CHAN_G(chan)) { + /* Check for a CCK CTL for 11G CCK powers */ + cfgCtl = (cfgCtl & ~CTL_MODE_M) | CTL_11B; + for (i = 0; i < ee->ee_numCtls; i++) { + uint16_t twiceMinEdgePowerCck; + + if (ee->ee_ctl[i] == 0) + continue; + if (ee->ee_ctl[i] == cfgCtl || + cfgCtl == ((ee->ee_ctl[i] & CTL_MODE_M) | SD_NO_CTL)) { + rep = &ee->ee_rdEdgesPower[i * NUM_EDGES]; + twiceMinEdgePowerCck = ar5212GetMaxEdgePower(chan->channel, rep); + if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) { + /* Find the minimum of all CTL edge powers that apply to this channel */ + twiceMaxEdgePowerCck = AH_MIN(twiceMaxEdgePowerCck, twiceMinEdgePowerCck); + } else { + twiceMaxEdgePowerCck = twiceMinEdgePowerCck; + break; + } + } + } + } else { + /* Set the 11B cck edge power to the one found before */ + twiceMaxEdgePowerCck = twiceMaxEdgePower; + } + + /* Get Antenna Gain reduction */ + if (IS_CHAN_5GHZ(chan)) { + ath_hal_eepromGet(ah, AR_EEP_ANTGAINMAX_5, &twiceAntennaGain); + } else { + ath_hal_eepromGet(ah, AR_EEP_ANTGAINMAX_2, &twiceAntennaGain); + } + twiceAntennaReduction = + ath_hal_getantennareduction(ah, chan, twiceAntennaGain); + + if (IS_CHAN_OFDM(chan)) { + /* Get final OFDM target powers */ + if (IS_CHAN_2GHZ(chan)) { + ar5212GetTargetPowers(ah, chan, ee->ee_trgtPwr_11g, + ee->ee_numTargetPwr_11g, &targetPowerOfdm); + } else { + ar5212GetTargetPowers(ah, chan, ee->ee_trgtPwr_11a, + ee->ee_numTargetPwr_11a, &targetPowerOfdm); + } + + /* Get Maximum OFDM power */ + /* Minimum of target and edge powers */ + scaledPower = AH_MIN(twiceMaxEdgePower, + twiceMaxRDPower - twiceAntennaReduction); + + /* + * If turbo is set, reduce power to keep power + * consumption under 2 Watts. Note that we always do + * this unless specially configured. Then we limit + * power only for non-AP operation. + */ + if (IS_CHAN_TURBO(chan) +#ifdef AH_ENABLE_AP_SUPPORT + && AH_PRIVATE(ah)->ah_opmode != HAL_M_HOSTAP +#endif + ) { + /* + * If turbo is set, reduce power to keep power + * consumption under 2 Watts + */ + if (ee->ee_version >= AR_EEPROM_VER3_1) + scaledPower = AH_MIN(scaledPower, + ee->ee_turbo2WMaxPower5); + /* + * EEPROM version 4.0 added an additional + * constraint on 2.4GHz channels. + */ + if (ee->ee_version >= AR_EEPROM_VER4_0 && + IS_CHAN_2GHZ(chan)) + scaledPower = AH_MIN(scaledPower, + ee->ee_turbo2WMaxPower2); + } + + maxAvailPower = AH_MIN(scaledPower, + targetPowerOfdm.twicePwr6_24); + + /* Reduce power by max regulatory domain allowed restrictions */ + scaledPower = maxAvailPower - (tpcScaleReduction * 2); + scaledPower = (scaledPower < 0) ? 0 : scaledPower; + scaledPower = AH_MIN(scaledPower, powerLimit); + + if (commit) { + /* Set OFDM rates 9, 12, 18, 24 */ + r0 = rpow[0] = rpow[1] = rpow[2] = rpow[3] = rpow[4] = scaledPower; + + /* Set OFDM rates 36, 48, 54, XR */ + rpow[5] = AH_MIN(rpow[0], targetPowerOfdm.twicePwr36); + rpow[6] = AH_MIN(rpow[0], targetPowerOfdm.twicePwr48); + r7 = rpow[7] = AH_MIN(rpow[0], targetPowerOfdm.twicePwr54); + + if (ee->ee_version >= AR_EEPROM_VER4_0) { + /* Setup XR target power from EEPROM */ + rpow[15] = AH_MIN(scaledPower, IS_CHAN_2GHZ(chan) ? + ee->ee_xrTargetPower2 : ee->ee_xrTargetPower5); + } else { + /* XR uses 6mb power */ + rpow[15] = rpow[0]; + } + ahp->ah_ofdmTxPower = *pMaxPower; + + } else { + r0 = scaledPower; + r7 = AH_MIN(r0, targetPowerOfdm.twicePwr54); + } + *pMinPower = r7; + *pMaxPower = r0; + + HALDEBUG(ah, HAL_DEBUG_RFPARAM, + "%s: MaxRD: %d TurboMax: %d MaxCTL: %d " + "TPC_Reduction %d chan=%d (0x%x) maxAvailPower=%d pwr6_24=%d, maxPower=%d\n", + __func__, twiceMaxRDPower, ee->ee_turbo2WMaxPower5, + twiceMaxEdgePower, tpcScaleReduction * 2, + chan->channel, chan->channelFlags, + maxAvailPower, targetPowerOfdm.twicePwr6_24, *pMaxPower); + } + + if (IS_CHAN_CCK(chan) || IS_CHAN_G(chan)) { + /* Get final CCK target powers */ + ar5212GetTargetPowers(ah, chan, ee->ee_trgtPwr_11b, + ee->ee_numTargetPwr_11b, &targetPowerCck); + + /* Reduce power by max regulatory domain allowed restrictions */ + scaledPower = AH_MIN(twiceMaxEdgePowerCck, + twiceMaxRDPower - twiceAntennaReduction); + if (maxAvailPower < AH_MIN(scaledPower, targetPowerCck.twicePwr6_24)) + maxAvailPower = AH_MIN(scaledPower, targetPowerCck.twicePwr6_24); + + /* Reduce power by user selection */ + scaledPower = AH_MIN(scaledPower, targetPowerCck.twicePwr6_24) - (tpcScaleReduction * 2); + scaledPower = (scaledPower < 0) ? 0 : scaledPower; + scaledPower = AH_MIN(scaledPower, powerLimit); + + if (commit) { + /* Set CCK rates 2L, 2S, 5.5L, 5.5S, 11L, 11S */ + rpow[8] = AH_MIN(scaledPower, targetPowerCck.twicePwr6_24); + r9 = rpow[9] = AH_MIN(scaledPower, targetPowerCck.twicePwr36); + rpow[10] = rpow[9]; + rpow[11] = AH_MIN(scaledPower, targetPowerCck.twicePwr48); + rpow[12] = rpow[11]; + r13 = rpow[13] = AH_MIN(scaledPower, targetPowerCck.twicePwr54); + rpow[14] = rpow[13]; + } else { + r9 = AH_MIN(scaledPower, targetPowerCck.twicePwr36); + r13 = AH_MIN(scaledPower, targetPowerCck.twicePwr54); + } + + /* Set min/max power based off OFDM values or initialization */ + if (r13 < *pMinPower) + *pMinPower = r13; + if (r9 > *pMaxPower) + *pMaxPower = r9; + + HALDEBUG(ah, HAL_DEBUG_RFPARAM, + "%s: cck: MaxRD: %d MaxCTL: %d " + "TPC_Reduction %d chan=%d (0x%x) maxAvailPower=%d pwr6_24=%d, maxPower=%d\n", + __func__, twiceMaxRDPower, twiceMaxEdgePowerCck, + tpcScaleReduction * 2, chan->channel, chan->channelFlags, + maxAvailPower, targetPowerCck.twicePwr6_24, *pMaxPower); + } + if (commit) { + ahp->ah_tx6PowerInHalfDbm = *pMaxPower; + AH_PRIVATE(ah)->ah_maxPowerLevel = ahp->ah_tx6PowerInHalfDbm; + } + return AH_TRUE; +} + +HAL_BOOL +ar5212GetChipPowerLimits(struct ath_hal *ah, HAL_CHANNEL *chans, uint32_t nchans) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + static const uint16_t tpcScaleReductionTable[5] = + { 0, 3, 6, 9, MAX_RATE_POWER }; + int16_t minPower, maxPower, tpcInDb, powerLimit; + HAL_CHANNEL *chan; + int i; + + /* + * Get Pier table max and min powers. + */ + for (i = 0; i < nchans; i++) { + chan = &chans[i]; + if (ahp->ah_rfHal->getChannelMaxMinPower(ah, chan, &maxPower, &minPower)) { + /* NB: rf code returns 1/4 dBm units, convert */ + chan->maxTxPower = maxPower / 2; + chan->minTxPower = minPower / 2; + } else { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: no min/max power for %u/0x%x\n", + __func__, chan->channel, chan->channelFlags); + chan->maxTxPower = MAX_RATE_POWER; + chan->minTxPower = 0; + } + } + /* + * Now adjust to reflect any global scale and/or CTL's. + * (XXX is that correct?) + */ + powerLimit = AH_MIN(MAX_RATE_POWER, AH_PRIVATE(ah)->ah_powerLimit); + if (powerLimit >= MAX_RATE_POWER || powerLimit == 0) + tpcInDb = tpcScaleReductionTable[AH_PRIVATE(ah)->ah_tpScale]; + else + tpcInDb = 0; + for (i=0; imaxTxPower) + chan->maxTxPower = maxPower; + if (minPower < chan->minTxPower) + chan->minTxPower = minPower; + } +#ifdef AH_DEBUG + for (i=0; i ofdm 6, 9, .. 48, 54 + * [8..14] --> cck 1L, 2L, 2S, .. 11L, 11S + * [15] --> XR (all rates get the same power) + * 2. powv[ii] is the pcdac corresponding to ii/2 dBm. + */ +static void +ar5212CorrectGainDelta(struct ath_hal *ah, int twiceOfdmCckDelta) +{ +#define N(_a) (sizeof(_a) / sizeof(_a[0])) + struct ath_hal_5212 *ahp = AH5212(ah); + const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom; + int16_t ratesIndex[N(ahp->ah_ratesArray)]; + uint16_t ii, jj, iter; + int32_t cckIndex; + int16_t gainDeltaAdjust; + + HALASSERT(ah->ah_magic == AR5212_MAGIC); + + gainDeltaAdjust = ee->ee_cckOfdmGainDelta; + + /* make a local copy of desired powers as initial indices */ + OS_MEMCPY(ratesIndex, ahp->ah_ratesArray, sizeof(ratesIndex)); + + /* fix only the CCK indices */ + for (ii = 8; ii < 15; ii++) { + /* apply a gain_delta correction of -15 for CCK */ + ratesIndex[ii] -= gainDeltaAdjust; + + /* Now check for contention with all ofdm target powers */ + jj = 0; + iter = 0; + /* indicates not all ofdm rates checked forcontention yet */ + while (jj < 16) { + if (ratesIndex[ii] < 0) + ratesIndex[ii] = 0; + if (jj == 8) { /* skip CCK rates */ + jj = 15; + continue; + } + if (ratesIndex[ii] == ahp->ah_ratesArray[jj]) { + if (ahp->ah_ratesArray[jj] == 0) + ratesIndex[ii]++; + else if (iter > 50) { + /* + * To avoid pathological case of of + * dm target powers 0 and 0.5dBm + */ + ratesIndex[ii]++; + } else + ratesIndex[ii]--; + /* check with all rates again */ + jj = 0; + iter++; + } else + jj++; + } + if (ratesIndex[ii] >= PWR_TABLE_SIZE) + ratesIndex[ii] = PWR_TABLE_SIZE -1; + cckIndex = ahp->ah_ratesArray[ii] - twiceOfdmCckDelta; + if (cckIndex < 0) + cckIndex = 0; + + /* + * Validate that the indexes for the powv are not + * out of bounds. + */ + HALASSERT(cckIndex < PWR_TABLE_SIZE); + HALASSERT(ratesIndex[ii] < PWR_TABLE_SIZE); + ahp->ah_pcdacTable[ratesIndex[ii]] = + ahp->ah_pcdacTable[cckIndex]; + } + /* Override rate per power table with new values */ + for (ii = 8; ii < 15; ii++) + ahp->ah_ratesArray[ii] = ratesIndex[ii]; +#undef N +} + +/* + * Find the maximum conformance test limit for the given channel and CTL info + */ +static uint16_t +ar5212GetMaxEdgePower(uint16_t channel, const RD_EDGES_POWER *pRdEdgesPower) +{ + /* temp array for holding edge channels */ + uint16_t tempChannelList[NUM_EDGES]; + uint16_t clo = 0, chi = 0, twiceMaxEdgePower; + int i, numEdges; + + /* Get the edge power */ + for (i = 0; i < NUM_EDGES; i++) { + if (pRdEdgesPower[i].rdEdge == 0) + break; + tempChannelList[i] = pRdEdgesPower[i].rdEdge; + } + numEdges = i; + + ar5212GetLowerUpperValues(channel, tempChannelList, + numEdges, &clo, &chi); + /* Get the index for the lower channel */ + for (i = 0; i < numEdges && clo != tempChannelList[i]; i++) + ; + /* Is lower channel ever outside the rdEdge? */ + HALASSERT(i != numEdges); + + if ((clo == chi && clo == channel) || (pRdEdgesPower[i].flag)) { + /* + * If there's an exact channel match or an inband flag set + * on the lower channel use the given rdEdgePower + */ + twiceMaxEdgePower = pRdEdgesPower[i].twice_rdEdgePower; + HALASSERT(twiceMaxEdgePower > 0); + } else + twiceMaxEdgePower = MAX_RATE_POWER; + return twiceMaxEdgePower; +} + +/* + * Returns interpolated or the scaled up interpolated value + */ +static uint16_t +interpolate(uint16_t target, uint16_t srcLeft, uint16_t srcRight, + uint16_t targetLeft, uint16_t targetRight) +{ + uint16_t rv; + int16_t lRatio; + + /* to get an accurate ratio, always scale, if want to scale, then don't scale back down */ + if ((targetLeft * targetRight) == 0) + return 0; + + if (srcRight != srcLeft) { + /* + * Note the ratio always need to be scaled, + * since it will be a fraction. + */ + lRatio = (target - srcLeft) * EEP_SCALE / (srcRight - srcLeft); + if (lRatio < 0) { + /* Return as Left target if value would be negative */ + rv = targetLeft; + } else if (lRatio > EEP_SCALE) { + /* Return as Right target if Ratio is greater than 100% (SCALE) */ + rv = targetRight; + } else { + rv = (lRatio * targetRight + (EEP_SCALE - lRatio) * + targetLeft) / EEP_SCALE; + } + } else { + rv = targetLeft; + } + return rv; +} + +/* + * Return the four rates of target power for the given target power table + * channel, and number of channels + */ +static void +ar5212GetTargetPowers(struct ath_hal *ah, HAL_CHANNEL *chan, + const TRGT_POWER_INFO *powInfo, + uint16_t numChannels, TRGT_POWER_INFO *pNewPower) +{ + /* temp array for holding target power channels */ + uint16_t tempChannelList[NUM_TEST_FREQUENCIES]; + uint16_t clo = 0, chi = 0, ixlo, ixhi; + int i; + + /* Copy the target powers into the temp channel list */ + for (i = 0; i < numChannels; i++) + tempChannelList[i] = powInfo[i].testChannel; + + ar5212GetLowerUpperValues(chan->channel, tempChannelList, + numChannels, &clo, &chi); + + /* Get the indices for the channel */ + ixlo = ixhi = 0; + for (i = 0; i < numChannels; i++) { + if (clo == tempChannelList[i]) { + ixlo = i; + } + if (chi == tempChannelList[i]) { + ixhi = i; + break; + } + } + + /* + * Get the lower and upper channels, target powers, + * and interpolate between them. + */ + pNewPower->twicePwr6_24 = interpolate(chan->channel, clo, chi, + powInfo[ixlo].twicePwr6_24, powInfo[ixhi].twicePwr6_24); + pNewPower->twicePwr36 = interpolate(chan->channel, clo, chi, + powInfo[ixlo].twicePwr36, powInfo[ixhi].twicePwr36); + pNewPower->twicePwr48 = interpolate(chan->channel, clo, chi, + powInfo[ixlo].twicePwr48, powInfo[ixhi].twicePwr48); + pNewPower->twicePwr54 = interpolate(chan->channel, clo, chi, + powInfo[ixlo].twicePwr54, powInfo[ixhi].twicePwr54); +} + +/* + * Search a list for a specified value v that is within + * EEP_DELTA of the search values. Return the closest + * values in the list above and below the desired value. + * EEP_DELTA is a factional value; everything is scaled + * so only integer arithmetic is used. + * + * NB: the input list is assumed to be sorted in ascending order + */ +void +ar5212GetLowerUpperValues(uint16_t v, uint16_t *lp, uint16_t listSize, + uint16_t *vlo, uint16_t *vhi) +{ + uint32_t target = v * EEP_SCALE; + uint16_t *ep = lp+listSize; + + /* + * Check first and last elements for out-of-bounds conditions. + */ + if (target < (uint32_t)(lp[0] * EEP_SCALE - EEP_DELTA)) { + *vlo = *vhi = lp[0]; + return; + } + if (target > (uint32_t)(ep[-1] * EEP_SCALE + EEP_DELTA)) { + *vlo = *vhi = ep[-1]; + return; + } + + /* look for value being near or between 2 values in list */ + for (; lp < ep; lp++) { + /* + * If value is close to the current value of the list + * then target is not between values, it is one of the values + */ + if (abs(lp[0] * EEP_SCALE - target) < EEP_DELTA) { + *vlo = *vhi = lp[0]; + return; + } + /* + * Look for value being between current value and next value + * if so return these 2 values + */ + if (target < (uint32_t)(lp[1] * EEP_SCALE - EEP_DELTA)) { + *vlo = lp[0]; + *vhi = lp[1]; + return; + } + } + HALASSERT(AH_FALSE); /* should not reach here */ +} + +/* + * Perform analog "swizzling" of parameters into their location + * + * NB: used by RF backends + */ +void +ar5212ModifyRfBuffer(uint32_t *rfBuf, uint32_t reg32, uint32_t numBits, + uint32_t firstBit, uint32_t column) +{ +#define MAX_ANALOG_START 319 /* XXX */ + uint32_t tmp32, mask, arrayEntry, lastBit; + int32_t bitPosition, bitsLeft; + + HALASSERT(column <= 3); + HALASSERT(numBits <= 32); + HALASSERT(firstBit + numBits <= MAX_ANALOG_START); + + tmp32 = ath_hal_reverseBits(reg32, numBits); + arrayEntry = (firstBit - 1) / 8; + bitPosition = (firstBit - 1) % 8; + bitsLeft = numBits; + while (bitsLeft > 0) { + lastBit = (bitPosition + bitsLeft > 8) ? + 8 : bitPosition + bitsLeft; + mask = (((1 << lastBit) - 1) ^ ((1 << bitPosition) - 1)) << + (column * 8); + rfBuf[arrayEntry] &= ~mask; + rfBuf[arrayEntry] |= ((tmp32 << bitPosition) << + (column * 8)) & mask; + bitsLeft -= 8 - bitPosition; + tmp32 = tmp32 >> (8 - bitPosition); + bitPosition = 0; + arrayEntry++; + } +#undef MAX_ANALOG_START +} + +/* + * Sets the rate to duration values in MAC - used for multi- + * rate retry. + * The rate duration table needs to cover all valid rate codes; + * the 11g table covers all ofdm rates, while the 11b table + * covers all cck rates => all valid rates get covered between + * these two mode's ratetables! + * But if we're turbo, the ofdm phy is replaced by the turbo phy + * and cck is not valid with turbo => all rates get covered + * by the turbo ratetable only + */ +void +ar5212SetRateDurationTable(struct ath_hal *ah, HAL_CHANNEL *chan) +{ + const HAL_RATE_TABLE *rt; + int i; + + /* NB: band doesn't matter for 1/2 and 1/4 rate */ + if (IS_CHAN_HALF_RATE(chan)) { + rt = ar5212GetRateTable(ah, HAL_MODE_11A_HALF_RATE); + } else if (IS_CHAN_QUARTER_RATE(chan)) { + rt = ar5212GetRateTable(ah, HAL_MODE_11A_QUARTER_RATE); + } else { + rt = ar5212GetRateTable(ah, + IS_CHAN_TURBO(chan) ? HAL_MODE_TURBO : HAL_MODE_11G); + } + + for (i = 0; i < rt->rateCount; ++i) + OS_REG_WRITE(ah, + AR_RATE_DURATION(rt->info[i].rateCode), + ath_hal_computetxtime(ah, rt, + WLAN_CTRL_FRAME_SIZE, + rt->info[i].controlRate, AH_FALSE)); + if (!IS_CHAN_TURBO(chan)) { + /* 11g Table is used to cover the CCK rates. */ + rt = ar5212GetRateTable(ah, HAL_MODE_11G); + for (i = 0; i < rt->rateCount; ++i) { + uint32_t reg = AR_RATE_DURATION(rt->info[i].rateCode); + + if (rt->info[i].phy != IEEE80211_T_CCK) + continue; + + OS_REG_WRITE(ah, reg, + ath_hal_computetxtime(ah, rt, + WLAN_CTRL_FRAME_SIZE, + rt->info[i].controlRate, AH_FALSE)); + /* cck rates have short preamble option also */ + if (rt->info[i].shortPreamble) { + reg += rt->info[i].shortPreamble << 2; + OS_REG_WRITE(ah, reg, + ath_hal_computetxtime(ah, rt, + WLAN_CTRL_FRAME_SIZE, + rt->info[i].controlRate, + AH_TRUE)); + } + } + } +} + +/* Adjust various register settings based on half/quarter rate clock setting. + * This includes: +USEC, TX/RX latency, + * + IFS params: slot, eifs, misc etc. + */ +void +ar5212SetIFSTiming(struct ath_hal *ah, HAL_CHANNEL *chan) +{ + uint32_t txLat, rxLat, usec, slot, refClock, eifs, init_usec; + + HALASSERT(IS_CHAN_HALF_RATE(chan) || IS_CHAN_QUARTER_RATE(chan)); + + refClock = OS_REG_READ(ah, AR_USEC) & AR_USEC_USEC32; + if (IS_CHAN_HALF_RATE(chan)) { + slot = IFS_SLOT_HALF_RATE; + rxLat = RX_NON_FULL_RATE_LATENCY << AR5212_USEC_RX_LAT_S; + txLat = TX_HALF_RATE_LATENCY << AR5212_USEC_TX_LAT_S; + usec = HALF_RATE_USEC; + eifs = IFS_EIFS_HALF_RATE; + init_usec = INIT_USEC >> 1; + } else { /* quarter rate */ + slot = IFS_SLOT_QUARTER_RATE; + rxLat = RX_NON_FULL_RATE_LATENCY << AR5212_USEC_RX_LAT_S; + txLat = TX_QUARTER_RATE_LATENCY << AR5212_USEC_TX_LAT_S; + usec = QUARTER_RATE_USEC; + eifs = IFS_EIFS_QUARTER_RATE; + init_usec = INIT_USEC >> 2; + } + + OS_REG_WRITE(ah, AR_USEC, (usec | refClock | txLat | rxLat)); + OS_REG_WRITE(ah, AR_D_GBL_IFS_SLOT, slot); + OS_REG_WRITE(ah, AR_D_GBL_IFS_EIFS, eifs); + OS_REG_RMW_FIELD(ah, AR_D_GBL_IFS_MISC, + AR_D_GBL_IFS_MISC_USEC_DURATION, init_usec); +} --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5212/ar5212_rfgain.c 2009-03-23 17:36:55.000000000 +0000 @@ -0,0 +1,330 @@ +/* + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2008 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ar5212_rfgain.c,v 1.1 2009/03/23 17:14:48 sborrill Exp $ + */ +#include "opt_ah.h" + +#include "ah.h" +#include "ah_internal.h" +#include "ah_devid.h" + +#include "ar5212/ar5212.h" +#include "ar5212/ar5212reg.h" +#include "ar5212/ar5212phy.h" + +#include "ah_eeprom_v3.h" + +static const GAIN_OPTIMIZATION_LADDER gainLadder = { + 9, /* numStepsInLadder */ + 4, /* defaultStepNum */ + { { {4, 1, 1, 1}, 6, "FG8"}, + { {4, 0, 1, 1}, 4, "FG7"}, + { {3, 1, 1, 1}, 3, "FG6"}, + { {4, 0, 0, 1}, 1, "FG5"}, + { {4, 1, 1, 0}, 0, "FG4"}, /* noJack */ + { {4, 0, 1, 0}, -2, "FG3"}, /* halfJack */ + { {3, 1, 1, 0}, -3, "FG2"}, /* clip3 */ + { {4, 0, 0, 0}, -4, "FG1"}, /* noJack */ + { {2, 1, 1, 0}, -6, "FG0"} /* clip2 */ + } +}; + +static const GAIN_OPTIMIZATION_LADDER gainLadder5112 = { + 8, /* numStepsInLadder */ + 1, /* defaultStepNum */ + { { {3, 0,0,0, 0,0,0}, 6, "FG7"}, /* most fixed gain */ + { {2, 0,0,0, 0,0,0}, 0, "FG6"}, + { {1, 0,0,0, 0,0,0}, -3, "FG5"}, + { {0, 0,0,0, 0,0,0}, -6, "FG4"}, + { {0, 1,1,0, 0,0,0}, -8, "FG3"}, + { {0, 1,1,0, 1,1,0}, -10, "FG2"}, + { {0, 1,0,1, 1,1,0}, -13, "FG1"}, + { {0, 1,0,1, 1,0,1}, -16, "FG0"}, /* least fixed gain */ + } +}; + +/* + * Initialize the gain structure to good values + */ +void +ar5212InitializeGainValues(struct ath_hal *ah) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + GAIN_VALUES *gv = &ahp->ah_gainValues; + + /* initialize gain optimization values */ + if (IS_RAD5112_ANY(ah)) { + gv->currStepNum = gainLadder5112.defaultStepNum; + gv->currStep = + &gainLadder5112.optStep[gainLadder5112.defaultStepNum]; + gv->active = AH_TRUE; + gv->loTrig = 20; + gv->hiTrig = 85; + } else { + gv->currStepNum = gainLadder.defaultStepNum; + gv->currStep = &gainLadder.optStep[gainLadder.defaultStepNum]; + gv->active = AH_TRUE; + gv->loTrig = 20; + gv->hiTrig = 35; + } +} + +#define MAX_ANALOG_START 319 /* XXX */ + +/* + * Find analog bits of given parameter data and return a reversed value + */ +static uint32_t +ar5212GetRfField(uint32_t *rfBuf, uint32_t numBits, uint32_t firstBit, uint32_t column) +{ + uint32_t reg32 = 0, mask, arrayEntry, lastBit; + uint32_t bitPosition, bitsShifted; + int32_t bitsLeft; + + HALASSERT(column <= 3); + HALASSERT(numBits <= 32); + HALASSERT(firstBit + numBits <= MAX_ANALOG_START); + + arrayEntry = (firstBit - 1) / 8; + bitPosition = (firstBit - 1) % 8; + bitsLeft = numBits; + bitsShifted = 0; + while (bitsLeft > 0) { + lastBit = (bitPosition + bitsLeft > 8) ? + (8) : (bitPosition + bitsLeft); + mask = (((1 << lastBit) - 1) ^ ((1 << bitPosition) - 1)) << + (column * 8); + reg32 |= (((rfBuf[arrayEntry] & mask) >> (column * 8)) >> + bitPosition) << bitsShifted; + bitsShifted += lastBit - bitPosition; + bitsLeft -= (8 - bitPosition); + bitPosition = 0; + arrayEntry++; + } + reg32 = ath_hal_reverseBits(reg32, numBits); + return reg32; +} + +static HAL_BOOL +ar5212InvalidGainReadback(struct ath_hal *ah, GAIN_VALUES *gv) +{ + uint32_t gStep, g, mixOvr; + uint32_t L1, L2, L3, L4; + + if (IS_RAD5112_ANY(ah)) { + mixOvr = ar5212GetRfField(ar5212GetRfBank(ah, 7), 1, 36, 0); + L1 = 0; + L2 = 107; + L3 = 0; + L4 = 107; + if (mixOvr == 1) { + L2 = 83; + L4 = 83; + gv->hiTrig = 55; + } + } else { + gStep = ar5212GetRfField(ar5212GetRfBank(ah, 7), 6, 37, 0); + + L1 = 0; + L2 = (gStep == 0x3f) ? 50 : gStep + 4; + L3 = (gStep != 0x3f) ? 0x40 : L1; + L4 = L3 + 50; + + gv->loTrig = L1 + (gStep == 0x3f ? DYN_ADJ_LO_MARGIN : 0); + /* never adjust if != 0x3f */ + gv->hiTrig = L4 - (gStep == 0x3f ? DYN_ADJ_UP_MARGIN : -5); + } + g = gv->currGain; + + return !((g >= L1 && g<= L2) || (g >= L3 && g <= L4)); +} + +/* + * Enable the probe gain check on the next packet + */ +void +ar5212RequestRfgain(struct ath_hal *ah) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + uint32_t probePowerIndex; + + /* Enable the gain readback probe */ + probePowerIndex = ahp->ah_ofdmTxPower + ahp->ah_txPowerIndexOffset; + OS_REG_WRITE(ah, AR_PHY_PAPD_PROBE, + SM(probePowerIndex, AR_PHY_PAPD_PROBE_POWERTX) + | AR_PHY_PAPD_PROBE_NEXT_TX); + + ahp->ah_rfgainState = HAL_RFGAIN_READ_REQUESTED; +} + +/* + * Check to see if our readback gain level sits within the linear + * region of our current variable attenuation window + */ +static HAL_BOOL +ar5212IsGainAdjustNeeded(struct ath_hal *ah, const GAIN_VALUES *gv) +{ + return (gv->currGain <= gv->loTrig || gv->currGain >= gv->hiTrig); +} + +/* + * Move the rabbit ears in the correct direction. + */ +static int32_t +ar5212AdjustGain(struct ath_hal *ah, GAIN_VALUES *gv) +{ + const GAIN_OPTIMIZATION_LADDER *gl; + + if (IS_RAD5112_ANY(ah)) + gl = &gainLadder5112; + else + gl = &gainLadder; + gv->currStep = &gl->optStep[gv->currStepNum]; + if (gv->currGain >= gv->hiTrig) { + if (gv->currStepNum == 0) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: Max gain limit.\n", + __func__); + return -1; + } + HALDEBUG(ah, HAL_DEBUG_RFPARAM, + "%s: Adding gain: currG=%d [%s] --> ", + __func__, gv->currGain, gv->currStep->stepName); + gv->targetGain = gv->currGain; + while (gv->targetGain >= gv->hiTrig && gv->currStepNum > 0) { + gv->targetGain -= 2 * (gl->optStep[--(gv->currStepNum)].stepGain - + gv->currStep->stepGain); + gv->currStep = &gl->optStep[gv->currStepNum]; + } + HALDEBUG(ah, HAL_DEBUG_RFPARAM, "targG=%d [%s]\n", + gv->targetGain, gv->currStep->stepName); + return 1; + } + if (gv->currGain <= gv->loTrig) { + if (gv->currStepNum == gl->numStepsInLadder-1) { + HALDEBUG(ah, HAL_DEBUG_RFPARAM, + "%s: Min gain limit.\n", __func__); + return -2; + } + HALDEBUG(ah, HAL_DEBUG_RFPARAM, + "%s: Deducting gain: currG=%d [%s] --> ", + __func__, gv->currGain, gv->currStep->stepName); + gv->targetGain = gv->currGain; + while (gv->targetGain <= gv->loTrig && + gv->currStepNum < (gl->numStepsInLadder - 1)) { + gv->targetGain -= 2 * + (gl->optStep[++(gv->currStepNum)].stepGain - gv->currStep->stepGain); + gv->currStep = &gl->optStep[gv->currStepNum]; + } + HALDEBUG(ah, HAL_DEBUG_RFPARAM, "targG=%d [%s]\n", + gv->targetGain, gv->currStep->stepName); + return 2; + } + return 0; /* caller didn't call needAdjGain first */ +} + +/* + * Read rf register to determine if gainF needs correction + */ +static void +ar5212GetGainFCorrection(struct ath_hal *ah) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + GAIN_VALUES *gv = &ahp->ah_gainValues; + + HALASSERT(IS_RADX112_REV2(ah)); + + gv->gainFCorrection = 0; + if (ar5212GetRfField(ar5212GetRfBank(ah, 7), 1, 36, 0) == 1) { + uint32_t mixGain = gv->currStep->paramVal[0]; + uint32_t gainStep = + ar5212GetRfField(ar5212GetRfBank(ah, 7), 4, 32, 0); + switch (mixGain) { + case 0 : + gv->gainFCorrection = 0; + break; + case 1 : + gv->gainFCorrection = gainStep; + break; + case 2 : + gv->gainFCorrection = 2 * gainStep - 5; + break; + case 3 : + gv->gainFCorrection = 2 * gainStep; + break; + } + } +} + +/* + * Exported call to check for a recent gain reading and return + * the current state of the thermal calibration gain engine. + */ +HAL_RFGAIN +ar5212GetRfgain(struct ath_hal *ah) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + GAIN_VALUES *gv = &ahp->ah_gainValues; + uint32_t rddata, probeType; + + if (!gv->active) + return HAL_RFGAIN_INACTIVE; + + if (ahp->ah_rfgainState == HAL_RFGAIN_READ_REQUESTED) { + /* Caller had asked to setup a new reading. Check it. */ + rddata = OS_REG_READ(ah, AR_PHY_PAPD_PROBE); + + if ((rddata & AR_PHY_PAPD_PROBE_NEXT_TX) == 0) { + /* bit got cleared, we have a new reading. */ + gv->currGain = rddata >> AR_PHY_PAPD_PROBE_GAINF_S; + probeType = MS(rddata, AR_PHY_PAPD_PROBE_TYPE); + if (probeType == AR_PHY_PAPD_PROBE_TYPE_CCK) { + const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom; + + HALASSERT(IS_RAD5112_ANY(ah)); + HALASSERT(ah->ah_magic == AR5212_MAGIC); + if (AH_PRIVATE(ah)->ah_phyRev >= AR_PHY_CHIP_ID_REV_2) + gv->currGain += ee->ee_cckOfdmGainDelta; + else + gv->currGain += PHY_PROBE_CCK_CORRECTION; + } + if (IS_RADX112_REV2(ah)) { + ar5212GetGainFCorrection(ah); + if (gv->currGain >= gv->gainFCorrection) + gv->currGain -= gv->gainFCorrection; + else + gv->currGain = 0; + } + /* inactive by default */ + ahp->ah_rfgainState = HAL_RFGAIN_INACTIVE; + + if (!ar5212InvalidGainReadback(ah, gv) && + ar5212IsGainAdjustNeeded(ah, gv) && + ar5212AdjustGain(ah, gv) > 0) { + /* + * Change needed. Copy ladder info + * into eeprom info. + */ + ahp->ah_rfgainState = HAL_RFGAIN_NEED_CHANGE; + /* for ap51 */ + ahp->ah_cwCalRequire = AH_TRUE; + /* Request IQ recalibration for temperature chang */ + ahp->ah_bIQCalibration = IQ_CAL_INACTIVE; + } + } + } + return ahp->ah_rfgainState; +} --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5212/ar5212_xmit.c 2009-03-23 17:36:55.000000000 +0000 @@ -0,0 +1,918 @@ +/* + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2008 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ar5212_xmit.c,v 1.1 2009/03/23 17:14:48 sborrill Exp $ + */ +#include "opt_ah.h" + +#include "ah.h" +#include "ah_internal.h" + +#include "ar5212/ar5212.h" +#include "ar5212/ar5212reg.h" +#include "ar5212/ar5212desc.h" +#include "ar5212/ar5212phy.h" +#ifdef AH_SUPPORT_5311 +#include "ar5212/ar5311reg.h" +#endif + +#ifdef AH_NEED_DESC_SWAP +static void ar5212SwapTxDesc(struct ath_desc *ds); +#endif + +/* + * Update Tx FIFO trigger level. + * + * Set bIncTrigLevel to TRUE to increase the trigger level. + * Set bIncTrigLevel to FALSE to decrease the trigger level. + * + * Returns TRUE if the trigger level was updated + */ +HAL_BOOL +ar5212UpdateTxTrigLevel(struct ath_hal *ah, HAL_BOOL bIncTrigLevel) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + uint32_t txcfg, curLevel, newLevel; + HAL_INT omask; + + /* + * Disable interrupts while futzing with the fifo level. + */ + omask = ar5212SetInterrupts(ah, ahp->ah_maskReg &~ HAL_INT_GLOBAL); + + txcfg = OS_REG_READ(ah, AR_TXCFG); + curLevel = MS(txcfg, AR_FTRIG); + newLevel = curLevel; + if (bIncTrigLevel) { /* increase the trigger level */ + if (curLevel < MAX_TX_FIFO_THRESHOLD) + newLevel++; + } else if (curLevel > MIN_TX_FIFO_THRESHOLD) + newLevel--; + if (newLevel != curLevel) + /* Update the trigger level */ + OS_REG_WRITE(ah, AR_TXCFG, + (txcfg &~ AR_FTRIG) | SM(newLevel, AR_FTRIG)); + + /* re-enable chip interrupts */ + ar5212SetInterrupts(ah, omask); + + return (newLevel != curLevel); +} + +/* + * Set the properties of the tx queue with the parameters + * from qInfo. + */ +HAL_BOOL +ar5212SetTxQueueProps(struct ath_hal *ah, int q, const HAL_TXQ_INFO *qInfo) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps; + + if (q >= pCap->halTotalQueues) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid queue num %u\n", + __func__, q); + return AH_FALSE; + } + return ath_hal_setTxQProps(ah, &ahp->ah_txq[q], qInfo); +} + +/* + * Return the properties for the specified tx queue. + */ +HAL_BOOL +ar5212GetTxQueueProps(struct ath_hal *ah, int q, HAL_TXQ_INFO *qInfo) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps; + + + if (q >= pCap->halTotalQueues) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid queue num %u\n", + __func__, q); + return AH_FALSE; + } + return ath_hal_getTxQProps(ah, qInfo, &ahp->ah_txq[q]); +} + +/* + * Allocate and initialize a tx DCU/QCU combination. + */ +int +ar5212SetupTxQueue(struct ath_hal *ah, HAL_TX_QUEUE type, + const HAL_TXQ_INFO *qInfo) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + HAL_TX_QUEUE_INFO *qi; + HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps; + int q, defqflags; + + /* by default enable OK+ERR+DESC+URN interrupts */ + defqflags = HAL_TXQ_TXOKINT_ENABLE + | HAL_TXQ_TXERRINT_ENABLE + | HAL_TXQ_TXDESCINT_ENABLE + | HAL_TXQ_TXURNINT_ENABLE; + /* XXX move queue assignment to driver */ + switch (type) { + case HAL_TX_QUEUE_BEACON: + q = pCap->halTotalQueues-1; /* highest priority */ + defqflags |= HAL_TXQ_DBA_GATED + | HAL_TXQ_CBR_DIS_QEMPTY + | HAL_TXQ_ARB_LOCKOUT_GLOBAL + | HAL_TXQ_BACKOFF_DISABLE; + break; + case HAL_TX_QUEUE_CAB: + q = pCap->halTotalQueues-2; /* next highest priority */ + defqflags |= HAL_TXQ_DBA_GATED + | HAL_TXQ_CBR_DIS_QEMPTY + | HAL_TXQ_CBR_DIS_BEMPTY + | HAL_TXQ_ARB_LOCKOUT_GLOBAL + | HAL_TXQ_BACKOFF_DISABLE; + break; + case HAL_TX_QUEUE_UAPSD: + q = pCap->halTotalQueues-3; /* nextest highest priority */ + if (ahp->ah_txq[q].tqi_type != HAL_TX_QUEUE_INACTIVE) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: no available UAPSD tx queue\n", __func__); + return -1; + } + break; + case HAL_TX_QUEUE_DATA: + for (q = 0; q < pCap->halTotalQueues; q++) + if (ahp->ah_txq[q].tqi_type == HAL_TX_QUEUE_INACTIVE) + break; + if (q == pCap->halTotalQueues) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: no available tx queue\n", __func__); + return -1; + } + break; + default: + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: bad tx queue type %u\n", __func__, type); + return -1; + } + + HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: queue %u\n", __func__, q); + + qi = &ahp->ah_txq[q]; + if (qi->tqi_type != HAL_TX_QUEUE_INACTIVE) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: tx queue %u already active\n", + __func__, q); + return -1; + } + OS_MEMZERO(qi, sizeof(HAL_TX_QUEUE_INFO)); + qi->tqi_type = type; + if (qInfo == AH_NULL) { + qi->tqi_qflags = defqflags; + qi->tqi_aifs = INIT_AIFS; + qi->tqi_cwmin = HAL_TXQ_USEDEFAULT; /* NB: do at reset */ + qi->tqi_cwmax = INIT_CWMAX; + qi->tqi_shretry = INIT_SH_RETRY; + qi->tqi_lgretry = INIT_LG_RETRY; + qi->tqi_physCompBuf = 0; + } else { + qi->tqi_physCompBuf = qInfo->tqi_compBuf; + (void) ar5212SetTxQueueProps(ah, q, qInfo); + } + /* NB: must be followed by ar5212ResetTxQueue */ + return q; +} + +/* + * Update the h/w interrupt registers to reflect a tx q's configuration. + */ +static void +setTxQInterrupts(struct ath_hal *ah, HAL_TX_QUEUE_INFO *qi) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + + HALDEBUG(ah, HAL_DEBUG_TXQUEUE, + "%s: tx ok 0x%x err 0x%x desc 0x%x eol 0x%x urn 0x%x\n", __func__, + ahp->ah_txOkInterruptMask, ahp->ah_txErrInterruptMask, + ahp->ah_txDescInterruptMask, ahp->ah_txEolInterruptMask, + ahp->ah_txUrnInterruptMask); + + OS_REG_WRITE(ah, AR_IMR_S0, + SM(ahp->ah_txOkInterruptMask, AR_IMR_S0_QCU_TXOK) + | SM(ahp->ah_txDescInterruptMask, AR_IMR_S0_QCU_TXDESC) + ); + OS_REG_WRITE(ah, AR_IMR_S1, + SM(ahp->ah_txErrInterruptMask, AR_IMR_S1_QCU_TXERR) + | SM(ahp->ah_txEolInterruptMask, AR_IMR_S1_QCU_TXEOL) + ); + OS_REG_RMW_FIELD(ah, AR_IMR_S2, + AR_IMR_S2_QCU_TXURN, ahp->ah_txUrnInterruptMask); +} + +/* + * Free a tx DCU/QCU combination. + */ +HAL_BOOL +ar5212ReleaseTxQueue(struct ath_hal *ah, u_int q) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps; + HAL_TX_QUEUE_INFO *qi; + + if (q >= pCap->halTotalQueues) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid queue num %u\n", + __func__, q); + return AH_FALSE; + } + qi = &ahp->ah_txq[q]; + if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) { + HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: inactive queue %u\n", + __func__, q); + return AH_FALSE; + } + + HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: release queue %u\n", __func__, q); + + qi->tqi_type = HAL_TX_QUEUE_INACTIVE; + ahp->ah_txOkInterruptMask &= ~(1 << q); + ahp->ah_txErrInterruptMask &= ~(1 << q); + ahp->ah_txDescInterruptMask &= ~(1 << q); + ahp->ah_txEolInterruptMask &= ~(1 << q); + ahp->ah_txUrnInterruptMask &= ~(1 << q); + setTxQInterrupts(ah, qi); + + return AH_TRUE; +} + +/* + * Set the retry, aifs, cwmin/max, readyTime regs for specified queue + * Assumes: + * phwChannel has been set to point to the current channel + */ +HAL_BOOL +ar5212ResetTxQueue(struct ath_hal *ah, u_int q) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps; + HAL_CHANNEL_INTERNAL *chan = AH_PRIVATE(ah)->ah_curchan; + HAL_TX_QUEUE_INFO *qi; + uint32_t cwMin, chanCwMin, value, qmisc, dmisc; + + if (q >= pCap->halTotalQueues) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid queue num %u\n", + __func__, q); + return AH_FALSE; + } + qi = &ahp->ah_txq[q]; + if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) { + HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: inactive queue %u\n", + __func__, q); + return AH_TRUE; /* XXX??? */ + } + + HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: reset queue %u\n", __func__, q); + + if (qi->tqi_cwmin == HAL_TXQ_USEDEFAULT) { + /* + * Select cwmin according to channel type. + * NB: chan can be NULL during attach + */ + if (chan && IS_CHAN_B(chan)) + chanCwMin = INIT_CWMIN_11B; + else + chanCwMin = INIT_CWMIN; + /* make sure that the CWmin is of the form (2^n - 1) */ + for (cwMin = 1; cwMin < chanCwMin; cwMin = (cwMin << 1) | 1) + ; + } else + cwMin = qi->tqi_cwmin; + + /* set cwMin/Max and AIFS values */ + OS_REG_WRITE(ah, AR_DLCL_IFS(q), + SM(cwMin, AR_D_LCL_IFS_CWMIN) + | SM(qi->tqi_cwmax, AR_D_LCL_IFS_CWMAX) + | SM(qi->tqi_aifs, AR_D_LCL_IFS_AIFS)); + + /* Set retry limit values */ + OS_REG_WRITE(ah, AR_DRETRY_LIMIT(q), + SM(INIT_SSH_RETRY, AR_D_RETRY_LIMIT_STA_SH) + | SM(INIT_SLG_RETRY, AR_D_RETRY_LIMIT_STA_LG) + | SM(qi->tqi_lgretry, AR_D_RETRY_LIMIT_FR_LG) + | SM(qi->tqi_shretry, AR_D_RETRY_LIMIT_FR_SH) + ); + + /* NB: always enable early termination on the QCU */ + qmisc = AR_Q_MISC_DCU_EARLY_TERM_REQ + | SM(AR_Q_MISC_FSP_ASAP, AR_Q_MISC_FSP); + + /* NB: always enable DCU to wait for next fragment from QCU */ + dmisc = AR_D_MISC_FRAG_WAIT_EN; + +#ifdef AH_SUPPORT_5311 + if (AH_PRIVATE(ah)->ah_macVersion < AR_SREV_VERSION_OAHU) { + /* Configure DCU to use the global sequence count */ + dmisc |= AR5311_D_MISC_SEQ_NUM_CONTROL; + } +#endif + /* multiqueue support */ + if (qi->tqi_cbrPeriod) { + OS_REG_WRITE(ah, AR_QCBRCFG(q), + SM(qi->tqi_cbrPeriod,AR_Q_CBRCFG_CBR_INTERVAL) + | SM(qi->tqi_cbrOverflowLimit, AR_Q_CBRCFG_CBR_OVF_THRESH)); + qmisc = (qmisc &~ AR_Q_MISC_FSP) | AR_Q_MISC_FSP_CBR; + if (qi->tqi_cbrOverflowLimit) + qmisc |= AR_Q_MISC_CBR_EXP_CNTR_LIMIT; + } + if (qi->tqi_readyTime) { + OS_REG_WRITE(ah, AR_QRDYTIMECFG(q), + SM(qi->tqi_readyTime, AR_Q_RDYTIMECFG_INT) + | AR_Q_RDYTIMECFG_ENA); + } + + OS_REG_WRITE(ah, AR_DCHNTIME(q), + SM(qi->tqi_burstTime, AR_D_CHNTIME_DUR) + | (qi->tqi_burstTime ? AR_D_CHNTIME_EN : 0)); + + if (qi->tqi_readyTime && + (qi->tqi_qflags & HAL_TXQ_RDYTIME_EXP_POLICY_ENABLE)) + qmisc |= AR_Q_MISC_RDYTIME_EXP_POLICY; + if (qi->tqi_qflags & HAL_TXQ_DBA_GATED) + qmisc = (qmisc &~ AR_Q_MISC_FSP) | AR_Q_MISC_FSP_DBA_GATED; + if (MS(qmisc, AR_Q_MISC_FSP) != AR_Q_MISC_FSP_ASAP) { + /* + * These are meangingful only when not scheduled asap. + */ + if (qi->tqi_qflags & HAL_TXQ_CBR_DIS_BEMPTY) + qmisc |= AR_Q_MISC_CBR_INCR_DIS0; + else + qmisc &= ~AR_Q_MISC_CBR_INCR_DIS0; + if (qi->tqi_qflags & HAL_TXQ_CBR_DIS_QEMPTY) + qmisc |= AR_Q_MISC_CBR_INCR_DIS1; + else + qmisc &= ~AR_Q_MISC_CBR_INCR_DIS1; + } + + if (qi->tqi_qflags & HAL_TXQ_BACKOFF_DISABLE) + dmisc |= AR_D_MISC_POST_FR_BKOFF_DIS; + if (qi->tqi_qflags & HAL_TXQ_FRAG_BURST_BACKOFF_ENABLE) + dmisc |= AR_D_MISC_FRAG_BKOFF_EN; + if (qi->tqi_qflags & HAL_TXQ_ARB_LOCKOUT_GLOBAL) + dmisc |= SM(AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL, + AR_D_MISC_ARB_LOCKOUT_CNTRL); + else if (qi->tqi_qflags & HAL_TXQ_ARB_LOCKOUT_INTRA) + dmisc |= SM(AR_D_MISC_ARB_LOCKOUT_CNTRL_INTRA_FR, + AR_D_MISC_ARB_LOCKOUT_CNTRL); + if (qi->tqi_qflags & HAL_TXQ_IGNORE_VIRTCOL) + dmisc |= SM(AR_D_MISC_VIR_COL_HANDLING_IGNORE, + AR_D_MISC_VIR_COL_HANDLING); + if (qi->tqi_qflags & HAL_TXQ_SEQNUM_INC_DIS) + dmisc |= AR_D_MISC_SEQ_NUM_INCR_DIS; + + /* + * Fillin type-dependent bits. Most of this can be + * removed by specifying the queue parameters in the + * driver; it's here for backwards compatibility. + */ + switch (qi->tqi_type) { + case HAL_TX_QUEUE_BEACON: /* beacon frames */ + qmisc |= AR_Q_MISC_FSP_DBA_GATED + | AR_Q_MISC_BEACON_USE + | AR_Q_MISC_CBR_INCR_DIS1; + + dmisc |= SM(AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL, + AR_D_MISC_ARB_LOCKOUT_CNTRL) + | AR_D_MISC_BEACON_USE + | AR_D_MISC_POST_FR_BKOFF_DIS; + break; + case HAL_TX_QUEUE_CAB: /* CAB frames */ + /* + * No longer Enable AR_Q_MISC_RDYTIME_EXP_POLICY, + * There is an issue with the CAB Queue + * not properly refreshing the Tx descriptor if + * the TXE clear setting is used. + */ + qmisc |= AR_Q_MISC_FSP_DBA_GATED + | AR_Q_MISC_CBR_INCR_DIS1 + | AR_Q_MISC_CBR_INCR_DIS0; + + if (!qi->tqi_readyTime) { + /* + * NB: don't set default ready time if driver + * has explicitly specified something. This is + * here solely for backwards compatibility. + */ + value = (ahp->ah_beaconInterval + - (ath_hal_sw_beacon_response_time - + ath_hal_dma_beacon_response_time) + - ath_hal_additional_swba_backoff) * 1024; + OS_REG_WRITE(ah, AR_QRDYTIMECFG(q), value | AR_Q_RDYTIMECFG_ENA); + } + dmisc |= SM(AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL, + AR_D_MISC_ARB_LOCKOUT_CNTRL); + break; + default: /* NB: silence compiler */ + break; + } + + OS_REG_WRITE(ah, AR_QMISC(q), qmisc); + OS_REG_WRITE(ah, AR_DMISC(q), dmisc); + + /* Setup compression scratchpad buffer */ + /* + * XXX: calling this asynchronously to queue operation can + * cause unexpected behavior!!! + */ + if (qi->tqi_physCompBuf) { + HALASSERT(qi->tqi_type == HAL_TX_QUEUE_DATA || + qi->tqi_type == HAL_TX_QUEUE_UAPSD); + OS_REG_WRITE(ah, AR_Q_CBBS, (80 + 2*q)); + OS_REG_WRITE(ah, AR_Q_CBBA, qi->tqi_physCompBuf); + OS_REG_WRITE(ah, AR_Q_CBC, HAL_COMP_BUF_MAX_SIZE/1024); + OS_REG_WRITE(ah, AR_Q0_MISC + 4*q, + OS_REG_READ(ah, AR_Q0_MISC + 4*q) + | AR_Q_MISC_QCU_COMP_EN); + } + + /* + * Always update the secondary interrupt mask registers - this + * could be a new queue getting enabled in a running system or + * hw getting re-initialized during a reset! + * + * Since we don't differentiate between tx interrupts corresponding + * to individual queues - secondary tx mask regs are always unmasked; + * tx interrupts are enabled/disabled for all queues collectively + * using the primary mask reg + */ + if (qi->tqi_qflags & HAL_TXQ_TXOKINT_ENABLE) + ahp->ah_txOkInterruptMask |= 1 << q; + else + ahp->ah_txOkInterruptMask &= ~(1 << q); + if (qi->tqi_qflags & HAL_TXQ_TXERRINT_ENABLE) + ahp->ah_txErrInterruptMask |= 1 << q; + else + ahp->ah_txErrInterruptMask &= ~(1 << q); + if (qi->tqi_qflags & HAL_TXQ_TXDESCINT_ENABLE) + ahp->ah_txDescInterruptMask |= 1 << q; + else + ahp->ah_txDescInterruptMask &= ~(1 << q); + if (qi->tqi_qflags & HAL_TXQ_TXEOLINT_ENABLE) + ahp->ah_txEolInterruptMask |= 1 << q; + else + ahp->ah_txEolInterruptMask &= ~(1 << q); + if (qi->tqi_qflags & HAL_TXQ_TXURNINT_ENABLE) + ahp->ah_txUrnInterruptMask |= 1 << q; + else + ahp->ah_txUrnInterruptMask &= ~(1 << q); + setTxQInterrupts(ah, qi); + + return AH_TRUE; +} + +/* + * Get the TXDP for the specified queue + */ +uint32_t +ar5212GetTxDP(struct ath_hal *ah, u_int q) +{ + HALASSERT(q < AH_PRIVATE(ah)->ah_caps.halTotalQueues); + return OS_REG_READ(ah, AR_QTXDP(q)); +} + +/* + * Set the TxDP for the specified queue + */ +HAL_BOOL +ar5212SetTxDP(struct ath_hal *ah, u_int q, uint32_t txdp) +{ + HALASSERT(q < AH_PRIVATE(ah)->ah_caps.halTotalQueues); + HALASSERT(AH5212(ah)->ah_txq[q].tqi_type != HAL_TX_QUEUE_INACTIVE); + + /* + * Make sure that TXE is deasserted before setting the TXDP. If TXE + * is still asserted, setting TXDP will have no effect. + */ + HALASSERT((OS_REG_READ(ah, AR_Q_TXE) & (1 << q)) == 0); + + OS_REG_WRITE(ah, AR_QTXDP(q), txdp); + + return AH_TRUE; +} + +/* + * Set Transmit Enable bits for the specified queue + */ +HAL_BOOL +ar5212StartTxDma(struct ath_hal *ah, u_int q) +{ + HALASSERT(q < AH_PRIVATE(ah)->ah_caps.halTotalQueues); + + HALASSERT(AH5212(ah)->ah_txq[q].tqi_type != HAL_TX_QUEUE_INACTIVE); + + HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: queue %u\n", __func__, q); + + /* Check to be sure we're not enabling a q that has its TXD bit set. */ + HALASSERT((OS_REG_READ(ah, AR_Q_TXD) & (1 << q)) == 0); + + OS_REG_WRITE(ah, AR_Q_TXE, 1 << q); + return AH_TRUE; +} + +/* + * Return the number of pending frames or 0 if the specified + * queue is stopped. + */ +uint32_t +ar5212NumTxPending(struct ath_hal *ah, u_int q) +{ + uint32_t npend; + + HALASSERT(q < AH_PRIVATE(ah)->ah_caps.halTotalQueues); + HALASSERT(AH5212(ah)->ah_txq[q].tqi_type != HAL_TX_QUEUE_INACTIVE); + + npend = OS_REG_READ(ah, AR_QSTS(q)) & AR_Q_STS_PEND_FR_CNT; + if (npend == 0) { + /* + * Pending frame count (PFC) can momentarily go to zero + * while TXE remains asserted. In other words a PFC of + * zero is not sufficient to say that the queue has stopped. + */ + if (OS_REG_READ(ah, AR_Q_TXE) & (1 << q)) + npend = 1; /* arbitrarily return 1 */ + } + return npend; +} + +/* + * Stop transmit on the specified queue + */ +HAL_BOOL +ar5212StopTxDma(struct ath_hal *ah, u_int q) +{ + u_int i; + u_int wait; + + HALASSERT(q < AH_PRIVATE(ah)->ah_caps.halTotalQueues); + + HALASSERT(AH5212(ah)->ah_txq[q].tqi_type != HAL_TX_QUEUE_INACTIVE); + + OS_REG_WRITE(ah, AR_Q_TXD, 1 << q); + for (i = 1000; i != 0; i--) { + if (ar5212NumTxPending(ah, q) == 0) + break; + OS_DELAY(100); /* XXX get actual value */ + } +#ifdef AH_DEBUG + if (i == 0) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: queue %u DMA did not stop in 100 msec\n", __func__, q); + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: QSTS 0x%x Q_TXE 0x%x Q_TXD 0x%x Q_CBR 0x%x\n", __func__, + OS_REG_READ(ah, AR_QSTS(q)), OS_REG_READ(ah, AR_Q_TXE), + OS_REG_READ(ah, AR_Q_TXD), OS_REG_READ(ah, AR_QCBRCFG(q))); + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: Q_MISC 0x%x Q_RDYTIMECFG 0x%x Q_RDYTIMESHDN 0x%x\n", + __func__, OS_REG_READ(ah, AR_QMISC(q)), + OS_REG_READ(ah, AR_QRDYTIMECFG(q)), + OS_REG_READ(ah, AR_Q_RDYTIMESHDN)); + } +#endif /* AH_DEBUG */ + + /* 2413+ and up can kill packets at the PCU level */ + if (ar5212NumTxPending(ah, q) && + (IS_2413(ah) || IS_5413(ah) || IS_2425(ah) || IS_2417(ah))) { + uint32_t tsfLow, j; + + HALDEBUG(ah, HAL_DEBUG_TXQUEUE, + "%s: Num of pending TX Frames %d on Q %d\n", + __func__, ar5212NumTxPending(ah, q), q); + + /* Kill last PCU Tx Frame */ + /* TODO - save off and restore current values of Q1/Q2? */ + for (j = 0; j < 2; j++) { + tsfLow = OS_REG_READ(ah, AR_TSF_L32); + OS_REG_WRITE(ah, AR_QUIET2, SM(100, AR_QUIET2_QUIET_PER) | + SM(10, AR_QUIET2_QUIET_DUR)); + OS_REG_WRITE(ah, AR_QUIET1, AR_QUIET1_QUIET_ENABLE | + SM(tsfLow >> 10, AR_QUIET1_NEXT_QUIET)); + if ((OS_REG_READ(ah, AR_TSF_L32) >> 10) == (tsfLow >> 10)) { + break; + } + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: TSF moved while trying to set quiet time " + "TSF: 0x%08x\n", __func__, tsfLow); + HALASSERT(j < 1); /* TSF shouldn't count twice or reg access is taking forever */ + } + + OS_REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_CHAN_IDLE); + + /* Allow the quiet mechanism to do its work */ + OS_DELAY(200); + OS_REG_CLR_BIT(ah, AR_QUIET1, AR_QUIET1_QUIET_ENABLE); + + /* Give at least 1 millisec more to wait */ + wait = 100; + + /* Verify all transmit is dead */ + while (ar5212NumTxPending(ah, q)) { + if ((--wait) == 0) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: Failed to stop Tx DMA in %d msec after killing last frame\n", + __func__, wait); + break; + } + OS_DELAY(10); + } + + OS_REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_CHAN_IDLE); + } + + OS_REG_WRITE(ah, AR_Q_TXD, 0); + return (i != 0); +} + +/* + * Descriptor Access Functions + */ + +#define VALID_PKT_TYPES \ + ((1<ah_txPowerIndexOffset ); + if(txPower > 63) txPower=63; + + ads->ds_ctl0 = (pktLen & AR_FrameLen) + | (txPower << AR_XmitPower_S) + | (flags & HAL_TXDESC_VEOL ? AR_VEOL : 0) + | (flags & HAL_TXDESC_CLRDMASK ? AR_ClearDestMask : 0) + | SM(antMode, AR_AntModeXmit) + | (flags & HAL_TXDESC_INTREQ ? AR_TxInterReq : 0) + ; + ads->ds_ctl1 = (type << AR_FrmType_S) + | (flags & HAL_TXDESC_NOACK ? AR_NoAck : 0) + | (comp << AR_CompProc_S) + | (compicvLen << AR_CompICVLen_S) + | (compivLen << AR_CompIVLen_S) + ; + ads->ds_ctl2 = SM(txTries0, AR_XmitDataTries0) + | (flags & HAL_TXDESC_DURENA ? AR_DurUpdateEna : 0) + ; + ads->ds_ctl3 = (txRate0 << AR_XmitRate0_S) + ; + if (keyIx != HAL_TXKEYIX_INVALID) { + /* XXX validate key index */ + ads->ds_ctl1 |= SM(keyIx, AR_DestIdx); + ads->ds_ctl0 |= AR_DestIdxValid; + } + if (flags & RTSCTS) { + if (!isValidTxRate(rtsctsRate)) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: invalid rts/cts rate 0x%x\n", + __func__, rtsctsRate); + return AH_FALSE; + } + /* XXX validate rtsctsDuration */ + ads->ds_ctl0 |= (flags & HAL_TXDESC_CTSENA ? AR_CTSEnable : 0) + | (flags & HAL_TXDESC_RTSENA ? AR_RTSCTSEnable : 0) + ; + ads->ds_ctl2 |= SM(rtsctsDuration, AR_RTSCTSDuration); + ads->ds_ctl3 |= (rtsctsRate << AR_RTSCTSRate_S); + } + return AH_TRUE; +#undef RTSCTS +} + +HAL_BOOL +ar5212SetupXTxDesc(struct ath_hal *ah, struct ath_desc *ds, + u_int txRate1, u_int txTries1, + u_int txRate2, u_int txTries2, + u_int txRate3, u_int txTries3) +{ + struct ar5212_desc *ads = AR5212DESC(ds); + + if (txTries1) { + HALASSERT(isValidTxRate(txRate1)); + ads->ds_ctl2 |= SM(txTries1, AR_XmitDataTries1) + | AR_DurUpdateEna + ; + ads->ds_ctl3 |= (txRate1 << AR_XmitRate1_S); + } + if (txTries2) { + HALASSERT(isValidTxRate(txRate2)); + ads->ds_ctl2 |= SM(txTries2, AR_XmitDataTries2) + | AR_DurUpdateEna + ; + ads->ds_ctl3 |= (txRate2 << AR_XmitRate2_S); + } + if (txTries3) { + HALASSERT(isValidTxRate(txRate3)); + ads->ds_ctl2 |= SM(txTries3, AR_XmitDataTries3) + | AR_DurUpdateEna + ; + ads->ds_ctl3 |= (txRate3 << AR_XmitRate3_S); + } + return AH_TRUE; +} + +void +ar5212IntrReqTxDesc(struct ath_hal *ah, struct ath_desc *ds) +{ + struct ar5212_desc *ads = AR5212DESC(ds); + +#ifdef AH_NEED_DESC_SWAP + ads->ds_ctl0 |= __bswap32(AR_TxInterReq); +#else + ads->ds_ctl0 |= AR_TxInterReq; +#endif +} + +HAL_BOOL +ar5212FillTxDesc(struct ath_hal *ah, struct ath_desc *ds, + u_int segLen, HAL_BOOL firstSeg, HAL_BOOL lastSeg, + const struct ath_desc *ds0) +{ + struct ar5212_desc *ads = AR5212DESC(ds); + + HALASSERT((segLen &~ AR_BufLen) == 0); + + if (firstSeg) { + /* + * First descriptor, don't clobber xmit control data + * setup by ar5212SetupTxDesc. + */ + ads->ds_ctl1 |= segLen | (lastSeg ? 0 : AR_More); + } else if (lastSeg) { /* !firstSeg && lastSeg */ + /* + * Last descriptor in a multi-descriptor frame, + * copy the multi-rate transmit parameters from + * the first frame for processing on completion. + */ + ads->ds_ctl0 = 0; + ads->ds_ctl1 = segLen; +#ifdef AH_NEED_DESC_SWAP + ads->ds_ctl2 = __bswap32(AR5212DESC_CONST(ds0)->ds_ctl2); + ads->ds_ctl3 = __bswap32(AR5212DESC_CONST(ds0)->ds_ctl3); +#else + ads->ds_ctl2 = AR5212DESC_CONST(ds0)->ds_ctl2; + ads->ds_ctl3 = AR5212DESC_CONST(ds0)->ds_ctl3; +#endif + } else { /* !firstSeg && !lastSeg */ + /* + * Intermediate descriptor in a multi-descriptor frame. + */ + ads->ds_ctl0 = 0; + ads->ds_ctl1 = segLen | AR_More; + ads->ds_ctl2 = 0; + ads->ds_ctl3 = 0; + } + ads->ds_txstatus0 = ads->ds_txstatus1 = 0; + return AH_TRUE; +} + +#ifdef AH_NEED_DESC_SWAP +/* Swap transmit descriptor */ +static __inline void +ar5212SwapTxDesc(struct ath_desc *ds) +{ + ds->ds_data = __bswap32(ds->ds_data); + ds->ds_ctl0 = __bswap32(ds->ds_ctl0); + ds->ds_ctl1 = __bswap32(ds->ds_ctl1); + ds->ds_hw[0] = __bswap32(ds->ds_hw[0]); + ds->ds_hw[1] = __bswap32(ds->ds_hw[1]); + ds->ds_hw[2] = __bswap32(ds->ds_hw[2]); + ds->ds_hw[3] = __bswap32(ds->ds_hw[3]); +} +#endif + +/* + * Processing of HW TX descriptor. + */ +HAL_STATUS +ar5212ProcTxDesc(struct ath_hal *ah, + struct ath_desc *ds, struct ath_tx_status *ts) +{ + struct ar5212_desc *ads = AR5212DESC(ds); + +#ifdef AH_NEED_DESC_SWAP + if ((ads->ds_txstatus1 & __bswap32(AR_Done)) == 0) + return HAL_EINPROGRESS; + + ar5212SwapTxDesc(ds); +#else + if ((ads->ds_txstatus1 & AR_Done) == 0) + return HAL_EINPROGRESS; +#endif + + /* Update software copies of the HW status */ + ts->ts_seqnum = MS(ads->ds_txstatus1, AR_SeqNum); + ts->ts_tstamp = MS(ads->ds_txstatus0, AR_SendTimestamp); + ts->ts_status = 0; + if ((ads->ds_txstatus0 & AR_FrmXmitOK) == 0) { + if (ads->ds_txstatus0 & AR_ExcessiveRetries) + ts->ts_status |= HAL_TXERR_XRETRY; + if (ads->ds_txstatus0 & AR_Filtered) + ts->ts_status |= HAL_TXERR_FILT; + if (ads->ds_txstatus0 & AR_FIFOUnderrun) + ts->ts_status |= HAL_TXERR_FIFO; + } + /* + * Extract the transmit rate used and mark the rate as + * ``alternate'' if it wasn't the series 0 rate. + */ + ts->ts_finaltsi = MS(ads->ds_txstatus1, AR_FinalTSIndex); + switch (ts->ts_finaltsi) { + case 0: + ts->ts_rate = MS(ads->ds_ctl3, AR_XmitRate0); + break; + case 1: + ts->ts_rate = MS(ads->ds_ctl3, AR_XmitRate1) | + HAL_TXSTAT_ALTRATE; + break; + case 2: + ts->ts_rate = MS(ads->ds_ctl3, AR_XmitRate2) | + HAL_TXSTAT_ALTRATE; + break; + case 3: + ts->ts_rate = MS(ads->ds_ctl3, AR_XmitRate3) | + HAL_TXSTAT_ALTRATE; + break; + } + ts->ts_rssi = MS(ads->ds_txstatus1, AR_AckSigStrength); + ts->ts_shortretry = MS(ads->ds_txstatus0, AR_RTSFailCnt); + ts->ts_longretry = MS(ads->ds_txstatus0, AR_DataFailCnt); + /* + * The retry count has the number of un-acked tries for the + * final series used. When doing multi-rate retry we must + * fixup the retry count by adding in the try counts for + * each series that was fully-processed. Beware that this + * takes values from the try counts in the final descriptor. + * These are not required by the hardware. We assume they + * are placed there by the driver as otherwise we have no + * access and the driver can't do the calculation because it + * doesn't know the descriptor format. + */ + switch (ts->ts_finaltsi) { + case 3: ts->ts_longretry += MS(ads->ds_ctl2, AR_XmitDataTries2); + case 2: ts->ts_longretry += MS(ads->ds_ctl2, AR_XmitDataTries1); + case 1: ts->ts_longretry += MS(ads->ds_ctl2, AR_XmitDataTries0); + } + ts->ts_virtcol = MS(ads->ds_txstatus0, AR_VirtCollCnt); + ts->ts_antenna = (ads->ds_txstatus1 & AR_XmitAtenna ? 2 : 1); + + return HAL_OK; +} + +/* + * Determine which tx queues need interrupt servicing. + */ +void +ar5212GetTxIntrQueue(struct ath_hal *ah, uint32_t *txqs) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + *txqs &= ahp->ah_intrTxqs; + ahp->ah_intrTxqs &= ~(*txqs); +} --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5212/ar5212desc.h 2009-03-23 17:36:55.000000000 +0000 @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2008 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ar5212desc.h,v 1.1 2009/03/23 17:14:48 sborrill Exp $ + */ +#ifndef _ATH_AR5212_DESC_H_ +#define _ATH_AR5212_DESC_H_ + +/* + * Hardware-specific descriptor structures. + */ +#include "ah_desc.h" + +/* + * AR5212-specific tx/rx descriptor definition. + */ +struct ar5212_desc { + uint32_t ds_link; /* link pointer */ + uint32_t ds_data; /* data buffer pointer */ + uint32_t ds_ctl0; /* DMA control 0 */ + uint32_t ds_ctl1; /* DMA control 1 */ + union { + struct { /* xmit format */ + uint32_t ctl2; /* DMA control 2 */ + uint32_t ctl3; /* DMA control 3 */ + uint32_t status0;/* DMA status 0 */ + uint32_t status1;/* DMA status 1 */ + } tx; + struct { /* recv format */ + uint32_t status0;/* DMA status 0 */ + uint32_t status1;/* DMA status 1 */ + } rx; + } u; +} __packed; +#define AR5212DESC(_ds) ((struct ar5212_desc *)(_ds)) +#define AR5212DESC_CONST(_ds) ((const struct ar5212_desc *)(_ds)) + +#define ds_ctl2 u.tx.ctl2 +#define ds_ctl3 u.tx.ctl3 +#define ds_txstatus0 u.tx.status0 +#define ds_txstatus1 u.tx.status1 +#define ds_rxstatus0 u.rx.status0 +#define ds_rxstatus1 u.rx.status1 + +/* TX ds_ctl0 */ +#define AR_FrameLen 0x00000fff /* frame length */ +/* bits 12-15 are reserved */ +#define AR_XmitPower 0x003f0000 /* transmit power control */ +#define AR_XmitPower_S 16 +#define AR_RTSCTSEnable 0x00400000 /* RTS/CTS protocol enable */ +#define AR_VEOL 0x00800000 /* virtual end-of-list */ +#define AR_ClearDestMask 0x01000000 /* Clear destination mask bit */ +#define AR_AntModeXmit 0x1e000000 /* TX antenna seslection */ +#define AR_AntModeXmit_S 25 +#define AR_TxInterReq 0x20000000 /* TX interrupt request */ +#define AR_DestIdxValid 0x40000000 /* destination index valid */ +#define AR_CTSEnable 0x80000000 /* precede frame with CTS */ + +/* TX ds_ctl1 */ +#define AR_BufLen 0x00000fff /* data buffer length */ +#define AR_More 0x00001000 /* more desc in this frame */ +#define AR_DestIdx 0x000fe000 /* destination table index */ +#define AR_DestIdx_S 13 +#define AR_FrmType 0x00f00000 /* frame type indication */ +#define AR_FrmType_S 20 +#define AR_NoAck 0x01000000 /* No ACK flag */ +#define AR_CompProc 0x06000000 /* compression processing */ +#define AR_CompProc_S 25 +#define AR_CompIVLen 0x18000000 /* length of frame IV */ +#define AR_CompIVLen_S 27 +#define AR_CompICVLen 0x60000000 /* length of frame ICV */ +#define AR_CompICVLen_S 29 +/* bit 31 is reserved */ + +/* TX ds_ctl2 */ +#define AR_RTSCTSDuration 0x00007fff /* RTS/CTS duration */ +#define AR_RTSCTSDuration_S 0 +#define AR_DurUpdateEna 0x00008000 /* frame duration update ctl */ +#define AR_XmitDataTries0 0x000f0000 /* series 0 max attempts */ +#define AR_XmitDataTries0_S 16 +#define AR_XmitDataTries1 0x00f00000 /* series 1 max attempts */ +#define AR_XmitDataTries1_S 20 +#define AR_XmitDataTries2 0x0f000000 /* series 2 max attempts */ +#define AR_XmitDataTries2_S 24 +#define AR_XmitDataTries3 0xf0000000 /* series 3 max attempts */ +#define AR_XmitDataTries3_S 28 + +/* TX ds_ctl3 */ +#define AR_XmitRate0 0x0000001f /* series 0 tx rate */ +#define AR_XmitRate0_S 0 +#define AR_XmitRate1 0x000003e0 /* series 1 tx rate */ +#define AR_XmitRate1_S 5 +#define AR_XmitRate2 0x00007c00 /* series 2 tx rate */ +#define AR_XmitRate2_S 10 +#define AR_XmitRate3 0x000f8000 /* series 3 tx rate */ +#define AR_XmitRate3_S 15 +#define AR_RTSCTSRate 0x01f00000 /* RTS or CTS rate */ +#define AR_RTSCTSRate_S 20 +/* bits 25-31 are reserved */ + +/* RX ds_ctl1 */ +/* AR_BufLen 0x00000fff data buffer length */ +/* bit 12 is reserved */ +#define AR_RxInterReq 0x00002000 /* RX interrupt request */ +/* bits 14-31 are reserved */ + +/* TX ds_txstatus0 */ +#define AR_FrmXmitOK 0x00000001 /* TX success */ +#define AR_ExcessiveRetries 0x00000002 /* excessive retries */ +#define AR_FIFOUnderrun 0x00000004 /* TX FIFO underrun */ +#define AR_Filtered 0x00000008 /* TX filter indication */ +#define AR_RTSFailCnt 0x000000f0 /* RTS failure count */ +#define AR_RTSFailCnt_S 4 +#define AR_DataFailCnt 0x00000f00 /* Data failure count */ +#define AR_DataFailCnt_S 8 +#define AR_VirtCollCnt 0x0000f000 /* virtual collision count */ +#define AR_VirtCollCnt_S 12 +#define AR_SendTimestamp 0xffff0000 /* TX timestamp */ +#define AR_SendTimestamp_S 16 + +/* RX ds_rxstatus0 */ +#define AR_DataLen 0x00000fff /* RX data length */ +/* AR_More 0x00001000 more desc in this frame */ +#define AR_DecompCRCErr 0x00002000 /* decompression CRC error */ +/* bit 14 is reserved */ +#define AR_RcvRate 0x000f8000 /* reception rate */ +#define AR_RcvRate_S 15 +#define AR_RcvSigStrength 0x0ff00000 /* receive signal strength */ +#define AR_RcvSigStrength_S 20 +#define AR_RcvAntenna 0xf0000000 /* receive antenaa */ +#define AR_RcvAntenna_S 28 + +/* TX ds_txstatus1 */ +#define AR_Done 0x00000001 /* descripter complete */ +#define AR_SeqNum 0x00001ffe /* TX sequence number */ +#define AR_SeqNum_S 1 +#define AR_AckSigStrength 0x001fe000 /* strength of ACK */ +#define AR_AckSigStrength_S 13 +#define AR_FinalTSIndex 0x00600000 /* final TX attempt series ix */ +#define AR_FinalTSIndex_S 21 +#define AR_CompSuccess 0x00800000 /* compression status */ +#define AR_XmitAtenna 0x01000000 /* transmit antenna */ +/* bits 25-31 are reserved */ + +/* RX ds_rxstatus1 */ +/* AR_Done 0x00000001 descripter complete */ +#define AR_FrmRcvOK 0x00000002 /* frame reception success */ +#define AR_CRCErr 0x00000004 /* CRC error */ +#define AR_DecryptCRCErr 0x00000008 /* Decryption CRC fiailure */ +#define AR_PHYErr 0x00000010 /* PHY error */ +#define AR_MichaelErr 0x00000020 /* Michae MIC decrypt error */ +/* bits 6-7 are reserved */ +#define AR_KeyIdxValid 0x00000100 /* decryption key index valid */ +#define AR_KeyIdx 0x0000fe00 /* Decryption key index */ +#define AR_KeyIdx_S 9 +#define AR_RcvTimestamp 0x7fff0000 /* timestamp */ +#define AR_RcvTimestamp_S 16 +#define AR_KeyCacheMiss 0x80000000 /* key cache miss indication */ + +/* NB: phy error code overlays key index and valid fields */ +#define AR_PHYErrCode 0x0000ff00 /* PHY error code */ +#define AR_PHYErrCode_S 8 + +#endif /* _ATH_AR5212_DESC_H_ */ --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5212/ar5212reg.h 2009-03-23 17:36:55.000000000 +0000 @@ -0,0 +1,995 @@ +/* + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2008 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ar5212reg.h,v 1.1 2009/03/23 17:14:48 sborrill Exp $ + */ +#ifndef _DEV_ATH_AR5212REG_H_ +#define _DEV_ATH_AR5212REG_H_ + +/* + * Definitions for the Atheros 5212 chipset. + */ + +/* DMA Control and Interrupt Registers */ +#define AR_CR 0x0008 /* MAC control register */ +#define AR_RXDP 0x000C /* MAC receive queue descriptor pointer */ +#define AR_CFG 0x0014 /* MAC configuration and status register */ +#define AR_IER 0x0024 /* MAC Interrupt enable register */ +/* 0x28 is RTSD0 on the 5211 */ +/* 0x2c is RTSD1 on the 5211 */ +#define AR_TXCFG 0x0030 /* MAC tx DMA size config register */ +#define AR_RXCFG 0x0034 /* MAC rx DMA size config register */ +/* 0x38 is the jumbo descriptor address on the 5211 */ +#define AR_MIBC 0x0040 /* MAC MIB control register */ +#define AR_TOPS 0x0044 /* MAC timeout prescale count */ +#define AR_RXNPTO 0x0048 /* MAC no frame received timeout */ +#define AR_TXNPTO 0x004C /* MAC no frame trasmitted timeout */ +#define AR_RPGTO 0x0050 /* MAC receive frame gap timeout */ +#define AR_RPCNT 0x0054 /* MAC receive frame count limit */ +#define AR_MACMISC 0x0058 /* MAC miscellaneous control/status register */ +#define AR_SPC_0 0x005c /* MAC sleep performance (awake cycles) */ +#define AR_SPC_1 0x0060 /* MAC sleep performance (asleep cycles) */ +/* 0x5c is for QCU/DCU clock gating control on 5311 */ +#define AR_ISR 0x0080 /* MAC Primary interrupt status register */ +#define AR_ISR_S0 0x0084 /* MAC Secondary interrupt status register 0 */ +#define AR_ISR_S1 0x0088 /* MAC Secondary interrupt status register 1 */ +#define AR_ISR_S2 0x008c /* MAC Secondary interrupt status register 2 */ +#define AR_ISR_S3 0x0090 /* MAC Secondary interrupt status register 3 */ +#define AR_ISR_S4 0x0094 /* MAC Secondary interrupt status register 4 */ +#define AR_IMR 0x00a0 /* MAC Primary interrupt mask register */ +#define AR_IMR_S0 0x00a4 /* MAC Secondary interrupt mask register 0 */ +#define AR_IMR_S1 0x00a8 /* MAC Secondary interrupt mask register 1 */ +#define AR_IMR_S2 0x00ac /* MAC Secondary interrupt mask register 2 */ +#define AR_IMR_S3 0x00b0 /* MAC Secondary interrupt mask register 3 */ +#define AR_IMR_S4 0x00b4 /* MAC Secondary interrupt mask register 4 */ +#define AR_ISR_RAC 0x00c0 /* ISR read-and-clear access */ +/* Shadow copies with read-and-clear access */ +#define AR_ISR_S0_S 0x00c4 /* ISR_S0 shadow copy */ +#define AR_ISR_S1_S 0x00c8 /* ISR_S1 shadow copy */ +#define AR_ISR_S2_S 0x00cc /* ISR_S2 shadow copy */ +#define AR_ISR_S3_S 0x00d0 /* ISR_S3 shadow copy */ +#define AR_ISR_S4_S 0x00d4 /* ISR_S4 shadow copy */ +#define AR_DMADBG_0 0x00e0 /* DMA debug 0 */ +#define AR_DMADBG_1 0x00e4 /* DMA debug 1 */ +#define AR_DMADBG_2 0x00e8 /* DMA debug 2 */ +#define AR_DMADBG_3 0x00ec /* DMA debug 3 */ +#define AR_DMADBG_4 0x00f0 /* DMA debug 4 */ +#define AR_DMADBG_5 0x00f4 /* DMA debug 5 */ +#define AR_DMADBG_6 0x00f8 /* DMA debug 6 */ +#define AR_DMADBG_7 0x00fc /* DMA debug 7 */ +#define AR_DCM_A 0x0400 /* Decompression mask address */ +#define AR_DCM_D 0x0404 /* Decompression mask data */ +#define AR_DCCFG 0x0420 /* Decompression configuration */ +#define AR_CCFG 0x0600 /* Compression configuration */ +#define AR_CCUCFG 0x0604 /* Compression catchup configuration */ +#define AR_CPC_0 0x0610 /* Compression performance counter 0 */ +#define AR_CPC_1 0x0614 /* Compression performance counter 1 */ +#define AR_CPC_2 0x0618 /* Compression performance counter 2 */ +#define AR_CPC_3 0x061c /* Compression performance counter 3 */ +#define AR_CPCOVF 0x0620 /* Compression performance overflow status */ + +#define AR_Q0_TXDP 0x0800 /* MAC Transmit Queue descriptor pointer */ +#define AR_Q1_TXDP 0x0804 /* MAC Transmit Queue descriptor pointer */ +#define AR_Q2_TXDP 0x0808 /* MAC Transmit Queue descriptor pointer */ +#define AR_Q3_TXDP 0x080c /* MAC Transmit Queue descriptor pointer */ +#define AR_Q4_TXDP 0x0810 /* MAC Transmit Queue descriptor pointer */ +#define AR_Q5_TXDP 0x0814 /* MAC Transmit Queue descriptor pointer */ +#define AR_Q6_TXDP 0x0818 /* MAC Transmit Queue descriptor pointer */ +#define AR_Q7_TXDP 0x081c /* MAC Transmit Queue descriptor pointer */ +#define AR_Q8_TXDP 0x0820 /* MAC Transmit Queue descriptor pointer */ +#define AR_Q9_TXDP 0x0824 /* MAC Transmit Queue descriptor pointer */ +#define AR_QTXDP(_i) (AR_Q0_TXDP + ((_i)<<2)) + +#define AR_Q_TXE 0x0840 /* MAC Transmit Queue enable */ +#define AR_Q_TXD 0x0880 /* MAC Transmit Queue disable */ + +#define AR_Q0_CBRCFG 0x08c0 /* MAC CBR configuration */ +#define AR_Q1_CBRCFG 0x08c4 /* MAC CBR configuration */ +#define AR_Q2_CBRCFG 0x08c8 /* MAC CBR configuration */ +#define AR_Q3_CBRCFG 0x08cc /* MAC CBR configuration */ +#define AR_Q4_CBRCFG 0x08d0 /* MAC CBR configuration */ +#define AR_Q5_CBRCFG 0x08d4 /* MAC CBR configuration */ +#define AR_Q6_CBRCFG 0x08d8 /* MAC CBR configuration */ +#define AR_Q7_CBRCFG 0x08dc /* MAC CBR configuration */ +#define AR_Q8_CBRCFG 0x08e0 /* MAC CBR configuration */ +#define AR_Q9_CBRCFG 0x08e4 /* MAC CBR configuration */ +#define AR_QCBRCFG(_i) (AR_Q0_CBRCFG + ((_i)<<2)) + +#define AR_Q0_RDYTIMECFG 0x0900 /* MAC ReadyTime configuration */ +#define AR_Q1_RDYTIMECFG 0x0904 /* MAC ReadyTime configuration */ +#define AR_Q2_RDYTIMECFG 0x0908 /* MAC ReadyTime configuration */ +#define AR_Q3_RDYTIMECFG 0x090c /* MAC ReadyTime configuration */ +#define AR_Q4_RDYTIMECFG 0x0910 /* MAC ReadyTime configuration */ +#define AR_Q5_RDYTIMECFG 0x0914 /* MAC ReadyTime configuration */ +#define AR_Q6_RDYTIMECFG 0x0918 /* MAC ReadyTime configuration */ +#define AR_Q7_RDYTIMECFG 0x091c /* MAC ReadyTime configuration */ +#define AR_Q8_RDYTIMECFG 0x0920 /* MAC ReadyTime configuration */ +#define AR_Q9_RDYTIMECFG 0x0924 /* MAC ReadyTime configuration */ +#define AR_QRDYTIMECFG(_i) (AR_Q0_RDYTIMECFG + ((_i)<<2)) + +#define AR_Q_ONESHOTARM_SC 0x0940 /* MAC OneShotArm set control */ +#define AR_Q_ONESHOTARM_CC 0x0980 /* MAC OneShotArm clear control */ + +#define AR_Q0_MISC 0x09c0 /* MAC Miscellaneous QCU settings */ +#define AR_Q1_MISC 0x09c4 /* MAC Miscellaneous QCU settings */ +#define AR_Q2_MISC 0x09c8 /* MAC Miscellaneous QCU settings */ +#define AR_Q3_MISC 0x09cc /* MAC Miscellaneous QCU settings */ +#define AR_Q4_MISC 0x09d0 /* MAC Miscellaneous QCU settings */ +#define AR_Q5_MISC 0x09d4 /* MAC Miscellaneous QCU settings */ +#define AR_Q6_MISC 0x09d8 /* MAC Miscellaneous QCU settings */ +#define AR_Q7_MISC 0x09dc /* MAC Miscellaneous QCU settings */ +#define AR_Q8_MISC 0x09e0 /* MAC Miscellaneous QCU settings */ +#define AR_Q9_MISC 0x09e4 /* MAC Miscellaneous QCU settings */ +#define AR_QMISC(_i) (AR_Q0_MISC + ((_i)<<2)) + +#define AR_Q0_STS 0x0a00 /* MAC Miscellaneous QCU status */ +#define AR_Q1_STS 0x0a04 /* MAC Miscellaneous QCU status */ +#define AR_Q2_STS 0x0a08 /* MAC Miscellaneous QCU status */ +#define AR_Q3_STS 0x0a0c /* MAC Miscellaneous QCU status */ +#define AR_Q4_STS 0x0a10 /* MAC Miscellaneous QCU status */ +#define AR_Q5_STS 0x0a14 /* MAC Miscellaneous QCU status */ +#define AR_Q6_STS 0x0a18 /* MAC Miscellaneous QCU status */ +#define AR_Q7_STS 0x0a1c /* MAC Miscellaneous QCU status */ +#define AR_Q8_STS 0x0a20 /* MAC Miscellaneous QCU status */ +#define AR_Q9_STS 0x0a24 /* MAC Miscellaneous QCU status */ +#define AR_QSTS(_i) (AR_Q0_STS + ((_i)<<2)) + +#define AR_Q_RDYTIMESHDN 0x0a40 /* MAC ReadyTimeShutdown status */ +#define AR_Q_CBBS 0xb00 /* Compression buffer base select */ +#define AR_Q_CBBA 0xb04 /* Compression buffer base access */ +#define AR_Q_CBC 0xb08 /* Compression buffer configuration */ + +#define AR_D0_QCUMASK 0x1000 /* MAC QCU Mask */ +#define AR_D1_QCUMASK 0x1004 /* MAC QCU Mask */ +#define AR_D2_QCUMASK 0x1008 /* MAC QCU Mask */ +#define AR_D3_QCUMASK 0x100c /* MAC QCU Mask */ +#define AR_D4_QCUMASK 0x1010 /* MAC QCU Mask */ +#define AR_D5_QCUMASK 0x1014 /* MAC QCU Mask */ +#define AR_D6_QCUMASK 0x1018 /* MAC QCU Mask */ +#define AR_D7_QCUMASK 0x101c /* MAC QCU Mask */ +#define AR_D8_QCUMASK 0x1020 /* MAC QCU Mask */ +#define AR_D9_QCUMASK 0x1024 /* MAC QCU Mask */ +#define AR_DQCUMASK(_i) (AR_D0_QCUMASK + ((_i)<<2)) + +#define AR_D0_LCL_IFS 0x1040 /* MAC DCU-specific IFS settings */ +#define AR_D1_LCL_IFS 0x1044 /* MAC DCU-specific IFS settings */ +#define AR_D2_LCL_IFS 0x1048 /* MAC DCU-specific IFS settings */ +#define AR_D3_LCL_IFS 0x104c /* MAC DCU-specific IFS settings */ +#define AR_D4_LCL_IFS 0x1050 /* MAC DCU-specific IFS settings */ +#define AR_D5_LCL_IFS 0x1054 /* MAC DCU-specific IFS settings */ +#define AR_D6_LCL_IFS 0x1058 /* MAC DCU-specific IFS settings */ +#define AR_D7_LCL_IFS 0x105c /* MAC DCU-specific IFS settings */ +#define AR_D8_LCL_IFS 0x1060 /* MAC DCU-specific IFS settings */ +#define AR_D9_LCL_IFS 0x1064 /* MAC DCU-specific IFS settings */ +#define AR_DLCL_IFS(_i) (AR_D0_LCL_IFS + ((_i)<<2)) + +#define AR_D0_RETRY_LIMIT 0x1080 /* MAC Retry limits */ +#define AR_D1_RETRY_LIMIT 0x1084 /* MAC Retry limits */ +#define AR_D2_RETRY_LIMIT 0x1088 /* MAC Retry limits */ +#define AR_D3_RETRY_LIMIT 0x108c /* MAC Retry limits */ +#define AR_D4_RETRY_LIMIT 0x1090 /* MAC Retry limits */ +#define AR_D5_RETRY_LIMIT 0x1094 /* MAC Retry limits */ +#define AR_D6_RETRY_LIMIT 0x1098 /* MAC Retry limits */ +#define AR_D7_RETRY_LIMIT 0x109c /* MAC Retry limits */ +#define AR_D8_RETRY_LIMIT 0x10a0 /* MAC Retry limits */ +#define AR_D9_RETRY_LIMIT 0x10a4 /* MAC Retry limits */ +#define AR_DRETRY_LIMIT(_i) (AR_D0_RETRY_LIMIT + ((_i)<<2)) + +#define AR_D0_CHNTIME 0x10c0 /* MAC ChannelTime settings */ +#define AR_D1_CHNTIME 0x10c4 /* MAC ChannelTime settings */ +#define AR_D2_CHNTIME 0x10c8 /* MAC ChannelTime settings */ +#define AR_D3_CHNTIME 0x10cc /* MAC ChannelTime settings */ +#define AR_D4_CHNTIME 0x10d0 /* MAC ChannelTime settings */ +#define AR_D5_CHNTIME 0x10d4 /* MAC ChannelTime settings */ +#define AR_D6_CHNTIME 0x10d8 /* MAC ChannelTime settings */ +#define AR_D7_CHNTIME 0x10dc /* MAC ChannelTime settings */ +#define AR_D8_CHNTIME 0x10e0 /* MAC ChannelTime settings */ +#define AR_D9_CHNTIME 0x10e4 /* MAC ChannelTime settings */ +#define AR_DCHNTIME(_i) (AR_D0_CHNTIME + ((_i)<<2)) + +#define AR_D0_MISC 0x1100 /* MAC Miscellaneous DCU-specific settings */ +#define AR_D1_MISC 0x1104 /* MAC Miscellaneous DCU-specific settings */ +#define AR_D2_MISC 0x1108 /* MAC Miscellaneous DCU-specific settings */ +#define AR_D3_MISC 0x110c /* MAC Miscellaneous DCU-specific settings */ +#define AR_D4_MISC 0x1110 /* MAC Miscellaneous DCU-specific settings */ +#define AR_D5_MISC 0x1114 /* MAC Miscellaneous DCU-specific settings */ +#define AR_D6_MISC 0x1118 /* MAC Miscellaneous DCU-specific settings */ +#define AR_D7_MISC 0x111c /* MAC Miscellaneous DCU-specific settings */ +#define AR_D8_MISC 0x1120 /* MAC Miscellaneous DCU-specific settings */ +#define AR_D9_MISC 0x1124 /* MAC Miscellaneous DCU-specific settings */ +#define AR_DMISC(_i) (AR_D0_MISC + ((_i)<<2)) + +#define AR_D_SEQNUM 0x1140 /* MAC Frame sequence number */ + +/* MAC DCU-global IFS settings */ +#define AR_D_GBL_IFS_SIFS 0x1030 /* DCU global SIFS settings */ +#define AR_D_GBL_IFS_SLOT 0x1070 /* DC global slot interval */ +#define AR_D_GBL_IFS_EIFS 0x10b0 /* DCU global EIFS setting */ +#define AR_D_GBL_IFS_MISC 0x10f0 /* DCU global misc. IFS settings */ +#define AR_D_FPCTL 0x1230 /* DCU frame prefetch settings */ +#define AR_D_TXPSE 0x1270 /* DCU transmit pause control/status */ +#define AR_D_TXBLK_CMD 0x1038 /* DCU transmit filter cmd (w/only) */ +#define AR_D_TXBLK_DATA(i) (AR_D_TXBLK_CMD+(i)) /* DCU transmit filter data */ +#define AR_D_TXBLK_CLR 0x143c /* DCU clear tx filter (w/only) */ +#define AR_D_TXBLK_SET 0x147c /* DCU set tx filter (w/only) */ + +#define AR_RC 0x4000 /* Warm reset control register */ +#define AR_SCR 0x4004 /* Sleep control register */ +#define AR_INTPEND 0x4008 /* Interrupt Pending register */ +#define AR_SFR 0x400C /* Sleep force register */ +#define AR_PCICFG 0x4010 /* PCI configuration register */ +#define AR_GPIOCR 0x4014 /* GPIO control register */ +#define AR_GPIODO 0x4018 /* GPIO data output access register */ +#define AR_GPIODI 0x401C /* GPIO data input access register */ +#define AR_SREV 0x4020 /* Silicon Revision register */ +#define AR_TXEPOST 0x4028 /* TXE write posting resgister */ +#define AR_QSM 0x402C /* QCU sleep mask */ + +#define AR_PCIE_PMC 0x4068 /* PCIe power mgt config and status register */ +#define AR_PCIE_SERDES 0x4080 /* PCIe Serdes register */ +#define AR_PCIE_SERDES2 0x4084 /* PCIe Serdes register */ + +#define AR_EEPROM_ADDR 0x6000 /* EEPROM address register (10 bit) */ +#define AR_EEPROM_DATA 0x6004 /* EEPROM data register (16 bit) */ +#define AR_EEPROM_CMD 0x6008 /* EEPROM command register */ +#define AR_EEPROM_STS 0x600c /* EEPROM status register */ +#define AR_EEPROM_CFG 0x6010 /* EEPROM configuration register */ + +#define AR_STA_ID0 0x8000 /* MAC station ID0 register - low 32 bits */ +#define AR_STA_ID1 0x8004 /* MAC station ID1 register - upper 16 bits */ +#define AR_BSS_ID0 0x8008 /* MAC BSSID low 32 bits */ +#define AR_BSS_ID1 0x800C /* MAC BSSID upper 16 bits / AID */ +#define AR_SLOT_TIME 0x8010 /* MAC Time-out after a collision */ +#define AR_TIME_OUT 0x8014 /* MAC ACK & CTS time-out */ +#define AR_RSSI_THR 0x8018 /* MAC RSSI warning & missed beacon threshold */ +#define AR_USEC 0x801c /* MAC transmit latency register */ +#define AR_BEACON 0x8020 /* MAC beacon control value/mode bits */ +#define AR_CFP_PERIOD 0x8024 /* MAC CFP Interval (TU/msec) */ +#define AR_TIMER0 0x8028 /* MAC Next beacon time (TU/msec) */ +#define AR_TIMER1 0x802c /* MAC DMA beacon alert time (1/8 TU) */ +#define AR_TIMER2 0x8030 /* MAC Software beacon alert (1/8 TU) */ +#define AR_TIMER3 0x8034 /* MAC ATIM window time */ +#define AR_CFP_DUR 0x8038 /* MAC maximum CFP duration in TU */ +#define AR_RX_FILTER 0x803C /* MAC receive filter register */ +#define AR_MCAST_FIL0 0x8040 /* MAC multicast filter lower 32 bits */ +#define AR_MCAST_FIL1 0x8044 /* MAC multicast filter upper 32 bits */ +#define AR_DIAG_SW 0x8048 /* MAC PCU control register */ +#define AR_TSF_L32 0x804c /* MAC local clock lower 32 bits */ +#define AR_TSF_U32 0x8050 /* MAC local clock upper 32 bits */ +#define AR_TST_ADDAC 0x8054 /* ADDAC test register */ +#define AR_DEF_ANTENNA 0x8058 /* default antenna register */ +#define AR_QOS_MASK 0x805c /* MAC AES mute mask: QoS field */ +#define AR_SEQ_MASK 0x8060 /* MAC AES mute mask: seqnum field */ +#define AR_OBSERV_2 0x8068 /* Observation bus 2 */ +#define AR_OBSERV_1 0x806c /* Observation bus 1 */ + +#define AR_LAST_TSTP 0x8080 /* MAC Time stamp of the last beacon received */ +#define AR_NAV 0x8084 /* MAC current NAV value */ +#define AR_RTS_OK 0x8088 /* MAC RTS exchange success counter */ +#define AR_RTS_FAIL 0x808c /* MAC RTS exchange failure counter */ +#define AR_ACK_FAIL 0x8090 /* MAC ACK failure counter */ +#define AR_FCS_FAIL 0x8094 /* FCS check failure counter */ +#define AR_BEACON_CNT 0x8098 /* Valid beacon counter */ + +#define AR_SLEEP1 0x80d4 /* Enhanced sleep control 1 */ +#define AR_SLEEP2 0x80d8 /* Enhanced sleep control 2 */ +#define AR_SLEEP3 0x80dc /* Enhanced sleep control 3 */ +#define AR_BSSMSKL 0x80e0 /* BSSID mask lower 32 bits */ +#define AR_BSSMSKU 0x80e4 /* BSSID mask upper 16 bits */ +#define AR_TPC 0x80e8 /* Transmit power control for self gen frames */ +#define AR_TFCNT 0x80ec /* Profile count, transmit frames */ +#define AR_RFCNT 0x80f0 /* Profile count, receive frames */ +#define AR_RCCNT 0x80f4 /* Profile count, receive clear */ +#define AR_CCCNT 0x80f8 /* Profile count, cycle counter */ + +#define AR_QUIET1 0x80fc /* Quiet time programming for TGh */ +#define AR_QUIET1_NEXT_QUIET_S 0 /* TSF of next quiet period (TU) */ +#define AR_QUIET1_NEXT_QUIET 0xffff +#define AR_QUIET1_QUIET_ENABLE 0x10000 /* Enable Quiet time operation */ +#define AR_QUIET1_QUIET_ACK_CTS_ENABLE 0x20000 /* Do we ack/cts during quiet period */ + +#define AR_QUIET2 0x8100 /* More Quiet time programming */ +#define AR_QUIET2_QUIET_PER_S 0 /* Periodicity of quiet period (TU) */ +#define AR_QUIET2_QUIET_PER 0xffff +#define AR_QUIET2_QUIET_DUR_S 16 /* Duration of quiet period (TU) */ +#define AR_QUIET2_QUIET_DUR 0xffff0000 + +#define AR_TSF_PARM 0x8104 /* TSF parameters */ +#define AR_NOACK 0x8108 /* No ack policy in QoS Control Field */ +#define AR_PHY_ERR 0x810c /* Phy error filter */ + +#define AR_QOS_CONTROL 0x8118 /* Control TKIP MIC for QoS */ +#define AR_QOS_SELECT 0x811c /* MIC QoS select */ +#define AR_MISC_MODE 0x8120 /* PCU Misc. mode control */ + +/* Hainan MIB counter registers */ +#define AR_FILTOFDM 0x8124 /* Count of filtered OFDM frames */ +#define AR_FILTCCK 0x8128 /* Count of filtered CCK frames */ +#define AR_PHYCNT1 0x812c /* Phy Error 1 counter */ +#define AR_PHYCNTMASK1 0x8130 /* Phy Error 1 counter mask */ +#define AR_PHYCNT2 0x8134 /* Phy Error 2 counter */ +#define AR_PHYCNTMASK2 0x8138 /* Phy Error 2 counter mask */ +#define AR_PHY_COUNTMAX (3 << 22) /* Max value in counter before intr */ +#define AR_MIBCNT_INTRMASK (3<<22) /* Mask for top two bits of counters */ + +#define AR_RATE_DURATION_0 0x8700 /* base of multi-rate retry */ +#define AR_RATE_DURATION(_n) (AR_RATE_DURATION_0 + ((_n)<<2)) + +#define AR_KEYTABLE_0 0x8800 /* MAC Key Cache */ +#define AR_KEYTABLE(_n) (AR_KEYTABLE_0 + ((_n)*32)) + +#define AR_CFP_MASK 0x0000ffff /* Mask for next beacon time */ + +#define AR_CR_RXE 0x00000004 /* Receive enable */ +#define AR_CR_RXD 0x00000020 /* Receive disable */ +#define AR_CR_SWI 0x00000040 /* One-shot software interrupt */ + +#define AR_CFG_SWTD 0x00000001 /* byteswap tx descriptor words */ +#define AR_CFG_SWTB 0x00000002 /* byteswap tx data buffer words */ +#define AR_CFG_SWRD 0x00000004 /* byteswap rx descriptor words */ +#define AR_CFG_SWRB 0x00000008 /* byteswap rx data buffer words */ +#define AR_CFG_SWRG 0x00000010 /* byteswap register access data words */ +#define AR_CFG_AP_ADHOC_INDICATION 0x00000020 /* AP/adhoc indication (0-AP, 1-Adhoc) */ +#define AR_CFG_PHOK 0x00000100 /* PHY OK status */ +#define AR_CFG_EEBS 0x00000200 /* EEPROM busy */ +#define AR_5211_CFG_CLK_GATE_DIS 0x00000400 /* Clock gating disable (Oahu only) */ +#define AR_CFG_PCI_MASTER_REQ_Q_THRESH 0x00060000 /* Mask of PCI core master request queue full threshold */ +#define AR_CFG_PCI_MASTER_REQ_Q_THRESH_S 17 /* Shift for PCI core master request queue full threshold */ + +#define AR_IER_ENABLE 0x00000001 /* Global interrupt enable */ +#define AR_IER_DISABLE 0x00000000 /* Global interrupt disable */ + +#define AR_DMASIZE_4B 0x00000000 /* DMA size 4 bytes (TXCFG + RXCFG) */ +#define AR_DMASIZE_8B 0x00000001 /* DMA size 8 bytes */ +#define AR_DMASIZE_16B 0x00000002 /* DMA size 16 bytes */ +#define AR_DMASIZE_32B 0x00000003 /* DMA size 32 bytes */ +#define AR_DMASIZE_64B 0x00000004 /* DMA size 64 bytes */ +#define AR_DMASIZE_128B 0x00000005 /* DMA size 128 bytes */ +#define AR_DMASIZE_256B 0x00000006 /* DMA size 256 bytes */ +#define AR_DMASIZE_512B 0x00000007 /* DMA size 512 bytes */ + +#define AR_FTRIG 0x000003F0 /* Mask for Frame trigger level */ +#define AR_FTRIG_S 4 /* Shift for Frame trigger level */ +#define AR_FTRIG_IMMED 0x00000000 /* bytes in PCU TX FIFO before air */ +#define AR_FTRIG_64B 0x00000010 /* default */ +#define AR_FTRIG_128B 0x00000020 +#define AR_FTRIG_192B 0x00000030 +#define AR_FTRIG_256B 0x00000040 /* 5 bits total */ + +#define AR_RXCFG_ZLFDMA 0x00000010 /* Enable DMA of zero-length frame */ + +#define AR_MIBC_COW 0x00000001 /* counter overflow warning */ +#define AR_MIBC_FMC 0x00000002 /* freeze MIB counters */ +#define AR_MIBC_CMC 0x00000004 /* clear MIB counters */ +#define AR_MIBC_MCS 0x00000008 /* MIB counter strobe, increment all */ + +#define AR_TOPS_MASK 0x0000FFFF /* Mask for timeout prescale */ + +#define AR_RXNPTO_MASK 0x000003FF /* Mask for no frame received timeout */ + +#define AR_TXNPTO_MASK 0x000003FF /* Mask for no frame transmitted timeout */ +#define AR_TXNPTO_QCU_MASK 0x000FFC00 /* Mask indicating the set of QCUs */ + /* for which frame completions will cause */ + /* a reset of the no frame xmit'd timeout */ + +#define AR_RPGTO_MASK 0x000003FF /* Mask for receive frame gap timeout */ + +#define AR_RPCNT_MASK 0x0000001F /* Mask for receive frame count limit */ + +#define AR_MACMISC_DMA_OBS 0x000001E0 /* Mask for DMA observation bus mux select */ +#define AR_MACMISC_DMA_OBS_S 5 /* Shift for DMA observation bus mux select */ +#define AR_MACMISC_MISC_OBS 0x00000E00 /* Mask for MISC observation bus mux select */ +#define AR_MACMISC_MISC_OBS_S 9 /* Shift for MISC observation bus mux select */ +#define AR_MACMISC_MAC_OBS_BUS_LSB 0x00007000 /* Mask for MAC observation bus mux select (lsb) */ +#define AR_MACMISC_MAC_OBS_BUS_LSB_S 12 /* Shift for MAC observation bus mux select (lsb) */ +#define AR_MACMISC_MAC_OBS_BUS_MSB 0x00038000 /* Mask for MAC observation bus mux select (msb) */ +#define AR_MACMISC_MAC_OBS_BUS_MSB_S 15 /* Shift for MAC observation bus mux select (msb) */ + +/* + * Interrupt Status Registers + * + * Only the bits in the ISR_P register and the IMR_P registers + * control whether the MAC's INTA# output is asserted. The bits in + * the secondary interrupt status/mask registers control what bits + * are set in the primary interrupt status register; however the + * IMR_S* registers DO NOT determine whether INTA# is asserted. + * That is INTA# is asserted only when the logical AND of ISR_P + * and IMR_P is non-zero. The secondary interrupt mask/status + * registers affect what bits are set in ISR_P but they do not + * directly affect whether INTA# is asserted. + */ +#define AR_ISR_RXOK 0x00000001 /* At least one frame received sans errors */ +#define AR_ISR_RXDESC 0x00000002 /* Receive interrupt request */ +#define AR_ISR_RXERR 0x00000004 /* Receive error interrupt */ +#define AR_ISR_RXNOPKT 0x00000008 /* No frame received within timeout clock */ +#define AR_ISR_RXEOL 0x00000010 /* Received descriptor empty interrupt */ +#define AR_ISR_RXORN 0x00000020 /* Receive FIFO overrun interrupt */ +#define AR_ISR_TXOK 0x00000040 /* Transmit okay interrupt */ +#define AR_ISR_TXDESC 0x00000080 /* Transmit interrupt request */ +#define AR_ISR_TXERR 0x00000100 /* Transmit error interrupt */ +#define AR_ISR_TXNOPKT 0x00000200 /* No frame transmitted interrupt */ +#define AR_ISR_TXEOL 0x00000400 /* Transmit descriptor empty interrupt */ +#define AR_ISR_TXURN 0x00000800 /* Transmit FIFO underrun interrupt */ +#define AR_ISR_MIB 0x00001000 /* MIB interrupt - see MIBC */ +#define AR_ISR_SWI 0x00002000 /* Software interrupt */ +#define AR_ISR_RXPHY 0x00004000 /* PHY receive error interrupt */ +#define AR_ISR_RXKCM 0x00008000 /* Key-cache miss interrupt */ +#define AR_ISR_SWBA 0x00010000 /* Software beacon alert interrupt */ +#define AR_ISR_BRSSI 0x00020000 /* Beacon threshold interrupt */ +#define AR_ISR_BMISS 0x00040000 /* Beacon missed interrupt */ +#define AR_ISR_HIUERR 0x00080000 /* An unexpected bus error has occurred */ +#define AR_ISR_BNR 0x00100000 /* Beacon not ready interrupt */ +#define AR_ISR_RXCHIRP 0x00200000 /* Phy received a 'chirp' */ +#define AR_ISR_RXDOPPL 0x00400000 /* Phy received a 'doppler chirp' */ +#define AR_ISR_BCNMISC 0x00800000 /* 'or' of TIM, CABEND, DTIMSYNC, BCNTO, + CABTO, DTIM bits from ISR_S2 */ +#define AR_ISR_TIM 0x00800000 /* TIM interrupt */ +#define AR_ISR_GPIO 0x01000000 /* GPIO Interrupt */ +#define AR_ISR_QCBROVF 0x02000000 /* QCU CBR overflow interrupt */ +#define AR_ISR_QCBRURN 0x04000000 /* QCU CBR underrun interrupt */ +#define AR_ISR_QTRIG 0x08000000 /* QCU scheduling trigger interrupt */ +#define AR_ISR_RESV0 0xF0000000 /* Reserved */ + +#define AR_ISR_S0_QCU_TXOK 0x000003FF /* Mask for TXOK (QCU 0-9) */ +#define AR_ISR_S0_QCU_TXOK_S 0 +#define AR_ISR_S0_QCU_TXDESC 0x03FF0000 /* Mask for TXDESC (QCU 0-9) */ +#define AR_ISR_S0_QCU_TXDESC_S 16 + +#define AR_ISR_S1_QCU_TXERR 0x000003FF /* Mask for TXERR (QCU 0-9) */ +#define AR_ISR_S1_QCU_TXERR_S 0 +#define AR_ISR_S1_QCU_TXEOL 0x03FF0000 /* Mask for TXEOL (QCU 0-9) */ +#define AR_ISR_S1_QCU_TXEOL_S 16 + +#define AR_ISR_S2_QCU_TXURN 0x000003FF /* Mask for TXURN (QCU 0-9) */ +#define AR_ISR_S2_MCABT 0x00010000 /* Master cycle abort interrupt */ +#define AR_ISR_S2_SSERR 0x00020000 /* SERR interrupt */ +#define AR_ISR_S2_DPERR 0x00040000 /* PCI bus parity error */ +#define AR_ISR_S2_TIM 0x01000000 /* TIM */ +#define AR_ISR_S2_CABEND 0x02000000 /* CABEND */ +#define AR_ISR_S2_DTIMSYNC 0x04000000 /* DTIMSYNC */ +#define AR_ISR_S2_BCNTO 0x08000000 /* BCNTO */ +#define AR_ISR_S2_CABTO 0x10000000 /* CABTO */ +#define AR_ISR_S2_DTIM 0x20000000 /* DTIM */ +#define AR_ISR_S2_RESV0 0xE0F8FC00 /* Reserved */ + +#define AR_ISR_S3_QCU_QCBROVF 0x000003FF /* Mask for QCBROVF (QCU 0-9) */ +#define AR_ISR_S3_QCU_QCBRURN 0x03FF0000 /* Mask for QCBRURN (QCU 0-9) */ + +#define AR_ISR_S4_QCU_QTRIG 0x000003FF /* Mask for QTRIG (QCU 0-9) */ +#define AR_ISR_S4_RESV0 0xFFFFFC00 /* Reserved */ + +/* + * Interrupt Mask Registers + * + * Only the bits in the IMR control whether the MAC's INTA# + * output will be asserted. The bits in the secondary interrupt + * mask registers control what bits get set in the primary + * interrupt status register; however the IMR_S* registers + * DO NOT determine whether INTA# is asserted. + */ +#define AR_IMR_RXOK 0x00000001 /* At least one frame received sans errors */ +#define AR_IMR_RXDESC 0x00000002 /* Receive interrupt request */ +#define AR_IMR_RXERR 0x00000004 /* Receive error interrupt */ +#define AR_IMR_RXNOPKT 0x00000008 /* No frame received within timeout clock */ +#define AR_IMR_RXEOL 0x00000010 /* Received descriptor empty interrupt */ +#define AR_IMR_RXORN 0x00000020 /* Receive FIFO overrun interrupt */ +#define AR_IMR_TXOK 0x00000040 /* Transmit okay interrupt */ +#define AR_IMR_TXDESC 0x00000080 /* Transmit interrupt request */ +#define AR_IMR_TXERR 0x00000100 /* Transmit error interrupt */ +#define AR_IMR_TXNOPKT 0x00000200 /* No frame transmitted interrupt */ +#define AR_IMR_TXEOL 0x00000400 /* Transmit descriptor empty interrupt */ +#define AR_IMR_TXURN 0x00000800 /* Transmit FIFO underrun interrupt */ +#define AR_IMR_MIB 0x00001000 /* MIB interrupt - see MIBC */ +#define AR_IMR_SWI 0x00002000 /* Software interrupt */ +#define AR_IMR_RXPHY 0x00004000 /* PHY receive error interrupt */ +#define AR_IMR_RXKCM 0x00008000 /* Key-cache miss interrupt */ +#define AR_IMR_SWBA 0x00010000 /* Software beacon alert interrupt */ +#define AR_IMR_BRSSI 0x00020000 /* Beacon threshold interrupt */ +#define AR_IMR_BMISS 0x00040000 /* Beacon missed interrupt */ +#define AR_IMR_HIUERR 0x00080000 /* An unexpected bus error has occurred */ +#define AR_IMR_BNR 0x00100000 /* BNR interrupt */ +#define AR_IMR_RXCHIRP 0x00200000 /* RXCHIRP interrupt */ +#define AR_IMR_BCNMISC 0x00800000 /* Venice: BCNMISC */ +#define AR_IMR_TIM 0x00800000 /* TIM interrupt */ +#define AR_IMR_GPIO 0x01000000 /* GPIO Interrupt */ +#define AR_IMR_QCBROVF 0x02000000 /* QCU CBR overflow interrupt */ +#define AR_IMR_QCBRURN 0x04000000 /* QCU CBR underrun interrupt */ +#define AR_IMR_QTRIG 0x08000000 /* QCU scheduling trigger interrupt */ +#define AR_IMR_RESV0 0xF0000000 /* Reserved */ + +#define AR_IMR_S0_QCU_TXOK 0x000003FF /* TXOK (QCU 0-9) */ +#define AR_IMR_S0_QCU_TXOK_S 0 +#define AR_IMR_S0_QCU_TXDESC 0x03FF0000 /* TXDESC (QCU 0-9) */ +#define AR_IMR_S0_QCU_TXDESC_S 16 + +#define AR_IMR_S1_QCU_TXERR 0x000003FF /* TXERR (QCU 0-9) */ +#define AR_IMR_S1_QCU_TXERR_S 0 +#define AR_IMR_S1_QCU_TXEOL 0x03FF0000 /* TXEOL (QCU 0-9) */ +#define AR_IMR_S1_QCU_TXEOL_S 16 + +#define AR_IMR_S2_QCU_TXURN 0x000003FF /* Mask for TXURN (QCU 0-9) */ +#define AR_IMR_S2_QCU_TXURN_S 0 +#define AR_IMR_S2_MCABT 0x00010000 /* Master cycle abort interrupt */ +#define AR_IMR_S2_SSERR 0x00020000 /* SERR interrupt */ +#define AR_IMR_S2_DPERR 0x00040000 /* PCI bus parity error */ +#define AR_IMR_S2_TIM 0x01000000 /* TIM */ +#define AR_IMR_S2_CABEND 0x02000000 /* CABEND */ +#define AR_IMR_S2_DTIMSYNC 0x04000000 /* DTIMSYNC */ +#define AR_IMR_S2_BCNTO 0x08000000 /* BCNTO */ +#define AR_IMR_S2_CABTO 0x10000000 /* CABTO */ +#define AR_IMR_S2_DTIM 0x20000000 /* DTIM */ +#define AR_IMR_S2_TSFOOR 0x80000000 /* TSF OOR */ +#define AR_IMR_S2_RESV0 0xE0F8FC00 /* Reserved */ + +#define AR_IMR_S3_QCU_QCBROVF 0x000003FF /* Mask for QCBROVF (QCU 0-9) */ +#define AR_IMR_S3_QCU_QCBRURN 0x03FF0000 /* Mask for QCBRURN (QCU 0-9) */ +#define AR_IMR_S3_QCU_QCBRURN_S 16 /* Shift for QCBRURN (QCU 0-9) */ + +#define AR_IMR_S4_QCU_QTRIG 0x000003FF /* Mask for QTRIG (QCU 0-9) */ +#define AR_IMR_S4_RESV0 0xFFFFFC00 /* Reserved */ + +/* QCU registers */ +#define AR_NUM_QCU 10 /* Only use QCU 0-9 for forward QCU compatibility */ +#define AR_QCU_0 0x0001 +#define AR_QCU_1 0x0002 +#define AR_QCU_2 0x0004 +#define AR_QCU_3 0x0008 +#define AR_QCU_4 0x0010 +#define AR_QCU_5 0x0020 +#define AR_QCU_6 0x0040 +#define AR_QCU_7 0x0080 +#define AR_QCU_8 0x0100 +#define AR_QCU_9 0x0200 + +#define AR_Q_CBRCFG_CBR_INTERVAL 0x00FFFFFF /* Mask for CBR interval (us) */ +#define AR_Q_CBRCFG_CBR_INTERVAL_S 0 /* Shift for CBR interval */ +#define AR_Q_CBRCFG_CBR_OVF_THRESH 0xFF000000 /* Mask for CBR overflow threshold */ +#define AR_Q_CBRCFG_CBR_OVF_THRESH_S 24 /* Shift for CBR overflow thresh */ + +#define AR_Q_RDYTIMECFG_INT 0x00FFFFFF /* CBR interval (us) */ +#define AR_Q_RDYTIMECFG_INT_S 0 // Shift for ReadyTime Interval (us) */ +#define AR_Q_RDYTIMECFG_ENA 0x01000000 /* CBR enable */ +/* bits 25-31 are reserved */ + +#define AR_Q_MISC_FSP 0x0000000F /* Frame Scheduling Policy mask */ +#define AR_Q_MISC_FSP_ASAP 0 /* ASAP */ +#define AR_Q_MISC_FSP_CBR 1 /* CBR */ +#define AR_Q_MISC_FSP_DBA_GATED 2 /* DMA Beacon Alert gated */ +#define AR_Q_MISC_FSP_TIM_GATED 3 /* TIM gated */ +#define AR_Q_MISC_FSP_BEACON_SENT_GATED 4 /* Beacon-sent-gated */ +#define AR_Q_MISC_FSP_S 0 +#define AR_Q_MISC_ONE_SHOT_EN 0x00000010 /* OneShot enable */ +#define AR_Q_MISC_CBR_INCR_DIS1 0x00000020 /* Disable CBR expired counter incr + (empty q) */ +#define AR_Q_MISC_CBR_INCR_DIS0 0x00000040 /* Disable CBR expired counter incr + (empty beacon q) */ +#define AR_Q_MISC_BEACON_USE 0x00000080 /* Beacon use indication */ +#define AR_Q_MISC_CBR_EXP_CNTR_LIMIT 0x00000100 /* CBR expired counter limit enable */ +#define AR_Q_MISC_RDYTIME_EXP_POLICY 0x00000200 /* Enable TXE cleared on ReadyTime expired or VEOL */ +#define AR_Q_MISC_RESET_CBR_EXP_CTR 0x00000400 /* Reset CBR expired counter */ +#define AR_Q_MISC_DCU_EARLY_TERM_REQ 0x00000800 /* DCU frame early termination request control */ +#define AR_Q_MISC_QCU_COMP_EN 0x00001000 /* QCU frame compression enable */ +#define AR_Q_MISC_RESV0 0xFFFFF000 /* Reserved */ + +#define AR_Q_STS_PEND_FR_CNT 0x00000003 /* Mask for Pending Frame Count */ +#define AR_Q_STS_RESV0 0x000000FC /* Reserved */ +#define AR_Q_STS_CBR_EXP_CNT 0x0000FF00 /* Mask for CBR expired counter */ +#define AR_Q_STS_RESV1 0xFFFF0000 /* Reserved */ + +/* DCU registers */ +#define AR_NUM_DCU 10 /* Only use 10 DCU's for forward QCU/DCU compatibility */ +#define AR_DCU_0 0x0001 +#define AR_DCU_1 0x0002 +#define AR_DCU_2 0x0004 +#define AR_DCU_3 0x0008 +#define AR_DCU_4 0x0010 +#define AR_DCU_5 0x0020 +#define AR_DCU_6 0x0040 +#define AR_DCU_7 0x0080 +#define AR_DCU_8 0x0100 +#define AR_DCU_9 0x0200 + +#define AR_D_QCUMASK 0x000003FF /* Mask for QCU Mask (QCU 0-9) */ +#define AR_D_QCUMASK_RESV0 0xFFFFFC00 /* Reserved */ + +#define AR_D_LCL_IFS_CWMIN 0x000003FF /* Mask for CW_MIN */ +#define AR_D_LCL_IFS_CWMIN_S 0 +#define AR_D_LCL_IFS_CWMAX 0x000FFC00 /* Mask for CW_MAX */ +#define AR_D_LCL_IFS_CWMAX_S 10 +#define AR_D_LCL_IFS_AIFS 0x0FF00000 /* Mask for AIFS */ +#define AR_D_LCL_IFS_AIFS_S 20 +/* + * Note: even though this field is 8 bits wide the + * maximum supported AIFS value is 0xfc. Setting the AIFS value + * to 0xfd 0xfe, or 0xff will not work correctly and will cause + * the DCU to hang. + */ +#define AR_D_LCL_IFS_RESV0 0xF0000000 /* Reserved */ + +#define AR_D_RETRY_LIMIT_FR_SH 0x0000000F /* frame short retry limit */ +#define AR_D_RETRY_LIMIT_FR_SH_S 0 +#define AR_D_RETRY_LIMIT_FR_LG 0x000000F0 /* frame long retry limit */ +#define AR_D_RETRY_LIMIT_FR_LG_S 4 +#define AR_D_RETRY_LIMIT_STA_SH 0x00003F00 /* station short retry limit */ +#define AR_D_RETRY_LIMIT_STA_SH_S 8 +#define AR_D_RETRY_LIMIT_STA_LG 0x000FC000 /* station short retry limit */ +#define AR_D_RETRY_LIMIT_STA_LG_S 14 +#define AR_D_RETRY_LIMIT_RESV0 0xFFF00000 /* Reserved */ + +#define AR_D_CHNTIME_DUR 0x000FFFFF /* ChannelTime duration (us) */ +#define AR_D_CHNTIME_DUR_S 0 /* Shift for ChannelTime duration */ +#define AR_D_CHNTIME_EN 0x00100000 /* ChannelTime enable */ +#define AR_D_CHNTIME_RESV0 0xFFE00000 /* Reserved */ + +#define AR_D_MISC_BKOFF_THRESH 0x0000003F /* Backoff threshold */ +#define AR_D_MISC_ETS_RTS 0x00000040 /* End of transmission series + station RTS/data failure + count reset policy */ +#define AR_D_MISC_ETS_CW 0x00000080 /* End of transmission series + CW reset policy */ +#define AR_D_MISC_FRAG_WAIT_EN 0x00000100 /* Wait for next fragment */ +#define AR_D_MISC_FRAG_BKOFF_EN 0x00000200 /* Backoff during a frag burst */ +#define AR_D_MISC_HCF_POLL_EN 0x00000800 /* HFC poll enable */ +#define AR_D_MISC_BKOFF_PERSISTENCE 0x00001000 /* Backoff persistence factor + setting */ +#define AR_D_MISC_FR_PREFETCH_EN 0x00002000 /* Frame prefetch enable */ +#define AR_D_MISC_VIR_COL_HANDLING 0x0000C000 /* Mask for Virtual collision + handling policy */ +#define AR_D_MISC_VIR_COL_HANDLING_S 14 +/* FOO redefined for venice CW increment policy */ +#define AR_D_MISC_VIR_COL_HANDLING_DEFAULT 0 /* Normal */ +#define AR_D_MISC_VIR_COL_HANDLING_IGNORE 1 /* Ignore */ +#define AR_D_MISC_BEACON_USE 0x00010000 /* Beacon use indication */ +#define AR_D_MISC_ARB_LOCKOUT_CNTRL 0x00060000 /* DCU arbiter lockout ctl */ +#define AR_D_MISC_ARB_LOCKOUT_CNTRL_S 17 /* DCU arbiter lockout ctl */ +#define AR_D_MISC_ARB_LOCKOUT_CNTRL_NONE 0 /* No lockout */ +#define AR_D_MISC_ARB_LOCKOUT_CNTRL_INTRA_FR 1 /* Intra-frame */ +#define AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL 2 /* Global */ +#define AR_D_MISC_ARB_LOCKOUT_IGNORE 0x00080000 /* DCU arbiter lockout ignore control */ +#define AR_D_MISC_SEQ_NUM_INCR_DIS 0x00100000 /* Sequence number increment disable */ +#define AR_D_MISC_POST_FR_BKOFF_DIS 0x00200000 /* Post-frame backoff disable */ +#define AR_D_MISC_VIRT_COLL_POLICY 0x00400000 /* Virtual coll. handling policy */ +#define AR_D_MISC_BLOWN_IFS_POLICY 0x00800000 /* Blown IFS handling policy */ +#define AR_D_MISC_RESV0 0xFE000000 /* Reserved */ + +#define AR_D_SEQNUM_RESV0 0xFFFFF000 /* Reserved */ + +#define AR_D_GBL_IFS_MISC_LFSR_SLICE_SEL 0x00000007 /* LFSR slice select */ +#define AR_D_GBL_IFS_MISC_TURBO_MODE 0x00000008 /* Turbo mode indication */ +#define AR_D_GBL_IFS_MISC_SIFS_DURATION_USEC 0x000003F0 /* SIFS duration (us) */ +#define AR_D_GBL_IFS_MISC_USEC_DURATION 0x000FFC00 /* microsecond duration */ +#define AR_D_GBL_IFS_MISC_USEC_DURATION_S 10 +#define AR_D_GBL_IFS_MISC_DCU_ARBITER_DLY 0x00300000 /* DCU arbiter delay */ +#define AR_D_GBL_IFS_MISC_RESV0 0xFFC00000 /* Reserved */ + +/* DMA & PCI Registers in PCI space (usable during sleep) */ +#define AR_RC_MAC 0x00000001 /* MAC reset */ +#define AR_RC_BB 0x00000002 /* Baseband reset */ +#define AR_RC_RESV0 0x00000004 /* Reserved */ +#define AR_RC_RESV1 0x00000008 /* Reserved */ +#define AR_RC_PCI 0x00000010 /* PCI-core reset */ + +#define AR_SCR_SLDUR 0x0000ffff /* sleep duration, units of 128us */ +#define AR_SCR_SLDUR_S 0 +#define AR_SCR_SLE 0x00030000 /* sleep enable */ +#define AR_SCR_SLE_S 16 +#define AR_SCR_SLE_WAKE 0 /* force wake */ +#define AR_SCR_SLE_SLP 1 /* force sleep */ +#define AR_SCR_SLE_NORM 2 /* sleep logic normal operation */ +#define AR_SCR_SLDTP 0x00040000 /* sleep duration timing policy */ +#define AR_SCR_SLDWP 0x00080000 /* sleep duration write policy */ +#define AR_SCR_SLEPOL 0x00100000 /* sleep policy mode */ +#define AR_SCR_MIBIE 0x00200000 /* sleep perf cntrs MIB intr ena */ + +#define AR_INTPEND_TRUE 0x00000001 /* interrupt pending */ + +#define AR_SFR_SLEEP 0x00000001 /* force sleep */ + +#define AR_PCICFG_SCLK_SEL 0x00000002 /* sleep clock select */ +#define AR_PCICFG_SCLK_SEL_S 1 +#define AR_PCICFG_CLKRUNEN 0x00000004 /* enable PCI CLKRUN function */ +#define AR_PCICFG_EEPROM_SIZE 0x00000018 /* Mask for EEPROM size */ +#define AR_PCICFG_EEPROM_SIZE_4 0 /* EEPROM size 4 Kbit */ +#define AR_PCICFG_EEPROM_SIZE_8K 1 /* EEPROM size 8 Kbit */ +#define AR_PCICFG_EEPROM_SIZE_16K 2 /* EEPROM size 16 Kbit */ +#define AR_PCICFG_EEPROM_SIZE_FAILED 3 /* Failure */ +#define AR_PCICFG_EEPROM_SIZE_S 3 +#define AR_PCICFG_LEDCTL 0x00000060 /* LED control Status */ +#define AR_PCICFG_LEDCTL_NONE 0 /* STA is not associated or trying */ +#define AR_PCICFG_LEDCTL_PEND 1 /* STA is trying to associate */ +#define AR_PCICFG_LEDCTL_ASSOC 2 /* STA is associated */ +#define AR_PCICFG_LEDCTL_S 5 +#define AR_PCICFG_PCI_BUS_SEL 0x00000380 /* PCI observation bus mux select */ +#define AR_PCICFG_DIS_CBE_FIX 0x00000400 /* Disable fix for bad PCI CBE# generation */ +#define AR_PCICFG_SL_INTEN 0x00000800 /* enable interrupt line assertion when asleep */ +#define AR_PCICFG_RETRYFIXEN 0x00001000 /* Enable PCI core retry fix */ +#define AR_PCICFG_SL_INPEN 0x00002000 /* Force asleep when an interrupt is pending */ +#define AR_PCICFG_RESV1 0x0000C000 /* Reserved */ +#define AR_PCICFG_SPWR_DN 0x00010000 /* mask for sleep/awake indication */ +#define AR_PCICFG_LEDMODE 0x000E0000 /* LED mode */ +#define AR_PCICFG_LEDMODE_PROP 0 /* Blink prop to filtered tx/rx */ +#define AR_PCICFG_LEDMODE_RPROP 1 /* Blink prop to unfiltered tx/rx */ +#define AR_PCICFG_LEDMODE_SPLIT 2 /* Blink power for tx/net for rx */ +#define AR_PCICFG_LEDMODE_RAND 3 /* Blink randomly */ +/* NB: s/w led control present in Hainan 1.1 and above */ +#define AR_PCICFG_LEDMODE_OFF 4 /* s/w control + both led's off */ +#define AR_PCICFG_LEDMODE_POWON 5 /* s/w control + power led on */ +#define AR_PCICFG_LEDMODE_NETON 6 /* s/w control + network led on */ +#define AR_PCICFG_LEDMODE_S 17 +#define AR_PCICFG_LEDBLINK 0x00700000 /* LED blink threshold select */ +#define AR_PCICFG_LEDBLINK_S 20 +#define AR_PCICFG_LEDSLOW 0x00800000 /* LED slowest blink rate mode */ +#define AR_PCICFG_LEDSLOW_S 23 +#define AR_PCICFG_SCLK_RATE_IND 0x03000000 /* Sleep clock rate */ +#define AR_PCICFG_SCLK_RATE_IND_S 24 +#define AR_PCICFG_RESV2 0xFC000000 /* Reserved */ + +#define AR_GPIOCR_CR_SHIFT 2 /* Each CR is 2 bits */ +#define AR_GPIOCR_CR_N(_g) (0 << (AR_GPIOCR_CR_SHIFT * (_g))) +#define AR_GPIOCR_CR_0(_g) (1 << (AR_GPIOCR_CR_SHIFT * (_g))) +#define AR_GPIOCR_CR_1(_g) (2 << (AR_GPIOCR_CR_SHIFT * (_g))) +#define AR_GPIOCR_CR_A(_g) (3 << (AR_GPIOCR_CR_SHIFT * (_g))) +#define AR_GPIOCR_INT_SHIFT 12 /* Interrupt select field shifter */ +#define AR_GPIOCR_INT(_g) ((_g) << AR_GPIOCR_INT_SHIFT) +#define AR_GPIOCR_INT_MASK 0x00007000 /* Interrupt select field mask */ +#define AR_GPIOCR_INT_ENA 0x00008000 /* Enable GPIO Interrupt */ +#define AR_GPIOCR_INT_SELL 0x00000000 /* Generate int if pin is low */ +#define AR_GPIOCR_INT_SELH 0x00010000 /* Generate int if pin is high */ +#define AR_GPIOCR_INT_SEL AR_GPIOCR_INT_SELH + +#define AR_SREV_ID 0x000000FF /* Mask to read SREV info */ +#define AR_SREV_ID_S 4 /* Mask to shift Major Rev Info */ +#define AR_SREV_REVISION 0x0000000F /* Mask for Chip revision level */ +#define AR_SREV_REVISION_MIN 0 /* lowest revision level */ +#define AR_SREV_REVISION_MAX 0xF /* highest revision level */ +#define AR_SREV_FPGA 1 +#define AR_SREV_D2PLUS 2 +#define AR_SREV_D2PLUS_MS 3 /* metal spin */ +#define AR_SREV_CRETE 4 +#define AR_SREV_CRETE_MS 5 /* FCS metal spin */ +#define AR_SREV_CRETE_MS23 7 /* 2.3 metal spin (6 skipped) */ +#define AR_SREV_CRETE_23 8 /* 2.3 full tape out */ +#define AR_SREV_GRIFFIN_LITE 8 +#define AR_SREV_HAINAN 9 +#define AR_SREV_CONDOR 11 +#define AR_SREV_VERSION 0x000000F0 /* Mask for Chip version */ +#define AR_SREV_VERSION_CRETE 0 +#define AR_SREV_VERSION_MAUI_1 1 +#define AR_SREV_VERSION_MAUI_2 2 +#define AR_SREV_VERSION_SPIRIT 3 +#define AR_SREV_VERSION_OAHU 4 +#define AR_SREV_VERSION_VENICE 5 +#define AR_SREV_VERSION_GRIFFIN 7 +#define AR_SREV_VERSION_CONDOR 9 +#define AR_SREV_VERSION_EAGLE 10 +#define AR_SREV_VERSION_COBRA 11 +#define AR_SREV_2413 AR_SREV_VERSION_GRIFFIN +#define AR_SREV_5413 AR_SREV_VERSION_EAGLE +#define AR_SREV_2415 AR_SREV_VERSION_COBRA +#define AR_SREV_5424 AR_SREV_VERSION_CONDOR +#define AR_SREV_2425 14 /* SWAN */ +#define AR_SREV_2417 15 /* Nala */ +#define AR_SREV_OAHU_ES 0 /* Engineering Sample */ +#define AR_SREV_OAHU_PROD 2 /* Production */ + +#define AR_PHYREV_HAINAN 0x43 +#define AR_ANALOG5REV_HAINAN 0x46 + +#define AR_RADIO_SREV_MAJOR 0xF0 +#define AR_RADIO_SREV_MINOR 0x0F +#define AR_RAD5111_SREV_MAJOR 0x10 /* All current supported ar5211 5 GHz + radios are rev 0x10 */ +#define AR_RAD5111_SREV_PROD 0x15 /* Current production level radios */ +#define AR_RAD2111_SREV_MAJOR 0x20 /* All current supported ar5211 2 GHz + radios are rev 0x10 */ +#define AR_RAD5112_SREV_MAJOR 0x30 /* 5112 Major Rev */ +#define AR_RAD5112_SREV_2_0 0x35 /* AR5112 Revision 2.0 */ +#define AR_RAD5112_SREV_2_1 0x36 /* AR5112 Revision 2.1 */ +#define AR_RAD2112_SREV_MAJOR 0x40 /* 2112 Major Rev */ +#define AR_RAD2112_SREV_2_0 0x45 /* AR2112 Revision 2.0 */ +#define AR_RAD2112_SREV_2_1 0x46 /* AR2112 Revision 2.1 */ +#define AR_RAD2413_SREV_MAJOR 0x50 /* 2413 Major Rev */ +#define AR_RAD5413_SREV_MAJOR 0x60 /* 5413 Major Rev */ +#define AR_RAD2316_SREV_MAJOR 0x70 /* 2316 Major Rev */ +#define AR_RAD2317_SREV_MAJOR 0x80 /* 2317 Major Rev */ +#define AR_RAD5424_SREV_MAJOR 0xa0 /* Mostly same as 5413 Major Rev */ + +#define AR_PCIE_PMC_ENA_L1 0x01 /* enable PCIe core enter L1 when + d2_sleep_en is asserted */ +#define AR_PCIE_PMC_ENA_RESET 0x08 /* enable reset on link going down */ + +/* EEPROM Registers in the MAC */ +#define AR_EEPROM_CMD_READ 0x00000001 +#define AR_EEPROM_CMD_WRITE 0x00000002 +#define AR_EEPROM_CMD_RESET 0x00000004 + +#define AR_EEPROM_STS_READ_ERROR 0x00000001 +#define AR_EEPROM_STS_READ_COMPLETE 0x00000002 +#define AR_EEPROM_STS_WRITE_ERROR 0x00000004 +#define AR_EEPROM_STS_WRITE_COMPLETE 0x00000008 + +#define AR_EEPROM_CFG_SIZE 0x00000003 /* size determination override */ +#define AR_EEPROM_CFG_SIZE_AUTO 0 +#define AR_EEPROM_CFG_SIZE_4KBIT 1 +#define AR_EEPROM_CFG_SIZE_8KBIT 2 +#define AR_EEPROM_CFG_SIZE_16KBIT 3 +#define AR_EEPROM_CFG_DIS_WWRCL 0x00000004 /* Disable wait for write completion */ +#define AR_EEPROM_CFG_CLOCK 0x00000018 /* clock rate control */ +#define AR_EEPROM_CFG_CLOCK_S 3 /* clock rate control */ +#define AR_EEPROM_CFG_CLOCK_156KHZ 0 +#define AR_EEPROM_CFG_CLOCK_312KHZ 1 +#define AR_EEPROM_CFG_CLOCK_625KHZ 2 +#define AR_EEPROM_CFG_RESV0 0x000000E0 /* Reserved */ +#define AR_EEPROM_CFG_PKEY 0x00FFFF00 /* protection key */ +#define AR_EEPROM_CFG_PKEY_S 8 +#define AR_EEPROM_CFG_EN_L 0x01000000 /* EPRM_EN_L setting */ + +/* MAC PCU Registers */ + +#define AR_STA_ID1_SADH_MASK 0x0000FFFF /* upper 16 bits of MAC addr */ +#define AR_STA_ID1_STA_AP 0x00010000 /* Device is AP */ +#define AR_STA_ID1_ADHOC 0x00020000 /* Device is ad-hoc */ +#define AR_STA_ID1_PWR_SAV 0x00040000 /* Power save reporting in + self-generated frames */ +#define AR_STA_ID1_KSRCHDIS 0x00080000 /* Key search disable */ +#define AR_STA_ID1_PCF 0x00100000 /* Observe PCF */ +#define AR_STA_ID1_USE_DEFANT 0x00200000 /* Use default antenna */ +#define AR_STA_ID1_UPD_DEFANT 0x00400000 /* Update default antenna w/ + TX antenna */ +#define AR_STA_ID1_RTS_USE_DEF 0x00800000 /* Use default antenna to send RTS */ +#define AR_STA_ID1_ACKCTS_6MB 0x01000000 /* Use 6Mb/s rate for ACK & CTS */ +#define AR_STA_ID1_BASE_RATE_11B 0x02000000/* Use 11b base rate for ACK & CTS */ +#define AR_STA_ID1_USE_DA_SG 0x04000000 /* Use default antenna for + self-generated frames */ +#define AR_STA_ID1_CRPT_MIC_ENABLE 0x08000000 /* Enable Michael */ +#define AR_STA_ID1_KSRCH_MODE 0x10000000 /* Look-up key when keyID != 0 */ +#define AR_STA_ID1_PRE_SEQNUM 0x20000000 /* Preserve s/w sequence number */ +#define AR_STA_ID1_CBCIV_ENDIAN 0x40000000 +#define AR_STA_ID1_MCAST_KSRCH 0x80000000 /* Do keycache search for mcast */ + +#define AR_BSS_ID1_U16 0x0000FFFF /* Upper 16 bits of BSSID */ +#define AR_BSS_ID1_AID 0xFFFF0000 /* Association ID */ +#define AR_BSS_ID1_AID_S 16 + +#define AR_SLOT_TIME_MASK 0x000007FF /* Slot time mask */ + +#define AR_TIME_OUT_ACK 0x00003FFF /* ACK time-out */ +#define AR_TIME_OUT_ACK_S 0 +#define AR_TIME_OUT_CTS 0x3FFF0000 /* CTS time-out */ +#define AR_TIME_OUT_CTS_S 16 + +#define AR_RSSI_THR_MASK 0x000000FF /* Beacon RSSI warning threshold */ +#define AR_RSSI_THR_BM_THR 0x0000FF00 /* Missed beacon threshold */ +#define AR_RSSI_THR_BM_THR_S 8 + +#define AR_USEC_USEC 0x0000007F /* clock cycles in 1 usec */ +#define AR_USEC_USEC_S 0 +#define AR_USEC_USEC32 0x00003F80 /* 32MHz clock cycles in 1 usec */ +#define AR_USEC_USEC32_S 7 + +#define AR5212_USEC_TX_LAT_M 0x007FC000 /* Tx latency */ +#define AR5212_USEC_TX_LAT_S 14 +#define AR5212_USEC_RX_LAT_M 0x1F800000 /* Rx latency */ +#define AR5212_USEC_RX_LAT_S 23 + +#define AR_BEACON_PERIOD 0x0000FFFF /* Beacon period mask in TU/msec */ +#define AR_BEACON_PERIOD_S 0 +#define AR_BEACON_TIM 0x007F0000 /* byte offset of TIM start */ +#define AR_BEACON_TIM_S 16 +#define AR_BEACON_EN 0x00800000 /* Beacon enable */ +#define AR_BEACON_RESET_TSF 0x01000000 /* Clear TSF to 0 */ + +#define AR_RX_NONE 0x00000000 /* Disallow all frames */ +#define AR_RX_UCAST 0x00000001 /* Allow unicast frames */ +#define AR_RX_MCAST 0x00000002 /* Allow multicast frames */ +#define AR_RX_BCAST 0x00000004 /* Allow broadcast frames */ +#define AR_RX_CONTROL 0x00000008 /* Allow control frames */ +#define AR_RX_BEACON 0x00000010 /* Allow beacon frames */ +#define AR_RX_PROM 0x00000020 /* Promiscuous mode, all packets */ +#define AR_RX_PROBE_REQ 0x00000080 /* Allow probe request frames */ + +#define AR_DIAG_CACHE_ACK 0x00000001 /* No ACK if no valid key found */ +#define AR_DIAG_ACK_DIS 0x00000002 /* Disable ACK generation */ +#define AR_DIAG_CTS_DIS 0x00000004 /* Disable CTS generation */ +#define AR_DIAG_ENCRYPT_DIS 0x00000008 /* Disable encryption */ +#define AR_DIAG_DECRYPT_DIS 0x00000010 /* Disable decryption */ +#define AR_DIAG_RX_DIS 0x00000020 /* Disable receive */ +#define AR_DIAG_CORR_FCS 0x00000080 /* Corrupt FCS */ +#define AR_DIAG_CHAN_INFO 0x00000100 /* Dump channel info */ +#define AR_DIAG_EN_SCRAMSD 0x00000200 /* Enable fixed scrambler seed */ +#define AR_DIAG_SCRAM_SEED 0x0001FC00 /* Fixed scrambler seed */ +#define AR_DIAG_SCRAM_SEED_S 10 +#define AR_DIAG_FRAME_NV0 0x00020000 /* Accept frames of non-zero + protocol version */ +#define AR_DIAG_OBS_PT_SEL 0x000C0000 /* Observation point select */ +#define AR_DIAG_OBS_PT_SEL_S 18 +#define AR_DIAG_RX_CLR_HI 0x00100000 /* Force rx_clear high */ +#define AR_DIAG_IGNORE_CS 0x00200000 /* Force virtual carrier sense */ +#define AR_DIAG_CHAN_IDLE 0x00400000 /* Force channel idle high */ +#define AR_DIAG_PHEAR_ME 0x00800000 /* Uses framed and wait_wep in the pherr_enable_eifs if set to 0 */ + +#define AR_SLEEP1_NEXT_DTIM 0x0007ffff /* Abs. time(1/8TU) for next DTIM */ +#define AR_SLEEP1_NEXT_DTIM_S 0 +#define AR_SLEEP1_ASSUME_DTIM 0x00080000 /* Assume DTIM present on missent beacon */ +#define AR_SLEEP1_ENH_SLEEP_ENA 0x00100000 /* Enable enhanced sleep logic */ +#define AR_SLEEP1_CAB_TIMEOUT 0xff000000 /* CAB timeout(TU) */ +#define AR_SLEEP1_CAB_TIMEOUT_S 24 + +#define AR_SLEEP2_NEXT_TIM 0x0007ffff /* Abs. time(1/8TU) for next DTIM */ +#define AR_SLEEP2_NEXT_TIM_S 0 +#define AR_SLEEP2_BEACON_TIMEOUT 0xff000000 /* Beacon timeout(TU) */ +#define AR_SLEEP2_BEACON_TIMEOUT_S 24 + +#define AR_SLEEP3_TIM_PERIOD 0x0000ffff /* Tim/Beacon period (TU) */ +#define AR_SLEEP3_TIM_PERIOD_S 0 +#define AR_SLEEP3_DTIM_PERIOD 0xffff0000 /* DTIM period (TU) */ +#define AR_SLEEP3_DTIM_PERIOD_S 16 + +#define AR_TPC_ACK 0x0000003f /* ack frames */ +#define AR_TPC_ACK_S 0 +#define AR_TPC_CTS 0x00003f00 /* cts frames */ +#define AR_TPC_CTS_S 8 +#define AR_TPC_CHIRP 0x003f0000 /* chirp frames */ +#define AR_TPC_CHIRP_S 16 +#define AR_TPC_DOPPLER 0x0f000000 /* doppler chirp span */ +#define AR_TPC_DOPPLER_S 24 + +#define AR_PHY_ERR_RADAR 0x00000020 /* Radar signal */ +#define AR_PHY_ERR_OFDM_TIMING 0x00020000 /* False detect for OFDM */ +#define AR_PHY_ERR_CCK_TIMING 0x02000000 /* False detect for CCK */ + +#define AR_TSF_PARM_INCREMENT 0x000000ff +#define AR_TSF_PARM_INCREMENT_S 0 + +#define AR_NOACK_2BIT_VALUE 0x0000000f +#define AR_NOACK_2BIT_VALUE_S 0 +#define AR_NOACK_BIT_OFFSET 0x00000070 +#define AR_NOACK_BIT_OFFSET_S 4 +#define AR_NOACK_BYTE_OFFSET 0x00000180 +#define AR_NOACK_BYTE_OFFSET_S 7 + +#define AR_MISC_MODE_BSSID_MATCH_FORCE 0x1 /* Force BSSID match */ +#define AR_MISC_MODE_ACKSIFS_MEMORY 0x2 /* ACKSIFS use contents of Rate */ +#define AR_MISC_MODE_MIC_NEW_LOC_ENABLE 0x4 /* Xmit Michael Key same as Rcv */ +#define AR_MISC_MODE_TX_ADD_TSF 0x8 /* Beacon/Probe-Rsp timestamp add (not replace) */ + +#define AR_KEYTABLE_KEY0(_n) (AR_KEYTABLE(_n) + 0) /* key bit 0-31 */ +#define AR_KEYTABLE_KEY1(_n) (AR_KEYTABLE(_n) + 4) /* key bit 32-47 */ +#define AR_KEYTABLE_KEY2(_n) (AR_KEYTABLE(_n) + 8) /* key bit 48-79 */ +#define AR_KEYTABLE_KEY3(_n) (AR_KEYTABLE(_n) + 12) /* key bit 80-95 */ +#define AR_KEYTABLE_KEY4(_n) (AR_KEYTABLE(_n) + 16) /* key bit 96-127 */ +#define AR_KEYTABLE_TYPE(_n) (AR_KEYTABLE(_n) + 20) /* key type */ +#define AR_KEYTABLE_TYPE_40 0x00000000 /* WEP 40 bit key */ +#define AR_KEYTABLE_TYPE_104 0x00000001 /* WEP 104 bit key */ +#define AR_KEYTABLE_TYPE_128 0x00000003 /* WEP 128 bit key */ +#define AR_KEYTABLE_TYPE_TKIP 0x00000004 /* TKIP and Michael */ +#define AR_KEYTABLE_TYPE_AES 0x00000005 /* AES/OCB 128 bit key */ +#define AR_KEYTABLE_TYPE_CCM 0x00000006 /* AES/CCM 128 bit key */ +#define AR_KEYTABLE_TYPE_CLR 0x00000007 /* no encryption */ +#define AR_KEYTABLE_ANT 0x00000008 /* previous transmit antenna */ +#define AR_KEYTABLE_MAC0(_n) (AR_KEYTABLE(_n) + 24) /* MAC address 1-32 */ +#define AR_KEYTABLE_MAC1(_n) (AR_KEYTABLE(_n) + 28) /* MAC address 33-47 */ +#define AR_KEYTABLE_VALID 0x00008000 /* key and MAC address valid */ + +/* Compress settings */ +#define AR_CCFG_WIN_M 0x00000007 /* mask for AR_CCFG_WIN size */ +#define AR_CCFG_MIB_INT_EN 0x00000008 /* compression performance MIB counter int enable */ +#define AR_CCUCFG_RESET_VAL 0x00100200 /* the should be reset value */ +#define AR_CCUCFG_CATCHUP_EN 0x00000001 /* Compression catchup enable */ +#define AR_DCM_D_EN 0x00000001 /* all direct frames to be decompressed */ +#define AR_COMPRESSION_WINDOW_SIZE 4096 /* default comp. window size */ + +#endif /* _DEV_AR5212REG_H_ */ --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5212/ar5311reg.h 2009-03-23 17:36:55.000000000 +0000 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2008 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ar5311reg.h,v 1.1 2009/03/23 17:14:48 sborrill Exp $ + */ +#ifndef _DEV_ATH_AR5311REG_H_ +#define _DEV_ATH_AR5311REG_H_ + +/* + * Definitions for the Atheros 5311 chipset. + */ +#define AR5311_QDCLKGATE 0x005c /* MAC QCU/DCU clock gating control */ +#define AR5311_QDCLKGATE_QCU_M 0x0000FFFF /* QCU clock disable */ +#define AR5311_QDCLKGATE_DCU_M 0x07FF0000 /* DCU clock disable */ + +#define AR5311_RXCFG_DEF_RX_ANTENNA 0x00000008 /* Default Receive Antenna */ + +/* + * NOTE: MAC_5211/MAC_5311 difference + * On Oahu the TX latency field has increased from 6 bits to 9 bits. + * The RX latency field is unchanged but is shifted over 3 bits. + */ +#define AR5311_USEC_TX_LAT_M 0x000FC000 /* tx latency (usec) */ +#define AR5311_USEC_TX_LAT_S 14 +#define AR5311_USEC_RX_LAT_M 0x03F00000 /* rx latency (usec) */ +#define AR5311_USEC_RX_LAT_S 20 + +/* + * NOTE: MAC_5211/MAC_5311 difference + * On Maui2/Spirit the frame sequence number is controlled per DCU. + * On Oahu the frame sequence number is global across all DCUs and + * is controlled + */ +#define AR5311_D_MISC_SEQ_NUM_CONTROL 0x01000000 /* seq num local or global */ +#define AR5311_DIAG_USE_ECO 0x00000400 /* "super secret" enable ECO */ + +#endif /* _DEV_ATH_AR5311REG_H_ */ --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5212/ar5413.c 2009-03-23 17:36:55.000000000 +0000 @@ -0,0 +1,797 @@ +/* + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2008 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ar5413.c,v 1.1 2009/03/23 17:14:48 sborrill Exp $ + */ +#include "opt_ah.h" + +#include "ah.h" +#include "ah_internal.h" + +#include "ah_eeprom_v3.h" + +#include "ar5212/ar5212.h" +#include "ar5212/ar5212reg.h" +#include "ar5212/ar5212phy.h" + +#define AH_5212_5413 +#include "ar5212/ar5212.ini" + +#define N(a) (sizeof(a)/sizeof(a[0])) + +struct ar5413State { + RF_HAL_FUNCS base; /* public state, must be first */ + uint16_t pcdacTable[PWR_TABLE_SIZE_2413]; + + uint32_t Bank1Data[N(ar5212Bank1_5413)]; + uint32_t Bank2Data[N(ar5212Bank2_5413)]; + uint32_t Bank3Data[N(ar5212Bank3_5413)]; + uint32_t Bank6Data[N(ar5212Bank6_5413)]; + uint32_t Bank7Data[N(ar5212Bank7_5413)]; + + /* + * Private state for reduced stack usage. + */ + /* filled out Vpd table for all pdGains (chanL) */ + uint16_t vpdTable_L[MAX_NUM_PDGAINS_PER_CHANNEL] + [MAX_PWR_RANGE_IN_HALF_DB]; + /* filled out Vpd table for all pdGains (chanR) */ + uint16_t vpdTable_R[MAX_NUM_PDGAINS_PER_CHANNEL] + [MAX_PWR_RANGE_IN_HALF_DB]; + /* filled out Vpd table for all pdGains (interpolated) */ + uint16_t vpdTable_I[MAX_NUM_PDGAINS_PER_CHANNEL] + [MAX_PWR_RANGE_IN_HALF_DB]; +}; +#define AR5413(ah) ((struct ar5413State *) AH5212(ah)->ah_rfHal) + +extern void ar5212ModifyRfBuffer(uint32_t *rfBuf, uint32_t reg32, + uint32_t numBits, uint32_t firstBit, uint32_t column); + +static void +ar5413WriteRegs(struct ath_hal *ah, u_int modesIndex, u_int freqIndex, + int writes) +{ + HAL_INI_WRITE_ARRAY(ah, ar5212Modes_5413, modesIndex, writes); + HAL_INI_WRITE_ARRAY(ah, ar5212Common_5413, 1, writes); + HAL_INI_WRITE_ARRAY(ah, ar5212BB_RfGain_5413, freqIndex, writes); +} + +/* + * Take the MHz channel value and set the Channel value + * + * ASSUMES: Writes enabled to analog bus + */ +static HAL_BOOL +ar5413SetChannel(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan) +{ + uint32_t channelSel = 0; + uint32_t bModeSynth = 0; + uint32_t aModeRefSel = 0; + uint32_t reg32 = 0; + uint16_t freq; + + OS_MARK(ah, AH_MARK_SETCHANNEL, chan->channel); + + if (chan->channel < 4800) { + uint32_t txctl; + + if (((chan->channel - 2192) % 5) == 0) { + channelSel = ((chan->channel - 672) * 2 - 3040)/10; + bModeSynth = 0; + } else if (((chan->channel - 2224) % 5) == 0) { + channelSel = ((chan->channel - 704) * 2 - 3040) / 10; + bModeSynth = 1; + } else { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: invalid channel %u MHz\n", + __func__, chan->channel); + return AH_FALSE; + } + + channelSel = (channelSel << 2) & 0xff; + channelSel = ath_hal_reverseBits(channelSel, 8); + + txctl = OS_REG_READ(ah, AR_PHY_CCK_TX_CTRL); + if (chan->channel == 2484) { + /* Enable channel spreading for channel 14 */ + OS_REG_WRITE(ah, AR_PHY_CCK_TX_CTRL, + txctl | AR_PHY_CCK_TX_CTRL_JAPAN); + } else { + OS_REG_WRITE(ah, AR_PHY_CCK_TX_CTRL, + txctl &~ AR_PHY_CCK_TX_CTRL_JAPAN); + } + } else if (((chan->channel % 5) == 2) && (chan->channel <= 5435)) { + freq = chan->channel - 2; /* Align to even 5MHz raster */ + channelSel = ath_hal_reverseBits( + (uint32_t)(((freq - 4800)*10)/25 + 1), 8); + aModeRefSel = ath_hal_reverseBits(0, 2); + } else if ((chan->channel % 20) == 0 && chan->channel >= 5120) { + channelSel = ath_hal_reverseBits( + ((chan->channel - 4800) / 20 << 2), 8); + aModeRefSel = ath_hal_reverseBits(1, 2); + } else if ((chan->channel % 10) == 0) { + channelSel = ath_hal_reverseBits( + ((chan->channel - 4800) / 10 << 1), 8); + aModeRefSel = ath_hal_reverseBits(1, 2); + } else if ((chan->channel % 5) == 0) { + channelSel = ath_hal_reverseBits( + (chan->channel - 4800) / 5, 8); + aModeRefSel = ath_hal_reverseBits(1, 2); + } else { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel %u MHz\n", + __func__, chan->channel); + return AH_FALSE; + } + + reg32 = (channelSel << 4) | (aModeRefSel << 2) | (bModeSynth << 1) | + (1 << 12) | 0x1; + OS_REG_WRITE(ah, AR_PHY(0x27), reg32 & 0xff); + + reg32 >>= 8; + OS_REG_WRITE(ah, AR_PHY(0x36), reg32 & 0x7f); + + AH_PRIVATE(ah)->ah_curchan = chan; + return AH_TRUE; +} + +/* + * Reads EEPROM header info from device structure and programs + * all rf registers + * + * REQUIRES: Access to the analog rf device + */ +static HAL_BOOL +ar5413SetRfRegs(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan, uint16_t modesIndex, uint16_t *rfXpdGain) +{ +#define RF_BANK_SETUP(_priv, _ix, _col) do { \ + int i; \ + for (i = 0; i < N(ar5212Bank##_ix##_5413); i++) \ + (_priv)->Bank##_ix##Data[i] = ar5212Bank##_ix##_5413[i][_col];\ +} while (0) + struct ath_hal_5212 *ahp = AH5212(ah); + const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom; + uint16_t ob5GHz = 0, db5GHz = 0; + uint16_t ob2GHz = 0, db2GHz = 0; + struct ar5413State *priv = AR5413(ah); + int regWrites = 0; + + HALDEBUG(ah, HAL_DEBUG_RFPARAM, + "%s: chan 0x%x flag 0x%x modesIndex 0x%x\n", + __func__, chan->channel, chan->channelFlags, modesIndex); + + HALASSERT(priv != AH_NULL); + + /* Setup rf parameters */ + switch (chan->channelFlags & CHANNEL_ALL) { + case CHANNEL_A: + case CHANNEL_T: + if (chan->channel > 4000 && chan->channel < 5260) { + ob5GHz = ee->ee_ob1; + db5GHz = ee->ee_db1; + } else if (chan->channel >= 5260 && chan->channel < 5500) { + ob5GHz = ee->ee_ob2; + db5GHz = ee->ee_db2; + } else if (chan->channel >= 5500 && chan->channel < 5725) { + ob5GHz = ee->ee_ob3; + db5GHz = ee->ee_db3; + } else if (chan->channel >= 5725) { + ob5GHz = ee->ee_ob4; + db5GHz = ee->ee_db4; + } else { + /* XXX else */ + } + break; + case CHANNEL_B: + ob2GHz = ee->ee_obFor24; + db2GHz = ee->ee_dbFor24; + break; + case CHANNEL_G: + case CHANNEL_108G: + ob2GHz = ee->ee_obFor24g; + db2GHz = ee->ee_dbFor24g; + break; + default: + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel flags 0x%x\n", + __func__, chan->channelFlags); + return AH_FALSE; + } + + /* Bank 1 Write */ + RF_BANK_SETUP(priv, 1, 1); + + /* Bank 2 Write */ + RF_BANK_SETUP(priv, 2, modesIndex); + + /* Bank 3 Write */ + RF_BANK_SETUP(priv, 3, modesIndex); + + /* Bank 6 Write */ + RF_BANK_SETUP(priv, 6, modesIndex); + + /* Only the 5 or 2 GHz OB/DB need to be set for a mode */ + if (IS_CHAN_2GHZ(chan)) { + ar5212ModifyRfBuffer(priv->Bank6Data, ob2GHz, 3, 241, 0); + ar5212ModifyRfBuffer(priv->Bank6Data, db2GHz, 3, 238, 0); + + /* TODO - only for Eagle 1.0 2GHz - remove for production */ + /* XXX: but without this bit G doesn't work. */ + ar5212ModifyRfBuffer(priv->Bank6Data, 1 , 1, 291, 2); + + /* Optimum value for rf_pwd_iclobuf2G for PCIe chips only */ + if (IS_PCIE(ah)) { + ar5212ModifyRfBuffer(priv->Bank6Data, ath_hal_reverseBits(6, 3), + 3, 131, 3); + } + } else { + ar5212ModifyRfBuffer(priv->Bank6Data, ob5GHz, 3, 247, 0); + ar5212ModifyRfBuffer(priv->Bank6Data, db5GHz, 3, 244, 0); + + } + + /* Bank 7 Setup */ + RF_BANK_SETUP(priv, 7, modesIndex); + + /* Write Analog registers */ + HAL_INI_WRITE_BANK(ah, ar5212Bank1_5413, priv->Bank1Data, regWrites); + HAL_INI_WRITE_BANK(ah, ar5212Bank2_5413, priv->Bank2Data, regWrites); + HAL_INI_WRITE_BANK(ah, ar5212Bank3_5413, priv->Bank3Data, regWrites); + HAL_INI_WRITE_BANK(ah, ar5212Bank6_5413, priv->Bank6Data, regWrites); + HAL_INI_WRITE_BANK(ah, ar5212Bank7_5413, priv->Bank7Data, regWrites); + + /* Now that we have reprogrammed rfgain value, clear the flag. */ + ahp->ah_rfgainState = HAL_RFGAIN_INACTIVE; + + return AH_TRUE; +#undef RF_BANK_SETUP +} + +/* + * Return a reference to the requested RF Bank. + */ +static uint32_t * +ar5413GetRfBank(struct ath_hal *ah, int bank) +{ + struct ar5413State *priv = AR5413(ah); + + HALASSERT(priv != AH_NULL); + switch (bank) { + case 1: return priv->Bank1Data; + case 2: return priv->Bank2Data; + case 3: return priv->Bank3Data; + case 6: return priv->Bank6Data; + case 7: return priv->Bank7Data; + } + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unknown RF Bank %d requested\n", + __func__, bank); + return AH_NULL; +} + +/* + * Return indices surrounding the value in sorted integer lists. + * + * NB: the input list is assumed to be sorted in ascending order + */ +static void +GetLowerUpperIndex(int16_t v, const uint16_t *lp, uint16_t listSize, + uint32_t *vlo, uint32_t *vhi) +{ + int16_t target = v; + const uint16_t *ep = lp+listSize; + const uint16_t *tp; + + /* + * Check first and last elements for out-of-bounds conditions. + */ + if (target < lp[0]) { + *vlo = *vhi = 0; + return; + } + if (target >= ep[-1]) { + *vlo = *vhi = listSize - 1; + return; + } + + /* look for value being near or between 2 values in list */ + for (tp = lp; tp < ep; tp++) { + /* + * If value is close to the current value of the list + * then target is not between values, it is one of the values + */ + if (*tp == target) { + *vlo = *vhi = tp - (const uint16_t *) lp; + return; + } + /* + * Look for value being between current value and next value + * if so return these 2 values + */ + if (target < tp[1]) { + *vlo = tp - (const uint16_t *) lp; + *vhi = *vlo + 1; + return; + } + } +} + +/* + * Fill the Vpdlist for indices Pmax-Pmin + */ +static HAL_BOOL +ar5413FillVpdTable(uint32_t pdGainIdx, int16_t Pmin, int16_t Pmax, + const int16_t *pwrList, const uint16_t *VpdList, + uint16_t numIntercepts, + uint16_t retVpdList[][64]) +{ + uint16_t ii, jj, kk; + int16_t currPwr = (int16_t)(2*Pmin); + /* since Pmin is pwr*2 and pwrList is 4*pwr */ + uint32_t idxL = 0, idxR = 0; + + ii = 0; + jj = 0; + + if (numIntercepts < 2) + return AH_FALSE; + + while (ii <= (uint16_t)(Pmax - Pmin)) { + GetLowerUpperIndex(currPwr, (const uint16_t *) pwrList, + numIntercepts, &(idxL), &(idxR)); + if (idxR < 1) + idxR = 1; /* extrapolate below */ + if (idxL == (uint32_t)(numIntercepts - 1)) + idxL = numIntercepts - 2; /* extrapolate above */ + if (pwrList[idxL] == pwrList[idxR]) + kk = VpdList[idxL]; + else + kk = (uint16_t) + (((currPwr - pwrList[idxL])*VpdList[idxR]+ + (pwrList[idxR] - currPwr)*VpdList[idxL])/ + (pwrList[idxR] - pwrList[idxL])); + retVpdList[pdGainIdx][ii] = kk; + ii++; + currPwr += 2; /* half dB steps */ + } + + return AH_TRUE; +} + +/* + * Returns interpolated or the scaled up interpolated value + */ +static int16_t +interpolate_signed(uint16_t target, uint16_t srcLeft, uint16_t srcRight, + int16_t targetLeft, int16_t targetRight) +{ + int16_t rv; + + if (srcRight != srcLeft) { + rv = ((target - srcLeft)*targetRight + + (srcRight - target)*targetLeft) / (srcRight - srcLeft); + } else { + rv = targetLeft; + } + return rv; +} + +/* + * Uses the data points read from EEPROM to reconstruct the pdadc power table + * Called by ar5413SetPowerTable() + */ +static int +ar5413getGainBoundariesAndPdadcsForPowers(struct ath_hal *ah, uint16_t channel, + const RAW_DATA_STRUCT_2413 *pRawDataset, + uint16_t pdGainOverlap_t2, + int16_t *pMinCalPower, uint16_t pPdGainBoundaries[], + uint16_t pPdGainValues[], uint16_t pPDADCValues[]) +{ + struct ar5413State *priv = AR5413(ah); +#define VpdTable_L priv->vpdTable_L +#define VpdTable_R priv->vpdTable_R +#define VpdTable_I priv->vpdTable_I + uint32_t ii, jj, kk; + int32_t ss;/* potentially -ve index for taking care of pdGainOverlap */ + uint32_t idxL = 0, idxR = 0; + uint32_t numPdGainsUsed = 0; + /* + * If desired to support -ve power levels in future, just + * change pwr_I_0 to signed 5-bits. + */ + int16_t Pmin_t2[MAX_NUM_PDGAINS_PER_CHANNEL]; + /* to accomodate -ve power levels later on. */ + int16_t Pmax_t2[MAX_NUM_PDGAINS_PER_CHANNEL]; + /* to accomodate -ve power levels later on */ + uint16_t numVpd = 0; + uint16_t Vpd_step; + int16_t tmpVal ; + uint32_t sizeCurrVpdTable, maxIndex, tgtIndex; + + /* Get upper lower index */ + GetLowerUpperIndex(channel, pRawDataset->pChannels, + pRawDataset->numChannels, &(idxL), &(idxR)); + + for (ii = 0; ii < MAX_NUM_PDGAINS_PER_CHANNEL; ii++) { + jj = MAX_NUM_PDGAINS_PER_CHANNEL - ii - 1; + /* work backwards 'cause highest pdGain for lowest power */ + numVpd = pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].numVpd; + if (numVpd > 0) { + pPdGainValues[numPdGainsUsed] = pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].pd_gain; + Pmin_t2[numPdGainsUsed] = pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].pwr_t4[0]; + if (Pmin_t2[numPdGainsUsed] >pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].pwr_t4[0]) { + Pmin_t2[numPdGainsUsed] = pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].pwr_t4[0]; + } + Pmin_t2[numPdGainsUsed] = (int16_t) + (Pmin_t2[numPdGainsUsed] / 2); + Pmax_t2[numPdGainsUsed] = pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].pwr_t4[numVpd-1]; + if (Pmax_t2[numPdGainsUsed] > pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].pwr_t4[numVpd-1]) + Pmax_t2[numPdGainsUsed] = + pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].pwr_t4[numVpd-1]; + Pmax_t2[numPdGainsUsed] = (int16_t)(Pmax_t2[numPdGainsUsed] / 2); + ar5413FillVpdTable( + numPdGainsUsed, Pmin_t2[numPdGainsUsed], Pmax_t2[numPdGainsUsed], + &(pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].pwr_t4[0]), + &(pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].Vpd[0]), numVpd, VpdTable_L + ); + ar5413FillVpdTable( + numPdGainsUsed, Pmin_t2[numPdGainsUsed], Pmax_t2[numPdGainsUsed], + &(pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].pwr_t4[0]), + &(pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].Vpd[0]), numVpd, VpdTable_R + ); + for (kk = 0; kk < (uint16_t)(Pmax_t2[numPdGainsUsed] - Pmin_t2[numPdGainsUsed]); kk++) { + VpdTable_I[numPdGainsUsed][kk] = + interpolate_signed( + channel, pRawDataset->pChannels[idxL], pRawDataset->pChannels[idxR], + (int16_t)VpdTable_L[numPdGainsUsed][kk], (int16_t)VpdTable_R[numPdGainsUsed][kk]); + } + /* fill VpdTable_I for this pdGain */ + numPdGainsUsed++; + } + /* if this pdGain is used */ + } + + *pMinCalPower = Pmin_t2[0]; + kk = 0; /* index for the final table */ + for (ii = 0; ii < numPdGainsUsed; ii++) { + if (ii == (numPdGainsUsed - 1)) + pPdGainBoundaries[ii] = Pmax_t2[ii] + + PD_GAIN_BOUNDARY_STRETCH_IN_HALF_DB; + else + pPdGainBoundaries[ii] = (uint16_t) + ((Pmax_t2[ii] + Pmin_t2[ii+1]) / 2 ); + if (pPdGainBoundaries[ii] > 63) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: clamp pPdGainBoundaries[%d] %d\n", + __func__, ii, pPdGainBoundaries[ii]);/*XXX*/ + pPdGainBoundaries[ii] = 63; + } + + /* Find starting index for this pdGain */ + if (ii == 0) + ss = 0; /* for the first pdGain, start from index 0 */ + else + ss = (pPdGainBoundaries[ii-1] - Pmin_t2[ii]) - + pdGainOverlap_t2; + Vpd_step = (uint16_t)(VpdTable_I[ii][1] - VpdTable_I[ii][0]); + Vpd_step = (uint16_t)((Vpd_step < 1) ? 1 : Vpd_step); + /* + *-ve ss indicates need to extrapolate data below for this pdGain + */ + while (ss < 0) { + tmpVal = (int16_t)(VpdTable_I[ii][0] + ss*Vpd_step); + pPDADCValues[kk++] = (uint16_t)((tmpVal < 0) ? 0 : tmpVal); + ss++; + } + + sizeCurrVpdTable = Pmax_t2[ii] - Pmin_t2[ii]; + tgtIndex = pPdGainBoundaries[ii] + pdGainOverlap_t2 - Pmin_t2[ii]; + maxIndex = (tgtIndex < sizeCurrVpdTable) ? tgtIndex : sizeCurrVpdTable; + + while (ss < (int16_t)maxIndex) + pPDADCValues[kk++] = VpdTable_I[ii][ss++]; + + Vpd_step = (uint16_t)(VpdTable_I[ii][sizeCurrVpdTable-1] - + VpdTable_I[ii][sizeCurrVpdTable-2]); + Vpd_step = (uint16_t)((Vpd_step < 1) ? 1 : Vpd_step); + /* + * for last gain, pdGainBoundary == Pmax_t2, so will + * have to extrapolate + */ + if (tgtIndex > maxIndex) { /* need to extrapolate above */ + while(ss < (int16_t)tgtIndex) { + tmpVal = (uint16_t) + (VpdTable_I[ii][sizeCurrVpdTable-1] + + (ss-maxIndex)*Vpd_step); + pPDADCValues[kk++] = (tmpVal > 127) ? + 127 : tmpVal; + ss++; + } + } /* extrapolated above */ + } /* for all pdGainUsed */ + + while (ii < MAX_NUM_PDGAINS_PER_CHANNEL) { + pPdGainBoundaries[ii] = pPdGainBoundaries[ii-1]; + ii++; + } + while (kk < 128) { + pPDADCValues[kk] = pPDADCValues[kk-1]; + kk++; + } + + return numPdGainsUsed; +#undef VpdTable_L +#undef VpdTable_R +#undef VpdTable_I +} + +static HAL_BOOL +ar5413SetPowerTable(struct ath_hal *ah, + int16_t *minPower, int16_t *maxPower, HAL_CHANNEL_INTERNAL *chan, + uint16_t *rfXpdGain) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom; + const RAW_DATA_STRUCT_2413 *pRawDataset = AH_NULL; + uint16_t pdGainOverlap_t2; + int16_t minCalPower5413_t2; + uint16_t *pdadcValues = ahp->ah_pcdacTable; + uint16_t gainBoundaries[4]; + uint32_t reg32, regoffset; + int i, numPdGainsUsed; +#ifndef AH_USE_INIPDGAIN + uint32_t tpcrg1; +#endif + + HALDEBUG(ah, HAL_DEBUG_RFPARAM, "%s: chan 0x%x flag 0x%x\n", + __func__, chan->channel,chan->channelFlags); + + if (IS_CHAN_G(chan) || IS_CHAN_108G(chan)) + pRawDataset = &ee->ee_rawDataset2413[headerInfo11G]; + else if (IS_CHAN_B(chan)) + pRawDataset = &ee->ee_rawDataset2413[headerInfo11B]; + else { + HALASSERT(IS_CHAN_5GHZ(chan)); + pRawDataset = &ee->ee_rawDataset2413[headerInfo11A]; + } + + pdGainOverlap_t2 = (uint16_t) SM(OS_REG_READ(ah, AR_PHY_TPCRG5), + AR_PHY_TPCRG5_PD_GAIN_OVERLAP); + + numPdGainsUsed = ar5413getGainBoundariesAndPdadcsForPowers(ah, + chan->channel, pRawDataset, pdGainOverlap_t2, + &minCalPower5413_t2,gainBoundaries, rfXpdGain, pdadcValues); + HALASSERT(1 <= numPdGainsUsed && numPdGainsUsed <= 3); + +#ifdef AH_USE_INIPDGAIN + /* + * Use pd_gains curve from eeprom; Atheros always uses + * the default curve from the ini file but some vendors + * (e.g. Zcomax) want to override this curve and not + * honoring their settings results in tx power 5dBm low. + */ + OS_REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN, + (pRawDataset->pDataPerChannel[0].numPdGains - 1)); +#else + tpcrg1 = OS_REG_READ(ah, AR_PHY_TPCRG1); + tpcrg1 = (tpcrg1 &~ AR_PHY_TPCRG1_NUM_PD_GAIN) + | SM(numPdGainsUsed-1, AR_PHY_TPCRG1_NUM_PD_GAIN); + switch (numPdGainsUsed) { + case 3: + tpcrg1 &= ~AR_PHY_TPCRG1_PDGAIN_SETTING3; + tpcrg1 |= SM(rfXpdGain[2], AR_PHY_TPCRG1_PDGAIN_SETTING3); + /* fall thru... */ + case 2: + tpcrg1 &= ~AR_PHY_TPCRG1_PDGAIN_SETTING2; + tpcrg1 |= SM(rfXpdGain[1], AR_PHY_TPCRG1_PDGAIN_SETTING2); + /* fall thru... */ + case 1: + tpcrg1 &= ~AR_PHY_TPCRG1_PDGAIN_SETTING1; + tpcrg1 |= SM(rfXpdGain[0], AR_PHY_TPCRG1_PDGAIN_SETTING1); + break; + } +#ifdef AH_DEBUG + if (tpcrg1 != OS_REG_READ(ah, AR_PHY_TPCRG1)) + HALDEBUG(ah, HAL_DEBUG_RFPARAM, "%s: using non-default " + "pd_gains (default 0x%x, calculated 0x%x)\n", + __func__, OS_REG_READ(ah, AR_PHY_TPCRG1), tpcrg1); +#endif + OS_REG_WRITE(ah, AR_PHY_TPCRG1, tpcrg1); +#endif + + /* + * Note the pdadc table may not start at 0 dBm power, could be + * negative or greater than 0. Need to offset the power + * values by the amount of minPower for griffin + */ + if (minCalPower5413_t2 != 0) + ahp->ah_txPowerIndexOffset = (int16_t)(0 - minCalPower5413_t2); + else + ahp->ah_txPowerIndexOffset = 0; + + /* Finally, write the power values into the baseband power table */ + regoffset = 0x9800 + (672 <<2); /* beginning of pdadc table in griffin */ + for (i = 0; i < 32; i++) { + reg32 = ((pdadcValues[4*i + 0] & 0xFF) << 0) | + ((pdadcValues[4*i + 1] & 0xFF) << 8) | + ((pdadcValues[4*i + 2] & 0xFF) << 16) | + ((pdadcValues[4*i + 3] & 0xFF) << 24) ; + OS_REG_WRITE(ah, regoffset, reg32); + regoffset += 4; + } + + OS_REG_WRITE(ah, AR_PHY_TPCRG5, + SM(pdGainOverlap_t2, AR_PHY_TPCRG5_PD_GAIN_OVERLAP) | + SM(gainBoundaries[0], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1) | + SM(gainBoundaries[1], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2) | + SM(gainBoundaries[2], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3) | + SM(gainBoundaries[3], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4)); + + return AH_TRUE; +} + +static int16_t +ar5413GetMinPower(struct ath_hal *ah, const RAW_DATA_PER_CHANNEL_2413 *data) +{ + uint32_t ii,jj; + uint16_t Pmin=0,numVpd; + + for (ii = 0; ii < MAX_NUM_PDGAINS_PER_CHANNEL; ii++) { + jj = MAX_NUM_PDGAINS_PER_CHANNEL - ii - 1; + /* work backwards 'cause highest pdGain for lowest power */ + numVpd = data->pDataPerPDGain[jj].numVpd; + if (numVpd > 0) { + Pmin = data->pDataPerPDGain[jj].pwr_t4[0]; + return(Pmin); + } + } + return(Pmin); +} + +static int16_t +ar5413GetMaxPower(struct ath_hal *ah, const RAW_DATA_PER_CHANNEL_2413 *data) +{ + uint32_t ii; + uint16_t Pmax=0,numVpd; + + for (ii=0; ii< MAX_NUM_PDGAINS_PER_CHANNEL; ii++) { + /* work forwards cuase lowest pdGain for highest power */ + numVpd = data->pDataPerPDGain[ii].numVpd; + if (numVpd > 0) { + Pmax = data->pDataPerPDGain[ii].pwr_t4[numVpd-1]; + return(Pmax); + } + } + return(Pmax); +} + +static HAL_BOOL +ar5413GetChannelMaxMinPower(struct ath_hal *ah, HAL_CHANNEL *chan, + int16_t *maxPow, int16_t *minPow) +{ + const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom; + const RAW_DATA_STRUCT_2413 *pRawDataset = AH_NULL; + const RAW_DATA_PER_CHANNEL_2413 *data=AH_NULL; + uint16_t numChannels; + int totalD,totalF, totalMin,last, i; + + *maxPow = 0; + + if (IS_CHAN_G(chan) || IS_CHAN_108G(chan)) + pRawDataset = &ee->ee_rawDataset2413[headerInfo11G]; + else if (IS_CHAN_B(chan)) + pRawDataset = &ee->ee_rawDataset2413[headerInfo11B]; + else { + HALASSERT(IS_CHAN_5GHZ(chan)); + pRawDataset = &ee->ee_rawDataset2413[headerInfo11A]; + } + + numChannels = pRawDataset->numChannels; + data = pRawDataset->pDataPerChannel; + + /* Make sure the channel is in the range of the TP values + * (freq piers) + */ + if (numChannels < 1) + return(AH_FALSE); + + if ((chan->channel < data[0].channelValue) || + (chan->channel > data[numChannels-1].channelValue)) { + if (chan->channel < data[0].channelValue) { + *maxPow = ar5413GetMaxPower(ah, &data[0]); + *minPow = ar5413GetMinPower(ah, &data[0]); + return(AH_TRUE); + } else { + *maxPow = ar5413GetMaxPower(ah, &data[numChannels - 1]); + *minPow = ar5413GetMinPower(ah, &data[numChannels - 1]); + return(AH_TRUE); + } + } + + /* Linearly interpolate the power value now */ + for (last=0,i=0; (ichannel > data[i].channelValue); + last = i++); + totalD = data[i].channelValue - data[last].channelValue; + if (totalD > 0) { + totalF = ar5413GetMaxPower(ah, &data[i]) - ar5413GetMaxPower(ah, &data[last]); + *maxPow = (int8_t) ((totalF*(chan->channel-data[last].channelValue) + + ar5413GetMaxPower(ah, &data[last])*totalD)/totalD); + totalMin = ar5413GetMinPower(ah, &data[i]) - ar5413GetMinPower(ah, &data[last]); + *minPow = (int8_t) ((totalMin*(chan->channel-data[last].channelValue) + + ar5413GetMinPower(ah, &data[last])*totalD)/totalD); + return(AH_TRUE); + } else { + if (chan->channel == data[i].channelValue) { + *maxPow = ar5413GetMaxPower(ah, &data[i]); + *minPow = ar5413GetMinPower(ah, &data[i]); + return(AH_TRUE); + } else + return(AH_FALSE); + } +} + +/* + * Free memory for analog bank scratch buffers + */ +static void +ar5413RfDetach(struct ath_hal *ah) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + + HALASSERT(ahp->ah_rfHal != AH_NULL); + ath_hal_free(ahp->ah_rfHal); + ahp->ah_rfHal = AH_NULL; +} + +/* + * Allocate memory for analog bank scratch buffers + * Scratch Buffer will be reinitialized every reset so no need to zero now + */ +static HAL_BOOL +ar5413RfAttach(struct ath_hal *ah, HAL_STATUS *status) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + struct ar5413State *priv; + + HALASSERT(ah->ah_magic == AR5212_MAGIC); + + HALASSERT(ahp->ah_rfHal == AH_NULL); + priv = ath_hal_malloc(sizeof(struct ar5413State)); + if (priv == AH_NULL) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: cannot allocate private state\n", __func__); + *status = HAL_ENOMEM; /* XXX */ + return AH_FALSE; + } + priv->base.rfDetach = ar5413RfDetach; + priv->base.writeRegs = ar5413WriteRegs; + priv->base.getRfBank = ar5413GetRfBank; + priv->base.setChannel = ar5413SetChannel; + priv->base.setRfRegs = ar5413SetRfRegs; + priv->base.setPowerTable = ar5413SetPowerTable; + priv->base.getChannelMaxMinPower = ar5413GetChannelMaxMinPower; + priv->base.getNfAdjust = ar5212GetNfAdjust; + + ahp->ah_pcdacTable = priv->pcdacTable; + ahp->ah_pcdacTableSize = sizeof(priv->pcdacTable); + ahp->ah_rfHal = &priv->base; + + return AH_TRUE; +} + +static HAL_BOOL +ar5413Probe(struct ath_hal *ah) +{ + return IS_5413(ah); +} +AH_RF(RF5413, ar5413Probe, ar5413RfAttach); --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5210/ar5210.h 2009-03-23 17:36:55.000000000 +0000 @@ -0,0 +1,278 @@ +/* + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2004 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ar5210.h,v 1.1 2009/03/23 17:14:47 sborrill Exp $ + */ +#ifndef _ATH_AR5210_H_ +#define _ATH_AR5210_H_ + +#define AR5210_MAGIC 0x19980124 + +#if 0 +/* + * RTS_ENABLE includes LONG_PKT because they essentially + * imply the same thing, and are set or not set together + * for this chip + */ +#define AR5210_TXD_CTRL_A_HDR_LEN(_val) (((_val) ) & 0x0003f) +#define AR5210_TXD_CTRL_A_TX_RATE(_val) (((_val) << 6) & 0x003c0) +#define AR5210_TXD_CTRL_A_RTS_ENABLE ( 0x00c00) +#define AR5210_TXD_CTRL_A_CLEAR_DEST_MASK(_val) (((_val) << 12) & 0x01000) +#define AR5210_TXD_CTRL_A_ANT_MODE(_val) (((_val) << 13) & 0x02000) +#define AR5210_TXD_CTRL_A_PKT_TYPE(_val) (((_val) << 14) & 0x1c000) +#define AR5210_TXD_CTRL_A_INT_REQ ( 0x20000) +#define AR5210_TXD_CTRL_A_KEY_VALID ( 0x40000) +#define AR5210_TXD_CTRL_B_KEY_ID(_val) (((_val) ) & 0x0003f) +#define AR5210_TXD_CTRL_B_RTS_DURATION(_val) (((_val) << 6) & 0x7ffc0) +#endif + +#define INIT_CONFIG_STATUS 0x00000000 +#define INIT_ACKTOPS 0x00000008 +#define INIT_BCON_CNTRL_REG 0x00000000 +#define INIT_SLOT_TIME 0x00000168 +#define INIT_SLOT_TIME_TURBO 0x000001e0 /* More aggressive turbo slot timing = 6 us */ +#define INIT_ACK_CTS_TIMEOUT 0x04000400 +#define INIT_ACK_CTS_TIMEOUT_TURBO 0x08000800 + +#define INIT_USEC 0x27 +#define INIT_USEC_TURBO 0x4f +#define INIT_USEC_32 0x1f +#define INIT_TX_LATENCY 0x36 +#define INIT_RX_LATENCY 0x1D +#define INIT_TRANSMIT_LATENCY \ + ((INIT_RX_LATENCY << AR_USEC_RX_LATENCY_S) | \ + (INIT_TX_LATENCY << AR_USEC_TX_LATENCY_S) | \ + (INIT_USEC_32 << 7) | INIT_USEC ) +#define INIT_TRANSMIT_LATENCY_TURBO \ + ((INIT_RX_LATENCY << AR_USEC_RX_LATENCY_S) | \ + (INIT_TX_LATENCY << AR_USEC_TX_LATENCY_S) | \ + (INIT_USEC_32 << 7) | INIT_USEC_TURBO) + +#define INIT_SIFS 0x230 /* = 16 us - 2 us */ +#define INIT_SIFS_TURBO 0x1E0 /* More aggressive turbo SIFS timing - 8 us - 2 us */ + +/* + * Various fifo fill before Tx start, in 64-byte units + * i.e. put the frame in the air while still DMAing + */ +#define MIN_TX_FIFO_THRESHOLD 0x1 +#define MAX_TX_FIFO_THRESHOLD ((IEEE80211_MAX_LEN / 64) + 1) + +#define INIT_NEXT_CFP_START 0xffffffff + +#define INIT_BEACON_PERIOD 0xffff +#define INIT_BEACON_EN 0 /* this should be set by AP only when it's ready */ +#define INIT_BEACON_CONTROL \ + ((INIT_RESET_TSF << 24) | (INIT_BEACON_EN << 23) | \ + (INIT_TIM_OFFSET<<16) | INIT_BEACON_PERIOD) + +#define INIT_RSSI_THR 0x00000700 /* Missed beacon counter initialized to max value of 7 */ +#define INIT_ProgIFS 0x398 /* PIFS - 2us */ +#define INIT_ProgIFS_TURBO 0x3C0 +#define INIT_EIFS 0xd70 +#define INIT_EIFS_TURBO 0x1ae0 +#define INIT_CARR_SENSE_EN 1 +#define INIT_PROTO_TIME_CNTRL ( (INIT_CARR_SENSE_EN << 26) | (INIT_EIFS << 12) | \ + (INIT_ProgIFS) ) +#define INIT_PROTO_TIME_CNTRL_TURBO ( (INIT_CARR_SENSE_EN << 26) | (INIT_EIFS_TURBO << 12) | \ + (INIT_ProgIFS_TURBO) ) + +#define AR5210_MAX_RATE_POWER 60 + +#undef HAL_NUM_TX_QUEUES /* from ah.h */ +#define HAL_NUM_TX_QUEUES 3 + +struct ath_hal_5210 { + struct ath_hal_private ah_priv; /* base definitions */ + + uint8_t ah_macaddr[IEEE80211_ADDR_LEN]; + /* + * Runtime state. + */ + uint32_t ah_maskReg; /* shadow of IMR+IER regs */ + uint32_t ah_txOkInterruptMask; + uint32_t ah_txErrInterruptMask; + uint32_t ah_txDescInterruptMask; + uint32_t ah_txEolInterruptMask; + uint32_t ah_txUrnInterruptMask; + HAL_POWER_MODE ah_powerMode; + uint8_t ah_bssid[IEEE80211_ADDR_LEN]; + HAL_TX_QUEUE_INFO ah_txq[HAL_NUM_TX_QUEUES]; /* beacon+cab+data */ + /* + * Station mode support. + */ + uint32_t ah_staId1Defaults; /* STA_ID1 default settings */ + uint32_t ah_rssiThr; /* RSSI_THR settings */ + + u_int ah_sifstime; /* user-specified sifs time */ + u_int ah_slottime; /* user-specified slot time */ + u_int ah_acktimeout; /* user-specified ack timeout */ + u_int ah_ctstimeout; /* user-specified cts timeout */ +}; +#define AH5210(ah) ((struct ath_hal_5210 *)(ah)) + +struct ath_hal; + +extern void ar5210Detach(struct ath_hal *ah); +extern HAL_BOOL ar5210Reset(struct ath_hal *, HAL_OPMODE, + HAL_CHANNEL *, HAL_BOOL bChannelChange, HAL_STATUS *); +extern void ar5210SetPCUConfig(struct ath_hal *); +extern HAL_BOOL ar5210PhyDisable(struct ath_hal *); +extern HAL_BOOL ar5210Disable(struct ath_hal *); +extern HAL_BOOL ar5210ChipReset(struct ath_hal *, HAL_CHANNEL *); +extern HAL_BOOL ar5210PerCalibration(struct ath_hal *, HAL_CHANNEL *, HAL_BOOL *); +extern HAL_BOOL ar5210PerCalibrationN(struct ath_hal *ah, HAL_CHANNEL *chan, + u_int chainMask, HAL_BOOL longCal, HAL_BOOL *isCalDone); +extern HAL_BOOL ar5210ResetCalValid(struct ath_hal *ah, HAL_CHANNEL *chan); +extern int16_t ar5210GetNoiseFloor(struct ath_hal *); +extern int16_t ar5210GetNfAdjust(struct ath_hal *, + const HAL_CHANNEL_INTERNAL *); +extern HAL_BOOL ar5210SetTxPowerLimit(struct ath_hal *, uint32_t limit); +extern HAL_BOOL ar5210SetTransmitPower(struct ath_hal *, HAL_CHANNEL *); +extern HAL_BOOL ar5210CalNoiseFloor(struct ath_hal *, HAL_CHANNEL_INTERNAL *); +extern HAL_BOOL ar5210ResetDma(struct ath_hal *, HAL_OPMODE); + +extern HAL_BOOL ar5210SetTxQueueProps(struct ath_hal *ah, int q, + const HAL_TXQ_INFO *qInfo); +extern HAL_BOOL ar5210GetTxQueueProps(struct ath_hal *ah, int q, + HAL_TXQ_INFO *qInfo); +extern int ar5210SetupTxQueue(struct ath_hal *ah, HAL_TX_QUEUE type, + const HAL_TXQ_INFO *qInfo); +extern HAL_BOOL ar5210ReleaseTxQueue(struct ath_hal *ah, u_int q); +extern HAL_BOOL ar5210ResetTxQueue(struct ath_hal *ah, u_int q); +extern uint32_t ar5210GetTxDP(struct ath_hal *, u_int); +extern HAL_BOOL ar5210SetTxDP(struct ath_hal *, u_int, uint32_t txdp); +extern HAL_BOOL ar5210UpdateTxTrigLevel(struct ath_hal *, HAL_BOOL); +extern uint32_t ar5210NumTxPending(struct ath_hal *, u_int); +extern HAL_BOOL ar5210StartTxDma(struct ath_hal *, u_int); +extern HAL_BOOL ar5210StopTxDma(struct ath_hal *, u_int); +extern HAL_BOOL ar5210SetupTxDesc(struct ath_hal *, struct ath_desc *, + u_int pktLen, u_int hdrLen, HAL_PKT_TYPE type, u_int txPower, + u_int txRate0, u_int txRetries0, + u_int keyIx, u_int antMode, u_int flags, + u_int rtsctsRate, u_int rtsctsDuration, + u_int compicvLen, u_int compivLen, u_int comp); +extern HAL_BOOL ar5210SetupXTxDesc(struct ath_hal *, struct ath_desc *, + u_int txRate1, u_int txRetries1, + u_int txRate2, u_int txRetries2, + u_int txRate3, u_int txRetries3); +extern HAL_BOOL ar5210FillTxDesc(struct ath_hal *, struct ath_desc *, + u_int segLen, HAL_BOOL firstSeg, HAL_BOOL lastSeg, + const struct ath_desc *ds0); +extern HAL_STATUS ar5210ProcTxDesc(struct ath_hal *, + struct ath_desc *, struct ath_tx_status *); +extern void ar5210GetTxIntrQueue(struct ath_hal *ah, uint32_t *); +extern void ar5210IntrReqTxDesc(struct ath_hal *ah, struct ath_desc *); + +extern uint32_t ar5210GetRxDP(struct ath_hal *); +extern void ar5210SetRxDP(struct ath_hal *, uint32_t rxdp); +extern void ar5210EnableReceive(struct ath_hal *); +extern HAL_BOOL ar5210StopDmaReceive(struct ath_hal *); +extern void ar5210StartPcuReceive(struct ath_hal *); +extern void ar5210StopPcuReceive(struct ath_hal *); +extern void ar5210SetMulticastFilter(struct ath_hal *, + uint32_t filter0, uint32_t filter1); +extern HAL_BOOL ar5210ClrMulticastFilterIndex(struct ath_hal *, uint32_t); +extern HAL_BOOL ar5210SetMulticastFilterIndex(struct ath_hal *, uint32_t); +extern uint32_t ar5210GetRxFilter(struct ath_hal *); +extern void ar5210SetRxFilter(struct ath_hal *, uint32_t); +extern HAL_BOOL ar5210SetupRxDesc(struct ath_hal *, struct ath_desc *, + uint32_t, u_int flags); +extern HAL_STATUS ar5210ProcRxDesc(struct ath_hal *, struct ath_desc *, + uint32_t, struct ath_desc *, uint64_t, + struct ath_rx_status *); + +extern void ar5210GetMacAddress(struct ath_hal *, uint8_t *); +extern HAL_BOOL ar5210SetMacAddress(struct ath_hal *ah, const uint8_t *); +extern void ar5210GetBssIdMask(struct ath_hal *, uint8_t *); +extern HAL_BOOL ar5210SetBssIdMask(struct ath_hal *, const uint8_t *); +extern HAL_BOOL ar5210EepromRead(struct ath_hal *, u_int off, uint16_t *data); +extern HAL_BOOL ar5210EepromWrite(struct ath_hal *, u_int off, uint16_t data); +extern HAL_BOOL ar5210SetRegulatoryDomain(struct ath_hal *, + uint16_t, HAL_STATUS *); +extern u_int ar5210GetWirelessModes(struct ath_hal *ah); +extern void ar5210EnableRfKill(struct ath_hal *); +extern HAL_BOOL ar5210GpioCfgInput(struct ath_hal *, uint32_t gpio); +extern HAL_BOOL ar5210GpioCfgOutput(struct ath_hal *, uint32_t gpio); +extern uint32_t ar5210GpioGet(struct ath_hal *, uint32_t gpio); +extern HAL_BOOL ar5210GpioSet(struct ath_hal *, uint32_t gpio, uint32_t); +extern void ar5210Gpio0SetIntr(struct ath_hal *, u_int, uint32_t ilevel); +extern void ar5210SetLedState(struct ath_hal *, HAL_LED_STATE); +extern u_int ar5210GetDefAntenna(struct ath_hal *); +extern void ar5210SetDefAntenna(struct ath_hal *, u_int); +extern HAL_ANT_SETTING ar5210GetAntennaSwitch(struct ath_hal *); +extern HAL_BOOL ar5210SetAntennaSwitch(struct ath_hal *, HAL_ANT_SETTING); +extern void ar5210WriteAssocid(struct ath_hal *, + const uint8_t *bssid, uint16_t assocId); +extern uint32_t ar5210GetTsf32(struct ath_hal *); +extern uint64_t ar5210GetTsf64(struct ath_hal *); +extern void ar5210ResetTsf(struct ath_hal *); +extern uint32_t ar5210GetRandomSeed(struct ath_hal *); +extern HAL_BOOL ar5210DetectCardPresent(struct ath_hal *); +extern void ar5210UpdateMibCounters(struct ath_hal *, HAL_MIB_STATS *); +extern void ar5210EnableHwEncryption(struct ath_hal *); +extern void ar5210DisableHwEncryption(struct ath_hal *); +extern HAL_RFGAIN ar5210GetRfgain(struct ath_hal *); +extern HAL_BOOL ar5210SetSifsTime(struct ath_hal *, u_int); +extern u_int ar5210GetSifsTime(struct ath_hal *); +extern HAL_BOOL ar5210SetSlotTime(struct ath_hal *, u_int); +extern u_int ar5210GetSlotTime(struct ath_hal *); +extern HAL_BOOL ar5210SetAckTimeout(struct ath_hal *, u_int); +extern u_int ar5210GetAckTimeout(struct ath_hal *); +extern HAL_BOOL ar5210SetAckCTSRate(struct ath_hal *, u_int); +extern u_int ar5210GetAckCTSRate(struct ath_hal *); +extern HAL_BOOL ar5210SetCTSTimeout(struct ath_hal *, u_int); +extern u_int ar5210GetCTSTimeout(struct ath_hal *); +extern HAL_BOOL ar5210SetDecompMask(struct ath_hal *, uint16_t, int); +void ar5210SetCoverageClass(struct ath_hal *, uint8_t, int); +extern HAL_STATUS ar5210GetCapability(struct ath_hal *, HAL_CAPABILITY_TYPE, + uint32_t, uint32_t *); +extern HAL_BOOL ar5210SetCapability(struct ath_hal *, HAL_CAPABILITY_TYPE, + uint32_t, uint32_t, HAL_STATUS *); +extern HAL_BOOL ar5210GetDiagState(struct ath_hal *ah, int request, + const void *args, uint32_t argsize, + void **result, uint32_t *resultsize); + +extern u_int ar5210GetKeyCacheSize(struct ath_hal *); +extern HAL_BOOL ar5210IsKeyCacheEntryValid(struct ath_hal *, uint16_t); +extern HAL_BOOL ar5210ResetKeyCacheEntry(struct ath_hal *, uint16_t entry); +extern HAL_BOOL ar5210SetKeyCacheEntry(struct ath_hal *, uint16_t entry, + const HAL_KEYVAL *, const uint8_t *mac, int xorKey); +extern HAL_BOOL ar5210SetKeyCacheEntryMac(struct ath_hal *, + uint16_t, const uint8_t *); + +extern HAL_BOOL ar5210SetPowerMode(struct ath_hal *, uint32_t powerRequest, + int setChip); +extern HAL_POWER_MODE ar5210GetPowerMode(struct ath_hal *); + +extern void ar5210SetBeaconTimers(struct ath_hal *, + const HAL_BEACON_TIMERS *); +extern void ar5210BeaconInit(struct ath_hal *, uint32_t, uint32_t); +extern void ar5210SetStaBeaconTimers(struct ath_hal *, + const HAL_BEACON_STATE *); +extern void ar5210ResetStaBeaconTimers(struct ath_hal *); + +extern HAL_BOOL ar5210IsInterruptPending(struct ath_hal *); +extern HAL_BOOL ar5210GetPendingInterrupts(struct ath_hal *, HAL_INT *); +extern HAL_INT ar5210GetInterrupts(struct ath_hal *); +extern HAL_INT ar5210SetInterrupts(struct ath_hal *, HAL_INT ints); + +extern const HAL_RATE_TABLE *ar5210GetRateTable(struct ath_hal *, u_int mode); + +extern HAL_BOOL ar5210AniControl(struct ath_hal *, HAL_ANI_CMD, int ); +extern void ar5210AniPoll(struct ath_hal *, const HAL_NODE_STATS *, HAL_CHANNEL *); +extern void ar5210MibEvent(struct ath_hal *, const HAL_NODE_STATS *); +#endif /* _ATH_AR5210_H_ */ --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5210/ar5210_attach.c 2009-03-23 17:36:55.000000000 +0000 @@ -0,0 +1,383 @@ +/* + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2004 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ar5210_attach.c,v 1.1 2009/03/23 17:14:47 sborrill Exp $ + */ +#include "opt_ah.h" + +#include "ah.h" +#include "ah_internal.h" +#include "ah_devid.h" + +#include "ar5210/ar5210.h" +#include "ar5210/ar5210reg.h" +#include "ar5210/ar5210phy.h" + +#include "ah_eeprom_v1.h" + +static HAL_BOOL ar5210GetChannelEdges(struct ath_hal *, + uint16_t flags, uint16_t *low, uint16_t *high); +static HAL_BOOL ar5210GetChipPowerLimits(struct ath_hal *ah, + HAL_CHANNEL *chans, uint32_t nchans); + +static const struct ath_hal_private ar5210hal = {{ + .ah_magic = AR5210_MAGIC, + .ah_abi = HAL_ABI_VERSION, + .ah_countryCode = CTRY_DEFAULT, + + .ah_getRateTable = ar5210GetRateTable, + .ah_detach = ar5210Detach, + + /* Reset Functions */ + .ah_reset = ar5210Reset, + .ah_phyDisable = ar5210PhyDisable, + .ah_disable = ar5210Disable, + .ah_setPCUConfig = ar5210SetPCUConfig, + .ah_perCalibration = ar5210PerCalibration, + .ah_perCalibrationN = ar5210PerCalibrationN, + .ah_resetCalValid = ar5210ResetCalValid, + .ah_setTxPowerLimit = ar5210SetTxPowerLimit, + .ah_getChanNoise = ath_hal_getChanNoise, + + /* Transmit functions */ + .ah_updateTxTrigLevel = ar5210UpdateTxTrigLevel, + .ah_setupTxQueue = ar5210SetupTxQueue, + .ah_setTxQueueProps = ar5210SetTxQueueProps, + .ah_getTxQueueProps = ar5210GetTxQueueProps, + .ah_releaseTxQueue = ar5210ReleaseTxQueue, + .ah_resetTxQueue = ar5210ResetTxQueue, + .ah_getTxDP = ar5210GetTxDP, + .ah_setTxDP = ar5210SetTxDP, + .ah_numTxPending = ar5210NumTxPending, + .ah_startTxDma = ar5210StartTxDma, + .ah_stopTxDma = ar5210StopTxDma, + .ah_setupTxDesc = ar5210SetupTxDesc, + .ah_setupXTxDesc = ar5210SetupXTxDesc, + .ah_fillTxDesc = ar5210FillTxDesc, + .ah_procTxDesc = ar5210ProcTxDesc, + .ah_getTxIntrQueue = ar5210GetTxIntrQueue, + .ah_reqTxIntrDesc = ar5210IntrReqTxDesc, + + /* RX Functions */ + .ah_getRxDP = ar5210GetRxDP, + .ah_setRxDP = ar5210SetRxDP, + .ah_enableReceive = ar5210EnableReceive, + .ah_stopDmaReceive = ar5210StopDmaReceive, + .ah_startPcuReceive = ar5210StartPcuReceive, + .ah_stopPcuReceive = ar5210StopPcuReceive, + .ah_setMulticastFilter = ar5210SetMulticastFilter, + .ah_setMulticastFilterIndex = ar5210SetMulticastFilterIndex, + .ah_clrMulticastFilterIndex = ar5210ClrMulticastFilterIndex, + .ah_getRxFilter = ar5210GetRxFilter, + .ah_setRxFilter = ar5210SetRxFilter, + .ah_setupRxDesc = ar5210SetupRxDesc, + .ah_procRxDesc = ar5210ProcRxDesc, + .ah_rxMonitor = ar5210AniPoll, + .ah_procMibEvent = ar5210MibEvent, + + /* Misc Functions */ + .ah_getCapability = ar5210GetCapability, + .ah_setCapability = ar5210SetCapability, + .ah_getDiagState = ar5210GetDiagState, + .ah_getMacAddress = ar5210GetMacAddress, + .ah_setMacAddress = ar5210SetMacAddress, + .ah_getBssIdMask = ar5210GetBssIdMask, + .ah_setBssIdMask = ar5210SetBssIdMask, + .ah_setRegulatoryDomain = ar5210SetRegulatoryDomain, + .ah_setLedState = ar5210SetLedState, + .ah_writeAssocid = ar5210WriteAssocid, + .ah_gpioCfgInput = ar5210GpioCfgInput, + .ah_gpioCfgOutput = ar5210GpioCfgOutput, + .ah_gpioGet = ar5210GpioGet, + .ah_gpioSet = ar5210GpioSet, + .ah_gpioSetIntr = ar5210Gpio0SetIntr, + .ah_getTsf32 = ar5210GetTsf32, + .ah_getTsf64 = ar5210GetTsf64, + .ah_resetTsf = ar5210ResetTsf, + .ah_detectCardPresent = ar5210DetectCardPresent, + .ah_updateMibCounters = ar5210UpdateMibCounters, + .ah_getRfGain = ar5210GetRfgain, + .ah_getDefAntenna = ar5210GetDefAntenna, + .ah_setDefAntenna = ar5210SetDefAntenna, + .ah_getAntennaSwitch = ar5210GetAntennaSwitch, + .ah_setAntennaSwitch = ar5210SetAntennaSwitch, + .ah_setSifsTime = ar5210SetSifsTime, + .ah_getSifsTime = ar5210GetSifsTime, + .ah_setSlotTime = ar5210SetSlotTime, + .ah_getSlotTime = ar5210GetSlotTime, + .ah_setAckTimeout = ar5210SetAckTimeout, + .ah_getAckTimeout = ar5210GetAckTimeout, + .ah_setAckCTSRate = ar5210SetAckCTSRate, + .ah_getAckCTSRate = ar5210GetAckCTSRate, + .ah_setCTSTimeout = ar5210SetCTSTimeout, + .ah_getCTSTimeout = ar5210GetCTSTimeout, + .ah_setDecompMask = ar5210SetDecompMask, + .ah_setCoverageClass = ar5210SetCoverageClass, + + /* Key Cache Functions */ + .ah_getKeyCacheSize = ar5210GetKeyCacheSize, + .ah_resetKeyCacheEntry = ar5210ResetKeyCacheEntry, + .ah_isKeyCacheEntryValid = ar5210IsKeyCacheEntryValid, + .ah_setKeyCacheEntry = ar5210SetKeyCacheEntry, + .ah_setKeyCacheEntryMac = ar5210SetKeyCacheEntryMac, + + /* Power Management Functions */ + .ah_setPowerMode = ar5210SetPowerMode, + .ah_getPowerMode = ar5210GetPowerMode, + + /* Beacon Functions */ + .ah_setBeaconTimers = ar5210SetBeaconTimers, + .ah_beaconInit = ar5210BeaconInit, + .ah_setStationBeaconTimers = ar5210SetStaBeaconTimers, + .ah_resetStationBeaconTimers = ar5210ResetStaBeaconTimers, + + /* Interrupt Functions */ + .ah_isInterruptPending = ar5210IsInterruptPending, + .ah_getPendingInterrupts = ar5210GetPendingInterrupts, + .ah_getInterrupts = ar5210GetInterrupts, + .ah_setInterrupts = ar5210SetInterrupts }, + + .ah_getChannelEdges = ar5210GetChannelEdges, + .ah_getWirelessModes = ar5210GetWirelessModes, + .ah_eepromRead = ar5210EepromRead, +#ifdef AH_SUPPORT_WRITE_EEPROM + .ah_eepromWrite = ar5210EepromWrite, +#endif + .ah_gpioCfgInput = ar5210GpioCfgInput, + .ah_gpioCfgOutput = ar5210GpioCfgOutput, + .ah_gpioGet = ar5210GpioGet, + .ah_gpioSet = ar5210GpioSet, + .ah_gpioSetIntr = ar5210Gpio0SetIntr, + .ah_getChipPowerLimits = ar5210GetChipPowerLimits, +}; + +static HAL_BOOL ar5210FillCapabilityInfo(struct ath_hal *ah); + +/* + * Attach for an AR5210 part. + */ +static struct ath_hal * +ar5210Attach(uint16_t devid, HAL_SOFTC sc, HAL_BUS_TAG st, HAL_BUS_HANDLE sh, + HAL_STATUS *status) +{ +#define N(a) (sizeof(a)/sizeof(a[0])) + struct ath_hal_5210 *ahp; + struct ath_hal *ah; + uint32_t revid, pcicfg; + uint16_t eeval; + HAL_STATUS ecode; + int i; + + HALDEBUG(AH_NULL, HAL_DEBUG_ATTACH, + "%s: devid 0x%x sc %p st %p sh %p\n", __func__, devid, + sc, (void*) st, (void*) sh); + + /* NB: memory is returned zero'd */ + ahp = ath_hal_malloc(sizeof (struct ath_hal_5210)); + if (ahp == AH_NULL) { + HALDEBUG(AH_NULL, HAL_DEBUG_ANY, + "%s: no memory for state block\n", __func__); + ecode = HAL_ENOMEM; + goto bad; + } + ah = &ahp->ah_priv.h; + /* set initial values */ + OS_MEMCPY(&ahp->ah_priv, &ar5210hal, sizeof(struct ath_hal_private)); + ah->ah_sc = sc; + ah->ah_st = st; + ah->ah_sh = sh; + + ah->ah_devid = devid; /* NB: for AH_DEBUG_ALQ */ + AH_PRIVATE(ah)->ah_devid = devid; + AH_PRIVATE(ah)->ah_subvendorid = 0; /* XXX */ + + AH_PRIVATE(ah)->ah_powerLimit = AR5210_MAX_RATE_POWER; + AH_PRIVATE(ah)->ah_tpScale = HAL_TP_SCALE_MAX; /* no scaling */ + + ahp->ah_powerMode = HAL_PM_UNDEFINED; + ahp->ah_staId1Defaults = 0; + ahp->ah_rssiThr = INIT_RSSI_THR; + ahp->ah_sifstime = (u_int) -1; + ahp->ah_slottime = (u_int) -1; + ahp->ah_acktimeout = (u_int) -1; + ahp->ah_ctstimeout = (u_int) -1; + + if (!ar5210ChipReset(ah, AH_NULL)) { /* reset chip */ + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: chip reset failed\n", + __func__); + ecode = HAL_EIO; + goto bad; + } + + /* Read Revisions from Chips */ + AH_PRIVATE(ah)->ah_macVersion = 1; + AH_PRIVATE(ah)->ah_macRev = OS_REG_READ(ah, AR_SREV) & 0xff; + AH_PRIVATE(ah)->ah_phyRev = OS_REG_READ(ah, AR_PHY_CHIPID); + AH_PRIVATE(ah)->ah_analog2GhzRev = 0; + + /* Read Radio Chip Rev Extract */ + OS_REG_WRITE(ah, (AR_PHY_BASE + (0x34 << 2)), 0x00001c16); + for (i = 0; i < 4; i++) + OS_REG_WRITE(ah, (AR_PHY_BASE + (0x20 << 2)), 0x00010000); + revid = (OS_REG_READ(ah, AR_PHY_BASE + (256 << 2)) >> 28) & 0xf; + + /* Chip labelling is 1 greater than revision register for AR5110 */ + AH_PRIVATE(ah)->ah_analog5GhzRev = ath_hal_reverseBits(revid, 4) + 1; + + /* + * Read all the settings from the EEPROM and stash + * ones we'll use later. + */ + pcicfg = OS_REG_READ(ah, AR_PCICFG); + OS_REG_WRITE(ah, AR_PCICFG, pcicfg | AR_PCICFG_EEPROMSEL); + ecode = ath_hal_v1EepromAttach(ah); + if (ecode != HAL_OK) { + goto eebad; + } + ecode = ath_hal_eepromGet(ah, AR_EEP_REGDMN_0, &eeval); + if (ecode != HAL_OK) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: cannot read regulatory domain from EEPROM\n", + __func__); + goto eebad; + } + AH_PRIVATE(ah)->ah_currentRD = eeval; + ecode = ath_hal_eepromGet(ah, AR_EEP_MACADDR, ahp->ah_macaddr); + if (ecode != HAL_OK) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: error getting mac address from EEPROM\n", __func__); + goto eebad; + } + OS_REG_WRITE(ah, AR_PCICFG, pcicfg); /* disable EEPROM access */ + + AH_PRIVATE(ah)->ah_getNfAdjust = ar5210GetNfAdjust; + + /* + * Got everything we need now to setup the capabilities. + */ + (void) ar5210FillCapabilityInfo(ah); + + HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s: return\n", __func__); + + return ah; +eebad: + OS_REG_WRITE(ah, AR_PCICFG, pcicfg); /* disable EEPROM access */ +bad: + if (ahp) + ath_hal_free(ahp); + if (status) + *status = ecode; + return AH_NULL; +#undef N +} + +void +ar5210Detach(struct ath_hal *ah) +{ + HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s:\n", __func__); + + HALASSERT(ah != AH_NULL); + HALASSERT(ah->ah_magic == AR5210_MAGIC); + + ath_hal_eepromDetach(ah); + ath_hal_free(ah); +} + +/* + * Store the channel edges for the requested operational mode + */ +static HAL_BOOL +ar5210GetChannelEdges(struct ath_hal *ah, + uint16_t flags, uint16_t *low, uint16_t *high) +{ + if (flags & CHANNEL_5GHZ) { + *low = 5120; + *high = 5430; + return AH_TRUE; + } else { + return AH_FALSE; + } +} + +static HAL_BOOL +ar5210GetChipPowerLimits(struct ath_hal *ah, HAL_CHANNEL *chans, uint32_t nchans) +{ + HAL_CHANNEL *chan; + int i; + + /* XXX fill in, this is just a placeholder */ + for (i = 0; i < nchans; i++) { + chan = &chans[i]; + HALDEBUG(ah, HAL_DEBUG_ATTACH, + "%s: no min/max power for %u/0x%x\n", + __func__, chan->channel, chan->channelFlags); + chan->maxTxPower = AR5210_MAX_RATE_POWER; + chan->minTxPower = 0; + } + return AH_TRUE; +} + +/* + * Fill all software cached or static hardware state information. + */ +static HAL_BOOL +ar5210FillCapabilityInfo(struct ath_hal *ah) +{ + struct ath_hal_private *ahpriv = AH_PRIVATE(ah); + HAL_CAPABILITIES *pCap = &ahpriv->ah_caps; + + pCap->halWirelessModes |= HAL_MODE_11A; + + pCap->halLow5GhzChan = 5120; + pCap->halHigh5GhzChan = 5430; + + pCap->halSleepAfterBeaconBroken = AH_TRUE; + pCap->halPSPollBroken = AH_FALSE; + + pCap->halTotalQueues = HAL_NUM_TX_QUEUES; + pCap->halKeyCacheSize = 64; + + /* XXX not needed */ + pCap->halChanHalfRate = AH_FALSE; + pCap->halChanQuarterRate = AH_FALSE; + + if (ath_hal_eepromGetFlag(ah, AR_EEP_RFKILL)) { + /* + * Setup initial rfsilent settings based on the EEPROM + * contents. Pin 0, polarity 0 is fixed; record this + * using the EEPROM format found in later parts. + */ + ahpriv->ah_rfsilent = SM(0, AR_EEPROM_RFSILENT_GPIO_SEL) + | SM(0, AR_EEPROM_RFSILENT_POLARITY); + ahpriv->ah_rfkillEnabled = AH_TRUE; + pCap->halRfSilentSupport = AH_TRUE; + } + + pCap->halTstampPrecision = 15; /* NB: s/w extended from 13 */ + + ahpriv->ah_rxornIsFatal = AH_TRUE; + return AH_TRUE; +} + +static const char* +ar5210Probe(uint16_t vendorid, uint16_t devid) +{ + if (vendorid == ATHEROS_VENDOR_ID && + (devid == AR5210_PROD || devid == AR5210_DEFAULT)) + return "Atheros 5210"; + return AH_NULL; +} +AH_CHIP(AR5210, ar5210Probe, ar5210Attach); --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5210/ar5210_beacon.c 2009-03-23 17:36:55.000000000 +0000 @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2004 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ar5210_beacon.c,v 1.1 2009/03/23 17:14:47 sborrill Exp $ + */ +#include "opt_ah.h" + +#include "ah.h" +#include "ah_internal.h" +#include "ah_desc.h" + +#include "ar5210/ar5210.h" +#include "ar5210/ar5210reg.h" +#include "ar5210/ar5210desc.h" + +/* + * Initialize all of the hardware registers used to send beacons. + */ +void +ar5210SetBeaconTimers(struct ath_hal *ah, const HAL_BEACON_TIMERS *bt) +{ + + OS_REG_WRITE(ah, AR_TIMER0, bt->bt_nexttbtt); + OS_REG_WRITE(ah, AR_TIMER1, bt->bt_nextdba); + OS_REG_WRITE(ah, AR_TIMER2, bt->bt_nextswba); + OS_REG_WRITE(ah, AR_TIMER3, bt->bt_nextatim); + /* + * Set the Beacon register after setting all timers. + */ + OS_REG_WRITE(ah, AR_BEACON, bt->bt_intval); +} + +/* + * Legacy api to Initialize all of the beacon registers. + */ +void +ar5210BeaconInit(struct ath_hal *ah, + uint32_t next_beacon, uint32_t beacon_period) +{ + HAL_BEACON_TIMERS bt; + + bt.bt_nexttbtt = next_beacon; + + if (AH_PRIVATE(ah)->ah_opmode != HAL_M_STA) { + bt.bt_nextdba = (next_beacon - + ath_hal_dma_beacon_response_time) << 3; /* 1/8 TU */ + bt.bt_nextswba = (next_beacon - + ath_hal_sw_beacon_response_time) << 3; /* 1/8 TU */ + /* + * The SWBA interrupt is not used for beacons in ad hoc mode + * as we don't yet support ATIMs. So since the beacon never + * changes, the beacon descriptor is set up once and read + * into a special HW buffer, from which it will be + * automagically retrieved at each DMA Beacon Alert (DBA). + */ + + /* Set the ATIM window */ + bt.bt_nextatim = next_beacon + 0; /* NB: no ATIMs */ + } else { + bt.bt_nextdba = ~0; + bt.bt_nextswba = ~0; + bt.bt_nextatim = 1; + } + bt.bt_intval = beacon_period & + (AR_BEACON_PERIOD | AR_BEACON_RESET_TSF | AR_BEACON_EN); + ar5210SetBeaconTimers(ah, &bt); +} + +void +ar5210ResetStaBeaconTimers(struct ath_hal *ah) +{ + uint32_t val; + + OS_REG_WRITE(ah, AR_TIMER0, 0); /* no beacons */ + val = OS_REG_READ(ah, AR_STA_ID1); + val |= AR_STA_ID1_NO_PSPOLL; /* XXX */ + /* tell the h/w that the associated AP is not PCF capable */ + OS_REG_WRITE(ah, AR_STA_ID1, + val & ~(AR_STA_ID1_DEFAULT_ANTENNA | AR_STA_ID1_PCF)); + OS_REG_WRITE(ah, AR_BEACON, AR_BEACON_PERIOD); +} + +/* + * Set all the beacon related bits on the h/w for stations + * i.e. initializes the corresponding h/w timers; + * also tells the h/w whether to anticipate PCF beacons + * + * dtim_count and cfp_count from the current beacon - their current + * values aren't necessarily maintained in the device struct + */ +void +ar5210SetStaBeaconTimers(struct ath_hal *ah, const HAL_BEACON_STATE *bs) +{ + struct ath_hal_5210 *ahp = AH5210(ah); + + HALDEBUG(ah, HAL_DEBUG_BEACON, "%s: setting beacon timers\n", __func__); + + HALASSERT(bs->bs_intval != 0); + /* if the AP will do PCF */ + if (bs->bs_cfpmaxduration != 0) { + /* tell the h/w that the associated AP is PCF capable */ + OS_REG_WRITE(ah, AR_STA_ID1, + (OS_REG_READ(ah, AR_STA_ID1) &~ AR_STA_ID1_DEFAULT_ANTENNA) + | AR_STA_ID1_PCF); + + /* set CFP_PERIOD(1.024ms) register */ + OS_REG_WRITE(ah, AR_CFP_PERIOD, bs->bs_cfpperiod); + + /* set CFP_DUR(1.024ms) register to max cfp duration */ + OS_REG_WRITE(ah, AR_CFP_DUR, bs->bs_cfpmaxduration); + + /* set TIMER2(128us) to anticipated time of next CFP */ + OS_REG_WRITE(ah, AR_TIMER2, bs->bs_cfpnext << 3); + } else { + /* tell the h/w that the associated AP is not PCF capable */ + OS_REG_WRITE(ah, AR_STA_ID1, + OS_REG_READ(ah, AR_STA_ID1) &~ (AR_STA_ID1_DEFAULT_ANTENNA | AR_STA_ID1_PCF)); + } + + /* + * Set TIMER0(1.024ms) to the anticipated time of the next beacon. + */ + OS_REG_WRITE(ah, AR_TIMER0, bs->bs_nexttbtt); + + /* + * Start the beacon timers by setting the BEACON register + * to the beacon interval; also write the tim offset which + * we should know by now. The code, in ar5211WriteAssocid, + * also sets the tim offset once the AID is known which can + * be left as such for now. + */ + OS_REG_WRITE(ah, AR_BEACON, + (OS_REG_READ(ah, AR_BEACON) &~ (AR_BEACON_PERIOD|AR_BEACON_TIM)) + | SM(bs->bs_intval, AR_BEACON_PERIOD) + | SM(bs->bs_timoffset ? bs->bs_timoffset + 4 : 0, AR_BEACON_TIM) + ); + + /* + * Configure the BMISS interrupt. Note that we + * assume the caller blocks interrupts while enabling + * the threshold. + */ + + /* + * Interrupt works only on Crete. + */ + if (AH_PRIVATE(ah)->ah_macRev < AR_SREV_CRETE) + return; + /* + * Counter is only 3-bits. + * Count of 0 with BMISS interrupt enabled will hang the system + * with too many interrupts + */ + if (AH_PRIVATE(ah)->ah_macRev >= AR_SREV_CRETE && + (bs->bs_bmissthreshold&7) == 0) { +#ifdef AH_DEBUG + ath_hal_printf(ah, "%s: invalid beacon miss threshold %u\n", + __func__, bs->bs_bmissthreshold); +#endif + return; + } +#define BMISS_MAX (AR_RSSI_THR_BM_THR >> AR_RSSI_THR_BM_THR_S) + /* + * Configure the BMISS interrupt. Note that we + * assume the caller blocks interrupts while enabling + * the threshold. + * + * NB: the beacon miss count field is only 3 bits which + * is much smaller than what's found on later parts; + * clamp overflow values as a safeguard. + */ + ahp->ah_rssiThr = (ahp->ah_rssiThr &~ AR_RSSI_THR_BM_THR) + | SM(bs->bs_bmissthreshold > BMISS_MAX ? + BMISS_MAX : bs->bs_bmissthreshold, + AR_RSSI_THR_BM_THR); + OS_REG_WRITE(ah, AR_RSSI_THR, ahp->ah_rssiThr); +#undef BMISS_MAX +} --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5210/ar5210_interrupts.c 2009-03-23 17:36:55.000000000 +0000 @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2004 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ar5210_interrupts.c,v 1.1 2009/03/23 17:14:47 sborrill Exp $ + */ +#include "opt_ah.h" + +#include "ah.h" +#include "ah_internal.h" + +#include "ar5210/ar5210.h" +#include "ar5210/ar5210reg.h" + +/* + * Return non-zero if an interrupt is pending. + */ +HAL_BOOL +ar5210IsInterruptPending(struct ath_hal *ah) +{ + return (OS_REG_READ(ah, AR_INTPEND) ? AH_TRUE : AH_FALSE); +} + +/* + * Read the Interrupt Status Register value and return + * an abstracted bitmask of the data found in the ISR. + * Note that reading the ISR clear pending interrupts. + */ +HAL_BOOL +ar5210GetPendingInterrupts(struct ath_hal *ah, HAL_INT *masked) +{ +#define AR_FATAL_INT \ + (AR_ISR_MCABT_INT | AR_ISR_SSERR_INT | AR_ISR_DPERR_INT | AR_ISR_RXORN_INT) + struct ath_hal_5210 *ahp = AH5210(ah); + uint32_t isr; + + isr = OS_REG_READ(ah, AR_ISR); + if (isr == 0xffffffff) { + *masked = 0; + return AH_FALSE; + } + + /* + * Mask interrupts that have no device-independent + * representation; these are added back below. We + * also masked with the abstracted IMR to insure no + * status bits leak through that weren't requested + * (e.g. RXNOFRM) and that might confuse the caller. + */ + *masked = (isr & HAL_INT_COMMON) & ahp->ah_maskReg; + + if (isr & AR_FATAL_INT) + *masked |= HAL_INT_FATAL; + if (isr & (AR_ISR_RXOK_INT | AR_ISR_RXERR_INT)) + *masked |= HAL_INT_RX; + if (isr & (AR_ISR_TXOK_INT | AR_ISR_TXDESC_INT | AR_ISR_TXERR_INT | AR_ISR_TXEOL_INT)) + *masked |= HAL_INT_TX; + + /* + * On fatal errors collect ISR state for debugging. + */ + if (*masked & HAL_INT_FATAL) { + AH_PRIVATE(ah)->ah_fatalState[0] = isr; + } + + return AH_TRUE; +#undef AR_FATAL_INT +} + +HAL_INT +ar5210GetInterrupts(struct ath_hal *ah) +{ + return AH5210(ah)->ah_maskReg; +} + +HAL_INT +ar5210SetInterrupts(struct ath_hal *ah, HAL_INT ints) +{ + struct ath_hal_5210 *ahp = AH5210(ah); + uint32_t omask = ahp->ah_maskReg; + uint32_t mask; + + HALDEBUG(ah, HAL_DEBUG_INTERRUPT, "%s: 0x%x => 0x%x\n", + __func__, omask, ints); + + /* + * Disable interrupts here before reading & modifying + * the mask so that the ISR does not modify the mask + * out from under us. + */ + if (omask & HAL_INT_GLOBAL) { + HALDEBUG(ah, HAL_DEBUG_INTERRUPT, "%s: disable IER\n", __func__); + OS_REG_WRITE(ah, AR_IER, AR_IER_DISABLE); + } + + mask = ints & HAL_INT_COMMON; + if (ints & HAL_INT_RX) + mask |= AR_IMR_RXOK_INT | AR_IMR_RXERR_INT; + if (ints & HAL_INT_TX) { + if (ahp->ah_txOkInterruptMask) + mask |= AR_IMR_TXOK_INT; + if (ahp->ah_txErrInterruptMask) + mask |= AR_IMR_TXERR_INT; + if (ahp->ah_txDescInterruptMask) + mask |= AR_IMR_TXDESC_INT; + if (ahp->ah_txEolInterruptMask) + mask |= AR_IMR_TXEOL_INT; + } + + /* Write the new IMR and store off our SW copy. */ + HALDEBUG(ah, HAL_DEBUG_INTERRUPT, "%s: new IMR 0x%x\n", __func__, mask); + OS_REG_WRITE(ah, AR_IMR, mask); + ahp->ah_maskReg = ints; + + /* Re-enable interrupts as appropriate. */ + if (ints & HAL_INT_GLOBAL) { + HALDEBUG(ah, HAL_DEBUG_INTERRUPT, "%s: enable IER\n", __func__); + OS_REG_WRITE(ah, AR_IER, AR_IER_ENABLE); + } + + return omask; +} --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5210/ar5210_keycache.c 2009-03-23 17:36:55.000000000 +0000 @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2004 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ar5210_keycache.c,v 1.1 2009/03/23 17:14:47 sborrill Exp $ + */ +#include "opt_ah.h" + +#include "ah.h" +#include "ah_internal.h" + +#include "ar5210/ar5210.h" +#include "ar5210/ar5210reg.h" + +#define AR_KEYTABLE_SIZE 64 +#define KEY_XOR 0xaa + +/* + * Return the size of the hardware key cache. + */ +u_int +ar5210GetKeyCacheSize(struct ath_hal *ah) +{ + return AR_KEYTABLE_SIZE; +} + +/* + * Return the size of the hardware key cache. + */ +HAL_BOOL +ar5210IsKeyCacheEntryValid(struct ath_hal *ah, uint16_t entry) +{ + if (entry < AR_KEYTABLE_SIZE) { + uint32_t val = OS_REG_READ(ah, AR_KEYTABLE_MAC1(entry)); + if (val & AR_KEYTABLE_VALID) + return AH_TRUE; + } + return AH_FALSE; +} + +/* + * Clear the specified key cache entry. + */ +HAL_BOOL +ar5210ResetKeyCacheEntry(struct ath_hal *ah, uint16_t entry) +{ + if (entry < AR_KEYTABLE_SIZE) { + OS_REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), 0); + OS_REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), 0); + OS_REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), 0); + OS_REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), 0); + OS_REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), 0); + OS_REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), 0); + OS_REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), 0); + OS_REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), 0); + return AH_TRUE; + } + return AH_FALSE; +} + +/* + * Sets the mac part of the specified key cache entry and mark it valid. + */ +HAL_BOOL +ar5210SetKeyCacheEntryMac(struct ath_hal *ah, uint16_t entry, const uint8_t *mac) +{ + uint32_t macHi, macLo; + + if (entry < AR_KEYTABLE_SIZE) { + /* + * Set MAC address -- shifted right by 1. MacLo is + * the 4 MSBs, and MacHi is the 2 LSBs. + */ + if (mac != AH_NULL) { + macHi = (mac[5] << 8) | mac[4]; + macLo = (mac[3] << 24)| (mac[2] << 16) + | (mac[1] << 8) | mac[0]; + macLo >>= 1; + macLo |= (macHi & 1) << 31; /* carry */ + macHi >>= 1; + } else { + macLo = macHi = 0; + } + + OS_REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), macLo); + OS_REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), + macHi | AR_KEYTABLE_VALID); + return AH_TRUE; + } + return AH_FALSE; +} + +/* + * Sets the contents of the specified key cache entry. + */ +HAL_BOOL +ar5210SetKeyCacheEntry(struct ath_hal *ah, uint16_t entry, + const HAL_KEYVAL *k, const uint8_t *mac, int xorKey) +{ + uint32_t key0, key1, key2, key3, key4; + uint32_t keyType; + uint32_t xorMask= xorKey ? + (KEY_XOR << 24 | KEY_XOR << 16 | KEY_XOR << 8 | KEY_XOR) : 0; + + if (entry >= AR_KEYTABLE_SIZE) + return AH_FALSE; + if (k->kv_type != HAL_CIPHER_WEP) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: cipher %u not supported\n", + __func__, k->kv_type); + return AH_FALSE; + } + + /* NB: only WEP supported */ + if (k->kv_len < 40 / NBBY) + return AH_FALSE; + if (k->kv_len <= 40 / NBBY) + keyType = AR_KEYTABLE_TYPE_40; + else if (k->kv_len <= 104 / NBBY) + keyType = AR_KEYTABLE_TYPE_104; + else + keyType = AR_KEYTABLE_TYPE_128; + + key0 = LE_READ_4(k->kv_val+0) ^ xorMask; + key1 = (LE_READ_2(k->kv_val+4) ^ xorMask) & 0xffff; + key2 = LE_READ_4(k->kv_val+6) ^ xorMask; + key3 = (LE_READ_2(k->kv_val+10) ^ xorMask) & 0xffff; + key4 = LE_READ_4(k->kv_val+12) ^ xorMask; + if (k->kv_len <= 104 / NBBY) + key4 &= 0xff; + + /* + * Note: WEP key cache hardware requires that each double-word + * pair be written in even/odd order (since the destination is + * a 64-bit register). Don't reorder these writes w/o + * understanding this! + */ + OS_REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0); + OS_REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1); + OS_REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2); + OS_REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3); + OS_REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4); + OS_REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType); + return ar5210SetKeyCacheEntryMac(ah, entry, mac); +} --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5210/ar5210_misc.c 2009-03-23 17:36:55.000000000 +0000 @@ -0,0 +1,642 @@ +/* + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2004 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ar5210_misc.c,v 1.1 2009/03/23 17:14:47 sborrill Exp $ + */ +#include "opt_ah.h" + +#include "ah.h" +#include "ah_internal.h" + +#include "ar5210/ar5210.h" +#include "ar5210/ar5210reg.h" +#include "ar5210/ar5210phy.h" + +#include "ah_eeprom_v1.h" + +#define AR_NUM_GPIO 6 /* 6 GPIO bits */ +#define AR_GPIOD_MASK 0x2f /* 6-bit mask */ + +void +ar5210GetMacAddress(struct ath_hal *ah, uint8_t *mac) +{ + struct ath_hal_5210 *ahp = AH5210(ah); + + OS_MEMCPY(mac, ahp->ah_macaddr, IEEE80211_ADDR_LEN); +} + +HAL_BOOL +ar5210SetMacAddress(struct ath_hal *ah, const uint8_t *mac) +{ + struct ath_hal_5210 *ahp = AH5210(ah); + + OS_MEMCPY(ahp->ah_macaddr, mac, IEEE80211_ADDR_LEN); + return AH_TRUE; +} + +void +ar5210GetBssIdMask(struct ath_hal *ah, uint8_t *mask) +{ + static const uint8_t ones[IEEE80211_ADDR_LEN] = + { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + OS_MEMCPY(mask, ones, IEEE80211_ADDR_LEN); +} + +HAL_BOOL +ar5210SetBssIdMask(struct ath_hal *ah, const uint8_t *mask) +{ + return AH_FALSE; +} + +/* + * Read 16 bits of data from the specified EEPROM offset. + */ +HAL_BOOL +ar5210EepromRead(struct ath_hal *ah, u_int off, uint16_t *data) +{ + (void) OS_REG_READ(ah, AR_EP_AIR(off)); /* activate read op */ + if (!ath_hal_wait(ah, AR_EP_STA, + AR_EP_STA_RDCMPLT | AR_EP_STA_RDERR, AR_EP_STA_RDCMPLT)) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: read failed for entry 0x%x\n", + __func__, AR_EP_AIR(off)); + return AH_FALSE; + } + *data = OS_REG_READ(ah, AR_EP_RDATA) & 0xffff; + return AH_TRUE; +} + +#ifdef AH_SUPPORT_WRITE_EEPROM +/* + * Write 16 bits of data to the specified EEPROM offset. + */ +HAL_BOOL +ar5210EepromWrite(struct ath_hal *ah, u_int off, uint16_t data) +{ + return AH_FALSE; +} +#endif /* AH_SUPPORT_WRITE_EEPROM */ + +/* + * Attempt to change the cards operating regulatory domain to the given value + */ +HAL_BOOL +ar5210SetRegulatoryDomain(struct ath_hal *ah, + uint16_t regDomain, HAL_STATUS *status) +{ + HAL_STATUS ecode; + + if (AH_PRIVATE(ah)->ah_currentRD == regDomain) { + ecode = HAL_EINVAL; + goto bad; + } + /* + * Check if EEPROM is configured to allow this; must + * be a proper version and the protection bits must + * permit re-writing that segment of the EEPROM. + */ + if (ath_hal_eepromGetFlag(ah, AR_EEP_WRITEPROTECT)) { + ecode = HAL_EEWRITE; + goto bad; + } + ecode = HAL_EIO; /* disallow all writes */ +bad: + if (status) + *status = ecode; + return AH_FALSE; +} + +/* + * Return the wireless modes (a,b,g,t) supported by hardware. + * + * This value is what is actually supported by the hardware + * and is unaffected by regulatory/country code settings. + * + */ +u_int +ar5210GetWirelessModes(struct ath_hal *ah) +{ + /* XXX could enable turbo mode but can't do all rates */ + return HAL_MODE_11A; +} + +/* + * Called if RfKill is supported (according to EEPROM). Set the interrupt and + * GPIO values so the ISR and can disable RF on a switch signal + */ +void +ar5210EnableRfKill(struct ath_hal *ah) +{ + uint16_t rfsilent = AH_PRIVATE(ah)->ah_rfsilent; + int select = MS(rfsilent, AR_EEPROM_RFSILENT_GPIO_SEL); + int polarity = MS(rfsilent, AR_EEPROM_RFSILENT_POLARITY); + + /* + * If radio disable switch connection to GPIO bit 0 is enabled + * program GPIO interrupt. + * If rfkill bit on eeprom is 1, setupeeprommap routine has already + * verified that it is a later version of eeprom, it has a place for + * rfkill bit and it is set to 1, indicating that GPIO bit 0 hardware + * connection is present. + */ + ar5210Gpio0SetIntr(ah, select, (ar5210GpioGet(ah, select) == polarity)); +} + +/* + * Configure GPIO Output lines + */ +HAL_BOOL +ar5210GpioCfgOutput(struct ath_hal *ah, uint32_t gpio) +{ + HALASSERT(gpio < AR_NUM_GPIO); + + OS_REG_WRITE(ah, AR_GPIOCR, + (OS_REG_READ(ah, AR_GPIOCR) &~ AR_GPIOCR_ALL(gpio)) + | AR_GPIOCR_OUT1(gpio)); + + return AH_TRUE; +} + +/* + * Configure GPIO Input lines + */ +HAL_BOOL +ar5210GpioCfgInput(struct ath_hal *ah, uint32_t gpio) +{ + HALASSERT(gpio < AR_NUM_GPIO); + + OS_REG_WRITE(ah, AR_GPIOCR, + (OS_REG_READ(ah, AR_GPIOCR) &~ AR_GPIOCR_ALL(gpio)) + | AR_GPIOCR_IN(gpio)); + + return AH_TRUE; +} + +/* + * Once configured for I/O - set output lines + */ +HAL_BOOL +ar5210GpioSet(struct ath_hal *ah, uint32_t gpio, uint32_t val) +{ + uint32_t reg; + + HALASSERT(gpio < AR_NUM_GPIO); + + reg = OS_REG_READ(ah, AR_GPIODO); + reg &= ~(1 << gpio); + reg |= (val&1) << gpio; + + OS_REG_WRITE(ah, AR_GPIODO, reg); + return AH_TRUE; +} + +/* + * Once configured for I/O - get input lines + */ +uint32_t +ar5210GpioGet(struct ath_hal *ah, uint32_t gpio) +{ + if (gpio < AR_NUM_GPIO) { + uint32_t val = OS_REG_READ(ah, AR_GPIODI); + val = ((val & AR_GPIOD_MASK) >> gpio) & 0x1; + return val; + } else { + return 0xffffffff; + } +} + +/* + * Set the GPIO 0 Interrupt + */ +void +ar5210Gpio0SetIntr(struct ath_hal *ah, u_int gpio, uint32_t ilevel) +{ + uint32_t val = OS_REG_READ(ah, AR_GPIOCR); + + /* Clear the bits that we will modify. */ + val &= ~(AR_GPIOCR_INT_SEL(gpio) | AR_GPIOCR_INT_SELH | AR_GPIOCR_INT_ENA | + AR_GPIOCR_ALL(gpio)); + + val |= AR_GPIOCR_INT_SEL(gpio) | AR_GPIOCR_INT_ENA; + if (ilevel) + val |= AR_GPIOCR_INT_SELH; + + /* Don't need to change anything for low level interrupt. */ + OS_REG_WRITE(ah, AR_GPIOCR, val); + + /* Change the interrupt mask. */ + ar5210SetInterrupts(ah, AH5210(ah)->ah_maskReg | HAL_INT_GPIO); +} + +/* + * Change the LED blinking pattern to correspond to the connectivity + */ +void +ar5210SetLedState(struct ath_hal *ah, HAL_LED_STATE state) +{ + uint32_t val; + + val = OS_REG_READ(ah, AR_PCICFG); + switch (state) { + case HAL_LED_INIT: + val &= ~(AR_PCICFG_LED_PEND | AR_PCICFG_LED_ACT); + break; + case HAL_LED_RUN: + /* normal blink when connected */ + val &= ~AR_PCICFG_LED_PEND; + val |= AR_PCICFG_LED_ACT; + break; + default: + val |= AR_PCICFG_LED_PEND; + val &= ~AR_PCICFG_LED_ACT; + break; + } + OS_REG_WRITE(ah, AR_PCICFG, val); +} + +/* + * Return 1 or 2 for the corresponding antenna that is in use + */ +u_int +ar5210GetDefAntenna(struct ath_hal *ah) +{ + uint32_t val = OS_REG_READ(ah, AR_STA_ID1); + return (val & AR_STA_ID1_DEFAULT_ANTENNA ? 2 : 1); +} + +void +ar5210SetDefAntenna(struct ath_hal *ah, u_int antenna) +{ + uint32_t val = OS_REG_READ(ah, AR_STA_ID1); + + if (antenna != (val & AR_STA_ID1_DEFAULT_ANTENNA ? 2 : 1)) { + /* + * Antenna change requested, force a toggle of the default. + */ + OS_REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_DEFAULT_ANTENNA); + } +} + +HAL_ANT_SETTING +ar5210GetAntennaSwitch(struct ath_hal *ah) +{ + return HAL_ANT_VARIABLE; +} + +HAL_BOOL +ar5210SetAntennaSwitch(struct ath_hal *ah, HAL_ANT_SETTING settings) +{ + /* XXX not sure how to fix antenna */ + return (settings == HAL_ANT_VARIABLE); +} + +/* + * Change association related fields programmed into the hardware. + * Writing a valid BSSID to the hardware effectively enables the hardware + * to synchronize its TSF to the correct beacons and receive frames coming + * from that BSSID. It is called by the SME JOIN operation. + */ +void +ar5210WriteAssocid(struct ath_hal *ah, const uint8_t *bssid, uint16_t assocId) +{ + struct ath_hal_5210 *ahp = AH5210(ah); + + /* XXX save bssid for possible re-use on reset */ + OS_MEMCPY(ahp->ah_bssid, bssid, IEEE80211_ADDR_LEN); + OS_REG_WRITE(ah, AR_BSS_ID0, LE_READ_4(ahp->ah_bssid)); + OS_REG_WRITE(ah, AR_BSS_ID1, LE_READ_2(ahp->ah_bssid+4) | + ((assocId & 0x3fff)<> 19) & 0x1ff; + if (nf & 0x100) + nf = 0 - ((nf ^ 0x1ff) + 1); + return (OS_REG_READ(ah, AR_TSF_U32) ^ + OS_REG_READ(ah, AR_TSF_L32) ^ nf); +} + +/* + * Detect if our card is present + */ +HAL_BOOL +ar5210DetectCardPresent(struct ath_hal *ah) +{ + /* + * Read the Silicon Revision register and compare that + * to what we read at attach time. If the same, we say + * a card/device is present. + */ + return (AH_PRIVATE(ah)->ah_macRev == (OS_REG_READ(ah, AR_SREV) & 0xff)); +} + +/* + * Update MIB Counters + */ +void +ar5210UpdateMibCounters(struct ath_hal *ah, HAL_MIB_STATS *stats) +{ + stats->ackrcv_bad += OS_REG_READ(ah, AR_ACK_FAIL); + stats->rts_bad += OS_REG_READ(ah, AR_RTS_FAIL); + stats->fcs_bad += OS_REG_READ(ah, AR_FCS_FAIL); + stats->rts_good += OS_REG_READ(ah, AR_RTS_OK); + stats->beacons += OS_REG_READ(ah, AR_BEACON_CNT); +} + +HAL_BOOL +ar5210SetSifsTime(struct ath_hal *ah, u_int us) +{ + struct ath_hal_5210 *ahp = AH5210(ah); + + if (us > ath_hal_mac_usec(ah, 0x7ff)) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad SIFS time %u\n", + __func__, us); + ahp->ah_sifstime = (u_int) -1; /* restore default handling */ + return AH_FALSE; + } else { + /* convert to system clocks */ + OS_REG_RMW_FIELD(ah, AR_IFS0, AR_IFS0_SIFS, + ath_hal_mac_clks(ah, us)); + ahp->ah_sifstime = us; + return AH_TRUE; + } +} + +u_int +ar5210GetSifsTime(struct ath_hal *ah) +{ + u_int clks = OS_REG_READ(ah, AR_IFS0) & 0x7ff; + return ath_hal_mac_usec(ah, clks); /* convert from system clocks */ +} + +HAL_BOOL +ar5210SetSlotTime(struct ath_hal *ah, u_int us) +{ + struct ath_hal_5210 *ahp = AH5210(ah); + + if (us < HAL_SLOT_TIME_9 || us > ath_hal_mac_usec(ah, 0xffff)) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad slot time %u\n", + __func__, us); + ahp->ah_slottime = (u_int) -1; /* restore default handling */ + return AH_FALSE; + } else { + /* convert to system clocks */ + OS_REG_WRITE(ah, AR_SLOT_TIME, ath_hal_mac_clks(ah, us)); + ahp->ah_slottime = us; + return AH_TRUE; + } +} + +u_int +ar5210GetSlotTime(struct ath_hal *ah) +{ + u_int clks = OS_REG_READ(ah, AR_SLOT_TIME) & 0xffff; + return ath_hal_mac_usec(ah, clks); /* convert from system clocks */ +} + +HAL_BOOL +ar5210SetAckTimeout(struct ath_hal *ah, u_int us) +{ + struct ath_hal_5210 *ahp = AH5210(ah); + + if (us > ath_hal_mac_usec(ah, MS(0xffffffff, AR_TIME_OUT_ACK))) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad ack timeout %u\n", + __func__, us); + ahp->ah_acktimeout = (u_int) -1; /* restore default handling */ + return AH_FALSE; + } else { + /* convert to system clocks */ + OS_REG_RMW_FIELD(ah, AR_TIME_OUT, + AR_TIME_OUT_ACK, ath_hal_mac_clks(ah, us)); + ahp->ah_acktimeout = us; + return AH_TRUE; + } +} + +u_int +ar5210GetAckTimeout(struct ath_hal *ah) +{ + u_int clks = MS(OS_REG_READ(ah, AR_TIME_OUT), AR_TIME_OUT_ACK); + return ath_hal_mac_usec(ah, clks); /* convert from system clocks */ +} + +u_int +ar5210GetAckCTSRate(struct ath_hal *ah) +{ + return ((AH5210(ah)->ah_staId1Defaults & AR_STA_ID1_ACKCTS_6MB) == 0); +} + +HAL_BOOL +ar5210SetAckCTSRate(struct ath_hal *ah, u_int high) +{ + struct ath_hal_5210 *ahp = AH5210(ah); + + if (high) { + OS_REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_ACKCTS_6MB); + ahp->ah_staId1Defaults &= ~AR_STA_ID1_ACKCTS_6MB; + } else { + OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_ACKCTS_6MB); + ahp->ah_staId1Defaults |= AR_STA_ID1_ACKCTS_6MB; + } + return AH_TRUE; +} + +HAL_BOOL +ar5210SetCTSTimeout(struct ath_hal *ah, u_int us) +{ + struct ath_hal_5210 *ahp = AH5210(ah); + + if (us > ath_hal_mac_usec(ah, MS(0xffffffff, AR_TIME_OUT_CTS))) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad cts timeout %u\n", + __func__, us); + ahp->ah_ctstimeout = (u_int) -1; /* restore default handling */ + return AH_FALSE; + } else { + /* convert to system clocks */ + OS_REG_RMW_FIELD(ah, AR_TIME_OUT, + AR_TIME_OUT_CTS, ath_hal_mac_clks(ah, us)); + ahp->ah_ctstimeout = us; + return AH_TRUE; + } +} + +u_int +ar5210GetCTSTimeout(struct ath_hal *ah) +{ + u_int clks = MS(OS_REG_READ(ah, AR_TIME_OUT), AR_TIME_OUT_CTS); + return ath_hal_mac_usec(ah, clks); /* convert from system clocks */ +} + +HAL_BOOL +ar5210SetDecompMask(struct ath_hal *ah, uint16_t keyidx, int en) +{ + /* nothing to do */ + return AH_TRUE; +} + +void +ar5210SetCoverageClass(struct ath_hal *ah, uint8_t coverageclass, int now) +{ +} + +/* + * Control Adaptive Noise Immunity Parameters + */ +HAL_BOOL +ar5210AniControl(struct ath_hal *ah, HAL_ANI_CMD cmd, int param) +{ + return AH_FALSE; +} + +void +ar5210AniPoll(struct ath_hal *ah, const HAL_NODE_STATS *stats, HAL_CHANNEL *chan) +{ +} + +void +ar5210MibEvent(struct ath_hal *ah, const HAL_NODE_STATS *stats) +{ +} + +#define AR_DIAG_SW_DIS_CRYPTO (AR_DIAG_SW_DIS_ENC | AR_DIAG_SW_DIS_DEC) + +HAL_STATUS +ar5210GetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, + uint32_t capability, uint32_t *result) +{ + + switch (type) { + case HAL_CAP_CIPHER: /* cipher handled in hardware */ + return (capability == HAL_CIPHER_WEP ? HAL_OK : HAL_ENOTSUPP); + default: + return ath_hal_getcapability(ah, type, capability, result); + } +} + +HAL_BOOL +ar5210SetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, + uint32_t capability, uint32_t setting, HAL_STATUS *status) +{ + + switch (type) { + case HAL_CAP_DIAG: /* hardware diagnostic support */ + /* + * NB: could split this up into virtual capabilities, + * (e.g. 1 => ACK, 2 => CTS, etc.) but it hardly + * seems worth the additional complexity. + */ +#ifdef AH_DEBUG + AH_PRIVATE(ah)->ah_diagreg = setting; +#else + AH_PRIVATE(ah)->ah_diagreg = setting & 0x6; /* ACK+CTS */ +#endif + OS_REG_WRITE(ah, AR_DIAG_SW, AH_PRIVATE(ah)->ah_diagreg); + return AH_TRUE; + case HAL_CAP_RXORN_FATAL: /* HAL_INT_RXORN treated as fatal */ + return AH_FALSE; /* NB: disallow */ + default: + return ath_hal_setcapability(ah, type, capability, + setting, status); + } +} + +HAL_BOOL +ar5210GetDiagState(struct ath_hal *ah, int request, + const void *args, uint32_t argsize, + void **result, uint32_t *resultsize) +{ +#ifdef AH_PRIVATE_DIAG + uint32_t pcicfg; + HAL_BOOL ok; + + switch (request) { + case HAL_DIAG_EEPROM: + /* XXX */ + break; + case HAL_DIAG_EEREAD: + if (argsize != sizeof(uint16_t)) + return AH_FALSE; + pcicfg = OS_REG_READ(ah, AR_PCICFG); + OS_REG_WRITE(ah, AR_PCICFG, pcicfg | AR_PCICFG_EEPROMSEL); + ok = ath_hal_eepromRead(ah, *(const uint16_t *)args, *result); + OS_REG_WRITE(ah, AR_PCICFG, pcicfg); + if (ok) + *resultsize = sizeof(uint16_t); + return ok; + } +#endif + return ath_hal_getdiagstate(ah, request, + args, argsize, result, resultsize); +} --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5210/ar5210_phy.c 2009-03-23 17:36:55.000000000 +0000 @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2004 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ar5210_phy.c,v 1.1 2009/03/23 17:14:47 sborrill Exp $ + */ +#include "opt_ah.h" + +#include "ah.h" +#include "ah_internal.h" + +#include "ar5210/ar5210.h" + +/* shorthands to compact tables for readability */ +#define OFDM IEEE80211_T_OFDM +#define TURBO IEEE80211_T_TURBO + +HAL_RATE_TABLE ar5210_11a_table = { + 8, /* number of rates */ + { 0 }, + { +/* short ctrl */ +/* valid rateCode Preamble dot11Rate Rate */ +/* 6 Mb */ { AH_TRUE, OFDM, 6000, 0x0b, 0x00, (0x80|12), 0, 0, 0 }, +/* 9 Mb */ { AH_TRUE, OFDM, 9000, 0x0f, 0x00, 18, 0, 0, 0 }, +/* 12 Mb */ { AH_TRUE, OFDM, 12000, 0x0a, 0x00, (0x80|24), 2, 0, 0 }, +/* 18 Mb */ { AH_TRUE, OFDM, 18000, 0x0e, 0x00, 36, 2, 0, 0 }, +/* 24 Mb */ { AH_TRUE, OFDM, 24000, 0x09, 0x00, (0x80|48), 4, 0, 0 }, +/* 36 Mb */ { AH_TRUE, OFDM, 36000, 0x0d, 0x00, 72, 4, 0, 0 }, +/* 48 Mb */ { AH_TRUE, OFDM, 48000, 0x08, 0x00, 96, 4, 0, 0 }, +/* 54 Mb */ { AH_TRUE, OFDM, 54000, 0x0c, 0x00, 108, 4, 0, 0 } + }, +}; + +HAL_RATE_TABLE ar5210_turbo_table = { + 8, /* number of rates */ + { 0 }, + { +/* short ctrl */ +/* valid rateCode Preamble dot11Rate Rate */ +/* 6 Mb */ { AH_TRUE, TURBO, 6000, 0x0b, 0x00, (0x80|12), 0, 0, 0 }, +/* 9 Mb */ { AH_TRUE, TURBO, 9000, 0x0f, 0x00, 18, 0, 0, 0 }, +/* 12 Mb */ { AH_TRUE, TURBO, 12000, 0x0a, 0x00, (0x80|24), 2, 0, 0 }, +/* 18 Mb */ { AH_TRUE, TURBO, 18000, 0x0e, 0x00, 36, 2, 0, 0 }, +/* 24 Mb */ { AH_TRUE, TURBO, 24000, 0x09, 0x00, (0x80|48), 4, 0, 0 }, +/* 36 Mb */ { AH_TRUE, TURBO, 36000, 0x0d, 0x00, 72, 4, 0, 0 }, +/* 48 Mb */ { AH_TRUE, TURBO, 48000, 0x08, 0x00, 96, 4, 0, 0 }, +/* 54 Mb */ { AH_TRUE, TURBO, 54000, 0x0c, 0x00, 108, 4, 0, 0 } + }, +}; + +#undef OFDM +#undef TURBO + +const HAL_RATE_TABLE * +ar5210GetRateTable(struct ath_hal *ah, u_int mode) +{ + HAL_RATE_TABLE *rt; + switch (mode) { + case HAL_MODE_11A: + rt = &ar5210_11a_table; + break; + case HAL_MODE_TURBO: + rt = &ar5210_turbo_table; + break; + default: + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid mode 0x%x\n", + __func__, mode); + return AH_NULL; + } + ath_hal_setupratetable(ah, rt); + return rt; +} --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5210/ar5210_power.c 2009-03-23 17:36:55.000000000 +0000 @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2004 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ar5210_power.c,v 1.1 2009/03/23 17:14:47 sborrill Exp $ + */ +#include "opt_ah.h" + +#include "ah.h" +#include "ah_internal.h" + +#include "ar5210/ar5210.h" +#include "ar5210/ar5210reg.h" + +/* + * Notify Power Mgt is disabled in self-generated frames. + * If requested, set Power Mode of chip to auto/normal. + */ +static void +ar5210SetPowerModeAuto(struct ath_hal *ah, int setChip) +{ + OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SV); + if (setChip) + OS_REG_RMW_FIELD(ah, AR_SCR, AR_SCR_SLE, AR_SCR_SLE_ALLOW); +} + +/* + * Notify Power Mgt is enabled in self-generated frames. + * If requested, force chip awake. + * + * Returns A_OK if chip is awake or successfully forced awake. + * + * WARNING WARNING WARNING + * There is a problem with the chip where sometimes it will not wake up. + */ +static HAL_BOOL +ar5210SetPowerModeAwake(struct ath_hal *ah, int setChip) +{ +#define POWER_UP_TIME 2000 + uint32_t val; + int i; + + if (setChip) { + OS_REG_RMW_FIELD(ah, AR_SCR, AR_SCR_SLE, AR_SCR_SLE_WAKE); + OS_DELAY(2000); /* Give chip the chance to awake */ + + for (i = POWER_UP_TIME / 200; i != 0; i--) { + val = OS_REG_READ(ah, AR_PCICFG); + if ((val & AR_PCICFG_SP