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_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_SV); + return AH_TRUE; +#undef POWER_UP_TIME +} + +/* + * Notify Power Mgt is disabled in self-generated frames. + * If requested, force chip to sleep. + */ +static void +ar5210SetPowerModeSleep(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_SLP); +} + +HAL_BOOL +ar5210SetPowerMode(struct ath_hal *ah, HAL_POWER_MODE mode, int setChip) +{ + struct ath_hal_5210 *ahp = AH5210(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 = ar5210SetPowerModeAwake(ah, setChip); + break; + case HAL_PM_FULL_SLEEP: + ar5210SetPowerModeSleep(ah, setChip); + break; + case HAL_PM_NETWORK_SLEEP: + ar5210SetPowerModeAuto(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 +ar5210GetPowerMode(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/ar5210/ar5210_recv.c 2009-03-23 17:36:55.000000000 +0000 @@ -0,0 +1,266 @@ +/* + * 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_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 "ar5210/ar5210.h" +#include "ar5210/ar5210reg.h" +#include "ar5210/ar5210desc.h" + +/* + * Get the RXDP. + */ +uint32_t +ar5210GetRxDP(struct ath_hal *ah) +{ + return OS_REG_READ(ah, AR_RXDP); +} + +/* + * Set the RxDP. + */ +void +ar5210SetRxDP(struct ath_hal *ah, uint32_t rxdp) +{ + OS_REG_WRITE(ah, AR_RXDP, rxdp); +} + + +/* + * Set Receive Enable bits. + */ +void +ar5210EnableReceive(struct ath_hal *ah) +{ + OS_REG_WRITE(ah, AR_CR, AR_CR_RXE); +} + +/* + * Stop Receive at the DMA engine + */ +HAL_BOOL +ar5210StopDmaReceive(struct ath_hal *ah) +{ + int i; + + OS_REG_WRITE(ah, AR_CR, AR_CR_RXD); /* Set receive disable bit */ + for (i = 0; i < 1000; i++) { + if ((OS_REG_READ(ah, AR_CR) & AR_CR_RXE) == 0) + return AH_TRUE; + OS_DELAY(10); + } +#ifdef AH_DEBUG + ath_hal_printf(ah, "ar5210: dma receive failed to stop in 10ms\n"); + ath_hal_printf(ah, "AR_CR=0x%x\n", OS_REG_READ(ah, AR_CR)); + ath_hal_printf(ah, "AR_DIAG_SW=0x%x\n", OS_REG_READ(ah, AR_DIAG_SW)); +#endif + return AH_FALSE; +} + +/* + * Start Transmit at the PCU engine (unpause receive) + */ +void +ar5210StartPcuReceive(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 +ar5210StopPcuReceive(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 +ar5210SetMulticastFilter(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 +ar5210ClrMulticastFilterIndex(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 +ar5210ProcRxDesc(struct ath_hal *ah, struct ath_desc *ds, + uint32_t pa, struct ath_desc *nds, uint64_t tsf, + struct ath_rx_status *rs) +{ + struct ar5210_desc *ads = AR5210DESC(ds); + struct ar5210_desc *ands = AR5210DESC(nds); + uint32_t now, rstamp; + + 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; + rstamp = MS(ads->ds_status1, AR_RcvTimestamp); + /* + * Convert timestamp. The value in the + * descriptor is bits [10..22] of the TSF. + */ + now = (OS_REG_READ(ah, AR_TSF_L32) >> 10) & 0xffff; + if ((now & 0x1fff) < rstamp) + rstamp |= (now - 0x2000) & 0xffff; + else + rstamp |= now; + /* NB: keep only 15 bits for consistency w/ other chips */ + rs->rs_tstamp = rstamp & 0x7fff; + 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 if (ads->ds_status1 & AR_FIFOOverrun) + rs->rs_status |= HAL_RXERR_FIFO; + else { + rs->rs_status |= HAL_RXERR_PHY; + rs->rs_phyerr = + (ads->ds_status1 & AR_PHYErr) >> AR_PHYErr_S; + } + } + /* 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 = (ads->ds_status0 & AR_RcvAntenna) ? 1 : 0; + 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/ar5210/ar5210_reset.c 2009-03-23 17:36:55.000000000 +0000 @@ -0,0 +1,1004 @@ +/* + * 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_reset.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" + +typedef struct { + uint32_t Offset; + uint32_t Value; +} REGISTER_VAL; + +static const REGISTER_VAL ar5k0007_init[] = { +#include "ar5210/ar5k_0007.ini" +}; + +/* Default Power Settings for channels outside of EEPROM range */ +static const uint8_t ar5k0007_pwrSettings[17] = { +/* gain delta pc dac */ +/* 54 48 36 24 18 12 9 54 48 36 24 18 12 9 6 ob db */ + 9, 9, 0, 0, 0, 0, 0, 2, 2, 6, 6, 6, 6, 6, 6, 2, 2 +}; + +/* + * The delay, in usecs, between writing AR_RC with a reset + * request and waiting for the chip to settle. If this is + * too short then the chip does not come out of sleep state. + * Note this value was empirically derived and may be dependent + * on the host machine (don't know--the problem was identified + * on an IBM 570e laptop; 10us delays worked on other systems). + */ +#define AR_RC_SETTLE_TIME 20000 + +static HAL_BOOL ar5210SetResetReg(struct ath_hal *, + uint32_t resetMask, u_int waitTime); +static HAL_BOOL ar5210SetChannel(struct ath_hal *, HAL_CHANNEL_INTERNAL *); +static void ar5210SetOperatingMode(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 +ar5210Reset(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_5210 *ahp = AH5210(ah); + const HAL_EEPROM_v1 *ee = AH_PRIVATE(ah)->ah_eeprom; + HAL_CHANNEL_INTERNAL *ichan; + HAL_STATUS ecode; + uint32_t ledstate; + int i, q; + + HALDEBUG(ah, HAL_DEBUG_RESET, + "%s: opmode %u channel %u/0x%x %s channel\n", __func__, + opmode, chan->channel, chan->channelFlags, + bChannelChange ? "change" : "same"); + + if ((chan->channelFlags & CHANNEL_5GHZ) == 0) { + /* Only 11a mode */ + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: channel not 5Ghz\n", __func__); + FAIL(HAL_EINVAL); + } + /* + * 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; + } + + ledstate = OS_REG_READ(ah, AR_PCICFG) & + (AR_PCICFG_LED_PEND | AR_PCICFG_LED_ACT); + + if (!ar5210ChipReset(ah, chan)) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: chip reset failed\n", + __func__); + FAIL(HAL_EIO); + } + + 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)); + ar5210SetOperatingMode(ah, opmode); + + switch (opmode) { + case HAL_M_HOSTAP: + OS_REG_WRITE(ah, AR_BCR, INIT_BCON_CNTRL_REG); + OS_REG_WRITE(ah, AR_PCICFG, + AR_PCICFG_LED_ACT | AR_PCICFG_LED_BCTL); + break; + case HAL_M_IBSS: + OS_REG_WRITE(ah, AR_BCR, INIT_BCON_CNTRL_REG | AR_BCR_BCMD); + OS_REG_WRITE(ah, AR_PCICFG, + AR_PCICFG_CLKRUNEN | AR_PCICFG_LED_PEND | AR_PCICFG_LED_BCTL); + break; + case HAL_M_STA: + OS_REG_WRITE(ah, AR_BCR, INIT_BCON_CNTRL_REG); + OS_REG_WRITE(ah, AR_PCICFG, + AR_PCICFG_CLKRUNEN | AR_PCICFG_LED_PEND | AR_PCICFG_LED_BCTL); + break; + case HAL_M_MONITOR: + OS_REG_WRITE(ah, AR_BCR, INIT_BCON_CNTRL_REG); + OS_REG_WRITE(ah, AR_PCICFG, + AR_PCICFG_LED_ACT | AR_PCICFG_LED_BCTL); + break; + } + + /* Restore previous led state */ + OS_REG_WRITE(ah, AR_PCICFG, OS_REG_READ(ah, AR_PCICFG) | ledstate); + + 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)); + + OS_REG_WRITE(ah, AR_TXDP0, 0); + OS_REG_WRITE(ah, AR_TXDP1, 0); + OS_REG_WRITE(ah, AR_RXDP, 0); + + /* + * Initialize interrupt state. + */ + (void) OS_REG_READ(ah, AR_ISR); /* cleared on read */ + OS_REG_WRITE(ah, AR_IMR, 0); + OS_REG_WRITE(ah, AR_IER, AR_IER_DISABLE); + ahp->ah_maskReg = 0; + + (void) OS_REG_READ(ah, AR_BSR); /* cleared on read */ + OS_REG_WRITE(ah, AR_TXCFG, AR_DMASIZE_128B); + OS_REG_WRITE(ah, AR_RXCFG, AR_DMASIZE_128B); + + OS_REG_WRITE(ah, AR_TOPS, 8); /* timeout prescale */ + OS_REG_WRITE(ah, AR_RXNOFRM, 8); /* RX no frame timeout */ + OS_REG_WRITE(ah, AR_RPGTO, 0); /* RX frame gap timeout */ + OS_REG_WRITE(ah, AR_TXNOFRM, 0); /* TX no frame timeout */ + + OS_REG_WRITE(ah, AR_SFR, 0); + OS_REG_WRITE(ah, AR_MIBC, 0); /* unfreeze ctrs + clr state */ + OS_REG_WRITE(ah, AR_RSSI_THR, ahp->ah_rssiThr); + OS_REG_WRITE(ah, AR_CFP_DUR, 0); + + ar5210SetRxFilter(ah, 0); /* nothing for now */ + OS_REG_WRITE(ah, AR_MCAST_FIL0, 0); /* multicast filter */ + OS_REG_WRITE(ah, AR_MCAST_FIL1, 0); /* XXX was 2 */ + + OS_REG_WRITE(ah, AR_TX_MASK0, 0); + OS_REG_WRITE(ah, AR_TX_MASK1, 0); + OS_REG_WRITE(ah, AR_CLR_TMASK, 1); + OS_REG_WRITE(ah, AR_TRIG_LEV, 1); /* minimum */ + + OS_REG_WRITE(ah, AR_DIAG_SW, 0); + + OS_REG_WRITE(ah, AR_CFP_PERIOD, 0); + OS_REG_WRITE(ah, AR_TIMER0, 0); /* next beacon time */ + OS_REG_WRITE(ah, AR_TSF_L32, 0); /* local clock */ + OS_REG_WRITE(ah, AR_TIMER1, ~0); /* next DMA beacon alert */ + OS_REG_WRITE(ah, AR_TIMER2, ~0); /* next SW beacon alert */ + OS_REG_WRITE(ah, AR_TIMER3, 1); /* next ATIM window */ + + /* Write the INI values for PHYreg initialization */ + for (i = 0; i < N(ar5k0007_init); i++) { + uint32_t reg = ar5k0007_init[i].Offset; + /* On channel change, don't reset the PCU registers */ + if (!(bChannelChange && (0x8000 <= reg && reg < 0x9000))) + OS_REG_WRITE(ah, reg, ar5k0007_init[i].Value); + } + + /* Setup the transmit power values for cards since 0x0[0-2]05 */ + if (!ar5210SetTransmitPower(ah, chan)) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: error init'ing transmit power\n", __func__); + FAIL(HAL_EIO); + } + + OS_REG_WRITE(ah, AR_PHY(10), + (OS_REG_READ(ah, AR_PHY(10)) & 0xFFFF00FF) | + (ee->ee_xlnaOn << 8)); + OS_REG_WRITE(ah, AR_PHY(13), + (ee->ee_xpaOff << 24) | (ee->ee_xpaOff << 16) | + (ee->ee_xpaOn << 8) | ee->ee_xpaOn); + OS_REG_WRITE(ah, AR_PHY(17), + (OS_REG_READ(ah, AR_PHY(17)) & 0xFFFFC07F) | + ((ee->ee_antenna >> 1) & 0x3F80)); + OS_REG_WRITE(ah, AR_PHY(18), + (OS_REG_READ(ah, AR_PHY(18)) & 0xFFFC0FFF) | + ((ee->ee_antenna << 10) & 0x3F000)); + OS_REG_WRITE(ah, AR_PHY(25), + (OS_REG_READ(ah, AR_PHY(25)) & 0xFFF80FFF) | + ((ee->ee_thresh62 << 12) & 0x7F000)); + OS_REG_WRITE(ah, AR_PHY(68), + (OS_REG_READ(ah, AR_PHY(68)) & 0xFFFFFFFC) | + (ee->ee_antenna & 0x3)); + + if (!ar5210SetChannel(ah, ichan)) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unable to set channel\n", + __func__); + FAIL(HAL_EIO); + } + if (bChannelChange) { + if (!(ichan->privFlags & CHANNEL_DFS)) + ichan->privFlags &= ~CHANNEL_INTERFERENCE; + chan->channelFlags = ichan->channelFlags; + chan->privFlags = ichan->privFlags; + } + + /* Activate the PHY */ + OS_REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ENABLE); + + OS_DELAY(1000); /* Wait a bit (1 msec) */ + + /* calibrate the HW and poll the bit going to 0 for completion */ + OS_REG_WRITE(ah, AR_PHY_AGCCTL, + OS_REG_READ(ah, AR_PHY_AGCCTL) | AR_PHY_AGC_CAL); + (void) ath_hal_wait(ah, AR_PHY_AGCCTL, AR_PHY_AGC_CAL, 0); + + /* Perform noise floor calibration and set status */ + if (!ar5210CalNoiseFloor(ah, ichan)) { + chan->channelFlags |= CHANNEL_CW_INT; + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: noise floor calibration failed\n", __func__); + FAIL(HAL_EIO); + } + + for (q = 0; q < HAL_NUM_TX_QUEUES; q++) + ar5210ResetTxQueue(ah, q); + + if (AH_PRIVATE(ah)->ah_rfkillEnabled) + ar5210EnableRfKill(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) + ar5210SetSifsTime(ah, ahp->ah_sifstime); + if (ahp->ah_slottime != (u_int) -1) + ar5210SetSlotTime(ah, ahp->ah_slottime); + if (ahp->ah_acktimeout != (u_int) -1) + ar5210SetAckTimeout(ah, ahp->ah_acktimeout); + if (ahp->ah_ctstimeout != (u_int) -1) + ar5210SetCTSTimeout(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 +} + +static void +ar5210SetOperatingMode(struct ath_hal *ah, int opmode) +{ + struct ath_hal_5210 *ahp = AH5210(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_AP + | AR_STA_ID1_NO_PSPOLL + | AR_STA_ID1_DESC_ANTENNA + | ahp->ah_staId1Defaults); + break; + case HAL_M_IBSS: + OS_REG_WRITE(ah, AR_STA_ID1, val + | AR_STA_ID1_ADHOC + | AR_STA_ID1_NO_PSPOLL + | AR_STA_ID1_DESC_ANTENNA + | ahp->ah_staId1Defaults); + break; + case HAL_M_STA: + OS_REG_WRITE(ah, AR_STA_ID1, val + | AR_STA_ID1_NO_PSPOLL + | AR_STA_ID1_PWR_SV + | ahp->ah_staId1Defaults); + break; + case HAL_M_MONITOR: + OS_REG_WRITE(ah, AR_STA_ID1, val + | AR_STA_ID1_NO_PSPOLL + | ahp->ah_staId1Defaults); + break; + } +} + +void +ar5210SetPCUConfig(struct ath_hal *ah) +{ + ar5210SetOperatingMode(ah, AH_PRIVATE(ah)->ah_opmode); +} + +/* + * 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 +ar5210PhyDisable(struct ath_hal *ah) +{ + return ar5210SetResetReg(ah, AR_RC_RPHY, 10); +} + +/* + * Places all of hardware into reset + */ +HAL_BOOL +ar5210Disable(struct ath_hal *ah) +{ +#define AR_RC_HW (AR_RC_RPCU | AR_RC_RDMA | AR_RC_RPHY | AR_RC_RMAC) + if (!ar5210SetPowerMode(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 (!ar5210SetResetReg(ah, AR_RC_HW, AR_RC_SETTLE_TIME)) + return AH_FALSE; + OS_DELAY(1000); + (void) ar5210SetResetReg(ah, AR_RC_HW | AR_RC_RPCI, AR_RC_SETTLE_TIME); + OS_DELAY(2100); /* 8245 @ 96Mhz hangs with 2000us. */ + + return AH_TRUE; +#undef AR_RC_HW +} + +/* + * Places the hardware into reset and then pulls it out of reset + */ +HAL_BOOL +ar5210ChipReset(struct ath_hal *ah, HAL_CHANNEL *chan) +{ +#define AR_RC_HW (AR_RC_RPCU | AR_RC_RDMA | AR_RC_RPHY | AR_RC_RMAC) + + HALDEBUG(ah, HAL_DEBUG_RESET, "%s turbo %s\n", __func__, + chan && IS_CHAN_TURBO(chan) ? "enabled" : "disabled"); + + if (!ar5210SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE)) + return AH_FALSE; + + /* Place chip in turbo before reset to cleanly reset clocks */ + OS_REG_WRITE(ah, AR_PHY_FRCTL, + chan && IS_CHAN_TURBO(chan) ? AR_PHY_TURBO_MODE : 0); + + /* + * Reset the HW. + * PCI must be reset after the rest of the device has been reset. + */ + if (!ar5210SetResetReg(ah, AR_RC_HW, AR_RC_SETTLE_TIME)) + return AH_FALSE; + OS_DELAY(1000); + if (!ar5210SetResetReg(ah, AR_RC_HW | AR_RC_RPCI, AR_RC_SETTLE_TIME)) + return AH_FALSE; + OS_DELAY(2100); /* 8245 @ 96Mhz hangs with 2000us. */ + + /* + * Bring out of sleep mode (AGAIN) + * + * WARNING WARNING WARNING + * + * There is a problem with the chip where it doesn't always indicate + * that it's awake, so initializePowerUp() will fail. + */ + if (!ar5210SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE)) + return AH_FALSE; + + /* Clear warm reset reg */ + return ar5210SetResetReg(ah, 0, 10); +#undef AR_RC_HW +} + +enum { + FIRPWR_M = 0x03fc0000, + FIRPWR_S = 18, + KCOARSEHIGH_M = 0x003f8000, + KCOARSEHIGH_S = 15, + KCOARSELOW_M = 0x00007f80, + KCOARSELOW_S = 7, + ADCSAT_ICOUNT_M = 0x0001f800, + ADCSAT_ICOUNT_S = 11, + ADCSAT_THRESH_M = 0x000007e0, + ADCSAT_THRESH_S = 5 +}; + +/* + * Recalibrate the lower PHY chips to account for temperature/environment + * changes. + */ +HAL_BOOL +ar5210PerCalibrationN(struct ath_hal *ah, HAL_CHANNEL *chan, u_int chainMask, + HAL_BOOL longCal, HAL_BOOL *isCalDone) +{ + uint32_t regBeacon; + uint32_t reg9858, reg985c, reg9868; + HAL_CHANNEL_INTERNAL *ichan; + + 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; + } + /* Disable tx and rx */ + OS_REG_WRITE(ah, AR_DIAG_SW, + OS_REG_READ(ah, AR_DIAG_SW) | (AR_DIAG_SW_DIS_TX | AR_DIAG_SW_DIS_RX)); + + /* Disable Beacon Enable */ + regBeacon = OS_REG_READ(ah, AR_BEACON); + OS_REG_WRITE(ah, AR_BEACON, regBeacon & ~AR_BEACON_EN); + + /* Delay 4ms to ensure that all tx and rx activity has ceased */ + OS_DELAY(4000); + + /* Disable AGC to radio traffic */ + OS_REG_WRITE(ah, 0x9808, OS_REG_READ(ah, 0x9808) | 0x08000000); + /* Wait for the AGC traffic to cease. */ + OS_DELAY(10); + + /* Change Channel to relock synth */ + if (!ar5210SetChannel(ah, ichan)) + return AH_FALSE; + + /* wait for the synthesizer lock to stabilize */ + OS_DELAY(1000); + + /* Re-enable AGC to radio traffic */ + OS_REG_WRITE(ah, 0x9808, OS_REG_READ(ah, 0x9808) & (~0x08000000)); + + /* + * Configure the AGC so that it is highly unlikely (if not + * impossible) for it to send any gain changes to the analog + * chip. We store off the current values so that they can + * be rewritten below. Setting the following values: + * firpwr = -1 + * Kcoursehigh = -1 + * Kcourselow = -127 + * ADCsat_icount = 2 + * ADCsat_thresh = 12 + */ + reg9858 = OS_REG_READ(ah, 0x9858); + reg985c = OS_REG_READ(ah, 0x985c); + reg9868 = OS_REG_READ(ah, 0x9868); + + OS_REG_WRITE(ah, 0x9858, (reg9858 & ~FIRPWR_M) | + ((-1 << FIRPWR_S) & FIRPWR_M)); + OS_REG_WRITE(ah, 0x985c, + (reg985c & ~(KCOARSEHIGH_M | KCOARSELOW_M)) | + ((-1 << KCOARSEHIGH_S) & KCOARSEHIGH_M) | + ((-127 << KCOARSELOW_S) & KCOARSELOW_M)); + OS_REG_WRITE(ah, 0x9868, + (reg9868 & ~(ADCSAT_ICOUNT_M | ADCSAT_THRESH_M)) | + ((2 << ADCSAT_ICOUNT_S) & ADCSAT_ICOUNT_M) | + ((12 << ADCSAT_THRESH_S) & ADCSAT_THRESH_M)); + + /* Wait for AGC changes to be enacted */ + OS_DELAY(20); + + /* + * We disable RF mix/gain stages for the PGA to avoid a + * race condition that will occur with receiving a frame + * and performing the AGC calibration. This will be + * re-enabled at the end of offset cal. We turn off AGC + * writes during this write as it will go over the analog bus. + */ + OS_REG_WRITE(ah, 0x9808, OS_REG_READ(ah, 0x9808) | 0x08000000); + OS_DELAY(10); /* wait for the AGC traffic to cease */ + OS_REG_WRITE(ah, 0x98D4, 0x21); + OS_REG_WRITE(ah, 0x9808, OS_REG_READ(ah, 0x9808) & (~0x08000000)); + + /* wait to make sure that additional AGC traffic has quiesced */ + OS_DELAY(1000); + + /* AGC calibration (this was added to make the NF threshold check work) */ + OS_REG_WRITE(ah, AR_PHY_AGCCTL, + OS_REG_READ(ah, AR_PHY_AGCCTL) | AR_PHY_AGC_CAL); + if (!ath_hal_wait(ah, AR_PHY_AGCCTL, AR_PHY_AGC_CAL, 0)) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: AGC calibration timeout\n", + __func__); + } + + /* Rewrite our AGC values we stored off earlier (return AGC to normal operation) */ + OS_REG_WRITE(ah, 0x9858, reg9858); + OS_REG_WRITE(ah, 0x985c, reg985c); + OS_REG_WRITE(ah, 0x9868, reg9868); + + /* Perform noise floor and set status */ + if (!ar5210CalNoiseFloor(ah, ichan)) { + /* + * Delay 5ms before retrying the noise floor - + * just to make sure. We're in an error + * condition here + */ + HALDEBUG(ah, HAL_DEBUG_NFCAL | HAL_DEBUG_PERCAL, + "%s: Performing 2nd Noise Cal\n", __func__); + OS_DELAY(5000); + if (!ar5210CalNoiseFloor(ah, ichan)) + chan->channelFlags |= CHANNEL_CW_INT; + } + + /* Clear tx and rx disable bit */ + OS_REG_WRITE(ah, AR_DIAG_SW, + OS_REG_READ(ah, AR_DIAG_SW) & ~(AR_DIAG_SW_DIS_TX | AR_DIAG_SW_DIS_RX)); + + /* Re-enable Beacons */ + OS_REG_WRITE(ah, AR_BEACON, regBeacon); + + *isCalDone = AH_TRUE; + + return AH_TRUE; +} + +HAL_BOOL +ar5210PerCalibration(struct ath_hal *ah, HAL_CHANNEL *chan, HAL_BOOL *isIQdone) +{ + return ar5210PerCalibrationN(ah, chan, 0x1, AH_TRUE, isIQdone); +} + +HAL_BOOL +ar5210ResetCalValid(struct ath_hal *ah, HAL_CHANNEL *chan) +{ + return AH_TRUE; +} + +/* + * Writes the given reset bit mask into the reset register + */ +static HAL_BOOL +ar5210SetResetReg(struct ath_hal *ah, uint32_t resetMask, u_int waitTime) +{ + uint32_t mask = resetMask ? resetMask : ~0; + HAL_BOOL rt; + + OS_REG_WRITE(ah, AR_RC, resetMask); + /* need to wait at least 128 clocks when reseting PCI before read */ + OS_DELAY(waitTime); + + resetMask &= AR_RC_RPCU | AR_RC_RDMA | AR_RC_RPHY | AR_RC_RMAC; + mask &= AR_RC_RPCU | AR_RC_RDMA | AR_RC_RPHY | AR_RC_RMAC; + rt = ath_hal_wait(ah, AR_RC, mask, resetMask); + if ((resetMask & AR_RC_RMAC) == 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; +} + + +/* + * Returns: the pcdac value + */ +static uint8_t +getPcdac(struct ath_hal *ah, const struct tpcMap *pRD, uint8_t dBm) +{ + int32_t i; + int useNextEntry = AH_FALSE; + uint32_t interp; + + for (i = AR_TP_SCALING_ENTRIES - 1; i >= 0; i--) { + /* Check for exact entry */ + if (dBm == AR_I2DBM(i)) { + if (pRD->pcdac[i] != 63) + return pRD->pcdac[i]; + useNextEntry = AH_TRUE; + } else if (dBm + 1 == AR_I2DBM(i) && i > 0) { + /* Interpolate for between entry with a logish scale */ + if (pRD->pcdac[i] != 63 && pRD->pcdac[i-1] != 63) { + interp = (350 * (pRD->pcdac[i] - pRD->pcdac[i-1])) + 999; + interp = (interp / 1000) + pRD->pcdac[i-1]; + return interp; + } + useNextEntry = AH_TRUE; + } else if (useNextEntry == AH_TRUE) { + /* Grab the next lowest */ + if (pRD->pcdac[i] != 63) + return pRD->pcdac[i]; + } + } + + /* Return the lowest Entry if we haven't returned */ + for (i = 0; i < AR_TP_SCALING_ENTRIES; i++) + if (pRD->pcdac[i] != 63) + return pRD->pcdac[i]; + + /* No value to return from table */ +#ifdef AH_DEBUG + ath_hal_printf(ah, "%s: empty transmit power table?\n", __func__); +#endif + return 1; +} + +/* + * Find or interpolates the gainF value from the table ptr. + */ +static uint8_t +getGainF(struct ath_hal *ah, const struct tpcMap *pRD, + uint8_t pcdac, uint8_t *dBm) +{ + uint32_t interp; + int low, high, i; + + low = high = -1; + + for (i = 0; i < AR_TP_SCALING_ENTRIES; i++) { + if(pRD->pcdac[i] == 63) + continue; + if (pcdac == pRD->pcdac[i]) { + *dBm = AR_I2DBM(i); + return pRD->gainF[i]; /* Exact Match */ + } + if (pcdac > pRD->pcdac[i]) + low = i; + if (pcdac < pRD->pcdac[i]) { + high = i; + if (low == -1) { + *dBm = AR_I2DBM(i); + /* PCDAC is lower than lowest setting */ + return pRD->gainF[i]; + } + break; + } + } + if (i >= AR_TP_SCALING_ENTRIES && low == -1) { + /* No settings were found */ +#ifdef AH_DEBUG + ath_hal_printf(ah, + "%s: no valid entries in the pcdac table: %d\n", + __func__, pcdac); +#endif + return 63; + } + if (i >= AR_TP_SCALING_ENTRIES) { + /* PCDAC setting was above the max setting in the table */ + *dBm = AR_I2DBM(low); + return pRD->gainF[low]; + } + /* Only exact if table has no missing entries */ + *dBm = (low + high) + 3; + + /* + * Perform interpolation between low and high values to find gainF + * linearly scale the pcdac between low and high + */ + interp = ((pcdac - pRD->pcdac[low]) * 1000) / + (pRD->pcdac[high] - pRD->pcdac[low]); + /* + * Multiply the scale ratio by the gainF difference + * (plus a rnd up factor) + */ + interp = ((interp * (pRD->gainF[high] - pRD->gainF[low])) + 999) / 1000; + + /* Add ratioed gain_f to low gain_f value */ + return interp + pRD->gainF[low]; +} + +HAL_BOOL +ar5210SetTxPowerLimit(struct ath_hal *ah, uint32_t limit) +{ + AH_PRIVATE(ah)->ah_powerLimit = AH_MIN(limit, AR5210_MAX_RATE_POWER); + /* XXX flush to h/w */ + return AH_TRUE; +} + +/* + * Get TXPower values and set them in the radio + */ +static HAL_BOOL +setupPowerSettings(struct ath_hal *ah, HAL_CHANNEL *chan, uint8_t cp[17]) +{ + const HAL_EEPROM_v1 *ee = AH_PRIVATE(ah)->ah_eeprom; + uint8_t gainFRD, gainF36, gainF48, gainF54; + uint8_t dBmRD = 0, dBm36 = 0, dBm48 = 0, dBm54 = 0, dontcare; + uint32_t rd, group; + const struct tpcMap *pRD; + + /* Set OB/DB Values regardless of channel */ + cp[15] = (ee->ee_biasCurrents >> 4) & 0x7; + cp[16] = ee->ee_biasCurrents & 0x7; + + if (chan->channel < 5170 || chan->channel > 5320) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel %u\n", + __func__, chan->channel); + return AH_FALSE; + } + + HALASSERT(ee->ee_version >= AR_EEPROM_VER1 && + ee->ee_version < AR_EEPROM_VER3); + + /* Match regulatory domain */ + for (rd = 0; rd < AR_REG_DOMAINS_MAX; rd++) + if (AH_PRIVATE(ah)->ah_currentRD == ee->ee_regDomain[rd]) + break; + if (rd == AR_REG_DOMAINS_MAX) { +#ifdef AH_DEBUG + ath_hal_printf(ah, + "%s: no calibrated regulatory domain matches the " + "current regularly domain (0x%0x)\n", __func__, + AH_PRIVATE(ah)->ah_currentRD); +#endif + return AH_FALSE; + } + group = ((chan->channel - 5170) / 10); + + if (group > 11) { + /* Pull 5.29 into the 5.27 group */ + group--; + } + + /* Integer divide will set group from 0 to 4 */ + group = group / 3; + pRD = &ee->ee_tpc[group]; + + /* Set PC DAC Values */ + cp[14] = pRD->regdmn[rd]; + cp[9] = AH_MIN(pRD->regdmn[rd], pRD->rate36); + cp[8] = AH_MIN(pRD->regdmn[rd], pRD->rate48); + cp[7] = AH_MIN(pRD->regdmn[rd], pRD->rate54); + + /* Find Corresponding gainF values for RD, 36, 48, 54 */ + gainFRD = getGainF(ah, pRD, pRD->regdmn[rd], &dBmRD); + gainF36 = getGainF(ah, pRD, cp[9], &dBm36); + gainF48 = getGainF(ah, pRD, cp[8], &dBm48); + gainF54 = getGainF(ah, pRD, cp[7], &dBm54); + + /* Power Scale if requested */ + if (AH_PRIVATE(ah)->ah_tpScale != HAL_TP_SCALE_MAX) { + static const uint16_t tpcScaleReductionTable[5] = + { 0, 3, 6, 9, AR5210_MAX_RATE_POWER }; + uint16_t tpScale; + + tpScale = tpcScaleReductionTable[AH_PRIVATE(ah)->ah_tpScale]; + if (dBmRD < tpScale+3) + dBmRD = 3; /* min */ + else + dBmRD -= tpScale; + cp[14] = getPcdac(ah, pRD, dBmRD); + gainFRD = getGainF(ah, pRD, cp[14], &dontcare); + dBm36 = AH_MIN(dBm36, dBmRD); + cp[9] = getPcdac(ah, pRD, dBm36); + gainF36 = getGainF(ah, pRD, cp[9], &dontcare); + dBm48 = AH_MIN(dBm48, dBmRD); + cp[8] = getPcdac(ah, pRD, dBm48); + gainF48 = getGainF(ah, pRD, cp[8], &dontcare); + dBm54 = AH_MIN(dBm54, dBmRD); + cp[7] = getPcdac(ah, pRD, dBm54); + gainF54 = getGainF(ah, pRD, cp[7], &dontcare); + } + /* Record current dBm at rate 6 */ + AH_PRIVATE(ah)->ah_maxPowerLevel = 2*dBmRD; + + cp[13] = cp[12] = cp[11] = cp[10] = cp[14]; + + /* Set GainF Values */ + cp[0] = gainFRD - gainF54; + cp[1] = gainFRD - gainF48; + cp[2] = gainFRD - gainF36; + /* 9, 12, 18, 24 have no gain_delta from 6 */ + cp[3] = cp[4] = cp[5] = cp[6] = 0; + return AH_TRUE; +} + +/* + * 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 + */ +HAL_BOOL +ar5210SetTransmitPower(struct ath_hal *ah, HAL_CHANNEL *chan) +{ +#define N(a) (sizeof (a) / sizeof (a[0])) + static const uint32_t pwr_regs_start[17] = { + 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xf0000000, + 0xcc000000, 0x00000000, 0x00000000, + 0x00000000, 0x0a000000, 0x000000e2, + 0x0a000020, 0x01000002, 0x01000018, + 0x40000000, 0x00000418 + }; + uint16_t i; + uint8_t cp[sizeof(ar5k0007_pwrSettings)]; + uint32_t pwr_regs[17]; + + OS_MEMCPY(pwr_regs, pwr_regs_start, sizeof(pwr_regs)); + OS_MEMCPY(cp, ar5k0007_pwrSettings, sizeof(cp)); + + /* Check the EEPROM tx power calibration settings */ + if (!setupPowerSettings(ah, chan, cp)) { +#ifdef AH_DEBUG + ath_hal_printf(ah, "%s: unable to setup power settings\n", + __func__); +#endif + return AH_FALSE; + } + if (cp[15] < 1 || cp[15] > 5) { +#ifdef AH_DEBUG + ath_hal_printf(ah, "%s: OB out of range (%u)\n", + __func__, cp[15]); +#endif + return AH_FALSE; + } + if (cp[16] < 1 || cp[16] > 5) { +#ifdef AH_DEBUG + ath_hal_printf(ah, "%s: DB out of range (%u)\n", + __func__, cp[16]); +#endif + return AH_FALSE; + } + + /* reverse bits of the transmit power array */ + for (i = 0; i < 7; i++) + cp[i] = ath_hal_reverseBits(cp[i], 5); + for (i = 7; i < 15; i++) + cp[i] = ath_hal_reverseBits(cp[i], 6); + + /* merge transmit power values into the register - quite gross */ + pwr_regs[0] |= ((cp[1] << 5) & 0xE0) | (cp[0] & 0x1F); + pwr_regs[1] |= ((cp[3] << 7) & 0x80) | ((cp[2] << 2) & 0x7C) | + ((cp[1] >> 3) & 0x03); + pwr_regs[2] |= ((cp[4] << 4) & 0xF0) | ((cp[3] >> 1) & 0x0F); + pwr_regs[3] |= ((cp[6] << 6) & 0xC0) | ((cp[5] << 1) & 0x3E) | + ((cp[4] >> 4) & 0x01); + pwr_regs[4] |= ((cp[7] << 3) & 0xF8) | ((cp[6] >> 2) & 0x07); + pwr_regs[5] |= ((cp[9] << 7) & 0x80) | ((cp[8] << 1) & 0x7E) | + ((cp[7] >> 5) & 0x01); + pwr_regs[6] |= ((cp[10] << 5) & 0xE0) | ((cp[9] >> 1) & 0x1F); + pwr_regs[7] |= ((cp[11] << 3) & 0xF8) | ((cp[10] >> 3) & 0x07); + pwr_regs[8] |= ((cp[12] << 1) & 0x7E) | ((cp[11] >> 5) & 0x01); + pwr_regs[9] |= ((cp[13] << 5) & 0xE0); + pwr_regs[10] |= ((cp[14] << 3) & 0xF8) | ((cp[13] >> 3) & 0x07); + pwr_regs[11] |= ((cp[14] >> 5) & 0x01); + + /* Set OB */ + pwr_regs[8] |= (ath_hal_reverseBits(cp[15], 3) << 7) & 0x80; + pwr_regs[9] |= (ath_hal_reverseBits(cp[15], 3) >> 1) & 0x03; + + /* Set DB */ + pwr_regs[9] |= (ath_hal_reverseBits(cp[16], 3) << 2) & 0x1C; + + /* Write the registers */ + for (i = 0; i < N(pwr_regs)-1; i++) + OS_REG_WRITE(ah, 0x0000989c, pwr_regs[i]); + /* last write is a flush */ + OS_REG_WRITE(ah, 0x000098d4, pwr_regs[i]); + + return AH_TRUE; +#undef N +} + +/* + * 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 +ar5210SetChannel(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan) +{ + uint32_t data; + + /* Set the Channel */ + data = ath_hal_reverseBits((chan->channel - 5120)/10, 5); + data = (data << 1) | 0x41; + OS_REG_WRITE(ah, AR_PHY(0x27), data); + OS_REG_WRITE(ah, AR_PHY(0x30), 0); + AH_PRIVATE(ah)->ah_curchan = chan; + return AH_TRUE; +} + +int16_t +ar5210GetNoiseFloor(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; +} + +#define NORMAL_NF_THRESH (-72) +/* + * Peform the noisefloor calibration and check for + * any constant channel interference + * + * Returns: TRUE for a successful noise floor calibration; else FALSE + */ +HAL_BOOL +ar5210CalNoiseFloor(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan) +{ + int32_t nf, nfLoops; + + /* Calibrate the noise floor */ + OS_REG_WRITE(ah, AR_PHY_AGCCTL, + OS_REG_READ(ah, AR_PHY_AGCCTL) | AR_PHY_AGC_NF); + + /* Do not read noise floor until it has done the first update */ + if (!ath_hal_wait(ah, AR_PHY_AGCCTL, AR_PHY_AGC_NF, 0)) { +#ifdef ATH_HAL_DEBUG + ath_hal_printf(ah, " -PHY NF Reg state: 0x%x\n", + OS_REG_READ(ah, AR_PHY_AGCCTL)); + ath_hal_printf(ah, " -MAC Reset Reg state: 0x%x\n", + OS_REG_READ(ah, AR_RC)); + ath_hal_printf(ah, " -PHY Active Reg state: 0x%x\n", + OS_REG_READ(ah, AR_PHY_ACTIVE)); +#endif /* ATH_HAL_DEBUG */ + return AH_FALSE; + } + + nf = 0; + /* Keep checking until the floor is below the threshold or the nf is done */ + for (nfLoops = 0; ((nfLoops < 21) && (nf > NORMAL_NF_THRESH)); nfLoops++) { + OS_DELAY(1000); /* Sleep for 1 ms */ + nf = ar5210GetNoiseFloor(ah); + } + + if (nf > NORMAL_NF_THRESH) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: Bad noise cal %d\n", + __func__, nf); + chan->rawNoiseFloor = 0; + return AH_FALSE; + } + chan->rawNoiseFloor = nf; + return AH_TRUE; +} + +/* + * Adjust NF based on statistical values for 5GHz frequencies. + */ +int16_t +ar5210GetNfAdjust(struct ath_hal *ah, const HAL_CHANNEL_INTERNAL *c) +{ + return 0; +} + +HAL_RFGAIN +ar5210GetRfgain(struct ath_hal *ah) +{ + return HAL_RFGAIN_INACTIVE; +} --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5210/ar5210_xmit.c 2009-03-23 17:36:55.000000000 +0000 @@ -0,0 +1,623 @@ +/* + * 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_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 "ar5210/ar5210.h" +#include "ar5210/ar5210reg.h" +#include "ar5210/ar5210phy.h" +#include "ar5210/ar5210desc.h" + +/* + * Set the properties of the tx queue with the parameters + * from qInfo. The queue must previously have been setup + * with a call to ar5210SetupTxQueue. + */ +HAL_BOOL +ar5210SetTxQueueProps(struct ath_hal *ah, int q, const HAL_TXQ_INFO *qInfo) +{ + struct ath_hal_5210 *ahp = AH5210(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 +ar5210GetTxQueueProps(struct ath_hal *ah, int q, HAL_TXQ_INFO *qInfo) +{ + struct ath_hal_5210 *ahp = AH5210(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 +ar5210SetupTxQueue(struct ath_hal *ah, HAL_TX_QUEUE type, + const HAL_TXQ_INFO *qInfo) +{ + struct ath_hal_5210 *ahp = AH5210(ah); + HAL_TX_QUEUE_INFO *qi; + int q; + + switch (type) { + case HAL_TX_QUEUE_BEACON: + q = 2; + break; + case HAL_TX_QUEUE_CAB: + q = 1; + break; + case HAL_TX_QUEUE_DATA: + q = 0; + 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_shretry = INIT_SH_RETRY; + qi->tqi_lgretry = INIT_LG_RETRY; + } else + (void) ar5210SetTxQueueProps(ah, q, qInfo); + /* NB: must be followed by ar5210ResetTxQueue */ + return q; +} + +/* + * Free a tx DCU/QCU combination. + */ +HAL_BOOL +ar5210ReleaseTxQueue(struct ath_hal *ah, u_int q) +{ + struct ath_hal_5210 *ahp = AH5210(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); + + return AH_TRUE; +#undef N +} + +HAL_BOOL +ar5210ResetTxQueue(struct ath_hal *ah, u_int q) +{ + struct ath_hal_5210 *ahp = AH5210(ah); + HAL_CHANNEL_INTERNAL *chan = AH_PRIVATE(ah)->ah_curchan; + HAL_TX_QUEUE_INFO *qi; + uint32_t cwMin; + + 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; + } + + /* + * Ignore any non-data queue(s). + */ + if (qi->tqi_type != HAL_TX_QUEUE_DATA) + return AH_TRUE; + + /* Set turbo mode / base mode parameters on or off */ + if (IS_CHAN_TURBO(chan)) { + OS_REG_WRITE(ah, AR_SLOT_TIME, INIT_SLOT_TIME_TURBO); + OS_REG_WRITE(ah, AR_TIME_OUT, INIT_ACK_CTS_TIMEOUT_TURBO); + OS_REG_WRITE(ah, AR_USEC, INIT_TRANSMIT_LATENCY_TURBO); + OS_REG_WRITE(ah, AR_IFS0, + ((INIT_SIFS_TURBO + qi->tqi_aifs * INIT_SLOT_TIME_TURBO) + << AR_IFS0_DIFS_S) + | INIT_SIFS_TURBO); + OS_REG_WRITE(ah, AR_IFS1, INIT_PROTO_TIME_CNTRL_TURBO); + OS_REG_WRITE(ah, AR_PHY(17), + (OS_REG_READ(ah, AR_PHY(17)) & ~0x7F) | 0x38); + OS_REG_WRITE(ah, AR_PHY_FRCTL, + AR_PHY_SERVICE_ERR | AR_PHY_TXURN_ERR | + AR_PHY_ILLLEN_ERR | AR_PHY_ILLRATE_ERR | + AR_PHY_PARITY_ERR | AR_PHY_TIMING_ERR | + 0x2020 | + AR_PHY_TURBO_MODE | AR_PHY_TURBO_SHORT); + } else { + OS_REG_WRITE(ah, AR_SLOT_TIME, INIT_SLOT_TIME); + OS_REG_WRITE(ah, AR_TIME_OUT, INIT_ACK_CTS_TIMEOUT); + OS_REG_WRITE(ah, AR_USEC, INIT_TRANSMIT_LATENCY); + OS_REG_WRITE(ah, AR_IFS0, + ((INIT_SIFS + qi->tqi_aifs * INIT_SLOT_TIME) + << AR_IFS0_DIFS_S) + | INIT_SIFS); + OS_REG_WRITE(ah, AR_IFS1, INIT_PROTO_TIME_CNTRL); + OS_REG_WRITE(ah, AR_PHY(17), + (OS_REG_READ(ah, AR_PHY(17)) & ~0x7F) | 0x1C); + OS_REG_WRITE(ah, AR_PHY_FRCTL, + AR_PHY_SERVICE_ERR | AR_PHY_TXURN_ERR | + AR_PHY_ILLLEN_ERR | AR_PHY_ILLRATE_ERR | + AR_PHY_PARITY_ERR | AR_PHY_TIMING_ERR | 0x1020); + } + + if (qi->tqi_cwmin == HAL_TXQ_USEDEFAULT) + cwMin = INIT_CWMIN; + else + cwMin = qi->tqi_cwmin; + + /* Set cwmin and retry limit values */ + OS_REG_WRITE(ah, AR_RETRY_LMT, + (cwMin << AR_RETRY_LMT_CW_MIN_S) + | SM(INIT_SLG_RETRY, AR_RETRY_LMT_SLG_RETRY) + | SM(INIT_SSH_RETRY, AR_RETRY_LMT_SSH_RETRY) + | SM(qi->tqi_lgretry, AR_RETRY_LMT_LG_RETRY) + | SM(qi->tqi_shretry, AR_RETRY_LMT_SH_RETRY) + ); + + 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); + + return AH_TRUE; +} + +/* + * Get the TXDP for the "main" data queue. Needs to be extended + * for multiple Q functionality + */ +uint32_t +ar5210GetTxDP(struct ath_hal *ah, u_int q) +{ + struct ath_hal_5210 *ahp = AH5210(ah); + HAL_TX_QUEUE_INFO *qi; + + HALASSERT(q < HAL_NUM_TX_QUEUES); + + qi = &ahp->ah_txq[q]; + switch (qi->tqi_type) { + case HAL_TX_QUEUE_DATA: + return OS_REG_READ(ah, AR_TXDP0); + case HAL_TX_QUEUE_INACTIVE: + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: inactive queue %u\n", + __func__, q); + /* fall thru... */ + default: + break; + } + return 0xffffffff; +} + +/* + * Set the TxDP for the "main" data queue. + */ +HAL_BOOL +ar5210SetTxDP(struct ath_hal *ah, u_int q, uint32_t txdp) +{ + struct ath_hal_5210 *ahp = AH5210(ah); + HAL_TX_QUEUE_INFO *qi; + + HALASSERT(q < HAL_NUM_TX_QUEUES); + + HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: queue %u 0x%x\n", + __func__, q, txdp); + qi = &ahp->ah_txq[q]; + switch (qi->tqi_type) { + case HAL_TX_QUEUE_DATA: +#ifdef AH_DEBUG + /* + * Make sure that TXE is deasserted before setting the + * TXDP. If TXE is still asserted, setting TXDP will + * have no effect. + */ + if (OS_REG_READ(ah, AR_CR) & AR_CR_TXE0) + ath_hal_printf(ah, "%s: TXE asserted; AR_CR=0x%x\n", + __func__, OS_REG_READ(ah, AR_CR)); +#endif + OS_REG_WRITE(ah, AR_TXDP0, txdp); + break; + case HAL_TX_QUEUE_BEACON: + case HAL_TX_QUEUE_CAB: + OS_REG_WRITE(ah, AR_TXDP1, txdp); + break; + case HAL_TX_QUEUE_INACTIVE: + HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: inactive queue %u\n", + __func__, q); + /* fall thru... */ + default: + return AH_FALSE; + } + return AH_TRUE; +} + +/* + * 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 +ar5210UpdateTxTrigLevel(struct ath_hal *ah, HAL_BOOL bIncTrigLevel) +{ + uint32_t curTrigLevel; + HAL_INT ints = ar5210GetInterrupts(ah); + + /* + * Disable chip interrupts. This is because halUpdateTxTrigLevel + * is called from both ISR and non-ISR contexts. + */ + (void) ar5210SetInterrupts(ah, ints &~ HAL_INT_GLOBAL); + curTrigLevel = OS_REG_READ(ah, AR_TRIG_LEV); + 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 */ + ar5210SetInterrupts(ah, ints); + return AH_FALSE; + } + } + /* Update the trigger level */ + OS_REG_WRITE(ah, AR_TRIG_LEV, curTrigLevel); + /* re-enable chip interrupts */ + ar5210SetInterrupts(ah, ints); + return AH_TRUE; +} + +/* + * Set Transmit Enable bits for the specified queues. + */ +HAL_BOOL +ar5210StartTxDma(struct ath_hal *ah, u_int q) +{ + struct ath_hal_5210 *ahp = AH5210(ah); + HAL_TX_QUEUE_INFO *qi; + + HALASSERT(q < HAL_NUM_TX_QUEUES); + + HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: queue %u\n", __func__, q); + qi = &ahp->ah_txq[q]; + switch (qi->tqi_type) { + case HAL_TX_QUEUE_DATA: + OS_REG_WRITE(ah, AR_CR, AR_CR_TXE0); + break; + case HAL_TX_QUEUE_CAB: + OS_REG_WRITE(ah, AR_CR, AR_CR_TXE1); /* enable altq xmit */ + OS_REG_WRITE(ah, AR_BCR, + AR_BCR_TQ1V | AR_BCR_BDMAE | AR_BCR_TQ1FV); + break; + case HAL_TX_QUEUE_BEACON: + /* XXX add CR_BCR_BCMD if IBSS mode */ + OS_REG_WRITE(ah, AR_BCR, AR_BCR_TQ1V | AR_BCR_BDMAE); + break; + case HAL_TX_QUEUE_INACTIVE: + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: inactive queue %u\n", + __func__, q); + /* fal thru... */ + default: + return AH_FALSE; + } + return AH_TRUE; +} + +uint32_t +ar5210NumTxPending(struct ath_hal *ah, u_int q) +{ + struct ath_hal_5210 *ahp = AH5210(ah); + HAL_TX_QUEUE_INFO *qi; + uint32_t v; + + HALASSERT(q < HAL_NUM_TX_QUEUES); + + HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: queue %u\n", __func__, q); + qi = &ahp->ah_txq[q]; + switch (qi->tqi_type) { + case HAL_TX_QUEUE_DATA: + v = OS_REG_READ(ah, AR_CFG); + return MS(v, AR_CFG_TXCNT); + case HAL_TX_QUEUE_INACTIVE: + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: inactive queue %u\n", + __func__, q); + /* fall thru... */ + default: + break; + } + return 0; +} + +/* + * Stop transmit on the specified queue + */ +HAL_BOOL +ar5210StopTxDma(struct ath_hal *ah, u_int q) +{ + struct ath_hal_5210 *ahp = AH5210(ah); + HAL_TX_QUEUE_INFO *qi; + + HALASSERT(q < HAL_NUM_TX_QUEUES); + + HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: queue %u\n", __func__, q); + qi = &ahp->ah_txq[q]; + switch (qi->tqi_type) { + case HAL_TX_QUEUE_DATA: { + int i; + OS_REG_WRITE(ah, AR_CR, AR_CR_TXD0); + for (i = 0; i < 1000; i++) { + if ((OS_REG_READ(ah, AR_CFG) & AR_CFG_TXCNT) == 0) + break; + OS_DELAY(10); + } + OS_REG_WRITE(ah, AR_CR, 0); + return (i < 1000); + } + case HAL_TX_QUEUE_BEACON: + return ath_hal_wait(ah, AR_BSR, AR_BSR_TXQ1F, 0); + case HAL_TX_QUEUE_INACTIVE: + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: inactive queue %u\n", + __func__, q); + /* fall thru... */ + default: + break; + } + return AH_FALSE; +} + +/* + * Descriptor Access Functions + */ + +#define VALID_PKT_TYPES \ + ((1<ds_ctl0 = (pktLen & AR_FrameLen) + | (txRate0 << AR_XmitRate_S) + | ((hdrLen << AR_HdrLen_S) & AR_HdrLen) + | frtype + | (flags & HAL_TXDESC_CLRDMASK ? AR_ClearDestMask : 0) + | (flags & HAL_TXDESC_INTREQ ? AR_TxInterReq : 0) + | (antMode ? AR_AntModeXmit : 0) + ; + if (keyIx != HAL_TXKEYIX_INVALID) { + ads->ds_ctl1 = (keyIx << AR_EncryptKeyIdx_S) & AR_EncryptKeyIdx; + ads->ds_ctl0 |= AR_EncryptKeyValid; + } else + ads->ds_ctl1 = 0; + if (flags & HAL_TXDESC_RTSENA) { + ads->ds_ctl0 |= AR_RTSCTSEnable; + ads->ds_ctl1 |= rtsctsDuration & AR_RTSDuration; + } + return AH_TRUE; +} + +HAL_BOOL +ar5210SetupXTxDesc(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 +ar5210IntrReqTxDesc(struct ath_hal *ah, struct ath_desc *ds) +{ + struct ar5210_desc *ads = AR5210DESC(ds); + + ads->ds_ctl0 |= AR_TxInterReq; +} + +HAL_BOOL +ar5210FillTxDesc(struct ath_hal *ah, struct ath_desc *ds, + u_int segLen, HAL_BOOL firstSeg, HAL_BOOL lastSeg, + const struct ath_desc *ds0) +{ + struct ar5210_desc *ads = AR5210DESC(ds); + + HALASSERT((segLen &~ AR_BufLen) == 0); + + if (firstSeg) { + /* + * First descriptor, don't clobber xmit control data + * setup by ar5210SetupTxDesc. + */ + 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 = AR5210DESC_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 +ar5210ProcTxDesc(struct ath_hal *ah, + struct ath_desc *ds, struct ath_tx_status *ts) +{ + struct ar5210_desc *ads = AR5210DESC(ds); + + if ((ads->ds_status1 & AR_Done) == 0) + return HAL_EINPROGRESS; + + /* Update software copies of the HW status */ + ts->ts_seqnum = 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_antenna = 0; /* NB: don't know */ + ts->ts_finaltsi = 0; + + return HAL_OK; +} + +/* + * Determine which tx queues need interrupt servicing. + * STUB. + */ +void +ar5210GetTxIntrQueue(struct ath_hal *ah, uint32_t *txqs) +{ + return; +} --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5210/ar5210desc.h 2009-03-23 17:36:55.000000000 +0000 @@ -0,0 +1,130 @@ +/* + * 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: ar5210desc.h,v 1.1 2009/03/23 17:14:47 sborrill Exp $ + */ +#ifndef _DEV_ATH_AR5210DESC_H +#define _DEV_ATH_AR5210DESC_H + +#include "ah_desc.h" + +/* + * Defintions for the DMA descriptors used by the Atheros + * AR5210/AR5211 and AR5110 Wireless Lan controller parts. + */ + +/* DMA descriptors */ +struct ar5210_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 AR5210DESC(_ds) ((struct ar5210_desc *)(_ds)) +#define AR5210DESC_CONST(_ds) ((const struct ar5210_desc *)(_ds)) + +/* TX ds_ctl0 */ +#define AR_FrameLen 0x00000fff /* frame length */ +#define AR_HdrLen 0x0003f000 /* header length */ +#define AR_HdrLen_S 12 +#define AR_XmitRate 0x003c0000 /* txrate */ +#define AR_XmitRate_S 18 +#define AR_Rate_6M 0xb +#define AR_Rate_9M 0xf +#define AR_Rate_12M 0xa +#define AR_Rate_18M 0xe +#define AR_Rate_24M 0x9 +#define AR_Rate_36M 0xd +#define AR_Rate_48M 0x8 +#define AR_Rate_54M 0xc +#define AR_RTSCTSEnable 0x00400000 /* RTS/CTS enable */ +#define AR_LongPkt 0x00800000 /* long packet indication */ +#define AR_ClearDestMask 0x01000000 /* Clear destination mask bit */ +#define AR_AntModeXmit 0x02000000 /* TX antenna seslection */ +#define AR_FrmType 0x1c000000 /* frame type indication */ +#define AR_Frm_Normal 0x00000000 /* normal frame */ +#define AR_Frm_ATIM 0x04000000 /* ATIM frame */ +#define AR_Frm_PSPOLL 0x08000000 /* PS poll frame */ +#define AR_Frm_NoDelay 0x0c000000 /* no delay data */ +#define AR_Frm_PIFS 0x10000000 /* PIFS data */ +#define AR_TxInterReq 0x20000000 /* TX interrupt request */ +#define AR_EncryptKeyValid 0x40000000 /* EncryptKeyIdx is valid */ + +/* TX ds_ctl1 */ +#define AR_BufLen 0x00000fff /* data buffer length */ +#define AR_More 0x00001000 /* more desc in this frame */ +#define AR_EncryptKeyIdx 0x0007e000 /* ecnrypt key table index */ +#define AR_EncryptKeyIdx_S 13 +#define AR_RTSDuration 0xfff80000 /* lower 13bit of duration */ + +/* RX ds_ctl1 */ +/* AR_BufLen 0x00000fff data buffer length */ +#define AR_RxInterReq 0x00002000 /* RX interrupt request */ + +/* 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_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 */ +#define AR_RcvAntenna 0x00004000 /* received on ant 1 */ +#define AR_RcvRate 0x00078000 /* reception rate */ +#define AR_RcvRate_S 15 +#define AR_RcvSigStrength 0x07f80000 /* receive signal strength */ +#define AR_RcvSigStrength_S 19 + +/* TX ds_status1 */ +#define AR_Done 0x00000001 /* descripter complete */ +#define AR_SeqNum 0x00001ffe /* TX sequence number */ +#define AR_AckSigStrength 0x001fe000 /* strength of ACK */ +#define AR_AckSigStrength_S 13 + +/* RX ds_status1 */ +/* AR_Done 0x00000001 descripter complete */ +#define AR_FrmRcvOK 0x00000002 /* frame reception success */ +#define AR_CRCErr 0x00000004 /* CRC error */ +#define AR_FIFOOverrun 0x00000008 /* RX FIFO overrun */ +#define AR_DecryptCRCErr 0x00000010 /* Decryption CRC fiailure */ +#define AR_PHYErr 0x000000e0 /* PHY error */ +#define AR_PHYErr_S 5 +#define AR_PHYErr_NoErr 0x00000000 /* No error */ +#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_QAM 0x000000a0 /* 64 QAM rate */ +#define AR_PHYErr_Srv 0x000000c0 /* Service bit error */ +#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_AR5210DESC_H_ */ --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5210/ar5210phy.h 2009-03-23 17:36:55.000000000 +0000 @@ -0,0 +1,59 @@ +/* + * 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: ar5210phy.h,v 1.1 2009/03/23 17:14:47 sborrill Exp $ + */ +#ifndef _DEV_ATH_AR5210PHY_H +#define _DEV_ATH_AR5210PHY_H + +/* + * Definitions for the PHY on the Atheros AR5210 parts. + */ + +/* PHY Registers */ +#define AR_PHY_BASE 0x9800 /* PHY register base */ +#define AR_PHY(_n) (AR_PHY_BASE + ((_n)<<2)) + +#define AR_PHY_FRCTL 0x9804 /* PHY frame control */ +#define AR_PHY_TURBO_MODE 0x00000001 /* PHY turbo mode */ +#define AR_PHY_TURBO_SHORT 0x00000002 /* PHY turbo short symbol */ +#define AR_PHY_TIMING_ERR 0x01000000 /* Detect PHY timing error */ +#define AR_PHY_PARITY_ERR 0x02000000 /* Detect signal parity err */ +#define AR_PHY_ILLRATE_ERR 0x04000000 /* Detect PHY illegal rate */ +#define AR_PHY_ILLLEN_ERR 0x08000000 /* Detect PHY illegal length */ +#define AR_PHY_SERVICE_ERR 0x20000000 /* Detect PHY nonzero service */ +#define AR_PHY_TXURN_ERR 0x40000000 /* DetectPHY TX underrun */ +#define AR_PHY_FRCTL_BITS \ + "\20\1TURBO_MODE\2TURBO_SHORT\30TIMING_ERR\31PARITY_ERR\32ILLRATE_ERR"\ + "\33ILLEN_ERR\35SERVICE_ERR\36TXURN_ERR" + +#define AR_PHY_AGC 0x9808 /* PHY AGC command */ +#define AR_PHY_AGC_DISABLE 0x08000000 /* Disable PHY AGC */ +#define AR_PHY_AGC_BITS "\20\33DISABLE" + +#define AR_PHY_CHIPID 0x9818 /* PHY chip revision */ + +#define AR_PHY_ACTIVE 0x981c /* PHY activation */ +#define AR_PHY_ENABLE 0x00000001 /* activate PHY */ +#define AR_PHY_DISABLE 0x00000002 /* deactivate PHY */ +#define AR_PHY_ACTIVE_BITS "\20\1ENABLE\2DISABLE" + +#define AR_PHY_AGCCTL 0x9860 /* PHY calibration and noise floor */ +#define AR_PHY_AGC_CAL 0x00000001 /* PHY internal calibration */ +#define AR_PHY_AGC_NF 0x00000002 /* calc PHY noise-floor */ +#define AR_PHY_AGCCTL_BITS "\20\1CAL\2NF" + +#endif /* _DEV_ATH_AR5210PHY_H */ --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5210/ar5210reg.h 2009-03-23 17:36:55.000000000 +0000 @@ -0,0 +1,401 @@ +/* + * 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: ar5210reg.h,v 1.1 2009/03/23 17:14:47 sborrill Exp $ + */ +#ifndef _DEV_ATH_AR5210REG_H +#define _DEV_ATH_AR5210REG_H + +/* + * Register defintions for the Atheros AR5210/5110 MAC/Basedband + * Processor for IEEE 802.11a 5-GHz Wireless LANs. + */ + +#ifndef PCI_VENDOR_ATHEROS +#define PCI_VENDOR_ATHEROS 0x168c +#endif +#define PCI_PRODUCT_ATHEROS_AR5210 0x0007 +#define PCI_PRODUCT_ATHEROS_AR5210_OLD 0x0004 + +/* DMA Registers */ +#define AR_TXDP0 0x0000 /* TX queue pointer 0 register */ +#define AR_TXDP1 0x0004 /* TX queue pointer 1 register */ +#define AR_CR 0x0008 /* Command register */ +#define AR_RXDP 0x000c /* RX queue descriptor ptr register */ +#define AR_CFG 0x0014 /* Configuration and status register */ +#define AR_ISR 0x001c /* Interrupt status register */ +#define AR_IMR 0x0020 /* Interrupt mask register */ +#define AR_IER 0x0024 /* Interrupt global enable register */ +#define AR_BCR 0x0028 /* Beacon control register */ +#define AR_BSR 0x002c /* Beacon status register */ +#define AR_TXCFG 0x0030 /* TX configuration register */ +#define AR_RXCFG 0x0034 /* RX configuration register */ +#define AR_MIBC 0x0040 /* MIB control register */ +#define AR_TOPS 0x0044 /* Timeout prescale register */ +#define AR_RXNOFRM 0x0048 /* RX no frame timeout register */ +#define AR_TXNOFRM 0x004c /* TX no frame timeout register */ +#define AR_RPGTO 0x0050 /* RX frame gap timeout register */ +#define AR_RFCNT 0x0054 /* RX frame count limit register */ +#define AR_MISC 0x0058 /* Misc control and status register */ +#define AR_RC 0x4000 /* Reset control */ +#define AR_SCR 0x4004 /* Sleep control */ +#define AR_INTPEND 0x4008 /* Interrupt pending */ +#define AR_SFR 0x400c /* Force sleep */ +#define AR_PCICFG 0x4010 /* PCI configuration */ +#define AR_GPIOCR 0x4014 /* GPIO configuration */ +#define AR_GPIODO 0x4018 /* GPIO data output */ +#define AR_GPIODI 0x401c /* GPIO data input */ +#define AR_SREV 0x4020 /* Silicon revision */ +/* EEPROM Access Registers */ +#define AR_EP_AIR_BASE 0x6000 /* EEPROM access initiation regs base */ +#define AR_EP_AIR(n) (AR_EP_AIR_BASE + (n)*4) +#define AR_EP_RDATA 0x6800 /* EEPROM read data register */ +#define AR_EP_STA 0x6c00 /* EEPROM access status register */ +/* PCU Registers */ +#define AR_STA_ID0 0x8000 /* Lower 32bits of MAC address */ +#define AR_STA_ID1 0x8004 /* Upper 16bits of MAC address */ +#define AR_BSS_ID0 0x8008 /* Lower 32bits of BSSID */ +#define AR_BSS_ID1 0x800c /* Upper 16bits of BSSID */ +#define AR_SLOT_TIME 0x8010 /* Length of a back-off */ +#define AR_TIME_OUT 0x8014 /* Timeout to wait for ACK and CTS */ +#define AR_RSSI_THR 0x8018 /* Beacon RSSI warning threshold */ +#define AR_RETRY_LMT 0x801c /* Short and long frame retry limit */ +#define AR_USEC 0x8020 /* Transmit latency */ +#define AR_BEACON 0x8024 /* Beacon control */ +#define AR_CFP_PERIOD 0x8028 /* CFP period */ +#define AR_TIMER0 0x802c /* Next beacon time */ +#define AR_TIMER1 0x8030 /* Next DMA beacon alert time */ +#define AR_TIMER2 0x8034 /* Next software beacon alert time */ +#define AR_TIMER3 0x8038 /* Next ATIM window time */ +#define AR_IFS0 0x8040 /* Protocol timers */ +#define AR_IFS1 0x8044 /* Protocol time and control */ +#define AR_CFP_DUR 0x8048 /* Maximum CFP duration */ +#define AR_RX_FILTER 0x804c /* Receive filter */ +#define AR_MCAST_FIL0 0x8050 /* Lower 32bits of mcast filter mask */ +#define AR_MCAST_FIL1 0x8054 /* Upper 16bits of mcast filter mask */ +#define AR_TX_MASK0 0x8058 /* Lower 32bits of TX mask */ +#define AR_TX_MASK1 0x805c /* Upper 16bits of TX mask */ +#define AR_CLR_TMASK 0x8060 /* Clear TX mask */ +#define AR_TRIG_LEV 0x8064 /* Minimum FIFO fill level before TX */ +#define AR_DIAG_SW 0x8068 /* PCU control */ +#define AR_TSF_L32 0x806c /* Lower 32bits of local clock */ +#define AR_TSF_U32 0x8070 /* Upper 32bits of local clock */ +#define AR_LAST_TSTP 0x8080 /* Lower 32bits of last beacon tstamp */ +#define AR_RETRY_CNT 0x8084 /* Current short or long retry cnt */ +#define AR_BACKOFF 0x8088 /* Back-off status */ +#define AR_NAV 0x808c /* Current NAV value */ +#define AR_RTS_OK 0x8090 /* RTS success counter */ +#define AR_RTS_FAIL 0x8094 /* RTS failure counter */ +#define AR_ACK_FAIL 0x8098 /* ACK failure counter */ +#define AR_FCS_FAIL 0x809c /* FCS failure counter */ +#define AR_BEACON_CNT 0x80a0 /* Valid beacon counter */ +#define AR_KEYTABLE_0 0x9000 /* Encryption key table */ +#define AR_KEYTABLE(n) (AR_KEYTABLE_0 + ((n)*32)) + +#define AR_CR_TXE0 0x00000001 /* TX queue 0 enable */ +#define AR_CR_TXE1 0x00000002 /* TX queue 1 enable */ +#define AR_CR_RXE 0x00000004 /* RX enable */ +#define AR_CR_TXD0 0x00000008 /* TX queue 0 disable */ +#define AR_CR_TXD1 0x00000010 /* TX queue 1 disable */ +#define AR_CR_RXD 0x00000020 /* RX disable */ +#define AR_CR_SWI 0x00000040 /* software interrupt */ +#define AR_CR_BITS \ + "\20\1TXE0\2TXE1\3RXE\4TXD0\5TXD1\6RXD\7SWI" + +#define AR_CFG_SWTD 0x00000001 /* BE for TX desc */ +#define AR_CFG_SWTB 0x00000002 /* BE for TX data */ +#define AR_CFG_SWRD 0x00000004 /* BE for RX desc */ +#define AR_CFG_SWRB 0x00000008 /* BE for RX data */ +#define AR_CFG_SWRG 0x00000010 /* BE for registers */ +#define AR_CFG_EEBS 0x00000200 /* EEPROM busy */ +#define AR_CFG_TXCNT 0x00007800 /* number of TX desc in Q */ +#define AR_CFG_TXCNT_S 11 +#define AR_CFG_TXFSTAT 0x00008000 /* TX DMA status */ +#define AR_CFG_TXFSTRT 0x00010000 /* re-enable TX DMA */ +#define AR_CFG_BITS \ + "\20\1SWTD\2SWTB\3SWRD\4SWRB\5SWRG\14EEBS\17TXFSTAT\20TXFSTRT" + +#define AR_ISR_RXOK_INT 0x00000001 /* RX frame OK */ +#define AR_ISR_RXDESC_INT 0x00000002 /* RX intr request */ +#define AR_ISR_RXERR_INT 0x00000004 /* RX error */ +#define AR_ISR_RXNOFRM_INT 0x00000008 /* no frame received */ +#define AR_ISR_RXEOL_INT 0x00000010 /* RX desc empty */ +#define AR_ISR_RXORN_INT 0x00000020 /* RX fifo overrun */ +#define AR_ISR_TXOK_INT 0x00000040 /* TX frame OK */ +#define AR_ISR_TXDESC_INT 0x00000080 /* TX intr request */ +#define AR_ISR_TXERR_INT 0x00000100 /* TX error */ +#define AR_ISR_TXNOFRM_INT 0x00000200 /* no frame transmitted */ +#define AR_ISR_TXEOL_INT 0x00000400 /* TX desc empty */ +#define AR_ISR_TXURN_INT 0x00000800 /* TX fifo underrun */ +#define AR_ISR_MIB_INT 0x00001000 /* MIB interrupt */ +#define AR_ISR_SWI_INT 0x00002000 /* software interrupt */ +#define AR_ISR_RXPHY_INT 0x00004000 /* PHY RX error */ +#define AR_ISR_RXKCM_INT 0x00008000 /* Key cache miss */ +#define AR_ISR_SWBA_INT 0x00010000 /* software beacon alert */ +#define AR_ISR_BRSSI_INT 0x00020000 /* beacon threshold */ +#define AR_ISR_BMISS_INT 0x00040000 /* beacon missed */ +#define AR_ISR_MCABT_INT 0x00100000 /* master cycle abort */ +#define AR_ISR_SSERR_INT 0x00200000 /* SERR on PCI */ +#define AR_ISR_DPERR_INT 0x00400000 /* Parity error on PCI */ +#define AR_ISR_GPIO_INT 0x01000000 /* GPIO interrupt */ +#define AR_ISR_BITS \ + "\20\1RXOK\2RXDESC\3RXERR\4RXNOFM\5RXEOL\6RXORN\7TXOK\10TXDESC"\ + "\11TXERR\12TXNOFRM\13TXEOL\14TXURN\15MIB\16SWI\17RXPHY\20RXKCM"\ + "\21SWBA\22BRSSI\23BMISS\24MCABT\25SSERR\26DPERR\27GPIO" + +#define AR_IMR_RXOK_INT 0x00000001 /* RX frame OK */ +#define AR_IMR_RXDESC_INT 0x00000002 /* RX intr request */ +#define AR_IMR_RXERR_INT 0x00000004 /* RX error */ +#define AR_IMR_RXNOFRM_INT 0x00000008 /* no frame received */ +#define AR_IMR_RXEOL_INT 0x00000010 /* RX desc empty */ +#define AR_IMR_RXORN_INT 0x00000020 /* RX fifo overrun */ +#define AR_IMR_TXOK_INT 0x00000040 /* TX frame OK */ +#define AR_IMR_TXDESC_INT 0x00000080 /* TX intr request */ +#define AR_IMR_TXERR_INT 0x00000100 /* TX error */ +#define AR_IMR_TXNOFRM_INT 0x00000200 /* no frame transmitted */ +#define AR_IMR_TXEOL_INT 0x00000400 /* TX desc empty */ +#define AR_IMR_TXURN_INT 0x00000800 /* TX fifo underrun */ +#define AR_IMR_MIB_INT 0x00001000 /* MIB interrupt */ +#define AR_IMR_SWI_INT 0x00002000 /* software interrupt */ +#define AR_IMR_RXPHY_INT 0x00004000 /* PHY RX error */ +#define AR_IMR_RXKCM_INT 0x00008000 /* Key cache miss */ +#define AR_IMR_SWBA_INT 0x00010000 /* software beacon alert */ +#define AR_IMR_BRSSI_INT 0x00020000 /* beacon threshold */ +#define AR_IMR_BMISS_INT 0x00040000 /* beacon missed */ +#define AR_IMR_MCABT_INT 0x00100000 /* master cycle abort */ +#define AR_IMR_SSERR_INT 0x00200000 /* SERR on PCI */ +#define AR_IMR_DPERR_INT 0x00400000 /* Parity error on PCI */ +#define AR_IMR_GPIO_INT 0x01000000 /* GPIO interrupt */ +#define AR_IMR_BITS AR_ISR_BITS + +#define AR_IER_DISABLE 0x00000000 /* pseudo-flag */ +#define AR_IER_ENABLE 0x00000001 /* global interrupt enable */ +#define AR_IER_BITS "\20\1ENABLE" + +#define AR_BCR_BCMD 0x00000001 /* ad hoc beacon mode */ +#define AR_BCR_BDMAE 0x00000002 /* beacon DMA enable */ +#define AR_BCR_TQ1FV 0x00000004 /* use TXQ1 for non-beacon */ +#define AR_BCR_TQ1V 0x00000008 /* TXQ1 valid for beacon */ +#define AR_BCR_BCGET 0x00000010 /* force a beacon fetch */ +#define AR_BCR_BITS "\20\1BCMD\2BDMAE\3TQ1FV\4TQ1V\5BCGET" + +#define AR_BSR_BDLYSW 0x00000001 /* software beacon delay */ +#define AR_BSR_BDLYDMA 0x00000002 /* DMA beacon delay */ +#define AR_BSR_TXQ1F 0x00000004 /* TXQ1 fetch */ +#define AR_BSR_ATIMDLY 0x00000008 /* ATIM delay */ +#define AR_BSR_SNPBCMD 0x00000100 /* snapshot of BCMD */ +#define AR_BSR_SNPBDMAE 0x00000200 /* snapshot of BDMAE */ +#define AR_BSR_SNPTQ1FV 0x00000400 /* snapshot of TQ1FV */ +#define AR_BSR_SNPTQ1V 0x00000800 /* snapshot of TQ1V */ +#define AR_BSR_SNAPPEDBCRVALID 0x00001000 /* snapshot of BCR are valid */ +#define AR_BSR_SWBA_CNT 0x00ff0000 /* software beacon alert cnt */ +#define AR_BSR_BITS \ + "\20\1BDLYSW\2BDLYDMA\3TXQ1F\4ATIMDLY\11SNPBCMD\12SNPBDMAE"\ + "\13SNPTQ1FV\14SNPTQ1V\15SNAPPEDBCRVALID" + +#define AR_TXCFG_SDMAMR 0x00000007 /* DMA burst size 2^(2+x) */ +#define AR_TXCFG_TXFSTP 0x00000008 /* Stop TX DMA on filtered */ +#define AR_TXCFG_TXFULL 0x00000070 /* TX DMA desc Q full thresh */ +#define AR_TXCFG_TXCONT_EN 0x00000080 /* Enable continuous TX mode */ +#define AR_TXCFG_BITS "\20\3TXFSTP\7TXCONT_EN" + +#define AR_RXCFG_SDMAMW 0x00000007 /* DMA burst size 2^(2+x) */ +#define AR_RXCFG_ZLFDMA 0x00000010 /* enable zero length DMA */ + +/* DMA sizes used for both AR_TXCFG_SDMAMR and AR_RXCFG_SDMAMW */ +#define AR_DMASIZE_4B 0 /* DMA size 4 bytes */ +#define AR_DMASIZE_8B 1 /* DMA size 8 bytes */ +#define AR_DMASIZE_16B 2 /* DMA size 16 bytes */ +#define AR_DMASIZE_32B 3 /* DMA size 32 bytes */ +#define AR_DMASIZE_64B 4 /* DMA size 64 bytes */ +#define AR_DMASIZE_128B 5 /* DMA size 128 bytes */ +#define AR_DMASIZE_256B 6 /* DMA size 256 bytes */ +#define AR_DMASIZE_512B 7 /* DMA size 512 bytes */ + +#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 */ + +#define AR_RFCNT_RFCL 0x0000000f /* RX frame count limit */ + +#define AR_MISC_LED_DECAY 0x001c0000 /* LED decay rate */ +#define AR_MISC_LED_BLINK 0x00e00000 /* LED blink rate */ + +#define AR_RC_RPCU 0x00000001 /* PCU Warm Reset */ +#define AR_RC_RDMA 0x00000002 /* DMA Warm Reset */ +#define AR_RC_RMAC 0x00000004 /* MAC Warm Reset */ +#define AR_RC_RPHY 0x00000008 /* PHY Warm Reset */ +#define AR_RC_RPCI 0x00000010 /* PCI Core Warm Reset */ +#define AR_RC_BITS "\20\1RPCU\2RDMA\3RMAC\4RPHY\5RPCI" + +#define AR_SCR_SLDUR 0x0000ffff /* sleep duration */ +#define AR_SCR_SLE 0x00030000 /* sleep enable */ +#define AR_SCR_SLE_S 16 +#define AR_SCR_SLE_WAKE 0x00000000 /* force wake */ +#define AR_SCR_SLE_SLP 0x00010000 /* force sleep */ +#define AR_SCR_SLE_ALLOW 0x00020000 /* allow to control sleep */ +#define AR_SCR_BITS "\20\20SLE_SLP\21SLE_ALLOW" + +#define AR_INTPEND_IP 0x00000001 /* interrupt pending */ +#define AR_INTPEND_BITS "\20\1IP" + +#define AR_SFR_SF 0x00000001 /* force sleep immediately */ + +#define AR_PCICFG_EEPROMSEL 0x00000001 /* EEPROM access enable */ +#define AR_PCICFG_CLKRUNEN 0x00000004 /* CLKRUN enable */ +#define AR_PCICFG_LED_PEND 0x00000020 /* LED for assoc pending */ +#define AR_PCICFG_LED_ACT 0x00000040 /* LED for assoc active */ +#define AR_PCICFG_SL_INTEN 0x00000800 /* Enable sleep intr */ +#define AR_PCICFG_LED_BCTL 0x00001000 /* LED blink for local act */ +#define AR_PCICFG_SL_INPEN 0x00002800 /* sleep even intr pending */ +#define AR_PCICFG_SPWR_DN 0x00010000 /* sleep indication */ +#define AR_PCICFG_BITS \ + "\20\1EEPROMSEL\3CLKRUNEN\5LED_PEND\6LED_ACT\13SL_INTEN"\ + "\14LED_BCTL\20SPWR_DN" + +#define AR_GPIOCR_IN(n) (0<<((n)*2)) /* input-only */ +#define AR_GPIOCR_OUT0(n) (1<<((n)*2)) /* output-only if GPIODO = 0 */ +#define AR_GPIOCR_OUT1(n) (2<<((n)*2)) /* output-only if GPIODO = 1 */ +#define AR_GPIOCR_OUT(n) (3<<((n)*2)) /* always output */ +#define AR_GPIOCR_ALL(n) (3<<((n)*2)) /* all bits for pin */ +#define AR_GPIOCR_INT_SEL(n) ((n)<<12) /* GPIO interrupt pin select */ +#define AR_GPIOCR_INT_ENA 0x00008000 /* Enable GPIO interrupt */ +#define AR_GPIOCR_INT_SELL 0x00000000 /* Interrupt if pin is low */ +#define AR_GPIOCR_INT_SELH 0x00010000 /* Interrupt if pin is high */ + +#define AR_SREV_CRETE 4 /* Crete 1st version */ +#define AR_SREV_CRETE_MS 5 /* Crete FCS version */ +#define AR_SREV_CRETE_23 8 /* Crete version 2.3 */ + +#define AR_EP_STA_RDERR 0x00000001 /* read error */ +#define AR_EP_STA_RDCMPLT 0x00000002 /* read complete */ +#define AR_EP_STA_WRERR 0x00000004 /* write error */ +#define AR_EP_STA_WRCMPLT 0x00000008 /* write complete */ +#define AR_EP_STA_BITS \ + "\20\1RDERR\2RDCMPLT\3WRERR\4WRCMPLT" + +#define AR_STA_ID1_AP 0x00010000 /* Access Point Operation */ +#define AR_STA_ID1_ADHOC 0x00020000 /* ad hoc Operation */ +#define AR_STA_ID1_PWR_SV 0x00040000 /* power save report enable */ +#define AR_STA_ID1_NO_KEYSRCH 0x00080000 /* key table search disable */ +#define AR_STA_ID1_NO_PSPOLL 0x00100000 /* auto PS-POLL disable */ +#define AR_STA_ID1_PCF 0x00200000 /* PCF observation enable */ +#define AR_STA_ID1_DESC_ANTENNA 0x00400000 /* use antenna in TX desc */ +#define AR_STA_ID1_DEFAULT_ANTENNA 0x00800000 /* toggle default antenna */ +#define AR_STA_ID1_ACKCTS_6MB 0x01000000 /* use 6Mbps for ACK/CTS */ +#define AR_STA_ID1_BITS \ + "\20\20AP\21ADHOC\22PWR_SV\23NO_KEYSRCH\24NO_PSPOLL\25PCF"\ + "\26DESC_ANTENNA\27DEFAULT_ANTENNA\30ACKCTS_6MB" + +#define AR_BSS_ID1_AID 0xffff0000 /* association ID */ +#define AR_BSS_ID1_AID_S 16 + +#define AR_TIME_OUT_ACK 0x00001fff /* ACK timeout */ +#define AR_TIME_OUT_ACK_S 0 +#define AR_TIME_OUT_CTS 0x1fff0000 /* CTS timeout */ +#define AR_TIME_OUT_CTS_S 16 + +#define AR_RSSI_THR_BM_THR 0x00000700 /* missed beacon threshold */ +#define AR_RSSI_THR_BM_THR_S 8 + +#define AR_RETRY_LMT_SH_RETRY 0x0000000f /* short frame retry limit */ +#define AR_RETRY_LMT_SH_RETRY_S 0 +#define AR_RETRY_LMT_LG_RETRY 0x000000f0 /* long frame retry limit */ +#define AR_RETRY_LMT_LG_RETRY_S 4 +#define AR_RETRY_LMT_SSH_RETRY 0x00003f00 /* short station retry limit */ +#define AR_RETRY_LMT_SSH_RETRY_S 8 +#define AR_RETRY_LMT_SLG_RETRY 0x000fc000 /* long station retry limit */ +#define AR_RETRY_LMT_SLG_RETRY_S 14 +#define AR_RETRY_LMT_CW_MIN 0x3ff00000 /* minimum contention window */ +#define AR_RETRY_LMT_CW_MIN_S 20 + +#define AR_USEC_1 0x0000007f /* number of clk in 1us */ +#define AR_USEC_1_S 0 +#define AR_USEC_32 0x00003f80 /* number of 32MHz clk in 1us */ +#define AR_USEC_32_S 7 +#define AR_USEC_TX_LATENCY 0x000fc000 /* transmit latency in us */ +#define AR_USEC_TX_LATENCY_S 14 +#define AR_USEC_RX_LATENCY 0x03f00000 /* receive latency in us */ +#define AR_USEC_RX_LATENCY_S 20 + +#define AR_BEACON_PERIOD 0x0000ffff /* beacon period in TU/ms */ +#define AR_BEACON_PERIOD_S 0 +#define AR_BEACON_TIM 0x007f0000 /* byte offset */ +#define AR_BEACON_TIM_S 16 +#define AR_BEACON_EN 0x00800000 /* beacon transmission enable */ +#define AR_BEACON_RESET_TSF 0x01000000 /* TSF reset oneshot */ +#define AR_BEACON_BITS "\20\27ENABLE\30RESET_TSF" + +#define AR_IFS0_SIFS 0x000007ff /* SIFS in core clock cycles */ +#define AR_IFS0_SIFS_S 0 +#define AR_IFS0_DIFS 0x007ff800 /* DIFS in core clock cycles */ +#define AR_IFS0_DIFS_S 11 + +#define AR_IFS1_PIFS 0x00000fff /* Programmable IFS */ +#define AR_IFS1_PIFS_S 0 +#define AR_IFS1_EIFS 0x03fff000 /* EIFS in core clock cycles */ +#define AR_IFS1_EIFS_S 12 +#define AR_IFS1_CS_EN 0x04000000 /* carrier sense enable */ + +#define AR_RX_FILTER_UNICAST 0x00000001 /* unicast frame enable */ +#define AR_RX_FILTER_MULTICAST 0x00000002 /* multicast frame enable */ +#define AR_RX_FILTER_BROADCAST 0x00000004 /* broadcast frame enable */ +#define AR_RX_FILTER_CONTROL 0x00000008 /* control frame enable */ +#define AR_RX_FILTER_BEACON 0x00000010 /* beacon frame enable */ +#define AR_RX_FILTER_PROMISCUOUS 0x00000020 /* promiscuous receive enable */ +#define AR_RX_FILTER_BITS \ + "\20\1UCAST\2MCAST\3BCAST\4CONTROL\5BEACON\6PROMISC" + +#define AR_DIAG_SW_DIS_WEP_ACK 0x00000001 /* disable ACK if no key found*/ +#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_ENC 0x00000008 /* encryption disable */ +#define AR_DIAG_SW_DIS_DEC 0x00000010 /* decryption disable */ +#define AR_DIAG_SW_DIS_TX 0x00000020 /* TX disable */ +#define AR_DIAG_SW_DIS_RX 0x00000040 /* RX disable */ +#define AR_DIAG_SW_LOOP_BACK 0x00000080 /* TX data loopback enable */ +#define AR_DIAG_SW_CORR_FCS 0x00000100 /* corrupt FCS enable */ +#define AR_DIAG_SW_CHAN_INFO 0x00000200 /* channel information enable */ +#define AR_DIAG_SW_EN_SCRAM_SEED 0x00000400 /* use fixed scrambler seed */ +#define AR_DIAG_SW_SCVRAM_SEED 0x0003f800 /* fixed scrambler seed */ +#define AR_DIAG_SW_DIS_SEQ_INC 0x00040000 /* seq increment disable */ +#define AR_DIAG_SW_FRAME_NV0 0x00080000 /* accept frame vers != 0 */ +#define AR_DIAG_SW_BITS \ + "\20\1DIS_WEP_ACK\2DIS_ACK\3DIS_CTS\4DIS_ENC\5DIS_DEC\6DIS_TX"\ + "\7DIS_RX\10LOOP_BACK\11CORR_FCS\12CHAN_INFO\13EN_SCRAM_SEED"\ + "\22DIS_SEQ_INC\24FRAME_NV0" + +#define AR_RETRY_CNT_SSH 0x0000003f /* current short retry count */ +#define AR_RETRY_CNT_SLG 0x00000fc0 /* current long retry count */ + +#define AR_BACKOFF_CW 0x000003ff /* current contention window */ +#define AR_BACKOFF_CNT 0x03ff0000 /* backoff count */ + +#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 /* 40 bit key */ +#define AR_KEYTABLE_TYPE_104 0x00000001 /* 104 bit key */ +#define AR_KEYTABLE_TYPE_128 0x00000003 /* 128 bit key */ +#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_AR5210REG_H */ --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5210/ar5k_0007.ini 2009-03-23 17:36:55.000000000 +0000 @@ -0,0 +1,194 @@ +/* + * 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: ar5k_0007.ini,v 1.1 2009/03/23 17:14:47 sborrill Exp $ + */ + + /* crete register init */ + { 0x00009800, 0x00000047 }, + { 0x00009808, 0x00000000 }, + { 0x0000980c, 0x09848ea6 }, + { 0x00009810, 0x3d32e000 }, + { 0x00009814, 0x0000076b }, + { 0x0000981c, 0x00000000 }, + { 0x00009820, 0x02020200 }, + { 0x00009824, 0x00000e0e }, + { 0x00009828, 0x0a020201 }, + { 0x0000982c, 0x00036ffc }, + { 0x00009830, 0x00000000 }, + { 0x00009834, 0x00000e0e }, + { 0x00009838, 0x00000007 }, + { 0x0000983c, 0x00020100 }, + { 0x00009840, 0x89630000 }, + { 0x00009844, 0x1372169c }, + { 0x00009848, 0x0018b633 }, + { 0x0000984c, 0x1284613c }, + { 0x00009850, 0x0de8b8e0 }, + { 0x00009854, 0x00074859 }, + { 0x00009858, 0x7e80beba }, + { 0x0000985c, 0x313a665e }, + { 0x00009860, 0x00001d08 }, + { 0x00009864, 0x0001ce00 }, + { 0x00009868, 0x409a4190 }, + { 0x00009870, 0x0000000f }, + { 0x00009874, 0x00000080 }, + { 0x00009878, 0x00000004 }, + { 0x00009900, 0x00000000 }, + { 0x00009904, 0x00000000 }, + { 0x00009908, 0x00000000 }, + { 0x0000990c, 0x00800000 }, + { 0x00009910, 0x00000003 }, + + + /* bb gain table */ + { 0x00009b00, 0x00000000 }, + { 0x00009b04, 0x00000020 }, + { 0x00009b08, 0x00000010 }, + { 0x00009b0c, 0x00000030 }, + { 0x00009b10, 0x00000008 }, + { 0x00009b14, 0x00000028 }, + { 0x00009b18, 0x00000028 }, + { 0x00009b1c, 0x00000004 }, + { 0x00009b20, 0x00000024 }, + { 0x00009b24, 0x00000014 }, + { 0x00009b28, 0x00000034 }, + { 0x00009b2c, 0x0000000c }, + { 0x00009b30, 0x0000002c }, + { 0x00009b34, 0x00000002 }, + { 0x00009b38, 0x00000022 }, + { 0x00009b3c, 0x00000012 }, + { 0x00009b40, 0x00000032 }, + { 0x00009b44, 0x0000000a }, + { 0x00009b48, 0x0000002a }, + { 0x00009b4c, 0x00000001 }, + { 0x00009b50, 0x00000021 }, + { 0x00009b54, 0x00000011 }, + { 0x00009b58, 0x00000031 }, + { 0x00009b5c, 0x00000009 }, + { 0x00009b60, 0x00000029 }, + { 0x00009b64, 0x00000005 }, + { 0x00009b68, 0x00000025 }, + { 0x00009b6c, 0x00000015 }, + { 0x00009b70, 0x00000035 }, + { 0x00009b74, 0x0000000d }, + { 0x00009b78, 0x0000002d }, + { 0x00009b7c, 0x00000003 }, + { 0x00009b80, 0x00000023 }, + { 0x00009b84, 0x00000013 }, + { 0x00009b88, 0x00000033 }, + { 0x00009b8c, 0x0000000b }, + { 0x00009b90, 0x0000002b }, + { 0x00009b94, 0x00000007 }, + { 0x00009b98, 0x00000027 }, + { 0x00009b9c, 0x00000017 }, + { 0x00009ba0, 0x00000037 }, + { 0x00009ba4, 0x0000000f }, + { 0x00009ba8, 0x0000002f }, + { 0x00009bac, 0x0000002f }, + { 0x00009bb0, 0x0000002f }, + { 0x00009bb4, 0x0000002f }, + { 0x00009bb8, 0x0000002f }, + { 0x00009bbc, 0x0000002f }, + { 0x00009bc0, 0x0000002f }, + { 0x00009bc4, 0x0000002f }, + { 0x00009bc8, 0x0000002f }, + { 0x00009bcc, 0x0000002f }, + { 0x00009bd0, 0x0000002f }, + { 0x00009bd4, 0x0000002f }, + { 0x00009bd8, 0x0000002f }, + { 0x00009bdc, 0x0000002f }, + { 0x00009be0, 0x0000002f }, + { 0x00009be4, 0x0000002f }, + { 0x00009be8, 0x0000002f }, + { 0x00009bec, 0x0000002f }, + { 0x00009bf0, 0x0000002f }, + { 0x00009bf4, 0x0000002f }, + { 0x00009bf8, 0x0000002f }, + { 0x00009bfc, 0x0000002f }, + + /* rf gain table */ + { 0x00009a00, 0x0000001d }, + { 0x00009a04, 0x0000005d }, + { 0x00009a08, 0x0000009d }, + { 0x00009a0c, 0x000000dd }, + { 0x00009a10, 0x0000011d }, + { 0x00009a14, 0x00000021 }, + { 0x00009a18, 0x00000061 }, + { 0x00009a1c, 0x000000a1 }, + { 0x00009a20, 0x000000e1 }, + { 0x00009a24, 0x00000031 }, + { 0x00009a28, 0x00000071 }, + { 0x00009a2c, 0x000000b1 }, + { 0x00009a30, 0x0000001c }, + { 0x00009a34, 0x0000005c }, + { 0x00009a38, 0x00000029 }, + { 0x00009a3c, 0x00000069 }, + { 0x00009a40, 0x000000a9 }, + { 0x00009a44, 0x00000020 }, + { 0x00009a48, 0x00000019 }, + { 0x00009a4c, 0x00000059 }, + { 0x00009a50, 0x00000099 }, + { 0x00009a54, 0x00000030 }, + { 0x00009a58, 0x00000005 }, + { 0x00009a5c, 0x00000025 }, + { 0x00009a60, 0x00000065 }, + { 0x00009a64, 0x000000a5 }, + { 0x00009a68, 0x00000028 }, + { 0x00009a6c, 0x00000068 }, + { 0x00009a70, 0x0000001f }, + { 0x00009a74, 0x0000001e }, + { 0x00009a78, 0x00000018 }, + { 0x00009a7c, 0x00000058 }, + { 0x00009a80, 0x00000098 }, + { 0x00009a84, 0x00000003 }, + { 0x00009a88, 0x00000004 }, + { 0x00009a8c, 0x00000044 }, + { 0x00009a90, 0x00000084 }, + { 0x00009a94, 0x00000013 }, + { 0x00009a98, 0x00000012 }, + { 0x00009a9c, 0x00000052 }, + { 0x00009aa0, 0x00000092 }, + { 0x00009aa4, 0x000000d2 }, + { 0x00009aa8, 0x0000002b }, + { 0x00009aac, 0x0000002a }, + { 0x00009ab0, 0x0000006a }, + { 0x00009ab4, 0x000000aa }, + { 0x00009ab8, 0x0000001b }, + { 0x00009abc, 0x0000001a }, + { 0x00009ac0, 0x0000005a }, + { 0x00009ac4, 0x0000009a }, + { 0x00009ac8, 0x000000da }, + { 0x00009acc, 0x00000006 }, + { 0x00009ad0, 0x00000006 }, + { 0x00009ad4, 0x00000006 }, + { 0x00009ad8, 0x00000006 }, + { 0x00009adc, 0x00000006 }, + { 0x00009ae0, 0x00000006 }, + { 0x00009ae4, 0x00000006 }, + { 0x00009ae8, 0x00000006 }, + { 0x00009aec, 0x00000006 }, + { 0x00009af0, 0x00000006 }, + { 0x00009af4, 0x00000006 }, + { 0x00009af8, 0x00000006 }, + { 0x00009afc, 0x00000006 }, + + /* fez register init */ + { 0x000098d4, 0x00000020 }, + { 0x000098cc, 0x00000004 }, + { 0x000098c8, 0x00060106 }, + { 0x0000989c, 0x0000006d }, + { 0x000098c0, 0x00000000 }, + { 0x000098d0, 0x00000014 }, --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5210/ar2133.c 2009-03-23 17:36:56.000000000 +0000 @@ -0,0 +1,466 @@ +/* + * 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: ar2133.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_v14.h" + +#include "ar5416/ar5416.h" +#include "ar5416/ar5416reg.h" +#include "ar5416/ar5416phy.h" + +#define N(a) (sizeof(a)/sizeof(a[0])) + +struct ar2133State { + RF_HAL_FUNCS base; /* public state, must be first */ + uint16_t pcdacTable[1]; + + uint32_t *Bank0Data; + uint32_t *Bank1Data; + uint32_t *Bank2Data; + uint32_t *Bank3Data; + uint32_t *Bank6Data; + uint32_t *Bank7Data; + + /* NB: Bank*Data storage follows */ +}; +#define AR2133(ah) ((struct ar2133State *) AH5212(ah)->ah_rfHal) + +#define ar5416ModifyRfBuffer ar5212ModifyRfBuffer /*XXX*/ + +extern void ar5416ModifyRfBuffer(uint32_t *rfBuf, uint32_t reg32, + uint32_t numBits, uint32_t firstBit, uint32_t column); +HAL_BOOL ar2133GetChipPowerLimits(struct ath_hal *ah, HAL_CHANNEL + *chans, uint32_t nchans); + +static HAL_BOOL ar2133GetChannelMaxMinPower(struct ath_hal *, HAL_CHANNEL *, + int16_t *maxPow,int16_t *minPow); +int16_t ar2133GetNfAdjust(struct ath_hal *ah, const HAL_CHANNEL_INTERNAL *c); + +static void +ar2133WriteRegs(struct ath_hal *ah, u_int modesIndex, u_int freqIndex, + int writes) +{ + (void) ath_hal_ini_write(ah, &AH5416(ah)->ah_ini_bb_rfgain, + freqIndex, writes); +} + +/* + * Take the MHz channel value and set the Channel value + * + * ASSUMES: Writes enabled to analog bus + */ +static HAL_BOOL +ar2133SetChannel(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; + CHAN_CENTERS centers; + + OS_MARK(ah, AH_MARK_SETCHANNEL, chan->channel); + + ar5416GetChannelCenters(ah, chan, ¢ers); + freq = centers.synth_center; + + if (freq < 4800) { + uint32_t txctl; + + if (((freq - 2192) % 5) == 0) { + channelSel = ((freq - 672) * 2 - 3040)/10; + bModeSynth = 0; + } else if (((freq - 2224) % 5) == 0) { + channelSel = ((freq - 704) * 2 - 3040) / 10; + bModeSynth = 1; + } else { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: invalid channel %u MHz\n", __func__, freq); + return AH_FALSE; + } + + channelSel = (channelSel << 2) & 0xff; + channelSel = ath_hal_reverseBits(channelSel, 8); + + txctl = OS_REG_READ(ah, AR_PHY_CCK_TX_CTRL); + if (freq == 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 ((freq % 20) == 0 && freq >= 5120) { + channelSel = ath_hal_reverseBits(((freq - 4800) / 20 << 2), 8); + if (AR_SREV_SOWL_10_OR_LATER(ah)) + aModeRefSel = ath_hal_reverseBits(3, 2); + else + aModeRefSel = ath_hal_reverseBits(1, 2); + } else if ((freq % 10) == 0) { + channelSel = ath_hal_reverseBits(((freq - 4800) / 10 << 1), 8); + if (AR_SREV_SOWL_10_OR_LATER(ah)) + aModeRefSel = ath_hal_reverseBits(2, 2); + else + aModeRefSel = ath_hal_reverseBits(1, 2); + } else if ((freq % 5) == 0) { + channelSel = ath_hal_reverseBits((freq - 4800) / 5, 8); + aModeRefSel = ath_hal_reverseBits(1, 2); + } else { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel %u MHz\n", + __func__, freq); + return AH_FALSE; + } + + reg32 = (channelSel << 8) | (aModeRefSel << 2) | (bModeSynth << 1) | + (1 << 5) | 0x1; + + OS_REG_WRITE(ah, AR_PHY(0x37), reg32); + + AH_PRIVATE(ah)->ah_curchan = chan; + return AH_TRUE; + +} + +/* + * Return a reference to the requested RF Bank. + */ +static uint32_t * +ar2133GetRfBank(struct ath_hal *ah, int bank) +{ + struct ar2133State *priv = AR2133(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 +ar2133SetRfRegs(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan, + uint16_t modesIndex, uint16_t *rfXpdGain) +{ + struct ar2133State *priv = AR2133(ah); + int writes; + + HALASSERT(priv); + + /* Setup Bank 0 Write */ + ath_hal_ini_bank_setup(priv->Bank0Data, &AH5416(ah)->ah_ini_bank0, 1); + + /* Setup Bank 1 Write */ + ath_hal_ini_bank_setup(priv->Bank1Data, &AH5416(ah)->ah_ini_bank1, 1); + + /* Setup Bank 2 Write */ + ath_hal_ini_bank_setup(priv->Bank2Data, &AH5416(ah)->ah_ini_bank2, 1); + + /* Setup Bank 3 Write */ + ath_hal_ini_bank_setup(priv->Bank3Data, &AH5416(ah)->ah_ini_bank3, modesIndex); + + /* Setup Bank 6 Write */ + ath_hal_ini_bank_setup(priv->Bank6Data, &AH5416(ah)->ah_ini_bank6, modesIndex); + + /* Only the 5 or 2 GHz OB/DB need to be set for a mode */ + if (IS_CHAN_2GHZ(chan)) { + ar5416ModifyRfBuffer(priv->Bank6Data, + ath_hal_eepromGet(ah, AR_EEP_OB_2, AH_NULL), 3, 197, 0); + ar5416ModifyRfBuffer(priv->Bank6Data, + ath_hal_eepromGet(ah, AR_EEP_DB_2, AH_NULL), 3, 194, 0); + } else { + ar5416ModifyRfBuffer(priv->Bank6Data, + ath_hal_eepromGet(ah, AR_EEP_OB_5, AH_NULL), 3, 203, 0); + ar5416ModifyRfBuffer(priv->Bank6Data, + ath_hal_eepromGet(ah, AR_EEP_DB_5, AH_NULL), 3, 200, 0); + } + /* Setup Bank 7 Setup */ + ath_hal_ini_bank_setup(priv->Bank7Data, &AH5416(ah)->ah_ini_bank7, 1); + + /* Write Analog registers */ + writes = ath_hal_ini_bank_write(ah, &AH5416(ah)->ah_ini_bank0, + priv->Bank0Data, 0); + writes = ath_hal_ini_bank_write(ah, &AH5416(ah)->ah_ini_bank1, + priv->Bank1Data, writes); + writes = ath_hal_ini_bank_write(ah, &AH5416(ah)->ah_ini_bank2, + priv->Bank2Data, writes); + writes = ath_hal_ini_bank_write(ah, &AH5416(ah)->ah_ini_bank3, + priv->Bank3Data, writes); + writes = ath_hal_ini_bank_write(ah, &AH5416(ah)->ah_ini_bank6, + priv->Bank6Data, writes); + (void) ath_hal_ini_bank_write(ah, &AH5416(ah)->ah_ini_bank7, + priv->Bank7Data, writes); + + 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 +ar2133SetPowerTable(struct ath_hal *ah, int16_t *pPowerMin, int16_t *pPowerMax, + HAL_CHANNEL_INTERNAL *chan, uint16_t *rfXpdGain) +{ + return AH_TRUE; +} + +#if 0 +static int16_t +ar2133GetMinPower(struct ath_hal *ah, 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); +} +#endif + +static HAL_BOOL +ar2133GetChannelMaxMinPower(struct ath_hal *ah, HAL_CHANNEL *chan, int16_t *maxPow, + int16_t *minPow) +{ +#if 0 + struct ath_hal_5212 *ahp = AH5212(ah); + int numChannels=0,i,last; + int totalD, totalF,totalMin; + EXPN_DATA_PER_CHANNEL_5112 *data=AH_NULL; + EEPROM_POWER_EXPN_5112 *powerArray=AH_NULL; + + *maxPow = 0; + if (IS_CHAN_A(chan)) { + powerArray = ahp->ah_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 = ahp->ah_modePowerArray5112; + data = powerArray[headerInfo11G].pDataPerChannel; + numChannels = powerArray[headerInfo11G].numChannels; + } else if (IS_CHAN_B(chan)) { + powerArray = ahp->ah_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) || + (chan->channel < data[0].channelValue) || + (chan->channel > data[numChannels-1].channelValue)) + return(AH_FALSE); + + /* 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 = ar2133GetMinPower(ah,&data[i]) - ar2133GetMinPower(ah, &data[last]); + *minPow = (int8_t) ((totalMin*(chan->channel-data[last].channelValue) + ar2133GetMinPower(ah, &data[last])*totalD)/totalD); + return (AH_TRUE); + } else { + if (chan->channel == data[i].channelValue) { + *maxPow = data[i].maxPower_t4; + *minPow = ar2133GetMinPower(ah, &data[i]); + return(AH_TRUE); + } else + return(AH_FALSE); + } +#else + *maxPow = *minPow = 0; + return AH_FALSE; +#endif +} + +static void +ar2133GetNoiseFloor(struct ath_hal *ah, int16_t nfarray[]) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + int16_t nf; + + switch (ahp->ah_rx_chainmask) { + case 0x7: + nf = MS(OS_REG_READ(ah, AR_PHY_CH2_CCA), AR_PHY_CH2_MINCCA_PWR); + if (nf & 0x100) + nf = 0 - ((nf ^ 0x1ff) + 1); + HALDEBUG(ah, HAL_DEBUG_NFCAL, + "NF calibrated [ctl] [chain 2] is %d\n", nf); + nfarray[4] = nf; + + nf = MS(OS_REG_READ(ah, AR_PHY_CH2_EXT_CCA), AR_PHY_CH2_EXT_MINCCA_PWR); + if (nf & 0x100) + nf = 0 - ((nf ^ 0x1ff) + 1); + HALDEBUG(ah, HAL_DEBUG_NFCAL, + "NF calibrated [ext] [chain 2] is %d\n", nf); + nfarray[5] = nf; + /* fall thru... */ + case 0x3: + case 0x5: + nf = MS(OS_REG_READ(ah, AR_PHY_CH1_CCA), AR_PHY_CH1_MINCCA_PWR); + if (nf & 0x100) + nf = 0 - ((nf ^ 0x1ff) + 1); + HALDEBUG(ah, HAL_DEBUG_NFCAL, + "NF calibrated [ctl] [chain 1] is %d\n", nf); + nfarray[2] = nf; + + + nf = MS(OS_REG_READ(ah, AR_PHY_CH1_EXT_CCA), AR_PHY_CH1_EXT_MINCCA_PWR); + if (nf & 0x100) + nf = 0 - ((nf ^ 0x1ff) + 1); + HALDEBUG(ah, HAL_DEBUG_NFCAL, + "NF calibrated [ext] [chain 1] is %d\n", nf); + nfarray[3] = nf; + /* fall thru... */ + case 0x1: + nf = MS(OS_REG_READ(ah, AR_PHY_CCA), AR_PHY_MINCCA_PWR); + if (nf & 0x100) + nf = 0 - ((nf ^ 0x1ff) + 1); + HALDEBUG(ah, HAL_DEBUG_NFCAL, + "NF calibrated [ctl] [chain 0] is %d\n", nf); + nfarray[0] = nf; + + nf = MS(OS_REG_READ(ah, AR_PHY_EXT_CCA), AR_PHY_EXT_MINCCA_PWR); + if (nf & 0x100) + nf = 0 - ((nf ^ 0x1ff) + 1); + HALDEBUG(ah, HAL_DEBUG_NFCAL, + "NF calibrated [ext] [chain 0] is %d\n", nf); + nfarray[1] = nf; + + break; + } +} + +/* + * Adjust NF based on statistical values for 5GHz frequencies. + * Stubbed:Not used by Fowl + */ +int16_t +ar2133GetNfAdjust(struct ath_hal *ah, const HAL_CHANNEL_INTERNAL *c) +{ + return 0; +} + +/* + * Free memory for analog bank scratch buffers + */ +static void +ar2133RfDetach(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 + */ +HAL_BOOL +ar2133RfAttach(struct ath_hal *ah, HAL_STATUS *status) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + struct ar2133State *priv; + uint32_t *bankData; + + HALASSERT(ahp->ah_rfHal == AH_NULL); + priv = ath_hal_malloc(sizeof(struct ar2133State) + + AH5416(ah)->ah_ini_bank0.rows * sizeof(uint32_t) + + AH5416(ah)->ah_ini_bank1.rows * sizeof(uint32_t) + + AH5416(ah)->ah_ini_bank2.rows * sizeof(uint32_t) + + AH5416(ah)->ah_ini_bank3.rows * sizeof(uint32_t) + + AH5416(ah)->ah_ini_bank6.rows * sizeof(uint32_t) + + AH5416(ah)->ah_ini_bank7.rows * sizeof(uint32_t) + ); + 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 = ar2133RfDetach; + priv->base.writeRegs = ar2133WriteRegs; + priv->base.getRfBank = ar2133GetRfBank; + priv->base.setChannel = ar2133SetChannel; + priv->base.setRfRegs = ar2133SetRfRegs; + priv->base.setPowerTable = ar2133SetPowerTable; + priv->base.getChannelMaxMinPower = ar2133GetChannelMaxMinPower; + priv->base.getNfAdjust = ar2133GetNfAdjust; + + bankData = (uint32_t *) &priv[1]; + priv->Bank0Data = bankData, bankData += AH5416(ah)->ah_ini_bank0.rows; + priv->Bank1Data = bankData, bankData += AH5416(ah)->ah_ini_bank1.rows; + priv->Bank2Data = bankData, bankData += AH5416(ah)->ah_ini_bank2.rows; + priv->Bank3Data = bankData, bankData += AH5416(ah)->ah_ini_bank3.rows; + priv->Bank6Data = bankData, bankData += AH5416(ah)->ah_ini_bank6.rows; + priv->Bank7Data = bankData, bankData += AH5416(ah)->ah_ini_bank7.rows; + + ahp->ah_pcdacTable = priv->pcdacTable; + ahp->ah_pcdacTableSize = sizeof(priv->pcdacTable); + ahp->ah_rfHal = &priv->base; + /* + * Set noise floor adjust method; we arrange a + * direct call instead of thunking. + */ + AH_PRIVATE(ah)->ah_getNfAdjust = priv->base.getNfAdjust; + AH_PRIVATE(ah)->ah_getNoiseFloor = ar2133GetNoiseFloor; + + return AH_TRUE; +} --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5210/ar5416.h 2009-03-23 17:36:56.000000000 +0000 @@ -0,0 +1,193 @@ +/* + * 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: ar5416.h,v 1.1 2009/03/23 17:14:48 sborrill Exp $ + */ +#ifndef _ATH_AR5416_H_ +#define _ATH_AR5416_H_ + +#include "ar5212/ar5212.h" +#include "ar5416_cal.h" + +#define AR5416_MAGIC 0x20065416 + +enum { + HAL_RESET_POWER_ON, + HAL_RESET_WARM, + HAL_RESET_COLD, +}; + +typedef struct { + uint16_t synth_center; + uint16_t ctl_center; + uint16_t ext_center; +} CHAN_CENTERS; + +#define AR5416_DEFAULT_RXCHAINMASK 7 +#define AR5416_DEFAULT_TXCHAINMASK 1 +#define AR5416_MAX_RATE_POWER 63 +#define AR5416_KEYTABLE_SIZE 128 + +#define AR5416_CCA_MAX_GOOD_VALUE -85 +#define AR5416_CCA_MAX_HIGH_VALUE -62 +#define AR5416_CCA_MIN_BAD_VALUE -140 + +struct ath_hal_5416 { + struct ath_hal_5212 ah_5212; + + /* NB: RF data setup at attach */ + HAL_INI_ARRAY ah_ini_bb_rfgain; + HAL_INI_ARRAY ah_ini_bank0; + HAL_INI_ARRAY ah_ini_bank1; + HAL_INI_ARRAY ah_ini_bank2; + HAL_INI_ARRAY ah_ini_bank3; + HAL_INI_ARRAY ah_ini_bank6; + HAL_INI_ARRAY ah_ini_bank7; + HAL_INI_ARRAY ah_ini_addac; + + u_int ah_globaltxtimeout; /* global tx timeout */ + int ah_hangs; /* h/w hangs state */ + uint8_t ah_keytype[AR5416_KEYTABLE_SIZE]; + /* + * Extension Channel Rx Clear State + */ + uint32_t ah_cycleCount; + uint32_t ah_ctlBusy; + uint32_t ah_extBusy; + uint32_t ah_rx_chainmask; + uint32_t ah_tx_chainmask; + + struct ar5416PerCal ah_cal; /* periodic calibration state */ +}; +#define AH5416(_ah) ((struct ath_hal_5416 *)(_ah)) + +#define IS_5416_PCI(ah) ((AH_PRIVATE(ah)->ah_macVersion) == AR_SREV_VERSION_OWL_PCI) +#define IS_5416_PCIE(ah) ((AH_PRIVATE(ah)->ah_macVersion) == AR_SREV_VERSION_OWL_PCIE) +#undef IS_PCIE +#define IS_PCIE(ah) (IS_5416_PCIE(ah)) + +extern HAL_BOOL ar2133RfAttach(struct ath_hal *, HAL_STATUS *); + +struct ath_hal; + +extern struct ath_hal * ar5416Attach(uint16_t devid, HAL_SOFTC sc, + HAL_BUS_TAG st, HAL_BUS_HANDLE sh, HAL_STATUS *status); +extern void ar5416InitState(struct ath_hal_5416 *, uint16_t devid, + HAL_SOFTC sc, HAL_BUS_TAG st, HAL_BUS_HANDLE sh, + HAL_STATUS *status); +extern void ar5416Detach(struct ath_hal *ah); +extern HAL_BOOL ar5416FillCapabilityInfo(struct ath_hal *ah); + +#define IS_5GHZ_FAST_CLOCK_EN(_ah, _c) \ + (IS_CHAN_5GHZ(_c) && ath_hal_eepromGetFlag(ah, AR_EEP_FSTCLK_5G)) + +extern void ar5416AniAttach(struct ath_hal *, const struct ar5212AniParams *, + const struct ar5212AniParams *, HAL_BOOL ena); +extern void ar5416AniDetach(struct ath_hal *); +extern HAL_BOOL ar5416AniControl(struct ath_hal *, HAL_ANI_CMD cmd, int param); +extern HAL_BOOL ar5416AniSetParams(struct ath_hal *, + const struct ar5212AniParams *, const struct ar5212AniParams *); +extern void ar5416ProcessMibIntr(struct ath_hal *, const HAL_NODE_STATS *); +extern void ar5416AniPoll(struct ath_hal *, const HAL_NODE_STATS *, + HAL_CHANNEL *); +extern void ar5416AniReset(struct ath_hal *, HAL_CHANNEL_INTERNAL *, + HAL_OPMODE, int); + +extern void ar5416SetBeaconTimers(struct ath_hal *, const HAL_BEACON_TIMERS *); +extern void ar5416BeaconInit(struct ath_hal *ah, + uint32_t next_beacon, uint32_t beacon_period); +extern void ar5416ResetStaBeaconTimers(struct ath_hal *ah); +extern void ar5416SetStaBeaconTimers(struct ath_hal *ah, + const HAL_BEACON_STATE *); + +extern HAL_BOOL ar5416EepromRead(struct ath_hal *, u_int off, uint16_t *data); +extern HAL_BOOL ar5416EepromWrite(struct ath_hal *, u_int off, uint16_t data); + +extern HAL_BOOL ar5416IsInterruptPending(struct ath_hal *ah); +extern HAL_BOOL ar5416GetPendingInterrupts(struct ath_hal *, HAL_INT *masked); +extern HAL_INT ar5416SetInterrupts(struct ath_hal *ah, HAL_INT ints); + +extern HAL_BOOL ar5416GpioCfgOutput(struct ath_hal *, uint32_t gpio); +extern HAL_BOOL ar5416GpioCfgInput(struct ath_hal *, uint32_t gpio); +extern HAL_BOOL ar5416GpioSet(struct ath_hal *, uint32_t gpio, uint32_t val); +extern uint32_t ar5416GpioGet(struct ath_hal *ah, uint32_t gpio); +extern void ar5416GpioSetIntr(struct ath_hal *ah, u_int, uint32_t ilevel); + +extern u_int ar5416GetWirelessModes(struct ath_hal *ah); +extern void ar5416SetLedState(struct ath_hal *ah, HAL_LED_STATE state); +extern void ar5416ResetTsf(struct ath_hal *ah); +extern HAL_BOOL ar5416SetAntennaSwitch(struct ath_hal *, HAL_ANT_SETTING); +extern HAL_BOOL ar5416SetDecompMask(struct ath_hal *, uint16_t, int); +extern void ar5416SetCoverageClass(struct ath_hal *, uint8_t, int); +extern uint32_t ar5416Get11nExtBusy(struct ath_hal *ah); +extern void ar5416Set11nMac2040(struct ath_hal *ah, HAL_HT_MACMODE mode); +extern HAL_HT_RXCLEAR ar5416Get11nRxClear(struct ath_hal *ah); +extern void ar5416Set11nRxClear(struct ath_hal *ah, HAL_HT_RXCLEAR rxclear); +extern HAL_STATUS ar5416GetCapability(struct ath_hal *ah, + HAL_CAPABILITY_TYPE type, uint32_t capability, uint32_t *result); +extern HAL_BOOL ar5416GetDiagState(struct ath_hal *ah, int request, + const void *args, uint32_t argsize, + void **result, uint32_t *resultsize); + +extern HAL_BOOL ar5416SetPowerMode(struct ath_hal *ah, HAL_POWER_MODE mode, + int setChip); +extern HAL_POWER_MODE ar5416GetPowerMode(struct ath_hal *ah); +extern HAL_BOOL ar5416GetPowerStatus(struct ath_hal *ah); + +extern HAL_BOOL ar5416ResetKeyCacheEntry(struct ath_hal *ah, uint16_t entry); +extern HAL_BOOL ar5416SetKeyCacheEntry(struct ath_hal *ah, uint16_t entry, + const HAL_KEYVAL *k, const uint8_t *mac, int xorKey); + +extern void ar5416StartPcuReceive(struct ath_hal *ah); +extern void ar5416StopPcuReceive(struct ath_hal *ah); +extern HAL_BOOL ar5416SetupRxDesc(struct ath_hal *, + struct ath_desc *, uint32_t size, u_int flags); +extern HAL_STATUS ar5416ProcRxDesc(struct ath_hal *ah, struct ath_desc *, + uint32_t, struct ath_desc *, uint64_t, + struct ath_rx_status *); + +extern HAL_BOOL ar5416Reset(struct ath_hal *ah, HAL_OPMODE opmode, + HAL_CHANNEL *chan, HAL_BOOL bChannelChange, HAL_STATUS *status); +extern HAL_BOOL ar5416PhyDisable(struct ath_hal *ah); +extern HAL_RFGAIN ar5416GetRfgain(struct ath_hal *ah); +extern HAL_BOOL ar5416Disable(struct ath_hal *ah); +extern HAL_BOOL ar5416ChipReset(struct ath_hal *ah, HAL_CHANNEL *); +extern HAL_BOOL ar5416SetResetReg(struct ath_hal *, uint32_t type); +extern HAL_BOOL ar5416SetTxPowerLimit(struct ath_hal *ah, uint32_t limit); +extern HAL_BOOL ar5416GetChipPowerLimits(struct ath_hal *ah, + HAL_CHANNEL *chans, uint32_t nchans); +extern void ar5416GetChannelCenters(struct ath_hal *, + HAL_CHANNEL_INTERNAL *chan, CHAN_CENTERS *centers); + +extern HAL_BOOL ar5416StopTxDma(struct ath_hal *ah, u_int q); +extern HAL_BOOL ar5416SetupTxDesc(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 ar5416SetupXTxDesc(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 ar5416FillTxDesc(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 ar5416ProcTxDesc(struct ath_hal *ah, + struct ath_desc *, struct ath_tx_status *); + +extern const HAL_RATE_TABLE *ar5416GetRateTable(struct ath_hal *, u_int mode); +#endif /* _ATH_AR5416_H_ */ --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5210/ar5416.ini 2009-03-23 17:36:56.000000000 +0000 @@ -0,0 +1,688 @@ +/* + * 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: ar5416.ini,v 1.1 2009/03/23 17:14:48 sborrill Exp $ + */ +/* Auto Generated PCI Register Writes. Created: 09/20/06 */ + +static const uint32_t ar5416Modes[][6] = { + /* Register A A-20/40 G-20/40 G G-Turbo */ + { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, + { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, + { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 }, + { 0x000010f0, 0x0000a000, 0x00014000, 0x00016000, 0x0000b000, 0x00014008 }, + { 0x00008014, 0x03e803e8, 0x07d007d0, 0x10801080, 0x08400840, 0x06e006e0 }, + { 0x0000801c, 0x128d93a7, 0x128d93cf, 0x12e013d7, 0x12e013ab, 0x098813cf }, + { 0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303 }, + { 0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200 }, + { 0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, + { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 }, + { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, + { 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 }, + { 0x00009844, 0x1372161e, 0x13721c1e, 0x13721c30, 0x137216a4, 0x13721c25 }, + { 0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, + { 0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, + { 0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, + { 0x00009850, 0x6c28b4e0, 0x6c28b4e0, 0x6d68b0de, 0x6d68b0de, 0x6c28b0de }, + { 0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e }, + { 0x0000985c, 0x313a5d5e, 0x313a5d5e, 0x313a605e, 0x313a605e, 0x313a5d5e }, + { 0x00009860, 0x00049d10, 0x00049d10, 0x00049d20, 0x00049d20, 0x00049d10 }, + { 0x0000c864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 }, + { 0x00009868, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190 }, + { 0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 }, + { 0x00009914, 0x000007d0, 0x000007d0, 0x00000898, 0x00000898, 0x000007d0 }, + { 0x00009918, 0x000001b8, 0x00000370, 0x00000268, 0x00000134, 0x00000370 }, + { 0x00009924, 0xd0058a0b, 0xd0058a0b, 0xd0058a19, 0xd0058a13, 0xd0058a0b }, + { 0x00009944, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020 }, +#ifdef TB243 + { 0x00009960, 0x00000900, 0x00000900, 0x00009b40, 0x00009b40, 0x00012d80 }, + { 0x0000a960, 0x00000900, 0x00000900, 0x00009b40, 0x00009b40, 0x00012d80 }, + { 0x0000b960, 0x00000900, 0x00000900, 0x00009b40, 0x00009b40, 0x00012d80 }, + { 0x00009964, 0x00000000, 0x00000000, 0x00002210, 0x00002210, 0x00001120 }, +#else + { 0x00009960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80 }, + { 0x0000a960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80 }, + { 0x0000b960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80 }, +#ifdef __LINUX_ARM_ARCH__ + { 0x00009964, 0x00000000, 0x00000000, 0x00001120, 0x00001120, 0x00001120 }, +#else + { 0x00009964, 0x00000000, 0x00000000, 0x00001120, 0x00001120, 0x00001120 }, +#endif +#endif + { 0x0000c9bc, 0x001a0a00, 0x001a0a00, 0x001a0a00, 0x001a0a00, 0x001a0a00 }, + { 0x000099c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, 0x038919be }, + { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 }, + { 0x000099c8, 0x60f6532c, 0x60f6532c, 0x60f6532c, 0x60f6532c, 0x60f6532c }, + { 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 }, + { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 }, + { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a204, 0x00000440, 0x00000440, 0x00000440, 0x00000440, 0x00000440 }, + { 0x0000a208, 0xd6be4788, 0xd6be4788, 0xd03e4788, 0xd03e4788, 0xd03e4788 }, + { 0x0000a20c, 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120, 0x002ac120 }, + { 0x0000b20c, 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120, 0x002ac120 }, + { 0x0000c20c, 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120, 0x002ac120 }, + { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a }, + { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 }, + { 0x0000a274, 0x0a1a9caa, 0x0a1a9caa, 0x0a1a7caa, 0x0a1a7caa, 0x0a1a7caa }, + { 0x0000a300, 0x18010000, 0x18010000, 0x18010000, 0x18010000, 0x18010000 }, + { 0x0000a304, 0x30032602, 0x30032602, 0x2e032402, 0x2e032402, 0x2e032402 }, + { 0x0000a308, 0x48073e06, 0x48073e06, 0x4a0a3c06, 0x4a0a3c06, 0x4a0a3c06 }, + { 0x0000a30c, 0x560b4c0a, 0x560b4c0a, 0x621a540b, 0x621a540b, 0x621a540b }, + { 0x0000a310, 0x641a600f, 0x641a600f, 0x764f6c1b, 0x764f6c1b, 0x764f6c1b }, + { 0x0000a314, 0x7a4f6e1b, 0x7a4f6e1b, 0x845b7a5a, 0x845b7a5a, 0x845b7a5a }, + { 0x0000a318, 0x8c5b7e5a, 0x8c5b7e5a, 0x950f8ccf, 0x950f8ccf, 0x950f8ccf }, + { 0x0000a31c, 0x9d0f96cf, 0x9d0f96cf, 0xa5cf9b4f, 0xa5cf9b4f, 0xa5cf9b4f }, + { 0x0000a320, 0xb51fa69f, 0xb51fa69f, 0xbddfaf1f, 0xbddfaf1f, 0xbddfaf1f }, + { 0x0000a324, 0xcb3fbd07, 0xcb3fbcbf, 0xd1ffc93f, 0xd1ffc93f, 0xd1ffc93f }, + { 0x0000a328, 0x0000d7bf, 0x0000d7bf, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a32c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a330, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a334, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, +}; + +static const uint32_t ar5416Common[][2] = { + { 0x0000000c, 0x00000000 }, + { 0x00000030, 0x00020015 }, + { 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 }, + { 0x00001040, 0x002ffc0f }, + { 0x00001044, 0x002ffc0f }, + { 0x00001048, 0x002ffc0f }, + { 0x0000104c, 0x002ffc0f }, + { 0x00001050, 0x002ffc0f }, + { 0x00001054, 0x002ffc0f }, + { 0x00001058, 0x002ffc0f }, + { 0x0000105c, 0x002ffc0f }, + { 0x00001060, 0x002ffc0f }, + { 0x00001064, 0x002ffc0f }, + { 0x00001230, 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 }, + { 0x00004030, 0x00000002 }, + { 0x0000403c, 0x00000002 }, +#ifdef AR9100 + { 0x00020010, 0x00000000 }, +#else + { 0x00007010, 0x00000000 }, +#endif + { 0x00007038, 0x000004c2 }, + { 0x00008004, 0x00000000 }, + { 0x00008008, 0x00000000 }, + { 0x0000800c, 0x00000000 }, + { 0x00008018, 0x00000700 }, + { 0x00008020, 0x00000000 }, + { 0x00008038, 0x00000000 }, + { 0x0000803c, 0x00000000 }, + { 0x00008048, 0x40000000 }, + { 0x00008054, 0x00000000 }, + { 0x00008058, 0x00000000 }, + { 0x0000805c, 0x000fc78f }, + { 0x00008060, 0x0000000f }, + { 0x00008064, 0x00000000 }, + { 0x000080c0, 0x2a82301a }, + { 0x000080c4, 0x05dc01e0 }, + { 0x000080c8, 0x1f402710 }, + { 0x000080cc, 0x01f40000 }, + { 0x000080d0, 0x00001e00 }, + { 0x000080d4, 0x00000000 }, + { 0x000080d8, 0x00400000 }, + { 0x000080e0, 0xffffffff }, + { 0x000080e4, 0x0000ffff }, + { 0x000080e8, 0x003f3f3f }, + { 0x000080ec, 0x00000000 }, + { 0x000080f0, 0x00000000 }, + { 0x000080f4, 0x00000000 }, + { 0x000080f8, 0x00000000 }, + { 0x000080fc, 0x00020000 }, + { 0x00008100, 0x00020000 }, + { 0x00008104, 0x00000001 }, + { 0x00008108, 0x00000052 }, + { 0x0000810c, 0x00000000 }, + { 0x00008110, 0x00000168 }, + { 0x00008118, 0x000100aa }, + { 0x0000811c, 0x00003210 }, + { 0x00008120, 0x08f04800 }, + { 0x00008124, 0x00000000 }, + { 0x00008128, 0x00000000 }, + { 0x0000812c, 0x00000000 }, + { 0x00008130, 0x00000000 }, + { 0x00008134, 0x00000000 }, + { 0x00008138, 0x00000000 }, + { 0x0000813c, 0x00000000 }, + { 0x00008144, 0x00000000 }, + { 0x00008168, 0x00000000 }, + { 0x0000816c, 0x00000000 }, + { 0x00008170, 0x32143320 }, + { 0x00008174, 0xfaa4fa50 }, + { 0x00008178, 0x00000100 }, + { 0x0000817c, 0x00000000 }, + { 0x000081c4, 0x00000000 }, + { 0x000081d0, 0x00003210 }, + { 0x000081ec, 0x00000000 }, + { 0x000081f0, 0x00000000 }, + { 0x000081f4, 0x00000000 }, + { 0x000081f8, 0x00000000 }, + { 0x000081fc, 0x00000000 }, + { 0x00008200, 0x00000000 }, + { 0x00008204, 0x00000000 }, + { 0x00008208, 0x00000000 }, + { 0x0000820c, 0x00000000 }, + { 0x00008210, 0x00000000 }, + { 0x00008214, 0x00000000 }, + { 0x00008218, 0x00000000 }, + { 0x0000821c, 0x00000000 }, + { 0x00008220, 0x00000000 }, + { 0x00008224, 0x00000000 }, + { 0x00008228, 0x00000000 }, + { 0x0000822c, 0x00000000 }, + { 0x00008230, 0x00000000 }, + { 0x00008234, 0x00000000 }, + { 0x00008238, 0x00000000 }, + { 0x0000823c, 0x00000000 }, + { 0x00008240, 0x00100000 }, + { 0x00008244, 0x0010f400 }, + { 0x00008248, 0x00000100 }, + { 0x0000824c, 0x0001e800 }, + { 0x00008250, 0x00000000 }, + { 0x00008254, 0x00000000 }, + { 0x00008258, 0x00000000 }, + { 0x0000825c, 0x400000ff }, + { 0x00008260, 0x00080922 }, + { 0x00008270, 0x00000000 }, + { 0x00008274, 0x40000000 }, + { 0x00008278, 0x003e4180 }, + { 0x0000827c, 0x00000000 }, + { 0x00008284, 0x0000002c }, + { 0x00008288, 0x0000002c }, + { 0x0000828c, 0x00000000 }, + { 0x00008294, 0x00000000 }, + { 0x00008298, 0x00000000 }, + { 0x00008300, 0x00000000 }, + { 0x00008304, 0x00000000 }, + { 0x00008308, 0x00000000 }, + { 0x0000830c, 0x00000000 }, + { 0x00008310, 0x00000000 }, + { 0x00008314, 0x00000000 }, + { 0x00008318, 0x00000000 }, + { 0x00008328, 0x00000000 }, + { 0x0000832c, 0x00000007 }, + { 0x00008330, 0x00000302 }, + { 0x00008334, 0x00000e00 }, + { 0x00008338, 0x00000000 }, + { 0x0000833c, 0x00000000 }, + { 0x00008340, 0x000107ff }, + { 0x00009808, 0x00000000 }, + { 0x0000980c, 0xad848e19 }, + { 0x00009810, 0x7d14e000 }, + { 0x00009814, 0x9c0a9f6b }, + { 0x0000981c, 0x00000000 }, + { 0x0000982c, 0x0000a000 }, + { 0x00009830, 0x00000000 }, + { 0x0000983c, 0x00200400 }, + { 0x00009840, 0x206a016e }, + { 0x0000984c, 0x1284233c }, + { 0x00009854, 0x00000859 }, + { 0x00009900, 0x00000000 }, + { 0x00009904, 0x00000000 }, + { 0x00009908, 0x00000000 }, + { 0x0000990c, 0x00000000 }, + { 0x0000991c, 0x10000fff }, + { 0x00009920, 0x05100000 }, + { 0x0000a920, 0x05100000 }, + { 0x0000b920, 0x05100000 }, + { 0x00009928, 0x00000001 }, + { 0x0000992c, 0x00000004 }, + { 0x00009934, 0x1e1f2022 }, + { 0x00009938, 0x0a0b0c0d }, + { 0x0000993c, 0x00000000 }, + { 0x00009948, 0x9280b212 }, + { 0x0000994c, 0x00020028 }, + { 0x00009954, 0x5d50e188 }, + { 0x00009958, 0x00081fff }, + { 0x0000c95c, 0x004b6a8e }, + { 0x0000c968, 0x000003ce }, + { 0x00009970, 0x190c0514 }, + { 0x00009974, 0x00000000 }, + { 0x00009978, 0x00000001 }, + { 0x0000997c, 0x00000000 }, + { 0x00009980, 0x00000000 }, + { 0x00009984, 0x00000000 }, + { 0x00009988, 0x00000000 }, + { 0x0000998c, 0x00000000 }, + { 0x00009990, 0x00000000 }, + { 0x00009994, 0x00000000 }, + { 0x00009998, 0x00000000 }, + { 0x0000999c, 0x00000000 }, + { 0x000099a0, 0x00000000 }, + { 0x000099a4, 0x00000001 }, + { 0x000099a8, 0x001fff00 }, + { 0x000099ac, 0x000000c4 }, + { 0x000099b0, 0x03051000 }, + { 0x000099dc, 0x00000000 }, + { 0x000099e0, 0x00000200 }, + { 0x000099e4, 0xaaaaaaaa }, + { 0x000099e8, 0x3c466478 }, + { 0x000099ec, 0x000000aa }, + { 0x000099fc, 0x00001042 }, + { 0x00009b00, 0x00000000 }, + { 0x00009b04, 0x00000001 }, + { 0x00009b08, 0x00000002 }, + { 0x00009b0c, 0x00000003 }, + { 0x00009b10, 0x00000004 }, + { 0x00009b14, 0x00000005 }, + { 0x00009b18, 0x00000008 }, + { 0x00009b1c, 0x00000009 }, + { 0x00009b20, 0x0000000a }, + { 0x00009b24, 0x0000000b }, + { 0x00009b28, 0x0000000c }, + { 0x00009b2c, 0x0000000d }, + { 0x00009b30, 0x00000010 }, + { 0x00009b34, 0x00000011 }, + { 0x00009b38, 0x00000012 }, + { 0x00009b3c, 0x00000013 }, + { 0x00009b40, 0x00000014 }, + { 0x00009b44, 0x00000015 }, + { 0x00009b48, 0x00000018 }, + { 0x00009b4c, 0x00000019 }, + { 0x00009b50, 0x0000001a }, + { 0x00009b54, 0x0000001b }, + { 0x00009b58, 0x0000001c }, + { 0x00009b5c, 0x0000001d }, + { 0x00009b60, 0x00000020 }, + { 0x00009b64, 0x00000021 }, + { 0x00009b68, 0x00000022 }, + { 0x00009b6c, 0x00000023 }, + { 0x00009b70, 0x00000024 }, + { 0x00009b74, 0x00000025 }, + { 0x00009b78, 0x00000028 }, + { 0x00009b7c, 0x00000029 }, + { 0x00009b80, 0x0000002a }, + { 0x00009b84, 0x0000002b }, + { 0x00009b88, 0x0000002c }, + { 0x00009b8c, 0x0000002d }, + { 0x00009b90, 0x00000030 }, + { 0x00009b94, 0x00000031 }, + { 0x00009b98, 0x00000032 }, + { 0x00009b9c, 0x00000033 }, + { 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 }, + { 0x0000a210, 0x40806333 }, + { 0x0000a214, 0x00106c10 }, + { 0x0000a218, 0x009c4060 }, + { 0x0000a220, 0x018830c6 }, + { 0x0000a224, 0x00000400 }, + { 0x0000a228, 0x00000bb5 }, + { 0x0000a22c, 0x00000011 }, + { 0x0000a234, 0x20202020 }, + { 0x0000a238, 0x20202020 }, + { 0x0000a23c, 0x13c889af }, + { 0x0000a240, 0x38490a20 }, + { 0x0000a244, 0x00007bb6 }, + { 0x0000a248, 0x0fff3ffc }, + { 0x0000a24c, 0x00000001 }, + { 0x0000a250, 0x0000a000 }, + { 0x0000a254, 0x00000000 }, + { 0x0000a258, 0x0cc75380 }, + { 0x0000a25c, 0x0f0f0f01 }, + { 0x0000a260, 0xdfa91f01 }, + { 0x0000a268, 0x00000000 }, + { 0x0000a26c, 0x0ebae9c6 }, + { 0x0000b26c, 0x0ebae9c6 }, + { 0x0000c26c, 0x0ebae9c6 }, + { 0x0000d270, 0x00820820 }, + { 0x0000a278, 0x1ce739ce }, + { 0x0000a27c, 0x051701ce }, + { 0x0000a338, 0x00000000 }, + { 0x0000a33c, 0x00000000 }, + { 0x0000a340, 0x00000000 }, + { 0x0000a344, 0x00000000 }, + { 0x0000a348, 0x3fffffff }, + { 0x0000a34c, 0x3fffffff }, + { 0x0000a350, 0x3fffffff }, + { 0x0000a354, 0x0003ffff }, + { 0x0000a358, 0x79a8aa1f }, + { 0x0000d35c, 0x066c420f }, + { 0x0000d360, 0x0f282207 }, + { 0x0000d364, 0x17601685 }, + { 0x0000d368, 0x1f801104 }, + { 0x0000d36c, 0x37a00c03 }, + { 0x0000d370, 0x3fc40883 }, + { 0x0000d374, 0x57c00803 }, + { 0x0000d378, 0x5fd80682 }, + { 0x0000d37c, 0x7fe00482 }, + { 0x0000d380, 0x7f3c7bba }, + { 0x0000d384, 0xf3307ff0 }, + { 0x0000a388, 0x08000000 }, + { 0x0000a38c, 0x20202020 }, + { 0x0000a390, 0x20202020 }, + { 0x0000a394, 0x1ce739ce }, + { 0x0000a398, 0x000001ce }, + { 0x0000a39c, 0x00000001 }, + { 0x0000a3a0, 0x00000000 }, + { 0x0000a3a4, 0x00000000 }, + { 0x0000a3a8, 0x00000000 }, + { 0x0000a3ac, 0x00000000 }, + { 0x0000a3b0, 0x00000000 }, + { 0x0000a3b4, 0x00000000 }, + { 0x0000a3b8, 0x00000000 }, + { 0x0000a3bc, 0x00000000 }, + { 0x0000a3c0, 0x00000000 }, + { 0x0000a3c4, 0x00000000 }, + { 0x0000a3c8, 0x00000246 }, + { 0x0000a3cc, 0x20202020 }, + { 0x0000a3d0, 0x20202020 }, + { 0x0000a3d4, 0x20202020 }, + { 0x0000a3dc, 0x1ce739ce }, + { 0x0000a3e0, 0x000001ce }, +}; + +static const uint32_t ar5416Bank0[][2] = { + { 0x000098b0, 0x1e5795e5 }, + { 0x000098e0, 0x02008020 }, +}; + +static const uint32_t ar5416BB_RfGain[][3] = { + { 0x00009a00, 0x00000000, 0x00000000 }, + { 0x00009a04, 0x00000040, 0x00000040 }, + { 0x00009a08, 0x00000080, 0x00000080 }, + { 0x00009a0c, 0x000001a1, 0x00000141 }, + { 0x00009a10, 0x000001e1, 0x00000181 }, + { 0x00009a14, 0x00000021, 0x000001c1 }, + { 0x00009a18, 0x00000061, 0x00000001 }, + { 0x00009a1c, 0x00000168, 0x00000041 }, + { 0x00009a20, 0x000001a8, 0x000001a8 }, + { 0x00009a24, 0x000001e8, 0x000001e8 }, + { 0x00009a28, 0x00000028, 0x00000028 }, + { 0x00009a2c, 0x00000068, 0x00000068 }, + { 0x00009a30, 0x00000189, 0x000000a8 }, + { 0x00009a34, 0x000001c9, 0x00000169 }, + { 0x00009a38, 0x00000009, 0x000001a9 }, + { 0x00009a3c, 0x00000049, 0x000001e9 }, + { 0x00009a40, 0x00000089, 0x00000029 }, + { 0x00009a44, 0x00000170, 0x00000069 }, + { 0x00009a48, 0x000001b0, 0x00000190 }, + { 0x00009a4c, 0x000001f0, 0x000001d0 }, + { 0x00009a50, 0x00000030, 0x00000010 }, + { 0x00009a54, 0x00000070, 0x00000050 }, + { 0x00009a58, 0x00000191, 0x00000090 }, + { 0x00009a5c, 0x000001d1, 0x00000151 }, + { 0x00009a60, 0x00000011, 0x00000191 }, + { 0x00009a64, 0x00000051, 0x000001d1 }, + { 0x00009a68, 0x00000091, 0x00000011 }, + { 0x00009a6c, 0x000001b8, 0x00000051 }, + { 0x00009a70, 0x000001f8, 0x00000198 }, + { 0x00009a74, 0x00000038, 0x000001d8 }, + { 0x00009a78, 0x00000078, 0x00000018 }, + { 0x00009a7c, 0x00000199, 0x00000058 }, + { 0x00009a80, 0x000001d9, 0x00000098 }, + { 0x00009a84, 0x00000019, 0x00000159 }, + { 0x00009a88, 0x00000059, 0x00000199 }, + { 0x00009a8c, 0x00000099, 0x000001d9 }, + { 0x00009a90, 0x000000d9, 0x00000019 }, + { 0x00009a94, 0x000000f9, 0x00000059 }, + { 0x00009a98, 0x000000f9, 0x00000099 }, + { 0x00009a9c, 0x000000f9, 0x000000d9 }, + { 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 }, +}; + +static const uint32_t ar5416Bank1[][2] = { + { 0x000098b0, 0x02108421 }, + { 0x000098ec, 0x00000008 }, +}; + +static const uint32_t ar5416Bank2[][2] = { + { 0x000098b0, 0x0e73ff17 }, + { 0x000098e0, 0x00000420 }, +}; + +static const uint32_t ar5416Bank3[][3] = { + { 0x000098f0, 0x01400018, 0x01c00018 }, +}; + +#ifdef USE_NONTPC_BANK +static const uint32_t ar5416Bank6[][3] = { +/* Reg A G */ + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00e00000, 0x00e00000 }, + { 0x0000989c, 0x005e0000, 0x005e0000 }, + { 0x0000989c, 0x00120000, 0x00120000 }, + { 0x0000989c, 0x00620000, 0x00620000 }, + { 0x0000989c, 0x00020000, 0x00020000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x40ff0000, 0x40ff0000 }, + { 0x0000989c, 0x005f0000, 0x005f0000 }, + { 0x0000989c, 0x00870000, 0x00870000 }, + { 0x0000989c, 0x00f90000, 0x00f90000 }, + { 0x0000989c, 0x007b0000, 0x007b0000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x00f50000, 0x00f50000 }, + { 0x0000989c, 0x00dc0000, 0x00dc0000 }, + { 0x0000989c, 0x00110000, 0x00110000 }, + { 0x0000989c, 0x006100a8, 0x006100a8 }, + { 0x0000989c, 0x004210a2, 0x004210a2 }, + { 0x0000989c, 0x0014008f, 0x0014008f }, + { 0x0000989c, 0x00c40003, 0x00c40003 }, + { 0x0000989c, 0x003000f2, 0x003000f2 }, + { 0x0000989c, 0x00440016, 0x00440016 }, + { 0x0000989c, 0x00410040, 0x00410040 }, + { 0x0000989c, 0x0001805e, 0x0001805e }, + { 0x0000989c, 0x0000c0ab, 0x0000c0ab }, + { 0x0000989c, 0x000000f1, 0x000000f1 }, + { 0x0000989c, 0x00002081, 0x00002081 }, + { 0x0000989c, 0x000000d4, 0x000000d4 }, + { 0x000098d0, 0x0000000f, 0x0010000f }, +}; + +#else +/* TPC bank */ +static const uint32_t ar5416Bank6[][3] = { +/* Reg A G */ + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00e00000, 0x00e00000 }, + { 0x0000989c, 0x005e0000, 0x005e0000 }, + { 0x0000989c, 0x00120000, 0x00120000 }, + { 0x0000989c, 0x00620000, 0x00620000 }, + { 0x0000989c, 0x00020000, 0x00020000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x40ff0000, 0x40ff0000 }, + { 0x0000989c, 0x005f0000, 0x005f0000 }, + { 0x0000989c, 0x00870000, 0x00870000 }, + { 0x0000989c, 0x00f90000, 0x00f90000 }, + { 0x0000989c, 0x007b0000, 0x007b0000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x00f50000, 0x00f50000 }, + { 0x0000989c, 0x00dc0000, 0x00dc0000 }, + { 0x0000989c, 0x00110000, 0x00110000 }, + { 0x0000989c, 0x006100a8, 0x006100a8 }, + { 0x0000989c, 0x00421022, 0x00421022 }, + { 0x0000989c, 0x001400df, 0x001400df }, + { 0x0000989c, 0x00c40002, 0x00c40002 }, + { 0x0000989c, 0x003000f2, 0x003000f2 }, + { 0x0000989c, 0x00440016, 0x00440016 }, + { 0x0000989c, 0x00410040, 0x00410040 }, + { 0x0000989c, 0x0001805e, 0x0001805e }, + { 0x0000989c, 0x0000c0ab, 0x0000c0ab }, + { 0x0000989c, 0x000000e1, 0x000000e1 }, + { 0x0000989c, 0x00002081, 0x00002081 }, + { 0x0000989c, 0x000000d4, 0x000000d4 }, + { 0x000098d0, 0x0000000f, 0x0010000f }, +}; + +#endif + +static const uint32_t ar5416Bank7[][2] = { + { 0x0000989c, 0x00000500 }, + { 0x0000989c, 0x00000800 }, + { 0x000098cc, 0x0000000e }, +}; + +static const uint32_t ar5416Addac[][2] = { + {0x0989c, 0x00000000 }, + {0x0989c, 0x00000003 }, + {0x0989c, 0x00000000 }, + {0x0989c, 0x0000000c }, + {0x0989c, 0x00000000 }, + {0x0989c, 0x00000030 }, + {0x0989c, 0x00000000 }, + {0x0989c, 0x00000000 }, + {0x0989c, 0x00000000 }, + {0x0989c, 0x00000000 }, + {0x0989c, 0x00000000 }, + {0x0989c, 0x00000000 }, + {0x0989c, 0x00000000 }, + {0x0989c, 0x00000000 }, + {0x0989c, 0x00000000 }, + {0x0989c, 0x00000000 }, + {0x0989c, 0x00000000 }, + {0x0989c, 0x00000000 }, + {0x0989c, 0x00000060 }, + {0x0989c, 0x00000000 }, + {0x0989c, 0x00000000 }, + {0x0989c, 0x00000000 }, + {0x0989c, 0x00000000 }, + {0x0989c, 0x00000000 }, + {0x0989c, 0x00000000 }, + {0x0989c, 0x00000000 }, + {0x0989c, 0x00000000 }, + {0x0989c, 0x00000000 }, + {0x0989c, 0x00000000 }, + {0x0989c, 0x00000000 }, + {0x0989c, 0x00000000 }, + {0x0989c, 0x00000058 }, + {0x0989c, 0x00000000 }, + {0x0989c, 0x00000000 }, + {0x0989c, 0x00000000 }, + {0x0989c, 0x00000000 }, + {0x098c4, 0x00000000 }, +}; --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5210/ar5416_ani.c 2009-03-23 17:36:56.000000000 +0000 @@ -0,0 +1,886 @@ +/* + * 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: ar5416_ani.c,v 1.1 2009/03/23 17:14:48 sborrill Exp $ + */ +#include "opt_ah.h" + +/* + * XXX this is virtually the same code as for 5212; we reuse + * storage in the 5212 state block; need to refactor. + */ +#include "ah.h" +#include "ah_internal.h" +#include "ah_desc.h" + +#include "ar5416/ar5416.h" +#include "ar5416/ar5416reg.h" +#include "ar5416/ar5416phy.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_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); + OS_REG_WRITE(ah, AR_PHY_ERR_MASK_2, 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_PHY_ERR_MASK_1, 0); + OS_REG_WRITE(ah, AR_PHY_ERR_MASK_2, 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 +ar5416GetAniChannelIndex(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 +} + +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 ar5416AniReset should be + * called by ar5416Reset before anything else happens and + * that's where we force initial settings. + */ +void +ar5416AniAttach(struct ath_hal *ah, const struct ar5212AniParams *params24, + const struct ar5212AniParams *params5, HAL_BOOL enable) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + + 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)); + /* 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; + } +} + +/* + * Cleanup any ANI state setup. + */ +void +ar5416AniDetach(struct ath_hal *ah) +{ + HALDEBUG(ah, HAL_DEBUG_ANI, "Detaching Ani\n"); + disableAniMIBCounters(ah); +} + +/* + * Control Adaptive Noise Immunity Parameters + */ +HAL_BOOL +ar5416AniControl(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]); + + OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, + AR_PHY_SFCORR_EXT_M1_THRESH_LOW, m1ThreshLow[on]); + OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, + AR_PHY_SFCORR_EXT_M2_THRESH_LOW, m2ThreshLow[on]); + OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, + AR_PHY_SFCORR_EXT_M1_THRESH, m1Thresh[on]); + OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, + AR_PHY_SFCORR_EXT_M2_THRESH, m2Thresh[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 */ + ar5416AniDetach(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; + 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*/); + 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 +ar5416AniOfdmErrTrigger(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) { + ar5416AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL, + aniState->noiseImmunityLevel + 1); + return; + } + /* then, raise spur immunity level, up to max */ + if (aniState->spurImmunityLevel+1 < params->maxSpurImmunityLevel) { + ar5416AniControl(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) { + ar5416AniControl(ah, + HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, + AH_FALSE); + ar5416AniControl(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) { + ar5416AniControl(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) + ar5416AniControl(ah, + HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, + AH_TRUE); + if (aniState->firstepLevel+1 < params->maxFirstepLevel) + ar5416AniControl(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) + ar5416AniControl(ah, + HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, + AH_FALSE); + if (aniState->firstepLevel > 0) + ar5416AniControl(ah, + HAL_ANI_FIRSTEP_LEVEL, 0); + return; + } + } + } +} + +static void +ar5416AniCckErrTrigger(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) { + ar5416AniControl(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) + ar5416AniControl(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) + ar5416AniControl(ah, + HAL_ANI_FIRSTEP_LEVEL, 0); + } + } + } +} + +static void +ar5416AniRestart(struct ath_hal *ah, struct ar5212AniState *aniState) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + const struct ar5212AniParams *params = aniState->params; + + aniState->listenTime = 0; + /* + * NB: these are written on reset based on the + * ini so we must re-write them! + */ + HALDEBUG(ah, HAL_DEBUG_ANI, + "%s: Writing ofdmbase=%u cckbase=%u\n", __func__, + params->ofdmPhyErrBase, params->cckPhyErrBase); + OS_REG_WRITE(ah, AR_PHY_ERR_1, params->ofdmPhyErrBase); + OS_REG_WRITE(ah, AR_PHY_ERR_2, params->cckPhyErrBase); + OS_REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); + OS_REG_WRITE(ah, AR_PHY_ERR_MASK_1, 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 +ar5416AniReset(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 = ar5416GetAniChannelIndex(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) { + ar5416AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL, + aniState->noiseImmunityLevel); + ar5416AniControl(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL, + aniState->spurImmunityLevel); + ar5416AniControl(ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, + !aniState->ofdmWeakSigDetectOff); + ar5416AniControl(ah, HAL_ANI_CCK_WEAK_SIGNAL_THR, + aniState->cckWeakSigThreshold); + ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, + aniState->firstepLevel); + } else { + ar5416AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL, 0); + ar5416AniControl(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL, 0); + ar5416AniControl(ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, + AH_TRUE); + ar5416AniControl(ah, HAL_ANI_CCK_WEAK_SIGNAL_THR, AH_FALSE); + ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, 0); + aniState->isSetup = AH_TRUE; + } + ar5416AniRestart(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 +ar5416ProcessMibIntr(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_PHY_ERR_1); + phyCnt2 = OS_REG_READ(ah, AR_PHY_ERR_2); + /* 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); + if ((OS_REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING) == 0) + OS_REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR); + + /* 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) + ar5416AniOfdmErrTrigger(ah); + if (aniState->cckPhyErrCount > params->cckTrigHigh) + ar5416AniCckErrTrigger(ah); + /* NB: always restart to insure the h/w counters are reset */ + ar5416AniRestart(ah, aniState); + } +} + +static void +ar5416AniLowerImmunity(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) { + ar5416AniControl(ah, + HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, + AH_TRUE); + return; + } + if (aniState->firstepLevel > 0) { + ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, + aniState->firstepLevel - 1); + return; + } + } else { + /* + * Beacon rssi is low, reduce firstep level. + */ + if (aniState->firstepLevel > 0) { + ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, + aniState->firstepLevel - 1); + return; + } + } + } + /* then lower spur immunity level, down to zero */ + if (aniState->spurImmunityLevel > 0) { + ar5416AniControl(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) { + ar5416AniControl(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 +ar5416AniGetListenTime(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; + + /* 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_PHY_ERR_1); + phyCnt2 = OS_REG_READ(ah, AR_PHY_ERR_2); + + /* 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 +ar5416AniPoll(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 = ar5416AniGetListenTime(ah); + if (listenTime < 0) { + ahp->ah_stats.ast_ani_lneg++; + /* restart ANI period if listenTime is invalid */ + ar5416AniRestart(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 + */ + updateMIBStats(ah, aniState); + if (aniState->ofdmPhyErrCount <= aniState->listenTime * + params->ofdmTrigLow/1000 && + aniState->cckPhyErrCount <= aniState->listenTime * + params->cckTrigLow/1000) + ar5416AniLowerImmunity(ah); + ar5416AniRestart(ah, aniState); + } else if (aniState->listenTime > params->period) { + updateMIBStats(ah, aniState); + /* check to see if need to raise immunity */ + if (aniState->ofdmPhyErrCount > aniState->listenTime * + params->ofdmTrigHigh / 1000) { + ar5416AniOfdmErrTrigger(ah); + ar5416AniRestart(ah, aniState); + } else if (aniState->cckPhyErrCount > aniState->listenTime * + params->cckTrigHigh / 1000) { + ar5416AniCckErrTrigger(ah); + ar5416AniRestart(ah, aniState); + } + } +} --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5210/ar5416_attach.c 2009-03-23 17:36:56.000000000 +0000 @@ -0,0 +1,486 @@ +/* + * 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: ar5416_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 "ar5416/ar5416.h" +#include "ar5416/ar5416reg.h" +#include "ar5416/ar5416phy.h" + +#include "ar5416/ar5416.ini" + +static void +ar5416AniSetup(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, + .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, + }; + /* NB: ANI is not enabled yet */ + ar5212AniAttach(ah, &aniparams, &aniparams, AH_FALSE); +} + +/* + * Attach for an AR5416 part. + */ +void +ar5416InitState(struct ath_hal_5416 *ahp5416, uint16_t devid, HAL_SOFTC sc, + HAL_BUS_TAG st, HAL_BUS_HANDLE sh, HAL_STATUS *status) +{ + struct ath_hal_5212 *ahp; + struct ath_hal *ah; + + ahp = &ahp5416->ah_5212; + ar5212InitState(ahp, devid, sc, st, sh, status); + ah = &ahp->ah_priv.h; + + /* override 5212 methods for our needs */ + ah->ah_magic = AR5416_MAGIC; + ah->ah_getRateTable = ar5416GetRateTable; + ah->ah_detach = ar5416Detach; + + /* Reset functions */ + ah->ah_reset = ar5416Reset; + ah->ah_phyDisable = ar5416PhyDisable; + ah->ah_disable = ar5416Disable; + ah->ah_perCalibration = ar5416PerCalibration; + ah->ah_perCalibrationN = ar5416PerCalibrationN, + ah->ah_resetCalValid = ar5416ResetCalValid, + ah->ah_setTxPowerLimit = ar5416SetTxPowerLimit; + + /* Transmit functions */ + ah->ah_stopTxDma = ar5416StopTxDma; + ah->ah_setupTxDesc = ar5416SetupTxDesc; + ah->ah_setupXTxDesc = ar5416SetupXTxDesc; + ah->ah_fillTxDesc = ar5416FillTxDesc; + ah->ah_procTxDesc = ar5416ProcTxDesc; + + /* Receive Functions */ + ah->ah_startPcuReceive = ar5416StartPcuReceive; + ah->ah_stopPcuReceive = ar5416StopPcuReceive; + ah->ah_setupRxDesc = ar5416SetupRxDesc; + ah->ah_procRxDesc = ar5416ProcRxDesc; + ah->ah_rxMonitor = ar5416AniPoll, + ah->ah_procMibEvent = ar5416ProcessMibIntr, + + /* Misc Functions */ + ah->ah_getDiagState = ar5416GetDiagState; + ah->ah_setLedState = ar5416SetLedState; + ah->ah_gpioCfgOutput = ar5416GpioCfgOutput; + ah->ah_gpioCfgInput = ar5416GpioCfgInput; + ah->ah_gpioGet = ar5416GpioGet; + ah->ah_gpioSet = ar5416GpioSet; + ah->ah_gpioSetIntr = ar5416GpioSetIntr; + ah->ah_resetTsf = ar5416ResetTsf; + ah->ah_getRfGain = ar5416GetRfgain; + ah->ah_setAntennaSwitch = ar5416SetAntennaSwitch; + ah->ah_setDecompMask = ar5416SetDecompMask; + ah->ah_setCoverageClass = ar5416SetCoverageClass; + + ah->ah_resetKeyCacheEntry = ar5416ResetKeyCacheEntry; + ah->ah_setKeyCacheEntry = ar5416SetKeyCacheEntry; + + /* Power Management Functions */ + ah->ah_setPowerMode = ar5416SetPowerMode; + + /* Beacon Management Functions */ + ah->ah_setBeaconTimers = ar5416SetBeaconTimers; + ah->ah_beaconInit = ar5416BeaconInit; + ah->ah_setStationBeaconTimers = ar5416SetStaBeaconTimers; + ah->ah_resetStationBeaconTimers = ar5416ResetStaBeaconTimers; + + /* XXX 802.11n Functions */ +#if 0 + ah->ah_chainTxDesc = ar5416ChainTxDesc; + ah->ah_setupFirstTxDesc = ar5416SetupFirstTxDesc; + ah->ah_setupLastTxDesc = ar5416SetupLastTxDesc; + ah->ah_set11nRateScenario = ar5416Set11nRateScenario; + ah->ah_set11nAggrMiddle = ar5416Set11nAggrMiddle; + ah->ah_clr11nAggr = ar5416Clr11nAggr; + ah->ah_set11nBurstDuration = ar5416Set11nBurstDuration; + ah->ah_get11nExtBusy = ar5416Get11nExtBusy; + ah->ah_set11nMac2040 = ar5416Set11nMac2040; + ah->ah_get11nRxClear = ar5416Get11nRxClear; + ah->ah_set11nRxClear = ar5416Set11nRxClear; +#endif + + /* Interrupt functions */ + ah->ah_isInterruptPending = ar5416IsInterruptPending; + ah->ah_getPendingInterrupts = ar5416GetPendingInterrupts; + ah->ah_setInterrupts = ar5416SetInterrupts; + + ahp->ah_priv.ah_getWirelessModes= ar5416GetWirelessModes; + ahp->ah_priv.ah_eepromRead = ar5416EepromRead; +#ifdef AH_SUPPORT_WRITE_EEPROM + ahp->ah_priv.ah_eepromWrite = ar5416EepromWrite; +#endif + ahp->ah_priv.ah_gpioCfgOutput = ar5416GpioCfgOutput; + ahp->ah_priv.ah_gpioCfgInput = ar5416GpioCfgInput; + ahp->ah_priv.ah_gpioGet = ar5416GpioGet; + ahp->ah_priv.ah_gpioSet = ar5416GpioSet; + ahp->ah_priv.ah_gpioSetIntr = ar5416GpioSetIntr; + ahp->ah_priv.ah_getChipPowerLimits = ar5416GetChipPowerLimits; + + /* + * Start by setting all Owl devices to 2x2 + */ + AH5416(ah)->ah_rx_chainmask = AR5416_DEFAULT_RXCHAINMASK; + AH5416(ah)->ah_tx_chainmask = AR5416_DEFAULT_TXCHAINMASK; +} + +/* + * Attach for an AR5416 part. + */ +struct ath_hal * +ar5416Attach(uint16_t devid, HAL_SOFTC sc, + HAL_BUS_TAG st, HAL_BUS_HANDLE sh, HAL_STATUS *status) +{ + struct ath_hal_5416 *ahp5416; + struct ath_hal_5212 *ahp; + struct ath_hal *ah; + uint32_t val; + HAL_STATUS ecode; + HAL_BOOL rfStatus; + + 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 */ + ahp5416 = ath_hal_malloc(sizeof (struct ath_hal_5416) + + /* extra space for Owl 2.1/2.2 WAR */ + sizeof(ar5416Addac) + ); + if (ahp5416 == AH_NULL) { + HALDEBUG(AH_NULL, HAL_DEBUG_ANY, + "%s: cannot allocate memory for state block\n", __func__); + *status = HAL_ENOMEM; + return AH_NULL; + } + ar5416InitState(ahp5416, devid, sc, st, sh, status); + ahp = &ahp5416->ah_5212; + ah = &ahp->ah_priv.h; + + if (!ar5416SetResetReg(ah, HAL_RESET_POWER_ON)) { + /* reset chip */ + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: couldn't reset chip\n", __func__); + ecode = HAL_EIO; + goto bad; + } + + if (!ar5416SetPowerMode(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; + + /* setup common ini data; rf backends handle remainder */ + HAL_INI_INIT(&ahp->ah_ini_modes, ar5416Modes, 6); + HAL_INI_INIT(&ahp->ah_ini_common, ar5416Common, 2); + + HAL_INI_INIT(&AH5416(ah)->ah_ini_bb_rfgain, ar5416BB_RfGain, 3); + HAL_INI_INIT(&AH5416(ah)->ah_ini_bank0, ar5416Bank0, 2); + HAL_INI_INIT(&AH5416(ah)->ah_ini_bank1, ar5416Bank1, 2); + HAL_INI_INIT(&AH5416(ah)->ah_ini_bank2, ar5416Bank2, 2); + HAL_INI_INIT(&AH5416(ah)->ah_ini_bank3, ar5416Bank3, 3); + HAL_INI_INIT(&AH5416(ah)->ah_ini_bank6, ar5416Bank6, 3); + HAL_INI_INIT(&AH5416(ah)->ah_ini_bank7, ar5416Bank7, 2); + HAL_INI_INIT(&AH5416(ah)->ah_ini_addac, ar5416Addac, 2); + + if (!IS_5416V2_2(ah)) { /* Owl 2.1/2.0 */ + struct ini { + uint32_t *data; /* NB: !const */ + int rows, cols; + }; + /* override CLKDRV value */ + OS_MEMCPY(&AH5416(ah)[1], ar5416Addac, sizeof(ar5416Addac)); + AH5416(ah)->ah_ini_addac.data = (uint32_t *) &AH5416(ah)[1]; + HAL_INI_VAL((struct ini *)&AH5416(ah)->ah_ini_addac, 31, 1) = 0; + } + + if (!ar5416ChipReset(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 (!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); + switch (AH_PRIVATE(ah)->ah_analog5GhzRev & AR_RADIO_SREV_MAJOR) { + case AR_RAD5122_SREV_MAJOR: /* Fowl: 5G/2x2 */ + case AR_RAD2122_SREV_MAJOR: /* Fowl: 2+5G/2x2 */ + case AR_RAD2133_SREV_MAJOR: /* Fowl: 2G/3x3 */ + case AR_RAD5133_SREV_MAJOR: /* Fowl: 2+5G/3x3 */ + break; + default: + if (AH_PRIVATE(ah)->ah_analog5GhzRev == 0) { + /* + * When RF_Silen is used the analog chip is reset. + * So when the system boots with radio switch off + * the RF chip rev reads back as zero and we need + * to use the mac+phy revs to set the radio rev. + */ + AH_PRIVATE(ah)->ah_analog5GhzRev = + AR_RAD5133_SREV_MAJOR; + break; + } + /* NB: silently accept anything in release code per Atheros */ +#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 + } + + ecode = ath_hal_v14EepromAttach(ah); + if (ecode != HAL_OK) + goto bad; + + /* + * Got everything we need now to setup the capabilities. + */ + if (!ar5416FillCapabilityInfo(ah)) { + ecode = HAL_EEREAD; + goto bad; + } + + 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; + } + /* XXX How about the serial number ? */ + /* Read Reg Domain */ + AH_PRIVATE(ah)->ah_currentRD = + ath_hal_eepromGet(ah, AR_EEP_REGDMN_0, AH_NULL); + + /* + * ah_miscMode is populated by ar5416FillCapabilityInfo() + * starting from griffin. Set here to make sure that + * AR_MISC_MODE_MIC_NEW_LOC_ENABLE is set before a GTK is + * placed into hardware. + */ + if (ahp->ah_miscMode != 0) + OS_REG_WRITE(ah, AR_MISC_MODE, ahp->ah_miscMode); + + HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s: Attaching AR2133 radio\n", + __func__); + rfStatus = ar2133RfAttach(ah, &ecode); + if (!rfStatus) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: RF setup failed, status %u\n", + __func__, ecode); + goto bad; + } + + ar5416AniSetup(ah); /* Anti Noise Immunity */ + ar5416InitNfHistBuff(AH5416(ah)->ah_cal.nfCalHist); + + HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s: return\n", __func__); + + return ah; +bad: + if (ahp) + ar5416Detach((struct ath_hal *) ahp); + if (status) + *status = ecode; + return AH_NULL; +} + +void +ar5416Detach(struct ath_hal *ah) +{ + HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s:\n", __func__); + + HALASSERT(ah != AH_NULL); + HALASSERT(ah->ah_magic == AR5416_MAGIC); + + ar5416AniDetach(ah); + ar5212RfDetach(ah); + ah->ah_disable(ah); + ar5416SetPowerMode(ah, HAL_PM_FULL_SLEEP, AH_TRUE); + ath_hal_eepromDetach(ah); + ath_hal_free(ah); +} + +/* + * Fill all software cached or static hardware state information. + * Return failure if capabilities are to come from EEPROM and + * cannot be read. + */ +HAL_BOOL +ar5416FillCapabilityInfo(struct ath_hal *ah) +{ + struct ath_hal_private *ahpriv = AH_PRIVATE(ah); + HAL_CAPABILITIES *pCap = &ahpriv->ah_caps; + uint16_t val; + + /* Construct wireless mode from EEPROM */ + pCap->halWirelessModes = 0; + if (ath_hal_eepromGetFlag(ah, AR_EEP_AMODE)) { + pCap->halWirelessModes |= HAL_MODE_11A + | HAL_MODE_11NA_HT20 + | HAL_MODE_11NA_HT40PLUS + | HAL_MODE_11NA_HT40MINUS + ; + } + if (ath_hal_eepromGetFlag(ah, AR_EEP_GMODE)) { + pCap->halWirelessModes |= HAL_MODE_11G + | HAL_MODE_11NG_HT20 + | HAL_MODE_11NG_HT40PLUS + | HAL_MODE_11NG_HT40MINUS + ; + pCap->halWirelessModes |= HAL_MODE_11A + | HAL_MODE_11NA_HT20 + | HAL_MODE_11NA_HT40PLUS + | HAL_MODE_11NA_HT40MINUS + ; + } + + pCap->halLow2GhzChan = 2312; + 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); + + 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. + */ + pCap->halTkipMicTxRxKeySupport = AH_TRUE; + pCap->halChanSpreadSupport = AH_TRUE; + pCap->halSleepAfterBeaconBroken = AH_TRUE; + + pCap->halCompressSupport = AH_FALSE; + pCap->halBurstSupport = AH_TRUE; + pCap->halFastFramesSupport = AH_FALSE; /* XXX? */ + 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_FALSE; + 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 = AR5416_KEYTABLE_SIZE; + + /* XXX not needed */ + pCap->halChanHalfRate = AH_FALSE; /* XXX ? */ + pCap->halChanQuarterRate = AH_FALSE; /* XXX ? */ + + pCap->halTstampPrecision = 32; + pCap->halHwPhyCounterSupport = AH_TRUE; + + pCap->halFastCCSupport = AH_TRUE; + pCap->halNumGpioPins = 6; + pCap->halWowSupport = AH_FALSE; + pCap->halWowMatchPatternExact = AH_FALSE; + pCap->halBtCoexSupport = AH_FALSE; /* XXX need support */ + pCap->halAutoSleepSupport = AH_FALSE; +#if 0 /* XXX not yet */ + pCap->halNumAntCfg2GHz = ar5416GetNumAntConfig(ahp, HAL_FREQ_BAND_2GHZ); + pCap->halNumAntCfg5GHz = ar5416GetNumAntConfig(ahp, HAL_FREQ_BAND_5GHZ); +#endif + pCap->halHTSupport = AH_TRUE; + pCap->halTxChainMask = ath_hal_eepromGet(ah, AR_EEP_TXMASK, AH_NULL); + /* XXX CB71 uses GPIO 0 to indicate 3 rx chains */ + pCap->halRxChainMask = ath_hal_eepromGet(ah, AR_EEP_RXMASK, AH_NULL); + pCap->halRtsAggrLimit = 8*1024; /* Owl 2.0 limit */ + pCap->halMbssidAggrSupport = AH_TRUE; + pCap->halForcePpmSupport = AH_TRUE; + pCap->halEnhancedPmSupport = 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; + } + + ahpriv->ah_rxornIsFatal = AH_FALSE; + + return AH_TRUE; +} + +static const char* +ar5416Probe(uint16_t vendorid, uint16_t devid) +{ + if (vendorid == ATHEROS_VENDOR_ID && + (devid == AR5416_DEVID_PCI || devid == AR5416_DEVID_PCIE)) + return "Atheros 5416"; + return AH_NULL; +} +AH_CHIP(AR5416, ar5416Probe, ar5416Attach); --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5210/ar5416_beacon.c 2009-03-23 17:36:56.000000000 +0000 @@ -0,0 +1,246 @@ +/* + * 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: ar5416_beacon.c,v 1.1 2009/03/23 17:14:48 sborrill Exp $ + */ +#include "opt_ah.h" + +#include "ah.h" +#include "ah_internal.h" + +#include "ar5416/ar5416.h" +#include "ar5416/ar5416reg.h" +#include "ar5416/ar5416phy.h" + +#define TU_TO_USEC(_tu) ((_tu) << 10) + +/* + * Initialize all of the hardware registers used to + * send beacons. Note that for station operation the + * driver calls ar5416SetStaBeaconTimers instead. + */ +void +ar5416SetBeaconTimers(struct ath_hal *ah, const HAL_BEACON_TIMERS *bt) +{ + uint32_t bperiod; + + OS_REG_WRITE(ah, AR_NEXT_TBTT, TU_TO_USEC(bt->bt_nexttbtt)); + OS_REG_WRITE(ah, AR_NEXT_DBA, TU_TO_USEC(bt->bt_nextdba) >> 3); + OS_REG_WRITE(ah, AR_NEXT_SWBA, TU_TO_USEC(bt->bt_nextswba) >> 3); + OS_REG_WRITE(ah, AR_NEXT_NDP, TU_TO_USEC(bt->bt_nextatim)); + + bperiod = TU_TO_USEC(bt->bt_intval & HAL_BEACON_PERIOD); + OS_REG_WRITE(ah, AR5416_BEACON_PERIOD, bperiod); + OS_REG_WRITE(ah, AR_DBA_PERIOD, bperiod); + OS_REG_WRITE(ah, AR_SWBA_PERIOD, bperiod); + OS_REG_WRITE(ah, AR_NDP_PERIOD, bperiod); + + /* + * Reset TSF if required. + */ + if (bt->bt_intval & AR_BEACON_RESET_TSF) + ar5416ResetTsf(ah); + + /* enable timers */ + /* NB: flags == 0 handled specially for backwards compatibility */ + OS_REG_SET_BIT(ah, AR_TIMER_MODE, + bt->bt_flags != 0 ? bt->bt_flags : + AR_TIMER_MODE_TBTT | AR_TIMER_MODE_DBA | AR_TIMER_MODE_SWBA); +} + +/* + * Initializes all of the hardware registers used to + * send beacons. Note that for station operation the + * driver calls ar5212SetStaBeaconTimers instead. + */ +void +ar5416BeaconInit(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. + */ + bt.bt_flags = 0; + switch (AH_PRIVATE(ah)->ah_opmode) { + case HAL_M_STA: + case HAL_M_MONITOR: + bt.bt_nextdba = 0xffff; + bt.bt_nextswba = 0x7ffff; + bt.bt_flags |= AR_TIMER_MODE_TBTT; + break; + case HAL_M_IBSS: + OS_REG_SET_BIT(ah, AR_TXCFG, AR_TXCFG_ATIM_TXPOLICY); + bt.bt_flags |= AR_TIMER_MODE_NDP; + /* fall thru... */ + 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 */ + bt.bt_flags |= AR_TIMER_MODE_TBTT + | AR_TIMER_MODE_DBA + | AR_TIMER_MODE_SWBA; + 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); + ar5416SetBeaconTimers(ah, &bt); +} + +#define AR_BEACON_PERIOD_MAX 0xffff + +void +ar5416ResetStaBeaconTimers(struct ath_hal *ah) +{ + uint32_t val; + + OS_REG_WRITE(ah, AR_NEXT_TBTT, 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, AR5416_BEACON_PERIOD, AR_BEACON_PERIOD_MAX); + OS_REG_WRITE(ah, AR_DBA_PERIOD, AR_BEACON_PERIOD_MAX); +} + +/* + * 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 +ar5416SetStaBeaconTimers(struct ath_hal *ah, const HAL_BEACON_STATE *bs) +{ + uint32_t nextTbtt, nextdtim,beaconintval, dtimperiod; + + HALASSERT(bs->bs_intval != 0); + + /* NB: no cfp setting since h/w automatically takes care */ + + OS_REG_WRITE(ah, AR_NEXT_TBTT, bs->bs_nexttbtt); + + /* + * Start the beacon timers by setting the BEACON register + * to the beacon interval; no need to write tim offset since + * h/w parses IEs. + */ + OS_REG_WRITE(ah, AR5416_BEACON_PERIOD, + TU_TO_USEC(bs->bs_intval & HAL_BEACON_PERIOD)); + OS_REG_WRITE(ah, AR_DBA_PERIOD, + TU_TO_USEC(bs->bs_intval & HAL_BEACON_PERIOD)); + + /* + * Configure the BMISS interrupt. Note that we + * assume the caller blocks interrupts while enabling + * the threshold. + */ + HALASSERT(bs->bs_bmissthreshold <= + (AR_RSSI_THR_BM_THR >> AR_RSSI_THR_BM_THR_S)); + OS_REG_RMW_FIELD(ah, AR_RSSI_THR, + AR_RSSI_THR_BM_THR, bs->bs_bmissthreshold); + + /* + * 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_NEXT_DTIM, + TU_TO_USEC(bs->bs_nextdtim - SLEEP_SLOP)); + OS_REG_WRITE(ah, AR_NEXT_TIM, TU_TO_USEC(nextTbtt - SLEEP_SLOP)); + + /* cab timeout is now in 1/8 TU */ + OS_REG_WRITE(ah, AR_SLEEP1, + SM((CAB_TIMEOUT_VAL << 3), AR5416_SLEEP1_CAB_TIMEOUT) + | AR_SLEEP1_ASSUME_DTIM); + /* beacon timeout is now in 1/8 TU */ + OS_REG_WRITE(ah, AR_SLEEP2, + SM((BEACON_TIMEOUT_VAL << 3), AR5416_SLEEP2_BEACON_TIMEOUT)); + + OS_REG_WRITE(ah, AR_TIM_PERIOD, beaconintval); + OS_REG_WRITE(ah, AR_DTIM_PERIOD, dtimperiod); + OS_REG_SET_BIT(ah, AR_TIMER_MODE, + AR_TIMER_MODE_TBTT | AR_TIMER_MODE_TIM | AR_TIMER_MODE_DTIM); + 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/ar5210/ar5416_cal.c 2009-03-23 17:36:56.000000000 +0000 @@ -0,0 +1,663 @@ +/* + * 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: ar5416_cal.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 "ah_eeprom_v14.h" + +#include "ar5416/ar5416.h" +#include "ar5416/ar5416reg.h" +#include "ar5416/ar5416phy.h" + +/* Owl specific stuff */ +#define NUM_NOISEFLOOR_READINGS 6 /* 3 chains * (ctl + ext) */ + +static void ar5416StartNFCal(struct ath_hal *ah); +static void ar5416LoadNF(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *); +static int16_t ar5416GetNf(struct ath_hal *, HAL_CHANNEL_INTERNAL *); + +/* + * Determine if calibration is supported by device and channel flags + */ +static OS_INLINE HAL_BOOL +ar5416IsCalSupp(struct ath_hal *ah, HAL_CHANNEL *chan, HAL_CAL_TYPE calType) +{ + struct ar5416PerCal *cal = &AH5416(ah)->ah_cal; + + switch (calType & cal->suppCals) { + case IQ_MISMATCH_CAL: + /* Run IQ Mismatch for non-CCK only */ + return !IS_CHAN_B(chan); + case ADC_GAIN_CAL: + case ADC_DC_CAL: + /* Run ADC Gain Cal for non-CCK & non 2GHz-HT20 only */ + return !IS_CHAN_B(chan) && + !(IS_CHAN_2GHZ(chan) && IS_CHAN_HT20(chan)); + } + return AH_FALSE; +} + +/* + * Setup HW to collect samples used for current cal + */ +static void +ar5416SetupMeasurement(struct ath_hal *ah, HAL_CAL_LIST *currCal) +{ + /* Start 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, + currCal->calData->calCountMax); + + /* Select calibration to run */ + switch (currCal->calData->calType) { + case IQ_MISMATCH_CAL: + OS_REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ); + HALDEBUG(ah, HAL_DEBUG_PERCAL, + "%s: start IQ Mismatch calibration\n", __func__); + break; + case ADC_GAIN_CAL: + OS_REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_GAIN); + HALDEBUG(ah, HAL_DEBUG_PERCAL, + "%s: start ADC Gain calibration\n", __func__); + break; + case ADC_DC_CAL: + OS_REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_PER); + HALDEBUG(ah, HAL_DEBUG_PERCAL, + "%s: start ADC DC calibration\n", __func__); + break; + case ADC_DC_INIT_CAL: + OS_REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_INIT); + HALDEBUG(ah, HAL_DEBUG_PERCAL, + "%s: start Init ADC DC calibration\n", __func__); + break; + } + /* Kick-off cal */ + OS_REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4, AR_PHY_TIMING_CTRL4_DO_CAL); +} + +/* + * Initialize shared data structures and prepare a cal to be run. + */ +static void +ar5416ResetMeasurement(struct ath_hal *ah, HAL_CAL_LIST *currCal) +{ + struct ar5416PerCal *cal = &AH5416(ah)->ah_cal; + + /* Reset data structures shared between different calibrations */ + OS_MEMZERO(cal->caldata, sizeof(cal->caldata)); + cal->calSamples = 0; + + /* Setup HW for new calibration */ + ar5416SetupMeasurement(ah, currCal); + + /* Change SW state to RUNNING for this calibration */ + currCal->calState = CAL_RUNNING; +} + +#if 0 +/* + * Run non-periodic calibrations. + */ +static HAL_BOOL +ar5416RunInitCals(struct ath_hal *ah, int init_cal_count) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416PerCal *cal = &AH5416(ah)->ah_cal; + HAL_CHANNEL_INTERNAL ichan; /* XXX bogus */ + HAL_CAL_LIST *curCal = ahp->ah_cal_curr; + HAL_BOOL isCalDone; + int i; + + if (curCal == AH_NULL) + return AH_FALSE; + + ichan.calValid = 0; + for (i = 0; i < init_cal_count; i++) { + /* Reset this Cal */ + ar5416ResetMeasurement(ah, curCal); + /* Poll for offset calibration complete */ + if (!ath_hal_wait(ah, AR_PHY_TIMING_CTRL4, AR_PHY_TIMING_CTRL4_DO_CAL, 0)) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: Cal %d failed to finish in 100ms.\n", + __func__, curCal->calData->calType); + /* Re-initialize list pointers for periodic cals */ + cal->cal_list = cal->cal_last = cal->cal_curr = AH_NULL; + return AH_FALSE; + } + /* Run this cal */ + ar5416DoCalibration(ah, &ichan, ahp->ah_rxchainmask, + curCal, &isCalDone); + if (!isCalDone) + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: init cal %d did not complete.\n", + __func__, curCal->calData->calType); + if (curCal->calNext != AH_NULL) + curCal = curCal->calNext; + } + + /* Re-initialize list pointers for periodic cals */ + cal->cal_list = cal->cal_last = cal->cal_curr = AH_NULL; + return AH_TRUE; +} +#endif + +/* + * Initialize Calibration infrastructure. + */ +HAL_BOOL +ar5416InitCal(struct ath_hal *ah, HAL_CHANNEL *chan) +{ + struct ar5416PerCal *cal = &AH5416(ah)->ah_cal; + HAL_CHANNEL_INTERNAL *ichan; + + ichan = ath_hal_checkchannel(ah, chan); + HALASSERT(ichan != AH_NULL); + + if (AR_SREV_MERLIN_10_OR_LATER(ah)) { + /* Enable Rx Filter Cal */ + OS_REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); + OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, + AR_PHY_AGC_CONTROL_FLTR_CAL); + + /* Clear the carrier leak cal bit */ + OS_REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); + + /* kick off the cal */ + OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL); + + /* Poll for offset calibration complete */ + 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__); + return AH_FALSE; + } + + /* Set the cl cal bit and rerun the cal a 2nd time */ + /* Enable Rx Filter Cal */ + OS_REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); + OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, + AR_PHY_AGC_CONTROL_FLTR_CAL); + + OS_REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); + } + + /* Calibrate the AGC */ + OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL); + + /* Poll for offset calibration complete */ + if (!ath_hal_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0)) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: offset calibration did not complete in 1ms; " + "noisy environment?\n", __func__); + return AH_FALSE; + } + + /* + * Do NF calibration after DC offset and other CALs. + * Per system engineers, noise floor value can sometimes be 20 dB + * higher than normal value if DC offset and noise floor cal are + * triggered at the same time. + */ + OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); + + /* Initialize list pointers */ + cal->cal_list = cal->cal_last = cal->cal_curr = AH_NULL; + + /* + * Enable IQ, ADC Gain, ADC DC Offset Cals + */ + if (AR_SREV_SOWL_10_OR_LATER(ah)) { + /* Setup all non-periodic, init time only calibrations */ + /* XXX: Init DC Offset not working yet */ +#if 0 + if (ar5416IsCalSupp(ah, chan, ADC_DC_INIT_CAL)) { + INIT_CAL(&cal->adcDcCalInitData); + INSERT_CAL(cal, &cal->adcDcCalInitData); + } + /* Initialize current pointer to first element in list */ + cal->cal_curr = cal->cal_list; + + if (cal->ah_cal_curr != AH_NULL && !ar5416RunInitCals(ah, 0)) + return AH_FALSE; +#endif + } + + /* If Cals are supported, add them to list via INIT/INSERT_CAL */ + if (ar5416IsCalSupp(ah, chan, ADC_GAIN_CAL)) { + INIT_CAL(&cal->adcGainCalData); + INSERT_CAL(cal, &cal->adcGainCalData); + HALDEBUG(ah, HAL_DEBUG_PERCAL, + "%s: enable ADC Gain Calibration.\n", __func__); + } + if (ar5416IsCalSupp(ah, chan, ADC_DC_CAL)) { + INIT_CAL(&cal->adcDcCalData); + INSERT_CAL(cal, &cal->adcDcCalData); + HALDEBUG(ah, HAL_DEBUG_PERCAL, + "%s: enable ADC DC Calibration.\n", __func__); + } + if (ar5416IsCalSupp(ah, chan, IQ_MISMATCH_CAL)) { + INIT_CAL(&cal->iqCalData); + INSERT_CAL(cal, &cal->iqCalData); + HALDEBUG(ah, HAL_DEBUG_PERCAL, + "%s: enable IQ Calibration.\n", __func__); + } + /* Initialize current pointer to first element in list */ + cal->cal_curr = cal->cal_list; + + /* Kick off measurements for the first cal */ + if (cal->cal_curr != AH_NULL) + ar5416ResetMeasurement(ah, cal->cal_curr); + + /* Mark all calibrations on this channel as being invalid */ + ichan->calValid = 0; + + return AH_TRUE; +} + +/* + * Entry point for upper layers to restart current cal. + * Reset the calibration valid bit in channel. + */ +HAL_BOOL +ar5416ResetCalValid(struct ath_hal *ah, HAL_CHANNEL *chan) +{ + struct ar5416PerCal *cal = &AH5416(ah)->ah_cal; + HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan); + HAL_CAL_LIST *currCal = cal->cal_curr; + + if (!AR_SREV_SOWL_10_OR_LATER(ah)) + return AH_FALSE; + if (currCal == AH_NULL) + return AH_FALSE; + 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; + } + /* + * Expected that this calibration has run before, post-reset. + * Current state should be done + */ + if (currCal->calState != CAL_DONE) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: Calibration state incorrect, %d\n", + __func__, currCal->calState); + return AH_FALSE; + } + + /* Verify Cal is supported on this channel */ + if (!ar5416IsCalSupp(ah, chan, currCal->calData->calType)) + return AH_FALSE; + + HALDEBUG(ah, HAL_DEBUG_PERCAL, + "%s: Resetting Cal %d state for channel %u/0x%x\n", + __func__, currCal->calData->calType, chan->channel, + chan->channelFlags); + + /* Disable cal validity in channel */ + ichan->calValid &= ~currCal->calData->calType; + currCal->calState = CAL_WAITING; + + return AH_TRUE; +} + +/* + * Recalibrate the lower PHY chips to account for temperature/environment + * changes. + */ +static void +ar5416DoCalibration(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan, + uint8_t rxchainmask, HAL_CAL_LIST *currCal, HAL_BOOL *isCalDone) +{ + struct ar5416PerCal *cal = &AH5416(ah)->ah_cal; + + /* Cal is assumed not done until explicitly set below */ + *isCalDone = AH_FALSE; + + HALDEBUG(ah, HAL_DEBUG_PERCAL, + "%s: %s Calibration, state %d, calValid 0x%x\n", + __func__, currCal->calData->calName, currCal->calState, + ichan->calValid); + + /* Calibration in progress. */ + if (currCal->calState == CAL_RUNNING) { + /* Check to see if it has finished. */ + if (!(OS_REG_READ(ah, AR_PHY_TIMING_CTRL4) & AR_PHY_TIMING_CTRL4_DO_CAL)) { + HALDEBUG(ah, HAL_DEBUG_PERCAL, + "%s: sample %d of %d finished\n", + __func__, cal->calSamples, + currCal->calData->calNumSamples); + /* + * Collect measurements for active chains. + */ + currCal->calData->calCollect(ah); + if (++cal->calSamples >= currCal->calData->calNumSamples) { + int i, numChains = 0; + for (i = 0; i < AR5416_MAX_CHAINS; i++) { + if (rxchainmask & (1 << i)) + numChains++; + } + /* + * Process accumulated data + */ + currCal->calData->calPostProc(ah, numChains); + + /* Calibration has finished. */ + ichan->calValid |= currCal->calData->calType; + currCal->calState = CAL_DONE; + *isCalDone = AH_TRUE; + } else { + /* + * Set-up to collect of another sub-sample. + */ + ar5416SetupMeasurement(ah, currCal); + } + } + } else if (!(ichan->calValid & currCal->calData->calType)) { + /* If current cal is marked invalid in channel, kick it off */ + ar5416ResetMeasurement(ah, currCal); + } +} + +/* + * Internal interface to schedule periodic calibration work. + */ +HAL_BOOL +ar5416PerCalibrationN(struct ath_hal *ah, HAL_CHANNEL *chan, + u_int rxchainmask, HAL_BOOL longcal, HAL_BOOL *isCalDone) +{ + struct ar5416PerCal *cal = &AH5416(ah)->ah_cal; + HAL_CAL_LIST *currCal = cal->cal_curr; + HAL_CHANNEL_INTERNAL *ichan; + + OS_MARK(ah, AH_MARK_PERCAL, chan->channel); + + *isCalDone = AH_TRUE; + + /* Invalid channel check */ + 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; + } + + /* + * For given calibration: + * 1. Call generic cal routine + * 2. When this cal is done (isCalDone) if we have more cals waiting + * (eg after reset), mask this to upper layers by not propagating + * isCalDone if it is set to TRUE. + * Instead, change isCalDone to FALSE and setup the waiting cal(s) + * to be run. + */ + if (currCal != AH_NULL && + (currCal->calState == CAL_RUNNING || + currCal->calState == CAL_WAITING)) { + ar5416DoCalibration(ah, ichan, rxchainmask, currCal, isCalDone); + if (*isCalDone == AH_TRUE) { + cal->cal_curr = currCal = currCal->calNext; + if (currCal->calState == CAL_WAITING) { + *isCalDone = AH_FALSE; + ar5416ResetMeasurement(ah, currCal); + } + } + } + + /* Do NF cal only at longer intervals */ + if (longcal) { + /* + * Get the value from the previous NF cal + * and update the history buffer. + */ + ar5416GetNf(ah, ichan); + + /* + * Load the NF from history buffer of the current channel. + * NF is slow time-variant, so it is OK to use a + * historical value. + */ + ar5416LoadNF(ah, AH_PRIVATE(ah)->ah_curchan); + + /* start NF calibration, without updating BB NF register*/ + ar5416StartNFCal(ah); + + if ((ichan->channelFlags & CHANNEL_CW_INT) != 0) { + /* report up and clear internal state */ + chan->channelFlags |= CHANNEL_CW_INT; + ichan->channelFlags &= ~CHANNEL_CW_INT; + } + } + return AH_TRUE; +} + +/* + * Recalibrate the lower PHY chips to account for temperature/environment + * changes. + */ +HAL_BOOL +ar5416PerCalibration(struct ath_hal *ah, HAL_CHANNEL *chan, HAL_BOOL *isIQdone) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416PerCal *cal = &AH5416(ah)->ah_cal; + HAL_CAL_LIST *curCal = cal->cal_curr; + + if (curCal != AH_NULL && curCal->calData->calType == IQ_MISMATCH_CAL) { + return ar5416PerCalibrationN(ah, chan, ahp->ah_rx_chainmask, + AH_TRUE, isIQdone); + } else { + HAL_BOOL isCalDone; + + *isIQdone = AH_FALSE; + return ar5416PerCalibrationN(ah, chan, ahp->ah_rx_chainmask, + AH_TRUE, &isCalDone); + } +} + +static HAL_BOOL +ar5416GetEepromNoiseFloorThresh(struct ath_hal *ah, + const HAL_CHANNEL_INTERNAL *chan, int16_t *nft) +{ + switch (chan->channelFlags & CHANNEL_ALL_NOTURBO) { + case CHANNEL_A: + case CHANNEL_A_HT20: + case CHANNEL_A_HT40PLUS: + case CHANNEL_A_HT40MINUS: + ath_hal_eepromGet(ah, AR_EEP_NFTHRESH_5, nft); + break; + case CHANNEL_B: + case CHANNEL_G: + case CHANNEL_G_HT20: + case CHANNEL_G_HT40PLUS: + case CHANNEL_G_HT40MINUS: + ath_hal_eepromGet(ah, AR_EEP_NFTHRESH_2, nft); + break; + default: + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: invalid channel flags 0x%x\n", + __func__, chan->channelFlags); + return AH_FALSE; + } + return AH_TRUE; +} + +static void +ar5416StartNFCal(struct ath_hal *ah) +{ + 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); +} + +static void +ar5416LoadNF(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan) +{ + static const uint32_t ar5416_cca_regs[] = { + AR_PHY_CCA, + AR_PHY_CH1_CCA, + AR_PHY_CH2_CCA, + AR_PHY_EXT_CCA, + AR_PHY_CH1_EXT_CCA, + AR_PHY_CH2_EXT_CCA + }; + struct ar5212NfCalHist *h; + int i, j; + int32_t val; + uint8_t chainmask; + + /* + * Force NF calibration for all chains. + */ + if (AR_SREV_KITE(ah)) { + /* Kite has only one chain */ + chainmask = 0x9; + } else if (AR_SREV_MERLIN(ah)) { + /* Merlin has only two chains */ + chainmask = 0x1B; + } else { + chainmask = 0x3F; + } + + /* + * Write filtered NF values into maxCCApwr register parameter + * so we can load below. + */ + h = AH5416(ah)->ah_cal.nfCalHist; + for (i = 0; i < AR5416_NUM_NF_READINGS; i ++) + if (chainmask & (1 << i)) { + val = OS_REG_READ(ah, ar5416_cca_regs[i]); + val &= 0xFFFFFE00; + val |= (((uint32_t)(h[i].privNF) << 1) & 0x1ff); + OS_REG_WRITE(ah, ar5416_cca_regs[i], val); + } + + /* Load software filtered NF value into baseband internal minCCApwr variable. */ + 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); + + /* Wait for load to complete, should be fast, a few 10s of us. */ + for (j = 0; j < 1000; j++) { + if ((OS_REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) == 0) + break; + OS_DELAY(10); + } + + /* + * Restore maxCCAPower register parameter again so that we're not capped + * by the median we just loaded. This will be initial (and max) value + * of next noise floor calibration the baseband does. + */ + for (i = 0; i < AR5416_NUM_NF_READINGS; i ++) + if (chainmask & (1 << i)) { + val = OS_REG_READ(ah, ar5416_cca_regs[i]); + val &= 0xFFFFFE00; + val |= (((uint32_t)(-50) << 1) & 0x1ff); + OS_REG_WRITE(ah, ar5416_cca_regs[i], val); + } +} + +void +ar5416InitNfHistBuff(struct ar5212NfCalHist *h) +{ + int i, j; + + for (i = 0; i < AR5416_NUM_NF_READINGS; i ++) { + h[i].currIndex = 0; + h[i].privNF = AR5416_CCA_MAX_GOOD_VALUE; + h[i].invalidNFcount = AR512_NF_CAL_HIST_MAX; + for (j = 0; j < AR512_NF_CAL_HIST_MAX; j ++) + h[i].nfCalBuffer[j] = AR5416_CCA_MAX_GOOD_VALUE; + } +} + +/* + * Update the noise floor buffer as a ring buffer + */ +static void +ar5416UpdateNFHistBuff(struct ar5212NfCalHist *h, int16_t *nfarray) +{ + int i; + + for (i = 0; i < AR5416_NUM_NF_READINGS; i ++) { + h[i].nfCalBuffer[h[i].currIndex] = nfarray[i]; + + if (++h[i].currIndex >= AR512_NF_CAL_HIST_MAX) + h[i].currIndex = 0; + if (h[i].invalidNFcount > 0) { + if (nfarray[i] < AR5416_CCA_MIN_BAD_VALUE || + nfarray[i] > AR5416_CCA_MAX_HIGH_VALUE) { + h[i].invalidNFcount = AR512_NF_CAL_HIST_MAX; + } else { + h[i].invalidNFcount--; + h[i].privNF = nfarray[i]; + } + } else { + h[i].privNF = ar5212GetNfHistMid(h[i].nfCalBuffer); + } + } +} + +/* + * Read the NF and check it against the noise floor threshhold + */ +static int16_t +ar5416GetNf(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan) +{ + int16_t nf, nfThresh; + + if (OS_REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: NF didn't complete in calibration window\n", __func__); + nf = 0; + } else { + /* Finished NF cal, check against threshold */ + int16_t nfarray[NUM_NOISEFLOOR_READINGS] = { 0 }; + + /* TODO - enhance for multiple chains and ext ch */ + ath_hal_getNoiseFloor(ah, nfarray); + nf = nfarray[0]; + if (ar5416GetEepromNoiseFloorThresh(ah, chan, &nfThresh)) { + if (nf > nfThresh) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: noise floor failed detected; " + "detected %d, threshold %d\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; + } + ar5416UpdateNFHistBuff(AH5416(ah)->ah_cal.nfCalHist, nfarray); + chan->rawNoiseFloor = nf; + } + return nf; +} --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5210/ar5416_cal.h 2009-03-23 17:36:56.000000000 +0000 @@ -0,0 +1,119 @@ +/* + * 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: ar5416_cal.h,v 1.1 2009/03/23 17:14:48 sborrill Exp $ + */ +#ifndef _ATH_AR5416_CAL_H_ +#define _ATH_AR5416_CAL_H_ + +typedef enum { + ADC_DC_INIT_CAL = 0x1, + ADC_GAIN_CAL = 0x2, + ADC_DC_CAL = 0x4, + IQ_MISMATCH_CAL = 0x8 +} HAL_CAL_TYPE; + +/* Calibrate state */ +typedef enum { + CAL_INACTIVE, + CAL_WAITING, + CAL_RUNNING, + CAL_DONE +} HAL_CAL_STATE; + +typedef union { + uint32_t u; + int32_t s; +} HAL_CAL_SAMPLE; + +#define MIN_CAL_SAMPLES 1 +#define MAX_CAL_SAMPLES 64 +#define INIT_LOG_COUNT 5 +#define PER_MIN_LOG_COUNT 2 +#define PER_MAX_LOG_COUNT 10 + +/* Per Calibration data structure */ +typedef struct per_cal_data { + const char *calName; /* for diagnostics */ + HAL_CAL_TYPE calType; /* Type of calibration */ + uint32_t calNumSamples; /* # SW samples to collect */ + uint32_t calCountMax; /* # HW samples to collect */ + void (*calCollect)(struct ath_hal *); /* Accumulator function */ + /* Post-processing function */ + void (*calPostProc)(struct ath_hal *, uint8_t); +} HAL_PERCAL_DATA; + +/* List structure for calibration data */ +typedef struct cal_list { + struct cal_list *calNext; + HAL_CAL_STATE calState; + const HAL_PERCAL_DATA *calData; +} HAL_CAL_LIST; + +struct ar5416PerCal { + /* + * Periodic calibration state. + */ + HAL_CAL_TYPE suppCals; + HAL_CAL_LIST iqCalData; + HAL_CAL_LIST adcGainCalData; + HAL_CAL_LIST adcDcCalInitData; + HAL_CAL_LIST adcDcCalData; + HAL_CAL_LIST *cal_list; + HAL_CAL_LIST *cal_last; + HAL_CAL_LIST *cal_curr; +#define AR5416_MAX_CHAINS 3 /* XXX dup's eeprom def */ + HAL_CAL_SAMPLE caldata[4][AR5416_MAX_CHAINS]; + int calSamples; + /* + * Noise floor cal histogram support. + * XXX be nice to re-use space in ar5212 + */ +#define AR5416_NUM_NF_READINGS 6 /* (3 chains * (ctl + ext) */ + struct ar5212NfCalHist nfCalHist[AR5416_NUM_NF_READINGS]; +}; + +#define INIT_CAL(_perCal) do { \ + (_perCal)->calState = CAL_WAITING; \ + (_perCal)->calNext = AH_NULL; \ +} while (0) + +#define INSERT_CAL(_cal, _perCal) do { \ + if ((_cal)->cal_last == AH_NULL) { \ + (_cal)->cal_list = (_cal)->cal_last = (_perCal); \ + ((_cal)->cal_last)->calNext = (_perCal); \ + } else { \ + ((_cal)->cal_last)->calNext = (_perCal); \ + (_cal)->cal_last = (_perCal); \ + (_perCal)->calNext = (_cal)->cal_list; \ + } \ +} while (0) + +HAL_BOOL ar5416InitCal(struct ath_hal *ah, HAL_CHANNEL *chan); +HAL_BOOL ar5416PerCalibration(struct ath_hal *, HAL_CHANNEL *, + HAL_BOOL *isIQdone); +HAL_BOOL ar5416PerCalibrationN(struct ath_hal *ah, HAL_CHANNEL *chan, + u_int chainMask, HAL_BOOL longCal, HAL_BOOL *isCalDone); +HAL_BOOL ar5416ResetCalValid(struct ath_hal *ah, HAL_CHANNEL *chan); + +void ar5416IQCalCollect(struct ath_hal *ah); +void ar5416IQCalibration(struct ath_hal *ah, uint8_t numChains); +void ar5416AdcGainCalCollect(struct ath_hal *ah); +void ar5416AdcGainCalibration(struct ath_hal *ah, uint8_t numChains); +void ar5416AdcDcCalCollect(struct ath_hal *ah); +void ar5416AdcDcCalibration(struct ath_hal *ah, uint8_t numChains); +void ar5416InitNfHistBuff(struct ar5212NfCalHist *h); +#endif /* _ATH_AR5416_CAL_H_ */ --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5210/ar5416_cal_adcdc.c 2009-03-23 17:36:56.000000000 +0000 @@ -0,0 +1,111 @@ +/* + * 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: ar5416_cal_adcdc.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 "ar5416/ar5416.h" +#include "ar5416/ar5416reg.h" +#include "ar5416/ar5416phy.h" + +/* Adc DC Offset Cal aliases */ +#define totalAdcDcOffsetIOddPhase(i) caldata[0][i].s +#define totalAdcDcOffsetIEvenPhase(i) caldata[1][i].s +#define totalAdcDcOffsetQOddPhase(i) caldata[2][i].s +#define totalAdcDcOffsetQEvenPhase(i) caldata[3][i].s + +void +ar5416AdcDcCalCollect(struct ath_hal *ah) +{ + struct ar5416PerCal *cal = &AH5416(ah)->ah_cal; + int i; + + for (i = 0; i < AR5416_MAX_CHAINS; i++) { + cal->totalAdcDcOffsetIOddPhase(i) += (int32_t) + OS_REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); + cal->totalAdcDcOffsetIEvenPhase(i) += (int32_t) + OS_REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); + cal->totalAdcDcOffsetQOddPhase(i) += (int32_t) + OS_REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); + cal->totalAdcDcOffsetQEvenPhase(i) += (int32_t) + OS_REG_READ(ah, AR_PHY_CAL_MEAS_3(i)); + + HALDEBUG(ah, HAL_DEBUG_PERCAL, + "%d: Chn %d oddi=0x%08x; eveni=0x%08x; oddq=0x%08x; evenq=0x%08x;\n", + cal->calSamples, i, + cal->totalAdcDcOffsetIOddPhase(i), + cal->totalAdcDcOffsetIEvenPhase(i), + cal->totalAdcDcOffsetQOddPhase(i), + cal->totalAdcDcOffsetQEvenPhase(i)); + } +} + +void +ar5416AdcDcCalibration(struct ath_hal *ah, uint8_t numChains) +{ + struct ar5416PerCal *cal = &AH5416(ah)->ah_cal; + const HAL_PERCAL_DATA *calData = cal->cal_curr->calData; + uint32_t numSamples; + int i; + + numSamples = (1 << (calData->calCountMax + 5)) * calData->calNumSamples; + for (i = 0; i < numChains; i++) { + uint32_t iOddMeasOffset = cal->totalAdcDcOffsetIOddPhase(i); + uint32_t iEvenMeasOffset = cal->totalAdcDcOffsetIEvenPhase(i); + int32_t qOddMeasOffset = cal->totalAdcDcOffsetQOddPhase(i); + int32_t qEvenMeasOffset = cal->totalAdcDcOffsetQEvenPhase(i); + int32_t qDcMismatch, iDcMismatch; + uint32_t val; + + HALDEBUG(ah, HAL_DEBUG_PERCAL, + "Starting ADC DC Offset Cal for Chain %d\n", i); + + HALDEBUG(ah, HAL_DEBUG_PERCAL, " pwr_meas_odd_i = %d\n", + iOddMeasOffset); + HALDEBUG(ah, HAL_DEBUG_PERCAL, " pwr_meas_even_i = %d\n", + iEvenMeasOffset); + HALDEBUG(ah, HAL_DEBUG_PERCAL, " pwr_meas_odd_q = %d\n", + qOddMeasOffset); + HALDEBUG(ah, HAL_DEBUG_PERCAL, " pwr_meas_even_q = %d\n", + qEvenMeasOffset); + + HALASSERT(numSamples); + + iDcMismatch = (((iEvenMeasOffset - iOddMeasOffset) * 2) / + numSamples) & 0x1ff; + qDcMismatch = (((qOddMeasOffset - qEvenMeasOffset) * 2) / + numSamples) & 0x1ff; + HALDEBUG(ah, HAL_DEBUG_PERCAL, + " dc_offset_mismatch_i = 0x%08x\n", iDcMismatch); + HALDEBUG(ah, HAL_DEBUG_PERCAL, + " dc_offset_mismatch_q = 0x%08x\n", qDcMismatch); + + val = OS_REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i)); + val &= 0xc0000fff; + val |= (qDcMismatch << 12) | (iDcMismatch << 21); + OS_REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val); + + HALDEBUG(ah, HAL_DEBUG_PERCAL, + "ADC DC Offset Cal done for Chain %d\n", i); + } + OS_REG_SET_BIT(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0), + AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE); +} --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5210/ar5416_cal_adcgain.c 2009-03-23 17:36:56.000000000 +0000 @@ -0,0 +1,116 @@ +/* + * 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: ar5416_cal_adcgain.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 "ar5416/ar5416.h" +#include "ar5416/ar5416reg.h" +#include "ar5416/ar5416phy.h" + +/* Adc Gain Cal aliases */ +#define totalAdcIOddPhase(i) caldata[0][i].u +#define totalAdcIEvenPhase(i) caldata[1][i].u +#define totalAdcQOddPhase(i) caldata[2][i].u +#define totalAdcQEvenPhase(i) caldata[3][i].u + +/* + * Collect data from HW to later perform ADC Gain Calibration + */ +void +ar5416AdcGainCalCollect(struct ath_hal *ah) +{ + struct ar5416PerCal *cal = &AH5416(ah)->ah_cal; + int i; + + /* + * Accumulate ADC Gain cal measures for active chains + */ + for (i = 0; i < AR5416_MAX_CHAINS; i++) { + cal->totalAdcIOddPhase(i) += + OS_REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); + cal->totalAdcIEvenPhase(i) += + OS_REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); + cal->totalAdcQOddPhase(i) += + OS_REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); + cal->totalAdcQEvenPhase(i) += + OS_REG_READ(ah, AR_PHY_CAL_MEAS_3(i)); + + HALDEBUG(ah, HAL_DEBUG_PERCAL, + "%d: Chn %d oddi=0x%08x; eveni=0x%08x; oddq=0x%08x; evenq=0x%08x;\n", + cal->calSamples, i, cal->totalAdcIOddPhase(i), + cal->totalAdcIEvenPhase(i), cal->totalAdcQOddPhase(i), + cal->totalAdcQEvenPhase(i)); + } +} + +/* + * Use HW data to do ADC Gain Calibration + */ +void +ar5416AdcGainCalibration(struct ath_hal *ah, uint8_t numChains) +{ + struct ar5416PerCal *cal = &AH5416(ah)->ah_cal; + uint32_t i; + + for (i = 0; i < numChains; i++) { + uint32_t iOddMeasOffset = cal->totalAdcIOddPhase(i); + uint32_t iEvenMeasOffset = cal->totalAdcIEvenPhase(i); + uint32_t qOddMeasOffset = cal->totalAdcQOddPhase(i); + uint32_t qEvenMeasOffset = cal->totalAdcQEvenPhase(i); + + HALDEBUG(ah, HAL_DEBUG_PERCAL, + "Start ADC Gain Cal for Chain %d\n", i); + HALDEBUG(ah, HAL_DEBUG_PERCAL, + " pwr_meas_odd_i = 0x%08x\n", iOddMeasOffset); + HALDEBUG(ah, HAL_DEBUG_PERCAL, + " pwr_meas_even_i = 0x%08x\n", iEvenMeasOffset); + HALDEBUG(ah, HAL_DEBUG_PERCAL, + " pwr_meas_odd_q = 0x%08x\n", qOddMeasOffset); + HALDEBUG(ah, HAL_DEBUG_PERCAL, + " pwr_meas_even_q = 0x%08x\n", qEvenMeasOffset); + + if (iOddMeasOffset != 0 && qEvenMeasOffset != 0) { + uint32_t iGainMismatch = + ((iEvenMeasOffset*32)/iOddMeasOffset) & 0x3f; + uint32_t qGainMismatch = + ((qOddMeasOffset*32)/qEvenMeasOffset) & 0x3f; + uint32_t val; + + HALDEBUG(ah, HAL_DEBUG_PERCAL, + " gain_mismatch_i = 0x%08x\n", + iGainMismatch); + HALDEBUG(ah, HAL_DEBUG_PERCAL, + " gain_mismatch_q = 0x%08x\n", + qGainMismatch); + + val = OS_REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i)); + val &= 0xfffff000; + val |= (qGainMismatch) | (iGainMismatch << 6); + OS_REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val); + + HALDEBUG(ah, HAL_DEBUG_PERCAL, + "ADC Gain Cal done for Chain %d\n", i); + } + } + OS_REG_SET_BIT(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0), + AR_PHY_NEW_ADC_GAIN_CORR_ENABLE); +} --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5210/ar5416_cal_iq.c 2009-03-23 17:36:56.000000000 +0000 @@ -0,0 +1,132 @@ +/* + * 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: ar5416_cal_iq.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 "ar5416/ar5416.h" +#include "ar5416/ar5416reg.h" +#include "ar5416/ar5416phy.h" + +/* IQ Cal aliases */ +#define totalPowerMeasI(i) caldata[0][i].u +#define totalPowerMeasQ(i) caldata[1][i].u +#define totalIqCorrMeas(i) caldata[2][i].s + +/* + * Collect data from HW to later perform IQ Mismatch Calibration + */ +void +ar5416IQCalCollect(struct ath_hal *ah) +{ + struct ar5416PerCal *cal = &AH5416(ah)->ah_cal; + int i; + + /* + * Accumulate IQ cal measures for active chains + */ + for (i = 0; i < AR5416_MAX_CHAINS; i++) { + cal->totalPowerMeasI(i) += + OS_REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); + cal->totalPowerMeasQ(i) += + OS_REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); + cal->totalIqCorrMeas(i) += (int32_t) + OS_REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); + HALDEBUG(ah, HAL_DEBUG_PERCAL, + "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n", + cal->calSamples, i, cal->totalPowerMeasI(i), + cal->totalPowerMeasQ(i), cal->totalIqCorrMeas(i)); + } +} + +/* + * Use HW data to do IQ Mismatch Calibration + */ +void +ar5416IQCalibration(struct ath_hal *ah, uint8_t numChains) +{ + struct ar5416PerCal *cal = &AH5416(ah)->ah_cal; + int i; + + for (i = 0; i < numChains; i++) { + uint32_t powerMeasI = cal->totalPowerMeasI(i); + uint32_t powerMeasQ = cal->totalPowerMeasQ(i); + uint32_t iqCorrMeas = cal->totalIqCorrMeas(i); + uint32_t qCoffDenom, iCoffDenom; + int iqCorrNeg; + + HALDEBUG(ah, HAL_DEBUG_PERCAL, + "Start IQ Cal and Correction for Chain %d\n", i); + HALDEBUG(ah, HAL_DEBUG_PERCAL, + "Orignal: iq_corr_meas = 0x%08x\n", iqCorrMeas); + + iqCorrNeg = 0; + /* iqCorrMeas is always negative. */ + if (iqCorrMeas > 0x80000000) { + iqCorrMeas = (0xffffffff - iqCorrMeas) + 1; + iqCorrNeg = 1; + } + + HALDEBUG(ah, HAL_DEBUG_PERCAL, " pwr_meas_i = 0x%08x\n", + powerMeasI); + HALDEBUG(ah, HAL_DEBUG_PERCAL, " pwr_meas_q = 0x%08x\n", + powerMeasQ); + HALDEBUG(ah, HAL_DEBUG_PERCAL, " iqCorrNeg is 0x%08x\n", + iqCorrNeg); + + iCoffDenom = (powerMeasI/2 + powerMeasQ/2)/ 128; + qCoffDenom = powerMeasQ / 64; + /* Protect against divide-by-0 */ + if (powerMeasQ != 0) { + /* IQ corr_meas is already negated if iqcorr_neg == 1 */ + int32_t iCoff = iqCorrMeas/iCoffDenom; + int32_t qCoff = powerMeasI/qCoffDenom - 64; + + HALDEBUG(ah, HAL_DEBUG_PERCAL, " iCoff = 0x%08x\n", + iCoff); + HALDEBUG(ah, HAL_DEBUG_PERCAL, " qCoff = 0x%08x\n", + qCoff); + + /* Negate iCoff if iqCorrNeg == 0 */ + iCoff = iCoff & 0x3f; + HALDEBUG(ah, HAL_DEBUG_PERCAL, + "New: iCoff = 0x%08x\n", iCoff); + + if (iqCorrNeg == 0x0) + iCoff = 0x40 - iCoff; + if (qCoff > 15) + qCoff = 15; + else if (qCoff <= -16) + qCoff = 16; + HALDEBUG(ah, HAL_DEBUG_PERCAL, + " : iCoff = 0x%x qCoff = 0x%x\n", iCoff, qCoff); + + OS_REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4_CHAIN(i), + AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF, iCoff); + OS_REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4_CHAIN(i), + AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF, qCoff); + HALDEBUG(ah, HAL_DEBUG_PERCAL, + "IQ Cal and Correction done for Chain %d\n", i); + } + } + OS_REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4, + AR_PHY_TIMING_CTRL4_IQCORR_ENABLE); +} --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5210/ar5416_eeprom.c 2009-03-23 17:36:56.000000000 +0000 @@ -0,0 +1,44 @@ +/* + * 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: ar5416_eeprom.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 "ah_eeprom_v14.h" + +#include "ar5416/ar5416.h" +#include "ar5416/ar5416reg.h" +#include "ar5416/ar5416phy.h" + +/* + * Read 16 bits of data from offset into *data + */ +HAL_BOOL +ar5416EepromRead(struct ath_hal *ah, u_int off, uint16_t *data) +{ + OS_REG_READ(ah, AR5416_EEPROM_OFFSET + (off << AR5416_EEPROM_S)); + if (!ath_hal_wait(ah, AR_EEPROM_STATUS_DATA, + AR_EEPROM_STATUS_DATA_BUSY | AR_EEPROM_STATUS_DATA_PROT_ACCESS, 0)) + return AH_FALSE; + *data = MS(OS_REG_READ(ah, AR_EEPROM_STATUS_DATA), + AR_EEPROM_STATUS_DATA_VAL); + return AH_TRUE; +} --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5210/ar5416_gpio.c 2009-03-23 17:36:56.000000000 +0000 @@ -0,0 +1,112 @@ +/* + * 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: ar5416_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 "ar5416/ar5416.h" +#include "ar5416/ar5416reg.h" +#include "ar5416/ar5416phy.h" + +#define AR_NUM_GPIO 6 /* 6 GPIO pins */ +#define AR_GPIO_BIT(_gpio) (1 << _gpio) + +/* + * Configure GPIO Output lines + */ +HAL_BOOL +ar5416GpioCfgOutput(struct ath_hal *ah, uint32_t gpio) +{ + HALASSERT(gpio < AR_NUM_GPIO); + OS_REG_CLR_BIT(ah, AR_GPIO_INTR_OUT, AR_GPIO_BIT(gpio)); + return AH_TRUE; +} + +/* + * Configure GPIO Input lines + */ +HAL_BOOL +ar5416GpioCfgInput(struct ath_hal *ah, uint32_t gpio) +{ + HALASSERT(gpio < AR_NUM_GPIO); + OS_REG_SET_BIT(ah, AR_GPIO_INTR_OUT, AR_GPIO_BIT(gpio)); + return AH_TRUE; +} + +/* + * Once configured for I/O - set output lines + */ +HAL_BOOL +ar5416GpioSet(struct ath_hal *ah, uint32_t gpio, uint32_t val) +{ + uint32_t reg; + + HALASSERT(gpio < AR_NUM_GPIO); + reg = MS(OS_REG_READ(ah, AR_GPIO_INTR_OUT), AR_GPIO_OUT_VAL); + if (val & 1) + reg |= AR_GPIO_BIT(gpio); + else + reg &= ~AR_GPIO_BIT(gpio); + + OS_REG_RMW_FIELD(ah, AR_GPIO_INTR_OUT, AR_GPIO_OUT_VAL, reg); + return AH_TRUE; +} + +/* + * Once configured for I/O - get input lines + */ +uint32_t +ar5416GpioGet(struct ath_hal *ah, uint32_t gpio) +{ + if (gpio >= AR_NUM_GPIO) + return 0xffffffff; + return ((OS_REG_READ(ah, AR_GPIO_IN) & AR_GPIO_BIT(gpio)) >> gpio); +} + +/* + * Set the GPIO Interrupt + */ +void +ar5416GpioSetIntr(struct ath_hal *ah, u_int gpio, uint32_t ilevel) +{ + uint32_t val; + + HALASSERT(gpio < AR_NUM_GPIO); + /* XXX bounds check gpio */ + val = MS(OS_REG_READ(ah, AR_GPIO_INTR_OUT), AR_GPIO_INTR_CTRL); + if (ilevel) /* 0 == interrupt on pin high */ + val &= ~AR_GPIO_BIT(gpio); + else /* 1 == interrupt on pin low */ + val |= AR_GPIO_BIT(gpio); + OS_REG_RMW_FIELD(ah, AR_GPIO_INTR_OUT, AR_GPIO_INTR_CTRL, val); + + /* Change the interrupt mask. */ + val = MS(OS_REG_READ(ah, AR_INTR_ASYNC_ENABLE), AR_INTR_GPIO); + val |= AR_GPIO_BIT(gpio); + OS_REG_RMW_FIELD(ah, AR_INTR_ASYNC_ENABLE, AR_INTR_GPIO, val); + + val = MS(OS_REG_READ(ah, AR_INTR_ASYNC_MASK), AR_INTR_GPIO); + val |= AR_GPIO_BIT(gpio); + OS_REG_RMW_FIELD(ah, AR_INTR_ASYNC_MASK, AR_INTR_GPIO, val); +} --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5210/ar5416_interrupts.c 2009-03-23 17:36:56.000000000 +0000 @@ -0,0 +1,259 @@ +/* + * 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: ar5416_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 "ar5416/ar5416.h" +#include "ar5416/ar5416reg.h" + +/* + * Checks to see if an interrupt is pending on our NIC + * + * Returns: TRUE if an interrupt is pending + * FALSE if not + */ +HAL_BOOL +ar5416IsInterruptPending(struct ath_hal *ah) +{ + uint32_t isr; + /* + * Some platforms trigger our ISR before applying power to + * the card, so make sure the INTPEND is really 1, not 0xffffffff. + */ + isr = OS_REG_READ(ah, AR_INTR_ASYNC_CAUSE); + if (isr != AR_INTR_SPURIOUS && (isr & AR_INTR_MAC_IRQ) != 0) + return AH_TRUE; + + isr = OS_REG_READ(ah, AR_INTR_SYNC_CAUSE); + if (isr != AR_INTR_SPURIOUS && (isr & AR_INTR_SYNC_DEFAULT)) + return AH_TRUE; + + return AH_FALSE; +} + +/* + * 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 +ar5416GetPendingInterrupts(struct ath_hal *ah, HAL_INT *masked) +{ + uint32_t isr, isr0, isr1, sync_cause; + + /* + * Verify there's a mac interrupt and the RTC is on. + */ + if ((OS_REG_READ(ah, AR_INTR_ASYNC_CAUSE) & AR_INTR_MAC_IRQ) && + (OS_REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M) == AR_RTC_STATUS_ON) + isr = OS_REG_READ(ah, AR_ISR); + else + isr = 0; + sync_cause = OS_REG_READ(ah, AR_INTR_SYNC_CAUSE); + sync_cause &= AR_INTR_SYNC_DEFAULT; + if (isr == 0 && sync_cause == 0) { + *masked = 0; + return AH_FALSE; + } + + if (isr != 0) { + struct ath_hal_5212 *ahp = AH5212(ah); + uint32_t mask2; + + mask2 = 0; + if (isr & AR_ISR_BCNMISC) { + uint32_t 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; + if (isr2 & AR_ISR_S2_GTT) + mask2 |= HAL_INT_GTT; + if (isr2 & AR_ISR_S2_CST) + mask2 |= HAL_INT_CST; + if (isr2 & AR_ISR_S2_TSFOOR) + mask2 |= HAL_INT_TSFOOR; + } + + 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_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); + } + + /* Interrupt Mitigation on AR5416 */ +#ifdef AR5416_INT_MITIGATION + if (isr & (AR_ISR_RXMINTR | AR_ISR_RXINTM)) + *masked |= HAL_INT_RX; + if (isr & (AR_ISR_TXMINTR | AR_ISR_TXINTM)) + *masked |= HAL_INT_TX; +#endif + *masked |= mask2; + } + if (sync_cause != 0) { + if (sync_cause & (AR_INTR_SYNC_HOST1_FATAL | AR_INTR_SYNC_HOST1_PERR)) { + *masked |= HAL_INT_FATAL; + } + if (sync_cause & AR_INTR_SYNC_RADM_CPL_TIMEOUT) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: RADM CPL timeout\n", + __func__); + OS_REG_WRITE(ah, AR_RC, AR_RC_HOSTIF); + OS_REG_WRITE(ah, AR_RC, 0); + *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] = sync_cause; + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: fatal error, ISR_RAC 0x%x SYNC_CAUSE 0x%x\n", + __func__, isr, sync_cause); + } + + OS_REG_WRITE(ah, AR_INTR_SYNC_CAUSE_CLR, sync_cause); + /* NB: flush write */ + (void) OS_REG_READ(ah, AR_INTR_SYNC_CAUSE_CLR); + } + return AH_TRUE; +} + +/* + * Atomically enables NIC interrupts. Interrupts are passed in + * via the enumerated bitmask in ints. + */ +HAL_INT +ar5416SetInterrupts(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); + + OS_REG_WRITE(ah, AR_INTR_ASYNC_ENABLE, 0); + (void) OS_REG_READ(ah, AR_INTR_ASYNC_ENABLE); + + OS_REG_WRITE(ah, AR_INTR_SYNC_ENABLE, 0); + (void) OS_REG_READ(ah, AR_INTR_SYNC_ENABLE); + } + + 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; +#ifdef AR5416_INT_MITIGATION + /* + * Overwrite default mask if Interrupt mitigation + * is specified for AR5416 + */ + mask = ints & HAL_INT_COMMON; + if (ints & HAL_INT_TX) + mask |= AR_IMR_TXMINTR | AR_IMR_TXINTM; + if (ints & HAL_INT_RX) + mask |= AR_IMR_RXERR | AR_IMR_RXMINTR | AR_IMR_RXINTM; +#endif + 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_GTT) + mask2 |= AR_IMR_S2_GTT; + if (ints & HAL_INT_CST) + mask2 |= AR_IMR_S2_CST; + if (ints & HAL_INT_TSFOOR) + mask2 |= AR_IMR_S2_TSFOOR; + } + + /* 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); + mask = 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 | + AR_IMR_S2_GTT | + AR_IMR_S2_CST); + OS_REG_WRITE(ah, AR_IMR_S2, mask | 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); + + OS_REG_WRITE(ah, AR_INTR_ASYNC_ENABLE, AR_INTR_MAC_IRQ); + OS_REG_WRITE(ah, AR_INTR_ASYNC_MASK, AR_INTR_MAC_IRQ); + + OS_REG_WRITE(ah, AR_INTR_SYNC_ENABLE, AR_INTR_SYNC_DEFAULT); + OS_REG_WRITE(ah, AR_INTR_SYNC_MASK, AR_INTR_SYNC_DEFAULT); + } + + return omask; +} --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5210/ar5416_keycache.c 2009-03-23 17:36:56.000000000 +0000 @@ -0,0 +1,66 @@ +/* + * 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: ar5416_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 "ar5416/ar5416.h" + +static const int keyType[] = { + 1, /* HAL_CIPHER_WEP */ + 0, /* HAL_CIPHER_AES_OCB */ + 2, /* HAL_CIPHER_AES_CCM */ + 0, /* HAL_CIPHER_CKIP */ + 3, /* HAL_CIPHER_TKIP */ + 0, /* HAL_CIPHER_CLR */ +}; + +/* + * Clear the specified key cache entry and any associated MIC entry. + */ +HAL_BOOL +ar5416ResetKeyCacheEntry(struct ath_hal *ah, uint16_t entry) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + + if (ar5212ResetKeyCacheEntry(ah, entry)) { + ahp->ah_keytype[entry] = keyType[HAL_CIPHER_CLR]; + return AH_TRUE; + } else + return AH_FALSE; +} + +/* + * Sets the contents of the specified key cache entry + * and any associated MIC entry. + */ +HAL_BOOL +ar5416SetKeyCacheEntry(struct ath_hal *ah, uint16_t entry, + const HAL_KEYVAL *k, const uint8_t *mac, + int xorKey) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + + if (ar5212SetKeyCacheEntry(ah, entry, k, mac, xorKey)) { + ahp->ah_keytype[entry] = keyType[k->kv_type]; + return AH_TRUE; + } else + return AH_FALSE; +} --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5210/ar5416_misc.c 2009-03-23 17:36:56.000000000 +0000 @@ -0,0 +1,499 @@ +/* + * 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: ar5416_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 "ar5416/ar5416.h" +#include "ar5416/ar5416reg.h" +#include "ar5416/ar5416phy.h" + +/* + * 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 +ar5416GetWirelessModes(struct ath_hal *ah) +{ + u_int mode; + + mode = ar5212GetWirelessModes(ah); + if (mode & HAL_MODE_11A) + mode |= HAL_MODE_11NA_HT20 + | HAL_MODE_11NA_HT40PLUS + | HAL_MODE_11NA_HT40MINUS + ; + if (mode & HAL_MODE_11G) + mode |= HAL_MODE_11NG_HT20 + | HAL_MODE_11NG_HT40PLUS + | HAL_MODE_11NG_HT40MINUS + ; + return mode; +} + +/* + * Change the LED blinking pattern to correspond to the connectivity + */ +void +ar5416SetLedState(struct ath_hal *ah, HAL_LED_STATE state) +{ + static const uint32_t ledbits[8] = { + AR_MAC_LED_ASSOC_NONE, /* HAL_LED_INIT */ + AR_MAC_LED_ASSOC_PEND, /* HAL_LED_SCAN */ + AR_MAC_LED_ASSOC_PEND, /* HAL_LED_AUTH */ + AR_MAC_LED_ASSOC_ACTIVE, /* HAL_LED_ASSOC*/ + AR_MAC_LED_ASSOC_ACTIVE, /* HAL_LED_RUN */ + AR_MAC_LED_ASSOC_NONE, + AR_MAC_LED_ASSOC_NONE, + AR_MAC_LED_ASSOC_NONE, + }; + uint32_t bits; + + bits = OS_REG_READ(ah, AR_MAC_LED); + bits = (bits &~ AR_MAC_LED_MODE) + | SM(AR_MAC_LED_MODE_POWON, AR_MAC_LED_MODE) +#if 1 + | SM(AR_MAC_LED_MODE_NETON, AR_MAC_LED_MODE) +#endif + ; + bits = (bits &~ AR_MAC_LED_ASSOC) + | SM(ledbits[state & 0x7], AR_MAC_LED_ASSOC); + OS_REG_WRITE(ah, AR_MAC_LED, bits); +} + +/* + * Reset the current hardware tsf for stamlme. + */ +void +ar5416ResetTsf(struct ath_hal *ah) +{ + uint32_t v; + int i; + + for (i = 0; i < 10; i++) { + v = OS_REG_READ(ah, AR_SLP32_MODE); + if ((v & AR_SLP32_TSF_WRITE_STATUS) == 0) + break; + OS_DELAY(10); + } + OS_REG_WRITE(ah, AR_RESET_TSF, AR_RESET_TSF_ONCE); +} + +HAL_BOOL +ar5416SetAntennaSwitch(struct ath_hal *ah, HAL_ANT_SETTING settings) +{ + return AH_TRUE; +} + +/* Setup decompression for given key index */ +HAL_BOOL +ar5416SetDecompMask(struct ath_hal *ah, uint16_t keyidx, int en) +{ + return HAL_OK; +} + +/* Setup coverage class */ +void +ar5416SetCoverageClass(struct ath_hal *ah, uint8_t coverageclass, int now) +{ +} + +/* + * Return approximation of extension channel busy over an time interval + * 0% (clear) -> 100% (busy) + * + */ +uint32_t +ar5416Get11nExtBusy(struct ath_hal *ah) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + uint32_t busy; /* percentage */ + uint32_t cycleCount, ctlBusy, extBusy; + + ctlBusy = OS_REG_READ(ah, AR_RCCNT); + extBusy = OS_REG_READ(ah, AR_EXTRCCNT); + cycleCount = OS_REG_READ(ah, AR_CCCNT); + + if (ahp->ah_cycleCount == 0 || ahp->ah_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. + */ + busy = 0; + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: cycle counter wrap. ExtBusy = 0\n", + __func__); + + } else { + uint32_t cycleDelta = cycleCount - ahp->ah_cycleCount; + uint32_t ctlBusyDelta = ctlBusy - ahp->ah_ctlBusy; + uint32_t extBusyDelta = extBusy - ahp->ah_extBusy; + uint32_t ctlClearDelta = 0; + + /* Compute control channel rxclear. + * The cycle delta may be less than the control channel delta. + * This could be solved by freezing the timers (or an atomic read, + * if one was available). Checking for the condition should be + * sufficient. + */ + if (cycleDelta > ctlBusyDelta) { + ctlClearDelta = cycleDelta - ctlBusyDelta; + } + + /* Compute ratio of extension channel busy to control channel clear + * as an approximation to extension channel cleanliness. + * + * According to the hardware folks, ext rxclear is undefined + * if the ctrl rxclear is de-asserted (i.e. busy) + */ + if (ctlClearDelta) { + busy = (extBusyDelta * 100) / ctlClearDelta; + } else { + busy = 100; + } + if (busy > 100) { + busy = 100; + } +#if 0 + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: cycleDelta 0x%x, ctlBusyDelta 0x%x, " + "extBusyDelta 0x%x, ctlClearDelta 0x%x, " + "busy %d\n", + __func__, cycleDelta, ctlBusyDelta, extBusyDelta, ctlClearDelta, busy); +#endif + } + + ahp->ah_cycleCount = cycleCount; + ahp->ah_ctlBusy = ctlBusy; + ahp->ah_extBusy = extBusy; + + return busy; +} + +/* + * Configure 20/40 operation + * + * 20/40 = joint rx clear (control and extension) + * 20 = rx clear (control) + * + * - NOTE: must stop MAC (tx) and requeue 40 MHz packets as 20 MHz when changing + * from 20/40 => 20 only + */ +void +ar5416Set11nMac2040(struct ath_hal *ah, HAL_HT_MACMODE mode) +{ + uint32_t macmode; + + /* Configure MAC for 20/40 operation */ + if (mode == HAL_HT_MACMODE_2040) { + macmode = AR_2040_JOINED_RX_CLEAR; + } else { + macmode = 0; + } + OS_REG_WRITE(ah, AR_2040_MODE, macmode); +} + +/* + * Get Rx clear (control/extension channel) + * + * Returns active low (busy) for ctrl/ext channel + * Owl 2.0 + */ +HAL_HT_RXCLEAR +ar5416Get11nRxClear(struct ath_hal *ah) +{ + HAL_HT_RXCLEAR rxclear = 0; + uint32_t val; + + val = OS_REG_READ(ah, AR_DIAG_SW); + + /* control channel */ + if (val & AR_DIAG_RXCLEAR_CTL_LOW) { + rxclear |= HAL_RX_CLEAR_CTL_LOW; + } + /* extension channel */ + if (val & AR_DIAG_RXCLEAR_CTL_LOW) { + rxclear |= HAL_RX_CLEAR_EXT_LOW; + } + return rxclear; +} + +/* + * Set Rx clear (control/extension channel) + * + * Useful for forcing the channel to appear busy for + * debugging/diagnostics + * Owl 2.0 + */ +void +ar5416Set11nRxClear(struct ath_hal *ah, HAL_HT_RXCLEAR rxclear) +{ + /* control channel */ + if (rxclear & HAL_RX_CLEAR_CTL_LOW) { + OS_REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RXCLEAR_CTL_LOW); + } else { + OS_REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_RXCLEAR_CTL_LOW); + } + /* extension channel */ + if (rxclear & HAL_RX_CLEAR_EXT_LOW) { + OS_REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RXCLEAR_EXT_LOW); + } else { + OS_REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_RXCLEAR_EXT_LOW); + } +} + +HAL_STATUS +ar5416GetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, + uint32_t capability, uint32_t *result) +{ + switch (type) { + case HAL_CAP_BB_HANG: + switch (capability) { + case HAL_BB_HANG_RIFS: + return AR_SREV_SOWL(ah) ? HAL_OK : HAL_ENOTSUPP; + case HAL_BB_HANG_DFS: + return AR_SREV_SOWL(ah) ? HAL_OK : HAL_ENOTSUPP; + case HAL_BB_HANG_RX_CLEAR: + return AR_SREV_MERLIN(ah) ? HAL_OK : HAL_ENOTSUPP; + } + break; + case HAL_CAP_MAC_HANG: + return ((ah->ah_macVersion == AR_XSREV_VERSION_OWL_PCI) || + (ah->ah_macVersion == AR_XSREV_VERSION_OWL_PCIE) || + AR_SREV_SOWL(ah)) ? + HAL_OK : HAL_ENOTSUPP; + default: + break; + } + return ar5212GetCapability(ah, type, capability, result); +} + +static int ar5416DetectMacHang(struct ath_hal *ah); +static int ar5416DetectBBHang(struct ath_hal *ah); + +HAL_BOOL +ar5416GetDiagState(struct ath_hal *ah, int request, + const void *args, uint32_t argsize, + void **result, uint32_t *resultsize) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + int hangs; + + 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_CHECK_HANGS: + if (argsize != sizeof(int)) + return AH_FALSE; + hangs = *(const int *) args; + ahp->ah_hangs = 0; + if (hangs & HAL_BB_HANGS) + ahp->ah_hangs |= ar5416DetectBBHang(ah); + /* NB: if BB is hung MAC will be hung too so skip check */ + if (ahp->ah_hangs == 0 && (hangs & HAL_MAC_HANGS)) + ahp->ah_hangs |= ar5416DetectMacHang(ah); + *result = &ahp->ah_hangs; + *resultsize = sizeof(ahp->ah_hangs); + return AH_TRUE; + } + return ar5212GetDiagState(ah, request, + args, argsize, result, resultsize); +} + +typedef struct { + uint32_t dma_dbg_3; + uint32_t dma_dbg_4; + uint32_t dma_dbg_5; + uint32_t dma_dbg_6; +} mac_dbg_regs_t; + +typedef enum { + dcu_chain_state = 0x1, + dcu_complete_state = 0x2, + qcu_state = 0x4, + qcu_fsp_ok = 0x8, + qcu_fsp_state = 0x10, + qcu_stitch_state = 0x20, + qcu_fetch_state = 0x40, + qcu_complete_state = 0x80 +} hal_mac_hangs_t; + +typedef struct { + int states; + uint8_t dcu_chain_state; + uint8_t dcu_complete_state; + uint8_t qcu_state; + uint8_t qcu_fsp_ok; + uint8_t qcu_fsp_state; + uint8_t qcu_stitch_state; + uint8_t qcu_fetch_state; + uint8_t qcu_complete_state; +} hal_mac_hang_check_t; + +static HAL_BOOL +ar5416CompareDbgHang(struct ath_hal *ah, const mac_dbg_regs_t *regs, + const hal_mac_hang_check_t *check) +{ + int found_states; + + found_states = 0; + if (check->states & dcu_chain_state) { + int i; + + for (i = 0; i < 6; i++) { + if (((regs->dma_dbg_4 >> (5*i)) & 0x1f) == + check->dcu_chain_state) + found_states |= dcu_chain_state; + } + for (i = 0; i < 4; i++) { + if (((regs->dma_dbg_5 >> (5*i)) & 0x1f) == + check->dcu_chain_state) + found_states |= dcu_chain_state; + } + } + if (check->states & dcu_complete_state) { + if ((regs->dma_dbg_6 & 0x3) == check->dcu_complete_state) + found_states |= dcu_complete_state; + } + if (check->states & qcu_stitch_state) { + if (((regs->dma_dbg_3 >> 18) & 0xf) == check->qcu_stitch_state) + found_states |= qcu_stitch_state; + } + if (check->states & qcu_fetch_state) { + if (((regs->dma_dbg_3 >> 22) & 0xf) == check->qcu_fetch_state) + found_states |= qcu_fetch_state; + } + if (check->states & qcu_complete_state) { + if (((regs->dma_dbg_3 >> 26) & 0x7) == check->qcu_complete_state) + found_states |= qcu_complete_state; + } + return (found_states == check->states); +} + +#define NUM_STATUS_READS 50 + +static int +ar5416DetectMacHang(struct ath_hal *ah) +{ + static const hal_mac_hang_check_t hang_sig1 = { + .dcu_chain_state = 0x6, + .dcu_complete_state = 0x1, + .states = dcu_chain_state + | dcu_complete_state, + }; + static const hal_mac_hang_check_t hang_sig2 = { + .qcu_stitch_state = 0x9, + .qcu_fetch_state = 0x8, + .qcu_complete_state = 0x4, + .states = qcu_stitch_state + | qcu_fetch_state + | qcu_complete_state, + }; + mac_dbg_regs_t mac_dbg; + int i; + + mac_dbg.dma_dbg_3 = OS_REG_READ(ah, AR_DMADBG_3); + mac_dbg.dma_dbg_4 = OS_REG_READ(ah, AR_DMADBG_4); + mac_dbg.dma_dbg_5 = OS_REG_READ(ah, AR_DMADBG_5); + mac_dbg.dma_dbg_6 = OS_REG_READ(ah, AR_DMADBG_6); + for (i = 1; i <= NUM_STATUS_READS; i++) { + if (mac_dbg.dma_dbg_3 != OS_REG_READ(ah, AR_DMADBG_3) || + mac_dbg.dma_dbg_4 != OS_REG_READ(ah, AR_DMADBG_4) || + mac_dbg.dma_dbg_5 != OS_REG_READ(ah, AR_DMADBG_5) || + mac_dbg.dma_dbg_6 != OS_REG_READ(ah, AR_DMADBG_6)) + return 0; + } + + if (ar5416CompareDbgHang(ah, &mac_dbg, &hang_sig1)) + return HAL_MAC_HANG_SIG1; + if (ar5416CompareDbgHang(ah, &mac_dbg, &hang_sig2)) + return HAL_MAC_HANG_SIG2; + + HALDEBUG(ah, HAL_DEBUG_ANY, "%s Found an unknown MAC hang signature " + "DMADBG_3=0x%x DMADBG_4=0x%x DMADBG_5=0x%x DMADBG_6=0x%x\n", + __func__, mac_dbg.dma_dbg_3, mac_dbg.dma_dbg_4, mac_dbg.dma_dbg_5, + mac_dbg.dma_dbg_6); + + return HAL_MAC_HANG_UNKNOWN; +} + +/* + * Determine if the baseband using the Observation Bus Register + */ +static int +ar5416DetectBBHang(struct ath_hal *ah) +{ +#define N(a) (sizeof(a)/sizeof(a[0])) + /* + * Check the PCU Observation Bus 1 register (0x806c) + * NUM_STATUS_READS times + * + * 4 known BB hang signatures - + * [1] bits 8,9,11 are 0. State machine state (bits 25-31) is 0x1E + * [2] bits 8,9 are 1, bit 11 is 0. State machine state + * (bits 25-31) is 0x52 + * [3] bits 8,9 are 1, bit 11 is 0. State machine state + * (bits 25-31) is 0x18 + * [4] bit 10 is 1, bit 11 is 0. WEP state (bits 12-17) is 0x2, + * Rx State (bits 20-24) is 0x7. + */ + static const struct { + uint32_t val; + uint32_t mask; + int code; + } hang_list[] = { + /* Reg Value Reg Mask Hang Code XXX */ + { 0x1E000000, 0x7E000B00, HAL_BB_HANG_DFS }, + { 0x52000B00, 0x7E000B00, HAL_BB_HANG_RIFS }, + { 0x18000B00, 0x7E000B00, HAL_BB_HANG_RX_CLEAR }, + { 0x00702400, 0x7E7FFFEF, HAL_BB_HANG_RX_CLEAR } + }; + uint32_t hang_sig; + int i; + + hang_sig = OS_REG_READ(ah, AR_OBSERV_1); + for (i = 1; i <= NUM_STATUS_READS; i++) { + if (hang_sig != OS_REG_READ(ah, AR_OBSERV_1)) + return 0; + } + for (i = 0; i < N(hang_list); i++) + if ((hang_sig & hang_list[i].mask) == hang_list[i].val) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s BB hang, signature 0x%x, code 0x%x\n", + __func__, hang_sig, hang_list[i].code); + return hang_list[i].code; + } + + HALDEBUG(ah, HAL_DEBUG_ANY, "%s Found an unknown BB hang signature! " + "<0x806c>=0x%x\n", __func__, hang_sig); + + return HAL_BB_HANG_UNKNOWN; +#undef N +} +#undef NUM_STATUS_READS --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5210/ar5416_phy.c 2009-03-23 17:36:56.000000000 +0000 @@ -0,0 +1,126 @@ +/* + * 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: ar5416_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 "ar5416/ar5416.h" + +/* shorthands to compact tables for readability */ +#define OFDM IEEE80211_T_OFDM +#define CCK IEEE80211_T_CCK +#define HT IEEE80211_T_HT + +HAL_RATE_TABLE ar5416_11ng_table = { + 28, /* 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 }, +/* 6.5 Mb */ { AH_TRUE, HT, 6500, 0x80, 0x00, 0, 8, 0, 0 }, +/* 13 Mb */ { AH_TRUE, HT, 13000, 0x81, 0x00, 1, 8, 0, 0 }, +/*19.5 Mb */ { AH_TRUE, HT, 19500, 0x82, 0x00, 2, 8, 0, 0 }, +/* 26 Mb */ { AH_TRUE, HT, 26000, 0x83, 0x00, 3, 8, 0, 0 }, +/* 39 Mb */ { AH_TRUE, HT, 39000, 0x84, 0x00, 4, 8, 0, 0 }, +/* 52 Mb */ { AH_TRUE, HT, 52000, 0x85, 0x00, 5, 8, 0, 0 }, +/*58.5 Mb */ { AH_TRUE, HT, 58500, 0x86, 0x00, 6, 8, 0, 0 }, +/* 65 Mb */ { AH_TRUE, HT, 65000, 0x87, 0x00, 7, 8, 0, 0 }, +/* 13 Mb */ { AH_TRUE, HT, 13000, 0x88, 0x00, 8, 8, 0, 0 }, +/* 26 Mb */ { AH_TRUE, HT, 26000, 0x89, 0x00, 9, 8, 0, 0 }, +/* 39 Mb */ { AH_TRUE, HT, 39000, 0x8a, 0x00, 10, 8, 0, 0 }, +/* 52 Mb */ { AH_TRUE, HT, 52000, 0x8b, 0x00, 11, 8, 0, 0 }, +/* 78 Mb */ { AH_TRUE, HT, 78000, 0x8c, 0x00, 12, 8, 0, 0 }, +/* 104 Mb */ { AH_TRUE, HT, 104000, 0x8d, 0x00, 13, 8, 0, 0 }, +/* 117 Mb */ { AH_TRUE, HT, 117000, 0x8e, 0x00, 14, 8, 0, 0 }, +/* 130 Mb */ { AH_TRUE, HT, 130000, 0x8f, 0x00, 15, 8, 0, 0 }, + }, +}; + +static HAL_RATE_TABLE ar5416_11na_table = { + 24, /* 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, 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 }, +/* 6.5 Mb */ { AH_TRUE, HT, 6500, 0x80, 0x00, 0, 8, 0, 0 }, +/* 13 Mb */ { AH_TRUE, HT, 13000, 0x81, 0x00, 1, 8, 0, 0 }, +/*19.5 Mb */ { AH_TRUE, HT, 19500, 0x82, 0x00, 2, 8, 0, 0 }, +/* 26 Mb */ { AH_TRUE, HT, 26000, 0x83, 0x00, 3, 8, 0, 0 }, +/* 39 Mb */ { AH_TRUE, HT, 39000, 0x84, 0x00, 4, 8, 0, 0 }, +/* 52 Mb */ { AH_TRUE, HT, 52000, 0x85, 0x00, 5, 8, 0, 0 }, +/*58.5 Mb */ { AH_TRUE, HT, 58500, 0x86, 0x00, 6, 8, 0, 0 }, +/* 65 Mb */ { AH_TRUE, HT, 65000, 0x87, 0x00, 7, 8, 0, 0 }, +/* 13 Mb */ { AH_TRUE, HT, 13000, 0x88, 0x00, 8, 8, 0, 0 }, +/* 26 Mb */ { AH_TRUE, HT, 26000, 0x89, 0x00, 9, 8, 0, 0 }, +/* 39 Mb */ { AH_TRUE, HT, 39000, 0x8a, 0x00, 10, 8, 0, 0 }, +/* 52 Mb */ { AH_TRUE, HT, 52000, 0x8b, 0x00, 11, 8, 0, 0 }, +/* 78 Mb */ { AH_TRUE, HT, 78000, 0x8c, 0x00, 12, 8, 0, 0 }, +/* 104 Mb */ { AH_TRUE, HT, 104000, 0x8d, 0x00, 13, 8, 0, 0 }, +/* 117 Mb */ { AH_TRUE, HT, 117000, 0x8e, 0x00, 14, 8, 0, 0 }, +/* 130 Mb */ { AH_TRUE, HT, 130000, 0x8f, 0x00, 15, 8, 0, 0 }, + }, +}; + +#undef OFDM +#undef CCK +#undef HT + +const HAL_RATE_TABLE * +ar5416GetRateTable(struct ath_hal *ah, u_int mode) +{ + HAL_RATE_TABLE *rt; + switch (mode) { + case HAL_MODE_11NG_HT20: + case HAL_MODE_11NG_HT40PLUS: + case HAL_MODE_11NG_HT40MINUS: + rt = &ar5416_11ng_table; + break; + case HAL_MODE_11NA_HT20: + case HAL_MODE_11NA_HT40PLUS: + case HAL_MODE_11NA_HT40MINUS: + rt = &ar5416_11na_table; + break; + default: + return ar5212GetRateTable(ah, mode); + } + ath_hal_setupratetable(ah, rt); + return rt; +} --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5210/ar5416_power.c 2009-03-23 17:36:56.000000000 +0000 @@ -0,0 +1,173 @@ +/* + * 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: ar5416_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 "ar5416/ar5416.h" +#include "ar5416/ar5416reg.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 +ar5416SetPowerModeAwake(struct ath_hal *ah, int setChip) +{ +#define POWER_UP_TIME 200000 + uint32_t val; + int i = 0; + + if (setChip) { + /* + * Do a Power-On-Reset if OWL is shutdown + * the NetBSD driver power-cycles the Cardbus slot + * as part of the reset procedure. + */ + if ((OS_REG_READ(ah, AR_RTC_STATUS) + & AR_RTC_PM_STATUS_M) == AR_RTC_STATUS_SHUTDOWN) { + if (!ar5416SetResetReg(ah, HAL_RESET_POWER_ON)) + goto bad; + } + + OS_REG_SET_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN); + OS_DELAY(50); /* Give chip the chance to awake */ + + for (i = POWER_UP_TIME / 50; i != 0; i--) { + val = OS_REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M; + if (val == AR_RTC_STATUS_ON) + break; + OS_DELAY(50); + OS_REG_SET_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN); + } + bad: + if (i == 0) { +#ifdef AH_DEBUG + ath_hal_printf(ah, "%s: Failed to wakeup in %ums\n", + __func__, POWER_UP_TIME/1000); +#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 +ar5416SetPowerModeSleep(struct ath_hal *ah, int setChip) +{ + OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); + if (setChip) { + /* Clear the RTC force wake bit to allow the mac to sleep */ + OS_REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN); + OS_REG_WRITE(ah, AR_RC, AR_RC_AHB|AR_RC_HOSTIF); + /* Shutdown chip. Active low */ + OS_REG_CLR_BIT(ah, AR_RTC_RESET, AR_RTC_RESET_EN); + } +} + +/* + * 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 +ar5416SetPowerModeNetworkSleep(struct ath_hal *ah, int setChip) +{ + OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); + + if (setChip) + OS_REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN); +} + +/* + * Set power mgt to the requested mode, and conditionally set + * the chip as well + */ +HAL_BOOL +ar5416SetPowerMode(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; + if (!setChip) + return 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 = ar5416SetPowerModeAwake(ah, setChip); + break; + case HAL_PM_FULL_SLEEP: + ar5416SetPowerModeSleep(ah, setChip); + break; + case HAL_PM_NETWORK_SLEEP: + ar5416SetPowerModeNetworkSleep(ah, setChip); + break; + default: + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unknown power mode 0x%x\n", + __func__, mode); + return AH_FALSE; + } + ahp->ah_powerMode = mode; + return status; +} + +/* + * Return the current sleep mode of the chip + */ +HAL_POWER_MODE +ar5416GetPowerMode(struct ath_hal *ah) +{ + int mode = OS_REG_READ(ah, AR_RTC_STATUS); + switch (mode & AR_RTC_PM_STATUS_M) { + case AR_RTC_STATUS_ON: + case AR_RTC_STATUS_WAKEUP: + return HAL_PM_AWAKE; + case AR_RTC_STATUS_SLEEP: + return HAL_PM_NETWORK_SLEEP; + case AR_RTC_STATUS_SHUTDOWN: + return HAL_PM_FULL_SLEEP; + default: + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: unknown power mode, RTC_STATUS 0x%x\n", + __func__, mode); + return HAL_PM_UNDEFINED; + } +} --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5210/ar5416_recv.c 2009-03-23 17:36:56.000000000 +0000 @@ -0,0 +1,178 @@ +/* + * 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: ar5416_recv.c,v 1.1 2009/03/23 17:14:48 sborrill Exp $ + */ +#include "opt_ah.h" + +#include "ah.h" +#include "ah_desc.h" +#include "ah_internal.h" + +#include "ar5416/ar5416.h" +#include "ar5416/ar5416reg.h" +#include "ar5416/ar5416desc.h" + +/* + * Start receive at the PCU engine + */ +void +ar5416StartPcuReceive(struct ath_hal *ah) +{ + struct ath_hal_private *ahp = AH_PRIVATE(ah); + + HALDEBUG(ah, HAL_DEBUG_RX, "%s: Start PCU Receive \n", __func__); + ar5212EnableMibCounters(ah); + /* NB: restore current settings */ + ar5416AniReset(ah, ahp->ah_curchan, ahp->ah_opmode, AH_TRUE); + /* + * NB: must do after enabling phy errors to avoid rx + * frames w/ corrupted descriptor status. + */ + OS_REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT); +} + +/* + * Stop receive at the PCU engine + * and abort current frame in PCU + */ +void +ar5416StopPcuReceive(struct ath_hal *ah) +{ + OS_REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT); + + HALDEBUG(ah, HAL_DEBUG_RX, "%s: Stop PCU Receive \n", __func__); + ar5212DisableMibCounters(ah); +} + +/* + * Initialize RX descriptor, by clearing the status and setting + * the size (and any other flags). + */ +HAL_BOOL +ar5416SetupRxDesc(struct ath_hal *ah, struct ath_desc *ds, + uint32_t size, u_int flags) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + + HALASSERT((size &~ AR_BufLen) == 0); + + ads->ds_ctl1 = size & AR_BufLen; + if (flags & HAL_RXDESC_INTREQ) + ads->ds_ctl1 |= AR_RxIntrReq; + + /* this should be enough */ + ads->ds_rxstatus8 &= ~AR_RxDone; + + 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 +ar5416ProcRxDesc(struct ath_hal *ah, struct ath_desc *ds, + uint32_t pa, struct ath_desc *nds, uint64_t tsf, + struct ath_rx_status *rs) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + struct ar5416_desc *ands = AR5416DESC(nds); + + if ((ads->ds_rxstatus8 & AR_RxDone) == 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_rxstatus8 & AR_RxDone) == 0 + && OS_REG_READ(ah, AR_RXDP) == pa) + return HAL_EINPROGRESS; + + rs->rs_status = 0; + rs->rs_flags = 0; + + rs->rs_datalen = ads->ds_rxstatus1 & AR_DataLen; + rs->rs_tstamp = ads->AR_RcvTimestamp; + + /* XXX what about KeyCacheMiss? */ + + rs->rs_rssi = MS(ads->ds_rxstatus4, AR_RxRSSICombined); + rs->rs_rssi_ctl[0] = MS(ads->ds_rxstatus0, AR_RxRSSIAnt00); + rs->rs_rssi_ctl[1] = MS(ads->ds_rxstatus0, AR_RxRSSIAnt01); + rs->rs_rssi_ctl[2] = MS(ads->ds_rxstatus0, AR_RxRSSIAnt02); + rs->rs_rssi_ext[0] = MS(ads->ds_rxstatus4, AR_RxRSSIAnt10); + rs->rs_rssi_ext[1] = MS(ads->ds_rxstatus4, AR_RxRSSIAnt11); + rs->rs_rssi_ext[2] = MS(ads->ds_rxstatus4, AR_RxRSSIAnt12); + + if (ads->ds_rxstatus8 & AR_RxKeyIdxValid) + rs->rs_keyix = MS(ads->ds_rxstatus8, AR_KeyIdx); + else + rs->rs_keyix = HAL_RXKEYIX_INVALID; + + /* NB: caller expected to do rate table mapping */ + rs->rs_rate = RXSTATUS_RATE(ah, ads); + rs->rs_more = (ads->ds_rxstatus1 & AR_RxMore) ? 1 : 0; + + rs->rs_isaggr = (ads->ds_rxstatus8 & AR_RxAggr) ? 1 : 0; + rs->rs_moreaggr = (ads->ds_rxstatus8 & AR_RxMoreAggr) ? 1 : 0; + rs->rs_antenna = MS(ads->ds_rxstatus3, AR_RxAntenna); + + if (ads->ds_rxstatus3 & AR_GI) + rs->rs_flags |= HAL_RX_GI; + if (ads->ds_rxstatus3 & AR_2040) + rs->rs_flags |= HAL_RX_2040; + + if (ads->ds_rxstatus8 & AR_PreDelimCRCErr) + rs->rs_flags |= HAL_RX_DELIM_CRC_PRE; + if (ads->ds_rxstatus8 & AR_PostDelimCRCErr) + rs->rs_flags |= HAL_RX_DELIM_CRC_POST; + if (ads->ds_rxstatus8 & AR_DecryptBusyErr) + rs->rs_flags |= HAL_RX_DECRYPT_BUSY; + if (ads->ds_rxstatus8 & AR_HiRxChain) + rs->rs_flags |= HAL_RX_HI_RX_CHAIN; + + if ((ads->ds_rxstatus8 & AR_RxFrameOK) == 0) { + /* + * These four bits should not be set together. The + * 5416 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_rxstatus8 & AR_CRCErr) + rs->rs_status |= HAL_RXERR_CRC; + else if (ads->ds_rxstatus8 & AR_PHYErr) { + u_int phyerr; + + rs->rs_status |= HAL_RXERR_PHY; + phyerr = MS(ads->ds_rxstatus8, AR_PHYErrCode); + rs->rs_phyerr = phyerr; + } else if (ads->ds_rxstatus8 & AR_DecryptCRCErr) + rs->rs_status |= HAL_RXERR_DECRYPT; + else if (ads->ds_rxstatus8 & 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/ar5210/ar5416_reset.c 2009-03-23 17:36:56.000000000 +0000 @@ -0,0 +1,2895 @@ +/* + * 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: ar5416_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 "ah_eeprom_v14.h" + +#include "ar5416/ar5416.h" +#include "ar5416/ar5416reg.h" +#include "ar5416/ar5416phy.h" +#ifdef AH_SUPPORT_AR9280 +#include "ar5416/ar9280.h" +#endif + +/* Eeprom versioning macros. Returns true if the version is equal or newer than the ver specified */ +#define EEP_MINOR(_ah) \ + (AH_PRIVATE(_ah)->ah_eeversion & AR5416_EEP_VER_MINOR_MASK) +#define IS_EEP_MINOR_V2(_ah) (EEP_MINOR(_ah) >= AR5416_EEP_MINOR_VER_2) +#define IS_EEP_MINOR_V3(_ah) (EEP_MINOR(_ah) >= AR5416_EEP_MINOR_VER_3) + +/* Additional Time delay to wait after activiting the Base band */ +#define BASE_ACTIVATE_DELAY 100 /* 100 usec */ +#define PLL_SETTLE_DELAY 300 /* 300 usec */ +#define RTC_PLL_SETTLE_DELAY 1000 /* 1 ms */ + +static void ar5416InitDMA(struct ath_hal *ah); +static void ar5416InitBB(struct ath_hal *ah, HAL_CHANNEL *chan); +static void ar5416InitIMR(struct ath_hal *ah, HAL_OPMODE opmode); +static void ar5416InitQoS(struct ath_hal *ah); +static void ar5416InitUserSettings(struct ath_hal *ah); + +static HAL_BOOL ar5416SetTransmitPower(struct ath_hal *ah, + HAL_CHANNEL_INTERNAL *chan, uint16_t *rfXpdGain); + +#if 0 +static HAL_BOOL ar5416ChannelChange(struct ath_hal *, HAL_CHANNEL *); +#endif +static void ar5416SetDeltaSlope(struct ath_hal *, HAL_CHANNEL_INTERNAL *); +static void ar5416SpurMitigate(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan); +#ifdef AH_SUPPORT_AR9280 +static void ar9280SpurMitigate(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan); +#endif + +static HAL_BOOL ar5416SetResetPowerOn(struct ath_hal *ah); +static HAL_BOOL ar5416SetReset(struct ath_hal *ah, int type); +static void ar5416InitPLL(struct ath_hal *ah, HAL_CHANNEL *chan); +static HAL_BOOL ar5416SetBoardValues(struct ath_hal *, HAL_CHANNEL_INTERNAL *); +static HAL_BOOL ar5416SetPowerPerRateTable(struct ath_hal *ah, + struct ar5416eeprom *pEepData, + HAL_CHANNEL_INTERNAL *chan, int16_t *ratesArray, + uint16_t cfgCtl, uint16_t AntennaReduction, + uint16_t twiceMaxRegulatoryPower, + uint16_t powerLimit); +static HAL_BOOL ar5416SetPowerCalTable(struct ath_hal *ah, + struct ar5416eeprom *pEepData, + HAL_CHANNEL_INTERNAL *chan, + int16_t *pTxPowerIndexOffset); +static uint16_t ar5416GetMaxEdgePower(uint16_t freq, + CAL_CTL_EDGES *pRdEdgesPower, HAL_BOOL is2GHz); +static void ar5416GetTargetPowers(struct ath_hal *ah, + HAL_CHANNEL_INTERNAL *chan, CAL_TARGET_POWER_HT *powInfo, + uint16_t numChannels, CAL_TARGET_POWER_HT *pNewPower, + uint16_t numRates, HAL_BOOL isHt40Target); +static void ar5416GetTargetPowersLeg(struct ath_hal *ah, + HAL_CHANNEL_INTERNAL *chan, CAL_TARGET_POWER_LEG *powInfo, + uint16_t numChannels, CAL_TARGET_POWER_LEG *pNewPower, + uint16_t numRates, HAL_BOOL isExtTarget); + +static int16_t interpolate(uint16_t target, uint16_t srcLeft, + uint16_t srcRight, int16_t targetLeft, int16_t targetRight); +static void ar5416Set11nRegs(struct ath_hal *ah, HAL_CHANNEL *chan); +static void ar5416GetGainBoundariesAndPdadcs(struct ath_hal *ah, + HAL_CHANNEL_INTERNAL *chan, CAL_DATA_PER_FREQ *pRawDataSet, + uint8_t * bChans, uint16_t availPiers, + uint16_t tPdGainOverlap, int16_t *pMinCalPower, + uint16_t * pPdGainBoundaries, uint8_t * pPDADCValues, + uint16_t numXpdGains); +static HAL_BOOL getLowerUpperIndex(uint8_t target, uint8_t *pList, + uint16_t listSize, uint16_t *indexL, uint16_t *indexR); +static HAL_BOOL ar5416FillVpdTable(uint8_t pwrMin, uint8_t pwrMax, + uint8_t *pPwrList, uint8_t *pVpdList, + uint16_t numIntercepts, uint8_t *pRetVpdList); + +/* + * 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 +ar5416Reset(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; + uint32_t softLedCfg; + uint32_t saveDefAntenna, saveLedState; + uint32_t macStaId1; + uint16_t rfXpdGain[2]; + u_int modesIndex, freqIndex; + HAL_STATUS ecode; + int i, regWrites = 0; + uint32_t powerVal, rssiThrReg; + uint32_t ackTpcPow, ctsTpcPow, chirpTpcPow; + + 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 (!ar5416SetPowerMode(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); + } else { + HALDEBUG(ah, HAL_DEBUG_RESET, + "%s: Ch=%u Max=%d Min=%d\n",__func__, + ichan->channel, ichan->maxTxPower, ichan->minTxPower); + } + 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_VER14_1); + + /* XXX Turn on fast channel change for 5416 */ + /* + * Preserve the bmiss rssi threshold and count threshold + * across resets + */ + rssiThrReg = OS_REG_READ(ah, AR_RSSI_THR); + /* If reg is zero, first time thru set to default val */ + if (rssiThrReg == 0) + rssiThrReg = INIT_RSSI_THR; + + /* + * 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_MAC_LED) & + (AR_MAC_LED_ASSOC | AR_MAC_LED_MODE | + AR_MAC_LED_BLINK_THRESH_SEL | AR_MAC_LED_BLINK_SLOW); + softLedCfg = OS_REG_READ(ah, AR_GPIO_INTR_OUT); + + /* + * Adjust gain parameters before reset if + * there's an outstanding gain updated. + */ + (void) ar5416GetRfgain(ah); + + if (!ar5416ChipReset(ah, chan)) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: chip reset failed\n", __func__); + FAIL(HAL_EIO); + } + + /* Restore bmiss rssi & count thresholds */ + OS_REG_WRITE(ah, AR_RSSI_THR, rssiThrReg); + + /* Setup the indices for the next set of register array writes */ + /* XXX Ignore 11n dynamic mode on the AR5416 for the moment */ + switch (chan->channelFlags & CHANNEL_ALL) { + case CHANNEL_A: + case CHANNEL_A_HT20: + modesIndex = 1; + freqIndex = 1; + break; + case CHANNEL_T: + case CHANNEL_A_HT40PLUS: + case CHANNEL_A_HT40MINUS: + modesIndex = 2; + freqIndex = 1; + break; + case CHANNEL_PUREG: + case CHANNEL_G_HT20: + case CHANNEL_B: /* treat as channel G , no B mode suport in owl */ + modesIndex = 4; + freqIndex = 2; + break; + case CHANNEL_G_HT40PLUS: + case CHANNEL_G_HT40MINUS: + modesIndex = 3; + 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); + + /* + * Write addac shifts + */ + OS_REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_EXTERNAL_RADIO); +#if 0 + /* NB: only required for Sowl */ + ar5416EepromSetAddac(ah, ichan); +#endif + regWrites = ath_hal_ini_write(ah, &AH5416(ah)->ah_ini_addac, 1, + regWrites); + OS_REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_INTERNAL_ADDAC); + + /* XXX Merlin ini fixups */ + /* XXX Merlin 100us delay for shift registers */ + regWrites = ath_hal_ini_write(ah, &ahp->ah_ini_modes, modesIndex, + regWrites); +#ifdef AH_SUPPORT_AR9280 + if (AR_SREV_MERLIN_20_OR_LATER(ah)) { + regWrites = ath_hal_ini_write(ah, &AH9280(ah)->ah_ini_rxgain, + modesIndex, regWrites); + regWrites = ath_hal_ini_write(ah, &AH9280(ah)->ah_ini_txgain, + modesIndex, regWrites); + } +#endif + /* XXX Merlin 100us delay for shift registers */ + regWrites = ath_hal_ini_write(ah, &ahp->ah_ini_common, 1, regWrites); + /* Setup 11n MAC/Phy mode registers */ + ar5416Set11nRegs(ah,chan); + /* XXX updated regWrites? */ + ahp->ah_rfHal->writeRegs(ah, modesIndex, freqIndex, regWrites); +#ifdef AH_SUPPORT_AR9280 + if (AR_SREV_MERLIN_20(ah) && IS_5GHZ_FAST_CLOCK_EN(ah, chan)) { + /* 5GHz channels w/ Fast Clock use different modal values */ + regWrites = ath_hal_ini_write(ah, &AH9280(ah)->ah_ini_xmodes, + modesIndex, regWrites); + } +#endif + + OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__); + + HALDEBUG(ah, HAL_DEBUG_RESET, ">>>2 %s: AR_PHY_DAG_CTRLCCK=0x%x\n", + __func__, OS_REG_READ(ah,AR_PHY_DAG_CTRLCCK)); + HALDEBUG(ah, HAL_DEBUG_RESET, ">>>2 %s: AR_PHY_ADC_CTL=0x%x\n", + __func__, OS_REG_READ(ah,AR_PHY_ADC_CTL)); + + /* Set the mute mask to the correct default */ + if (AH_PRIVATE(ah)->ah_phyRev >= AR_PHY_CHIP_ID_REV_2) + 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 (AH5416(ah)->ah_rx_chainmask == 0x5 || + AH5416(ah)->ah_tx_chainmask == 0x5) + OS_REG_WRITE(ah, AR_PHY_ANALOG_SWAP, AR_PHY_SWAP_ALT_CHAIN); + /* Setup Chain Masks */ + OS_REG_WRITE(ah, AR_PHY_RX_CHAINMASK, AH5416(ah)->ah_rx_chainmask); + OS_REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, AH5416(ah)->ah_rx_chainmask); + OS_REG_WRITE(ah, AR_SELFGEN_MASK, AH5416(ah)->ah_tx_chainmask); + + /* Setup the transmit power values. */ + if (!ar5416SetTransmitPower(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, freqIndex, 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)|| IS_CHAN_HT(chan)) + ar5416SetDeltaSlope(ah, ichan); + +#ifdef AH_SUPPORT_AR9280 + if (AR_SREV_MERLIN_10_OR_LATER(ah)) + ar9280SpurMitigate(ah, ichan); + else +#endif + ar5416SpurMitigate(ah, ichan); + + /* Setup board specific options for EEPROM version 3 */ + if (!ar5416SetBoardValues(ah, ichan)) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: error setting board options\n", __func__); + FAIL(HAL_EIO); + } + + 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_MAC_LED, OS_REG_READ(ah, AR_MAC_LED) | saveLedState); + /* Restore soft Led state to GPIO */ + OS_REG_WRITE(ah, AR_GPIO_INTR_OUT, softLedCfg); + + /* 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__); + + /* 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); + + ar5416InitIMR(ah, opmode); + ar5212SetCoverageClass(ah, AH_PRIVATE(ah)->ah_coverageClass, 1); + ar5416InitQoS(ah); + ar5416InitUserSettings(ah); + + /* + * disable seq number generation in hw + */ + OS_REG_WRITE(ah, AR_STA_ID1, + OS_REG_READ(ah, AR_STA_ID1) | AR_STA_ID1_PRESERVE_SEQNUM); + + ar5416InitDMA(ah); + + /* + * program OBS bus to see MAC interrupts + */ + OS_REG_WRITE(ah, AR_OBS, 8); + +#ifdef AR5416_INT_MITIGATION + OS_REG_WRITE(ah, AR_MIRT, 0); + OS_REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_LAST, 500); + OS_REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_FIRST, 2000); +#endif + + ar5416InitBB(ah, chan); + + /* Setup compression registers */ + ar5212SetCompRegs(ah); /* XXX not needed? */ + + /* + * 5416 baseband will check the per rate power table + * and select the lower of the two + */ + ackTpcPow = 63; + ctsTpcPow = 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); + + if (!ar5416InitCal(ah, chan)) + FAIL(HAL_ESELFTEST); + + 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__); + + 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 +} + +#if 0 +/* + * 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 +ar5416ChannelChange(struct ath_hal *ah, HAL_CHANNEL *chan) +{ + uint32_t ulCount; + uint32_t data, synthDelay, qnum; + uint16_t rfXpdGain[4]; + struct ath_hal_5212 *ahp = AH5212(ah); + 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)) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: frames pending on queue %d\n", __func__, qnum); + return AH_FALSE; + } + } + + /* + * Kill last Baseband Rx Frame - Request analog bus grant + */ + OS_REG_WRITE(ah, AR_PHY_RFBUS_REQ, AR_PHY_RFBUS_REQ_REQUEST); + if (!ath_hal_wait(ah, AR_PHY_RFBUS_GNT, AR_PHY_RFBUS_GRANT_EN, AR_PHY_RFBUS_GRANT_EN)) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: could not kill baseband rx\n", + __func__); + return AH_FALSE; + } + + ar5416Set11nRegs(ah, chan); /* NB: setup 5416-specific regs */ + + /* Change the synth */ + if (!ar5212SetChannel(ah, ichan)) + return AH_FALSE; + + /* Setup the transmit power values. */ + if (!ar5416SetTransmitPower(ah, ichan, rfXpdGain)) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: error init'ing transmit power\n", __func__); + 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); + + /* Release the RFBus Grant */ + OS_REG_WRITE(ah, AR_PHY_RFBUS_REQ, 0); + + /* Write delta slope for OFDM enabled modes (A, G, Turbo) */ + if (IS_CHAN_OFDM(ichan)|| IS_CHAN_HT(chan)) { + if (ahp->ah_eeprom.ee_version >= AR_EEPROM_VER5_3 && + !IS_CHAN_B(chan)) + ar5212SetSpurMitigation(ah, ichan); + ar5416SetDeltaSlope(ah, ichan); + } + + /* XXX spur mitigation for Melin */ + + /* Copy over internal channel flags to public hal channel */ + + 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; + AH_PRIVATE(ah)->ah_curchan->ah_channel_time=0; + AH_PRIVATE(ah)->ah_curchan->ah_tsf_last = ar5212GetTsf64(ah); + ar5212TxEnable(ah,AH_TRUE); + return AH_TRUE; +} +#endif + +static void +ar5416InitDMA(struct ath_hal *ah) +{ + + /* + * set AHB_MODE not to do cacheline prefetches + */ + OS_REG_SET_BIT(ah, AR_AHB_MODE, AR_AHB_PREFETCH_RD_EN); + + /* + * let mac dma reads be in 128 byte chunks + */ + OS_REG_WRITE(ah, AR_TXCFG, + (OS_REG_READ(ah, AR_TXCFG) & ~AR_TXCFG_DMASZ_MASK) | AR_TXCFG_DMASZ_128B); + + /* + * let mac dma writes be in 128 byte chunks + */ + OS_REG_WRITE(ah, AR_RXCFG, + (OS_REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_DMASZ_MASK) | AR_RXCFG_DMASZ_128B); + + /* XXX restore TX trigger level */ + + /* + * Setup receive FIFO threshold to hold off TX activities + */ + OS_REG_WRITE(ah, AR_RXFIFO_CFG, 0x200); + + /* + * reduce the number of usable entries in PCU TXBUF to avoid + * wrap around. + */ + OS_REG_WRITE(ah, AR_PCU_TXBUF_CTRL, AR_PCU_TXBUF_CTRL_USABLE_SIZE); +} + +static void +ar5416InitBB(struct ath_hal *ah, HAL_CHANNEL *chan) +{ + uint32_t synthDelay; + + /* + * 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; + } + + /* Turn on PLL on 5416 */ + HALDEBUG(ah, HAL_DEBUG_RESET, "%s %s channel\n", + __func__, IS_CHAN_5GHZ(chan) ? "5GHz" : "2GHz"); + ar5416InitPLL(ah, chan); + + /* Activate the PHY (includes baseband activate and synthesizer on) */ + OS_REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); + + /* + * If the AP starts the calibration before the base band timeout + * completes we could get rx_clear false triggering. Add 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); + } +} + +static void +ar5416InitIMR(struct ath_hal *ah, HAL_OPMODE opmode) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + + /* + * 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_TXERR | AR_IMR_TXURN + | AR_IMR_RXERR | AR_IMR_RXORN + | AR_IMR_BCNMISC; + +#ifdef AR5416_INT_MITIGATION + ahp->ah_maskReg |= AR_IMR_TXINTM | AR_IMR_RXINTM + | AR_IMR_TXMINTR | AR_IMR_RXMINTR; +#else + ahp->ah_maskReg |= AR_IMR_TXOK | AR_IMR_RXOK; +#endif + 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 */ + +#if 0 + OS_REG_WRITE(ah, AR_IMR_S2, + OS_REG_READ(ah, AR_IMR_S2) | AR_IMR_S2_GTT | AR_IMR_S2_CST); +#endif +} + +static void +ar5416InitQoS(struct ath_hal *ah) +{ + /* QoS support */ + 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)); + + /* + * initialize TXOP for all TIDs + */ + OS_REG_WRITE(ah, AR_TXOP_X, AR_TXOP_X_VAL); + OS_REG_WRITE(ah, AR_TXOP_0_3, 0xFFFFFFFF); + OS_REG_WRITE(ah, AR_TXOP_4_7, 0xFFFFFFFF); + OS_REG_WRITE(ah, AR_TXOP_8_11, 0xFFFFFFFF); + OS_REG_WRITE(ah, AR_TXOP_12_15, 0xFFFFFFFF); +} + +static void +ar5416InitUserSettings(struct ath_hal *ah) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + + /* 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); +#if 0 /* XXX Todo */ + if (ahp->ah_globaltxtimeout != (u_int) -1) + ar5416SetGlobalTxTimeout(ah, ahp->ah_globaltxtimeout); +#endif +} + +/* + * Places the hardware into reset and then pulls it out of reset + */ +HAL_BOOL +ar5416ChipReset(struct ath_hal *ah, HAL_CHANNEL *chan) +{ + uint32_t rfMode = 0; + + OS_MARK(ah, AH_MARK_CHIPRESET, chan ? chan->channel : 0); + /* + * Warm reset is optimistic. + */ + if (AR_SREV_MERLIN_20_OR_LATER(ah) && + ath_hal_eepromGetFlag(ah, AR_EEP_OL_PWRCTRL)) { + if (!ar5416SetResetReg(ah, HAL_RESET_POWER_ON)) + return AH_FALSE; + } else { + if (!ar5416SetResetReg(ah, HAL_RESET_WARM)) + return AH_FALSE; + } + + /* Bring out of sleep mode (AGAIN) */ + if (!ar5416SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE)) + return AH_FALSE; + + ar5416InitPLL(ah, chan); + + /* + * 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. + */ + if (chan != AH_NULL) { + /* treat channel B as channel G , no B mode suport in owl */ + rfMode |= (IS_CHAN_G(chan) || IS_CHAN_B(chan)) ? + AR_PHY_MODE_DYNAMIC : AR_PHY_MODE_OFDM; + if (AR_SREV_MERLIN_20(ah) && IS_5GHZ_FAST_CLOCK_EN(ah, chan)) { + /* phy mode bits for 5GHz channels require Fast Clock */ + rfMode |= AR_PHY_MODE_DYNAMIC + | AR_PHY_MODE_DYN_CCK_DISABLE; + } else if (!AR_SREV_MERLIN_10_OR_LATER(ah)) { + rfMode |= (IS_CHAN_5GHZ(chan)) ? + AR_PHY_MODE_RF5GHZ : AR_PHY_MODE_RF2GHZ; + } + OS_REG_WRITE(ah, AR_PHY_MODE, rfMode); + } + return AH_TRUE; +} + +/* + * Delta slope coefficient computation. + * Required for OFDM operation. + */ +static void +ar5416GetDeltaSlopeValues(struct ath_hal *ah, uint32_t coef_scaled, + uint32_t *coef_mantissa, uint32_t *coef_exponent) +{ +#define COEF_SCALE_S 24 + uint32_t coef_exp, coef_man; + /* + * 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)); + + *coef_mantissa = coef_man >> (COEF_SCALE_S - coef_exp); + *coef_exponent = coef_exp - 16; + +#undef COEF_SCALE_S +} + +void +ar5416SetDeltaSlope(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan) +{ +#define INIT_CLOCKMHZSCALED 0x64000000 + uint32_t coef_scaled, ds_coef_exp, ds_coef_man; + uint32_t clockMhzScaled = INIT_CLOCKMHZSCALED; + + CHAN_CENTERS centers; + + 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 + */ + ar5416GetChannelCenters(ah, chan, ¢ers); + coef_scaled = clockMhzScaled / centers.synth_center; + + ar5416GetDeltaSlopeValues(ah, coef_scaled, &ds_coef_man, &ds_coef_exp); + + 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); + + /* + * For Short GI, + * scaled coeff is 9/10 that of normal coeff + */ + coef_scaled = (9 * coef_scaled)/10; + + ar5416GetDeltaSlopeValues(ah, coef_scaled, &ds_coef_man, &ds_coef_exp); + + /* for short gi */ + OS_REG_RMW_FIELD(ah, AR_PHY_HALFGI, + AR_PHY_HALFGI_DSC_MAN, ds_coef_man); + OS_REG_RMW_FIELD(ah, AR_PHY_HALFGI, + AR_PHY_HALFGI_DSC_EXP, ds_coef_exp); +#undef INIT_CLOCKMHZSCALED +} + +/* + * Convert to baseband spur frequency given input channel frequency + * and compute register settings below. + */ +#define SPUR_RSSI_THRESH 40 + +static void +ar5416SpurMitigate(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan) +{ + static const int pilot_mask_reg[4] = { AR_PHY_TIMING7, AR_PHY_TIMING8, + AR_PHY_PILOT_MASK_01_30, AR_PHY_PILOT_MASK_31_60 }; + static const int chan_mask_reg[4] = { AR_PHY_TIMING9, AR_PHY_TIMING10, + AR_PHY_CHANNEL_MASK_01_30, AR_PHY_CHANNEL_MASK_31_60 }; + static const int inc[4] = { 0, 100, 0, 0 }; + + int bb_spur = AR_NO_SPUR; + int bin, cur_bin; + int spur_freq_sd; + int spur_delta_phase; + int denominator; + int upper, lower, cur_vit_mask; + int tmp, new; + int i; + + int8_t mask_m[123]; + int8_t mask_p[123]; + int8_t mask_amt; + int tmp_mask; + int cur_bb_spur; + HAL_BOOL is2GHz = IS_CHAN_2GHZ(chan); + + OS_MEMZERO(mask_m, sizeof(mask_m)); + OS_MEMZERO(mask_p, sizeof(mask_p)); + + /* + * Need to verify range +/- 9.5 for static ht20, otherwise spur + * is out-of-band and can be ignored. + */ + for (i = 0; i < AR5416_EEPROM_MODAL_SPURS; i++) { + cur_bb_spur = ath_hal_getSpurChan(ah, i, is2GHz); + if (AR_NO_SPUR == cur_bb_spur) + break; + cur_bb_spur = cur_bb_spur - (chan->channel * 10); + if ((cur_bb_spur > -95) && (cur_bb_spur < 95)) { + bb_spur = cur_bb_spur; + break; + } + } + if (AR_NO_SPUR == bb_spur) + return; + + bin = bb_spur * 32; + + tmp = OS_REG_READ(ah, AR_PHY_TIMING_CTRL4_CHAIN(0)); + new = tmp | (AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI | + 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_CHAIN(0), new); + + new = (AR_PHY_SPUR_REG_MASK_RATE_CNTL | + AR_PHY_SPUR_REG_ENABLE_MASK_PPM | + AR_PHY_SPUR_REG_MASK_RATE_SELECT | + AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI | + SM(SPUR_RSSI_THRESH, AR_PHY_SPUR_REG_SPUR_RSSI_THRESH)); + OS_REG_WRITE(ah, AR_PHY_SPUR_REG, new); + /* + * Should offset bb_spur by +/- 10 MHz for dynamic 2040 MHz + * config, no offset for HT20. + * spur_delta_phase = bb_spur/40 * 2**21 for static ht20, + * /80 for dyn2040. + */ + spur_delta_phase = ((bb_spur * 524288) / 100) & + AR_PHY_TIMING11_SPUR_DELTA_PHASE; + /* + * in 11A mode the denominator of spur_freq_sd should be 40 and + * it should be 44 in 11G + */ + denominator = IS_CHAN_2GHZ(chan) ? 440 : 400; + spur_freq_sd = ((bb_spur * 2048) / denominator) & 0x3ff; + + new = (AR_PHY_TIMING11_USE_SPUR_IN_AGC | + SM(spur_freq_sd, AR_PHY_TIMING11_SPUR_FREQ_SD) | + SM(spur_delta_phase, AR_PHY_TIMING11_SPUR_DELTA_PHASE)); + OS_REG_WRITE(ah, AR_PHY_TIMING11, new); + + + /* + * ============================================ + * pilot mask 1 [31:0] = +6..-26, no 0 bin + * pilot mask 2 [19:0] = +26..+7 + * + * channel mask 1 [31:0] = +6..-26, no 0 bin + * channel mask 2 [19:0] = +26..+7 + */ + //cur_bin = -26; + cur_bin = -6000; + upper = bin + 100; + lower = bin - 100; + + for (i = 0; i < 4; i++) { + int pilot_mask = 0; + int chan_mask = 0; + int bp = 0; + for (bp = 0; bp < 30; bp++) { + if ((cur_bin > lower) && (cur_bin < upper)) { + pilot_mask = pilot_mask | 0x1 << bp; + chan_mask = chan_mask | 0x1 << bp; + } + cur_bin += 100; + } + cur_bin += inc[i]; + OS_REG_WRITE(ah, pilot_mask_reg[i], pilot_mask); + OS_REG_WRITE(ah, chan_mask_reg[i], chan_mask); + } + + /* ================================================= + * viterbi mask 1 based on channel magnitude + * four levels 0-3 + * - mask (-27 to 27) (reg 64,0x9900 to 67,0x990c) + * [1 2 2 1] for -9.6 or [1 2 1] for +16 + * - enable_mask_ppm, all bins move with freq + * + * - mask_select, 8 bits for rates (reg 67,0x990c) + * - mask_rate_cntl, 8 bits for rates (reg 67,0x990c) + * choose which mask to use mask or mask2 + */ + + /* + * viterbi mask 2 2nd set for per data rate puncturing + * four levels 0-3 + * - mask_select, 8 bits for rates (reg 67) + * - mask (-27 to 27) (reg 98,0x9988 to 101,0x9994) + * [1 2 2 1] for -9.6 or [1 2 1] for +16 + */ + cur_vit_mask = 6100; + upper = bin + 120; + lower = bin - 120; + + for (i = 0; i < 123; i++) { + if ((cur_vit_mask > lower) && (cur_vit_mask < upper)) { + if ((abs(cur_vit_mask - bin)) < 75) { + mask_amt = 1; + } else { + mask_amt = 0; + } + if (cur_vit_mask < 0) { + mask_m[abs(cur_vit_mask / 100)] = mask_amt; + } else { + mask_p[cur_vit_mask / 100] = mask_amt; + } + } + cur_vit_mask -= 100; + } + + tmp_mask = (mask_m[46] << 30) | (mask_m[47] << 28) + | (mask_m[48] << 26) | (mask_m[49] << 24) + | (mask_m[50] << 22) | (mask_m[51] << 20) + | (mask_m[52] << 18) | (mask_m[53] << 16) + | (mask_m[54] << 14) | (mask_m[55] << 12) + | (mask_m[56] << 10) | (mask_m[57] << 8) + | (mask_m[58] << 6) | (mask_m[59] << 4) + | (mask_m[60] << 2) | (mask_m[61] << 0); + OS_REG_WRITE(ah, AR_PHY_BIN_MASK_1, tmp_mask); + OS_REG_WRITE(ah, AR_PHY_VIT_MASK2_M_46_61, tmp_mask); + + tmp_mask = (mask_m[31] << 28) + | (mask_m[32] << 26) | (mask_m[33] << 24) + | (mask_m[34] << 22) | (mask_m[35] << 20) + | (mask_m[36] << 18) | (mask_m[37] << 16) + | (mask_m[48] << 14) | (mask_m[39] << 12) + | (mask_m[40] << 10) | (mask_m[41] << 8) + | (mask_m[42] << 6) | (mask_m[43] << 4) + | (mask_m[44] << 2) | (mask_m[45] << 0); + OS_REG_WRITE(ah, AR_PHY_BIN_MASK_2, tmp_mask); + OS_REG_WRITE(ah, AR_PHY_MASK2_M_31_45, tmp_mask); + + tmp_mask = (mask_m[16] << 30) | (mask_m[16] << 28) + | (mask_m[18] << 26) | (mask_m[18] << 24) + | (mask_m[20] << 22) | (mask_m[20] << 20) + | (mask_m[22] << 18) | (mask_m[22] << 16) + | (mask_m[24] << 14) | (mask_m[24] << 12) + | (mask_m[25] << 10) | (mask_m[26] << 8) + | (mask_m[27] << 6) | (mask_m[28] << 4) + | (mask_m[29] << 2) | (mask_m[30] << 0); + OS_REG_WRITE(ah, AR_PHY_BIN_MASK_3, tmp_mask); + OS_REG_WRITE(ah, AR_PHY_MASK2_M_16_30, tmp_mask); + + tmp_mask = (mask_m[ 0] << 30) | (mask_m[ 1] << 28) + | (mask_m[ 2] << 26) | (mask_m[ 3] << 24) + | (mask_m[ 4] << 22) | (mask_m[ 5] << 20) + | (mask_m[ 6] << 18) | (mask_m[ 7] << 16) + | (mask_m[ 8] << 14) | (mask_m[ 9] << 12) + | (mask_m[10] << 10) | (mask_m[11] << 8) + | (mask_m[12] << 6) | (mask_m[13] << 4) + | (mask_m[14] << 2) | (mask_m[15] << 0); + OS_REG_WRITE(ah, AR_PHY_MASK_CTL, tmp_mask); + OS_REG_WRITE(ah, AR_PHY_MASK2_M_00_15, tmp_mask); + + tmp_mask = (mask_p[15] << 28) + | (mask_p[14] << 26) | (mask_p[13] << 24) + | (mask_p[12] << 22) | (mask_p[11] << 20) + | (mask_p[10] << 18) | (mask_p[ 9] << 16) + | (mask_p[ 8] << 14) | (mask_p[ 7] << 12) + | (mask_p[ 6] << 10) | (mask_p[ 5] << 8) + | (mask_p[ 4] << 6) | (mask_p[ 3] << 4) + | (mask_p[ 2] << 2) | (mask_p[ 1] << 0); + OS_REG_WRITE(ah, AR_PHY_BIN_MASK2_1, tmp_mask); + OS_REG_WRITE(ah, AR_PHY_MASK2_P_15_01, tmp_mask); + + tmp_mask = (mask_p[30] << 28) + | (mask_p[29] << 26) | (mask_p[28] << 24) + | (mask_p[27] << 22) | (mask_p[26] << 20) + | (mask_p[25] << 18) | (mask_p[24] << 16) + | (mask_p[23] << 14) | (mask_p[22] << 12) + | (mask_p[21] << 10) | (mask_p[20] << 8) + | (mask_p[19] << 6) | (mask_p[18] << 4) + | (mask_p[17] << 2) | (mask_p[16] << 0); + OS_REG_WRITE(ah, AR_PHY_BIN_MASK2_2, tmp_mask); + OS_REG_WRITE(ah, AR_PHY_MASK2_P_30_16, tmp_mask); + + tmp_mask = (mask_p[45] << 28) + | (mask_p[44] << 26) | (mask_p[43] << 24) + | (mask_p[42] << 22) | (mask_p[41] << 20) + | (mask_p[40] << 18) | (mask_p[39] << 16) + | (mask_p[38] << 14) | (mask_p[37] << 12) + | (mask_p[36] << 10) | (mask_p[35] << 8) + | (mask_p[34] << 6) | (mask_p[33] << 4) + | (mask_p[32] << 2) | (mask_p[31] << 0); + OS_REG_WRITE(ah, AR_PHY_BIN_MASK2_3, tmp_mask); + OS_REG_WRITE(ah, AR_PHY_MASK2_P_45_31, tmp_mask); + + tmp_mask = (mask_p[61] << 30) | (mask_p[60] << 28) + | (mask_p[59] << 26) | (mask_p[58] << 24) + | (mask_p[57] << 22) | (mask_p[56] << 20) + | (mask_p[55] << 18) | (mask_p[54] << 16) + | (mask_p[53] << 14) | (mask_p[52] << 12) + | (mask_p[51] << 10) | (mask_p[50] << 8) + | (mask_p[49] << 6) | (mask_p[48] << 4) + | (mask_p[47] << 2) | (mask_p[46] << 0); + OS_REG_WRITE(ah, AR_PHY_BIN_MASK2_4, tmp_mask); + OS_REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask); +} + +#ifdef AH_SUPPORT_AR9280 +#define AR_BASE_FREQ_2GHZ 2300 +#define AR_BASE_FREQ_5GHZ 4900 +#define AR_SPUR_FEEQ_BOUND_HT40 19 +#define AR_SPUR_FEEQ_BOUND_HT20 10 + +static void +ar9280SpurMitigate(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan) +{ + static const int pilot_mask_reg[4] = { AR_PHY_TIMING7, AR_PHY_TIMING8, + AR_PHY_PILOT_MASK_01_30, AR_PHY_PILOT_MASK_31_60 }; + static const int chan_mask_reg[4] = { AR_PHY_TIMING9, AR_PHY_TIMING10, + AR_PHY_CHANNEL_MASK_01_30, AR_PHY_CHANNEL_MASK_31_60 }; + static int inc[4] = { 0, 100, 0, 0 }; + + int bb_spur = AR_NO_SPUR; + int freq; + int bin, cur_bin; + int bb_spur_off, spur_subchannel_sd; + int spur_freq_sd; + int spur_delta_phase; + int denominator; + int upper, lower, cur_vit_mask; + int tmp, newVal; + int i; + CHAN_CENTERS centers; + + int8_t mask_m[123]; + int8_t mask_p[123]; + int8_t mask_amt; + int tmp_mask; + int cur_bb_spur; + HAL_BOOL is2GHz = IS_CHAN_2GHZ(ichan); + + OS_MEMZERO(&mask_m, sizeof(int8_t) * 123); + OS_MEMZERO(&mask_p, sizeof(int8_t) * 123); + + ar5416GetChannelCenters(ah, ichan, ¢ers); + freq = centers.synth_center; + + /* + * Need to verify range +/- 9.38 for static ht20 and +/- 18.75 for ht40, + * otherwise spur is out-of-band and can be ignored. + */ + for (i = 0; i < AR5416_EEPROM_MODAL_SPURS; i++) { + cur_bb_spur = ath_hal_getSpurChan(ah, i, is2GHz); + /* Get actual spur freq in MHz from EEPROM read value */ + if (is2GHz) { + cur_bb_spur = (cur_bb_spur / 10) + AR_BASE_FREQ_2GHZ; + } else { + cur_bb_spur = (cur_bb_spur / 10) + AR_BASE_FREQ_5GHZ; + } + + if (AR_NO_SPUR == cur_bb_spur) + break; + cur_bb_spur = cur_bb_spur - freq; + + if (IS_CHAN_HT40(ichan)) { + if ((cur_bb_spur > -AR_SPUR_FEEQ_BOUND_HT40) && + (cur_bb_spur < AR_SPUR_FEEQ_BOUND_HT40)) { + bb_spur = cur_bb_spur; + break; + } + } else if ((cur_bb_spur > -AR_SPUR_FEEQ_BOUND_HT20) && + (cur_bb_spur < AR_SPUR_FEEQ_BOUND_HT20)) { + bb_spur = cur_bb_spur; + break; + } + } + + if (AR_NO_SPUR == bb_spur) { +#if 1 + /* + * MRC CCK can interfere with beacon detection and cause deaf/mute. + * Disable MRC CCK for now. + */ + OS_REG_CLR_BIT(ah, AR_PHY_FORCE_CLKEN_CCK, AR_PHY_FORCE_CLKEN_CCK_MRC_MUX); +#else + /* Enable MRC CCK if no spur is found in this channel. */ + OS_REG_SET_BIT(ah, AR_PHY_FORCE_CLKEN_CCK, AR_PHY_FORCE_CLKEN_CCK_MRC_MUX); +#endif + return; + } else { + /* + * For Merlin, spur can break CCK MRC algorithm. Disable CCK MRC if spur + * is found in this channel. + */ + OS_REG_CLR_BIT(ah, AR_PHY_FORCE_CLKEN_CCK, AR_PHY_FORCE_CLKEN_CCK_MRC_MUX); + } + + bin = bb_spur * 320; + + tmp = OS_REG_READ(ah, AR_PHY_TIMING_CTRL4_CHAIN(0)); + + newVal = tmp | (AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI | + 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_CHAIN(0), newVal); + + newVal = (AR_PHY_SPUR_REG_MASK_RATE_CNTL | + AR_PHY_SPUR_REG_ENABLE_MASK_PPM | + AR_PHY_SPUR_REG_MASK_RATE_SELECT | + AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI | + SM(SPUR_RSSI_THRESH, AR_PHY_SPUR_REG_SPUR_RSSI_THRESH)); + OS_REG_WRITE(ah, AR_PHY_SPUR_REG, newVal); + + /* Pick control or extn channel to cancel the spur */ + if (IS_CHAN_HT40(ichan)) { + if (bb_spur < 0) { + spur_subchannel_sd = 1; + bb_spur_off = bb_spur + 10; + } else { + spur_subchannel_sd = 0; + bb_spur_off = bb_spur - 10; + } + } else { + spur_subchannel_sd = 0; + bb_spur_off = bb_spur; + } + + /* + * spur_delta_phase = bb_spur/40 * 2**21 for static ht20, + * /80 for dyn2040. + */ + if (IS_CHAN_HT40(ichan)) + spur_delta_phase = ((bb_spur * 262144) / 10) & AR_PHY_TIMING11_SPUR_DELTA_PHASE; + else + spur_delta_phase = ((bb_spur * 524288) / 10) & AR_PHY_TIMING11_SPUR_DELTA_PHASE; + + /* + * in 11A mode the denominator of spur_freq_sd should be 40 and + * it should be 44 in 11G + */ + denominator = IS_CHAN_2GHZ(ichan) ? 44 : 40; + spur_freq_sd = ((bb_spur_off * 2048) / denominator) & 0x3ff; + + newVal = (AR_PHY_TIMING11_USE_SPUR_IN_AGC | + SM(spur_freq_sd, AR_PHY_TIMING11_SPUR_FREQ_SD) | + SM(spur_delta_phase, AR_PHY_TIMING11_SPUR_DELTA_PHASE)); + OS_REG_WRITE(ah, AR_PHY_TIMING11, newVal); + + /* Choose to cancel between control and extension channels */ + newVal = spur_subchannel_sd << AR_PHY_SFCORR_SPUR_SUBCHNL_SD_S; + OS_REG_WRITE(ah, AR_PHY_SFCORR_EXT, newVal); + + /* + * ============================================ + * Set Pilot and Channel Masks + * + * pilot mask 1 [31:0] = +6..-26, no 0 bin + * pilot mask 2 [19:0] = +26..+7 + * + * channel mask 1 [31:0] = +6..-26, no 0 bin + * channel mask 2 [19:0] = +26..+7 + */ + cur_bin = -6000; + upper = bin + 100; + lower = bin - 100; + + for (i = 0; i < 4; i++) { + int pilot_mask = 0; + int chan_mask = 0; + int bp = 0; + for (bp = 0; bp < 30; bp++) { + if ((cur_bin > lower) && (cur_bin < upper)) { + pilot_mask = pilot_mask | 0x1 << bp; + chan_mask = chan_mask | 0x1 << bp; + } + cur_bin += 100; + } + cur_bin += inc[i]; + OS_REG_WRITE(ah, pilot_mask_reg[i], pilot_mask); + OS_REG_WRITE(ah, chan_mask_reg[i], chan_mask); + } + + /* ================================================= + * viterbi mask 1 based on channel magnitude + * four levels 0-3 + * - mask (-27 to 27) (reg 64,0x9900 to 67,0x990c) + * [1 2 2 1] for -9.6 or [1 2 1] for +16 + * - enable_mask_ppm, all bins move with freq + * + * - mask_select, 8 bits for rates (reg 67,0x990c) + * - mask_rate_cntl, 8 bits for rates (reg 67,0x990c) + * choose which mask to use mask or mask2 + */ + + /* + * viterbi mask 2 2nd set for per data rate puncturing + * four levels 0-3 + * - mask_select, 8 bits for rates (reg 67) + * - mask (-27 to 27) (reg 98,0x9988 to 101,0x9994) + * [1 2 2 1] for -9.6 or [1 2 1] for +16 + */ + cur_vit_mask = 6100; + upper = bin + 120; + lower = bin - 120; + + for (i = 0; i < 123; i++) { + if ((cur_vit_mask > lower) && (cur_vit_mask < upper)) { + if ((abs(cur_vit_mask - bin)) < 75) { + mask_amt = 1; + } else { + mask_amt = 0; + } + if (cur_vit_mask < 0) { + mask_m[abs(cur_vit_mask / 100)] = mask_amt; + } else { + mask_p[cur_vit_mask / 100] = mask_amt; + } + } + cur_vit_mask -= 100; + } + + tmp_mask = (mask_m[46] << 30) | (mask_m[47] << 28) + | (mask_m[48] << 26) | (mask_m[49] << 24) + | (mask_m[50] << 22) | (mask_m[51] << 20) + | (mask_m[52] << 18) | (mask_m[53] << 16) + | (mask_m[54] << 14) | (mask_m[55] << 12) + | (mask_m[56] << 10) | (mask_m[57] << 8) + | (mask_m[58] << 6) | (mask_m[59] << 4) + | (mask_m[60] << 2) | (mask_m[61] << 0); + OS_REG_WRITE(ah, AR_PHY_BIN_MASK_1, tmp_mask); + OS_REG_WRITE(ah, AR_PHY_VIT_MASK2_M_46_61, tmp_mask); + + tmp_mask = (mask_m[31] << 28) + | (mask_m[32] << 26) | (mask_m[33] << 24) + | (mask_m[34] << 22) | (mask_m[35] << 20) + | (mask_m[36] << 18) | (mask_m[37] << 16) + | (mask_m[48] << 14) | (mask_m[39] << 12) + | (mask_m[40] << 10) | (mask_m[41] << 8) + | (mask_m[42] << 6) | (mask_m[43] << 4) + | (mask_m[44] << 2) | (mask_m[45] << 0); + OS_REG_WRITE(ah, AR_PHY_BIN_MASK_2, tmp_mask); + OS_REG_WRITE(ah, AR_PHY_MASK2_M_31_45, tmp_mask); + + tmp_mask = (mask_m[16] << 30) | (mask_m[16] << 28) + | (mask_m[18] << 26) | (mask_m[18] << 24) + | (mask_m[20] << 22) | (mask_m[20] << 20) + | (mask_m[22] << 18) | (mask_m[22] << 16) + | (mask_m[24] << 14) | (mask_m[24] << 12) + | (mask_m[25] << 10) | (mask_m[26] << 8) + | (mask_m[27] << 6) | (mask_m[28] << 4) + | (mask_m[29] << 2) | (mask_m[30] << 0); + OS_REG_WRITE(ah, AR_PHY_BIN_MASK_3, tmp_mask); + OS_REG_WRITE(ah, AR_PHY_MASK2_M_16_30, tmp_mask); + + tmp_mask = (mask_m[ 0] << 30) | (mask_m[ 1] << 28) + | (mask_m[ 2] << 26) | (mask_m[ 3] << 24) + | (mask_m[ 4] << 22) | (mask_m[ 5] << 20) + | (mask_m[ 6] << 18) | (mask_m[ 7] << 16) + | (mask_m[ 8] << 14) | (mask_m[ 9] << 12) + | (mask_m[10] << 10) | (mask_m[11] << 8) + | (mask_m[12] << 6) | (mask_m[13] << 4) + | (mask_m[14] << 2) | (mask_m[15] << 0); + OS_REG_WRITE(ah, AR_PHY_MASK_CTL, tmp_mask); + OS_REG_WRITE(ah, AR_PHY_MASK2_M_00_15, tmp_mask); + + tmp_mask = (mask_p[15] << 28) + | (mask_p[14] << 26) | (mask_p[13] << 24) + | (mask_p[12] << 22) | (mask_p[11] << 20) + | (mask_p[10] << 18) | (mask_p[ 9] << 16) + | (mask_p[ 8] << 14) | (mask_p[ 7] << 12) + | (mask_p[ 6] << 10) | (mask_p[ 5] << 8) + | (mask_p[ 4] << 6) | (mask_p[ 3] << 4) + | (mask_p[ 2] << 2) | (mask_p[ 1] << 0); + OS_REG_WRITE(ah, AR_PHY_BIN_MASK2_1, tmp_mask); + OS_REG_WRITE(ah, AR_PHY_MASK2_P_15_01, tmp_mask); + + tmp_mask = (mask_p[30] << 28) + | (mask_p[29] << 26) | (mask_p[28] << 24) + | (mask_p[27] << 22) | (mask_p[26] << 20) + | (mask_p[25] << 18) | (mask_p[24] << 16) + | (mask_p[23] << 14) | (mask_p[22] << 12) + | (mask_p[21] << 10) | (mask_p[20] << 8) + | (mask_p[19] << 6) | (mask_p[18] << 4) + | (mask_p[17] << 2) | (mask_p[16] << 0); + OS_REG_WRITE(ah, AR_PHY_BIN_MASK2_2, tmp_mask); + OS_REG_WRITE(ah, AR_PHY_MASK2_P_30_16, tmp_mask); + + tmp_mask = (mask_p[45] << 28) + | (mask_p[44] << 26) | (mask_p[43] << 24) + | (mask_p[42] << 22) | (mask_p[41] << 20) + | (mask_p[40] << 18) | (mask_p[39] << 16) + | (mask_p[38] << 14) | (mask_p[37] << 12) + | (mask_p[36] << 10) | (mask_p[35] << 8) + | (mask_p[34] << 6) | (mask_p[33] << 4) + | (mask_p[32] << 2) | (mask_p[31] << 0); + OS_REG_WRITE(ah, AR_PHY_BIN_MASK2_3, tmp_mask); + OS_REG_WRITE(ah, AR_PHY_MASK2_P_45_31, tmp_mask); + + tmp_mask = (mask_p[61] << 30) | (mask_p[60] << 28) + | (mask_p[59] << 26) | (mask_p[58] << 24) + | (mask_p[57] << 22) | (mask_p[56] << 20) + | (mask_p[55] << 18) | (mask_p[54] << 16) + | (mask_p[53] << 14) | (mask_p[52] << 12) + | (mask_p[51] << 10) | (mask_p[50] << 8) + | (mask_p[49] << 6) | (mask_p[48] << 4) + | (mask_p[47] << 2) | (mask_p[46] << 0); + OS_REG_WRITE(ah, AR_PHY_BIN_MASK2_4, tmp_mask); + OS_REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask); +} +#endif /* AH_SUPPORT_AR9280 */ + +/* + * 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 +ar5416SetTxPowerLimit(struct ath_hal *ah, uint32_t limit) +{ + uint16_t dummyXpdGains[2]; + + AH_PRIVATE(ah)->ah_powerLimit = AH_MIN(limit, MAX_RATE_POWER); + return ar5416SetTransmitPower(ah, AH_PRIVATE(ah)->ah_curchan, + dummyXpdGains); +} + +HAL_BOOL +ar5416GetChipPowerLimits(struct ath_hal *ah, HAL_CHANNEL *chans, uint32_t nchans) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + int16_t minPower, maxPower; + 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 = AR5416_MAX_RATE_POWER; + chan->minTxPower = 0; + } + } +#ifdef AH_DEBUG + for (i=0; iah_eeprom; + struct ar5416eeprom *pEepData = &ee->ee_base; + + HALASSERT(AH_PRIVATE(ah)->ah_eeversion >= AR_EEPROM_VER14_1); + + /* Setup info for the actual eeprom */ + ath_hal_memzero(ratesArray, sizeof(ratesArray)); + cfgCtl = ath_hal_getctl(ah, (HAL_CHANNEL *)chan); + powerLimit = chan->maxRegTxPower * 2; + twiceAntennaReduction = chan->antennaMax; + twiceMaxRegulatoryPower = AH_MIN(MAX_RATE_POWER, AH_PRIVATE(ah)->ah_powerLimit); + pModal = &pEepData->modalHeader[IS_CHAN_2GHZ(chan)]; + HALDEBUG(ah, HAL_DEBUG_RESET, "%s Channel=%u CfgCtl=%u\n", + __func__,chan->channel, cfgCtl ); + + if (IS_EEP_MINOR_V2(ah)) { + ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc; + } + + if (!ar5416SetPowerPerRateTable(ah, pEepData, chan, + &ratesArray[0],cfgCtl, + twiceAntennaReduction, + twiceMaxRegulatoryPower, powerLimit)) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: unable to set tx power per rate table\n", __func__); + return AH_FALSE; + } + + if (!ar5416SetPowerCalTable(ah, pEepData, chan, &txPowerIndexOffset)) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unable to set power table\n", + __func__); + return AH_FALSE; + } + + maxPower = AH_MAX(ratesArray[rate6mb], ratesArray[rateHt20_0]); + + if (IS_CHAN_2GHZ(chan)) { + maxPower = AH_MAX(maxPower, ratesArray[rate1l]); + } + + if (IS_CHAN_HT40(chan)) { + maxPower = AH_MAX(maxPower, ratesArray[rateHt40_0]); + } + + ahp->ah_tx6PowerInHalfDbm = maxPower; + AH_PRIVATE(ah)->ah_maxPowerLevel = maxPower; + ahp->ah_txPowerIndexOffset = txPowerIndexOffset; + + /* + * txPowerIndexOffset is set by the SetPowerTable() call - + * adjust the rate table (0 offset if rates EEPROM not loaded) + */ + for (i = 0; i < N(ratesArray); i++) { + ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]); + if (ratesArray[i] > AR5416_MAX_RATE_POWER) + ratesArray[i] = AR5416_MAX_RATE_POWER; + } + +#ifdef AH_EEPROM_DUMP + ar5416PrintPowerPerRate(ah, ratesArray); +#endif + + /* Write the OFDM power per rate set */ + OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, + POW_SM(ratesArray[rate18mb], 24) + | POW_SM(ratesArray[rate12mb], 16) + | POW_SM(ratesArray[rate9mb], 8) + | POW_SM(ratesArray[rate6mb], 0) + ); + OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE2, + POW_SM(ratesArray[rate54mb], 24) + | POW_SM(ratesArray[rate48mb], 16) + | POW_SM(ratesArray[rate36mb], 8) + | POW_SM(ratesArray[rate24mb], 0) + ); + + if (IS_CHAN_2GHZ(chan)) { + /* Write the CCK power per rate set */ + OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, + POW_SM(ratesArray[rate2s], 24) + | POW_SM(ratesArray[rate2l], 16) + | POW_SM(ratesArray[rateXr], 8) /* XR target power */ + | POW_SM(ratesArray[rate1l], 0) + ); + OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, + POW_SM(ratesArray[rate11s], 24) + | POW_SM(ratesArray[rate11l], 16) + | POW_SM(ratesArray[rate5_5s], 8) + | POW_SM(ratesArray[rate5_5l], 0) + ); + HALDEBUG(ah, HAL_DEBUG_RESET, + "%s AR_PHY_POWER_TX_RATE3=0x%x AR_PHY_POWER_TX_RATE4=0x%x\n", + __func__, OS_REG_READ(ah,AR_PHY_POWER_TX_RATE3), + OS_REG_READ(ah,AR_PHY_POWER_TX_RATE4)); + } + + /* Write the HT20 power per rate set */ + OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE5, + POW_SM(ratesArray[rateHt20_3], 24) + | POW_SM(ratesArray[rateHt20_2], 16) + | POW_SM(ratesArray[rateHt20_1], 8) + | POW_SM(ratesArray[rateHt20_0], 0) + ); + OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE6, + POW_SM(ratesArray[rateHt20_7], 24) + | POW_SM(ratesArray[rateHt20_6], 16) + | POW_SM(ratesArray[rateHt20_5], 8) + | POW_SM(ratesArray[rateHt20_4], 0) + ); + + if (IS_CHAN_HT40(chan)) { + /* Write the HT40 power per rate set */ + /* Correct PAR difference between HT40 and HT20/LEGACY */ + OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE7, + POW_SM(ratesArray[rateHt40_3] + ht40PowerIncForPdadc, 24) + | POW_SM(ratesArray[rateHt40_2] + ht40PowerIncForPdadc, 16) + | POW_SM(ratesArray[rateHt40_1] + ht40PowerIncForPdadc, 8) + | POW_SM(ratesArray[rateHt40_0] + ht40PowerIncForPdadc, 0) + ); + OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE8, + POW_SM(ratesArray[rateHt40_7] + ht40PowerIncForPdadc, 24) + | POW_SM(ratesArray[rateHt40_6] + ht40PowerIncForPdadc, 16) + | POW_SM(ratesArray[rateHt40_5] + ht40PowerIncForPdadc, 8) + | POW_SM(ratesArray[rateHt40_4] + ht40PowerIncForPdadc, 0) + ); + /* Write the Dup/Ext 40 power per rate set */ + OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, + POW_SM(ratesArray[rateExtOfdm], 24) + | POW_SM(ratesArray[rateExtCck], 16) + | POW_SM(ratesArray[rateDupOfdm], 8) + | POW_SM(ratesArray[rateDupCck], 0) + ); + } + + /* Write the Power subtraction for dynamic chain changing, for per-packet powertx */ + OS_REG_WRITE(ah, AR_PHY_POWER_TX_SUB, + POW_SM(pModal->pwrDecreaseFor3Chain, 6) + | POW_SM(pModal->pwrDecreaseFor2Chain, 0) + ); + return AH_TRUE; +#undef POW_SM +#undef N +} + +/* + * Exported call to check for a recent gain reading and return + * the current state of the thermal calibration gain engine. + */ +HAL_RFGAIN +ar5416GetRfgain(struct ath_hal *ah) +{ + return HAL_RFGAIN_INACTIVE; +} + +/* + * Places all of hardware into reset + */ +HAL_BOOL +ar5416Disable(struct ath_hal *ah) +{ + if (!ar5212SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE)) + return AH_FALSE; + return ar5416SetResetReg(ah, HAL_RESET_COLD); +} + +/* + * 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 +ar5416PhyDisable(struct ath_hal *ah) +{ + return ar5416SetResetReg(ah, HAL_RESET_WARM); +} + +/* + * Write the given reset bit mask into the reset register + */ +HAL_BOOL +ar5416SetResetReg(struct ath_hal *ah, uint32_t type) +{ + /* + * Set force wake + */ + OS_REG_WRITE(ah, AR_RTC_FORCE_WAKE, + AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT); + + switch (type) { + case HAL_RESET_POWER_ON: + return ar5416SetResetPowerOn(ah); + break; + case HAL_RESET_WARM: + case HAL_RESET_COLD: + return ar5416SetReset(ah, type); + break; + default: + return AH_FALSE; + } +} + +static HAL_BOOL +ar5416SetResetPowerOn(struct ath_hal *ah) +{ + /* Power On Reset (Hard Reset) */ + + /* + * Set force wake + * + * If the MAC was running, previously calling + * reset will wake up the MAC but it may go back to sleep + * before we can start polling. + * Set force wake stops that + * This must be called before initiating a hard reset. + */ + OS_REG_WRITE(ah, AR_RTC_FORCE_WAKE, + AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT); + + /* + * RTC reset and clear + */ + OS_REG_WRITE(ah, AR_RTC_RESET, 0); + OS_DELAY(20); + OS_REG_WRITE(ah, AR_RTC_RESET, 1); + + /* + * Poll till RTC is ON + */ + if (!ath_hal_wait(ah, AR_RTC_STATUS, AR_RTC_PM_STATUS_M, AR_RTC_STATUS_ON)) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: RTC not waking up\n", __func__); + return AH_FALSE; + } + + return ar5416SetReset(ah, HAL_RESET_COLD); +} + +static HAL_BOOL +ar5416SetReset(struct ath_hal *ah, int type) +{ + uint32_t tmpReg; + + /* + * Force wake + */ + OS_REG_WRITE(ah, AR_RTC_FORCE_WAKE, + AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT); + + /* + * Reset AHB + */ + tmpReg = OS_REG_READ(ah, AR_INTR_SYNC_CAUSE); + if (tmpReg & (AR_INTR_SYNC_LOCAL_TIMEOUT|AR_INTR_SYNC_RADM_CPL_TIMEOUT)) { + OS_REG_WRITE(ah, AR_INTR_SYNC_ENABLE, 0); + OS_REG_WRITE(ah, AR_RC, AR_RC_AHB|AR_RC_HOSTIF); + } else { + OS_REG_WRITE(ah, AR_RC, AR_RC_AHB); + } + + /* + * Set Mac(BB,Phy) Warm Reset + */ + switch (type) { + case HAL_RESET_WARM: + OS_REG_WRITE(ah, AR_RTC_RC, AR_RTC_RC_MAC_WARM); + break; + case HAL_RESET_COLD: + OS_REG_WRITE(ah, AR_RTC_RC, AR_RTC_RC_MAC_WARM|AR_RTC_RC_MAC_COLD); + break; + default: + HALASSERT(0); + break; + } + + /* + * Clear resets and force wakeup + */ + OS_REG_WRITE(ah, AR_RTC_RC, 0); + if (!ath_hal_wait(ah, AR_RTC_RC, AR_RTC_RC_M, 0)) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: RTC stuck in MAC reset\n", __func__); + return AH_FALSE; + } + + /* Clear AHB reset */ + OS_REG_WRITE(ah, AR_RC, 0); + + /* Set register and descriptor swapping on + * Bigendian platforms on cold reset + */ +#ifdef __BIG_ENDIAN__ + if (type == HAL_RESET_COLD) { + uint32_t mask; + + HALDEBUG(ah, HAL_DEBUG_RESET, + "%s Applying descriptor swap\n", __func__); + + 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)); + } +#endif + + ar5416InitPLL(ah, AH_NULL); + + return AH_TRUE; +} + +#ifndef IS_5GHZ_FAST_CLOCK_EN +#define IS_5GHZ_FAST_CLOCK_EN(ah, chan) AH_FALSE +#endif + +static void +ar5416InitPLL(struct ath_hal *ah, HAL_CHANNEL *chan) +{ + uint32_t pll; + + if (AR_SREV_MERLIN_10_OR_LATER(ah)) { + pll = SM(0x5, AR_RTC_SOWL_PLL_REFDIV); + + if (chan != AH_NULL && IS_CHAN_HALF_RATE(chan)) { + pll |= SM(0x1, AR_RTC_SOWL_PLL_CLKSEL); + } else if (chan && IS_CHAN_QUARTER_RATE(chan)) { + pll |= SM(0x2, AR_RTC_SOWL_PLL_CLKSEL); + } + if (chan != AH_NULL && IS_CHAN_5GHZ(chan)) { + pll |= SM(0x28, AR_RTC_SOWL_PLL_DIV); + + /* + * PLL WAR for Merlin 2.0/2.1 + * When doing fast clock, set PLL to 0x142c + * Else, set PLL to 0x2850 to prevent reset-to-reset variation + */ + if (AR_SREV_MERLIN_20(ah)) { + if (IS_5GHZ_FAST_CLOCK_EN(ah, chan)) { + pll = 0x142c; + } else { + pll = 0x2850; + } + } + } else { + pll |= SM(0x2c, AR_RTC_SOWL_PLL_DIV); + } + } else if (AR_SREV_SOWL_10_OR_LATER(ah)) { + pll = SM(0x5, AR_RTC_SOWL_PLL_REFDIV); + + if (chan != AH_NULL && IS_CHAN_HALF_RATE(chan)) { + pll |= SM(0x1, AR_RTC_SOWL_PLL_CLKSEL); + } else if (chan && IS_CHAN_QUARTER_RATE(chan)) { + pll |= SM(0x2, AR_RTC_SOWL_PLL_CLKSEL); + } + if (chan != AH_NULL && IS_CHAN_5GHZ(chan)) { + pll |= SM(0x50, AR_RTC_SOWL_PLL_DIV); + } else { + pll |= SM(0x58, AR_RTC_SOWL_PLL_DIV); + } + } else { + pll = AR_RTC_PLL_REFDIV_5 | AR_RTC_PLL_DIV2; + + if (chan != AH_NULL && IS_CHAN_HALF_RATE(chan)) { + pll |= SM(0x1, AR_RTC_PLL_CLKSEL); + } else if (chan != AH_NULL && IS_CHAN_QUARTER_RATE(chan)) { + pll |= SM(0x2, AR_RTC_PLL_CLKSEL); + } + if (chan != AH_NULL && IS_CHAN_5GHZ(chan)) { + pll |= SM(0xa, AR_RTC_PLL_DIV); + } else { + pll |= SM(0xb, AR_RTC_PLL_DIV); + } + } + OS_REG_WRITE(ah, AR_RTC_PLL_CONTROL, pll); + + /* TODO: + * For multi-band owl, switch between bands by reiniting the PLL. + */ + + OS_DELAY(RTC_PLL_SETTLE_DELAY); + + OS_REG_WRITE(ah, AR_RTC_SLEEP_CLK, AR_RTC_SLEEP_DERIVED_CLK); +} + +/* + * Read EEPROM header info and program the device for correct operation + * given the channel value. + */ +static HAL_BOOL +ar5416SetBoardValues(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan) +{ + const HAL_EEPROM_v14 *ee = AH_PRIVATE(ah)->ah_eeprom; + const struct ar5416eeprom *eep = &ee->ee_base; + const MODAL_EEP_HEADER *pModal; + int i, regChainOffset; + uint8_t txRxAttenLocal; /* workaround for eeprom versions <= 14.2 */ + + HALASSERT(AH_PRIVATE(ah)->ah_eeversion >= AR_EEPROM_VER14_1); + pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]); + + txRxAttenLocal = IS_CHAN_2GHZ(chan) ? 23 : 44; /* workaround for eeprom versions <= 14.2 */ + + OS_REG_WRITE(ah, AR_PHY_SWITCH_COM, pModal->antCtrlCommon); + for (i = 0; i < AR5416_MAX_CHAINS; i++) { + if (AR_SREV_MERLIN(ah)) { + if (i >= 2) break; + } + if (AR_SREV_OWL_20_OR_LATER(ah) && + (AH5416(ah)->ah_rx_chainmask == 0x5 || + AH5416(ah)->ah_tx_chainmask == 0x5) && i != 0) { + /* Regs are swapped from chain 2 to 1 for 5416 2_0 with + * only chains 0 and 2 populated + */ + regChainOffset = (i == 1) ? 0x2000 : 0x1000; + } else { + regChainOffset = i * 0x1000; + } + + OS_REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset, pModal->antCtrlChain[i]); + OS_REG_WRITE(ah, AR_PHY_TIMING_CTRL4 + regChainOffset, + (OS_REG_READ(ah, AR_PHY_TIMING_CTRL4 + regChainOffset) & + ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) | + SM(pModal->iqCalICh[i], AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) | + SM(pModal->iqCalQCh[i], AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF)); + + /* + * Large signal upgrade. + * XXX update + */ + + if ((i == 0) || AR_SREV_OWL_20_OR_LATER(ah)) { + OS_REG_WRITE(ah, AR_PHY_RXGAIN + regChainOffset, + (OS_REG_READ(ah, AR_PHY_RXGAIN + regChainOffset) & ~AR_PHY_RXGAIN_TXRX_ATTEN) | + SM(IS_EEP_MINOR_V3(ah) ? pModal->txRxAttenCh[i] : txRxAttenLocal, + AR_PHY_RXGAIN_TXRX_ATTEN)); + + OS_REG_WRITE(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + (OS_REG_READ(ah, AR_PHY_GAIN_2GHZ + regChainOffset) & ~AR_PHY_GAIN_2GHZ_RXTX_MARGIN) | + SM(pModal->rxTxMarginCh[i], AR_PHY_GAIN_2GHZ_RXTX_MARGIN)); + } + } + + OS_REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH, pModal->switchSettling); + OS_REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_ADC, pModal->adcDesiredSize); + OS_REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_PGA, pModal->pgaDesiredSize); + OS_REG_WRITE(ah, AR_PHY_RF_CTL4, + SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF) + | SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAB_OFF) + | SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAA_ON) + | SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAB_ON)); + + OS_REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_A2_RX_ON, pModal->txEndToRxOn); + + if (AR_SREV_MERLIN_10_OR_LATER(ah)) { + OS_REG_RMW_FIELD(ah, AR_PHY_CCA, AR9280_PHY_CCA_THRESH62, + pModal->thresh62); + OS_REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, AR_PHY_EXT_CCA0_THRESH62, + pModal->thresh62); + } else { + OS_REG_RMW_FIELD(ah, AR_PHY_CCA, AR_PHY_CCA_THRESH62, + pModal->thresh62); + OS_REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, AR_PHY_EXT_CCA_THRESH62, + pModal->thresh62); + } + + /* Minor Version Specific application */ + if (IS_EEP_MINOR_V2(ah)) { + OS_REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_FRAME_TO_DATA_START, pModal->txFrameToDataStart); + OS_REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_FRAME_TO_PA_ON, pModal->txFrameToPaOn); + } + + if (IS_EEP_MINOR_V3(ah)) { + if (IS_CHAN_HT40(chan)) { + /* Overwrite switch settling with HT40 value */ + OS_REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH, pModal->swSettleHt40); + } + + if ((AR_SREV_OWL_20_OR_LATER(ah)) && + ( AH5416(ah)->ah_rx_chainmask == 0x5 || AH5416(ah)->ah_tx_chainmask == 0x5)){ + /* Reg Offsets are swapped for logical mapping */ + OS_REG_WRITE(ah, AR_PHY_GAIN_2GHZ + 0x1000, (OS_REG_READ(ah, AR_PHY_GAIN_2GHZ + 0x1000) & ~AR_PHY_GAIN_2GHZ_BSW_MARGIN) | + SM(pModal->bswMargin[2], AR_PHY_GAIN_2GHZ_BSW_MARGIN)); + OS_REG_WRITE(ah, AR_PHY_GAIN_2GHZ + 0x1000, (OS_REG_READ(ah, AR_PHY_GAIN_2GHZ + 0x1000) & ~AR_PHY_GAIN_2GHZ_BSW_ATTEN) | + SM(pModal->bswAtten[2], AR_PHY_GAIN_2GHZ_BSW_ATTEN)); + OS_REG_WRITE(ah, AR_PHY_GAIN_2GHZ + 0x2000, (OS_REG_READ(ah, AR_PHY_GAIN_2GHZ + 0x2000) & ~AR_PHY_GAIN_2GHZ_BSW_MARGIN) | + SM(pModal->bswMargin[1], AR_PHY_GAIN_2GHZ_BSW_MARGIN)); + OS_REG_WRITE(ah, AR_PHY_GAIN_2GHZ + 0x2000, (OS_REG_READ(ah, AR_PHY_GAIN_2GHZ + 0x2000) & ~AR_PHY_GAIN_2GHZ_BSW_ATTEN) | + SM(pModal->bswAtten[1], AR_PHY_GAIN_2GHZ_BSW_ATTEN)); + } else { + OS_REG_WRITE(ah, AR_PHY_GAIN_2GHZ + 0x1000, (OS_REG_READ(ah, AR_PHY_GAIN_2GHZ + 0x1000) & ~AR_PHY_GAIN_2GHZ_BSW_MARGIN) | + SM(pModal->bswMargin[1], AR_PHY_GAIN_2GHZ_BSW_MARGIN)); + OS_REG_WRITE(ah, AR_PHY_GAIN_2GHZ + 0x1000, (OS_REG_READ(ah, AR_PHY_GAIN_2GHZ + 0x1000) & ~AR_PHY_GAIN_2GHZ_BSW_ATTEN) | + SM(pModal->bswAtten[1], AR_PHY_GAIN_2GHZ_BSW_ATTEN)); + OS_REG_WRITE(ah, AR_PHY_GAIN_2GHZ + 0x2000, (OS_REG_READ(ah, AR_PHY_GAIN_2GHZ + 0x2000) & ~AR_PHY_GAIN_2GHZ_BSW_MARGIN) | + SM(pModal->bswMargin[2],AR_PHY_GAIN_2GHZ_BSW_MARGIN)); + OS_REG_WRITE(ah, AR_PHY_GAIN_2GHZ + 0x2000, (OS_REG_READ(ah, AR_PHY_GAIN_2GHZ + 0x2000) & ~AR_PHY_GAIN_2GHZ_BSW_ATTEN) | + SM(pModal->bswAtten[2], AR_PHY_GAIN_2GHZ_BSW_ATTEN)); + } + OS_REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ, AR_PHY_GAIN_2GHZ_BSW_MARGIN, pModal->bswMargin[0]); + OS_REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ, AR_PHY_GAIN_2GHZ_BSW_ATTEN, pModal->bswAtten[0]); + } + return AH_TRUE; +} + +/* + * Helper functions common for AP/CB/XB + */ + +/* + * ar5416SetPowerPerRateTable + * + * Sets the transmit power in the baseband for the given + * operating channel and mode. + */ +static HAL_BOOL +ar5416SetPowerPerRateTable(struct ath_hal *ah, struct ar5416eeprom *pEepData, + HAL_CHANNEL_INTERNAL *chan, + int16_t *ratesArray, uint16_t cfgCtl, + uint16_t AntennaReduction, + uint16_t twiceMaxRegulatoryPower, + uint16_t powerLimit) +{ +#define N(a) (sizeof(a)/sizeof(a[0])) +/* Local defines to distinguish between extension and control CTL's */ +#define EXT_ADDITIVE (0x8000) +#define CTL_11A_EXT (CTL_11A | EXT_ADDITIVE) +#define CTL_11G_EXT (CTL_11G | EXT_ADDITIVE) +#define CTL_11B_EXT (CTL_11B | EXT_ADDITIVE) + + uint16_t twiceMaxEdgePower = AR5416_MAX_RATE_POWER; + int i; + int16_t twiceLargestAntenna; + CAL_CTL_DATA *rep; + CAL_TARGET_POWER_LEG targetPowerOfdm, targetPowerCck = {0, {0, 0, 0, 0}}; + CAL_TARGET_POWER_LEG targetPowerOfdmExt = {0, {0, 0, 0, 0}}, targetPowerCckExt = {0, {0, 0, 0, 0}}; + CAL_TARGET_POWER_HT targetPowerHt20, targetPowerHt40 = {0, {0, 0, 0, 0}}; + int16_t scaledPower, minCtlPower; + +#define SUB_NUM_CTL_MODES_AT_5G_40 2 /* excluding HT40, EXT-OFDM */ +#define SUB_NUM_CTL_MODES_AT_2G_40 3 /* excluding HT40, EXT-OFDM, EXT-CCK */ + static const uint16_t ctlModesFor11a[] = { + CTL_11A, CTL_5GHT20, CTL_11A_EXT, CTL_5GHT40 + }; + static const uint16_t ctlModesFor11g[] = { + CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT, CTL_2GHT40 + }; + const uint16_t *pCtlMode; + uint16_t numCtlModes, ctlMode, freq; + CHAN_CENTERS centers; + + ar5416GetChannelCenters(ah, chan, ¢ers); + + /* Compute TxPower reduction due to Antenna Gain */ + + twiceLargestAntenna = AH_MAX(AH_MAX(pEepData->modalHeader[IS_CHAN_2GHZ(chan)].antennaGainCh[0], + pEepData->modalHeader[IS_CHAN_2GHZ(chan)].antennaGainCh[1]), + pEepData->modalHeader[IS_CHAN_2GHZ(chan)].antennaGainCh[2]); +#if 0 + /* Turn it back on if we need to calculate per chain antenna gain reduction */ + /* Use only if the expected gain > 6dbi */ + /* Chain 0 is always used */ + twiceLargestAntenna = pEepData->modalHeader[IS_CHAN_2GHZ(chan)].antennaGainCh[0]; + + /* Look at antenna gains of Chains 1 and 2 if the TX mask is set */ + if (ahp->ah_tx_chainmask & 0x2) + twiceLargestAntenna = AH_MAX(twiceLargestAntenna, + pEepData->modalHeader[IS_CHAN_2GHZ(chan)].antennaGainCh[1]); + + if (ahp->ah_tx_chainmask & 0x4) + twiceLargestAntenna = AH_MAX(twiceLargestAntenna, + pEepData->modalHeader[IS_CHAN_2GHZ(chan)].antennaGainCh[2]); +#endif + twiceLargestAntenna = (int16_t)AH_MIN((AntennaReduction) - twiceLargestAntenna, 0); + + /* XXX setup for 5212 use (really used?) */ + ath_hal_eepromSet(ah, + IS_CHAN_2GHZ(chan) ? AR_EEP_ANTGAINMAX_2 : AR_EEP_ANTGAINMAX_5, + twiceLargestAntenna); + + /* + * scaledPower is the minimum of the user input power level and + * the regulatory allowed power level + */ + scaledPower = AH_MIN(powerLimit, twiceMaxRegulatoryPower + twiceLargestAntenna); + + /* Reduce scaled Power by number of chains active to get to per chain tx power level */ + /* TODO: better value than these? */ + switch (owl_get_ntxchains(AH5416(ah)->ah_tx_chainmask)) { + case 1: + break; + case 2: + scaledPower -= pEepData->modalHeader[IS_CHAN_2GHZ(chan)].pwrDecreaseFor2Chain; + break; + case 3: + scaledPower -= pEepData->modalHeader[IS_CHAN_2GHZ(chan)].pwrDecreaseFor3Chain; + break; + default: + return AH_FALSE; /* Unsupported number of chains */ + } + + scaledPower = AH_MAX(0, scaledPower); + + /* Get target powers from EEPROM - our baseline for TX Power */ + if (IS_CHAN_2GHZ(chan)) { + /* Setup for CTL modes */ + numCtlModes = N(ctlModesFor11g) - SUB_NUM_CTL_MODES_AT_2G_40; /* CTL_11B, CTL_11G, CTL_2GHT20 */ + pCtlMode = ctlModesFor11g; + + ar5416GetTargetPowersLeg(ah, chan, pEepData->calTargetPowerCck, + AR5416_NUM_2G_CCK_TARGET_POWERS, &targetPowerCck, 4, AH_FALSE); + ar5416GetTargetPowersLeg(ah, chan, pEepData->calTargetPower2G, + AR5416_NUM_2G_20_TARGET_POWERS, &targetPowerOfdm, 4, AH_FALSE); + ar5416GetTargetPowers(ah, chan, pEepData->calTargetPower2GHT20, + AR5416_NUM_2G_20_TARGET_POWERS, &targetPowerHt20, 8, AH_FALSE); + + if (IS_CHAN_HT40(chan)) { + numCtlModes = N(ctlModesFor11g); /* All 2G CTL's */ + + ar5416GetTargetPowers(ah, chan, pEepData->calTargetPower2GHT40, + AR5416_NUM_2G_40_TARGET_POWERS, &targetPowerHt40, 8, AH_TRUE); + /* Get target powers for extension channels */ + ar5416GetTargetPowersLeg(ah, chan, pEepData->calTargetPowerCck, + AR5416_NUM_2G_CCK_TARGET_POWERS, &targetPowerCckExt, 4, AH_TRUE); + ar5416GetTargetPowersLeg(ah, chan, pEepData->calTargetPower2G, + AR5416_NUM_2G_20_TARGET_POWERS, &targetPowerOfdmExt, 4, AH_TRUE); + } + } else { + /* Setup for CTL modes */ + numCtlModes = N(ctlModesFor11a) - SUB_NUM_CTL_MODES_AT_5G_40; /* CTL_11A, CTL_5GHT20 */ + pCtlMode = ctlModesFor11a; + + ar5416GetTargetPowersLeg(ah, chan, pEepData->calTargetPower5G, + AR5416_NUM_5G_20_TARGET_POWERS, &targetPowerOfdm, 4, AH_FALSE); + ar5416GetTargetPowers(ah, chan, pEepData->calTargetPower5GHT20, + AR5416_NUM_5G_20_TARGET_POWERS, &targetPowerHt20, 8, AH_FALSE); + + if (IS_CHAN_HT40(chan)) { + numCtlModes = N(ctlModesFor11a); /* All 5G CTL's */ + + ar5416GetTargetPowers(ah, chan, pEepData->calTargetPower5GHT40, + AR5416_NUM_5G_40_TARGET_POWERS, &targetPowerHt40, 8, AH_TRUE); + ar5416GetTargetPowersLeg(ah, chan, pEepData->calTargetPower5G, + AR5416_NUM_5G_20_TARGET_POWERS, &targetPowerOfdmExt, 4, AH_TRUE); + } + } + + /* + * For MIMO, need to apply regulatory caps individually across dynamically + * running modes: CCK, OFDM, HT20, HT40 + * + * The outer loop walks through each possible applicable runtime mode. + * The inner loop walks through each ctlIndex entry in EEPROM. + * The ctl value is encoded as [7:4] == test group, [3:0] == test mode. + * + */ + for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) { + + HAL_BOOL isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) || + (pCtlMode[ctlMode] == CTL_2GHT40); + if (isHt40CtlMode) { + freq = centers.ctl_center; + } else if (pCtlMode[ctlMode] & EXT_ADDITIVE) { + freq = centers.ext_center; + } else { + freq = centers.ctl_center; + } + + /* walk through each CTL index stored in EEPROM */ + for (i = 0; (i < AR5416_NUM_CTLS) && pEepData->ctlIndex[i]; i++) { + uint16_t twiceMinEdgePower; + + /* compare test group from regulatory channel list with test mode from pCtlMode list */ + if ((((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) == pEepData->ctlIndex[i]) || + (((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) == + ((pEepData->ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL))) { + rep = &(pEepData->ctlData[i]); + twiceMinEdgePower = ar5416GetMaxEdgePower(freq, + rep->ctlEdges[owl_get_ntxchains(AH5416(ah)->ah_tx_chainmask) - 1], + IS_CHAN_2GHZ(chan)); + 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 { + /* specific */ + twiceMaxEdgePower = twiceMinEdgePower; + break; + } + } + } + minCtlPower = (uint8_t)AH_MIN(twiceMaxEdgePower, scaledPower); + /* Apply ctl mode to correct target power set */ + switch(pCtlMode[ctlMode]) { + case CTL_11B: + for (i = 0; i < N(targetPowerCck.tPow2x); i++) { + targetPowerCck.tPow2x[i] = (uint8_t)AH_MIN(targetPowerCck.tPow2x[i], minCtlPower); + } + break; + case CTL_11A: + case CTL_11G: + for (i = 0; i < N(targetPowerOfdm.tPow2x); i++) { + targetPowerOfdm.tPow2x[i] = (uint8_t)AH_MIN(targetPowerOfdm.tPow2x[i], minCtlPower); + } + break; + case CTL_5GHT20: + case CTL_2GHT20: + for (i = 0; i < N(targetPowerHt20.tPow2x); i++) { + targetPowerHt20.tPow2x[i] = (uint8_t)AH_MIN(targetPowerHt20.tPow2x[i], minCtlPower); + } + break; + case CTL_11B_EXT: + targetPowerCckExt.tPow2x[0] = (uint8_t)AH_MIN(targetPowerCckExt.tPow2x[0], minCtlPower); + break; + case CTL_11A_EXT: + case CTL_11G_EXT: + targetPowerOfdmExt.tPow2x[0] = (uint8_t)AH_MIN(targetPowerOfdmExt.tPow2x[0], minCtlPower); + break; + case CTL_5GHT40: + case CTL_2GHT40: + for (i = 0; i < N(targetPowerHt40.tPow2x); i++) { + targetPowerHt40.tPow2x[i] = (uint8_t)AH_MIN(targetPowerHt40.tPow2x[i], minCtlPower); + } + break; + default: + return AH_FALSE; + break; + } + } /* end ctl mode checking */ + + /* Set rates Array from collected data */ + ratesArray[rate6mb] = ratesArray[rate9mb] = ratesArray[rate12mb] = ratesArray[rate18mb] = ratesArray[rate24mb] = targetPowerOfdm.tPow2x[0]; + ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1]; + ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2]; + ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3]; + ratesArray[rateXr] = targetPowerOfdm.tPow2x[0]; + + for (i = 0; i < N(targetPowerHt20.tPow2x); i++) { + ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i]; + } + + if (IS_CHAN_2GHZ(chan)) { + ratesArray[rate1l] = targetPowerCck.tPow2x[0]; + ratesArray[rate2s] = ratesArray[rate2l] = targetPowerCck.tPow2x[1]; + ratesArray[rate5_5s] = ratesArray[rate5_5l] = targetPowerCck.tPow2x[2]; + ratesArray[rate11s] = ratesArray[rate11l] = targetPowerCck.tPow2x[3]; + } + if (IS_CHAN_HT40(chan)) { + for (i = 0; i < N(targetPowerHt40.tPow2x); i++) { + ratesArray[rateHt40_0 + i] = targetPowerHt40.tPow2x[i]; + } + ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0]; + ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0]; + ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0]; + if (IS_CHAN_2GHZ(chan)) { + ratesArray[rateExtCck] = targetPowerCckExt.tPow2x[0]; + } + } + return AH_TRUE; +#undef EXT_ADDITIVE +#undef CTL_11A_EXT +#undef CTL_11G_EXT +#undef CTL_11B_EXT +#undef SUB_NUM_CTL_MODES_AT_5G_40 +#undef SUB_NUM_CTL_MODES_AT_2G_40 +#undef N +} + +/************************************************************************** + * fbin2freq + * + * Get channel value from binary representation held in eeprom + * RETURNS: the frequency in MHz + */ +static uint16_t +fbin2freq(uint8_t fbin, HAL_BOOL is2GHz) +{ + /* + * Reserved value 0xFF provides an empty definition both as + * an fbin and as a frequency - do not convert + */ + if (fbin == AR5416_BCHAN_UNUSED) { + return fbin; + } + + return (uint16_t)((is2GHz) ? (2300 + fbin) : (4800 + 5 * fbin)); +} + +/* + * ar5416GetMaxEdgePower + * + * Find the maximum conformance test limit for the given channel and CTL info + */ +static uint16_t +ar5416GetMaxEdgePower(uint16_t freq, CAL_CTL_EDGES *pRdEdgesPower, HAL_BOOL is2GHz) +{ + uint16_t twiceMaxEdgePower = AR5416_MAX_RATE_POWER; + int i; + + /* Get the edge power */ + for (i = 0; (i < AR5416_NUM_BAND_EDGES) && (pRdEdgesPower[i].bChannel != AR5416_BCHAN_UNUSED) ; i++) { + /* + * If there's an exact channel match or an inband flag set + * on the lower channel use the given rdEdgePower + */ + if (freq == fbin2freq(pRdEdgesPower[i].bChannel, is2GHz)) { + twiceMaxEdgePower = MS(pRdEdgesPower[i].tPowerFlag, CAL_CTL_EDGES_POWER); + break; + } else if ((i > 0) && (freq < fbin2freq(pRdEdgesPower[i].bChannel, is2GHz))) { + if (fbin2freq(pRdEdgesPower[i - 1].bChannel, is2GHz) < freq && (pRdEdgesPower[i - 1].tPowerFlag & CAL_CTL_EDGES_FLAG) != 0) { + twiceMaxEdgePower = MS(pRdEdgesPower[i - 1].tPowerFlag, CAL_CTL_EDGES_POWER); + } + /* Leave loop - no more affecting edges possible in this monotonic increasing list */ + break; + } + } + HALASSERT(twiceMaxEdgePower > 0); + return twiceMaxEdgePower; +} + +/************************************************************** + * ar5416GetTargetPowers + * + * Return the rates of target power for the given target power table + * channel, and number of channels + */ +static void +ar5416GetTargetPowers(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan, + CAL_TARGET_POWER_HT *powInfo, uint16_t numChannels, + CAL_TARGET_POWER_HT *pNewPower, uint16_t numRates, + HAL_BOOL isHt40Target) +{ + uint16_t clo, chi; + int i; + int matchIndex = -1, lowIndex = -1; + uint16_t freq; + CHAN_CENTERS centers; + + ar5416GetChannelCenters(ah, chan, ¢ers); + freq = isHt40Target ? centers.synth_center : centers.ctl_center; + + /* Copy the target powers into the temp channel list */ + if (freq <= fbin2freq(powInfo[0].bChannel, IS_CHAN_2GHZ(chan))) { + matchIndex = 0; + } else { + for (i = 0; (i < numChannels) && (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) { + if (freq == fbin2freq(powInfo[i].bChannel, IS_CHAN_2GHZ(chan))) { + matchIndex = i; + break; + } else if ((freq < fbin2freq(powInfo[i].bChannel, IS_CHAN_2GHZ(chan))) && + (freq > fbin2freq(powInfo[i - 1].bChannel, IS_CHAN_2GHZ(chan)))) + { + lowIndex = i - 1; + break; + } + } + if ((matchIndex == -1) && (lowIndex == -1)) { + HALASSERT(freq > fbin2freq(powInfo[i - 1].bChannel, IS_CHAN_2GHZ(chan))); + matchIndex = i - 1; + } + } + + if (matchIndex != -1) { + OS_MEMCPY(pNewPower, &powInfo[matchIndex], sizeof(*pNewPower)); + } else { + HALASSERT(lowIndex != -1); + /* + * Get the lower and upper channels, target powers, + * and interpolate between them. + */ + clo = fbin2freq(powInfo[lowIndex].bChannel, IS_CHAN_2GHZ(chan)); + chi = fbin2freq(powInfo[lowIndex + 1].bChannel, IS_CHAN_2GHZ(chan)); + + for (i = 0; i < numRates; i++) { + pNewPower->tPow2x[i] = (uint8_t)interpolate(freq, clo, chi, + powInfo[lowIndex].tPow2x[i], powInfo[lowIndex + 1].tPow2x[i]); + } + } +} +/************************************************************** + * ar5416GetTargetPowersLeg + * + * Return the four rates of target power for the given target power table + * channel, and number of channels + */ +static void +ar5416GetTargetPowersLeg(struct ath_hal *ah, + HAL_CHANNEL_INTERNAL *chan, + CAL_TARGET_POWER_LEG *powInfo, uint16_t numChannels, + CAL_TARGET_POWER_LEG *pNewPower, uint16_t numRates, + HAL_BOOL isExtTarget) +{ + uint16_t clo, chi; + int i; + int matchIndex = -1, lowIndex = -1; + uint16_t freq; + CHAN_CENTERS centers; + + ar5416GetChannelCenters(ah, chan, ¢ers); + freq = (isExtTarget) ? centers.ext_center :centers.ctl_center; + + /* Copy the target powers into the temp channel list */ + if (freq <= fbin2freq(powInfo[0].bChannel, IS_CHAN_2GHZ(chan))) { + matchIndex = 0; + } else { + for (i = 0; (i < numChannels) && (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) { + if (freq == fbin2freq(powInfo[i].bChannel, IS_CHAN_2GHZ(chan))) { + matchIndex = i; + break; + } else if ((freq < fbin2freq(powInfo[i].bChannel, IS_CHAN_2GHZ(chan))) && + (freq > fbin2freq(powInfo[i - 1].bChannel, IS_CHAN_2GHZ(chan)))) + { + lowIndex = i - 1; + break; + } + } + if ((matchIndex == -1) && (lowIndex == -1)) { + HALASSERT(freq > fbin2freq(powInfo[i - 1].bChannel, IS_CHAN_2GHZ(chan))); + matchIndex = i - 1; + } + } + + if (matchIndex != -1) { + OS_MEMCPY(pNewPower, &powInfo[matchIndex], sizeof(*pNewPower)); + } else { + HALASSERT(lowIndex != -1); + /* + * Get the lower and upper channels, target powers, + * and interpolate between them. + */ + clo = fbin2freq(powInfo[lowIndex].bChannel, IS_CHAN_2GHZ(chan)); + chi = fbin2freq(powInfo[lowIndex + 1].bChannel, IS_CHAN_2GHZ(chan)); + + for (i = 0; i < numRates; i++) { + pNewPower->tPow2x[i] = (uint8_t)interpolate(freq, clo, chi, + powInfo[lowIndex].tPow2x[i], powInfo[lowIndex + 1].tPow2x[i]); + } + } +} + +/************************************************************** + * ar5416SetPowerCalTable + * + * Pull the PDADC piers from cal data and interpolate them across the given + * points as well as from the nearest pier(s) to get a power detector + * linear voltage to power level table. + */ +static HAL_BOOL +ar5416SetPowerCalTable(struct ath_hal *ah, struct ar5416eeprom *pEepData, HAL_CHANNEL_INTERNAL *chan, int16_t *pTxPowerIndexOffset) +{ + CAL_DATA_PER_FREQ *pRawDataset; + uint8_t *pCalBChans = AH_NULL; + uint16_t pdGainOverlap_t2; + static uint8_t pdadcValues[AR5416_NUM_PDADC_VALUES]; + uint16_t gainBoundaries[AR5416_PD_GAINS_IN_MASK]; + uint16_t numPiers, i, j; + int16_t tMinCalPower; + uint16_t numXpdGain, xpdMask; + uint16_t xpdGainValues[AR5416_NUM_PD_GAINS]; + uint32_t reg32, regOffset, regChainOffset; + + ath_hal_memzero(xpdGainValues, sizeof(xpdGainValues)); + + xpdMask = pEepData->modalHeader[IS_CHAN_2GHZ(chan)].xpdGain; + + if (IS_EEP_MINOR_V2(ah)) { + pdGainOverlap_t2 = pEepData->modalHeader[IS_CHAN_2GHZ(chan)].pdGainOverlap; + } else { + pdGainOverlap_t2 = (uint16_t)(MS(OS_REG_READ(ah, AR_PHY_TPCRG5), AR_PHY_TPCRG5_PD_GAIN_OVERLAP)); + } + + if (IS_CHAN_2GHZ(chan)) { + pCalBChans = pEepData->calFreqPier2G; + numPiers = AR5416_NUM_2G_CAL_PIERS; + } else { + pCalBChans = pEepData->calFreqPier5G; + numPiers = AR5416_NUM_5G_CAL_PIERS; + } + + numXpdGain = 0; + /* Calculate the value of xpdgains from the xpdGain Mask */ + for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) { + if ((xpdMask >> (AR5416_PD_GAINS_IN_MASK - i)) & 1) { + if (numXpdGain >= AR5416_NUM_PD_GAINS) { + HALASSERT(0); + break; + } + xpdGainValues[numXpdGain] = (uint16_t)(AR5416_PD_GAINS_IN_MASK - i); + numXpdGain++; + } + } + + /* Write the detector gain biases and their number */ + OS_REG_WRITE(ah, AR_PHY_TPCRG1, (OS_REG_READ(ah, AR_PHY_TPCRG1) & + ~(AR_PHY_TPCRG1_NUM_PD_GAIN | AR_PHY_TPCRG1_PD_GAIN_1 | AR_PHY_TPCRG1_PD_GAIN_2 | AR_PHY_TPCRG1_PD_GAIN_3)) | + SM(numXpdGain - 1, AR_PHY_TPCRG1_NUM_PD_GAIN) | SM(xpdGainValues[0], AR_PHY_TPCRG1_PD_GAIN_1 ) | + SM(xpdGainValues[1], AR_PHY_TPCRG1_PD_GAIN_2) | SM(xpdGainValues[2], AR_PHY_TPCRG1_PD_GAIN_3)); + + for (i = 0; i < AR5416_MAX_CHAINS; i++) { + + if (AR_SREV_OWL_20_OR_LATER(ah) && + ( AH5416(ah)->ah_rx_chainmask == 0x5 || AH5416(ah)->ah_tx_chainmask == 0x5) && (i != 0)) { + /* Regs are swapped from chain 2 to 1 for 5416 2_0 with + * only chains 0 and 2 populated + */ + regChainOffset = (i == 1) ? 0x2000 : 0x1000; + } else { + regChainOffset = i * 0x1000; + } + + if (pEepData->baseEepHeader.txMask & (1 << i)) { + if (IS_CHAN_2GHZ(chan)) { + pRawDataset = pEepData->calPierData2G[i]; + } else { + pRawDataset = pEepData->calPierData5G[i]; + } + + ar5416GetGainBoundariesAndPdadcs(ah, chan, pRawDataset, + pCalBChans, numPiers, + pdGainOverlap_t2, + &tMinCalPower, gainBoundaries, + pdadcValues, numXpdGain); + + if ((i == 0) || AR_SREV_OWL_20_OR_LATER(ah)) { + /* + * 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 + */ + + OS_REG_WRITE(ah, AR_PHY_TPCRG5 + regChainOffset, + 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)); + } + + /* Write the power values into the baseband power table */ + regOffset = AR_PHY_BASE + (672 << 2) + regChainOffset; + + for (j = 0; j < 32; j++) { + reg32 = ((pdadcValues[4*j + 0] & 0xFF) << 0) | + ((pdadcValues[4*j + 1] & 0xFF) << 8) | + ((pdadcValues[4*j + 2] & 0xFF) << 16) | + ((pdadcValues[4*j + 3] & 0xFF) << 24) ; + OS_REG_WRITE(ah, regOffset, reg32); + +#ifdef PDADC_DUMP + ath_hal_printf(ah, "PDADC: Chain %d | PDADC %3d Value %3d | PDADC %3d Value %3d | PDADC %3d Value %3d | PDADC %3d Value %3d |\n", + i, + 4*j, pdadcValues[4*j], + 4*j+1, pdadcValues[4*j + 1], + 4*j+2, pdadcValues[4*j + 2], + 4*j+3, pdadcValues[4*j + 3]); +#endif + regOffset += 4; + } + } + } + *pTxPowerIndexOffset = 0; + + return AH_TRUE; +} + +/************************************************************** + * ar5416GetGainBoundariesAndPdadcs + * + * Uses the data points read from EEPROM to reconstruct the pdadc power table + * Called by ar5416SetPowerCalTable only. + */ +static void +ar5416GetGainBoundariesAndPdadcs(struct ath_hal *ah, + HAL_CHANNEL_INTERNAL *chan, CAL_DATA_PER_FREQ *pRawDataSet, + uint8_t * bChans, uint16_t availPiers, + uint16_t tPdGainOverlap, int16_t *pMinCalPower, uint16_t * pPdGainBoundaries, + uint8_t * pPDADCValues, uint16_t numXpdGains) +{ + + int i, j, k; + int16_t ss; /* potentially -ve index for taking care of pdGainOverlap */ + uint16_t idxL = 0, idxR = 0, numPiers; /* Pier indexes */ + + /* filled out Vpd table for all pdGains (chanL) */ + static uint8_t vpdTableL[AR5416_NUM_PD_GAINS][AR5416_MAX_PWR_RANGE_IN_HALF_DB]; + + /* filled out Vpd table for all pdGains (chanR) */ + static uint8_t vpdTableR[AR5416_NUM_PD_GAINS][AR5416_MAX_PWR_RANGE_IN_HALF_DB]; + + /* filled out Vpd table for all pdGains (interpolated) */ + static uint8_t vpdTableI[AR5416_NUM_PD_GAINS][AR5416_MAX_PWR_RANGE_IN_HALF_DB]; + + uint8_t *pVpdL, *pVpdR, *pPwrL, *pPwrR; + uint8_t minPwrT4[AR5416_NUM_PD_GAINS]; + uint8_t maxPwrT4[AR5416_NUM_PD_GAINS]; + int16_t vpdStep; + int16_t tmpVal; + uint16_t sizeCurrVpdTable, maxIndex, tgtIndex; + HAL_BOOL match; + int16_t minDelta = 0; + CHAN_CENTERS centers; + + ar5416GetChannelCenters(ah, chan, ¢ers); + + /* Trim numPiers for the number of populated channel Piers */ + for (numPiers = 0; numPiers < availPiers; numPiers++) { + if (bChans[numPiers] == AR5416_BCHAN_UNUSED) { + break; + } + } + + /* Find pier indexes around the current channel */ + match = getLowerUpperIndex((uint8_t)FREQ2FBIN(centers.synth_center, IS_CHAN_2GHZ(chan)), + bChans, numPiers, &idxL, &idxR); + + if (match) { + /* Directly fill both vpd tables from the matching index */ + for (i = 0; i < numXpdGains; i++) { + minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0]; + maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4]; + ar5416FillVpdTable(minPwrT4[i], maxPwrT4[i], pRawDataSet[idxL].pwrPdg[i], + pRawDataSet[idxL].vpdPdg[i], AR5416_PD_GAIN_ICEPTS, vpdTableI[i]); + } + } else { + for (i = 0; i < numXpdGains; i++) { + pVpdL = pRawDataSet[idxL].vpdPdg[i]; + pPwrL = pRawDataSet[idxL].pwrPdg[i]; + pVpdR = pRawDataSet[idxR].vpdPdg[i]; + pPwrR = pRawDataSet[idxR].pwrPdg[i]; + + /* Start Vpd interpolation from the max of the minimum powers */ + minPwrT4[i] = AH_MAX(pPwrL[0], pPwrR[0]); + + /* End Vpd interpolation from the min of the max powers */ + maxPwrT4[i] = AH_MIN(pPwrL[AR5416_PD_GAIN_ICEPTS - 1], pPwrR[AR5416_PD_GAIN_ICEPTS - 1]); + HALASSERT(maxPwrT4[i] > minPwrT4[i]); + + /* Fill pier Vpds */ + ar5416FillVpdTable(minPwrT4[i], maxPwrT4[i], pPwrL, pVpdL, AR5416_PD_GAIN_ICEPTS, vpdTableL[i]); + ar5416FillVpdTable(minPwrT4[i], maxPwrT4[i], pPwrR, pVpdR, AR5416_PD_GAIN_ICEPTS, vpdTableR[i]); + + /* Interpolate the final vpd */ + for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) { + vpdTableI[i][j] = (uint8_t)(interpolate((uint16_t)FREQ2FBIN(centers.synth_center, IS_CHAN_2GHZ(chan)), + bChans[idxL], bChans[idxR], vpdTableL[i][j], vpdTableR[i][j])); + } + } + } + *pMinCalPower = (int16_t)(minPwrT4[0] / 2); + + k = 0; /* index for the final table */ + for (i = 0; i < numXpdGains; i++) { + if (i == (numXpdGains - 1)) { + pPdGainBoundaries[i] = (uint16_t)(maxPwrT4[i] / 2); + } else { + pPdGainBoundaries[i] = (uint16_t)((maxPwrT4[i] + minPwrT4[i+1]) / 4); + } + + pPdGainBoundaries[i] = (uint16_t)AH_MIN(AR5416_MAX_RATE_POWER, pPdGainBoundaries[i]); + + /* NB: only applies to owl 1.0 */ + if ((i == 0) && !AR_SREV_OWL_20_OR_LATER(ah) ) { + /* + * fix the gain delta, but get a delta that can be applied to min to + * keep the upper power values accurate, don't think max needs to + * be adjusted because should not be at that area of the table? + */ + minDelta = pPdGainBoundaries[0] - 23; + pPdGainBoundaries[0] = 23; + } + else { + minDelta = 0; + } + + /* Find starting index for this pdGain */ + if (i == 0) { + ss = 0; /* for the first pdGain, start from index 0 */ + } else { + /* need overlap entries extrapolated below. */ + ss = (int16_t)((pPdGainBoundaries[i-1] - (minPwrT4[i] / 2)) - tPdGainOverlap + 1 + minDelta); + } + vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]); + vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); + /* + *-ve ss indicates need to extrapolate data below for this pdGain + */ + while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { + tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep); + pPDADCValues[k++] = (uint8_t)((tmpVal < 0) ? 0 : tmpVal); + ss++; + } + + sizeCurrVpdTable = (uint8_t)((maxPwrT4[i] - minPwrT4[i]) / 2 +1); + tgtIndex = (uint8_t)(pPdGainBoundaries[i] + tPdGainOverlap - (minPwrT4[i] / 2)); + maxIndex = (tgtIndex < sizeCurrVpdTable) ? tgtIndex : sizeCurrVpdTable; + + while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { + pPDADCValues[k++] = vpdTableI[i][ss++]; + } + + vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] - vpdTableI[i][sizeCurrVpdTable - 2]); + vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); + /* + * for last gain, pdGainBoundary == Pmax_t2, so will + * have to extrapolate + */ + if (tgtIndex > maxIndex) { /* need to extrapolate above */ + while ((ss <= tgtIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { + tmpVal = (int16_t)((vpdTableI[i][sizeCurrVpdTable - 1] + + (ss - maxIndex +1) * vpdStep)); + pPDADCValues[k++] = (uint8_t)((tmpVal > 255) ? 255 : tmpVal); + ss++; + } + } /* extrapolated above */ + } /* for all pdGainUsed */ + + /* Fill out pdGainBoundaries - only up to 2 allowed here, but hardware allows up to 4 */ + while (i < AR5416_PD_GAINS_IN_MASK) { + pPdGainBoundaries[i] = pPdGainBoundaries[i-1]; + i++; + } + + while (k < AR5416_NUM_PDADC_VALUES) { + pPDADCValues[k] = pPDADCValues[k-1]; + k++; + } + return; +} + +/************************************************************** + * getLowerUppderIndex + * + * Return indices surrounding the value in sorted integer lists. + * Requirement: the input list must be monotonically increasing + * and populated up to the list size + * Returns: match is set if an index in the array matches exactly + * or a the target is before or after the range of the array. + */ +HAL_BOOL +getLowerUpperIndex(uint8_t target, uint8_t *pList, uint16_t listSize, + uint16_t *indexL, uint16_t *indexR) +{ + uint16_t i; + + /* + * Check first and last elements for beyond ordered array cases. + */ + if (target <= pList[0]) { + *indexL = *indexR = 0; + return AH_TRUE; + } + if (target >= pList[listSize-1]) { + *indexL = *indexR = (uint16_t)(listSize - 1); + return AH_TRUE; + } + + /* look for value being near or between 2 values in list */ + for (i = 0; i < listSize - 1; 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 (pList[i] == target) { + *indexL = *indexR = i; + return AH_TRUE; + } + /* + * Look for value being between current value and next value + * if so return these 2 values + */ + if (target < pList[i + 1]) { + *indexL = i; + *indexR = (uint16_t)(i + 1); + return AH_FALSE; + } + } + HALASSERT(0); + return AH_FALSE; +} + +/************************************************************** + * ar5416FillVpdTable + * + * Fill the Vpdlist for indices Pmax-Pmin + * Note: pwrMin, pwrMax and Vpdlist are all in dBm * 4 + */ +static HAL_BOOL +ar5416FillVpdTable(uint8_t pwrMin, uint8_t pwrMax, uint8_t *pPwrList, + uint8_t *pVpdList, uint16_t numIntercepts, uint8_t *pRetVpdList) +{ + uint16_t i, k; + uint8_t currPwr = pwrMin; + uint16_t idxL = 0, idxR = 0; + + HALASSERT(pwrMax > pwrMin); + for (i = 0; i <= (pwrMax - pwrMin) / 2; i++) { + getLowerUpperIndex(currPwr, pPwrList, numIntercepts, + &(idxL), &(idxR)); + if (idxR < 1) + idxR = 1; /* extrapolate below */ + if (idxL == numIntercepts - 1) + idxL = (uint16_t)(numIntercepts - 2); /* extrapolate above */ + if (pPwrList[idxL] == pPwrList[idxR]) + k = pVpdList[idxL]; + else + k = (uint16_t)( ((currPwr - pPwrList[idxL]) * pVpdList[idxR] + (pPwrList[idxR] - currPwr) * pVpdList[idxL]) / + (pPwrList[idxR] - pPwrList[idxL]) ); + HALASSERT(k < 256); + pRetVpdList[i] = (uint8_t)k; + currPwr += 2; /* half dB steps */ + } + + return AH_TRUE; +} + +/************************************************************************** + * interpolate + * + * Returns signed interpolated or the scaled up interpolated value + */ +static int16_t +interpolate(uint16_t target, uint16_t srcLeft, uint16_t srcRight, + int16_t targetLeft, int16_t targetRight) +{ + int16_t rv; + + if (srcRight == srcLeft) { + rv = targetLeft; + } else { + rv = (int16_t)( ((target - srcLeft) * targetRight + + (srcRight - target) * targetLeft) / (srcRight - srcLeft) ); + } + return rv; +} + +static void +ar5416Set11nRegs(struct ath_hal *ah, HAL_CHANNEL *chan) +{ + uint32_t phymode; + HAL_HT_MACMODE macmode; /* MAC - 20/40 mode */ + + if (!IS_CHAN_HT(chan)) + return; + + /* Enable 11n HT, 20 MHz */ + phymode = AR_PHY_FC_HT_EN | AR_PHY_FC_SHORT_GI_40 + | AR_PHY_FC_SINGLE_HT_LTF1 | AR_PHY_FC_WALSH; + + /* Configure baseband for dynamic 20/40 operation */ + if (IS_CHAN_HT40(chan)) { + phymode |= AR_PHY_FC_DYN2040_EN | AR_PHY_FC_SHORT_GI_40; + + /* Configure control (primary) channel at +-10MHz */ + if ((chan->channelFlags & CHANNEL_HT40PLUS)) + phymode |= AR_PHY_FC_DYN2040_PRI_CH; +#if 0 + /* Configure 20/25 spacing */ + if (ht->ht_extprotspacing == HAL_HT_EXTPROTSPACING_25) + phymode |= AR_PHY_FC_DYN2040_EXT_CH; +#endif + macmode = HAL_HT_MACMODE_2040; + } else + macmode = HAL_HT_MACMODE_20; + OS_REG_WRITE(ah, AR_PHY_TURBO, phymode); + + /* Configure MAC for 20/40 operation */ + ar5416Set11nMac2040(ah, macmode); + + /* global transmit timeout (25 TUs default)*/ + /* XXX - put this elsewhere??? */ + OS_REG_WRITE(ah, AR_GTXTO, 25 << AR_GTXTO_TIMEOUT_LIMIT_S) ; + + /* carrier sense timeout */ + OS_REG_SET_BIT(ah, AR_GTTM, AR_GTTM_CST_USEC); + OS_REG_WRITE(ah, AR_CST, 1 << AR_CST_TIMEOUT_LIMIT_S); +} + +void +ar5416GetChannelCenters(struct ath_hal *ah, + HAL_CHANNEL_INTERNAL *chan, CHAN_CENTERS *centers) +{ + centers->ctl_center = chan->channel; + centers->synth_center = chan->channel; + /* + * In 20/40 phy mode, the center frequency is + * "between" the control and extension channels. + */ + if (chan->channelFlags & CHANNEL_HT40PLUS) { + centers->synth_center += HT40_CHANNEL_CENTER_SHIFT; + centers->ext_center = + centers->synth_center + HT40_CHANNEL_CENTER_SHIFT; + } else if (chan->channelFlags & CHANNEL_HT40MINUS) { + centers->synth_center -= HT40_CHANNEL_CENTER_SHIFT; + centers->ext_center = + centers->synth_center - HT40_CHANNEL_CENTER_SHIFT; + } else { + centers->ext_center = chan->channel; + } +} --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5210/ar5416_xmit.c 2009-03-23 17:36:56.000000000 +0000 @@ -0,0 +1,698 @@ +/* + * 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: ar5416_xmit.c,v 1.1 2009/03/23 17:14:48 sborrill Exp $ + */ +#include "opt_ah.h" + +#include "ah.h" +#include "ah_desc.h" +#include "ah_internal.h" + +#include "ar5416/ar5416.h" +#include "ar5416/ar5416reg.h" +#include "ar5416/ar5416phy.h" +#include "ar5416/ar5416desc.h" + +/* + * Stop transmit on the specified queue + */ +HAL_BOOL +ar5416StopTxDma(struct ath_hal *ah, u_int q) +{ +#define STOP_DMA_TIMEOUT 4000 /* us */ +#define STOP_DMA_ITER 100 /* us */ + u_int i; + + 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 = STOP_DMA_TIMEOUT/STOP_DMA_ITER; i != 0; i--) { + if (ar5212NumTxPending(ah, q) == 0) + break; + OS_DELAY(STOP_DMA_ITER); + } +#ifdef AH_DEBUG + if (i == 0) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: queue %u DMA did not stop in 400 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 */ + + /* ar5416 and up can kill packets at the PCU level */ + if (ar5212NumTxPending(ah, q)) { + uint32_t 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++) { + uint32_t tsfLow = OS_REG_READ(ah, AR_TSF_L32); + OS_REG_WRITE(ah, AR_QUIET2, + SM(10, AR_QUIET2_QUIET_DUR)); + OS_REG_WRITE(ah, AR_QUIET_PERIOD, 100); + OS_REG_WRITE(ah, AR_NEXT_QUIET, tsfLow >> 10); + OS_REG_SET_BIT(ah, AR_TIMER_MODE, AR_TIMER_MODE_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_TIMER_MODE, AR_TIMER_MODE_QUIET); + + /* Verify the transmit q is empty */ + for (i = STOP_DMA_TIMEOUT/STOP_DMA_ITER; i != 0; i--) { + if (ar5212NumTxPending(ah, q) == 0) + break; + OS_DELAY(STOP_DMA_ITER); + } + if (i == 0) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: Failed to stop Tx DMA in %d msec after killing" + " last frame\n", __func__, STOP_DMA_TIMEOUT / 1000); + } + OS_REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_CHAN_IDLE); + } + + OS_REG_WRITE(ah, AR_Q_TXD, 0); + return (i != 0); +#undef STOP_DMA_ITER +#undef STOP_DMA_TIMEOUT +} + +#define VALID_KEY_TYPES \ + ((1 << HAL_KEY_TYPE_CLEAR) | (1 << HAL_KEY_TYPE_WEP)|\ + (1 << HAL_KEY_TYPE_AES) | (1 << HAL_KEY_TYPE_TKIP)) +#define isValidKeyType(_t) ((1 << (_t)) & VALID_KEY_TYPES) + +#define set11nTries(_series, _index) \ + (SM((_series)[_index].Tries, AR_XmitDataTries##_index)) + +#define set11nRate(_series, _index) \ + (SM((_series)[_index].Rate, AR_XmitRate##_index)) + +#define set11nPktDurRTSCTS(_series, _index) \ + (SM((_series)[_index].PktDuration, AR_PacketDur##_index) |\ + ((_series)[_index].RateFlags & HAL_RATESERIES_RTS_CTS ?\ + AR_RTSCTSQual##_index : 0)) + +#define set11nRateFlags(_series, _index) \ + ((_series)[_index].RateFlags & HAL_RATESERIES_2040 ? AR_2040_##_index : 0) \ + |((_series)[_index].RateFlags & HAL_RATESERIES_HALFGI ? AR_GI##_index : 0) \ + |SM((_series)[_index].ChSel, AR_ChainSel##_index) + +/* + * 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_ClrDestMask : 0) + | (flags & HAL_TXDESC_INTREQ ? AR_TxIntrReq : 0) + ; + ads->ds_ctl1 = (type << AR_FrameType_S) + | (flags & HAL_TXDESC_NOACK ? AR_NoAck : 0) + ; + ads->ds_ctl2 = SM(txTries0, AR_XmitDataTries0) + | (flags & HAL_TXDESC_DURENA ? AR_DurUpdateEn : 0) + ; + ads->ds_ctl3 = (txRate0 << AR_XmitRate0_S) + ; + ads->ds_ctl4 = 0; + ads->ds_ctl5 = 0; + ads->ds_ctl6 = 0; + ads->ds_ctl7 = SM(ahp->ah_tx_chainmask, AR_ChainSel0) + | SM(ahp->ah_tx_chainmask, AR_ChainSel1) + | SM(ahp->ah_tx_chainmask, AR_ChainSel2) + | SM(ahp->ah_tx_chainmask, AR_ChainSel3) + ; + ads->ds_ctl8 = 0; + ads->ds_ctl9 = (txPower << 24); /* XXX? */ + ads->ds_ctl10 = (txPower << 24); /* XXX? */ + ads->ds_ctl11 = (txPower << 24); /* XXX? */ + if (keyIx != HAL_TXKEYIX_INVALID) { + /* XXX validate key index */ + ads->ds_ctl1 |= SM(keyIx, AR_DestIdx); + ads->ds_ctl0 |= AR_DestIdxValid; + ads->ds_ctl6 |= SM(ahp->ah_keytype[keyIx], AR_EncrType); + } + 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_RTSEnable : 0) + ; + ads->ds_ctl2 |= SM(rtsctsDuration, AR_BurstDur); + ads->ds_ctl7 |= (rtsctsRate << AR_RTSCTSRate_S); + } + return AH_TRUE; +#undef RTSCTS +} + +HAL_BOOL +ar5416SetupXTxDesc(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 ar5416_desc *ads = AR5416DESC(ds); + + if (txTries1) { + HALASSERT(isValidTxRate(txRate1)); + ads->ds_ctl2 |= SM(txTries1, AR_XmitDataTries1); + ads->ds_ctl3 |= (txRate1 << AR_XmitRate1_S); + } + if (txTries2) { + HALASSERT(isValidTxRate(txRate2)); + ads->ds_ctl2 |= SM(txTries2, AR_XmitDataTries2); + ads->ds_ctl3 |= (txRate2 << AR_XmitRate2_S); + } + if (txTries3) { + HALASSERT(isValidTxRate(txRate3)); + ads->ds_ctl2 |= SM(txTries3, AR_XmitDataTries3); + ads->ds_ctl3 |= (txRate3 << AR_XmitRate3_S); + } + return AH_TRUE; +} + +HAL_BOOL +ar5416FillTxDesc(struct ath_hal *ah, struct ath_desc *ds, + u_int segLen, HAL_BOOL firstSeg, HAL_BOOL lastSeg, + const struct ath_desc *ds0) +{ + struct ar5416_desc *ads = AR5416DESC(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_TxMore); + } 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(AR5416DESC_CONST(ds0)->ds_ctl2); + ads->ds_ctl3 = __bswap32(AR5416DESC_CONST(ds0)->ds_ctl3); +#else + ads->ds_ctl2 = AR5416DESC_CONST(ds0)->ds_ctl2; + ads->ds_ctl3 = AR5416DESC_CONST(ds0)->ds_ctl3; +#endif + } else { /* !firstSeg && !lastSeg */ + /* + * Intermediate descriptor in a multi-descriptor frame. + */ + ads->ds_ctl0 = 0; + ads->ds_ctl1 = segLen | AR_TxMore; + ads->ds_ctl2 = 0; + ads->ds_ctl3 = 0; + } + /* XXX only on last descriptor? */ + OS_MEMZERO(ads->u.tx.status, sizeof(ads->u.tx.status)); + return AH_TRUE; +} + +#if 0 + +HAL_BOOL +ar5416ChainTxDesc(struct ath_hal *ah, struct ath_desc *ds, + u_int pktLen, + u_int hdrLen, + HAL_PKT_TYPE type, + u_int keyIx, + HAL_CIPHER cipher, + uint8_t delims, + u_int segLen, + HAL_BOOL firstSeg, + HAL_BOOL lastSeg) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + uint32_t *ds_txstatus = AR5416_DS_TXSTATUS(ah,ads); + + int isaggr = 0; + + (void) hdrLen; + (void) ah; + + HALASSERT((segLen &~ AR_BufLen) == 0); + + HALASSERT(isValidPktType(type)); + if (type == HAL_PKT_TYPE_AMPDU) { + type = HAL_PKT_TYPE_NORMAL; + isaggr = 1; + } + + if (!firstSeg) { + ath_hal_memzero(ds->ds_hw, AR5416_DESC_TX_CTL_SZ); + } + + ads->ds_ctl0 = (pktLen & AR_FrameLen); + ads->ds_ctl1 = (type << AR_FrameType_S) + | (isaggr ? (AR_IsAggr | AR_MoreAggr) : 0); + ads->ds_ctl2 = 0; + ads->ds_ctl3 = 0; + if (keyIx != HAL_TXKEYIX_INVALID) { + /* XXX validate key index */ + ads->ds_ctl1 |= SM(keyIx, AR_DestIdx); + ads->ds_ctl0 |= AR_DestIdxValid; + } + + ads->ds_ctl6 = SM(keyType[cipher], AR_EncrType); + if (isaggr) { + ads->ds_ctl6 |= SM(delims, AR_PadDelim); + } + + if (firstSeg) { + ads->ds_ctl1 |= segLen | (lastSeg ? 0 : AR_TxMore); + } else if (lastSeg) { /* !firstSeg && lastSeg */ + ads->ds_ctl0 = 0; + ads->ds_ctl1 |= segLen; + } else { /* !firstSeg && !lastSeg */ + /* + * Intermediate descriptor in a multi-descriptor frame. + */ + ads->ds_ctl0 = 0; + ads->ds_ctl1 |= segLen | AR_TxMore; + } + ds_txstatus[0] = ds_txstatus[1] = 0; + ds_txstatus[9] &= ~AR_TxDone; + + return AH_TRUE; +} + +HAL_BOOL +ar5416SetupFirstTxDesc(struct ath_hal *ah, struct ath_desc *ds, + u_int aggrLen, u_int flags, u_int txPower, + u_int txRate0, u_int txTries0, u_int antMode, + u_int rtsctsRate, u_int rtsctsDuration) +{ +#define RTSCTS (HAL_TXDESC_RTSENA|HAL_TXDESC_CTSENA) + struct ar5416_desc *ads = AR5416DESC(ds); + struct ath_hal_5212 *ahp = AH5212(ah); + + HALASSERT(txTries0 != 0); + HALASSERT(isValidTxRate(txRate0)); + HALASSERT((flags & RTSCTS) != RTSCTS); + /* XXX validate antMode */ + + txPower = (txPower + ahp->ah_txPowerIndexOffset ); + if(txPower > 63) txPower=63; + + ads->ds_ctl0 |= (txPower << AR_XmitPower_S) + | (flags & HAL_TXDESC_VEOL ? AR_VEOL : 0) + | (flags & HAL_TXDESC_CLRDMASK ? AR_ClrDestMask : 0) + | (flags & HAL_TXDESC_INTREQ ? AR_TxIntrReq : 0); + ads->ds_ctl1 |= (flags & HAL_TXDESC_NOACK ? AR_NoAck : 0); + ads->ds_ctl2 |= SM(txTries0, AR_XmitDataTries0); + ads->ds_ctl3 |= (txRate0 << AR_XmitRate0_S); + ads->ds_ctl7 = SM(AH5416(ah)->ah_tx_chainmask, AR_ChainSel0) + | SM(AH5416(ah)->ah_tx_chainmask, AR_ChainSel1) + | SM(AH5416(ah)->ah_tx_chainmask, AR_ChainSel2) + | SM(AH5416(ah)->ah_tx_chainmask, AR_ChainSel3); + + /* NB: no V1 WAR */ + ads->ds_ctl8 = 0; + ads->ds_ctl9 = (txPower << 24); + ads->ds_ctl10 = (txPower << 24); + ads->ds_ctl11 = (txPower << 24); + + ads->ds_ctl6 &= ~(0xffff); + ads->ds_ctl6 |= SM(aggrLen, AR_AggrLen); + + if (flags & RTSCTS) { + /* XXX validate rtsctsDuration */ + ads->ds_ctl0 |= (flags & HAL_TXDESC_CTSENA ? AR_CTSEnable : 0) + | (flags & HAL_TXDESC_RTSENA ? AR_RTSEnable : 0); + ads->ds_ctl2 |= SM(rtsctsDuration, AR_BurstDur); + } + + return AH_TRUE; +#undef RTSCTS +} + +HAL_BOOL +ar5416SetupLastTxDesc(struct ath_hal *ah, struct ath_desc *ds, + const struct ath_desc *ds0) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + + ads->ds_ctl1 &= ~AR_MoreAggr; + ads->ds_ctl6 &= ~AR_PadDelim; + + /* hack to copy rate info to last desc for later processing */ +#ifdef AH_NEED_DESC_SWAP + ads->ds_ctl2 = __bswap32(AR5416DESC_CONST(ds0)->ds_ctl2); + ads->ds_ctl3 = __bswap32(AR5416DESC_CONST(ds0)->ds_ctl3); +#else + ads->ds_ctl2 = AR5416DESC_CONST(ds0)->ds_ctl2; + ads->ds_ctl3 = AR5416DESC_CONST(ds0)->ds_ctl3; +#endif + + return AH_TRUE; +} +#endif /* 0 */ + +#ifdef AH_NEED_DESC_SWAP +/* Swap transmit descriptor */ +static __inline void +ar5416SwapTxDesc(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 +ar5416ProcTxDesc(struct ath_hal *ah, + struct ath_desc *ds, struct ath_tx_status *ts) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + uint32_t *ds_txstatus = AR5416_DS_TXSTATUS(ah,ads); + +#ifdef AH_NEED_DESC_SWAP + if ((ds_txstatus[9] & __bswap32(AR_TxDone)) == 0) + return HAL_EINPROGRESS; + ar5416SwapTxDesc(ds); +#else + if ((ds_txstatus[9] & AR_TxDone) == 0) + return HAL_EINPROGRESS; +#endif + + /* Update software copies of the HW status */ + ts->ts_seqnum = MS(ds_txstatus[9], AR_SeqNum); + ts->ts_tstamp = AR_SendTimestamp(ds_txstatus); + + ts->ts_status = 0; + if (ds_txstatus[1] & AR_ExcessiveRetries) + ts->ts_status |= HAL_TXERR_XRETRY; + if (ds_txstatus[1] & AR_Filtered) + ts->ts_status |= HAL_TXERR_FILT; + if (ds_txstatus[1] & AR_FIFOUnderrun) + ts->ts_status |= HAL_TXERR_FIFO; + if (ds_txstatus[9] & AR_TxOpExceeded) + ts->ts_status |= HAL_TXERR_XTXOP; + if (ds_txstatus[1] & AR_TxTimerExpired) + ts->ts_status |= HAL_TXERR_TIMER_EXPIRED; + + ts->ts_flags = 0; + if (ds_txstatus[0] & AR_TxBaStatus) { + ts->ts_flags |= HAL_TX_BA; + ts->ts_ba_low = AR_BaBitmapLow(ds_txstatus); + ts->ts_ba_high = AR_BaBitmapHigh(ds_txstatus); + } + if (ds->ds_ctl1 & AR_IsAggr) + ts->ts_flags |= HAL_TX_AGGR; + if (ds_txstatus[1] & AR_DescCfgErr) + ts->ts_flags |= HAL_TX_DESC_CFG_ERR; + if (ds_txstatus[1] & AR_TxDataUnderrun) + ts->ts_flags |= HAL_TX_DATA_UNDERRUN; + if (ds_txstatus[1] & AR_TxDelimUnderrun) + ts->ts_flags |= HAL_TX_DELIM_UNDERRUN; + + /* + * Extract the transmit rate used and mark the rate as + * ``alternate'' if it wasn't the series 0 rate. + */ + ts->ts_finaltsi = MS(ds_txstatus[9], AR_FinalTxIdx); + 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(ds_txstatus[5], AR_TxRSSICombined); + ts->ts_rssi_ctl[0] = MS(ds_txstatus[0], AR_TxRSSIAnt00); + ts->ts_rssi_ctl[1] = MS(ds_txstatus[0], AR_TxRSSIAnt01); + ts->ts_rssi_ctl[2] = MS(ds_txstatus[0], AR_TxRSSIAnt02); + ts->ts_rssi_ext[0] = MS(ds_txstatus[5], AR_TxRSSIAnt10); + ts->ts_rssi_ext[1] = MS(ds_txstatus[5], AR_TxRSSIAnt11); + ts->ts_rssi_ext[2] = MS(ds_txstatus[5], AR_TxRSSIAnt12); + ts->ts_evm0 = AR_TxEVM0(ds_txstatus); + ts->ts_evm1 = AR_TxEVM1(ds_txstatus); + ts->ts_evm2 = AR_TxEVM2(ds_txstatus); + + ts->ts_shortretry = MS(ds_txstatus[1], AR_RTSFailCnt); + ts->ts_longretry = MS(ds_txstatus[1], 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); + } + + /* + * These fields are not used. Zero these to preserve compatability + * with existing drivers. + */ + ts->ts_virtcol = MS(ads->ds_ctl1, AR_VirtRetryCnt); + ts->ts_antenna = 0; /* We don't switch antennas on Owl*/ + + /* handle tx trigger level changes internally */ + if ((ts->ts_status & HAL_TXERR_FIFO) || + (ts->ts_flags & (HAL_TX_DATA_UNDERRUN | HAL_TX_DELIM_UNDERRUN))) + ar5212UpdateTxTrigLevel(ah, AH_TRUE); + + return HAL_OK; +} + +#if 0 +HAL_BOOL +ar5416SetGlobalTxTimeout(struct ath_hal *ah, u_int tu) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + + if (tu > 0xFFFF) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad global tx timeout %u\n", + __func__, tu); + /* restore default handling */ + ahp->ah_globaltxtimeout = (u_int) -1; + return AH_FALSE; + } + OS_REG_RMW_FIELD(ah, AR_GTXTO, AR_GTXTO_TIMEOUT_LIMIT, tu); + ahp->ah_globaltxtimeout = tu; + return AH_TRUE; +} + +u_int +ar5416GetGlobalTxTimeout(struct ath_hal *ah) +{ + return MS(OS_REG_READ(ah, AR_GTXTO), AR_GTXTO_TIMEOUT_LIMIT); +} + +void +ar5416Set11nRateScenario(struct ath_hal *ah, struct ath_desc *ds, + u_int durUpdateEn, u_int rtsctsRate, + HAL_11N_RATE_SERIES series[], u_int nseries) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + + HALASSERT(nseries == 4); + (void)nseries; + + + ads->ds_ctl2 = set11nTries(series, 0) + | set11nTries(series, 1) + | set11nTries(series, 2) + | set11nTries(series, 3) + | (durUpdateEn ? AR_DurUpdateEn : 0); + + ads->ds_ctl3 = set11nRate(series, 0) + | set11nRate(series, 1) + | set11nRate(series, 2) + | set11nRate(series, 3); + + ads->ds_ctl4 = set11nPktDurRTSCTS(series, 0) + | set11nPktDurRTSCTS(series, 1); + + ads->ds_ctl5 = set11nPktDurRTSCTS(series, 2) + | set11nPktDurRTSCTS(series, 3); + + ads->ds_ctl7 = set11nRateFlags(series, 0) + | set11nRateFlags(series, 1) + | set11nRateFlags(series, 2) + | set11nRateFlags(series, 3) + | SM(rtsctsRate, AR_RTSCTSRate); + + /* + * Enable RTSCTS if any of the series is flagged for RTSCTS, + * but only if CTS is not enabled. + */ + /* + * FIXME : the entire RTS/CTS handling should be moved to this + * function (by passing the global RTS/CTS flags to this function). + * currently it is split between this function and the + * setupFiirstDescriptor. with this current implementation there + * is an implicit assumption that setupFirstDescriptor is called + * before this function. + */ + if (((series[0].RateFlags & HAL_RATESERIES_RTS_CTS) || + (series[1].RateFlags & HAL_RATESERIES_RTS_CTS) || + (series[2].RateFlags & HAL_RATESERIES_RTS_CTS) || + (series[3].RateFlags & HAL_RATESERIES_RTS_CTS) ) && + (ads->ds_ctl0 & AR_CTSEnable) == 0) { + ads->ds_ctl0 |= AR_RTSEnable; + ads->ds_ctl0 &= ~AR_CTSEnable; + } +} + +void +ar5416Set11nAggrMiddle(struct ath_hal *ah, struct ath_desc *ds, u_int numDelims) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + uint32_t *ds_txstatus = AR5416_DS_TXSTATUS(ah,ads); + + ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr); + + ads->ds_ctl6 &= ~AR_PadDelim; + ads->ds_ctl6 |= SM(numDelims, AR_PadDelim); + ads->ds_ctl6 &= ~AR_AggrLen; + + /* + * Clear the TxDone status here, may need to change + * func name to reflect this + */ + ds_txstatus[9] &= ~AR_TxDone; +} + +void +ar5416Clr11nAggr(struct ath_hal *ah, struct ath_desc *ds) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + + ads->ds_ctl1 &= (~AR_IsAggr & ~AR_MoreAggr); + ads->ds_ctl6 &= ~AR_PadDelim; + ads->ds_ctl6 &= ~AR_AggrLen; +} + +void +ar5416Set11nBurstDuration(struct ath_hal *ah, struct ath_desc *ds, + u_int burstDuration) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + + ads->ds_ctl2 &= ~AR_BurstDur; + ads->ds_ctl2 |= SM(burstDuration, AR_BurstDur); +} +#endif --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5210/ar5416desc.h 2009-03-23 17:36:56.000000000 +0000 @@ -0,0 +1,397 @@ +/* + * 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: ar5416desc.h,v 1.1 2009/03/23 17:14:48 sborrill Exp $ + */ +#ifndef _ATH_AR5416_DESC_H_ +#define _ATH_AR5416_DESC_H + +/* + * Hardware-specific descriptor structures. + */ +#include "ah_desc.h" + +/* XXX Need to replace this with a dynamic + * method of determining Owl2 if possible + */ +#define _get_index(_ah) ( IS_5416V1(_ah) ? -4 : 0 ) +#define AR5416_DS_TXSTATUS(_ah, _ads) \ + ((uint32_t*)(&(_ads)->u.tx.status[_get_index(_ah)])) +#define AR5416_DS_TXSTATUS_CONST(_ah, _ads) \ + ((const uint32_t*)(&(_ads)->u.tx.status[_get_index(_ah)])) + +#define AR5416_NUM_TX_STATUS 10 /* Number of TX status words */ +/* Clear the whole descriptor */ +#define AR5416_DESC_TX_CTL_SZ sizeof(struct ar5416_tx_desc) + +struct ar5416_tx_desc { /* tx desc has 12 control words + 10 status words */ + uint32_t ctl2; + uint32_t ctl3; + uint32_t ctl4; + uint32_t ctl5; + uint32_t ctl6; + uint32_t ctl7; + uint32_t ctl8; + uint32_t ctl9; + uint32_t ctl10; + uint32_t ctl11; + uint32_t status[AR5416_NUM_TX_STATUS]; +}; + +struct ar5416_rx_desc { /* rx desc has 2 control words + 9 status words */ + uint32_t status0; + uint32_t status1; + uint32_t status2; + uint32_t status3; + uint32_t status4; + uint32_t status5; + uint32_t status6; + uint32_t status7; + uint32_t status8; +}; + + +struct ar5416_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 ar5416_tx_desc tx; + struct ar5416_rx_desc rx; + } u; +} __packed; +#define AR5416DESC(_ds) ((struct ar5416_desc *)(_ds)) +#define AR5416DESC_CONST(_ds) ((const struct ar5416_desc *)(_ds)) + +#define ds_ctl2 u.tx.ctl2 +#define ds_ctl3 u.tx.ctl3 +#define ds_ctl4 u.tx.ctl4 +#define ds_ctl5 u.tx.ctl5 +#define ds_ctl6 u.tx.ctl6 +#define ds_ctl7 u.tx.ctl7 +#define ds_ctl8 u.tx.ctl8 +#define ds_ctl9 u.tx.ctl9 +#define ds_ctl10 u.tx.ctl10 +#define ds_ctl11 u.tx.ctl11 + +#define ds_rxstatus0 u.rx.status0 +#define ds_rxstatus1 u.rx.status1 +#define ds_rxstatus2 u.rx.status2 +#define ds_rxstatus3 u.rx.status3 +#define ds_rxstatus4 u.rx.status4 +#define ds_rxstatus5 u.rx.status5 +#define ds_rxstatus6 u.rx.status6 +#define ds_rxstatus7 u.rx.status7 +#define ds_rxstatus8 u.rx.status8 + +/*********** + * TX Desc * + ***********/ + +/* ds_ctl0 */ +#define AR_FrameLen 0x00000fff +#define AR_VirtMoreFrag 0x00001000 +#define AR_TxCtlRsvd00 0x0000e000 +#define AR_XmitPower 0x003f0000 +#define AR_XmitPower_S 16 +#define AR_RTSEnable 0x00400000 +#define AR_VEOL 0x00800000 +#define AR_ClrDestMask 0x01000000 +#define AR_TxCtlRsvd01 0x1e000000 +#define AR_TxIntrReq 0x20000000 +#define AR_DestIdxValid 0x40000000 +#define AR_CTSEnable 0x80000000 + +/* ds_ctl1 */ +#define AR_BufLen 0x00000fff +#define AR_TxMore 0x00001000 +#define AR_DestIdx 0x000fe000 +#define AR_DestIdx_S 13 +#define AR_FrameType 0x00f00000 +#define AR_FrameType_S 20 +#define AR_NoAck 0x01000000 +#define AR_InsertTS 0x02000000 +#define AR_CorruptFCS 0x04000000 +#define AR_ExtOnly 0x08000000 +#define AR_ExtAndCtl 0x10000000 +#define AR_MoreAggr 0x20000000 +#define AR_IsAggr 0x40000000 +#define AR_MoreRifs 0x80000000 + +/* ds_ctl2 */ +#define AR_BurstDur 0x00007fff +#define AR_BurstDur_S 0 +#define AR_DurUpdateEn 0x00008000 +#define AR_XmitDataTries0 0x000f0000 +#define AR_XmitDataTries0_S 16 +#define AR_XmitDataTries1 0x00f00000 +#define AR_XmitDataTries1_S 20 +#define AR_XmitDataTries2 0x0f000000 +#define AR_XmitDataTries2_S 24 +#define AR_XmitDataTries3 0xf0000000 +#define AR_XmitDataTries3_S 28 + +/* ds_ctl3 */ +#define AR_XmitRate0 0x000000ff +#define AR_XmitRate0_S 0 +#define AR_XmitRate1 0x0000ff00 +#define AR_XmitRate1_S 8 +#define AR_XmitRate2 0x00ff0000 +#define AR_XmitRate2_S 16 +#define AR_XmitRate3 0xff000000 +#define AR_XmitRate3_S 24 + +/* ds_ctl4 */ +#define AR_PacketDur0 0x00007fff +#define AR_PacketDur0_S 0 +#define AR_RTSCTSQual0 0x00008000 +#define AR_PacketDur1 0x7fff0000 +#define AR_PacketDur1_S 16 +#define AR_RTSCTSQual1 0x80000000 + +/* ds_ctl5 */ +#define AR_PacketDur2 0x00007fff +#define AR_PacketDur2_S 0 +#define AR_RTSCTSQual2 0x00008000 +#define AR_PacketDur3 0x7fff0000 +#define AR_PacketDur3_S 16 +#define AR_RTSCTSQual3 0x80000000 + +/* ds_ctl6 */ +#define AR_AggrLen 0x0000ffff +#define AR_AggrLen_S 0 +#define AR_TxCtlRsvd60 0x00030000 +#define AR_PadDelim 0x03fc0000 +#define AR_PadDelim_S 18 +#define AR_EncrType 0x0c000000 +#define AR_EncrType_S 26 +#define AR_TxCtlRsvd61 0xf0000000 + +/* ds_ctl7 */ +#define AR_2040_0 0x00000001 +#define AR_GI0 0x00000002 +#define AR_ChainSel0 0x0000001c +#define AR_ChainSel0_S 2 +#define AR_2040_1 0x00000020 +#define AR_GI1 0x00000040 +#define AR_ChainSel1 0x00000380 +#define AR_ChainSel1_S 7 +#define AR_2040_2 0x00000400 +#define AR_GI2 0x00000800 +#define AR_ChainSel2 0x00007000 +#define AR_ChainSel2_S 12 +#define AR_2040_3 0x00008000 +#define AR_GI3 0x00010000 +#define AR_ChainSel3 0x000e0000 +#define AR_ChainSel3_S 17 +#define AR_RTSCTSRate 0x0ff00000 +#define AR_RTSCTSRate_S 20 +#define AR_STBC0 0x10000000 +#define AR_STBC1 0x20000000 +#define AR_STBC2 0x40000000 +#define AR_STBC3 0x80000000 + +/************* + * TX Status * + *************/ + +/* ds_status0 */ +#define AR_TxRSSIAnt00 0x000000ff +#define AR_TxRSSIAnt00_S 0 +#define AR_TxRSSIAnt01 0x0000ff00 +#define AR_TxRSSIAnt01_S 8 +#define AR_TxRSSIAnt02 0x00ff0000 +#define AR_TxRSSIAnt02_S 16 +#define AR_TxStatusRsvd00 0x3f000000 +#define AR_TxBaStatus 0x40000000 +#define AR_TxStatusRsvd01 0x80000000 + +/* ds_status1 */ +#define AR_FrmXmitOK 0x00000001 +#define AR_ExcessiveRetries 0x00000002 +#define AR_FIFOUnderrun 0x00000004 +#define AR_Filtered 0x00000008 +#define AR_RTSFailCnt 0x000000f0 +#define AR_RTSFailCnt_S 4 +#define AR_DataFailCnt 0x00000f00 +#define AR_DataFailCnt_S 8 +#define AR_VirtRetryCnt 0x0000f000 +#define AR_VirtRetryCnt_S 12 +#define AR_TxDelimUnderrun 0x00010000 +#define AR_TxDelimUnderrun_S 13 +#define AR_TxDataUnderrun 0x00020000 +#define AR_TxDataUnderrun_S 14 +#define AR_DescCfgErr 0x00040000 +#define AR_DescCfgErr_S 15 +#define AR_TxTimerExpired 0x00080000 +#define AR_TxStatusRsvd10 0xfff00000 + +/* ds_status2 */ +#define AR_SendTimestamp(_ptr) (_ptr)[2] + +/* ds_status3 */ +#define AR_BaBitmapLow(_ptr) (_ptr)[3] + +/* ds_status4 */ +#define AR_BaBitmapHigh(_ptr) (_ptr)[4] + +/* ds_status5 */ +#define AR_TxRSSIAnt10 0x000000ff +#define AR_TxRSSIAnt10_S 0 +#define AR_TxRSSIAnt11 0x0000ff00 +#define AR_TxRSSIAnt11_S 8 +#define AR_TxRSSIAnt12 0x00ff0000 +#define AR_TxRSSIAnt12_S 16 +#define AR_TxRSSICombined 0xff000000 +#define AR_TxRSSICombined_S 24 + +/* ds_status6 */ +#define AR_TxEVM0(_ptr) (_ptr)[6] + +/* ds_status7 */ +#define AR_TxEVM1(_ptr) (_ptr)[7] + +/* ds_status8 */ +#define AR_TxEVM2(_ptr) (_ptr)[8] + +/* ds_status9 */ +#define AR_TxDone 0x00000001 +#define AR_SeqNum 0x00001ffe +#define AR_SeqNum_S 1 +#define AR_TxStatusRsvd80 0x0001e000 +#define AR_TxOpExceeded 0x00020000 +#define AR_TxStatusRsvd81 0x001c0000 +#define AR_FinalTxIdx 0x00600000 +#define AR_FinalTxIdx_S 21 +#define AR_TxStatusRsvd82 0x01800000 +#define AR_PowerMgmt 0x02000000 +#define AR_TxStatusRsvd83 0xfc000000 + +/*********** + * RX Desc * + ***********/ + +/* ds_ctl0 */ +#define AR_RxCTLRsvd00 0xffffffff + +/* ds_ctl1 */ +#define AR_BufLen 0x00000fff +#define AR_RxCtlRsvd00 0x00001000 +#define AR_RxIntrReq 0x00002000 +#define AR_RxCtlRsvd01 0xffffc000 + +/************* + * Rx Status * + *************/ + +/* ds_status0 */ +#define AR_RxRSSIAnt00 0x000000ff +#define AR_RxRSSIAnt00_S 0 +#define AR_RxRSSIAnt01 0x0000ff00 +#define AR_RxRSSIAnt01_S 8 +#define AR_RxRSSIAnt02 0x00ff0000 +#define AR_RxRSSIAnt02_S 16 +/* Rev specific */ +/* Owl 1.x only */ +#define AR_RxStatusRsvd00 0xff000000 +/* Owl 2.x only */ +#define AR_RxRate 0xff000000 +#define AR_RxRate_S 24 + +/* ds_status1 */ +#define AR_DataLen 0x00000fff +#define AR_RxMore 0x00001000 +#define AR_NumDelim 0x003fc000 +#define AR_NumDelim_S 14 +#define AR_RxStatusRsvd10 0xff800000 + +/* ds_status2 */ +#define AR_RcvTimestamp ds_rxstatus2 + +/* ds_status3 */ +#define AR_GI 0x00000001 +#define AR_2040 0x00000002 +/* Rev specific */ +/* Owl 1.x only */ +#define AR_RxRateV1 0x000003fc +#define AR_RxRateV1_S 2 +#define AR_Parallel40 0x00000400 +#define AR_RxStatusRsvd30 0xfffff800 +/* Owl 2.x only */ +#define AR_DupFrame 0x00000004 +#define AR_RxAntenna 0xffffff00 +#define AR_RxAntenna_S 8 + +/* ds_status4 */ +#define AR_RxRSSIAnt10 0x000000ff +#define AR_RxRSSIAnt10_S 0 +#define AR_RxRSSIAnt11 0x0000ff00 +#define AR_RxRSSIAnt11_S 8 +#define AR_RxRSSIAnt12 0x00ff0000 +#define AR_RxRSSIAnt12_S 16 +#define AR_RxRSSICombined 0xff000000 +#define AR_RxRSSICombined_S 24 + +/* ds_status5 */ +#define AR_RxEVM0 ds_rxstatus5 + +/* ds_status6 */ +#define AR_RxEVM1 ds_rxstatus6 + +/* ds_status7 */ +#define AR_RxEVM2 ds_rxstatus7 + +/* ds_status8 */ +#define AR_RxDone 0x00000001 +#define AR_RxFrameOK 0x00000002 +#define AR_CRCErr 0x00000004 +#define AR_DecryptCRCErr 0x00000008 +#define AR_PHYErr 0x00000010 +#define AR_MichaelErr 0x00000020 +#define AR_PreDelimCRCErr 0x00000040 +#define AR_RxStatusRsvd70 0x00000080 +#define AR_RxKeyIdxValid 0x00000100 +#define AR_KeyIdx 0x0000fe00 +#define AR_KeyIdx_S 9 +#define AR_PHYErrCode 0x0000ff00 +#define AR_PHYErrCode_S 8 +#define AR_RxMoreAggr 0x00010000 +#define AR_RxAggr 0x00020000 +#define AR_PostDelimCRCErr 0x00040000 +#define AR_RxStatusRsvd71 0x2ff80000 +#define AR_HiRxChain 0x10000000 +#define AR_DecryptBusyErr 0x40000000 +#define AR_KeyMiss 0x80000000 + +#define TXCTL_OFFSET(ah) 2 +#define TXCTL_NUMWORDS(ah) (AR_SREV_5416_V20_OR_LATER(ah) ? 12 : 8) +#define TXSTATUS_OFFSET(ah) (AR_SREV_5416_V20_OR_LATER(ah) ? 14 : 10) +#define TXSTATUS_NUMWORDS(ah) 10 + +#define RXCTL_OFFSET(ah) 3 +#define RXCTL_NUMWORDS(ah) 1 +#define RXSTATUS_OFFSET(ah) 4 +#define RXSTATUS_NUMWORDS(ah) 9 +#define RXSTATUS_RATE(ah, ads) \ + (AR_SREV_OWL_20_OR_LATER(ah) ? \ + MS((ads)->ds_rxstatus0, AR_RxRate) : \ + ((ads)->ds_rxstatus3 >> 2) & 0xFF) +#define RXSTATUS_DUPLICATE(ah, ads) \ + (AR_SREV_OWL_20_OR_LATER(ah) ? \ + MS((ads)->ds_rxstatus3, AR_Parallel40) : \ + ((ads)->ds_rxstatus3 >> 10) & 0x1) +#endif /* _ATH_AR5416_DESC_H_ */ --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5210/ar5416phy.h 2009-03-23 17:36:56.000000000 +0000 @@ -0,0 +1,250 @@ +/* + * 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: ar5416phy.h,v 1.1 2009/03/23 17:14:48 sborrill Exp $ + */ +#ifndef _DEV_ATH_AR5416PHY_H_ +#define _DEV_ATH_AR5416PHY_H_ + +#include "ar5212/ar5212phy.h" + +#define AR_PHY_CHIP_ID_REV_0 0x80 /* 5416 Rev 0 (owl 1.0) BB */ +#define AR_PHY_CHIP_ID_REV_1 0x81 /* 5416 Rev 1 (owl 2.0) BB */ + +#define RFSILENT_BB 0x00002000 /* shush bb */ +#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 + +/* PLL settling times */ +#define RTC_PLL_SETTLE_DELAY 1000 /* 1 ms */ +#define HT40_CHANNEL_CENTER_SHIFT 10 /* MHz */ + +#define AR_PHY_RFBUS_REQ 0x997C +#define AR_PHY_RFBUS_REQ_EN 0x00000001 + +#define AR_2040_MODE 0x8318 +#define AR_2040_JOINED_RX_CLEAR 0x00000001 // use ctl + ext rx_clear for cca + +#define AR_PHY_FC_TURBO_SHORT 0x00000002 /* Set short symbols to turbo mode setting */ +#define AR_PHY_FC_DYN2040_EN 0x00000004 /* Enable dyn 20/40 mode */ +#define AR_PHY_FC_DYN2040_PRI_ONLY 0x00000008 /* dyn 20/40 - primary only */ +#define AR_PHY_FC_DYN2040_PRI_CH 0x00000010 /* dyn 20/40 - primary ch offset (0=+10MHz, 1=-10MHz)*/ +#define AR_PHY_FC_DYN2040_EXT_CH 0x00000020 /* dyn 20/40 - ext ch spacing (0=20MHz/ 1=25MHz) */ +#define AR_PHY_FC_HT_EN 0x00000040 /* ht enable */ +#define AR_PHY_FC_SHORT_GI_40 0x00000080 /* allow short GI for HT 40 */ +#define AR_PHY_FC_WALSH 0x00000100 /* walsh spatial spreading for 2 chains,2 streams TX */ +#define AR_PHY_FC_SINGLE_HT_LTF1 0x00000200 /* single length (4us) 1st HT long training symbol */ + +#define AR_PHY_TIMING2 0x9810 /* Timing Control 2 */ +#define AR_PHY_TIMING2_USE_FORCE 0x00001000 +#define AR_PHY_TIMING2_FORCE_VAL 0x00000fff + +#define AR_PHY_TIMING_CTRL4_CHAIN(_i) \ + (AR_PHY_TIMING_CTRL4 + ((_i) << 12)) +#define AR_PHY_TIMING_CTRL4_DO_CAL 0x10000 /* perform calibration */ +#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_ENABLE_SPUR_RSSI 0x80000000 +#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_ADC_SERIAL_CTL 0x9830 +#define AR_PHY_SEL_INTERNAL_ADDAC 0x00000000 +#define AR_PHY_SEL_EXTERNAL_RADIO 0x00000001 + +#define AR_PHY_GAIN_2GHZ_BSW_MARGIN 0x00003C00 +#define AR_PHY_GAIN_2GHZ_BSW_MARGIN_S 10 +#define AR_PHY_GAIN_2GHZ_BSW_ATTEN 0x0000001F +#define AR_PHY_GAIN_2GHZ_BSW_ATTEN_S 0 + +#define AR_PHY_EXT_CCA 0x99bc +#define AR_PHY_EXT_CCA_CYCPWR_THR1 0x0000FE00 +#define AR_PHY_EXT_CCA_CYCPWR_THR1_S 9 +#define AR_PHY_EXT_MINCCA_PWR 0xFF800000 +#define AR_PHY_EXT_MINCCA_PWR_S 23 +#define AR_PHY_EXT_CCA_THRESH62 0x007F0000 +#define AR_PHY_EXT_CCA_THRESH62_S 16 +#define AR9280_PHY_EXT_MINCCA_PWR 0x01FF0000 +#define AR9280_PHY_EXT_MINCCA_PWR_S 16 + +#define AR_PHY_HALFGI 0x99D0 /* Timing control 3 */ +#define AR_PHY_HALFGI_DSC_MAN 0x0007FFF0 +#define AR_PHY_HALFGI_DSC_MAN_S 4 +#define AR_PHY_HALFGI_DSC_EXP 0x0000000F +#define AR_PHY_HALFGI_DSC_EXP_S 0 + +#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 + +#define AR_PHY_CALMODE 0x99f0 +/* Calibration Types */ +#define AR_PHY_CALMODE_IQ 0x00000000 +#define AR_PHY_CALMODE_ADC_GAIN 0x00000001 +#define AR_PHY_CALMODE_ADC_DC_PER 0x00000002 +#define AR_PHY_CALMODE_ADC_DC_INIT 0x00000003 +/* Calibration results */ +#define AR_PHY_CAL_MEAS_0(_i) (0x9c10 + ((_i) << 12)) +#define AR_PHY_CAL_MEAS_1(_i) (0x9c14 + ((_i) << 12)) +#define AR_PHY_CAL_MEAS_2(_i) (0x9c18 + ((_i) << 12)) +#define AR_PHY_CAL_MEAS_3(_i) (0x9c1c + ((_i) << 12)) + + +#define AR_PHY_CCA 0x9864 +#define AR_PHY_MINCCA_PWR 0x0FF80000 +#define AR_PHY_MINCCA_PWR_S 19 +#define AR9280_PHY_MINCCA_PWR 0x1FF00000 +#define AR9280_PHY_MINCCA_PWR_S 20 +#define AR9280_PHY_CCA_THRESH62 0x000FF000 +#define AR9280_PHY_CCA_THRESH62_S 12 + +#define AR_PHY_CH1_CCA 0xa864 +#define AR_PHY_CH1_MINCCA_PWR 0x0FF80000 +#define AR_PHY_CH1_MINCCA_PWR_S 19 +#define AR_PHY_CCA_THRESH62 0x0007F000 +#define AR_PHY_CCA_THRESH62_S 12 +#define AR9280_PHY_CH1_MINCCA_PWR 0x1FF00000 +#define AR9280_PHY_CH1_MINCCA_PWR_S 20 + +#define AR_PHY_CH2_CCA 0xb864 +#define AR_PHY_CH2_MINCCA_PWR 0x0FF80000 +#define AR_PHY_CH2_MINCCA_PWR_S 19 + +#define AR_PHY_CH1_EXT_CCA 0xa9bc +#define AR_PHY_CH1_EXT_MINCCA_PWR 0xFF800000 +#define AR_PHY_CH1_EXT_MINCCA_PWR_S 23 +#define AR9280_PHY_CH1_EXT_MINCCA_PWR 0x01FF0000 +#define AR9280_PHY_CH1_EXT_MINCCA_PWR_S 16 + +#define AR_PHY_CH2_EXT_CCA 0xb9bc +#define AR_PHY_CH2_EXT_MINCCA_PWR 0xFF800000 +#define AR_PHY_CH2_EXT_MINCCA_PWR_S 23 + +#define AR_PHY_RX_CHAINMASK 0x99a4 + +#define AR_PHY_NEW_ADC_DC_GAIN_CORR(_i) (0x99b4 + ((_i) << 12)) +#define AR_PHY_NEW_ADC_GAIN_CORR_ENABLE 0x40000000 +#define AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE 0x80000000 +#define AR_PHY_MULTICHAIN_GAIN_CTL 0x99ac + +#define AR_PHY_EXT_CCA0 0x99b8 +#define AR_PHY_EXT_CCA0_THRESH62 0x000000FF +#define AR_PHY_EXT_CCA0_THRESH62_S 0 + +#define AR_PHY_CH1_EXT_CCA 0xa9bc +#define AR_PHY_CH1_EXT_MINCCA_PWR 0xFF800000 +#define AR_PHY_CH1_EXT_MINCCA_PWR_S 23 + +#define AR_PHY_CH2_EXT_CCA 0xb9bc +#define AR_PHY_CH2_EXT_MINCCA_PWR 0xFF800000 +#define AR_PHY_CH2_EXT_MINCCA_PWR_S 23 +#define AR_PHY_ANALOG_SWAP 0xa268 +#define AR_PHY_SWAP_ALT_CHAIN 0x00000040 +#define AR_PHY_CAL_CHAINMASK 0xa39c + +#define AR_PHY_SWITCH_CHAIN_0 0x9960 +#define AR_PHY_SWITCH_COM 0x9964 + +#define AR_PHY_RF_CTL2 0x9824 +#define AR_PHY_TX_FRAME_TO_DATA_START 0x000000FF +#define AR_PHY_TX_FRAME_TO_DATA_START_S 0 +#define AR_PHY_TX_FRAME_TO_PA_ON 0x0000FF00 +#define AR_PHY_TX_FRAME_TO_PA_ON_S 8 + +#define AR_PHY_RF_CTL3 0x9828 +#define AR_PHY_TX_END_TO_A2_RX_ON 0x00FF0000 +#define AR_PHY_TX_END_TO_A2_RX_ON_S 16 + +#define AR_PHY_RF_CTL4 0x9834 +#define AR_PHY_RF_CTL4_TX_END_XPAB_OFF 0xFF000000 +#define AR_PHY_RF_CTL4_TX_END_XPAB_OFF_S 24 +#define AR_PHY_RF_CTL4_TX_END_XPAA_OFF 0x00FF0000 +#define AR_PHY_RF_CTL4_TX_END_XPAA_OFF_S 16 +#define AR_PHY_RF_CTL4_FRAME_XPAB_ON 0x0000FF00 +#define AR_PHY_RF_CTL4_FRAME_XPAB_ON_S 8 +#define AR_PHY_RF_CTL4_FRAME_XPAA_ON 0x000000FF +#define AR_PHY_RF_CTL4_FRAME_XPAA_ON_S 0 + +#define AR_PHY_SYNTH_CONTROL 0x9874 + +#define AR_PHY_FORCE_CLKEN_CCK 0xA22C +#define AR_PHY_FORCE_CLKEN_CCK_MRC_MUX 0x00000040 + +#define AR_PHY_POWER_TX_SUB 0xA3C8 +#define AR_PHY_POWER_TX_RATE5 0xA38C +#define AR_PHY_POWER_TX_RATE6 0xA390 +#define AR_PHY_POWER_TX_RATE7 0xA3CC +#define AR_PHY_POWER_TX_RATE8 0xA3D0 +#define AR_PHY_POWER_TX_RATE9 0xA3D4 + +#define AR_PHY_TPCRG1_PD_GAIN_1 0x00030000 +#define AR_PHY_TPCRG1_PD_GAIN_1_S 16 +#define AR_PHY_TPCRG1_PD_GAIN_2 0x000C0000 +#define AR_PHY_TPCRG1_PD_GAIN_2_S 18 +#define AR_PHY_TPCRG1_PD_GAIN_3 0x00300000 +#define AR_PHY_TPCRG1_PD_GAIN_3_S 20 + +#define AR_PHY_VIT_MASK2_M_46_61 0xa3a0 +#define AR_PHY_MASK2_M_31_45 0xa3a4 +#define AR_PHY_MASK2_M_16_30 0xa3a8 +#define AR_PHY_MASK2_M_00_15 0xa3ac +#define AR_PHY_MASK2_P_15_01 0xa3b8 +#define AR_PHY_MASK2_P_30_16 0xa3bc +#define AR_PHY_MASK2_P_45_31 0xa3c0 +#define AR_PHY_MASK2_P_61_45 0xa3c4 + +#define AR_PHY_SPUR_REG 0x994c +#define AR_PHY_SFCORR_EXT 0x99c0 +#define AR_PHY_SFCORR_EXT_M1_THRESH 0x0000007F +#define AR_PHY_SFCORR_EXT_M1_THRESH_S 0 +#define AR_PHY_SFCORR_EXT_M2_THRESH 0x00003F80 +#define AR_PHY_SFCORR_EXT_M2_THRESH_S 7 +#define AR_PHY_SFCORR_EXT_M1_THRESH_LOW 0x001FC000 +#define AR_PHY_SFCORR_EXT_M1_THRESH_LOW_S 14 +#define AR_PHY_SFCORR_EXT_M2_THRESH_LOW 0x0FE00000 +#define AR_PHY_SFCORR_EXT_M2_THRESH_LOW_S 21 +#define AR_PHY_SFCORR_SPUR_SUBCHNL_SD_S 28 + +/* enable vit puncture per rate, 8 bits, lsb is low rate */ +#define AR_PHY_SPUR_REG_MASK_RATE_CNTL (0xFF << 18) +#define AR_PHY_SPUR_REG_MASK_RATE_CNTL_S 18 + +#define AR_PHY_SPUR_REG_ENABLE_MASK_PPM 0x20000 /* bins move with freq offset */ +#define AR_PHY_SPUR_REG_MASK_RATE_SELECT (0xFF << 9) /* use mask1 or mask2, one per rate */ +#define AR_PHY_SPUR_REG_MASK_RATE_SELECT_S 9 +#define AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI 0x100 +#define AR_PHY_SPUR_REG_SPUR_RSSI_THRESH 0x7F +#define AR_PHY_SPUR_REG_SPUR_RSSI_THRESH_S 0 + +#define AR_PHY_PILOT_MASK_01_30 0xa3b0 +#define AR_PHY_PILOT_MASK_31_60 0xa3b4 + +#define AR_PHY_CHANNEL_MASK_01_30 0x99d4 +#define AR_PHY_CHANNEL_MASK_31_60 0x99d8 + +#define AR_PHY_CL_CAL_CTL 0xA358 /* carrier leak cal control */ +#define AR_PHY_CL_CAL_ENABLE 0x00000002 +#endif /* _DEV_ATH_AR5416PHY_H_ */ --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5210/ar5416reg.h 2009-03-23 17:36:56.000000000 +0000 @@ -0,0 +1,506 @@ +/* + * 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: ar5416reg.h,v 1.1 2009/03/23 17:14:48 sborrill Exp $ + */ +#ifndef _DEV_ATH_AR5416REG_H +#define _DEV_ATH_AR5416REG_H + +#include "ar5212/ar5212reg.h" + +/* + * Register added starting with the AR5416 + */ +#define AR_MIRT 0x0020 /* interrupt rate threshold */ +#define AR_TIMT 0x0028 /* Tx Interrupt mitigation threshold */ +#define AR_RIMT 0x002C /* Rx Interrupt mitigation threshold */ +#define AR_GTXTO 0x0064 /* global transmit timeout */ +#define AR_GTTM 0x0068 /* global transmit timeout mode */ +#define AR_CST 0x006C /* carrier sense timeout */ +#define AR_MAC_LED 0x1f04 /* LED control */ +#define AR5416_PCIE_PM_CTRL 0x4014 +#define AR_AHB_MODE 0x4024 /* AHB mode for dma */ +#define AR_INTR_SYNC_CAUSE_CLR 0x4028 /* clear interrupt */ +#define AR_INTR_SYNC_CAUSE 0x4028 /* check pending interrupts */ +#define AR_INTR_SYNC_ENABLE 0x402c /* enable interrupts */ +#define AR_INTR_ASYNC_MASK 0x4030 /* asynchronous interrupt mask */ +#define AR_INTR_SYNC_MASK 0x4034 /* synchronous interrupt mask */ +#define AR_INTR_ASYNC_CAUSE 0x4038 /* check pending interrupts */ +#define AR_INTR_ASYNC_ENABLE 0x403c /* enable interrupts */ +#define AR5416_PCIE_SERDES 0x4040 +#define AR5416_PCIE_SERDES2 0x4044 +#define AR_GPIO_IN 0x4048 /* GPIO input register */ +#define AR_GPIO_INTR_OUT 0x404c /* GPIO output register */ +#define AR_EEPROM_STATUS_DATA 0x407c +#define AR_OBS 0x4080 +#define AR_RTC_RC 0x7000 /* reset control */ +#define AR_RTC_PLL_CONTROL 0x7014 +#define AR_RTC_RESET 0x7040 /* RTC reset register */ +#define AR_RTC_STATUS 0x7044 /* system sleep status */ +#define AR_RTC_SLEEP_CLK 0x7048 +#define AR_RTC_FORCE_WAKE 0x704c /* control MAC force wake */ +#define AR_RTC_INTR_CAUSE 0x7050 /* RTC interrupt cause/clear */ +#define AR_RTC_INTR_ENABLE 0x7054 /* RTC interrupt enable */ +#define AR_RTC_INTR_MASK 0x7058 /* RTC interrupt mask */ +/* AR9280: rf long shift registers */ +#define AR_AN_RF2G1_CH0 0x7810 +#define AR_AN_RF5G1_CH0 0x7818 +#define AR_AN_RF2G1_CH1 0x7834 +#define AR_AN_RF5G1_CH1 0x783C +#define AR_AN_TOP2 0x7894 +#define AR_AN_SYNTH9 0x7868 +#define AR9285_AN_RF2G3 0x7828 +#define AR9285_AN_TOP3 0x786c +#define AR_RESET_TSF 0x8020 +#define AR_RXFIFO_CFG 0x8114 +#define AR_PHY_ERR_1 0x812c +#define AR_PHY_ERR_MASK_1 0x8130 /* mask for AR_PHY_ERR_1 */ +#define AR_PHY_ERR_2 0x8134 +#define AR_PHY_ERR_MASK_2 0x8138 /* mask for AR_PHY_ERR_2 */ +#define AR_TSFOOR_THRESHOLD 0x813c +#define AR_PHY_ERR_3 0x8168 +#define AR_PHY_ERR_MASK_3 0x816c /* mask for AR_PHY_ERR_3 */ +#define AR_TXOP_X 0x81ec /* txop for legacy non-qos */ +#define AR_TXOP_0_3 0x81f0 /* txop for various tid's */ +#define AR_TXOP_4_7 0x81f4 +#define AR_TXOP_8_11 0x81f8 +#define AR_TXOP_12_15 0x81fc +/* generic timers based on tsf - all uS */ +#define AR_NEXT_TBTT 0x8200 +#define AR_NEXT_DBA 0x8204 +#define AR_NEXT_SWBA 0x8208 +#define AR_NEXT_CFP 0x8208 +#define AR_NEXT_HCF 0x820C +#define AR_NEXT_TIM 0x8210 +#define AR_NEXT_DTIM 0x8214 +#define AR_NEXT_QUIET 0x8218 +#define AR_NEXT_NDP 0x821C +#define AR5416_BEACON_PERIOD 0x8220 +#define AR_DBA_PERIOD 0x8224 +#define AR_SWBA_PERIOD 0x8228 +#define AR_HCF_PERIOD 0x822C +#define AR_TIM_PERIOD 0x8230 +#define AR_DTIM_PERIOD 0x8234 +#define AR_QUIET_PERIOD 0x8238 +#define AR_NDP_PERIOD 0x823C +#define AR_TIMER_MODE 0x8240 +#define AR_SLP32_MODE 0x8244 +#define AR_SLP32_WAKE 0x8248 +#define AR_SLP32_INC 0x824c +#define AR_SLP_CNT 0x8250 /* 32kHz cycles with mac asleep */ +#define AR_SLP_CYCLE_CNT 0x8254 /* absolute number of 32kHz cycles */ +#define AR_SLP_MIB_CTRL 0x8258 +#define AR_2040_MODE 0x8318 +#define AR_EXTRCCNT 0x8328 /* extension channel rx clear count */ +#define AR_SELFGEN_MASK 0x832c /* rx and cal chain masks */ +#define AR_PCU_TXBUF_CTRL 0x8340 + +/* DMA & PCI Registers in PCI space (usable during sleep)*/ +#define AR_RC_AHB 0x00000001 /* AHB reset */ +#define AR_RC_APB 0x00000002 /* APB reset */ +#define AR_RC_HOSTIF 0x00000100 /* host interface reset */ + +#define AR_MIRT_VAL 0x0000ffff /* in uS */ +#define AR_MIRT_VAL_S 16 + +#define AR_TIMT_LAST 0x0000ffff /* Last packet threshold */ +#define AR_TIMT_LAST_S 0 +#define AR_TIMT_FIRST 0xffff0000 /* First packet threshold */ +#define AR_TIMT_FIRST_S 16 + +#define AR_RIMT_LAST 0x0000ffff /* Last packet threshold */ +#define AR_RIMT_LAST_S 0 +#define AR_RIMT_FIRST 0xffff0000 /* First packet threshold */ +#define AR_RIMT_FIRST_S 16 + +#define AR_GTXTO_TIMEOUT_COUNTER 0x0000FFFF // Mask for timeout counter (in TUs) +#define AR_GTXTO_TIMEOUT_LIMIT 0xFFFF0000 // Mask for timeout limit (in TUs) +#define AR_GTXTO_TIMEOUT_LIMIT_S 16 // Shift for timeout limit + +#define AR_GTTM_USEC 0x00000001 // usec strobe +#define AR_GTTM_IGNORE_IDLE 0x00000002 // ignore channel idle +#define AR_GTTM_RESET_IDLE 0x00000004 // reset counter on channel idle low +#define AR_GTTM_CST_USEC 0x00000008 // CST usec strobe + +#define AR_CST_TIMEOUT_COUNTER 0x0000FFFF // Mask for timeout counter (in TUs) +#define AR_CST_TIMEOUT_LIMIT 0xFFFF0000 // Mask for timeout limit (in TUs) +#define AR_CST_TIMEOUT_LIMIT_S 16 // Shift for timeout limit + +/* MAC tx DMA size config */ +#define AR_TXCFG_DMASZ_MASK 0x00000003 +#define AR_TXCFG_DMASZ_4B 0 +#define AR_TXCFG_DMASZ_8B 1 +#define AR_TXCFG_DMASZ_16B 2 +#define AR_TXCFG_DMASZ_32B 3 +#define AR_TXCFG_DMASZ_64B 4 +#define AR_TXCFG_DMASZ_128B 5 +#define AR_TXCFG_DMASZ_256B 6 +#define AR_TXCFG_DMASZ_512B 7 +#define AR_TXCFG_ATIM_TXPOLICY 0x00000800 + +/* MAC rx DMA size config */ +#define AR_RXCFG_DMASZ_MASK 0x00000007 +#define AR_RXCFG_DMASZ_4B 0 +#define AR_RXCFG_DMASZ_8B 1 +#define AR_RXCFG_DMASZ_16B 2 +#define AR_RXCFG_DMASZ_32B 3 +#define AR_RXCFG_DMASZ_64B 4 +#define AR_RXCFG_DMASZ_128B 5 +#define AR_RXCFG_DMASZ_256B 6 +#define AR_RXCFG_DMASZ_512B 7 + +/* MAC Led registers */ +#define AR_MAC_LED_BLINK_SLOW 0x00000008 /* LED slowest blink rate mode */ +#define AR_MAC_LED_BLINK_THRESH_SEL 0x00000070 /* LED blink threshold select */ +#define AR_MAC_LED_MODE 0x00000380 /* LED mode select */ +#define AR_MAC_LED_MODE_S 7 +#define AR_MAC_LED_MODE_PROP 0 /* Blink prop to filtered tx/rx */ +#define AR_MAC_LED_MODE_RPROP 1 /* Blink prop to unfiltered tx/rx */ +#define AR_MAC_LED_MODE_SPLIT 2 /* Blink power for tx/net for rx */ +#define AR_MAC_LED_MODE_RAND 3 /* Blink randomly */ +#define AR_MAC_LED_MODE_POWON 5 /* Power LED on (s/w control) */ +#define AR_MAC_LED_MODE_NETON 6 /* Network LED on (s/w control) */ +#define AR_MAC_LED_ASSOC 0x00000c00 +#define AR_MAC_LED_ASSOC_NONE 0x00000000 /* STA is not associated or trying */ +#define AR_MAC_LED_ASSOC_ACTIVE 0x00000400 /* STA is associated */ +#define AR_MAC_LED_ASSOC_PEND 0x00000800 /* STA is trying to associate */ +#define AR_MAC_LED_ASSOC_S 10 + +#define AR_AHB_EXACT_WR_EN 0x00000000 /* write exact bytes */ +#define AR_AHB_BUF_WR_EN 0x00000001 /* buffer write upto cacheline*/ +#define AR_AHB_EXACT_RD_EN 0x00000000 /* read exact bytes */ +#define AR_AHB_CACHELINE_RD_EN 0x00000002 /* read upto end of cacheline */ +#define AR_AHB_PREFETCH_RD_EN 0x00000004 /* prefetch upto page boundary*/ +#define AR_AHB_PAGE_SIZE_1K 0x00000000 /* set page-size as 1k */ +#define AR_AHB_PAGE_SIZE_2K 0x00000008 /* set page-size as 2k */ +#define AR_AHB_PAGE_SIZE_4K 0x00000010 /* set page-size as 4k */ + +/* MAC PCU Registers */ +#define AR_STA_ID1_PRESERVE_SEQNUM 0x20000000 /* Don't replace seq num */ + +/* Extended PCU DIAG_SW control fields */ +#define AR_DIAG_DUAL_CHAIN_INFO 0x01000000 /* dual chain channel info */ +#define AR_DIAG_RX_ABORT 0x02000000 /* abort rx */ +#define AR_DIAG_SATURATE_CCNT 0x04000000 /* sat. cycle cnts (no shift) */ +#define AR_DIAG_OBS_PT_SEL2 0x08000000 /* observation point sel */ +#define AR_DIAG_RXCLEAR_CTL_LOW 0x10000000 /* force rx_clear(ctl) low/busy */ +#define AR_DIAG_RXCLEAR_EXT_LOW 0x20000000 /* force rx_clear(ext) low/busy */ + +#define AR_TXOP_X_VAL 0x000000FF + +#define AR_RESET_TSF_ONCE 0x01000000 /* reset tsf once; self-clears*/ + +/* Interrupts */ +#define AR_ISR_TXMINTR 0x00080000 /* Maximum interrupt tx rate */ +#define AR_ISR_RXMINTR 0x01000000 /* Maximum interrupt rx rate */ +#define AR_ISR_TXINTM 0x40000000 /* Tx int after mitigation */ +#define AR_ISR_RXINTM 0x80000000 /* Rx int after mitigation */ + +#define AR_ISR_S2_CST 0x00400000 /* Carrier sense timeout */ +#define AR_ISR_S2_GTT 0x00800000 /* Global transmit timeout */ +#define AR_ISR_S2_TSFOOR 0x40000000 /* RX TSF out of range */ + +#define AR_INTR_SPURIOUS 0xffffffff +#define AR_INTR_RTC_IRQ 0x00000001 /* rtc in shutdown state */ +#define AR_INTR_MAC_IRQ 0x00000002 /* pending mac interrupt */ +#define AR_INTR_EEP_PROT_ACCESS 0x00000004 /* eeprom protected access */ +#define AR_INTR_MAC_AWAKE 0x00020000 /* mac is awake */ +#define AR_INTR_MAC_ASLEEP 0x00040000 /* mac is asleep */ + +/* Interrupt Mask Registers */ +#define AR_IMR_TXMINTR 0x00080000 /* Maximum interrupt tx rate */ +#define AR_IMR_RXMINTR 0x01000000 /* Maximum interrupt rx rate */ +#define AR_IMR_TXINTM 0x40000000 /* Tx int after mitigation */ +#define AR_IMR_RXINTM 0x80000000 /* Rx int after mitigation */ + +#define AR_IMR_S2_CST 0x00400000 /* Carrier sense timeout */ +#define AR_IMR_S2_GTT 0x00800000 /* Global transmit timeout */ + +/* synchronous interrupt signals */ +#define AR_INTR_SYNC_RTC_IRQ 0x00000001 +#define AR_INTR_SYNC_MAC_IRQ 0x00000002 +#define AR_INTR_SYNC_EEPROM_ILLEGAL_ACCESS 0x00000004 +#define AR_INTR_SYNC_APB_TIMEOUT 0x00000008 +#define AR_INTR_SYNC_PCI_MODE_CONFLICT 0x00000010 +#define AR_INTR_SYNC_HOST1_FATAL 0x00000020 +#define AR_INTR_SYNC_HOST1_PERR 0x00000040 +#define AR_INTR_SYNC_TRCV_FIFO_PERR 0x00000080 +#define AR_INTR_SYNC_RADM_CPL_EP 0x00000100 +#define AR_INTR_SYNC_RADM_CPL_DLLP_ABORT 0x00000200 +#define AR_INTR_SYNC_RADM_CPL_TLP_ABORT 0x00000400 +#define AR_INTR_SYNC_RADM_CPL_ECRC_ERR 0x00000800 +#define AR_INTR_SYNC_RADM_CPL_TIMEOUT 0x00001000 +#define AR_INTR_SYNC_LOCAL_TIMEOUT 0x00002000 +#define AR_INTR_SYNC_PM_ACCESS 0x00004000 +#define AR_INTR_SYNC_MAC_AWAKE 0x00008000 +#define AR_INTR_SYNC_MAC_ASLEEP 0x00010000 +#define AR_INTR_SYNC_MAC_SLEEP_ACCESS 0x00020000 +#define AR_INTR_SYNC_ALL 0x0003FFFF + +/* default synchronous interrupt signals enabled */ +#define AR_INTR_SYNC_DEFAULT \ + (AR_INTR_SYNC_HOST1_FATAL | AR_INTR_SYNC_HOST1_PERR | \ + AR_INTR_SYNC_RADM_CPL_EP | AR_INTR_SYNC_RADM_CPL_DLLP_ABORT | \ + AR_INTR_SYNC_RADM_CPL_TLP_ABORT | AR_INTR_SYNC_RADM_CPL_ECRC_ERR | \ + AR_INTR_SYNC_RADM_CPL_TIMEOUT | AR_INTR_SYNC_LOCAL_TIMEOUT | \ + AR_INTR_SYNC_MAC_SLEEP_ACCESS) + +/* RTC registers */ +#define AR_RTC_RC_M 0x00000003 +#define AR_RTC_RC_MAC_WARM 0x00000001 +#define AR_RTC_RC_MAC_COLD 0x00000002 +#define AR_RTC_PLL_DIV 0x0000001f +#define AR_RTC_PLL_DIV_S 0 +#define AR_RTC_PLL_DIV2 0x00000020 +#define AR_RTC_PLL_REFDIV_5 0x000000c0 + +#define AR_RTC_SOWL_PLL_DIV 0x000003ff +#define AR_RTC_SOWL_PLL_DIV_S 0 +#define AR_RTC_SOWL_PLL_REFDIV 0x00003C00 +#define AR_RTC_SOWL_PLL_REFDIV_S 10 +#define AR_RTC_SOWL_PLL_CLKSEL 0x0000C000 +#define AR_RTC_SOWL_PLL_CLKSEL_S 14 + +#define AR_RTC_RESET_EN 0x00000001 /* Reset RTC bit */ + +#define AR_RTC_PM_STATUS_M 0x0000000f /* Pwr Mgmt Status */ +#define AR_RTC_STATUS_M 0x0000003f /* RTC Status */ +#define AR_RTC_STATUS_SHUTDOWN 0x00000001 +#define AR_RTC_STATUS_ON 0x00000002 +#define AR_RTC_STATUS_SLEEP 0x00000004 +#define AR_RTC_STATUS_WAKEUP 0x00000008 +#define AR_RTC_STATUS_COLDRESET 0x00000010 /* Not currently used */ +#define AR_RTC_STATUS_PLLCHANGE 0x00000020 /* Not currently used */ + +#define AR_RTC_SLEEP_DERIVED_CLK 0x2 + +#define AR_RTC_FORCE_WAKE_EN 0x00000001 /* enable force wake */ +#define AR_RTC_FORCE_WAKE_ON_INT 0x00000002 /* auto-wake on MAC interrupt */ + +#define AR_RTC_PLL_CLKSEL 0x00000300 +#define AR_RTC_PLL_CLKSEL_S 8 + +/* AR9280: rf long shift registers */ +#define AR_AN_RF2G1_CH0_OB 0x03800000 +#define AR_AN_RF2G1_CH0_OB_S 23 +#define AR_AN_RF2G1_CH0_DB 0x1C000000 +#define AR_AN_RF2G1_CH0_DB_S 26 + +#define AR_AN_RF5G1_CH0_OB5 0x00070000 +#define AR_AN_RF5G1_CH0_OB5_S 16 +#define AR_AN_RF5G1_CH0_DB5 0x00380000 +#define AR_AN_RF5G1_CH0_DB5_S 19 + +#define AR_AN_RF2G1_CH1_OB 0x03800000 +#define AR_AN_RF2G1_CH1_OB_S 23 +#define AR_AN_RF2G1_CH1_DB 0x1C000000 +#define AR_AN_RF2G1_CH1_DB_S 26 + +#define AR_AN_RF5G1_CH1_OB5 0x00070000 +#define AR_AN_RF5G1_CH1_OB5_S 16 +#define AR_AN_RF5G1_CH1_DB5 0x00380000 +#define AR_AN_RF5G1_CH1_DB5_S 19 + +#define AR_AN_TOP2_XPABIAS_LVL 0xC0000000 +#define AR_AN_TOP2_XPABIAS_LVL_S 30 +#define AR_AN_TOP2_LOCALBIAS 0x00200000 +#define AR_AN_TOP2_LOCALBIAS_S 21 +#define AR_AN_TOP2_PWDCLKIND 0x00400000 +#define AR_AN_TOP2_PWDCLKIND_S 22 + +#define AR_AN_SYNTH9_REFDIVA 0xf8000000 +#define AR_AN_SYNTH9_REFDIVA_S 27 + +/* AR9285 Analog registers */ +#define AR9285_AN_RF2G3_OB_0 0x00E00000 +#define AR9285_AN_RF2G3_OB_0_S 21 +#define AR9285_AN_RF2G3_OB_1 0x001C0000 +#define AR9285_AN_RF2G3_OB_1_S 18 +#define AR9285_AN_RF2G3_OB_2 0x00038000 +#define AR9285_AN_RF2G3_OB_2_S 15 +#define AR9285_AN_RF2G3_OB_3 0x00007000 +#define AR9285_AN_RF2G3_OB_3_S 12 +#define AR9285_AN_RF2G3_OB_4 0x00000E00 +#define AR9285_AN_RF2G3_OB_4_S 9 + +#define AR9285_AN_RF2G3_DB1_0 0x000001C0 +#define AR9285_AN_RF2G3_DB1_0_S 6 +#define AR9285_AN_RF2G3_DB1_1 0x00000038 +#define AR9285_AN_RF2G3_DB1_1_S 3 +#define AR9285_AN_RF2G3_DB1_2 0x00000007 +#define AR9285_AN_RF2G3_DB1_2_S 0 +#define AR9285_AN_RF2G4 0x782C +#define AR9285_AN_RF2G4_DB1_3 0xE0000000 +#define AR9285_AN_RF2G4_DB1_3_S 29 +#define AR9285_AN_RF2G4_DB1_4 0x1C000000 +#define AR9285_AN_RF2G4_DB1_4_S 26 + +#define AR9285_AN_RF2G4_DB2_0 0x03800000 +#define AR9285_AN_RF2G4_DB2_0_S 23 +#define AR9285_AN_RF2G4_DB2_1 0x00700000 +#define AR9285_AN_RF2G4_DB2_1_S 20 +#define AR9285_AN_RF2G4_DB2_2 0x000E0000 +#define AR9285_AN_RF2G4_DB2_2_S 17 +#define AR9285_AN_RF2G4_DB2_3 0x0001C000 +#define AR9285_AN_RF2G4_DB2_3_S 14 +#define AR9285_AN_RF2G4_DB2_4 0x00003800 +#define AR9285_AN_RF2G4_DB2_4_S 11 + +#define AR9285_AN_TOP3_XPABIAS_LVL 0x0000000C +#define AR9285_AN_TOP3_XPABIAS_LVL_S 2 + +/* Sleep control */ +#define AR5416_SLEEP1_CAB_TIMEOUT 0xFFE00000 /* Cab timeout (TU) */ +#define AR5416_SLEEP1_CAB_TIMEOUT_S 22 + +#define AR5416_SLEEP2_BEACON_TIMEOUT 0xFFE00000 /* Beacon timeout (TU)*/ +#define AR5416_SLEEP2_BEACON_TIMEOUT_S 22 + +/* Sleep Registers */ +#define AR_SLP32_HALFCLK_LATENCY 0x000FFFFF /* rising <-> falling edge */ +#define AR_SLP32_ENA 0x00100000 +#define AR_SLP32_TSF_WRITE_STATUS 0x00200000 /* tsf update in progress */ + +#define AR_SLP32_WAKE_XTL_TIME 0x0000FFFF /* time to wake crystal */ + +#define AR_SLP32_TST_INC 0x000FFFFF + +#define AR_SLP_MIB_CLEAR 0x00000001 /* clear pending */ +#define AR_SLP_MIB_PENDING 0x00000002 /* clear counters */ + +#define AR_TIMER_MODE_TBTT 0x00000001 +#define AR_TIMER_MODE_DBA 0x00000002 +#define AR_TIMER_MODE_SWBA 0x00000004 +#define AR_TIMER_MODE_HCF 0x00000008 +#define AR_TIMER_MODE_TIM 0x00000010 +#define AR_TIMER_MODE_DTIM 0x00000020 +#define AR_TIMER_MODE_QUIET 0x00000040 +#define AR_TIMER_MODE_NDP 0x00000080 +#define AR_TIMER_MODE_OVERFLOW_INDEX 0x00000700 +#define AR_TIMER_MODE_OVERFLOW_INDEX_S 8 +#define AR_TIMER_MODE_THRESH 0xFFFFF000 +#define AR_TIMER_MODE_THRESH_S 12 + +/* PCU Misc modes */ +#define AR_PCU_FORCE_BSSID_MATCH 0x00000001 /* force bssid to match */ +#define AR_PCU_MIC_NEW_LOC_ENA 0x00000004 /* tx/rx mic keys together */ +#define AR_PCU_TX_ADD_TSF 0x00000008 /* add tx_tsf + int_tsf */ +#define AR_PCU_CCK_SIFS_MODE 0x00000010 /* assume 11b sifs */ +#define AR_PCU_RX_ANT_UPDT 0x00000800 /* KC_RX_ANT_UPDATE */ +#define AR_PCU_TXOP_TBTT_LIMIT_ENA 0x00001000 /* enforce txop / tbtt */ +#define AR_PCU_MISS_BCN_IN_SLEEP 0x00004000 /* count bmiss's when sleeping */ +#define AR_PCU_BUG_12306_FIX_ENA 0x00020000 /* use rx_clear to count sifs */ +#define AR_PCU_FORCE_QUIET_COLL 0x00040000 /* kill xmit for channel change */ +#define AR_PCU_TBTT_PROTECT 0x00200000 /* no xmit upto tbtt+20 uS */ +#define AR_PCU_CLEAR_VMF 0x01000000 /* clear vmf mode (fast cc)*/ +#define AR_PCU_CLEAR_BA_VALID 0x04000000 /* clear ba state */ + +/* GPIO Interrupt */ +#define AR_INTR_GPIO 0x3FF00000 /* gpio interrupted */ +#define AR_INTR_GPIO_S 20 + +#define AR_GPIO_OUT_CTRL 0x000003FF /* 0 = out, 1 = in */ +#define AR_GPIO_OUT_VAL 0x000FFC00 +#define AR_GPIO_OUT_VAL_S 10 +#define AR_GPIO_INTR_CTRL 0x3FF00000 +#define AR_GPIO_INTR_CTRL_S 20 + +#define AR_2040_JOINED_RX_CLEAR 0x00000001 /* use ctl + ext rx_clear for cca */ + +#define AR_PCU_TXBUF_CTRL_SIZE_MASK 0x7FF +#define AR_PCU_TXBUF_CTRL_USABLE_SIZE 0x700 + +/* Eeprom defines */ +#define AR_EEPROM_STATUS_DATA_VAL 0x0000ffff +#define AR_EEPROM_STATUS_DATA_VAL_S 0 +#define AR_EEPROM_STATUS_DATA_BUSY 0x00010000 +#define AR_EEPROM_STATUS_DATA_BUSY_ACCESS 0x00020000 +#define AR_EEPROM_STATUS_DATA_PROT_ACCESS 0x00040000 +#define AR_EEPROM_STATUS_DATA_ABSENT_ACCESS 0x00080000 + +#define AR_SREV_REVISION_OWL_10 0x08 +#define AR_SREV_REVISION_OWL_20 0x09 +#define AR_SREV_REVISION_OWL_22 0x0a + +#define AR_RAD5133_SREV_MAJOR 0xc0 /* Fowl: 2+5G/3x3 */ +#define AR_RAD2133_SREV_MAJOR 0xd0 /* Fowl: 2G/3x3 */ +#define AR_RAD5122_SREV_MAJOR 0xe0 /* Fowl: 5G/2x2 */ +#define AR_RAD2122_SREV_MAJOR 0xf0 /* Fowl: 2+5G/2x2 */ + +/* Test macro for owl 1.0 */ +#define IS_5416V1(_ah) ((_ah)->ah_macRev == AR_SREV_REVISION_OWL_10) +#define IS_5416V2(_ah) ((_ah)->ah_macRev >= AR_SREV_REVISION_OWL_20) +#define IS_5416V2_2(_ah) ((_ah)->ah_macRev == AR_SREV_REVISION_OWL_22) + +/* Expanded Mac Silicon Rev (16 bits starting with Sowl) */ +#define AR_XSREV_ID 0xFFFFFFFF /* Chip ID */ +#define AR_XSREV_ID_S 0 +#define AR_XSREV_VERSION 0xFFFC0000 /* Chip version */ +#define AR_XSREV_VERSION_S 18 +#define AR_XSREV_TYPE 0x0003F000 /* Chip type */ +#define AR_XSREV_TYPE_S 12 +#define AR_XSREV_TYPE_CHAIN 0x00001000 /* Chain Mode (1:3 chains, + * 0:2 chains) */ +#define AR_XSREV_TYPE_HOST_MODE 0x00002000 /* Host Mode (1:PCI, 0:PCIe) */ +#define AR_XSREV_REVISION 0x00000F00 +#define AR_XSREV_REVISION_S 8 + +#define AR_XSREV_VERSION_OWL_PCI 0x0D +#define AR_XSREV_VERSION_OWL_PCIE 0x0C +#define AR_XSREV_REVISION_OWL_10 0 /* Owl 1.0 */ +#define AR_XSREV_REVISION_OWL_20 1 /* Owl 2.0/2.1 */ +#define AR_XSREV_REVISION_OWL_22 2 /* Owl 2.2 */ +#define AR_XSREV_VERSION_SOWL 0x40 +#define AR_XSREV_REVISION_SOWL_10 0 /* Sowl 1.0 */ +#define AR_XSREV_REVISION_SOWL_11 1 /* Sowl 1.1 */ +#define AR_XSREV_VERSION_MERLIN 0x80 /* Merlin Version */ +#define AR_XSREV_REVISION_MERLIN_10 0 /* Merlin 1.0 */ +#define AR_XSREV_REVISION_MERLIN_20 1 /* Merlin 2.0 */ +#define AR_XSREV_REVISION_MERLIN_21 2 /* Merlin 2.1 */ +#define AR_XSREV_VERSION_KITE 0xC0 /* Kite Version */ +#define AR_XSREV_REVISION_KITE_10 0 /* Kite 1.0 */ + +#define AR_SREV_OWL_20_OR_LATER(_ah) \ + (AH_PRIVATE((_ah))->ah_macVersion >= AR_XSREV_VERSION_SOWL || \ + AH_PRIVATE((_ah))->ah_macRev >= AR_XSREV_REVISION_OWL_20) +#define AR_SREV_OWL_22_OR_LATER(_ah) \ + (AH_PRIVATE((_ah))->ah_macVersion >= AR_XSREV_VERSION_SOWL || \ + AH_PRIVATE((_ah))->ah_macRev >= AR_XSREV_REVISION_OWL_22) + +#define AR_SREV_SOWL(_ah) \ + (AH_PRIVATE((_ah))->ah_macVersion == AR_XSREV_VERSION_SOWL) +#define AR_SREV_SOWL_10_OR_LATER(_ah) \ + (AH_PRIVATE((_ah))->ah_macVersion >= AR_XSREV_VERSION_SOWL) +#define AR_SREV_SOWL_11(_ah) \ + (AR_SREV_SOWL(_ah) && \ + AH_PRIVATE((_ah))->ah_macRev == AR_XSREV_REVISION_SOWL_11) + +#define AR_SREV_MERLIN(_ah) \ + (AH_PRIVATE((_ah))->ah_macVersion == AR_XSREV_VERSION_MERLIN) +#define AR_SREV_MERLIN_10_OR_LATER(_ah) \ + (AH_PRIVATE((_ah))->ah_macVersion >= AR_XSREV_VERSION_MERLIN) +#define AR_SREV_MERLIN_20(_ah) \ + (AR_SREV_MERLIN(_ah) && \ + AH_PRIVATE((_ah))->ah_macRev >= AR_XSREV_REVISION_MERLIN_20) +#define AR_SREV_MERLIN_20_OR_LATER(_ah) \ + (AR_SREV_MERLIN_20(_ah) || \ + AH_PRIVATE((_ah))->ah_macVersion > AR_XSREV_VERSION_MERLIN) + +#define AR_SREV_KITE(_ah) \ + (AH_PRIVATE((_ah))->ah_macVersion == AR_XSREV_VERSION_KITE) +#define AR_SREV_KITE_10_OR_LATER(_ah) \ + (AH_PRIVATE((_ah))->ah_macVersion >= AR_XSREV_VERSION_KITE) +#endif /* _DEV_ATH_AR5416REG_H */ --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5210/ar9160.ini 2009-03-23 17:36:56.000000000 +0000 @@ -0,0 +1,699 @@ +/* + * 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: ar9160.ini,v 1.1 2009/03/23 17:14:48 sborrill Exp $ + */ +/* Auto Generated PCI Register Writes. Created: 05/22/08 */ + +static const uint32_t ar9160Modes[][6] = { + { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, + { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, + { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 }, + { 0x000010f0, 0x0000a000, 0x00014000, 0x00016000, 0x0000b000, 0x00014008 }, + { 0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0 }, + { 0x0000801c, 0x128d93a7, 0x128d93cf, 0x12e013d7, 0x12e013ab, 0x098813cf }, + { 0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303 }, + { 0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200 }, + { 0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, + { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 }, + { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, + { 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 }, + { 0x00009844, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0, 0x037216a0 }, + { 0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, + { 0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, + { 0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, + { 0x00009850, 0x6d48b4e2, 0x6d48b4e2, 0x6d48b0e2, 0x6d48b0e2, 0x6d48b0e2 }, + { 0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e }, + { 0x0000985c, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e }, + { 0x00009860, 0x00048d18, 0x00048d18, 0x00048d20, 0x00048d20, 0x00048d18 }, + { 0x0000c864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 }, + { 0x00009868, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0 }, + { 0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 }, + { 0x00009914, 0x000007d0, 0x000007d0, 0x00000898, 0x00000898, 0x000007d0 }, + { 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 }, + { 0x00009924, 0xd00a8a07, 0xd00a8a07, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d }, + { 0x00009944, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020 }, + { 0x00009960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40 }, + { 0x0000a960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40 }, + { 0x0000b960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40 }, + { 0x00009964, 0x00001120, 0x00001120, 0x00001120, 0x00001120, 0x00001120 }, + { 0x0000c968, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce, 0x000003ce }, + { 0x0000c9bc, 0x001a0600, 0x001a0600, 0x001a0c00, 0x001a0c00, 0x001a0c00 }, + { 0x000099c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, 0x038919be }, + { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 }, + { 0x000099c8, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329 }, + { 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 }, + { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 }, + { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a204, 0x00000880, 0x00000880, 0x00000880, 0x00000880, 0x00000880 }, + { 0x0000a208, 0xd6be4788, 0xd6be4788, 0xd03e4788, 0xd03e4788, 0xd03e4788 }, + { 0x0000a20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120 }, + { 0x0000b20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120 }, + { 0x0000c20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120 }, + { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a }, + { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 }, + { 0x0000a274, 0x0a1a9caa, 0x0a1a9caa, 0x0a1a7caa, 0x0a1a7caa, 0x0a1a7caa }, + { 0x0000a300, 0x18010000, 0x18010000, 0x18010000, 0x18010000, 0x18010000 }, + { 0x0000a304, 0x30032602, 0x30032602, 0x2e032402, 0x2e032402, 0x2e032402 }, + { 0x0000a308, 0x48073e06, 0x48073e06, 0x4a0a3c06, 0x4a0a3c06, 0x4a0a3c06 }, + { 0x0000a30c, 0x560b4c0a, 0x560b4c0a, 0x621a540b, 0x621a540b, 0x621a540b }, + { 0x0000a310, 0x641a600f, 0x641a600f, 0x764f6c1b, 0x764f6c1b, 0x764f6c1b }, + { 0x0000a314, 0x7a4f6e1b, 0x7a4f6e1b, 0x845b7a5a, 0x845b7a5a, 0x845b7a5a }, + { 0x0000a318, 0x8c5b7e5a, 0x8c5b7e5a, 0x950f8ccf, 0x950f8ccf, 0x950f8ccf }, + { 0x0000a31c, 0x9d0f96cf, 0x9d0f96cf, 0xa5cf9b4f, 0xa5cf9b4f, 0xa5cf9b4f }, + { 0x0000a320, 0xb51fa69f, 0xb51fa69f, 0xbddfaf1f, 0xbddfaf1f, 0xbddfaf1f }, + { 0x0000a324, 0xcb3fbd07, 0xcb3fbcbf, 0xd1ffc93f, 0xd1ffc93f, 0xd1ffc93f }, + { 0x0000a328, 0x0000d7bf, 0x0000d7bf, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a32c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a330, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a334, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, +}; + +static const uint32_t ar9160Common[][2] = { + { 0x0000000c, 0x00000000 }, + { 0x00000030, 0x00020015 }, + { 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 }, + { 0x00001040, 0x002ffc0f }, + { 0x00001044, 0x002ffc0f }, + { 0x00001048, 0x002ffc0f }, + { 0x0000104c, 0x002ffc0f }, + { 0x00001050, 0x002ffc0f }, + { 0x00001054, 0x002ffc0f }, + { 0x00001058, 0x002ffc0f }, + { 0x0000105c, 0x002ffc0f }, + { 0x00001060, 0x002ffc0f }, + { 0x00001064, 0x002ffc0f }, + { 0x00001230, 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 }, + { 0x00004030, 0x00000002 }, + { 0x0000403c, 0x00000002 }, + { 0x00007010, 0x00000020 }, + { 0x00007038, 0x000004c2 }, + { 0x00008004, 0x00000000 }, + { 0x00008008, 0x00000000 }, + { 0x0000800c, 0x00000000 }, + { 0x00008018, 0x00000700 }, + { 0x00008020, 0x00000000 }, + { 0x00008038, 0x00000000 }, + { 0x0000803c, 0x00000000 }, + { 0x00008048, 0x40000000 }, + { 0x00008054, 0x00000000 }, + { 0x00008058, 0x00000000 }, + { 0x0000805c, 0x000fc78f }, + { 0x00008060, 0x0000000f }, + { 0x00008064, 0x00000000 }, + { 0x000080c0, 0x2a82301a }, + { 0x000080c4, 0x05dc01e0 }, + { 0x000080c8, 0x1f402710 }, + { 0x000080cc, 0x01f40000 }, + { 0x000080d0, 0x00001e00 }, + { 0x000080d4, 0x00000000 }, + { 0x000080d8, 0x00400000 }, + { 0x000080e0, 0xffffffff }, + { 0x000080e4, 0x0000ffff }, + { 0x000080e8, 0x003f3f3f }, + { 0x000080ec, 0x00000000 }, + { 0x000080f0, 0x00000000 }, + { 0x000080f4, 0x00000000 }, + { 0x000080f8, 0x00000000 }, + { 0x000080fc, 0x00020000 }, + { 0x00008100, 0x00020000 }, + { 0x00008104, 0x00000001 }, + { 0x00008108, 0x00000052 }, + { 0x0000810c, 0x00000000 }, + { 0x00008110, 0x00000168 }, + { 0x00008118, 0x000100aa }, + { 0x0000811c, 0x00003210 }, + { 0x00008120, 0x08f04800 }, + { 0x00008124, 0x00000000 }, + { 0x00008128, 0x00000000 }, + { 0x0000812c, 0x00000000 }, + { 0x00008130, 0x00000000 }, + { 0x00008134, 0x00000000 }, + { 0x00008138, 0x00000000 }, + { 0x0000813c, 0x00000000 }, + { 0x00008144, 0x00000000 }, + { 0x00008168, 0x00000000 }, + { 0x0000816c, 0x00000000 }, + { 0x00008170, 0x32143320 }, + { 0x00008174, 0xfaa4fa50 }, + { 0x00008178, 0x00000100 }, + { 0x0000817c, 0x00000000 }, + { 0x000081c4, 0x00000000 }, + { 0x000081d0, 0x00003210 }, + { 0x000081ec, 0x00000000 }, + { 0x000081f0, 0x00000000 }, + { 0x000081f4, 0x00000000 }, + { 0x000081f8, 0x00000000 }, + { 0x000081fc, 0x00000000 }, + { 0x00008200, 0x00000000 }, + { 0x00008204, 0x00000000 }, + { 0x00008208, 0x00000000 }, + { 0x0000820c, 0x00000000 }, + { 0x00008210, 0x00000000 }, + { 0x00008214, 0x00000000 }, + { 0x00008218, 0x00000000 }, + { 0x0000821c, 0x00000000 }, + { 0x00008220, 0x00000000 }, + { 0x00008224, 0x00000000 }, + { 0x00008228, 0x00000000 }, + { 0x0000822c, 0x00000000 }, + { 0x00008230, 0x00000000 }, + { 0x00008234, 0x00000000 }, + { 0x00008238, 0x00000000 }, + { 0x0000823c, 0x00000000 }, + { 0x00008240, 0x00100000 }, + { 0x00008244, 0x0010f400 }, + { 0x00008248, 0x00000100 }, + { 0x0000824c, 0x0001e800 }, + { 0x00008250, 0x00000000 }, + { 0x00008254, 0x00000000 }, + { 0x00008258, 0x00000000 }, + { 0x0000825c, 0x400000ff }, + { 0x00008260, 0x00080922 }, + { 0x00008270, 0x00000000 }, + { 0x00008274, 0x40000000 }, + { 0x00008278, 0x003e4180 }, + { 0x0000827c, 0x00000000 }, + { 0x00008284, 0x0000002c }, + { 0x00008288, 0x0000002c }, + { 0x0000828c, 0x00000000 }, + { 0x00008294, 0x00000000 }, + { 0x00008298, 0x00000000 }, + { 0x00008300, 0x00000000 }, + { 0x00008304, 0x00000000 }, + { 0x00008308, 0x00000000 }, + { 0x0000830c, 0x00000000 }, + { 0x00008310, 0x00000000 }, + { 0x00008314, 0x00000000 }, + { 0x00008318, 0x00000000 }, + { 0x00008328, 0x00000000 }, + { 0x0000832c, 0x00000007 }, + { 0x00008330, 0x00000302 }, + { 0x00008334, 0x00000e00 }, + { 0x00008338, 0x00000000 }, + { 0x0000833c, 0x00000000 }, + { 0x00008340, 0x000107ff }, + { 0x00009808, 0x00000000 }, + { 0x0000980c, 0xad848e19 }, + { 0x00009810, 0x7d14e000 }, + { 0x00009814, 0x9c0a9f6b }, + { 0x0000981c, 0x00000000 }, + { 0x0000982c, 0x0000a000 }, + { 0x00009830, 0x00000000 }, + { 0x0000983c, 0x00200400 }, + { 0x00009840, 0x206a01ae }, + { 0x0000984c, 0x1284233c }, + { 0x00009854, 0x00000859 }, + { 0x00009900, 0x00000000 }, + { 0x00009904, 0x00000000 }, + { 0x00009908, 0x00000000 }, + { 0x0000990c, 0x00000000 }, + { 0x0000991c, 0x10000fff }, + { 0x00009920, 0x05100000 }, + { 0x0000a920, 0x05100000 }, + { 0x0000b920, 0x05100000 }, + { 0x00009928, 0x00000001 }, + { 0x0000992c, 0x00000004 }, + { 0x00009934, 0x1e1f2022 }, + { 0x00009938, 0x0a0b0c0d }, + { 0x0000993c, 0x00000000 }, + { 0x00009948, 0x9280b212 }, + { 0x0000994c, 0x00020028 }, + { 0x00009954, 0x5f3ca3de }, + { 0x00009958, 0x2108ecff }, + { 0x00009940, 0x00750604 }, + { 0x0000c95c, 0x004b6a8e }, + { 0x00009970, 0x190fb515 }, + { 0x00009974, 0x00000000 }, + { 0x00009978, 0x00000001 }, + { 0x0000997c, 0x00000000 }, + { 0x00009980, 0x00000000 }, + { 0x00009984, 0x00000000 }, + { 0x00009988, 0x00000000 }, + { 0x0000998c, 0x00000000 }, + { 0x00009990, 0x00000000 }, + { 0x00009994, 0x00000000 }, + { 0x00009998, 0x00000000 }, + { 0x0000999c, 0x00000000 }, + { 0x000099a0, 0x00000000 }, + { 0x000099a4, 0x00000001 }, + { 0x000099a8, 0x201fff00 }, + { 0x000099ac, 0x006f0000 }, + { 0x000099b0, 0x03051000 }, + { 0x000099dc, 0x00000000 }, + { 0x000099e0, 0x00000200 }, + { 0x000099e4, 0xaaaaaaaa }, + { 0x000099e8, 0x3c466478 }, + { 0x000099ec, 0x0cc80caa }, + { 0x000099fc, 0x00001042 }, + { 0x00009b00, 0x00000000 }, + { 0x00009b04, 0x00000001 }, + { 0x00009b08, 0x00000002 }, + { 0x00009b0c, 0x00000003 }, + { 0x00009b10, 0x00000004 }, + { 0x00009b14, 0x00000005 }, + { 0x00009b18, 0x00000008 }, + { 0x00009b1c, 0x00000009 }, + { 0x00009b20, 0x0000000a }, + { 0x00009b24, 0x0000000b }, + { 0x00009b28, 0x0000000c }, + { 0x00009b2c, 0x0000000d }, + { 0x00009b30, 0x00000010 }, + { 0x00009b34, 0x00000011 }, + { 0x00009b38, 0x00000012 }, + { 0x00009b3c, 0x00000013 }, + { 0x00009b40, 0x00000014 }, + { 0x00009b44, 0x00000015 }, + { 0x00009b48, 0x00000018 }, + { 0x00009b4c, 0x00000019 }, + { 0x00009b50, 0x0000001a }, + { 0x00009b54, 0x0000001b }, + { 0x00009b58, 0x0000001c }, + { 0x00009b5c, 0x0000001d }, + { 0x00009b60, 0x00000020 }, + { 0x00009b64, 0x00000021 }, + { 0x00009b68, 0x00000022 }, + { 0x00009b6c, 0x00000023 }, + { 0x00009b70, 0x00000024 }, + { 0x00009b74, 0x00000025 }, + { 0x00009b78, 0x00000028 }, + { 0x00009b7c, 0x00000029 }, + { 0x00009b80, 0x0000002a }, + { 0x00009b84, 0x0000002b }, + { 0x00009b88, 0x0000002c }, + { 0x00009b8c, 0x0000002d }, + { 0x00009b90, 0x00000030 }, + { 0x00009b94, 0x00000031 }, + { 0x00009b98, 0x00000032 }, + { 0x00009b9c, 0x00000033 }, + { 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 }, + { 0x0000a210, 0x40806333 }, + { 0x0000a214, 0x00106c10 }, + { 0x0000a218, 0x009c4060 }, + { 0x0000a220, 0x018830c6 }, + { 0x0000a224, 0x00000400 }, + { 0x0000a228, 0x001a0bb5 }, + { 0x0000a22c, 0x00000000 }, + { 0x0000a234, 0x20202020 }, + { 0x0000a238, 0x20202020 }, + { 0x0000a23c, 0x13c889af }, + { 0x0000a240, 0x38490a20 }, + { 0x0000a244, 0x00007bb6 }, + { 0x0000a248, 0x0fff3ffc }, + { 0x0000a24c, 0x00000001 }, + { 0x0000a250, 0x0000a000 }, + { 0x0000a254, 0x00000000 }, + { 0x0000a258, 0x0cc75380 }, + { 0x0000a25c, 0x0f0f0f01 }, + { 0x0000a260, 0xdfa91f01 }, + { 0x0000a268, 0x00000001 }, + { 0x0000a26c, 0x0ebae9c6 }, + { 0x0000b26c, 0x0ebae9c6 }, + { 0x0000c26c, 0x0ebae9c6 }, + { 0x0000d270, 0x00820820 }, + { 0x0000a278, 0x1ce739ce }, + { 0x0000a27c, 0x050701ce }, + { 0x0000a338, 0x00000000 }, + { 0x0000a33c, 0x00000000 }, + { 0x0000a340, 0x00000000 }, + { 0x0000a344, 0x00000000 }, + { 0x0000a348, 0x3fffffff }, + { 0x0000a34c, 0x3fffffff }, + { 0x0000a350, 0x3fffffff }, + { 0x0000a354, 0x0003ffff }, + { 0x0000a358, 0x79a8aa33 }, + { 0x0000d35c, 0x07ffffef }, + { 0x0000d360, 0x0fffffe7 }, + { 0x0000d364, 0x17ffffe5 }, + { 0x0000d368, 0x1fffffe4 }, + { 0x0000d36c, 0x37ffffe3 }, + { 0x0000d370, 0x3fffffe3 }, + { 0x0000d374, 0x57ffffe3 }, + { 0x0000d378, 0x5fffffe2 }, + { 0x0000d37c, 0x7fffffe2 }, + { 0x0000d380, 0x7f3c7bba }, + { 0x0000d384, 0xf3307ff0 }, + { 0x0000a388, 0x0c000000 }, + { 0x0000a38c, 0x20202020 }, + { 0x0000a390, 0x20202020 }, + { 0x0000a394, 0x1ce739ce }, + { 0x0000a398, 0x000001ce }, + { 0x0000a39c, 0x00000001 }, + { 0x0000a3a0, 0x00000000 }, + { 0x0000a3a4, 0x00000000 }, + { 0x0000a3a8, 0x00000000 }, + { 0x0000a3ac, 0x00000000 }, + { 0x0000a3b0, 0x00000000 }, + { 0x0000a3b4, 0x00000000 }, + { 0x0000a3b8, 0x00000000 }, + { 0x0000a3bc, 0x00000000 }, + { 0x0000a3c0, 0x00000000 }, + { 0x0000a3c4, 0x00000000 }, + { 0x0000a3c8, 0x00000246 }, + { 0x0000a3cc, 0x20202020 }, + { 0x0000a3d0, 0x20202020 }, + { 0x0000a3d4, 0x20202020 }, + { 0x0000a3dc, 0x1ce739ce }, + { 0x0000a3e0, 0x000001ce }, +}; + +static const uint32_t ar9160Bank0[][2] = { + { 0x000098b0, 0x1e5795e5 }, + { 0x000098e0, 0x02008020 }, +}; + +static const uint32_t ar9160BB_RfGain[][3] = { + { 0x00009a00, 0x00000000, 0x00000000 }, + { 0x00009a04, 0x00000040, 0x00000040 }, + { 0x00009a08, 0x00000080, 0x00000080 }, + { 0x00009a0c, 0x000001a1, 0x00000141 }, + { 0x00009a10, 0x000001e1, 0x00000181 }, + { 0x00009a14, 0x00000021, 0x000001c1 }, + { 0x00009a18, 0x00000061, 0x00000001 }, + { 0x00009a1c, 0x00000168, 0x00000041 }, + { 0x00009a20, 0x000001a8, 0x000001a8 }, + { 0x00009a24, 0x000001e8, 0x000001e8 }, + { 0x00009a28, 0x00000028, 0x00000028 }, + { 0x00009a2c, 0x00000068, 0x00000068 }, + { 0x00009a30, 0x00000189, 0x000000a8 }, + { 0x00009a34, 0x000001c9, 0x00000169 }, + { 0x00009a38, 0x00000009, 0x000001a9 }, + { 0x00009a3c, 0x00000049, 0x000001e9 }, + { 0x00009a40, 0x00000089, 0x00000029 }, + { 0x00009a44, 0x00000170, 0x00000069 }, + { 0x00009a48, 0x000001b0, 0x00000190 }, + { 0x00009a4c, 0x000001f0, 0x000001d0 }, + { 0x00009a50, 0x00000030, 0x00000010 }, + { 0x00009a54, 0x00000070, 0x00000050 }, + { 0x00009a58, 0x00000191, 0x00000090 }, + { 0x00009a5c, 0x000001d1, 0x00000151 }, + { 0x00009a60, 0x00000011, 0x00000191 }, + { 0x00009a64, 0x00000051, 0x000001d1 }, + { 0x00009a68, 0x00000091, 0x00000011 }, + { 0x00009a6c, 0x000001b8, 0x00000051 }, + { 0x00009a70, 0x000001f8, 0x00000198 }, + { 0x00009a74, 0x00000038, 0x000001d8 }, + { 0x00009a78, 0x00000078, 0x00000018 }, + { 0x00009a7c, 0x00000199, 0x00000058 }, + { 0x00009a80, 0x000001d9, 0x00000098 }, + { 0x00009a84, 0x00000019, 0x00000159 }, + { 0x00009a88, 0x00000059, 0x00000199 }, + { 0x00009a8c, 0x00000099, 0x000001d9 }, + { 0x00009a90, 0x000000d9, 0x00000019 }, + { 0x00009a94, 0x000000f9, 0x00000059 }, + { 0x00009a98, 0x000000f9, 0x00000099 }, + { 0x00009a9c, 0x000000f9, 0x000000d9 }, + { 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 }, +}; + +static const uint32_t ar9160Bank1[][2] = { + { 0x000098b0, 0x02108421 }, + { 0x000098ec, 0x00000008 }, +}; + +static const uint32_t ar9160Bank2[][2] = { + { 0x000098b0, 0x0e73ff17 }, + { 0x000098e0, 0x00000420 }, +}; + +static const uint32_t ar9160Bank3[][3] = { + { 0x000098f0, 0x01400018, 0x01c00018 }, +}; + +static const uint32_t ar9160Bank6[][3] = { +/* Reg A G */ + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00e00000, 0x00e00000 }, + { 0x0000989c, 0x005e0000, 0x005e0000 }, + { 0x0000989c, 0x00120000, 0x00120000 }, + { 0x0000989c, 0x00620000, 0x00620000 }, + { 0x0000989c, 0x00020000, 0x00020000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x40ff0000, 0x40ff0000 }, + { 0x0000989c, 0x005f0000, 0x005f0000 }, + { 0x0000989c, 0x00870000, 0x00870000 }, + { 0x0000989c, 0x00f90000, 0x00f90000 }, + { 0x0000989c, 0x007b0000, 0x007b0000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x00f50000, 0x00f50000 }, + { 0x0000989c, 0x00dc0000, 0x00dc0000 }, + { 0x0000989c, 0x00110000, 0x00110000 }, + { 0x0000989c, 0x006100a8, 0x006100a8 }, + { 0x0000989c, 0x004210a2, 0x004210a2 }, + { 0x0000989c, 0x0014008f, 0x0014008f }, + { 0x0000989c, 0x00c40003, 0x00c40003 }, + { 0x0000989c, 0x003000f2, 0x003000f2 }, + { 0x0000989c, 0x00440016, 0x00440016 }, + { 0x0000989c, 0x00410040, 0x00410040 }, + { 0x0000989c, 0x0001805e, 0x0001805e }, + { 0x0000989c, 0x0000c0ab, 0x0000c0ab }, + { 0x0000989c, 0x000000f1, 0x000000f1 }, + { 0x0000989c, 0x00002081, 0x00002081 }, + { 0x0000989c, 0x000000d4, 0x000000d4 }, + { 0x000098d0, 0x0000000f, 0x0010000f }, +}; + +static const uint32_t ar9160Bank6TPC[][3] = { + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00e00000, 0x00e00000 }, + { 0x0000989c, 0x005e0000, 0x005e0000 }, + { 0x0000989c, 0x00120000, 0x00120000 }, + { 0x0000989c, 0x00620000, 0x00620000 }, + { 0x0000989c, 0x00020000, 0x00020000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x40ff0000, 0x40ff0000 }, + { 0x0000989c, 0x005f0000, 0x005f0000 }, + { 0x0000989c, 0x00870000, 0x00870000 }, + { 0x0000989c, 0x00f90000, 0x00f90000 }, + { 0x0000989c, 0x007b0000, 0x007b0000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x00f50000, 0x00f50000 }, + { 0x0000989c, 0x00dc0000, 0x00dc0000 }, + { 0x0000989c, 0x00110000, 0x00110000 }, + { 0x0000989c, 0x006100a8, 0x006100a8 }, + { 0x0000989c, 0x00423022, 0x00423022 }, + { 0x0000989c, 0x2014008f, 0x2014008f }, + { 0x0000989c, 0x00c40002, 0x00c40002 }, + { 0x0000989c, 0x003000f2, 0x003000f2 }, + { 0x0000989c, 0x00440016, 0x00440016 }, + { 0x0000989c, 0x00410040, 0x00410040 }, + { 0x0000989c, 0x0001805e, 0x0001805e }, + { 0x0000989c, 0x0000c0ab, 0x0000c0ab }, + { 0x0000989c, 0x000000e1, 0x000000e1 }, + { 0x0000989c, 0x00007080, 0x00007080 }, + { 0x0000989c, 0x000000d4, 0x000000d4 }, + { 0x000098d0, 0x0000000f, 0x0010000f }, +}; + +static const uint32_t ar9160Bank7[][2] = { + { 0x0000989c, 0x00000500 }, + { 0x0000989c, 0x00000800 }, + { 0x000098cc, 0x0000000e }, +}; + +/* Auto generated PCI Register Writes for SOWL1.0 ADDAC Shift Chain */ +static const uint32_t ar9160Addac[][2] = { + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x000000c0 }, + {0x0000989c, 0x00000018 }, + {0x0000989c, 0x00000004 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x000000c0 }, + {0x0000989c, 0x00000019 }, + {0x0000989c, 0x00000004 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000004 }, + {0x0000989c, 0x00000003 }, + {0x0000989c, 0x00000008 }, + {0x0000989c, 0x00000000 }, + {0x000098cc, 0x00000000 }, +}; + +/* Auto generated PCI Register Writes for SOWL1.1 ADDAC Shift Chain */ +static const uint32_t ar9160Addac_1_1[][2] = { + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x000000c0 }, + {0x0000989c, 0x00000018 }, + {0x0000989c, 0x00000004 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x000000c0 }, + {0x0000989c, 0x00000019 }, + {0x0000989c, 0x00000004 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x000098cc, 0x00000000 }, +}; --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5210/ar9160_attach.c 2009-03-23 17:36:56.000000000 +0000 @@ -0,0 +1,307 @@ +/* + * Copyright (c) 2008 Sam Leffler, Errno Consulting + * Copyright (c) 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: ar9160_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 "ar5416/ar5416.h" +#include "ar5416/ar5416reg.h" +#include "ar5416/ar5416phy.h" + +#include "ar5416/ar9160.ini" + +static const HAL_PERCAL_DATA ar9160_iq_cal = { /* multi sample */ + .calName = "IQ", .calType = IQ_MISMATCH_CAL, + .calNumSamples = MAX_CAL_SAMPLES, + .calCountMax = PER_MIN_LOG_COUNT, + .calCollect = ar5416IQCalCollect, + .calPostProc = ar5416IQCalibration +}; +static const HAL_PERCAL_DATA ar9160_adc_gain_cal = { /* multi sample */ + .calName = "ADC Gain", .calType = ADC_GAIN_CAL, + .calNumSamples = MAX_CAL_SAMPLES, + .calCountMax = PER_MIN_LOG_COUNT, + .calCollect = ar5416AdcGainCalCollect, + .calPostProc = ar5416AdcGainCalibration +}; +static const HAL_PERCAL_DATA ar9160_adc_dc_cal = { /* multi sample */ + .calName = "ADC DC", .calType = ADC_DC_CAL, + .calNumSamples = MAX_CAL_SAMPLES, + .calCountMax = PER_MIN_LOG_COUNT, + .calCollect = ar5416AdcDcCalCollect, + .calPostProc = ar5416AdcDcCalibration +}; +static const HAL_PERCAL_DATA ar9160_adc_init_dc_cal = { + .calName = "ADC Init DC", .calType = ADC_DC_INIT_CAL, + .calNumSamples = MIN_CAL_SAMPLES, + .calCountMax = INIT_LOG_COUNT, + .calCollect = ar5416AdcDcCalCollect, + .calPostProc = ar5416AdcDcCalibration +}; + +struct ath_hal *ar9160Attach(uint16_t devid, HAL_SOFTC sc, + HAL_BUS_TAG st, HAL_BUS_HANDLE sh, HAL_STATUS *status); +static void ar9160Detach(struct ath_hal *); +static HAL_BOOL ar9160FillCapabilityInfo(struct ath_hal *ah); + +static void +ar9160AniSetup(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, + .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, + }; + /* NB: ANI is not enabled yet */ + ar5212AniAttach(ah, &aniparams, &aniparams, AH_FALSE); +} + +/* + * Attach for an AR9160 part. + */ +struct ath_hal * +ar9160Attach(uint16_t devid, HAL_SOFTC sc, + HAL_BUS_TAG st, HAL_BUS_HANDLE sh, HAL_STATUS *status) +{ + struct ath_hal_5416 *ahp5416; + struct ath_hal_5212 *ahp; + struct ath_hal *ah; + uint32_t val; + HAL_STATUS ecode; + HAL_BOOL rfStatus; + + 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 */ + ahp5416 = ath_hal_malloc(sizeof (struct ath_hal_5416)); + if (ahp5416 == AH_NULL) { + HALDEBUG(AH_NULL, HAL_DEBUG_ANY, + "%s: cannot allocate memory for state block\n", __func__); + *status = HAL_ENOMEM; + return AH_NULL; + } + ar5416InitState(ahp5416, devid, sc, st, sh, status); + ahp = &ahp5416->ah_5212; + ah = &ahp->ah_priv.h; + + /* XXX override with 9160 specific state */ + /* override 5416 methods for our needs */ + ah->ah_detach = ar9160Detach; + + AH5416(ah)->ah_cal.iqCalData.calData = &ar9160_iq_cal; + AH5416(ah)->ah_cal.adcGainCalData.calData = &ar9160_adc_gain_cal; + AH5416(ah)->ah_cal.adcDcCalData.calData = &ar9160_adc_dc_cal; + AH5416(ah)->ah_cal.adcDcCalInitData.calData = &ar9160_adc_init_dc_cal; + AH5416(ah)->ah_cal.suppCals = ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL; + + if (!ar5416SetResetReg(ah, HAL_RESET_POWER_ON)) { + /* reset chip */ + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: couldn't reset chip\n", + __func__); + ecode = HAL_EIO; + goto bad; + } + + if (!ar5416SetPowerMode(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); + HALDEBUG(ah, HAL_DEBUG_ATTACH, + "%s: ID 0x%x VERSION 0x%x TYPE 0x%x REVISION 0x%x\n", + __func__, MS(val, AR_XSREV_ID), MS(val, AR_XSREV_VERSION), + MS(val, AR_XSREV_TYPE), MS(val, AR_XSREV_REVISION)); + /* NB: include chip type to differentiate from pre-Sowl versions */ + AH_PRIVATE(ah)->ah_macVersion = + (val & AR_XSREV_VERSION) >> AR_XSREV_TYPE_S; + AH_PRIVATE(ah)->ah_macRev = MS(val, AR_XSREV_REVISION); + /* XXX extract pcie info */ + + /* setup common ini data; rf backends handle remainder */ + HAL_INI_INIT(&ahp->ah_ini_modes, ar9160Modes, 6); + HAL_INI_INIT(&ahp->ah_ini_common, ar9160Common, 2); + + HAL_INI_INIT(&AH5416(ah)->ah_ini_bb_rfgain, ar9160BB_RfGain, 3); + HAL_INI_INIT(&AH5416(ah)->ah_ini_bank0, ar9160Bank0, 2); + HAL_INI_INIT(&AH5416(ah)->ah_ini_bank1, ar9160Bank1, 2); + HAL_INI_INIT(&AH5416(ah)->ah_ini_bank2, ar9160Bank2, 2); + HAL_INI_INIT(&AH5416(ah)->ah_ini_bank3, ar9160Bank3, 3); + HAL_INI_INIT(&AH5416(ah)->ah_ini_bank6, ar9160Bank6, 3); + HAL_INI_INIT(&AH5416(ah)->ah_ini_bank7, ar9160Bank7, 2); + if (AR_SREV_SOWL_11(ah)) + HAL_INI_INIT(&AH5416(ah)->ah_ini_addac, ar9160Addac_1_1, 2); + else + HAL_INI_INIT(&AH5416(ah)->ah_ini_addac, ar9160Addac, 2); + + if (!ar5416ChipReset(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 (!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); + switch (AH_PRIVATE(ah)->ah_analog5GhzRev & AR_RADIO_SREV_MAJOR) { + case AR_RAD2133_SREV_MAJOR: /* Sowl: 2G/3x3 */ + case AR_RAD5133_SREV_MAJOR: /* Sowl: 2+5G/3x3 */ + break; + default: + if (AH_PRIVATE(ah)->ah_analog5GhzRev == 0) { + AH_PRIVATE(ah)->ah_analog5GhzRev = + AR_RAD5133_SREV_MAJOR; + 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 + } + HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s: Attaching AR2133 radio\n", + __func__); + rfStatus = ar2133RfAttach(ah, &ecode); + if (!rfStatus) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: RF setup failed, status %u\n", + __func__, ecode); + goto bad; + } + + ecode = ath_hal_v14EepromAttach(ah); + if (ecode != HAL_OK) + goto bad; + + /* + * Got everything we need now to setup the capabilities. + */ + if (!ar9160FillCapabilityInfo(ah)) { + ecode = HAL_EEREAD; + goto bad; + } + + 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; + } + /* XXX How about the serial number ? */ + /* Read Reg Domain */ + AH_PRIVATE(ah)->ah_currentRD = + ath_hal_eepromGet(ah, AR_EEP_REGDMN_0, AH_NULL); + + /* + * ah_miscMode is populated by ar5416FillCapabilityInfo() + * starting from griffin. Set here to make sure that + * AR_MISC_MODE_MIC_NEW_LOC_ENABLE is set before a GTK is + * placed into hardware. + */ + if (ahp->ah_miscMode != 0) + OS_REG_WRITE(ah, AR_MISC_MODE, ahp->ah_miscMode); + + ar9160AniSetup(ah); /* Anti Noise Immunity */ + ar5416InitNfHistBuff(AH5416(ah)->ah_cal.nfCalHist); + + HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s: return\n", __func__); + + return ah; +bad: + if (ahp) + ar9160Detach((struct ath_hal *) ahp); + if (status) + *status = ecode; + return AH_NULL; +} + +void +ar9160Detach(struct ath_hal *ah) +{ + HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s:\n", __func__); + + HALASSERT(ah != AH_NULL); + HALASSERT(ah->ah_magic == AR5416_MAGIC); + + ar5416Detach(ah); +} + +/* + * Fill all software cached or static hardware state information. + * Return failure if capabilities are to come from EEPROM and + * cannot be read. + */ +static HAL_BOOL +ar9160FillCapabilityInfo(struct ath_hal *ah) +{ + HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps; + + if (!ar5416FillCapabilityInfo(ah)) + return AH_FALSE; + pCap->halCSTSupport = AH_TRUE; + pCap->halRifsRxSupport = AH_TRUE; + pCap->halRifsTxSupport = AH_TRUE; + pCap->halRtsAggrLimit = 64*1024; /* 802.11n max */ + pCap->halExtChanDfsSupport = AH_TRUE; + pCap->halAutoSleepSupport = AH_FALSE; /* XXX? */ + return AH_TRUE; +} + +static const char* +ar9160Probe(uint16_t vendorid, uint16_t devid) +{ + if (vendorid == ATHEROS_VENDOR_ID && devid == AR9160_DEVID_PCI) + return "Atheros 9160"; + return AH_NULL; +} +AH_CHIP(AR9160, ar9160Probe, ar9160Attach); --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5416/ar2133.c 2009-05-15 11:11:28.000000000 +0100 @@ -0,0 +1,466 @@ +/* + * 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: ar2133.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_v14.h" + +#include "ar5416/ar5416.h" +#include "ar5416/ar5416reg.h" +#include "ar5416/ar5416phy.h" + +#define N(a) (sizeof(a)/sizeof(a[0])) + +struct ar2133State { + RF_HAL_FUNCS base; /* public state, must be first */ + uint16_t pcdacTable[1]; + + uint32_t *Bank0Data; + uint32_t *Bank1Data; + uint32_t *Bank2Data; + uint32_t *Bank3Data; + uint32_t *Bank6Data; + uint32_t *Bank7Data; + + /* NB: Bank*Data storage follows */ +}; +#define AR2133(ah) ((struct ar2133State *) AH5212(ah)->ah_rfHal) + +#define ar5416ModifyRfBuffer ar5212ModifyRfBuffer /*XXX*/ + +extern void ar5416ModifyRfBuffer(uint32_t *rfBuf, uint32_t reg32, + uint32_t numBits, uint32_t firstBit, uint32_t column); +HAL_BOOL ar2133GetChipPowerLimits(struct ath_hal *ah, HAL_CHANNEL + *chans, uint32_t nchans); + +static HAL_BOOL ar2133GetChannelMaxMinPower(struct ath_hal *, HAL_CHANNEL *, + int16_t *maxPow,int16_t *minPow); +int16_t ar2133GetNfAdjust(struct ath_hal *ah, const HAL_CHANNEL_INTERNAL *c); + +static void +ar2133WriteRegs(struct ath_hal *ah, u_int modesIndex, u_int freqIndex, + int writes) +{ + (void) ath_hal_ini_write(ah, &AH5416(ah)->ah_ini_bb_rfgain, + freqIndex, writes); +} + +/* + * Take the MHz channel value and set the Channel value + * + * ASSUMES: Writes enabled to analog bus + */ +static HAL_BOOL +ar2133SetChannel(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; + CHAN_CENTERS centers; + + OS_MARK(ah, AH_MARK_SETCHANNEL, chan->channel); + + ar5416GetChannelCenters(ah, chan, ¢ers); + freq = centers.synth_center; + + if (freq < 4800) { + uint32_t txctl; + + if (((freq - 2192) % 5) == 0) { + channelSel = ((freq - 672) * 2 - 3040)/10; + bModeSynth = 0; + } else if (((freq - 2224) % 5) == 0) { + channelSel = ((freq - 704) * 2 - 3040) / 10; + bModeSynth = 1; + } else { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: invalid channel %u MHz\n", __func__, freq); + return AH_FALSE; + } + + channelSel = (channelSel << 2) & 0xff; + channelSel = ath_hal_reverseBits(channelSel, 8); + + txctl = OS_REG_READ(ah, AR_PHY_CCK_TX_CTRL); + if (freq == 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 ((freq % 20) == 0 && freq >= 5120) { + channelSel = ath_hal_reverseBits(((freq - 4800) / 20 << 2), 8); + if (AR_SREV_SOWL_10_OR_LATER(ah)) + aModeRefSel = ath_hal_reverseBits(3, 2); + else + aModeRefSel = ath_hal_reverseBits(1, 2); + } else if ((freq % 10) == 0) { + channelSel = ath_hal_reverseBits(((freq - 4800) / 10 << 1), 8); + if (AR_SREV_SOWL_10_OR_LATER(ah)) + aModeRefSel = ath_hal_reverseBits(2, 2); + else + aModeRefSel = ath_hal_reverseBits(1, 2); + } else if ((freq % 5) == 0) { + channelSel = ath_hal_reverseBits((freq - 4800) / 5, 8); + aModeRefSel = ath_hal_reverseBits(1, 2); + } else { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel %u MHz\n", + __func__, freq); + return AH_FALSE; + } + + reg32 = (channelSel << 8) | (aModeRefSel << 2) | (bModeSynth << 1) | + (1 << 5) | 0x1; + + OS_REG_WRITE(ah, AR_PHY(0x37), reg32); + + AH_PRIVATE(ah)->ah_curchan = chan; + return AH_TRUE; + +} + +/* + * Return a reference to the requested RF Bank. + */ +static uint32_t * +ar2133GetRfBank(struct ath_hal *ah, int bank) +{ + struct ar2133State *priv = AR2133(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 +ar2133SetRfRegs(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan, + uint16_t modesIndex, uint16_t *rfXpdGain) +{ + struct ar2133State *priv = AR2133(ah); + int writes; + + HALASSERT(priv); + + /* Setup Bank 0 Write */ + ath_hal_ini_bank_setup(priv->Bank0Data, &AH5416(ah)->ah_ini_bank0, 1); + + /* Setup Bank 1 Write */ + ath_hal_ini_bank_setup(priv->Bank1Data, &AH5416(ah)->ah_ini_bank1, 1); + + /* Setup Bank 2 Write */ + ath_hal_ini_bank_setup(priv->Bank2Data, &AH5416(ah)->ah_ini_bank2, 1); + + /* Setup Bank 3 Write */ + ath_hal_ini_bank_setup(priv->Bank3Data, &AH5416(ah)->ah_ini_bank3, modesIndex); + + /* Setup Bank 6 Write */ + ath_hal_ini_bank_setup(priv->Bank6Data, &AH5416(ah)->ah_ini_bank6, modesIndex); + + /* Only the 5 or 2 GHz OB/DB need to be set for a mode */ + if (IS_CHAN_2GHZ(chan)) { + ar5416ModifyRfBuffer(priv->Bank6Data, + ath_hal_eepromGet(ah, AR_EEP_OB_2, AH_NULL), 3, 197, 0); + ar5416ModifyRfBuffer(priv->Bank6Data, + ath_hal_eepromGet(ah, AR_EEP_DB_2, AH_NULL), 3, 194, 0); + } else { + ar5416ModifyRfBuffer(priv->Bank6Data, + ath_hal_eepromGet(ah, AR_EEP_OB_5, AH_NULL), 3, 203, 0); + ar5416ModifyRfBuffer(priv->Bank6Data, + ath_hal_eepromGet(ah, AR_EEP_DB_5, AH_NULL), 3, 200, 0); + } + /* Setup Bank 7 Setup */ + ath_hal_ini_bank_setup(priv->Bank7Data, &AH5416(ah)->ah_ini_bank7, 1); + + /* Write Analog registers */ + writes = ath_hal_ini_bank_write(ah, &AH5416(ah)->ah_ini_bank0, + priv->Bank0Data, 0); + writes = ath_hal_ini_bank_write(ah, &AH5416(ah)->ah_ini_bank1, + priv->Bank1Data, writes); + writes = ath_hal_ini_bank_write(ah, &AH5416(ah)->ah_ini_bank2, + priv->Bank2Data, writes); + writes = ath_hal_ini_bank_write(ah, &AH5416(ah)->ah_ini_bank3, + priv->Bank3Data, writes); + writes = ath_hal_ini_bank_write(ah, &AH5416(ah)->ah_ini_bank6, + priv->Bank6Data, writes); + (void) ath_hal_ini_bank_write(ah, &AH5416(ah)->ah_ini_bank7, + priv->Bank7Data, writes); + + 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 +ar2133SetPowerTable(struct ath_hal *ah, int16_t *pPowerMin, int16_t *pPowerMax, + HAL_CHANNEL_INTERNAL *chan, uint16_t *rfXpdGain) +{ + return AH_TRUE; +} + +#if 0 +static int16_t +ar2133GetMinPower(struct ath_hal *ah, 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); +} +#endif + +static HAL_BOOL +ar2133GetChannelMaxMinPower(struct ath_hal *ah, HAL_CHANNEL *chan, int16_t *maxPow, + int16_t *minPow) +{ +#if 0 + struct ath_hal_5212 *ahp = AH5212(ah); + int numChannels=0,i,last; + int totalD, totalF,totalMin; + EXPN_DATA_PER_CHANNEL_5112 *data=AH_NULL; + EEPROM_POWER_EXPN_5112 *powerArray=AH_NULL; + + *maxPow = 0; + if (IS_CHAN_A(chan)) { + powerArray = ahp->ah_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 = ahp->ah_modePowerArray5112; + data = powerArray[headerInfo11G].pDataPerChannel; + numChannels = powerArray[headerInfo11G].numChannels; + } else if (IS_CHAN_B(chan)) { + powerArray = ahp->ah_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) || + (chan->channel < data[0].channelValue) || + (chan->channel > data[numChannels-1].channelValue)) + return(AH_FALSE); + + /* 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 = ar2133GetMinPower(ah,&data[i]) - ar2133GetMinPower(ah, &data[last]); + *minPow = (int8_t) ((totalMin*(chan->channel-data[last].channelValue) + ar2133GetMinPower(ah, &data[last])*totalD)/totalD); + return (AH_TRUE); + } else { + if (chan->channel == data[i].channelValue) { + *maxPow = data[i].maxPower_t4; + *minPow = ar2133GetMinPower(ah, &data[i]); + return(AH_TRUE); + } else + return(AH_FALSE); + } +#else + *maxPow = *minPow = 0; + return AH_FALSE; +#endif +} + +static void +ar2133GetNoiseFloor(struct ath_hal *ah, int16_t nfarray[]) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + int16_t nf; + + switch (ahp->ah_rx_chainmask) { + case 0x7: + nf = MS(OS_REG_READ(ah, AR_PHY_CH2_CCA), AR_PHY_CH2_MINCCA_PWR); + if (nf & 0x100) + nf = 0 - ((nf ^ 0x1ff) + 1); + HALDEBUG(ah, HAL_DEBUG_NFCAL, + "NF calibrated [ctl] [chain 2] is %d\n", nf); + nfarray[4] = nf; + + nf = MS(OS_REG_READ(ah, AR_PHY_CH2_EXT_CCA), AR_PHY_CH2_EXT_MINCCA_PWR); + if (nf & 0x100) + nf = 0 - ((nf ^ 0x1ff) + 1); + HALDEBUG(ah, HAL_DEBUG_NFCAL, + "NF calibrated [ext] [chain 2] is %d\n", nf); + nfarray[5] = nf; + /* fall thru... */ + case 0x3: + case 0x5: + nf = MS(OS_REG_READ(ah, AR_PHY_CH1_CCA), AR_PHY_CH1_MINCCA_PWR); + if (nf & 0x100) + nf = 0 - ((nf ^ 0x1ff) + 1); + HALDEBUG(ah, HAL_DEBUG_NFCAL, + "NF calibrated [ctl] [chain 1] is %d\n", nf); + nfarray[2] = nf; + + + nf = MS(OS_REG_READ(ah, AR_PHY_CH1_EXT_CCA), AR_PHY_CH1_EXT_MINCCA_PWR); + if (nf & 0x100) + nf = 0 - ((nf ^ 0x1ff) + 1); + HALDEBUG(ah, HAL_DEBUG_NFCAL, + "NF calibrated [ext] [chain 1] is %d\n", nf); + nfarray[3] = nf; + /* fall thru... */ + case 0x1: + nf = MS(OS_REG_READ(ah, AR_PHY_CCA), AR_PHY_MINCCA_PWR); + if (nf & 0x100) + nf = 0 - ((nf ^ 0x1ff) + 1); + HALDEBUG(ah, HAL_DEBUG_NFCAL, + "NF calibrated [ctl] [chain 0] is %d\n", nf); + nfarray[0] = nf; + + nf = MS(OS_REG_READ(ah, AR_PHY_EXT_CCA), AR_PHY_EXT_MINCCA_PWR); + if (nf & 0x100) + nf = 0 - ((nf ^ 0x1ff) + 1); + HALDEBUG(ah, HAL_DEBUG_NFCAL, + "NF calibrated [ext] [chain 0] is %d\n", nf); + nfarray[1] = nf; + + break; + } +} + +/* + * Adjust NF based on statistical values for 5GHz frequencies. + * Stubbed:Not used by Fowl + */ +int16_t +ar2133GetNfAdjust(struct ath_hal *ah, const HAL_CHANNEL_INTERNAL *c) +{ + return 0; +} + +/* + * Free memory for analog bank scratch buffers + */ +static void +ar2133RfDetach(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 + */ +HAL_BOOL +ar2133RfAttach(struct ath_hal *ah, HAL_STATUS *status) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + struct ar2133State *priv; + uint32_t *bankData; + + HALASSERT(ahp->ah_rfHal == AH_NULL); + priv = ath_hal_malloc(sizeof(struct ar2133State) + + AH5416(ah)->ah_ini_bank0.rows * sizeof(uint32_t) + + AH5416(ah)->ah_ini_bank1.rows * sizeof(uint32_t) + + AH5416(ah)->ah_ini_bank2.rows * sizeof(uint32_t) + + AH5416(ah)->ah_ini_bank3.rows * sizeof(uint32_t) + + AH5416(ah)->ah_ini_bank6.rows * sizeof(uint32_t) + + AH5416(ah)->ah_ini_bank7.rows * sizeof(uint32_t) + ); + 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 = ar2133RfDetach; + priv->base.writeRegs = ar2133WriteRegs; + priv->base.getRfBank = ar2133GetRfBank; + priv->base.setChannel = ar2133SetChannel; + priv->base.setRfRegs = ar2133SetRfRegs; + priv->base.setPowerTable = ar2133SetPowerTable; + priv->base.getChannelMaxMinPower = ar2133GetChannelMaxMinPower; + priv->base.getNfAdjust = ar2133GetNfAdjust; + + bankData = (uint32_t *) &priv[1]; + priv->Bank0Data = bankData, bankData += AH5416(ah)->ah_ini_bank0.rows; + priv->Bank1Data = bankData, bankData += AH5416(ah)->ah_ini_bank1.rows; + priv->Bank2Data = bankData, bankData += AH5416(ah)->ah_ini_bank2.rows; + priv->Bank3Data = bankData, bankData += AH5416(ah)->ah_ini_bank3.rows; + priv->Bank6Data = bankData, bankData += AH5416(ah)->ah_ini_bank6.rows; + priv->Bank7Data = bankData, bankData += AH5416(ah)->ah_ini_bank7.rows; + + ahp->ah_pcdacTable = priv->pcdacTable; + ahp->ah_pcdacTableSize = sizeof(priv->pcdacTable); + ahp->ah_rfHal = &priv->base; + /* + * Set noise floor adjust method; we arrange a + * direct call instead of thunking. + */ + AH_PRIVATE(ah)->ah_getNfAdjust = priv->base.getNfAdjust; + AH_PRIVATE(ah)->ah_getNoiseFloor = ar2133GetNoiseFloor; + + return AH_TRUE; +} --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5416/ar5416.h 2009-05-15 11:11:28.000000000 +0100 @@ -0,0 +1,193 @@ +/* + * 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: ar5416.h,v 1.1 2009/03/23 17:14:48 sborrill Exp $ + */ +#ifndef _ATH_AR5416_H_ +#define _ATH_AR5416_H_ + +#include "ar5212/ar5212.h" +#include "ar5416_cal.h" + +#define AR5416_MAGIC 0x20065416 + +enum { + HAL_RESET_POWER_ON, + HAL_RESET_WARM, + HAL_RESET_COLD, +}; + +typedef struct { + uint16_t synth_center; + uint16_t ctl_center; + uint16_t ext_center; +} CHAN_CENTERS; + +#define AR5416_DEFAULT_RXCHAINMASK 7 +#define AR5416_DEFAULT_TXCHAINMASK 1 +#define AR5416_MAX_RATE_POWER 63 +#define AR5416_KEYTABLE_SIZE 128 + +#define AR5416_CCA_MAX_GOOD_VALUE -85 +#define AR5416_CCA_MAX_HIGH_VALUE -62 +#define AR5416_CCA_MIN_BAD_VALUE -140 + +struct ath_hal_5416 { + struct ath_hal_5212 ah_5212; + + /* NB: RF data setup at attach */ + HAL_INI_ARRAY ah_ini_bb_rfgain; + HAL_INI_ARRAY ah_ini_bank0; + HAL_INI_ARRAY ah_ini_bank1; + HAL_INI_ARRAY ah_ini_bank2; + HAL_INI_ARRAY ah_ini_bank3; + HAL_INI_ARRAY ah_ini_bank6; + HAL_INI_ARRAY ah_ini_bank7; + HAL_INI_ARRAY ah_ini_addac; + + u_int ah_globaltxtimeout; /* global tx timeout */ + int ah_hangs; /* h/w hangs state */ + uint8_t ah_keytype[AR5416_KEYTABLE_SIZE]; + /* + * Extension Channel Rx Clear State + */ + uint32_t ah_cycleCount; + uint32_t ah_ctlBusy; + uint32_t ah_extBusy; + uint32_t ah_rx_chainmask; + uint32_t ah_tx_chainmask; + + struct ar5416PerCal ah_cal; /* periodic calibration state */ +}; +#define AH5416(_ah) ((struct ath_hal_5416 *)(_ah)) + +#define IS_5416_PCI(ah) ((AH_PRIVATE(ah)->ah_macVersion) == AR_SREV_VERSION_OWL_PCI) +#define IS_5416_PCIE(ah) ((AH_PRIVATE(ah)->ah_macVersion) == AR_SREV_VERSION_OWL_PCIE) +#undef IS_PCIE +#define IS_PCIE(ah) (IS_5416_PCIE(ah)) + +extern HAL_BOOL ar2133RfAttach(struct ath_hal *, HAL_STATUS *); + +struct ath_hal; + +extern struct ath_hal * ar5416Attach(uint16_t devid, HAL_SOFTC sc, + HAL_BUS_TAG st, HAL_BUS_HANDLE sh, HAL_STATUS *status); +extern void ar5416InitState(struct ath_hal_5416 *, uint16_t devid, + HAL_SOFTC sc, HAL_BUS_TAG st, HAL_BUS_HANDLE sh, + HAL_STATUS *status); +extern void ar5416Detach(struct ath_hal *ah); +extern HAL_BOOL ar5416FillCapabilityInfo(struct ath_hal *ah); + +#define IS_5GHZ_FAST_CLOCK_EN(_ah, _c) \ + (IS_CHAN_5GHZ(_c) && ath_hal_eepromGetFlag(ah, AR_EEP_FSTCLK_5G)) + +extern void ar5416AniAttach(struct ath_hal *, const struct ar5212AniParams *, + const struct ar5212AniParams *, HAL_BOOL ena); +extern void ar5416AniDetach(struct ath_hal *); +extern HAL_BOOL ar5416AniControl(struct ath_hal *, HAL_ANI_CMD cmd, int param); +extern HAL_BOOL ar5416AniSetParams(struct ath_hal *, + const struct ar5212AniParams *, const struct ar5212AniParams *); +extern void ar5416ProcessMibIntr(struct ath_hal *, const HAL_NODE_STATS *); +extern void ar5416AniPoll(struct ath_hal *, const HAL_NODE_STATS *, + HAL_CHANNEL *); +extern void ar5416AniReset(struct ath_hal *, HAL_CHANNEL_INTERNAL *, + HAL_OPMODE, int); + +extern void ar5416SetBeaconTimers(struct ath_hal *, const HAL_BEACON_TIMERS *); +extern void ar5416BeaconInit(struct ath_hal *ah, + uint32_t next_beacon, uint32_t beacon_period); +extern void ar5416ResetStaBeaconTimers(struct ath_hal *ah); +extern void ar5416SetStaBeaconTimers(struct ath_hal *ah, + const HAL_BEACON_STATE *); + +extern HAL_BOOL ar5416EepromRead(struct ath_hal *, u_int off, uint16_t *data); +extern HAL_BOOL ar5416EepromWrite(struct ath_hal *, u_int off, uint16_t data); + +extern HAL_BOOL ar5416IsInterruptPending(struct ath_hal *ah); +extern HAL_BOOL ar5416GetPendingInterrupts(struct ath_hal *, HAL_INT *masked); +extern HAL_INT ar5416SetInterrupts(struct ath_hal *ah, HAL_INT ints); + +extern HAL_BOOL ar5416GpioCfgOutput(struct ath_hal *, uint32_t gpio); +extern HAL_BOOL ar5416GpioCfgInput(struct ath_hal *, uint32_t gpio); +extern HAL_BOOL ar5416GpioSet(struct ath_hal *, uint32_t gpio, uint32_t val); +extern uint32_t ar5416GpioGet(struct ath_hal *ah, uint32_t gpio); +extern void ar5416GpioSetIntr(struct ath_hal *ah, u_int, uint32_t ilevel); + +extern u_int ar5416GetWirelessModes(struct ath_hal *ah); +extern void ar5416SetLedState(struct ath_hal *ah, HAL_LED_STATE state); +extern void ar5416ResetTsf(struct ath_hal *ah); +extern HAL_BOOL ar5416SetAntennaSwitch(struct ath_hal *, HAL_ANT_SETTING); +extern HAL_BOOL ar5416SetDecompMask(struct ath_hal *, uint16_t, int); +extern void ar5416SetCoverageClass(struct ath_hal *, uint8_t, int); +extern uint32_t ar5416Get11nExtBusy(struct ath_hal *ah); +extern void ar5416Set11nMac2040(struct ath_hal *ah, HAL_HT_MACMODE mode); +extern HAL_HT_RXCLEAR ar5416Get11nRxClear(struct ath_hal *ah); +extern void ar5416Set11nRxClear(struct ath_hal *ah, HAL_HT_RXCLEAR rxclear); +extern HAL_STATUS ar5416GetCapability(struct ath_hal *ah, + HAL_CAPABILITY_TYPE type, uint32_t capability, uint32_t *result); +extern HAL_BOOL ar5416GetDiagState(struct ath_hal *ah, int request, + const void *args, uint32_t argsize, + void **result, uint32_t *resultsize); + +extern HAL_BOOL ar5416SetPowerMode(struct ath_hal *ah, HAL_POWER_MODE mode, + int setChip); +extern HAL_POWER_MODE ar5416GetPowerMode(struct ath_hal *ah); +extern HAL_BOOL ar5416GetPowerStatus(struct ath_hal *ah); + +extern HAL_BOOL ar5416ResetKeyCacheEntry(struct ath_hal *ah, uint16_t entry); +extern HAL_BOOL ar5416SetKeyCacheEntry(struct ath_hal *ah, uint16_t entry, + const HAL_KEYVAL *k, const uint8_t *mac, int xorKey); + +extern void ar5416StartPcuReceive(struct ath_hal *ah); +extern void ar5416StopPcuReceive(struct ath_hal *ah); +extern HAL_BOOL ar5416SetupRxDesc(struct ath_hal *, + struct ath_desc *, uint32_t size, u_int flags); +extern HAL_STATUS ar5416ProcRxDesc(struct ath_hal *ah, struct ath_desc *, + uint32_t, struct ath_desc *, uint64_t, + struct ath_rx_status *); + +extern HAL_BOOL ar5416Reset(struct ath_hal *ah, HAL_OPMODE opmode, + HAL_CHANNEL *chan, HAL_BOOL bChannelChange, HAL_STATUS *status); +extern HAL_BOOL ar5416PhyDisable(struct ath_hal *ah); +extern HAL_RFGAIN ar5416GetRfgain(struct ath_hal *ah); +extern HAL_BOOL ar5416Disable(struct ath_hal *ah); +extern HAL_BOOL ar5416ChipReset(struct ath_hal *ah, HAL_CHANNEL *); +extern HAL_BOOL ar5416SetResetReg(struct ath_hal *, uint32_t type); +extern HAL_BOOL ar5416SetTxPowerLimit(struct ath_hal *ah, uint32_t limit); +extern HAL_BOOL ar5416GetChipPowerLimits(struct ath_hal *ah, + HAL_CHANNEL *chans, uint32_t nchans); +extern void ar5416GetChannelCenters(struct ath_hal *, + HAL_CHANNEL_INTERNAL *chan, CHAN_CENTERS *centers); + +extern HAL_BOOL ar5416StopTxDma(struct ath_hal *ah, u_int q); +extern HAL_BOOL ar5416SetupTxDesc(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 ar5416SetupXTxDesc(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 ar5416FillTxDesc(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 ar5416ProcTxDesc(struct ath_hal *ah, + struct ath_desc *, struct ath_tx_status *); + +extern const HAL_RATE_TABLE *ar5416GetRateTable(struct ath_hal *, u_int mode); +#endif /* _ATH_AR5416_H_ */ --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5416/ar5416.ini 2009-05-15 11:11:28.000000000 +0100 @@ -0,0 +1,688 @@ +/* + * 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: ar5416.ini,v 1.1 2009/03/23 17:14:48 sborrill Exp $ + */ +/* Auto Generated PCI Register Writes. Created: 09/20/06 */ + +static const uint32_t ar5416Modes[][6] = { + /* Register A A-20/40 G-20/40 G G-Turbo */ + { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, + { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, + { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 }, + { 0x000010f0, 0x0000a000, 0x00014000, 0x00016000, 0x0000b000, 0x00014008 }, + { 0x00008014, 0x03e803e8, 0x07d007d0, 0x10801080, 0x08400840, 0x06e006e0 }, + { 0x0000801c, 0x128d93a7, 0x128d93cf, 0x12e013d7, 0x12e013ab, 0x098813cf }, + { 0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303 }, + { 0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200 }, + { 0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, + { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 }, + { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, + { 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 }, + { 0x00009844, 0x1372161e, 0x13721c1e, 0x13721c30, 0x137216a4, 0x13721c25 }, + { 0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, + { 0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, + { 0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, + { 0x00009850, 0x6c28b4e0, 0x6c28b4e0, 0x6d68b0de, 0x6d68b0de, 0x6c28b0de }, + { 0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e }, + { 0x0000985c, 0x313a5d5e, 0x313a5d5e, 0x313a605e, 0x313a605e, 0x313a5d5e }, + { 0x00009860, 0x00049d10, 0x00049d10, 0x00049d20, 0x00049d20, 0x00049d10 }, + { 0x0000c864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 }, + { 0x00009868, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190 }, + { 0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 }, + { 0x00009914, 0x000007d0, 0x000007d0, 0x00000898, 0x00000898, 0x000007d0 }, + { 0x00009918, 0x000001b8, 0x00000370, 0x00000268, 0x00000134, 0x00000370 }, + { 0x00009924, 0xd0058a0b, 0xd0058a0b, 0xd0058a19, 0xd0058a13, 0xd0058a0b }, + { 0x00009944, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020 }, +#ifdef TB243 + { 0x00009960, 0x00000900, 0x00000900, 0x00009b40, 0x00009b40, 0x00012d80 }, + { 0x0000a960, 0x00000900, 0x00000900, 0x00009b40, 0x00009b40, 0x00012d80 }, + { 0x0000b960, 0x00000900, 0x00000900, 0x00009b40, 0x00009b40, 0x00012d80 }, + { 0x00009964, 0x00000000, 0x00000000, 0x00002210, 0x00002210, 0x00001120 }, +#else + { 0x00009960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80 }, + { 0x0000a960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80 }, + { 0x0000b960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80 }, +#ifdef __LINUX_ARM_ARCH__ + { 0x00009964, 0x00000000, 0x00000000, 0x00001120, 0x00001120, 0x00001120 }, +#else + { 0x00009964, 0x00000000, 0x00000000, 0x00001120, 0x00001120, 0x00001120 }, +#endif +#endif + { 0x0000c9bc, 0x001a0a00, 0x001a0a00, 0x001a0a00, 0x001a0a00, 0x001a0a00 }, + { 0x000099c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, 0x038919be }, + { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 }, + { 0x000099c8, 0x60f6532c, 0x60f6532c, 0x60f6532c, 0x60f6532c, 0x60f6532c }, + { 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 }, + { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 }, + { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a204, 0x00000440, 0x00000440, 0x00000440, 0x00000440, 0x00000440 }, + { 0x0000a208, 0xd6be4788, 0xd6be4788, 0xd03e4788, 0xd03e4788, 0xd03e4788 }, + { 0x0000a20c, 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120, 0x002ac120 }, + { 0x0000b20c, 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120, 0x002ac120 }, + { 0x0000c20c, 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120, 0x002ac120 }, + { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a }, + { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 }, + { 0x0000a274, 0x0a1a9caa, 0x0a1a9caa, 0x0a1a7caa, 0x0a1a7caa, 0x0a1a7caa }, + { 0x0000a300, 0x18010000, 0x18010000, 0x18010000, 0x18010000, 0x18010000 }, + { 0x0000a304, 0x30032602, 0x30032602, 0x2e032402, 0x2e032402, 0x2e032402 }, + { 0x0000a308, 0x48073e06, 0x48073e06, 0x4a0a3c06, 0x4a0a3c06, 0x4a0a3c06 }, + { 0x0000a30c, 0x560b4c0a, 0x560b4c0a, 0x621a540b, 0x621a540b, 0x621a540b }, + { 0x0000a310, 0x641a600f, 0x641a600f, 0x764f6c1b, 0x764f6c1b, 0x764f6c1b }, + { 0x0000a314, 0x7a4f6e1b, 0x7a4f6e1b, 0x845b7a5a, 0x845b7a5a, 0x845b7a5a }, + { 0x0000a318, 0x8c5b7e5a, 0x8c5b7e5a, 0x950f8ccf, 0x950f8ccf, 0x950f8ccf }, + { 0x0000a31c, 0x9d0f96cf, 0x9d0f96cf, 0xa5cf9b4f, 0xa5cf9b4f, 0xa5cf9b4f }, + { 0x0000a320, 0xb51fa69f, 0xb51fa69f, 0xbddfaf1f, 0xbddfaf1f, 0xbddfaf1f }, + { 0x0000a324, 0xcb3fbd07, 0xcb3fbcbf, 0xd1ffc93f, 0xd1ffc93f, 0xd1ffc93f }, + { 0x0000a328, 0x0000d7bf, 0x0000d7bf, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a32c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a330, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a334, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, +}; + +static const uint32_t ar5416Common[][2] = { + { 0x0000000c, 0x00000000 }, + { 0x00000030, 0x00020015 }, + { 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 }, + { 0x00001040, 0x002ffc0f }, + { 0x00001044, 0x002ffc0f }, + { 0x00001048, 0x002ffc0f }, + { 0x0000104c, 0x002ffc0f }, + { 0x00001050, 0x002ffc0f }, + { 0x00001054, 0x002ffc0f }, + { 0x00001058, 0x002ffc0f }, + { 0x0000105c, 0x002ffc0f }, + { 0x00001060, 0x002ffc0f }, + { 0x00001064, 0x002ffc0f }, + { 0x00001230, 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 }, + { 0x00004030, 0x00000002 }, + { 0x0000403c, 0x00000002 }, +#ifdef AR9100 + { 0x00020010, 0x00000000 }, +#else + { 0x00007010, 0x00000000 }, +#endif + { 0x00007038, 0x000004c2 }, + { 0x00008004, 0x00000000 }, + { 0x00008008, 0x00000000 }, + { 0x0000800c, 0x00000000 }, + { 0x00008018, 0x00000700 }, + { 0x00008020, 0x00000000 }, + { 0x00008038, 0x00000000 }, + { 0x0000803c, 0x00000000 }, + { 0x00008048, 0x40000000 }, + { 0x00008054, 0x00000000 }, + { 0x00008058, 0x00000000 }, + { 0x0000805c, 0x000fc78f }, + { 0x00008060, 0x0000000f }, + { 0x00008064, 0x00000000 }, + { 0x000080c0, 0x2a82301a }, + { 0x000080c4, 0x05dc01e0 }, + { 0x000080c8, 0x1f402710 }, + { 0x000080cc, 0x01f40000 }, + { 0x000080d0, 0x00001e00 }, + { 0x000080d4, 0x00000000 }, + { 0x000080d8, 0x00400000 }, + { 0x000080e0, 0xffffffff }, + { 0x000080e4, 0x0000ffff }, + { 0x000080e8, 0x003f3f3f }, + { 0x000080ec, 0x00000000 }, + { 0x000080f0, 0x00000000 }, + { 0x000080f4, 0x00000000 }, + { 0x000080f8, 0x00000000 }, + { 0x000080fc, 0x00020000 }, + { 0x00008100, 0x00020000 }, + { 0x00008104, 0x00000001 }, + { 0x00008108, 0x00000052 }, + { 0x0000810c, 0x00000000 }, + { 0x00008110, 0x00000168 }, + { 0x00008118, 0x000100aa }, + { 0x0000811c, 0x00003210 }, + { 0x00008120, 0x08f04800 }, + { 0x00008124, 0x00000000 }, + { 0x00008128, 0x00000000 }, + { 0x0000812c, 0x00000000 }, + { 0x00008130, 0x00000000 }, + { 0x00008134, 0x00000000 }, + { 0x00008138, 0x00000000 }, + { 0x0000813c, 0x00000000 }, + { 0x00008144, 0x00000000 }, + { 0x00008168, 0x00000000 }, + { 0x0000816c, 0x00000000 }, + { 0x00008170, 0x32143320 }, + { 0x00008174, 0xfaa4fa50 }, + { 0x00008178, 0x00000100 }, + { 0x0000817c, 0x00000000 }, + { 0x000081c4, 0x00000000 }, + { 0x000081d0, 0x00003210 }, + { 0x000081ec, 0x00000000 }, + { 0x000081f0, 0x00000000 }, + { 0x000081f4, 0x00000000 }, + { 0x000081f8, 0x00000000 }, + { 0x000081fc, 0x00000000 }, + { 0x00008200, 0x00000000 }, + { 0x00008204, 0x00000000 }, + { 0x00008208, 0x00000000 }, + { 0x0000820c, 0x00000000 }, + { 0x00008210, 0x00000000 }, + { 0x00008214, 0x00000000 }, + { 0x00008218, 0x00000000 }, + { 0x0000821c, 0x00000000 }, + { 0x00008220, 0x00000000 }, + { 0x00008224, 0x00000000 }, + { 0x00008228, 0x00000000 }, + { 0x0000822c, 0x00000000 }, + { 0x00008230, 0x00000000 }, + { 0x00008234, 0x00000000 }, + { 0x00008238, 0x00000000 }, + { 0x0000823c, 0x00000000 }, + { 0x00008240, 0x00100000 }, + { 0x00008244, 0x0010f400 }, + { 0x00008248, 0x00000100 }, + { 0x0000824c, 0x0001e800 }, + { 0x00008250, 0x00000000 }, + { 0x00008254, 0x00000000 }, + { 0x00008258, 0x00000000 }, + { 0x0000825c, 0x400000ff }, + { 0x00008260, 0x00080922 }, + { 0x00008270, 0x00000000 }, + { 0x00008274, 0x40000000 }, + { 0x00008278, 0x003e4180 }, + { 0x0000827c, 0x00000000 }, + { 0x00008284, 0x0000002c }, + { 0x00008288, 0x0000002c }, + { 0x0000828c, 0x00000000 }, + { 0x00008294, 0x00000000 }, + { 0x00008298, 0x00000000 }, + { 0x00008300, 0x00000000 }, + { 0x00008304, 0x00000000 }, + { 0x00008308, 0x00000000 }, + { 0x0000830c, 0x00000000 }, + { 0x00008310, 0x00000000 }, + { 0x00008314, 0x00000000 }, + { 0x00008318, 0x00000000 }, + { 0x00008328, 0x00000000 }, + { 0x0000832c, 0x00000007 }, + { 0x00008330, 0x00000302 }, + { 0x00008334, 0x00000e00 }, + { 0x00008338, 0x00000000 }, + { 0x0000833c, 0x00000000 }, + { 0x00008340, 0x000107ff }, + { 0x00009808, 0x00000000 }, + { 0x0000980c, 0xad848e19 }, + { 0x00009810, 0x7d14e000 }, + { 0x00009814, 0x9c0a9f6b }, + { 0x0000981c, 0x00000000 }, + { 0x0000982c, 0x0000a000 }, + { 0x00009830, 0x00000000 }, + { 0x0000983c, 0x00200400 }, + { 0x00009840, 0x206a016e }, + { 0x0000984c, 0x1284233c }, + { 0x00009854, 0x00000859 }, + { 0x00009900, 0x00000000 }, + { 0x00009904, 0x00000000 }, + { 0x00009908, 0x00000000 }, + { 0x0000990c, 0x00000000 }, + { 0x0000991c, 0x10000fff }, + { 0x00009920, 0x05100000 }, + { 0x0000a920, 0x05100000 }, + { 0x0000b920, 0x05100000 }, + { 0x00009928, 0x00000001 }, + { 0x0000992c, 0x00000004 }, + { 0x00009934, 0x1e1f2022 }, + { 0x00009938, 0x0a0b0c0d }, + { 0x0000993c, 0x00000000 }, + { 0x00009948, 0x9280b212 }, + { 0x0000994c, 0x00020028 }, + { 0x00009954, 0x5d50e188 }, + { 0x00009958, 0x00081fff }, + { 0x0000c95c, 0x004b6a8e }, + { 0x0000c968, 0x000003ce }, + { 0x00009970, 0x190c0514 }, + { 0x00009974, 0x00000000 }, + { 0x00009978, 0x00000001 }, + { 0x0000997c, 0x00000000 }, + { 0x00009980, 0x00000000 }, + { 0x00009984, 0x00000000 }, + { 0x00009988, 0x00000000 }, + { 0x0000998c, 0x00000000 }, + { 0x00009990, 0x00000000 }, + { 0x00009994, 0x00000000 }, + { 0x00009998, 0x00000000 }, + { 0x0000999c, 0x00000000 }, + { 0x000099a0, 0x00000000 }, + { 0x000099a4, 0x00000001 }, + { 0x000099a8, 0x001fff00 }, + { 0x000099ac, 0x000000c4 }, + { 0x000099b0, 0x03051000 }, + { 0x000099dc, 0x00000000 }, + { 0x000099e0, 0x00000200 }, + { 0x000099e4, 0xaaaaaaaa }, + { 0x000099e8, 0x3c466478 }, + { 0x000099ec, 0x000000aa }, + { 0x000099fc, 0x00001042 }, + { 0x00009b00, 0x00000000 }, + { 0x00009b04, 0x00000001 }, + { 0x00009b08, 0x00000002 }, + { 0x00009b0c, 0x00000003 }, + { 0x00009b10, 0x00000004 }, + { 0x00009b14, 0x00000005 }, + { 0x00009b18, 0x00000008 }, + { 0x00009b1c, 0x00000009 }, + { 0x00009b20, 0x0000000a }, + { 0x00009b24, 0x0000000b }, + { 0x00009b28, 0x0000000c }, + { 0x00009b2c, 0x0000000d }, + { 0x00009b30, 0x00000010 }, + { 0x00009b34, 0x00000011 }, + { 0x00009b38, 0x00000012 }, + { 0x00009b3c, 0x00000013 }, + { 0x00009b40, 0x00000014 }, + { 0x00009b44, 0x00000015 }, + { 0x00009b48, 0x00000018 }, + { 0x00009b4c, 0x00000019 }, + { 0x00009b50, 0x0000001a }, + { 0x00009b54, 0x0000001b }, + { 0x00009b58, 0x0000001c }, + { 0x00009b5c, 0x0000001d }, + { 0x00009b60, 0x00000020 }, + { 0x00009b64, 0x00000021 }, + { 0x00009b68, 0x00000022 }, + { 0x00009b6c, 0x00000023 }, + { 0x00009b70, 0x00000024 }, + { 0x00009b74, 0x00000025 }, + { 0x00009b78, 0x00000028 }, + { 0x00009b7c, 0x00000029 }, + { 0x00009b80, 0x0000002a }, + { 0x00009b84, 0x0000002b }, + { 0x00009b88, 0x0000002c }, + { 0x00009b8c, 0x0000002d }, + { 0x00009b90, 0x00000030 }, + { 0x00009b94, 0x00000031 }, + { 0x00009b98, 0x00000032 }, + { 0x00009b9c, 0x00000033 }, + { 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 }, + { 0x0000a210, 0x40806333 }, + { 0x0000a214, 0x00106c10 }, + { 0x0000a218, 0x009c4060 }, + { 0x0000a220, 0x018830c6 }, + { 0x0000a224, 0x00000400 }, + { 0x0000a228, 0x00000bb5 }, + { 0x0000a22c, 0x00000011 }, + { 0x0000a234, 0x20202020 }, + { 0x0000a238, 0x20202020 }, + { 0x0000a23c, 0x13c889af }, + { 0x0000a240, 0x38490a20 }, + { 0x0000a244, 0x00007bb6 }, + { 0x0000a248, 0x0fff3ffc }, + { 0x0000a24c, 0x00000001 }, + { 0x0000a250, 0x0000a000 }, + { 0x0000a254, 0x00000000 }, + { 0x0000a258, 0x0cc75380 }, + { 0x0000a25c, 0x0f0f0f01 }, + { 0x0000a260, 0xdfa91f01 }, + { 0x0000a268, 0x00000000 }, + { 0x0000a26c, 0x0ebae9c6 }, + { 0x0000b26c, 0x0ebae9c6 }, + { 0x0000c26c, 0x0ebae9c6 }, + { 0x0000d270, 0x00820820 }, + { 0x0000a278, 0x1ce739ce }, + { 0x0000a27c, 0x051701ce }, + { 0x0000a338, 0x00000000 }, + { 0x0000a33c, 0x00000000 }, + { 0x0000a340, 0x00000000 }, + { 0x0000a344, 0x00000000 }, + { 0x0000a348, 0x3fffffff }, + { 0x0000a34c, 0x3fffffff }, + { 0x0000a350, 0x3fffffff }, + { 0x0000a354, 0x0003ffff }, + { 0x0000a358, 0x79a8aa1f }, + { 0x0000d35c, 0x066c420f }, + { 0x0000d360, 0x0f282207 }, + { 0x0000d364, 0x17601685 }, + { 0x0000d368, 0x1f801104 }, + { 0x0000d36c, 0x37a00c03 }, + { 0x0000d370, 0x3fc40883 }, + { 0x0000d374, 0x57c00803 }, + { 0x0000d378, 0x5fd80682 }, + { 0x0000d37c, 0x7fe00482 }, + { 0x0000d380, 0x7f3c7bba }, + { 0x0000d384, 0xf3307ff0 }, + { 0x0000a388, 0x08000000 }, + { 0x0000a38c, 0x20202020 }, + { 0x0000a390, 0x20202020 }, + { 0x0000a394, 0x1ce739ce }, + { 0x0000a398, 0x000001ce }, + { 0x0000a39c, 0x00000001 }, + { 0x0000a3a0, 0x00000000 }, + { 0x0000a3a4, 0x00000000 }, + { 0x0000a3a8, 0x00000000 }, + { 0x0000a3ac, 0x00000000 }, + { 0x0000a3b0, 0x00000000 }, + { 0x0000a3b4, 0x00000000 }, + { 0x0000a3b8, 0x00000000 }, + { 0x0000a3bc, 0x00000000 }, + { 0x0000a3c0, 0x00000000 }, + { 0x0000a3c4, 0x00000000 }, + { 0x0000a3c8, 0x00000246 }, + { 0x0000a3cc, 0x20202020 }, + { 0x0000a3d0, 0x20202020 }, + { 0x0000a3d4, 0x20202020 }, + { 0x0000a3dc, 0x1ce739ce }, + { 0x0000a3e0, 0x000001ce }, +}; + +static const uint32_t ar5416Bank0[][2] = { + { 0x000098b0, 0x1e5795e5 }, + { 0x000098e0, 0x02008020 }, +}; + +static const uint32_t ar5416BB_RfGain[][3] = { + { 0x00009a00, 0x00000000, 0x00000000 }, + { 0x00009a04, 0x00000040, 0x00000040 }, + { 0x00009a08, 0x00000080, 0x00000080 }, + { 0x00009a0c, 0x000001a1, 0x00000141 }, + { 0x00009a10, 0x000001e1, 0x00000181 }, + { 0x00009a14, 0x00000021, 0x000001c1 }, + { 0x00009a18, 0x00000061, 0x00000001 }, + { 0x00009a1c, 0x00000168, 0x00000041 }, + { 0x00009a20, 0x000001a8, 0x000001a8 }, + { 0x00009a24, 0x000001e8, 0x000001e8 }, + { 0x00009a28, 0x00000028, 0x00000028 }, + { 0x00009a2c, 0x00000068, 0x00000068 }, + { 0x00009a30, 0x00000189, 0x000000a8 }, + { 0x00009a34, 0x000001c9, 0x00000169 }, + { 0x00009a38, 0x00000009, 0x000001a9 }, + { 0x00009a3c, 0x00000049, 0x000001e9 }, + { 0x00009a40, 0x00000089, 0x00000029 }, + { 0x00009a44, 0x00000170, 0x00000069 }, + { 0x00009a48, 0x000001b0, 0x00000190 }, + { 0x00009a4c, 0x000001f0, 0x000001d0 }, + { 0x00009a50, 0x00000030, 0x00000010 }, + { 0x00009a54, 0x00000070, 0x00000050 }, + { 0x00009a58, 0x00000191, 0x00000090 }, + { 0x00009a5c, 0x000001d1, 0x00000151 }, + { 0x00009a60, 0x00000011, 0x00000191 }, + { 0x00009a64, 0x00000051, 0x000001d1 }, + { 0x00009a68, 0x00000091, 0x00000011 }, + { 0x00009a6c, 0x000001b8, 0x00000051 }, + { 0x00009a70, 0x000001f8, 0x00000198 }, + { 0x00009a74, 0x00000038, 0x000001d8 }, + { 0x00009a78, 0x00000078, 0x00000018 }, + { 0x00009a7c, 0x00000199, 0x00000058 }, + { 0x00009a80, 0x000001d9, 0x00000098 }, + { 0x00009a84, 0x00000019, 0x00000159 }, + { 0x00009a88, 0x00000059, 0x00000199 }, + { 0x00009a8c, 0x00000099, 0x000001d9 }, + { 0x00009a90, 0x000000d9, 0x00000019 }, + { 0x00009a94, 0x000000f9, 0x00000059 }, + { 0x00009a98, 0x000000f9, 0x00000099 }, + { 0x00009a9c, 0x000000f9, 0x000000d9 }, + { 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 }, +}; + +static const uint32_t ar5416Bank1[][2] = { + { 0x000098b0, 0x02108421 }, + { 0x000098ec, 0x00000008 }, +}; + +static const uint32_t ar5416Bank2[][2] = { + { 0x000098b0, 0x0e73ff17 }, + { 0x000098e0, 0x00000420 }, +}; + +static const uint32_t ar5416Bank3[][3] = { + { 0x000098f0, 0x01400018, 0x01c00018 }, +}; + +#ifdef USE_NONTPC_BANK +static const uint32_t ar5416Bank6[][3] = { +/* Reg A G */ + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00e00000, 0x00e00000 }, + { 0x0000989c, 0x005e0000, 0x005e0000 }, + { 0x0000989c, 0x00120000, 0x00120000 }, + { 0x0000989c, 0x00620000, 0x00620000 }, + { 0x0000989c, 0x00020000, 0x00020000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x40ff0000, 0x40ff0000 }, + { 0x0000989c, 0x005f0000, 0x005f0000 }, + { 0x0000989c, 0x00870000, 0x00870000 }, + { 0x0000989c, 0x00f90000, 0x00f90000 }, + { 0x0000989c, 0x007b0000, 0x007b0000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x00f50000, 0x00f50000 }, + { 0x0000989c, 0x00dc0000, 0x00dc0000 }, + { 0x0000989c, 0x00110000, 0x00110000 }, + { 0x0000989c, 0x006100a8, 0x006100a8 }, + { 0x0000989c, 0x004210a2, 0x004210a2 }, + { 0x0000989c, 0x0014008f, 0x0014008f }, + { 0x0000989c, 0x00c40003, 0x00c40003 }, + { 0x0000989c, 0x003000f2, 0x003000f2 }, + { 0x0000989c, 0x00440016, 0x00440016 }, + { 0x0000989c, 0x00410040, 0x00410040 }, + { 0x0000989c, 0x0001805e, 0x0001805e }, + { 0x0000989c, 0x0000c0ab, 0x0000c0ab }, + { 0x0000989c, 0x000000f1, 0x000000f1 }, + { 0x0000989c, 0x00002081, 0x00002081 }, + { 0x0000989c, 0x000000d4, 0x000000d4 }, + { 0x000098d0, 0x0000000f, 0x0010000f }, +}; + +#else +/* TPC bank */ +static const uint32_t ar5416Bank6[][3] = { +/* Reg A G */ + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00e00000, 0x00e00000 }, + { 0x0000989c, 0x005e0000, 0x005e0000 }, + { 0x0000989c, 0x00120000, 0x00120000 }, + { 0x0000989c, 0x00620000, 0x00620000 }, + { 0x0000989c, 0x00020000, 0x00020000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x40ff0000, 0x40ff0000 }, + { 0x0000989c, 0x005f0000, 0x005f0000 }, + { 0x0000989c, 0x00870000, 0x00870000 }, + { 0x0000989c, 0x00f90000, 0x00f90000 }, + { 0x0000989c, 0x007b0000, 0x007b0000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x00f50000, 0x00f50000 }, + { 0x0000989c, 0x00dc0000, 0x00dc0000 }, + { 0x0000989c, 0x00110000, 0x00110000 }, + { 0x0000989c, 0x006100a8, 0x006100a8 }, + { 0x0000989c, 0x00421022, 0x00421022 }, + { 0x0000989c, 0x001400df, 0x001400df }, + { 0x0000989c, 0x00c40002, 0x00c40002 }, + { 0x0000989c, 0x003000f2, 0x003000f2 }, + { 0x0000989c, 0x00440016, 0x00440016 }, + { 0x0000989c, 0x00410040, 0x00410040 }, + { 0x0000989c, 0x0001805e, 0x0001805e }, + { 0x0000989c, 0x0000c0ab, 0x0000c0ab }, + { 0x0000989c, 0x000000e1, 0x000000e1 }, + { 0x0000989c, 0x00002081, 0x00002081 }, + { 0x0000989c, 0x000000d4, 0x000000d4 }, + { 0x000098d0, 0x0000000f, 0x0010000f }, +}; + +#endif + +static const uint32_t ar5416Bank7[][2] = { + { 0x0000989c, 0x00000500 }, + { 0x0000989c, 0x00000800 }, + { 0x000098cc, 0x0000000e }, +}; + +static const uint32_t ar5416Addac[][2] = { + {0x0989c, 0x00000000 }, + {0x0989c, 0x00000003 }, + {0x0989c, 0x00000000 }, + {0x0989c, 0x0000000c }, + {0x0989c, 0x00000000 }, + {0x0989c, 0x00000030 }, + {0x0989c, 0x00000000 }, + {0x0989c, 0x00000000 }, + {0x0989c, 0x00000000 }, + {0x0989c, 0x00000000 }, + {0x0989c, 0x00000000 }, + {0x0989c, 0x00000000 }, + {0x0989c, 0x00000000 }, + {0x0989c, 0x00000000 }, + {0x0989c, 0x00000000 }, + {0x0989c, 0x00000000 }, + {0x0989c, 0x00000000 }, + {0x0989c, 0x00000000 }, + {0x0989c, 0x00000060 }, + {0x0989c, 0x00000000 }, + {0x0989c, 0x00000000 }, + {0x0989c, 0x00000000 }, + {0x0989c, 0x00000000 }, + {0x0989c, 0x00000000 }, + {0x0989c, 0x00000000 }, + {0x0989c, 0x00000000 }, + {0x0989c, 0x00000000 }, + {0x0989c, 0x00000000 }, + {0x0989c, 0x00000000 }, + {0x0989c, 0x00000000 }, + {0x0989c, 0x00000000 }, + {0x0989c, 0x00000058 }, + {0x0989c, 0x00000000 }, + {0x0989c, 0x00000000 }, + {0x0989c, 0x00000000 }, + {0x0989c, 0x00000000 }, + {0x098c4, 0x00000000 }, +}; --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5416/ar5416_ani.c 2009-05-15 11:11:28.000000000 +0100 @@ -0,0 +1,886 @@ +/* + * 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: ar5416_ani.c,v 1.1 2009/03/23 17:14:48 sborrill Exp $ + */ +#include "opt_ah.h" + +/* + * XXX this is virtually the same code as for 5212; we reuse + * storage in the 5212 state block; need to refactor. + */ +#include "ah.h" +#include "ah_internal.h" +#include "ah_desc.h" + +#include "ar5416/ar5416.h" +#include "ar5416/ar5416reg.h" +#include "ar5416/ar5416phy.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_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); + OS_REG_WRITE(ah, AR_PHY_ERR_MASK_2, 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_PHY_ERR_MASK_1, 0); + OS_REG_WRITE(ah, AR_PHY_ERR_MASK_2, 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 +ar5416GetAniChannelIndex(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 +} + +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 ar5416AniReset should be + * called by ar5416Reset before anything else happens and + * that's where we force initial settings. + */ +void +ar5416AniAttach(struct ath_hal *ah, const struct ar5212AniParams *params24, + const struct ar5212AniParams *params5, HAL_BOOL enable) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + + 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)); + /* 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; + } +} + +/* + * Cleanup any ANI state setup. + */ +void +ar5416AniDetach(struct ath_hal *ah) +{ + HALDEBUG(ah, HAL_DEBUG_ANI, "Detaching Ani\n"); + disableAniMIBCounters(ah); +} + +/* + * Control Adaptive Noise Immunity Parameters + */ +HAL_BOOL +ar5416AniControl(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]); + + OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, + AR_PHY_SFCORR_EXT_M1_THRESH_LOW, m1ThreshLow[on]); + OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, + AR_PHY_SFCORR_EXT_M2_THRESH_LOW, m2ThreshLow[on]); + OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, + AR_PHY_SFCORR_EXT_M1_THRESH, m1Thresh[on]); + OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, + AR_PHY_SFCORR_EXT_M2_THRESH, m2Thresh[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 */ + ar5416AniDetach(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; + 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*/); + 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 +ar5416AniOfdmErrTrigger(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) { + ar5416AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL, + aniState->noiseImmunityLevel + 1); + return; + } + /* then, raise spur immunity level, up to max */ + if (aniState->spurImmunityLevel+1 < params->maxSpurImmunityLevel) { + ar5416AniControl(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) { + ar5416AniControl(ah, + HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, + AH_FALSE); + ar5416AniControl(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) { + ar5416AniControl(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) + ar5416AniControl(ah, + HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, + AH_TRUE); + if (aniState->firstepLevel+1 < params->maxFirstepLevel) + ar5416AniControl(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) + ar5416AniControl(ah, + HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, + AH_FALSE); + if (aniState->firstepLevel > 0) + ar5416AniControl(ah, + HAL_ANI_FIRSTEP_LEVEL, 0); + return; + } + } + } +} + +static void +ar5416AniCckErrTrigger(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) { + ar5416AniControl(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) + ar5416AniControl(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) + ar5416AniControl(ah, + HAL_ANI_FIRSTEP_LEVEL, 0); + } + } + } +} + +static void +ar5416AniRestart(struct ath_hal *ah, struct ar5212AniState *aniState) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + const struct ar5212AniParams *params = aniState->params; + + aniState->listenTime = 0; + /* + * NB: these are written on reset based on the + * ini so we must re-write them! + */ + HALDEBUG(ah, HAL_DEBUG_ANI, + "%s: Writing ofdmbase=%u cckbase=%u\n", __func__, + params->ofdmPhyErrBase, params->cckPhyErrBase); + OS_REG_WRITE(ah, AR_PHY_ERR_1, params->ofdmPhyErrBase); + OS_REG_WRITE(ah, AR_PHY_ERR_2, params->cckPhyErrBase); + OS_REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); + OS_REG_WRITE(ah, AR_PHY_ERR_MASK_1, 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 +ar5416AniReset(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 = ar5416GetAniChannelIndex(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) { + ar5416AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL, + aniState->noiseImmunityLevel); + ar5416AniControl(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL, + aniState->spurImmunityLevel); + ar5416AniControl(ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, + !aniState->ofdmWeakSigDetectOff); + ar5416AniControl(ah, HAL_ANI_CCK_WEAK_SIGNAL_THR, + aniState->cckWeakSigThreshold); + ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, + aniState->firstepLevel); + } else { + ar5416AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL, 0); + ar5416AniControl(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL, 0); + ar5416AniControl(ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, + AH_TRUE); + ar5416AniControl(ah, HAL_ANI_CCK_WEAK_SIGNAL_THR, AH_FALSE); + ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, 0); + aniState->isSetup = AH_TRUE; + } + ar5416AniRestart(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 +ar5416ProcessMibIntr(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_PHY_ERR_1); + phyCnt2 = OS_REG_READ(ah, AR_PHY_ERR_2); + /* 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); + if ((OS_REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING) == 0) + OS_REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR); + + /* 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) + ar5416AniOfdmErrTrigger(ah); + if (aniState->cckPhyErrCount > params->cckTrigHigh) + ar5416AniCckErrTrigger(ah); + /* NB: always restart to insure the h/w counters are reset */ + ar5416AniRestart(ah, aniState); + } +} + +static void +ar5416AniLowerImmunity(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) { + ar5416AniControl(ah, + HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, + AH_TRUE); + return; + } + if (aniState->firstepLevel > 0) { + ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, + aniState->firstepLevel - 1); + return; + } + } else { + /* + * Beacon rssi is low, reduce firstep level. + */ + if (aniState->firstepLevel > 0) { + ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, + aniState->firstepLevel - 1); + return; + } + } + } + /* then lower spur immunity level, down to zero */ + if (aniState->spurImmunityLevel > 0) { + ar5416AniControl(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) { + ar5416AniControl(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 +ar5416AniGetListenTime(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; + + /* 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_PHY_ERR_1); + phyCnt2 = OS_REG_READ(ah, AR_PHY_ERR_2); + + /* 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 +ar5416AniPoll(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 = ar5416AniGetListenTime(ah); + if (listenTime < 0) { + ahp->ah_stats.ast_ani_lneg++; + /* restart ANI period if listenTime is invalid */ + ar5416AniRestart(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 + */ + updateMIBStats(ah, aniState); + if (aniState->ofdmPhyErrCount <= aniState->listenTime * + params->ofdmTrigLow/1000 && + aniState->cckPhyErrCount <= aniState->listenTime * + params->cckTrigLow/1000) + ar5416AniLowerImmunity(ah); + ar5416AniRestart(ah, aniState); + } else if (aniState->listenTime > params->period) { + updateMIBStats(ah, aniState); + /* check to see if need to raise immunity */ + if (aniState->ofdmPhyErrCount > aniState->listenTime * + params->ofdmTrigHigh / 1000) { + ar5416AniOfdmErrTrigger(ah); + ar5416AniRestart(ah, aniState); + } else if (aniState->cckPhyErrCount > aniState->listenTime * + params->cckTrigHigh / 1000) { + ar5416AniCckErrTrigger(ah); + ar5416AniRestart(ah, aniState); + } + } +} --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5416/ar5416_attach.c 2009-05-15 11:11:28.000000000 +0100 @@ -0,0 +1,486 @@ +/* + * 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: ar5416_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 "ar5416/ar5416.h" +#include "ar5416/ar5416reg.h" +#include "ar5416/ar5416phy.h" + +#include "ar5416/ar5416.ini" + +static void +ar5416AniSetup(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, + .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, + }; + /* NB: ANI is not enabled yet */ + ar5212AniAttach(ah, &aniparams, &aniparams, AH_FALSE); +} + +/* + * Attach for an AR5416 part. + */ +void +ar5416InitState(struct ath_hal_5416 *ahp5416, uint16_t devid, HAL_SOFTC sc, + HAL_BUS_TAG st, HAL_BUS_HANDLE sh, HAL_STATUS *status) +{ + struct ath_hal_5212 *ahp; + struct ath_hal *ah; + + ahp = &ahp5416->ah_5212; + ar5212InitState(ahp, devid, sc, st, sh, status); + ah = &ahp->ah_priv.h; + + /* override 5212 methods for our needs */ + ah->ah_magic = AR5416_MAGIC; + ah->ah_getRateTable = ar5416GetRateTable; + ah->ah_detach = ar5416Detach; + + /* Reset functions */ + ah->ah_reset = ar5416Reset; + ah->ah_phyDisable = ar5416PhyDisable; + ah->ah_disable = ar5416Disable; + ah->ah_perCalibration = ar5416PerCalibration; + ah->ah_perCalibrationN = ar5416PerCalibrationN, + ah->ah_resetCalValid = ar5416ResetCalValid, + ah->ah_setTxPowerLimit = ar5416SetTxPowerLimit; + + /* Transmit functions */ + ah->ah_stopTxDma = ar5416StopTxDma; + ah->ah_setupTxDesc = ar5416SetupTxDesc; + ah->ah_setupXTxDesc = ar5416SetupXTxDesc; + ah->ah_fillTxDesc = ar5416FillTxDesc; + ah->ah_procTxDesc = ar5416ProcTxDesc; + + /* Receive Functions */ + ah->ah_startPcuReceive = ar5416StartPcuReceive; + ah->ah_stopPcuReceive = ar5416StopPcuReceive; + ah->ah_setupRxDesc = ar5416SetupRxDesc; + ah->ah_procRxDesc = ar5416ProcRxDesc; + ah->ah_rxMonitor = ar5416AniPoll, + ah->ah_procMibEvent = ar5416ProcessMibIntr, + + /* Misc Functions */ + ah->ah_getDiagState = ar5416GetDiagState; + ah->ah_setLedState = ar5416SetLedState; + ah->ah_gpioCfgOutput = ar5416GpioCfgOutput; + ah->ah_gpioCfgInput = ar5416GpioCfgInput; + ah->ah_gpioGet = ar5416GpioGet; + ah->ah_gpioSet = ar5416GpioSet; + ah->ah_gpioSetIntr = ar5416GpioSetIntr; + ah->ah_resetTsf = ar5416ResetTsf; + ah->ah_getRfGain = ar5416GetRfgain; + ah->ah_setAntennaSwitch = ar5416SetAntennaSwitch; + ah->ah_setDecompMask = ar5416SetDecompMask; + ah->ah_setCoverageClass = ar5416SetCoverageClass; + + ah->ah_resetKeyCacheEntry = ar5416ResetKeyCacheEntry; + ah->ah_setKeyCacheEntry = ar5416SetKeyCacheEntry; + + /* Power Management Functions */ + ah->ah_setPowerMode = ar5416SetPowerMode; + + /* Beacon Management Functions */ + ah->ah_setBeaconTimers = ar5416SetBeaconTimers; + ah->ah_beaconInit = ar5416BeaconInit; + ah->ah_setStationBeaconTimers = ar5416SetStaBeaconTimers; + ah->ah_resetStationBeaconTimers = ar5416ResetStaBeaconTimers; + + /* XXX 802.11n Functions */ +#if 0 + ah->ah_chainTxDesc = ar5416ChainTxDesc; + ah->ah_setupFirstTxDesc = ar5416SetupFirstTxDesc; + ah->ah_setupLastTxDesc = ar5416SetupLastTxDesc; + ah->ah_set11nRateScenario = ar5416Set11nRateScenario; + ah->ah_set11nAggrMiddle = ar5416Set11nAggrMiddle; + ah->ah_clr11nAggr = ar5416Clr11nAggr; + ah->ah_set11nBurstDuration = ar5416Set11nBurstDuration; + ah->ah_get11nExtBusy = ar5416Get11nExtBusy; + ah->ah_set11nMac2040 = ar5416Set11nMac2040; + ah->ah_get11nRxClear = ar5416Get11nRxClear; + ah->ah_set11nRxClear = ar5416Set11nRxClear; +#endif + + /* Interrupt functions */ + ah->ah_isInterruptPending = ar5416IsInterruptPending; + ah->ah_getPendingInterrupts = ar5416GetPendingInterrupts; + ah->ah_setInterrupts = ar5416SetInterrupts; + + ahp->ah_priv.ah_getWirelessModes= ar5416GetWirelessModes; + ahp->ah_priv.ah_eepromRead = ar5416EepromRead; +#ifdef AH_SUPPORT_WRITE_EEPROM + ahp->ah_priv.ah_eepromWrite = ar5416EepromWrite; +#endif + ahp->ah_priv.ah_gpioCfgOutput = ar5416GpioCfgOutput; + ahp->ah_priv.ah_gpioCfgInput = ar5416GpioCfgInput; + ahp->ah_priv.ah_gpioGet = ar5416GpioGet; + ahp->ah_priv.ah_gpioSet = ar5416GpioSet; + ahp->ah_priv.ah_gpioSetIntr = ar5416GpioSetIntr; + ahp->ah_priv.ah_getChipPowerLimits = ar5416GetChipPowerLimits; + + /* + * Start by setting all Owl devices to 2x2 + */ + AH5416(ah)->ah_rx_chainmask = AR5416_DEFAULT_RXCHAINMASK; + AH5416(ah)->ah_tx_chainmask = AR5416_DEFAULT_TXCHAINMASK; +} + +/* + * Attach for an AR5416 part. + */ +struct ath_hal * +ar5416Attach(uint16_t devid, HAL_SOFTC sc, + HAL_BUS_TAG st, HAL_BUS_HANDLE sh, HAL_STATUS *status) +{ + struct ath_hal_5416 *ahp5416; + struct ath_hal_5212 *ahp; + struct ath_hal *ah; + uint32_t val; + HAL_STATUS ecode; + HAL_BOOL rfStatus; + + 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 */ + ahp5416 = ath_hal_malloc(sizeof (struct ath_hal_5416) + + /* extra space for Owl 2.1/2.2 WAR */ + sizeof(ar5416Addac) + ); + if (ahp5416 == AH_NULL) { + HALDEBUG(AH_NULL, HAL_DEBUG_ANY, + "%s: cannot allocate memory for state block\n", __func__); + *status = HAL_ENOMEM; + return AH_NULL; + } + ar5416InitState(ahp5416, devid, sc, st, sh, status); + ahp = &ahp5416->ah_5212; + ah = &ahp->ah_priv.h; + + if (!ar5416SetResetReg(ah, HAL_RESET_POWER_ON)) { + /* reset chip */ + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: couldn't reset chip\n", __func__); + ecode = HAL_EIO; + goto bad; + } + + if (!ar5416SetPowerMode(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; + + /* setup common ini data; rf backends handle remainder */ + HAL_INI_INIT(&ahp->ah_ini_modes, ar5416Modes, 6); + HAL_INI_INIT(&ahp->ah_ini_common, ar5416Common, 2); + + HAL_INI_INIT(&AH5416(ah)->ah_ini_bb_rfgain, ar5416BB_RfGain, 3); + HAL_INI_INIT(&AH5416(ah)->ah_ini_bank0, ar5416Bank0, 2); + HAL_INI_INIT(&AH5416(ah)->ah_ini_bank1, ar5416Bank1, 2); + HAL_INI_INIT(&AH5416(ah)->ah_ini_bank2, ar5416Bank2, 2); + HAL_INI_INIT(&AH5416(ah)->ah_ini_bank3, ar5416Bank3, 3); + HAL_INI_INIT(&AH5416(ah)->ah_ini_bank6, ar5416Bank6, 3); + HAL_INI_INIT(&AH5416(ah)->ah_ini_bank7, ar5416Bank7, 2); + HAL_INI_INIT(&AH5416(ah)->ah_ini_addac, ar5416Addac, 2); + + if (!IS_5416V2_2(ah)) { /* Owl 2.1/2.0 */ + struct ini { + uint32_t *data; /* NB: !const */ + int rows, cols; + }; + /* override CLKDRV value */ + OS_MEMCPY(&AH5416(ah)[1], ar5416Addac, sizeof(ar5416Addac)); + AH5416(ah)->ah_ini_addac.data = (uint32_t *) &AH5416(ah)[1]; + HAL_INI_VAL((struct ini *)&AH5416(ah)->ah_ini_addac, 31, 1) = 0; + } + + if (!ar5416ChipReset(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 (!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); + switch (AH_PRIVATE(ah)->ah_analog5GhzRev & AR_RADIO_SREV_MAJOR) { + case AR_RAD5122_SREV_MAJOR: /* Fowl: 5G/2x2 */ + case AR_RAD2122_SREV_MAJOR: /* Fowl: 2+5G/2x2 */ + case AR_RAD2133_SREV_MAJOR: /* Fowl: 2G/3x3 */ + case AR_RAD5133_SREV_MAJOR: /* Fowl: 2+5G/3x3 */ + break; + default: + if (AH_PRIVATE(ah)->ah_analog5GhzRev == 0) { + /* + * When RF_Silen is used the analog chip is reset. + * So when the system boots with radio switch off + * the RF chip rev reads back as zero and we need + * to use the mac+phy revs to set the radio rev. + */ + AH_PRIVATE(ah)->ah_analog5GhzRev = + AR_RAD5133_SREV_MAJOR; + break; + } + /* NB: silently accept anything in release code per Atheros */ +#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 + } + + ecode = ath_hal_v14EepromAttach(ah); + if (ecode != HAL_OK) + goto bad; + + /* + * Got everything we need now to setup the capabilities. + */ + if (!ar5416FillCapabilityInfo(ah)) { + ecode = HAL_EEREAD; + goto bad; + } + + 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; + } + /* XXX How about the serial number ? */ + /* Read Reg Domain */ + AH_PRIVATE(ah)->ah_currentRD = + ath_hal_eepromGet(ah, AR_EEP_REGDMN_0, AH_NULL); + + /* + * ah_miscMode is populated by ar5416FillCapabilityInfo() + * starting from griffin. Set here to make sure that + * AR_MISC_MODE_MIC_NEW_LOC_ENABLE is set before a GTK is + * placed into hardware. + */ + if (ahp->ah_miscMode != 0) + OS_REG_WRITE(ah, AR_MISC_MODE, ahp->ah_miscMode); + + HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s: Attaching AR2133 radio\n", + __func__); + rfStatus = ar2133RfAttach(ah, &ecode); + if (!rfStatus) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: RF setup failed, status %u\n", + __func__, ecode); + goto bad; + } + + ar5416AniSetup(ah); /* Anti Noise Immunity */ + ar5416InitNfHistBuff(AH5416(ah)->ah_cal.nfCalHist); + + HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s: return\n", __func__); + + return ah; +bad: + if (ahp) + ar5416Detach((struct ath_hal *) ahp); + if (status) + *status = ecode; + return AH_NULL; +} + +void +ar5416Detach(struct ath_hal *ah) +{ + HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s:\n", __func__); + + HALASSERT(ah != AH_NULL); + HALASSERT(ah->ah_magic == AR5416_MAGIC); + + ar5416AniDetach(ah); + ar5212RfDetach(ah); + ah->ah_disable(ah); + ar5416SetPowerMode(ah, HAL_PM_FULL_SLEEP, AH_TRUE); + ath_hal_eepromDetach(ah); + ath_hal_free(ah); +} + +/* + * Fill all software cached or static hardware state information. + * Return failure if capabilities are to come from EEPROM and + * cannot be read. + */ +HAL_BOOL +ar5416FillCapabilityInfo(struct ath_hal *ah) +{ + struct ath_hal_private *ahpriv = AH_PRIVATE(ah); + HAL_CAPABILITIES *pCap = &ahpriv->ah_caps; + uint16_t val; + + /* Construct wireless mode from EEPROM */ + pCap->halWirelessModes = 0; + if (ath_hal_eepromGetFlag(ah, AR_EEP_AMODE)) { + pCap->halWirelessModes |= HAL_MODE_11A + | HAL_MODE_11NA_HT20 + | HAL_MODE_11NA_HT40PLUS + | HAL_MODE_11NA_HT40MINUS + ; + } + if (ath_hal_eepromGetFlag(ah, AR_EEP_GMODE)) { + pCap->halWirelessModes |= HAL_MODE_11G + | HAL_MODE_11NG_HT20 + | HAL_MODE_11NG_HT40PLUS + | HAL_MODE_11NG_HT40MINUS + ; + pCap->halWirelessModes |= HAL_MODE_11A + | HAL_MODE_11NA_HT20 + | HAL_MODE_11NA_HT40PLUS + | HAL_MODE_11NA_HT40MINUS + ; + } + + pCap->halLow2GhzChan = 2312; + 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); + + 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. + */ + pCap->halTkipMicTxRxKeySupport = AH_TRUE; + pCap->halChanSpreadSupport = AH_TRUE; + pCap->halSleepAfterBeaconBroken = AH_TRUE; + + pCap->halCompressSupport = AH_FALSE; + pCap->halBurstSupport = AH_TRUE; + pCap->halFastFramesSupport = AH_FALSE; /* XXX? */ + 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_FALSE; + 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 = AR5416_KEYTABLE_SIZE; + + /* XXX not needed */ + pCap->halChanHalfRate = AH_FALSE; /* XXX ? */ + pCap->halChanQuarterRate = AH_FALSE; /* XXX ? */ + + pCap->halTstampPrecision = 32; + pCap->halHwPhyCounterSupport = AH_TRUE; + + pCap->halFastCCSupport = AH_TRUE; + pCap->halNumGpioPins = 6; + pCap->halWowSupport = AH_FALSE; + pCap->halWowMatchPatternExact = AH_FALSE; + pCap->halBtCoexSupport = AH_FALSE; /* XXX need support */ + pCap->halAutoSleepSupport = AH_FALSE; +#if 0 /* XXX not yet */ + pCap->halNumAntCfg2GHz = ar5416GetNumAntConfig(ahp, HAL_FREQ_BAND_2GHZ); + pCap->halNumAntCfg5GHz = ar5416GetNumAntConfig(ahp, HAL_FREQ_BAND_5GHZ); +#endif + pCap->halHTSupport = AH_TRUE; + pCap->halTxChainMask = ath_hal_eepromGet(ah, AR_EEP_TXMASK, AH_NULL); + /* XXX CB71 uses GPIO 0 to indicate 3 rx chains */ + pCap->halRxChainMask = ath_hal_eepromGet(ah, AR_EEP_RXMASK, AH_NULL); + pCap->halRtsAggrLimit = 8*1024; /* Owl 2.0 limit */ + pCap->halMbssidAggrSupport = AH_TRUE; + pCap->halForcePpmSupport = AH_TRUE; + pCap->halEnhancedPmSupport = 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; + } + + ahpriv->ah_rxornIsFatal = AH_FALSE; + + return AH_TRUE; +} + +static const char* +ar5416Probe(uint16_t vendorid, uint16_t devid) +{ + if (vendorid == ATHEROS_VENDOR_ID && + (devid == AR5416_DEVID_PCI || devid == AR5416_DEVID_PCIE)) + return "Atheros 5416"; + return AH_NULL; +} +AH_CHIP(AR5416, ar5416Probe, ar5416Attach); --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5416/ar5416_beacon.c 2009-05-15 11:11:28.000000000 +0100 @@ -0,0 +1,246 @@ +/* + * 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: ar5416_beacon.c,v 1.1 2009/03/23 17:14:48 sborrill Exp $ + */ +#include "opt_ah.h" + +#include "ah.h" +#include "ah_internal.h" + +#include "ar5416/ar5416.h" +#include "ar5416/ar5416reg.h" +#include "ar5416/ar5416phy.h" + +#define TU_TO_USEC(_tu) ((_tu) << 10) + +/* + * Initialize all of the hardware registers used to + * send beacons. Note that for station operation the + * driver calls ar5416SetStaBeaconTimers instead. + */ +void +ar5416SetBeaconTimers(struct ath_hal *ah, const HAL_BEACON_TIMERS *bt) +{ + uint32_t bperiod; + + OS_REG_WRITE(ah, AR_NEXT_TBTT, TU_TO_USEC(bt->bt_nexttbtt)); + OS_REG_WRITE(ah, AR_NEXT_DBA, TU_TO_USEC(bt->bt_nextdba) >> 3); + OS_REG_WRITE(ah, AR_NEXT_SWBA, TU_TO_USEC(bt->bt_nextswba) >> 3); + OS_REG_WRITE(ah, AR_NEXT_NDP, TU_TO_USEC(bt->bt_nextatim)); + + bperiod = TU_TO_USEC(bt->bt_intval & HAL_BEACON_PERIOD); + OS_REG_WRITE(ah, AR5416_BEACON_PERIOD, bperiod); + OS_REG_WRITE(ah, AR_DBA_PERIOD, bperiod); + OS_REG_WRITE(ah, AR_SWBA_PERIOD, bperiod); + OS_REG_WRITE(ah, AR_NDP_PERIOD, bperiod); + + /* + * Reset TSF if required. + */ + if (bt->bt_intval & AR_BEACON_RESET_TSF) + ar5416ResetTsf(ah); + + /* enable timers */ + /* NB: flags == 0 handled specially for backwards compatibility */ + OS_REG_SET_BIT(ah, AR_TIMER_MODE, + bt->bt_flags != 0 ? bt->bt_flags : + AR_TIMER_MODE_TBTT | AR_TIMER_MODE_DBA | AR_TIMER_MODE_SWBA); +} + +/* + * Initializes all of the hardware registers used to + * send beacons. Note that for station operation the + * driver calls ar5212SetStaBeaconTimers instead. + */ +void +ar5416BeaconInit(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. + */ + bt.bt_flags = 0; + switch (AH_PRIVATE(ah)->ah_opmode) { + case HAL_M_STA: + case HAL_M_MONITOR: + bt.bt_nextdba = 0xffff; + bt.bt_nextswba = 0x7ffff; + bt.bt_flags |= AR_TIMER_MODE_TBTT; + break; + case HAL_M_IBSS: + OS_REG_SET_BIT(ah, AR_TXCFG, AR_TXCFG_ATIM_TXPOLICY); + bt.bt_flags |= AR_TIMER_MODE_NDP; + /* fall thru... */ + 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 */ + bt.bt_flags |= AR_TIMER_MODE_TBTT + | AR_TIMER_MODE_DBA + | AR_TIMER_MODE_SWBA; + 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); + ar5416SetBeaconTimers(ah, &bt); +} + +#define AR_BEACON_PERIOD_MAX 0xffff + +void +ar5416ResetStaBeaconTimers(struct ath_hal *ah) +{ + uint32_t val; + + OS_REG_WRITE(ah, AR_NEXT_TBTT, 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, AR5416_BEACON_PERIOD, AR_BEACON_PERIOD_MAX); + OS_REG_WRITE(ah, AR_DBA_PERIOD, AR_BEACON_PERIOD_MAX); +} + +/* + * 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 +ar5416SetStaBeaconTimers(struct ath_hal *ah, const HAL_BEACON_STATE *bs) +{ + uint32_t nextTbtt, nextdtim,beaconintval, dtimperiod; + + HALASSERT(bs->bs_intval != 0); + + /* NB: no cfp setting since h/w automatically takes care */ + + OS_REG_WRITE(ah, AR_NEXT_TBTT, bs->bs_nexttbtt); + + /* + * Start the beacon timers by setting the BEACON register + * to the beacon interval; no need to write tim offset since + * h/w parses IEs. + */ + OS_REG_WRITE(ah, AR5416_BEACON_PERIOD, + TU_TO_USEC(bs->bs_intval & HAL_BEACON_PERIOD)); + OS_REG_WRITE(ah, AR_DBA_PERIOD, + TU_TO_USEC(bs->bs_intval & HAL_BEACON_PERIOD)); + + /* + * Configure the BMISS interrupt. Note that we + * assume the caller blocks interrupts while enabling + * the threshold. + */ + HALASSERT(bs->bs_bmissthreshold <= + (AR_RSSI_THR_BM_THR >> AR_RSSI_THR_BM_THR_S)); + OS_REG_RMW_FIELD(ah, AR_RSSI_THR, + AR_RSSI_THR_BM_THR, bs->bs_bmissthreshold); + + /* + * 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_NEXT_DTIM, + TU_TO_USEC(bs->bs_nextdtim - SLEEP_SLOP)); + OS_REG_WRITE(ah, AR_NEXT_TIM, TU_TO_USEC(nextTbtt - SLEEP_SLOP)); + + /* cab timeout is now in 1/8 TU */ + OS_REG_WRITE(ah, AR_SLEEP1, + SM((CAB_TIMEOUT_VAL << 3), AR5416_SLEEP1_CAB_TIMEOUT) + | AR_SLEEP1_ASSUME_DTIM); + /* beacon timeout is now in 1/8 TU */ + OS_REG_WRITE(ah, AR_SLEEP2, + SM((BEACON_TIMEOUT_VAL << 3), AR5416_SLEEP2_BEACON_TIMEOUT)); + + OS_REG_WRITE(ah, AR_TIM_PERIOD, beaconintval); + OS_REG_WRITE(ah, AR_DTIM_PERIOD, dtimperiod); + OS_REG_SET_BIT(ah, AR_TIMER_MODE, + AR_TIMER_MODE_TBTT | AR_TIMER_MODE_TIM | AR_TIMER_MODE_DTIM); + 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/ar5416/ar5416_cal.c 2009-05-15 11:11:28.000000000 +0100 @@ -0,0 +1,663 @@ +/* + * 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: ar5416_cal.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 "ah_eeprom_v14.h" + +#include "ar5416/ar5416.h" +#include "ar5416/ar5416reg.h" +#include "ar5416/ar5416phy.h" + +/* Owl specific stuff */ +#define NUM_NOISEFLOOR_READINGS 6 /* 3 chains * (ctl + ext) */ + +static void ar5416StartNFCal(struct ath_hal *ah); +static void ar5416LoadNF(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *); +static int16_t ar5416GetNf(struct ath_hal *, HAL_CHANNEL_INTERNAL *); + +/* + * Determine if calibration is supported by device and channel flags + */ +static OS_INLINE HAL_BOOL +ar5416IsCalSupp(struct ath_hal *ah, HAL_CHANNEL *chan, HAL_CAL_TYPE calType) +{ + struct ar5416PerCal *cal = &AH5416(ah)->ah_cal; + + switch (calType & cal->suppCals) { + case IQ_MISMATCH_CAL: + /* Run IQ Mismatch for non-CCK only */ + return !IS_CHAN_B(chan); + case ADC_GAIN_CAL: + case ADC_DC_CAL: + /* Run ADC Gain Cal for non-CCK & non 2GHz-HT20 only */ + return !IS_CHAN_B(chan) && + !(IS_CHAN_2GHZ(chan) && IS_CHAN_HT20(chan)); + } + return AH_FALSE; +} + +/* + * Setup HW to collect samples used for current cal + */ +static void +ar5416SetupMeasurement(struct ath_hal *ah, HAL_CAL_LIST *currCal) +{ + /* Start 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, + currCal->calData->calCountMax); + + /* Select calibration to run */ + switch (currCal->calData->calType) { + case IQ_MISMATCH_CAL: + OS_REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ); + HALDEBUG(ah, HAL_DEBUG_PERCAL, + "%s: start IQ Mismatch calibration\n", __func__); + break; + case ADC_GAIN_CAL: + OS_REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_GAIN); + HALDEBUG(ah, HAL_DEBUG_PERCAL, + "%s: start ADC Gain calibration\n", __func__); + break; + case ADC_DC_CAL: + OS_REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_PER); + HALDEBUG(ah, HAL_DEBUG_PERCAL, + "%s: start ADC DC calibration\n", __func__); + break; + case ADC_DC_INIT_CAL: + OS_REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_INIT); + HALDEBUG(ah, HAL_DEBUG_PERCAL, + "%s: start Init ADC DC calibration\n", __func__); + break; + } + /* Kick-off cal */ + OS_REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4, AR_PHY_TIMING_CTRL4_DO_CAL); +} + +/* + * Initialize shared data structures and prepare a cal to be run. + */ +static void +ar5416ResetMeasurement(struct ath_hal *ah, HAL_CAL_LIST *currCal) +{ + struct ar5416PerCal *cal = &AH5416(ah)->ah_cal; + + /* Reset data structures shared between different calibrations */ + OS_MEMZERO(cal->caldata, sizeof(cal->caldata)); + cal->calSamples = 0; + + /* Setup HW for new calibration */ + ar5416SetupMeasurement(ah, currCal); + + /* Change SW state to RUNNING for this calibration */ + currCal->calState = CAL_RUNNING; +} + +#if 0 +/* + * Run non-periodic calibrations. + */ +static HAL_BOOL +ar5416RunInitCals(struct ath_hal *ah, int init_cal_count) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416PerCal *cal = &AH5416(ah)->ah_cal; + HAL_CHANNEL_INTERNAL ichan; /* XXX bogus */ + HAL_CAL_LIST *curCal = ahp->ah_cal_curr; + HAL_BOOL isCalDone; + int i; + + if (curCal == AH_NULL) + return AH_FALSE; + + ichan.calValid = 0; + for (i = 0; i < init_cal_count; i++) { + /* Reset this Cal */ + ar5416ResetMeasurement(ah, curCal); + /* Poll for offset calibration complete */ + if (!ath_hal_wait(ah, AR_PHY_TIMING_CTRL4, AR_PHY_TIMING_CTRL4_DO_CAL, 0)) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: Cal %d failed to finish in 100ms.\n", + __func__, curCal->calData->calType); + /* Re-initialize list pointers for periodic cals */ + cal->cal_list = cal->cal_last = cal->cal_curr = AH_NULL; + return AH_FALSE; + } + /* Run this cal */ + ar5416DoCalibration(ah, &ichan, ahp->ah_rxchainmask, + curCal, &isCalDone); + if (!isCalDone) + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: init cal %d did not complete.\n", + __func__, curCal->calData->calType); + if (curCal->calNext != AH_NULL) + curCal = curCal->calNext; + } + + /* Re-initialize list pointers for periodic cals */ + cal->cal_list = cal->cal_last = cal->cal_curr = AH_NULL; + return AH_TRUE; +} +#endif + +/* + * Initialize Calibration infrastructure. + */ +HAL_BOOL +ar5416InitCal(struct ath_hal *ah, HAL_CHANNEL *chan) +{ + struct ar5416PerCal *cal = &AH5416(ah)->ah_cal; + HAL_CHANNEL_INTERNAL *ichan; + + ichan = ath_hal_checkchannel(ah, chan); + HALASSERT(ichan != AH_NULL); + + if (AR_SREV_MERLIN_10_OR_LATER(ah)) { + /* Enable Rx Filter Cal */ + OS_REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); + OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, + AR_PHY_AGC_CONTROL_FLTR_CAL); + + /* Clear the carrier leak cal bit */ + OS_REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); + + /* kick off the cal */ + OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL); + + /* Poll for offset calibration complete */ + 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__); + return AH_FALSE; + } + + /* Set the cl cal bit and rerun the cal a 2nd time */ + /* Enable Rx Filter Cal */ + OS_REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); + OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, + AR_PHY_AGC_CONTROL_FLTR_CAL); + + OS_REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); + } + + /* Calibrate the AGC */ + OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL); + + /* Poll for offset calibration complete */ + if (!ath_hal_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0)) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: offset calibration did not complete in 1ms; " + "noisy environment?\n", __func__); + return AH_FALSE; + } + + /* + * Do NF calibration after DC offset and other CALs. + * Per system engineers, noise floor value can sometimes be 20 dB + * higher than normal value if DC offset and noise floor cal are + * triggered at the same time. + */ + OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); + + /* Initialize list pointers */ + cal->cal_list = cal->cal_last = cal->cal_curr = AH_NULL; + + /* + * Enable IQ, ADC Gain, ADC DC Offset Cals + */ + if (AR_SREV_SOWL_10_OR_LATER(ah)) { + /* Setup all non-periodic, init time only calibrations */ + /* XXX: Init DC Offset not working yet */ +#if 0 + if (ar5416IsCalSupp(ah, chan, ADC_DC_INIT_CAL)) { + INIT_CAL(&cal->adcDcCalInitData); + INSERT_CAL(cal, &cal->adcDcCalInitData); + } + /* Initialize current pointer to first element in list */ + cal->cal_curr = cal->cal_list; + + if (cal->ah_cal_curr != AH_NULL && !ar5416RunInitCals(ah, 0)) + return AH_FALSE; +#endif + } + + /* If Cals are supported, add them to list via INIT/INSERT_CAL */ + if (ar5416IsCalSupp(ah, chan, ADC_GAIN_CAL)) { + INIT_CAL(&cal->adcGainCalData); + INSERT_CAL(cal, &cal->adcGainCalData); + HALDEBUG(ah, HAL_DEBUG_PERCAL, + "%s: enable ADC Gain Calibration.\n", __func__); + } + if (ar5416IsCalSupp(ah, chan, ADC_DC_CAL)) { + INIT_CAL(&cal->adcDcCalData); + INSERT_CAL(cal, &cal->adcDcCalData); + HALDEBUG(ah, HAL_DEBUG_PERCAL, + "%s: enable ADC DC Calibration.\n", __func__); + } + if (ar5416IsCalSupp(ah, chan, IQ_MISMATCH_CAL)) { + INIT_CAL(&cal->iqCalData); + INSERT_CAL(cal, &cal->iqCalData); + HALDEBUG(ah, HAL_DEBUG_PERCAL, + "%s: enable IQ Calibration.\n", __func__); + } + /* Initialize current pointer to first element in list */ + cal->cal_curr = cal->cal_list; + + /* Kick off measurements for the first cal */ + if (cal->cal_curr != AH_NULL) + ar5416ResetMeasurement(ah, cal->cal_curr); + + /* Mark all calibrations on this channel as being invalid */ + ichan->calValid = 0; + + return AH_TRUE; +} + +/* + * Entry point for upper layers to restart current cal. + * Reset the calibration valid bit in channel. + */ +HAL_BOOL +ar5416ResetCalValid(struct ath_hal *ah, HAL_CHANNEL *chan) +{ + struct ar5416PerCal *cal = &AH5416(ah)->ah_cal; + HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan); + HAL_CAL_LIST *currCal = cal->cal_curr; + + if (!AR_SREV_SOWL_10_OR_LATER(ah)) + return AH_FALSE; + if (currCal == AH_NULL) + return AH_FALSE; + 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; + } + /* + * Expected that this calibration has run before, post-reset. + * Current state should be done + */ + if (currCal->calState != CAL_DONE) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: Calibration state incorrect, %d\n", + __func__, currCal->calState); + return AH_FALSE; + } + + /* Verify Cal is supported on this channel */ + if (!ar5416IsCalSupp(ah, chan, currCal->calData->calType)) + return AH_FALSE; + + HALDEBUG(ah, HAL_DEBUG_PERCAL, + "%s: Resetting Cal %d state for channel %u/0x%x\n", + __func__, currCal->calData->calType, chan->channel, + chan->channelFlags); + + /* Disable cal validity in channel */ + ichan->calValid &= ~currCal->calData->calType; + currCal->calState = CAL_WAITING; + + return AH_TRUE; +} + +/* + * Recalibrate the lower PHY chips to account for temperature/environment + * changes. + */ +static void +ar5416DoCalibration(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan, + uint8_t rxchainmask, HAL_CAL_LIST *currCal, HAL_BOOL *isCalDone) +{ + struct ar5416PerCal *cal = &AH5416(ah)->ah_cal; + + /* Cal is assumed not done until explicitly set below */ + *isCalDone = AH_FALSE; + + HALDEBUG(ah, HAL_DEBUG_PERCAL, + "%s: %s Calibration, state %d, calValid 0x%x\n", + __func__, currCal->calData->calName, currCal->calState, + ichan->calValid); + + /* Calibration in progress. */ + if (currCal->calState == CAL_RUNNING) { + /* Check to see if it has finished. */ + if (!(OS_REG_READ(ah, AR_PHY_TIMING_CTRL4) & AR_PHY_TIMING_CTRL4_DO_CAL)) { + HALDEBUG(ah, HAL_DEBUG_PERCAL, + "%s: sample %d of %d finished\n", + __func__, cal->calSamples, + currCal->calData->calNumSamples); + /* + * Collect measurements for active chains. + */ + currCal->calData->calCollect(ah); + if (++cal->calSamples >= currCal->calData->calNumSamples) { + int i, numChains = 0; + for (i = 0; i < AR5416_MAX_CHAINS; i++) { + if (rxchainmask & (1 << i)) + numChains++; + } + /* + * Process accumulated data + */ + currCal->calData->calPostProc(ah, numChains); + + /* Calibration has finished. */ + ichan->calValid |= currCal->calData->calType; + currCal->calState = CAL_DONE; + *isCalDone = AH_TRUE; + } else { + /* + * Set-up to collect of another sub-sample. + */ + ar5416SetupMeasurement(ah, currCal); + } + } + } else if (!(ichan->calValid & currCal->calData->calType)) { + /* If current cal is marked invalid in channel, kick it off */ + ar5416ResetMeasurement(ah, currCal); + } +} + +/* + * Internal interface to schedule periodic calibration work. + */ +HAL_BOOL +ar5416PerCalibrationN(struct ath_hal *ah, HAL_CHANNEL *chan, + u_int rxchainmask, HAL_BOOL longcal, HAL_BOOL *isCalDone) +{ + struct ar5416PerCal *cal = &AH5416(ah)->ah_cal; + HAL_CAL_LIST *currCal = cal->cal_curr; + HAL_CHANNEL_INTERNAL *ichan; + + OS_MARK(ah, AH_MARK_PERCAL, chan->channel); + + *isCalDone = AH_TRUE; + + /* Invalid channel check */ + 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; + } + + /* + * For given calibration: + * 1. Call generic cal routine + * 2. When this cal is done (isCalDone) if we have more cals waiting + * (eg after reset), mask this to upper layers by not propagating + * isCalDone if it is set to TRUE. + * Instead, change isCalDone to FALSE and setup the waiting cal(s) + * to be run. + */ + if (currCal != AH_NULL && + (currCal->calState == CAL_RUNNING || + currCal->calState == CAL_WAITING)) { + ar5416DoCalibration(ah, ichan, rxchainmask, currCal, isCalDone); + if (*isCalDone == AH_TRUE) { + cal->cal_curr = currCal = currCal->calNext; + if (currCal->calState == CAL_WAITING) { + *isCalDone = AH_FALSE; + ar5416ResetMeasurement(ah, currCal); + } + } + } + + /* Do NF cal only at longer intervals */ + if (longcal) { + /* + * Get the value from the previous NF cal + * and update the history buffer. + */ + ar5416GetNf(ah, ichan); + + /* + * Load the NF from history buffer of the current channel. + * NF is slow time-variant, so it is OK to use a + * historical value. + */ + ar5416LoadNF(ah, AH_PRIVATE(ah)->ah_curchan); + + /* start NF calibration, without updating BB NF register*/ + ar5416StartNFCal(ah); + + if ((ichan->channelFlags & CHANNEL_CW_INT) != 0) { + /* report up and clear internal state */ + chan->channelFlags |= CHANNEL_CW_INT; + ichan->channelFlags &= ~CHANNEL_CW_INT; + } + } + return AH_TRUE; +} + +/* + * Recalibrate the lower PHY chips to account for temperature/environment + * changes. + */ +HAL_BOOL +ar5416PerCalibration(struct ath_hal *ah, HAL_CHANNEL *chan, HAL_BOOL *isIQdone) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416PerCal *cal = &AH5416(ah)->ah_cal; + HAL_CAL_LIST *curCal = cal->cal_curr; + + if (curCal != AH_NULL && curCal->calData->calType == IQ_MISMATCH_CAL) { + return ar5416PerCalibrationN(ah, chan, ahp->ah_rx_chainmask, + AH_TRUE, isIQdone); + } else { + HAL_BOOL isCalDone; + + *isIQdone = AH_FALSE; + return ar5416PerCalibrationN(ah, chan, ahp->ah_rx_chainmask, + AH_TRUE, &isCalDone); + } +} + +static HAL_BOOL +ar5416GetEepromNoiseFloorThresh(struct ath_hal *ah, + const HAL_CHANNEL_INTERNAL *chan, int16_t *nft) +{ + switch (chan->channelFlags & CHANNEL_ALL_NOTURBO) { + case CHANNEL_A: + case CHANNEL_A_HT20: + case CHANNEL_A_HT40PLUS: + case CHANNEL_A_HT40MINUS: + ath_hal_eepromGet(ah, AR_EEP_NFTHRESH_5, nft); + break; + case CHANNEL_B: + case CHANNEL_G: + case CHANNEL_G_HT20: + case CHANNEL_G_HT40PLUS: + case CHANNEL_G_HT40MINUS: + ath_hal_eepromGet(ah, AR_EEP_NFTHRESH_2, nft); + break; + default: + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: invalid channel flags 0x%x\n", + __func__, chan->channelFlags); + return AH_FALSE; + } + return AH_TRUE; +} + +static void +ar5416StartNFCal(struct ath_hal *ah) +{ + 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); +} + +static void +ar5416LoadNF(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan) +{ + static const uint32_t ar5416_cca_regs[] = { + AR_PHY_CCA, + AR_PHY_CH1_CCA, + AR_PHY_CH2_CCA, + AR_PHY_EXT_CCA, + AR_PHY_CH1_EXT_CCA, + AR_PHY_CH2_EXT_CCA + }; + struct ar5212NfCalHist *h; + int i, j; + int32_t val; + uint8_t chainmask; + + /* + * Force NF calibration for all chains. + */ + if (AR_SREV_KITE(ah)) { + /* Kite has only one chain */ + chainmask = 0x9; + } else if (AR_SREV_MERLIN(ah)) { + /* Merlin has only two chains */ + chainmask = 0x1B; + } else { + chainmask = 0x3F; + } + + /* + * Write filtered NF values into maxCCApwr register parameter + * so we can load below. + */ + h = AH5416(ah)->ah_cal.nfCalHist; + for (i = 0; i < AR5416_NUM_NF_READINGS; i ++) + if (chainmask & (1 << i)) { + val = OS_REG_READ(ah, ar5416_cca_regs[i]); + val &= 0xFFFFFE00; + val |= (((uint32_t)(h[i].privNF) << 1) & 0x1ff); + OS_REG_WRITE(ah, ar5416_cca_regs[i], val); + } + + /* Load software filtered NF value into baseband internal minCCApwr variable. */ + 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); + + /* Wait for load to complete, should be fast, a few 10s of us. */ + for (j = 0; j < 1000; j++) { + if ((OS_REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) == 0) + break; + OS_DELAY(10); + } + + /* + * Restore maxCCAPower register parameter again so that we're not capped + * by the median we just loaded. This will be initial (and max) value + * of next noise floor calibration the baseband does. + */ + for (i = 0; i < AR5416_NUM_NF_READINGS; i ++) + if (chainmask & (1 << i)) { + val = OS_REG_READ(ah, ar5416_cca_regs[i]); + val &= 0xFFFFFE00; + val |= (((uint32_t)(-50) << 1) & 0x1ff); + OS_REG_WRITE(ah, ar5416_cca_regs[i], val); + } +} + +void +ar5416InitNfHistBuff(struct ar5212NfCalHist *h) +{ + int i, j; + + for (i = 0; i < AR5416_NUM_NF_READINGS; i ++) { + h[i].currIndex = 0; + h[i].privNF = AR5416_CCA_MAX_GOOD_VALUE; + h[i].invalidNFcount = AR512_NF_CAL_HIST_MAX; + for (j = 0; j < AR512_NF_CAL_HIST_MAX; j ++) + h[i].nfCalBuffer[j] = AR5416_CCA_MAX_GOOD_VALUE; + } +} + +/* + * Update the noise floor buffer as a ring buffer + */ +static void +ar5416UpdateNFHistBuff(struct ar5212NfCalHist *h, int16_t *nfarray) +{ + int i; + + for (i = 0; i < AR5416_NUM_NF_READINGS; i ++) { + h[i].nfCalBuffer[h[i].currIndex] = nfarray[i]; + + if (++h[i].currIndex >= AR512_NF_CAL_HIST_MAX) + h[i].currIndex = 0; + if (h[i].invalidNFcount > 0) { + if (nfarray[i] < AR5416_CCA_MIN_BAD_VALUE || + nfarray[i] > AR5416_CCA_MAX_HIGH_VALUE) { + h[i].invalidNFcount = AR512_NF_CAL_HIST_MAX; + } else { + h[i].invalidNFcount--; + h[i].privNF = nfarray[i]; + } + } else { + h[i].privNF = ar5212GetNfHistMid(h[i].nfCalBuffer); + } + } +} + +/* + * Read the NF and check it against the noise floor threshhold + */ +static int16_t +ar5416GetNf(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan) +{ + int16_t nf, nfThresh; + + if (OS_REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: NF didn't complete in calibration window\n", __func__); + nf = 0; + } else { + /* Finished NF cal, check against threshold */ + int16_t nfarray[NUM_NOISEFLOOR_READINGS] = { 0 }; + + /* TODO - enhance for multiple chains and ext ch */ + ath_hal_getNoiseFloor(ah, nfarray); + nf = nfarray[0]; + if (ar5416GetEepromNoiseFloorThresh(ah, chan, &nfThresh)) { + if (nf > nfThresh) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: noise floor failed detected; " + "detected %d, threshold %d\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; + } + ar5416UpdateNFHistBuff(AH5416(ah)->ah_cal.nfCalHist, nfarray); + chan->rawNoiseFloor = nf; + } + return nf; +} --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5416/ar5416_cal.h 2009-05-15 11:11:28.000000000 +0100 @@ -0,0 +1,119 @@ +/* + * 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: ar5416_cal.h,v 1.1 2009/03/23 17:14:48 sborrill Exp $ + */ +#ifndef _ATH_AR5416_CAL_H_ +#define _ATH_AR5416_CAL_H_ + +typedef enum { + ADC_DC_INIT_CAL = 0x1, + ADC_GAIN_CAL = 0x2, + ADC_DC_CAL = 0x4, + IQ_MISMATCH_CAL = 0x8 +} HAL_CAL_TYPE; + +/* Calibrate state */ +typedef enum { + CAL_INACTIVE, + CAL_WAITING, + CAL_RUNNING, + CAL_DONE +} HAL_CAL_STATE; + +typedef union { + uint32_t u; + int32_t s; +} HAL_CAL_SAMPLE; + +#define MIN_CAL_SAMPLES 1 +#define MAX_CAL_SAMPLES 64 +#define INIT_LOG_COUNT 5 +#define PER_MIN_LOG_COUNT 2 +#define PER_MAX_LOG_COUNT 10 + +/* Per Calibration data structure */ +typedef struct per_cal_data { + const char *calName; /* for diagnostics */ + HAL_CAL_TYPE calType; /* Type of calibration */ + uint32_t calNumSamples; /* # SW samples to collect */ + uint32_t calCountMax; /* # HW samples to collect */ + void (*calCollect)(struct ath_hal *); /* Accumulator function */ + /* Post-processing function */ + void (*calPostProc)(struct ath_hal *, uint8_t); +} HAL_PERCAL_DATA; + +/* List structure for calibration data */ +typedef struct cal_list { + struct cal_list *calNext; + HAL_CAL_STATE calState; + const HAL_PERCAL_DATA *calData; +} HAL_CAL_LIST; + +struct ar5416PerCal { + /* + * Periodic calibration state. + */ + HAL_CAL_TYPE suppCals; + HAL_CAL_LIST iqCalData; + HAL_CAL_LIST adcGainCalData; + HAL_CAL_LIST adcDcCalInitData; + HAL_CAL_LIST adcDcCalData; + HAL_CAL_LIST *cal_list; + HAL_CAL_LIST *cal_last; + HAL_CAL_LIST *cal_curr; +#define AR5416_MAX_CHAINS 3 /* XXX dup's eeprom def */ + HAL_CAL_SAMPLE caldata[4][AR5416_MAX_CHAINS]; + int calSamples; + /* + * Noise floor cal histogram support. + * XXX be nice to re-use space in ar5212 + */ +#define AR5416_NUM_NF_READINGS 6 /* (3 chains * (ctl + ext) */ + struct ar5212NfCalHist nfCalHist[AR5416_NUM_NF_READINGS]; +}; + +#define INIT_CAL(_perCal) do { \ + (_perCal)->calState = CAL_WAITING; \ + (_perCal)->calNext = AH_NULL; \ +} while (0) + +#define INSERT_CAL(_cal, _perCal) do { \ + if ((_cal)->cal_last == AH_NULL) { \ + (_cal)->cal_list = (_cal)->cal_last = (_perCal); \ + ((_cal)->cal_last)->calNext = (_perCal); \ + } else { \ + ((_cal)->cal_last)->calNext = (_perCal); \ + (_cal)->cal_last = (_perCal); \ + (_perCal)->calNext = (_cal)->cal_list; \ + } \ +} while (0) + +HAL_BOOL ar5416InitCal(struct ath_hal *ah, HAL_CHANNEL *chan); +HAL_BOOL ar5416PerCalibration(struct ath_hal *, HAL_CHANNEL *, + HAL_BOOL *isIQdone); +HAL_BOOL ar5416PerCalibrationN(struct ath_hal *ah, HAL_CHANNEL *chan, + u_int chainMask, HAL_BOOL longCal, HAL_BOOL *isCalDone); +HAL_BOOL ar5416ResetCalValid(struct ath_hal *ah, HAL_CHANNEL *chan); + +void ar5416IQCalCollect(struct ath_hal *ah); +void ar5416IQCalibration(struct ath_hal *ah, uint8_t numChains); +void ar5416AdcGainCalCollect(struct ath_hal *ah); +void ar5416AdcGainCalibration(struct ath_hal *ah, uint8_t numChains); +void ar5416AdcDcCalCollect(struct ath_hal *ah); +void ar5416AdcDcCalibration(struct ath_hal *ah, uint8_t numChains); +void ar5416InitNfHistBuff(struct ar5212NfCalHist *h); +#endif /* _ATH_AR5416_CAL_H_ */ --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5416/ar5416_cal_adcdc.c 2009-05-15 11:11:28.000000000 +0100 @@ -0,0 +1,111 @@ +/* + * 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: ar5416_cal_adcdc.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 "ar5416/ar5416.h" +#include "ar5416/ar5416reg.h" +#include "ar5416/ar5416phy.h" + +/* Adc DC Offset Cal aliases */ +#define totalAdcDcOffsetIOddPhase(i) caldata[0][i].s +#define totalAdcDcOffsetIEvenPhase(i) caldata[1][i].s +#define totalAdcDcOffsetQOddPhase(i) caldata[2][i].s +#define totalAdcDcOffsetQEvenPhase(i) caldata[3][i].s + +void +ar5416AdcDcCalCollect(struct ath_hal *ah) +{ + struct ar5416PerCal *cal = &AH5416(ah)->ah_cal; + int i; + + for (i = 0; i < AR5416_MAX_CHAINS; i++) { + cal->totalAdcDcOffsetIOddPhase(i) += (int32_t) + OS_REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); + cal->totalAdcDcOffsetIEvenPhase(i) += (int32_t) + OS_REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); + cal->totalAdcDcOffsetQOddPhase(i) += (int32_t) + OS_REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); + cal->totalAdcDcOffsetQEvenPhase(i) += (int32_t) + OS_REG_READ(ah, AR_PHY_CAL_MEAS_3(i)); + + HALDEBUG(ah, HAL_DEBUG_PERCAL, + "%d: Chn %d oddi=0x%08x; eveni=0x%08x; oddq=0x%08x; evenq=0x%08x;\n", + cal->calSamples, i, + cal->totalAdcDcOffsetIOddPhase(i), + cal->totalAdcDcOffsetIEvenPhase(i), + cal->totalAdcDcOffsetQOddPhase(i), + cal->totalAdcDcOffsetQEvenPhase(i)); + } +} + +void +ar5416AdcDcCalibration(struct ath_hal *ah, uint8_t numChains) +{ + struct ar5416PerCal *cal = &AH5416(ah)->ah_cal; + const HAL_PERCAL_DATA *calData = cal->cal_curr->calData; + uint32_t numSamples; + int i; + + numSamples = (1 << (calData->calCountMax + 5)) * calData->calNumSamples; + for (i = 0; i < numChains; i++) { + uint32_t iOddMeasOffset = cal->totalAdcDcOffsetIOddPhase(i); + uint32_t iEvenMeasOffset = cal->totalAdcDcOffsetIEvenPhase(i); + int32_t qOddMeasOffset = cal->totalAdcDcOffsetQOddPhase(i); + int32_t qEvenMeasOffset = cal->totalAdcDcOffsetQEvenPhase(i); + int32_t qDcMismatch, iDcMismatch; + uint32_t val; + + HALDEBUG(ah, HAL_DEBUG_PERCAL, + "Starting ADC DC Offset Cal for Chain %d\n", i); + + HALDEBUG(ah, HAL_DEBUG_PERCAL, " pwr_meas_odd_i = %d\n", + iOddMeasOffset); + HALDEBUG(ah, HAL_DEBUG_PERCAL, " pwr_meas_even_i = %d\n", + iEvenMeasOffset); + HALDEBUG(ah, HAL_DEBUG_PERCAL, " pwr_meas_odd_q = %d\n", + qOddMeasOffset); + HALDEBUG(ah, HAL_DEBUG_PERCAL, " pwr_meas_even_q = %d\n", + qEvenMeasOffset); + + HALASSERT(numSamples); + + iDcMismatch = (((iEvenMeasOffset - iOddMeasOffset) * 2) / + numSamples) & 0x1ff; + qDcMismatch = (((qOddMeasOffset - qEvenMeasOffset) * 2) / + numSamples) & 0x1ff; + HALDEBUG(ah, HAL_DEBUG_PERCAL, + " dc_offset_mismatch_i = 0x%08x\n", iDcMismatch); + HALDEBUG(ah, HAL_DEBUG_PERCAL, + " dc_offset_mismatch_q = 0x%08x\n", qDcMismatch); + + val = OS_REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i)); + val &= 0xc0000fff; + val |= (qDcMismatch << 12) | (iDcMismatch << 21); + OS_REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val); + + HALDEBUG(ah, HAL_DEBUG_PERCAL, + "ADC DC Offset Cal done for Chain %d\n", i); + } + OS_REG_SET_BIT(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0), + AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE); +} --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5416/ar5416_cal_adcgain.c 2009-05-15 11:11:28.000000000 +0100 @@ -0,0 +1,116 @@ +/* + * 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: ar5416_cal_adcgain.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 "ar5416/ar5416.h" +#include "ar5416/ar5416reg.h" +#include "ar5416/ar5416phy.h" + +/* Adc Gain Cal aliases */ +#define totalAdcIOddPhase(i) caldata[0][i].u +#define totalAdcIEvenPhase(i) caldata[1][i].u +#define totalAdcQOddPhase(i) caldata[2][i].u +#define totalAdcQEvenPhase(i) caldata[3][i].u + +/* + * Collect data from HW to later perform ADC Gain Calibration + */ +void +ar5416AdcGainCalCollect(struct ath_hal *ah) +{ + struct ar5416PerCal *cal = &AH5416(ah)->ah_cal; + int i; + + /* + * Accumulate ADC Gain cal measures for active chains + */ + for (i = 0; i < AR5416_MAX_CHAINS; i++) { + cal->totalAdcIOddPhase(i) += + OS_REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); + cal->totalAdcIEvenPhase(i) += + OS_REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); + cal->totalAdcQOddPhase(i) += + OS_REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); + cal->totalAdcQEvenPhase(i) += + OS_REG_READ(ah, AR_PHY_CAL_MEAS_3(i)); + + HALDEBUG(ah, HAL_DEBUG_PERCAL, + "%d: Chn %d oddi=0x%08x; eveni=0x%08x; oddq=0x%08x; evenq=0x%08x;\n", + cal->calSamples, i, cal->totalAdcIOddPhase(i), + cal->totalAdcIEvenPhase(i), cal->totalAdcQOddPhase(i), + cal->totalAdcQEvenPhase(i)); + } +} + +/* + * Use HW data to do ADC Gain Calibration + */ +void +ar5416AdcGainCalibration(struct ath_hal *ah, uint8_t numChains) +{ + struct ar5416PerCal *cal = &AH5416(ah)->ah_cal; + uint32_t i; + + for (i = 0; i < numChains; i++) { + uint32_t iOddMeasOffset = cal->totalAdcIOddPhase(i); + uint32_t iEvenMeasOffset = cal->totalAdcIEvenPhase(i); + uint32_t qOddMeasOffset = cal->totalAdcQOddPhase(i); + uint32_t qEvenMeasOffset = cal->totalAdcQEvenPhase(i); + + HALDEBUG(ah, HAL_DEBUG_PERCAL, + "Start ADC Gain Cal for Chain %d\n", i); + HALDEBUG(ah, HAL_DEBUG_PERCAL, + " pwr_meas_odd_i = 0x%08x\n", iOddMeasOffset); + HALDEBUG(ah, HAL_DEBUG_PERCAL, + " pwr_meas_even_i = 0x%08x\n", iEvenMeasOffset); + HALDEBUG(ah, HAL_DEBUG_PERCAL, + " pwr_meas_odd_q = 0x%08x\n", qOddMeasOffset); + HALDEBUG(ah, HAL_DEBUG_PERCAL, + " pwr_meas_even_q = 0x%08x\n", qEvenMeasOffset); + + if (iOddMeasOffset != 0 && qEvenMeasOffset != 0) { + uint32_t iGainMismatch = + ((iEvenMeasOffset*32)/iOddMeasOffset) & 0x3f; + uint32_t qGainMismatch = + ((qOddMeasOffset*32)/qEvenMeasOffset) & 0x3f; + uint32_t val; + + HALDEBUG(ah, HAL_DEBUG_PERCAL, + " gain_mismatch_i = 0x%08x\n", + iGainMismatch); + HALDEBUG(ah, HAL_DEBUG_PERCAL, + " gain_mismatch_q = 0x%08x\n", + qGainMismatch); + + val = OS_REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i)); + val &= 0xfffff000; + val |= (qGainMismatch) | (iGainMismatch << 6); + OS_REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val); + + HALDEBUG(ah, HAL_DEBUG_PERCAL, + "ADC Gain Cal done for Chain %d\n", i); + } + } + OS_REG_SET_BIT(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0), + AR_PHY_NEW_ADC_GAIN_CORR_ENABLE); +} --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5416/ar5416_cal_iq.c 2009-05-15 11:11:28.000000000 +0100 @@ -0,0 +1,132 @@ +/* + * 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: ar5416_cal_iq.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 "ar5416/ar5416.h" +#include "ar5416/ar5416reg.h" +#include "ar5416/ar5416phy.h" + +/* IQ Cal aliases */ +#define totalPowerMeasI(i) caldata[0][i].u +#define totalPowerMeasQ(i) caldata[1][i].u +#define totalIqCorrMeas(i) caldata[2][i].s + +/* + * Collect data from HW to later perform IQ Mismatch Calibration + */ +void +ar5416IQCalCollect(struct ath_hal *ah) +{ + struct ar5416PerCal *cal = &AH5416(ah)->ah_cal; + int i; + + /* + * Accumulate IQ cal measures for active chains + */ + for (i = 0; i < AR5416_MAX_CHAINS; i++) { + cal->totalPowerMeasI(i) += + OS_REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); + cal->totalPowerMeasQ(i) += + OS_REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); + cal->totalIqCorrMeas(i) += (int32_t) + OS_REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); + HALDEBUG(ah, HAL_DEBUG_PERCAL, + "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n", + cal->calSamples, i, cal->totalPowerMeasI(i), + cal->totalPowerMeasQ(i), cal->totalIqCorrMeas(i)); + } +} + +/* + * Use HW data to do IQ Mismatch Calibration + */ +void +ar5416IQCalibration(struct ath_hal *ah, uint8_t numChains) +{ + struct ar5416PerCal *cal = &AH5416(ah)->ah_cal; + int i; + + for (i = 0; i < numChains; i++) { + uint32_t powerMeasI = cal->totalPowerMeasI(i); + uint32_t powerMeasQ = cal->totalPowerMeasQ(i); + uint32_t iqCorrMeas = cal->totalIqCorrMeas(i); + uint32_t qCoffDenom, iCoffDenom; + int iqCorrNeg; + + HALDEBUG(ah, HAL_DEBUG_PERCAL, + "Start IQ Cal and Correction for Chain %d\n", i); + HALDEBUG(ah, HAL_DEBUG_PERCAL, + "Orignal: iq_corr_meas = 0x%08x\n", iqCorrMeas); + + iqCorrNeg = 0; + /* iqCorrMeas is always negative. */ + if (iqCorrMeas > 0x80000000) { + iqCorrMeas = (0xffffffff - iqCorrMeas) + 1; + iqCorrNeg = 1; + } + + HALDEBUG(ah, HAL_DEBUG_PERCAL, " pwr_meas_i = 0x%08x\n", + powerMeasI); + HALDEBUG(ah, HAL_DEBUG_PERCAL, " pwr_meas_q = 0x%08x\n", + powerMeasQ); + HALDEBUG(ah, HAL_DEBUG_PERCAL, " iqCorrNeg is 0x%08x\n", + iqCorrNeg); + + iCoffDenom = (powerMeasI/2 + powerMeasQ/2)/ 128; + qCoffDenom = powerMeasQ / 64; + /* Protect against divide-by-0 */ + if (powerMeasQ != 0) { + /* IQ corr_meas is already negated if iqcorr_neg == 1 */ + int32_t iCoff = iqCorrMeas/iCoffDenom; + int32_t qCoff = powerMeasI/qCoffDenom - 64; + + HALDEBUG(ah, HAL_DEBUG_PERCAL, " iCoff = 0x%08x\n", + iCoff); + HALDEBUG(ah, HAL_DEBUG_PERCAL, " qCoff = 0x%08x\n", + qCoff); + + /* Negate iCoff if iqCorrNeg == 0 */ + iCoff = iCoff & 0x3f; + HALDEBUG(ah, HAL_DEBUG_PERCAL, + "New: iCoff = 0x%08x\n", iCoff); + + if (iqCorrNeg == 0x0) + iCoff = 0x40 - iCoff; + if (qCoff > 15) + qCoff = 15; + else if (qCoff <= -16) + qCoff = 16; + HALDEBUG(ah, HAL_DEBUG_PERCAL, + " : iCoff = 0x%x qCoff = 0x%x\n", iCoff, qCoff); + + OS_REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4_CHAIN(i), + AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF, iCoff); + OS_REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4_CHAIN(i), + AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF, qCoff); + HALDEBUG(ah, HAL_DEBUG_PERCAL, + "IQ Cal and Correction done for Chain %d\n", i); + } + } + OS_REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4, + AR_PHY_TIMING_CTRL4_IQCORR_ENABLE); +} --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5416/ar5416_eeprom.c 2009-05-15 11:11:29.000000000 +0100 @@ -0,0 +1,44 @@ +/* + * 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: ar5416_eeprom.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 "ah_eeprom_v14.h" + +#include "ar5416/ar5416.h" +#include "ar5416/ar5416reg.h" +#include "ar5416/ar5416phy.h" + +/* + * Read 16 bits of data from offset into *data + */ +HAL_BOOL +ar5416EepromRead(struct ath_hal *ah, u_int off, uint16_t *data) +{ + OS_REG_READ(ah, AR5416_EEPROM_OFFSET + (off << AR5416_EEPROM_S)); + if (!ath_hal_wait(ah, AR_EEPROM_STATUS_DATA, + AR_EEPROM_STATUS_DATA_BUSY | AR_EEPROM_STATUS_DATA_PROT_ACCESS, 0)) + return AH_FALSE; + *data = MS(OS_REG_READ(ah, AR_EEPROM_STATUS_DATA), + AR_EEPROM_STATUS_DATA_VAL); + return AH_TRUE; +} --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5416/ar5416_gpio.c 2009-05-15 11:11:29.000000000 +0100 @@ -0,0 +1,112 @@ +/* + * 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: ar5416_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 "ar5416/ar5416.h" +#include "ar5416/ar5416reg.h" +#include "ar5416/ar5416phy.h" + +#define AR_NUM_GPIO 6 /* 6 GPIO pins */ +#define AR_GPIO_BIT(_gpio) (1 << _gpio) + +/* + * Configure GPIO Output lines + */ +HAL_BOOL +ar5416GpioCfgOutput(struct ath_hal *ah, uint32_t gpio) +{ + HALASSERT(gpio < AR_NUM_GPIO); + OS_REG_CLR_BIT(ah, AR_GPIO_INTR_OUT, AR_GPIO_BIT(gpio)); + return AH_TRUE; +} + +/* + * Configure GPIO Input lines + */ +HAL_BOOL +ar5416GpioCfgInput(struct ath_hal *ah, uint32_t gpio) +{ + HALASSERT(gpio < AR_NUM_GPIO); + OS_REG_SET_BIT(ah, AR_GPIO_INTR_OUT, AR_GPIO_BIT(gpio)); + return AH_TRUE; +} + +/* + * Once configured for I/O - set output lines + */ +HAL_BOOL +ar5416GpioSet(struct ath_hal *ah, uint32_t gpio, uint32_t val) +{ + uint32_t reg; + + HALASSERT(gpio < AR_NUM_GPIO); + reg = MS(OS_REG_READ(ah, AR_GPIO_INTR_OUT), AR_GPIO_OUT_VAL); + if (val & 1) + reg |= AR_GPIO_BIT(gpio); + else + reg &= ~AR_GPIO_BIT(gpio); + + OS_REG_RMW_FIELD(ah, AR_GPIO_INTR_OUT, AR_GPIO_OUT_VAL, reg); + return AH_TRUE; +} + +/* + * Once configured for I/O - get input lines + */ +uint32_t +ar5416GpioGet(struct ath_hal *ah, uint32_t gpio) +{ + if (gpio >= AR_NUM_GPIO) + return 0xffffffff; + return ((OS_REG_READ(ah, AR_GPIO_IN) & AR_GPIO_BIT(gpio)) >> gpio); +} + +/* + * Set the GPIO Interrupt + */ +void +ar5416GpioSetIntr(struct ath_hal *ah, u_int gpio, uint32_t ilevel) +{ + uint32_t val; + + HALASSERT(gpio < AR_NUM_GPIO); + /* XXX bounds check gpio */ + val = MS(OS_REG_READ(ah, AR_GPIO_INTR_OUT), AR_GPIO_INTR_CTRL); + if (ilevel) /* 0 == interrupt on pin high */ + val &= ~AR_GPIO_BIT(gpio); + else /* 1 == interrupt on pin low */ + val |= AR_GPIO_BIT(gpio); + OS_REG_RMW_FIELD(ah, AR_GPIO_INTR_OUT, AR_GPIO_INTR_CTRL, val); + + /* Change the interrupt mask. */ + val = MS(OS_REG_READ(ah, AR_INTR_ASYNC_ENABLE), AR_INTR_GPIO); + val |= AR_GPIO_BIT(gpio); + OS_REG_RMW_FIELD(ah, AR_INTR_ASYNC_ENABLE, AR_INTR_GPIO, val); + + val = MS(OS_REG_READ(ah, AR_INTR_ASYNC_MASK), AR_INTR_GPIO); + val |= AR_GPIO_BIT(gpio); + OS_REG_RMW_FIELD(ah, AR_INTR_ASYNC_MASK, AR_INTR_GPIO, val); +} --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5416/ar5416_interrupts.c 2009-05-15 11:11:29.000000000 +0100 @@ -0,0 +1,259 @@ +/* + * 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: ar5416_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 "ar5416/ar5416.h" +#include "ar5416/ar5416reg.h" + +/* + * Checks to see if an interrupt is pending on our NIC + * + * Returns: TRUE if an interrupt is pending + * FALSE if not + */ +HAL_BOOL +ar5416IsInterruptPending(struct ath_hal *ah) +{ + uint32_t isr; + /* + * Some platforms trigger our ISR before applying power to + * the card, so make sure the INTPEND is really 1, not 0xffffffff. + */ + isr = OS_REG_READ(ah, AR_INTR_ASYNC_CAUSE); + if (isr != AR_INTR_SPURIOUS && (isr & AR_INTR_MAC_IRQ) != 0) + return AH_TRUE; + + isr = OS_REG_READ(ah, AR_INTR_SYNC_CAUSE); + if (isr != AR_INTR_SPURIOUS && (isr & AR_INTR_SYNC_DEFAULT)) + return AH_TRUE; + + return AH_FALSE; +} + +/* + * 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 +ar5416GetPendingInterrupts(struct ath_hal *ah, HAL_INT *masked) +{ + uint32_t isr, isr0, isr1, sync_cause; + + /* + * Verify there's a mac interrupt and the RTC is on. + */ + if ((OS_REG_READ(ah, AR_INTR_ASYNC_CAUSE) & AR_INTR_MAC_IRQ) && + (OS_REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M) == AR_RTC_STATUS_ON) + isr = OS_REG_READ(ah, AR_ISR); + else + isr = 0; + sync_cause = OS_REG_READ(ah, AR_INTR_SYNC_CAUSE); + sync_cause &= AR_INTR_SYNC_DEFAULT; + if (isr == 0 && sync_cause == 0) { + *masked = 0; + return AH_FALSE; + } + + if (isr != 0) { + struct ath_hal_5212 *ahp = AH5212(ah); + uint32_t mask2; + + mask2 = 0; + if (isr & AR_ISR_BCNMISC) { + uint32_t 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; + if (isr2 & AR_ISR_S2_GTT) + mask2 |= HAL_INT_GTT; + if (isr2 & AR_ISR_S2_CST) + mask2 |= HAL_INT_CST; + if (isr2 & AR_ISR_S2_TSFOOR) + mask2 |= HAL_INT_TSFOOR; + } + + 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_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); + } + + /* Interrupt Mitigation on AR5416 */ +#ifdef AR5416_INT_MITIGATION + if (isr & (AR_ISR_RXMINTR | AR_ISR_RXINTM)) + *masked |= HAL_INT_RX; + if (isr & (AR_ISR_TXMINTR | AR_ISR_TXINTM)) + *masked |= HAL_INT_TX; +#endif + *masked |= mask2; + } + if (sync_cause != 0) { + if (sync_cause & (AR_INTR_SYNC_HOST1_FATAL | AR_INTR_SYNC_HOST1_PERR)) { + *masked |= HAL_INT_FATAL; + } + if (sync_cause & AR_INTR_SYNC_RADM_CPL_TIMEOUT) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: RADM CPL timeout\n", + __func__); + OS_REG_WRITE(ah, AR_RC, AR_RC_HOSTIF); + OS_REG_WRITE(ah, AR_RC, 0); + *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] = sync_cause; + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: fatal error, ISR_RAC 0x%x SYNC_CAUSE 0x%x\n", + __func__, isr, sync_cause); + } + + OS_REG_WRITE(ah, AR_INTR_SYNC_CAUSE_CLR, sync_cause); + /* NB: flush write */ + (void) OS_REG_READ(ah, AR_INTR_SYNC_CAUSE_CLR); + } + return AH_TRUE; +} + +/* + * Atomically enables NIC interrupts. Interrupts are passed in + * via the enumerated bitmask in ints. + */ +HAL_INT +ar5416SetInterrupts(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); + + OS_REG_WRITE(ah, AR_INTR_ASYNC_ENABLE, 0); + (void) OS_REG_READ(ah, AR_INTR_ASYNC_ENABLE); + + OS_REG_WRITE(ah, AR_INTR_SYNC_ENABLE, 0); + (void) OS_REG_READ(ah, AR_INTR_SYNC_ENABLE); + } + + 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; +#ifdef AR5416_INT_MITIGATION + /* + * Overwrite default mask if Interrupt mitigation + * is specified for AR5416 + */ + mask = ints & HAL_INT_COMMON; + if (ints & HAL_INT_TX) + mask |= AR_IMR_TXMINTR | AR_IMR_TXINTM; + if (ints & HAL_INT_RX) + mask |= AR_IMR_RXERR | AR_IMR_RXMINTR | AR_IMR_RXINTM; +#endif + 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_GTT) + mask2 |= AR_IMR_S2_GTT; + if (ints & HAL_INT_CST) + mask2 |= AR_IMR_S2_CST; + if (ints & HAL_INT_TSFOOR) + mask2 |= AR_IMR_S2_TSFOOR; + } + + /* 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); + mask = 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 | + AR_IMR_S2_GTT | + AR_IMR_S2_CST); + OS_REG_WRITE(ah, AR_IMR_S2, mask | 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); + + OS_REG_WRITE(ah, AR_INTR_ASYNC_ENABLE, AR_INTR_MAC_IRQ); + OS_REG_WRITE(ah, AR_INTR_ASYNC_MASK, AR_INTR_MAC_IRQ); + + OS_REG_WRITE(ah, AR_INTR_SYNC_ENABLE, AR_INTR_SYNC_DEFAULT); + OS_REG_WRITE(ah, AR_INTR_SYNC_MASK, AR_INTR_SYNC_DEFAULT); + } + + return omask; +} --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5416/ar5416_keycache.c 2009-05-15 11:11:29.000000000 +0100 @@ -0,0 +1,66 @@ +/* + * 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: ar5416_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 "ar5416/ar5416.h" + +static const int keyType[] = { + 1, /* HAL_CIPHER_WEP */ + 0, /* HAL_CIPHER_AES_OCB */ + 2, /* HAL_CIPHER_AES_CCM */ + 0, /* HAL_CIPHER_CKIP */ + 3, /* HAL_CIPHER_TKIP */ + 0, /* HAL_CIPHER_CLR */ +}; + +/* + * Clear the specified key cache entry and any associated MIC entry. + */ +HAL_BOOL +ar5416ResetKeyCacheEntry(struct ath_hal *ah, uint16_t entry) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + + if (ar5212ResetKeyCacheEntry(ah, entry)) { + ahp->ah_keytype[entry] = keyType[HAL_CIPHER_CLR]; + return AH_TRUE; + } else + return AH_FALSE; +} + +/* + * Sets the contents of the specified key cache entry + * and any associated MIC entry. + */ +HAL_BOOL +ar5416SetKeyCacheEntry(struct ath_hal *ah, uint16_t entry, + const HAL_KEYVAL *k, const uint8_t *mac, + int xorKey) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + + if (ar5212SetKeyCacheEntry(ah, entry, k, mac, xorKey)) { + ahp->ah_keytype[entry] = keyType[k->kv_type]; + return AH_TRUE; + } else + return AH_FALSE; +} --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5416/ar5416_misc.c 2009-05-15 11:11:29.000000000 +0100 @@ -0,0 +1,499 @@ +/* + * 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: ar5416_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 "ar5416/ar5416.h" +#include "ar5416/ar5416reg.h" +#include "ar5416/ar5416phy.h" + +/* + * 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 +ar5416GetWirelessModes(struct ath_hal *ah) +{ + u_int mode; + + mode = ar5212GetWirelessModes(ah); + if (mode & HAL_MODE_11A) + mode |= HAL_MODE_11NA_HT20 + | HAL_MODE_11NA_HT40PLUS + | HAL_MODE_11NA_HT40MINUS + ; + if (mode & HAL_MODE_11G) + mode |= HAL_MODE_11NG_HT20 + | HAL_MODE_11NG_HT40PLUS + | HAL_MODE_11NG_HT40MINUS + ; + return mode; +} + +/* + * Change the LED blinking pattern to correspond to the connectivity + */ +void +ar5416SetLedState(struct ath_hal *ah, HAL_LED_STATE state) +{ + static const uint32_t ledbits[8] = { + AR_MAC_LED_ASSOC_NONE, /* HAL_LED_INIT */ + AR_MAC_LED_ASSOC_PEND, /* HAL_LED_SCAN */ + AR_MAC_LED_ASSOC_PEND, /* HAL_LED_AUTH */ + AR_MAC_LED_ASSOC_ACTIVE, /* HAL_LED_ASSOC*/ + AR_MAC_LED_ASSOC_ACTIVE, /* HAL_LED_RUN */ + AR_MAC_LED_ASSOC_NONE, + AR_MAC_LED_ASSOC_NONE, + AR_MAC_LED_ASSOC_NONE, + }; + uint32_t bits; + + bits = OS_REG_READ(ah, AR_MAC_LED); + bits = (bits &~ AR_MAC_LED_MODE) + | SM(AR_MAC_LED_MODE_POWON, AR_MAC_LED_MODE) +#if 1 + | SM(AR_MAC_LED_MODE_NETON, AR_MAC_LED_MODE) +#endif + ; + bits = (bits &~ AR_MAC_LED_ASSOC) + | SM(ledbits[state & 0x7], AR_MAC_LED_ASSOC); + OS_REG_WRITE(ah, AR_MAC_LED, bits); +} + +/* + * Reset the current hardware tsf for stamlme. + */ +void +ar5416ResetTsf(struct ath_hal *ah) +{ + uint32_t v; + int i; + + for (i = 0; i < 10; i++) { + v = OS_REG_READ(ah, AR_SLP32_MODE); + if ((v & AR_SLP32_TSF_WRITE_STATUS) == 0) + break; + OS_DELAY(10); + } + OS_REG_WRITE(ah, AR_RESET_TSF, AR_RESET_TSF_ONCE); +} + +HAL_BOOL +ar5416SetAntennaSwitch(struct ath_hal *ah, HAL_ANT_SETTING settings) +{ + return AH_TRUE; +} + +/* Setup decompression for given key index */ +HAL_BOOL +ar5416SetDecompMask(struct ath_hal *ah, uint16_t keyidx, int en) +{ + return HAL_OK; +} + +/* Setup coverage class */ +void +ar5416SetCoverageClass(struct ath_hal *ah, uint8_t coverageclass, int now) +{ +} + +/* + * Return approximation of extension channel busy over an time interval + * 0% (clear) -> 100% (busy) + * + */ +uint32_t +ar5416Get11nExtBusy(struct ath_hal *ah) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + uint32_t busy; /* percentage */ + uint32_t cycleCount, ctlBusy, extBusy; + + ctlBusy = OS_REG_READ(ah, AR_RCCNT); + extBusy = OS_REG_READ(ah, AR_EXTRCCNT); + cycleCount = OS_REG_READ(ah, AR_CCCNT); + + if (ahp->ah_cycleCount == 0 || ahp->ah_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. + */ + busy = 0; + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: cycle counter wrap. ExtBusy = 0\n", + __func__); + + } else { + uint32_t cycleDelta = cycleCount - ahp->ah_cycleCount; + uint32_t ctlBusyDelta = ctlBusy - ahp->ah_ctlBusy; + uint32_t extBusyDelta = extBusy - ahp->ah_extBusy; + uint32_t ctlClearDelta = 0; + + /* Compute control channel rxclear. + * The cycle delta may be less than the control channel delta. + * This could be solved by freezing the timers (or an atomic read, + * if one was available). Checking for the condition should be + * sufficient. + */ + if (cycleDelta > ctlBusyDelta) { + ctlClearDelta = cycleDelta - ctlBusyDelta; + } + + /* Compute ratio of extension channel busy to control channel clear + * as an approximation to extension channel cleanliness. + * + * According to the hardware folks, ext rxclear is undefined + * if the ctrl rxclear is de-asserted (i.e. busy) + */ + if (ctlClearDelta) { + busy = (extBusyDelta * 100) / ctlClearDelta; + } else { + busy = 100; + } + if (busy > 100) { + busy = 100; + } +#if 0 + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: cycleDelta 0x%x, ctlBusyDelta 0x%x, " + "extBusyDelta 0x%x, ctlClearDelta 0x%x, " + "busy %d\n", + __func__, cycleDelta, ctlBusyDelta, extBusyDelta, ctlClearDelta, busy); +#endif + } + + ahp->ah_cycleCount = cycleCount; + ahp->ah_ctlBusy = ctlBusy; + ahp->ah_extBusy = extBusy; + + return busy; +} + +/* + * Configure 20/40 operation + * + * 20/40 = joint rx clear (control and extension) + * 20 = rx clear (control) + * + * - NOTE: must stop MAC (tx) and requeue 40 MHz packets as 20 MHz when changing + * from 20/40 => 20 only + */ +void +ar5416Set11nMac2040(struct ath_hal *ah, HAL_HT_MACMODE mode) +{ + uint32_t macmode; + + /* Configure MAC for 20/40 operation */ + if (mode == HAL_HT_MACMODE_2040) { + macmode = AR_2040_JOINED_RX_CLEAR; + } else { + macmode = 0; + } + OS_REG_WRITE(ah, AR_2040_MODE, macmode); +} + +/* + * Get Rx clear (control/extension channel) + * + * Returns active low (busy) for ctrl/ext channel + * Owl 2.0 + */ +HAL_HT_RXCLEAR +ar5416Get11nRxClear(struct ath_hal *ah) +{ + HAL_HT_RXCLEAR rxclear = 0; + uint32_t val; + + val = OS_REG_READ(ah, AR_DIAG_SW); + + /* control channel */ + if (val & AR_DIAG_RXCLEAR_CTL_LOW) { + rxclear |= HAL_RX_CLEAR_CTL_LOW; + } + /* extension channel */ + if (val & AR_DIAG_RXCLEAR_CTL_LOW) { + rxclear |= HAL_RX_CLEAR_EXT_LOW; + } + return rxclear; +} + +/* + * Set Rx clear (control/extension channel) + * + * Useful for forcing the channel to appear busy for + * debugging/diagnostics + * Owl 2.0 + */ +void +ar5416Set11nRxClear(struct ath_hal *ah, HAL_HT_RXCLEAR rxclear) +{ + /* control channel */ + if (rxclear & HAL_RX_CLEAR_CTL_LOW) { + OS_REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RXCLEAR_CTL_LOW); + } else { + OS_REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_RXCLEAR_CTL_LOW); + } + /* extension channel */ + if (rxclear & HAL_RX_CLEAR_EXT_LOW) { + OS_REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RXCLEAR_EXT_LOW); + } else { + OS_REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_RXCLEAR_EXT_LOW); + } +} + +HAL_STATUS +ar5416GetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, + uint32_t capability, uint32_t *result) +{ + switch (type) { + case HAL_CAP_BB_HANG: + switch (capability) { + case HAL_BB_HANG_RIFS: + return AR_SREV_SOWL(ah) ? HAL_OK : HAL_ENOTSUPP; + case HAL_BB_HANG_DFS: + return AR_SREV_SOWL(ah) ? HAL_OK : HAL_ENOTSUPP; + case HAL_BB_HANG_RX_CLEAR: + return AR_SREV_MERLIN(ah) ? HAL_OK : HAL_ENOTSUPP; + } + break; + case HAL_CAP_MAC_HANG: + return ((ah->ah_macVersion == AR_XSREV_VERSION_OWL_PCI) || + (ah->ah_macVersion == AR_XSREV_VERSION_OWL_PCIE) || + AR_SREV_SOWL(ah)) ? + HAL_OK : HAL_ENOTSUPP; + default: + break; + } + return ar5212GetCapability(ah, type, capability, result); +} + +static int ar5416DetectMacHang(struct ath_hal *ah); +static int ar5416DetectBBHang(struct ath_hal *ah); + +HAL_BOOL +ar5416GetDiagState(struct ath_hal *ah, int request, + const void *args, uint32_t argsize, + void **result, uint32_t *resultsize) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + int hangs; + + 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_CHECK_HANGS: + if (argsize != sizeof(int)) + return AH_FALSE; + hangs = *(const int *) args; + ahp->ah_hangs = 0; + if (hangs & HAL_BB_HANGS) + ahp->ah_hangs |= ar5416DetectBBHang(ah); + /* NB: if BB is hung MAC will be hung too so skip check */ + if (ahp->ah_hangs == 0 && (hangs & HAL_MAC_HANGS)) + ahp->ah_hangs |= ar5416DetectMacHang(ah); + *result = &ahp->ah_hangs; + *resultsize = sizeof(ahp->ah_hangs); + return AH_TRUE; + } + return ar5212GetDiagState(ah, request, + args, argsize, result, resultsize); +} + +typedef struct { + uint32_t dma_dbg_3; + uint32_t dma_dbg_4; + uint32_t dma_dbg_5; + uint32_t dma_dbg_6; +} mac_dbg_regs_t; + +typedef enum { + dcu_chain_state = 0x1, + dcu_complete_state = 0x2, + qcu_state = 0x4, + qcu_fsp_ok = 0x8, + qcu_fsp_state = 0x10, + qcu_stitch_state = 0x20, + qcu_fetch_state = 0x40, + qcu_complete_state = 0x80 +} hal_mac_hangs_t; + +typedef struct { + int states; + uint8_t dcu_chain_state; + uint8_t dcu_complete_state; + uint8_t qcu_state; + uint8_t qcu_fsp_ok; + uint8_t qcu_fsp_state; + uint8_t qcu_stitch_state; + uint8_t qcu_fetch_state; + uint8_t qcu_complete_state; +} hal_mac_hang_check_t; + +static HAL_BOOL +ar5416CompareDbgHang(struct ath_hal *ah, const mac_dbg_regs_t *regs, + const hal_mac_hang_check_t *check) +{ + int found_states; + + found_states = 0; + if (check->states & dcu_chain_state) { + int i; + + for (i = 0; i < 6; i++) { + if (((regs->dma_dbg_4 >> (5*i)) & 0x1f) == + check->dcu_chain_state) + found_states |= dcu_chain_state; + } + for (i = 0; i < 4; i++) { + if (((regs->dma_dbg_5 >> (5*i)) & 0x1f) == + check->dcu_chain_state) + found_states |= dcu_chain_state; + } + } + if (check->states & dcu_complete_state) { + if ((regs->dma_dbg_6 & 0x3) == check->dcu_complete_state) + found_states |= dcu_complete_state; + } + if (check->states & qcu_stitch_state) { + if (((regs->dma_dbg_3 >> 18) & 0xf) == check->qcu_stitch_state) + found_states |= qcu_stitch_state; + } + if (check->states & qcu_fetch_state) { + if (((regs->dma_dbg_3 >> 22) & 0xf) == check->qcu_fetch_state) + found_states |= qcu_fetch_state; + } + if (check->states & qcu_complete_state) { + if (((regs->dma_dbg_3 >> 26) & 0x7) == check->qcu_complete_state) + found_states |= qcu_complete_state; + } + return (found_states == check->states); +} + +#define NUM_STATUS_READS 50 + +static int +ar5416DetectMacHang(struct ath_hal *ah) +{ + static const hal_mac_hang_check_t hang_sig1 = { + .dcu_chain_state = 0x6, + .dcu_complete_state = 0x1, + .states = dcu_chain_state + | dcu_complete_state, + }; + static const hal_mac_hang_check_t hang_sig2 = { + .qcu_stitch_state = 0x9, + .qcu_fetch_state = 0x8, + .qcu_complete_state = 0x4, + .states = qcu_stitch_state + | qcu_fetch_state + | qcu_complete_state, + }; + mac_dbg_regs_t mac_dbg; + int i; + + mac_dbg.dma_dbg_3 = OS_REG_READ(ah, AR_DMADBG_3); + mac_dbg.dma_dbg_4 = OS_REG_READ(ah, AR_DMADBG_4); + mac_dbg.dma_dbg_5 = OS_REG_READ(ah, AR_DMADBG_5); + mac_dbg.dma_dbg_6 = OS_REG_READ(ah, AR_DMADBG_6); + for (i = 1; i <= NUM_STATUS_READS; i++) { + if (mac_dbg.dma_dbg_3 != OS_REG_READ(ah, AR_DMADBG_3) || + mac_dbg.dma_dbg_4 != OS_REG_READ(ah, AR_DMADBG_4) || + mac_dbg.dma_dbg_5 != OS_REG_READ(ah, AR_DMADBG_5) || + mac_dbg.dma_dbg_6 != OS_REG_READ(ah, AR_DMADBG_6)) + return 0; + } + + if (ar5416CompareDbgHang(ah, &mac_dbg, &hang_sig1)) + return HAL_MAC_HANG_SIG1; + if (ar5416CompareDbgHang(ah, &mac_dbg, &hang_sig2)) + return HAL_MAC_HANG_SIG2; + + HALDEBUG(ah, HAL_DEBUG_ANY, "%s Found an unknown MAC hang signature " + "DMADBG_3=0x%x DMADBG_4=0x%x DMADBG_5=0x%x DMADBG_6=0x%x\n", + __func__, mac_dbg.dma_dbg_3, mac_dbg.dma_dbg_4, mac_dbg.dma_dbg_5, + mac_dbg.dma_dbg_6); + + return HAL_MAC_HANG_UNKNOWN; +} + +/* + * Determine if the baseband using the Observation Bus Register + */ +static int +ar5416DetectBBHang(struct ath_hal *ah) +{ +#define N(a) (sizeof(a)/sizeof(a[0])) + /* + * Check the PCU Observation Bus 1 register (0x806c) + * NUM_STATUS_READS times + * + * 4 known BB hang signatures - + * [1] bits 8,9,11 are 0. State machine state (bits 25-31) is 0x1E + * [2] bits 8,9 are 1, bit 11 is 0. State machine state + * (bits 25-31) is 0x52 + * [3] bits 8,9 are 1, bit 11 is 0. State machine state + * (bits 25-31) is 0x18 + * [4] bit 10 is 1, bit 11 is 0. WEP state (bits 12-17) is 0x2, + * Rx State (bits 20-24) is 0x7. + */ + static const struct { + uint32_t val; + uint32_t mask; + int code; + } hang_list[] = { + /* Reg Value Reg Mask Hang Code XXX */ + { 0x1E000000, 0x7E000B00, HAL_BB_HANG_DFS }, + { 0x52000B00, 0x7E000B00, HAL_BB_HANG_RIFS }, + { 0x18000B00, 0x7E000B00, HAL_BB_HANG_RX_CLEAR }, + { 0x00702400, 0x7E7FFFEF, HAL_BB_HANG_RX_CLEAR } + }; + uint32_t hang_sig; + int i; + + hang_sig = OS_REG_READ(ah, AR_OBSERV_1); + for (i = 1; i <= NUM_STATUS_READS; i++) { + if (hang_sig != OS_REG_READ(ah, AR_OBSERV_1)) + return 0; + } + for (i = 0; i < N(hang_list); i++) + if ((hang_sig & hang_list[i].mask) == hang_list[i].val) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s BB hang, signature 0x%x, code 0x%x\n", + __func__, hang_sig, hang_list[i].code); + return hang_list[i].code; + } + + HALDEBUG(ah, HAL_DEBUG_ANY, "%s Found an unknown BB hang signature! " + "<0x806c>=0x%x\n", __func__, hang_sig); + + return HAL_BB_HANG_UNKNOWN; +#undef N +} +#undef NUM_STATUS_READS --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5416/ar5416_phy.c 2009-05-15 11:11:29.000000000 +0100 @@ -0,0 +1,126 @@ +/* + * 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: ar5416_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 "ar5416/ar5416.h" + +/* shorthands to compact tables for readability */ +#define OFDM IEEE80211_T_OFDM +#define CCK IEEE80211_T_CCK +#define HT IEEE80211_T_HT + +HAL_RATE_TABLE ar5416_11ng_table = { + 28, /* 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 }, +/* 6.5 Mb */ { AH_TRUE, HT, 6500, 0x80, 0x00, 0, 8, 0, 0 }, +/* 13 Mb */ { AH_TRUE, HT, 13000, 0x81, 0x00, 1, 8, 0, 0 }, +/*19.5 Mb */ { AH_TRUE, HT, 19500, 0x82, 0x00, 2, 8, 0, 0 }, +/* 26 Mb */ { AH_TRUE, HT, 26000, 0x83, 0x00, 3, 8, 0, 0 }, +/* 39 Mb */ { AH_TRUE, HT, 39000, 0x84, 0x00, 4, 8, 0, 0 }, +/* 52 Mb */ { AH_TRUE, HT, 52000, 0x85, 0x00, 5, 8, 0, 0 }, +/*58.5 Mb */ { AH_TRUE, HT, 58500, 0x86, 0x00, 6, 8, 0, 0 }, +/* 65 Mb */ { AH_TRUE, HT, 65000, 0x87, 0x00, 7, 8, 0, 0 }, +/* 13 Mb */ { AH_TRUE, HT, 13000, 0x88, 0x00, 8, 8, 0, 0 }, +/* 26 Mb */ { AH_TRUE, HT, 26000, 0x89, 0x00, 9, 8, 0, 0 }, +/* 39 Mb */ { AH_TRUE, HT, 39000, 0x8a, 0x00, 10, 8, 0, 0 }, +/* 52 Mb */ { AH_TRUE, HT, 52000, 0x8b, 0x00, 11, 8, 0, 0 }, +/* 78 Mb */ { AH_TRUE, HT, 78000, 0x8c, 0x00, 12, 8, 0, 0 }, +/* 104 Mb */ { AH_TRUE, HT, 104000, 0x8d, 0x00, 13, 8, 0, 0 }, +/* 117 Mb */ { AH_TRUE, HT, 117000, 0x8e, 0x00, 14, 8, 0, 0 }, +/* 130 Mb */ { AH_TRUE, HT, 130000, 0x8f, 0x00, 15, 8, 0, 0 }, + }, +}; + +static HAL_RATE_TABLE ar5416_11na_table = { + 24, /* 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, 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 }, +/* 6.5 Mb */ { AH_TRUE, HT, 6500, 0x80, 0x00, 0, 8, 0, 0 }, +/* 13 Mb */ { AH_TRUE, HT, 13000, 0x81, 0x00, 1, 8, 0, 0 }, +/*19.5 Mb */ { AH_TRUE, HT, 19500, 0x82, 0x00, 2, 8, 0, 0 }, +/* 26 Mb */ { AH_TRUE, HT, 26000, 0x83, 0x00, 3, 8, 0, 0 }, +/* 39 Mb */ { AH_TRUE, HT, 39000, 0x84, 0x00, 4, 8, 0, 0 }, +/* 52 Mb */ { AH_TRUE, HT, 52000, 0x85, 0x00, 5, 8, 0, 0 }, +/*58.5 Mb */ { AH_TRUE, HT, 58500, 0x86, 0x00, 6, 8, 0, 0 }, +/* 65 Mb */ { AH_TRUE, HT, 65000, 0x87, 0x00, 7, 8, 0, 0 }, +/* 13 Mb */ { AH_TRUE, HT, 13000, 0x88, 0x00, 8, 8, 0, 0 }, +/* 26 Mb */ { AH_TRUE, HT, 26000, 0x89, 0x00, 9, 8, 0, 0 }, +/* 39 Mb */ { AH_TRUE, HT, 39000, 0x8a, 0x00, 10, 8, 0, 0 }, +/* 52 Mb */ { AH_TRUE, HT, 52000, 0x8b, 0x00, 11, 8, 0, 0 }, +/* 78 Mb */ { AH_TRUE, HT, 78000, 0x8c, 0x00, 12, 8, 0, 0 }, +/* 104 Mb */ { AH_TRUE, HT, 104000, 0x8d, 0x00, 13, 8, 0, 0 }, +/* 117 Mb */ { AH_TRUE, HT, 117000, 0x8e, 0x00, 14, 8, 0, 0 }, +/* 130 Mb */ { AH_TRUE, HT, 130000, 0x8f, 0x00, 15, 8, 0, 0 }, + }, +}; + +#undef OFDM +#undef CCK +#undef HT + +const HAL_RATE_TABLE * +ar5416GetRateTable(struct ath_hal *ah, u_int mode) +{ + HAL_RATE_TABLE *rt; + switch (mode) { + case HAL_MODE_11NG_HT20: + case HAL_MODE_11NG_HT40PLUS: + case HAL_MODE_11NG_HT40MINUS: + rt = &ar5416_11ng_table; + break; + case HAL_MODE_11NA_HT20: + case HAL_MODE_11NA_HT40PLUS: + case HAL_MODE_11NA_HT40MINUS: + rt = &ar5416_11na_table; + break; + default: + return ar5212GetRateTable(ah, mode); + } + ath_hal_setupratetable(ah, rt); + return rt; +} --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5416/ar5416_power.c 2009-05-15 11:11:29.000000000 +0100 @@ -0,0 +1,173 @@ +/* + * 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: ar5416_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 "ar5416/ar5416.h" +#include "ar5416/ar5416reg.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 +ar5416SetPowerModeAwake(struct ath_hal *ah, int setChip) +{ +#define POWER_UP_TIME 200000 + uint32_t val; + int i = 0; + + if (setChip) { + /* + * Do a Power-On-Reset if OWL is shutdown + * the NetBSD driver power-cycles the Cardbus slot + * as part of the reset procedure. + */ + if ((OS_REG_READ(ah, AR_RTC_STATUS) + & AR_RTC_PM_STATUS_M) == AR_RTC_STATUS_SHUTDOWN) { + if (!ar5416SetResetReg(ah, HAL_RESET_POWER_ON)) + goto bad; + } + + OS_REG_SET_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN); + OS_DELAY(50); /* Give chip the chance to awake */ + + for (i = POWER_UP_TIME / 50; i != 0; i--) { + val = OS_REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M; + if (val == AR_RTC_STATUS_ON) + break; + OS_DELAY(50); + OS_REG_SET_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN); + } + bad: + if (i == 0) { +#ifdef AH_DEBUG + ath_hal_printf(ah, "%s: Failed to wakeup in %ums\n", + __func__, POWER_UP_TIME/1000); +#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 +ar5416SetPowerModeSleep(struct ath_hal *ah, int setChip) +{ + OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); + if (setChip) { + /* Clear the RTC force wake bit to allow the mac to sleep */ + OS_REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN); + OS_REG_WRITE(ah, AR_RC, AR_RC_AHB|AR_RC_HOSTIF); + /* Shutdown chip. Active low */ + OS_REG_CLR_BIT(ah, AR_RTC_RESET, AR_RTC_RESET_EN); + } +} + +/* + * 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 +ar5416SetPowerModeNetworkSleep(struct ath_hal *ah, int setChip) +{ + OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); + + if (setChip) + OS_REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN); +} + +/* + * Set power mgt to the requested mode, and conditionally set + * the chip as well + */ +HAL_BOOL +ar5416SetPowerMode(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; + if (!setChip) + return 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 = ar5416SetPowerModeAwake(ah, setChip); + break; + case HAL_PM_FULL_SLEEP: + ar5416SetPowerModeSleep(ah, setChip); + break; + case HAL_PM_NETWORK_SLEEP: + ar5416SetPowerModeNetworkSleep(ah, setChip); + break; + default: + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unknown power mode 0x%x\n", + __func__, mode); + return AH_FALSE; + } + ahp->ah_powerMode = mode; + return status; +} + +/* + * Return the current sleep mode of the chip + */ +HAL_POWER_MODE +ar5416GetPowerMode(struct ath_hal *ah) +{ + int mode = OS_REG_READ(ah, AR_RTC_STATUS); + switch (mode & AR_RTC_PM_STATUS_M) { + case AR_RTC_STATUS_ON: + case AR_RTC_STATUS_WAKEUP: + return HAL_PM_AWAKE; + case AR_RTC_STATUS_SLEEP: + return HAL_PM_NETWORK_SLEEP; + case AR_RTC_STATUS_SHUTDOWN: + return HAL_PM_FULL_SLEEP; + default: + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: unknown power mode, RTC_STATUS 0x%x\n", + __func__, mode); + return HAL_PM_UNDEFINED; + } +} --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5416/ar5416_recv.c 2009-05-15 11:11:29.000000000 +0100 @@ -0,0 +1,178 @@ +/* + * 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: ar5416_recv.c,v 1.1 2009/03/23 17:14:48 sborrill Exp $ + */ +#include "opt_ah.h" + +#include "ah.h" +#include "ah_desc.h" +#include "ah_internal.h" + +#include "ar5416/ar5416.h" +#include "ar5416/ar5416reg.h" +#include "ar5416/ar5416desc.h" + +/* + * Start receive at the PCU engine + */ +void +ar5416StartPcuReceive(struct ath_hal *ah) +{ + struct ath_hal_private *ahp = AH_PRIVATE(ah); + + HALDEBUG(ah, HAL_DEBUG_RX, "%s: Start PCU Receive \n", __func__); + ar5212EnableMibCounters(ah); + /* NB: restore current settings */ + ar5416AniReset(ah, ahp->ah_curchan, ahp->ah_opmode, AH_TRUE); + /* + * NB: must do after enabling phy errors to avoid rx + * frames w/ corrupted descriptor status. + */ + OS_REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT); +} + +/* + * Stop receive at the PCU engine + * and abort current frame in PCU + */ +void +ar5416StopPcuReceive(struct ath_hal *ah) +{ + OS_REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT); + + HALDEBUG(ah, HAL_DEBUG_RX, "%s: Stop PCU Receive \n", __func__); + ar5212DisableMibCounters(ah); +} + +/* + * Initialize RX descriptor, by clearing the status and setting + * the size (and any other flags). + */ +HAL_BOOL +ar5416SetupRxDesc(struct ath_hal *ah, struct ath_desc *ds, + uint32_t size, u_int flags) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + + HALASSERT((size &~ AR_BufLen) == 0); + + ads->ds_ctl1 = size & AR_BufLen; + if (flags & HAL_RXDESC_INTREQ) + ads->ds_ctl1 |= AR_RxIntrReq; + + /* this should be enough */ + ads->ds_rxstatus8 &= ~AR_RxDone; + + 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 +ar5416ProcRxDesc(struct ath_hal *ah, struct ath_desc *ds, + uint32_t pa, struct ath_desc *nds, uint64_t tsf, + struct ath_rx_status *rs) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + struct ar5416_desc *ands = AR5416DESC(nds); + + if ((ads->ds_rxstatus8 & AR_RxDone) == 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_rxstatus8 & AR_RxDone) == 0 + && OS_REG_READ(ah, AR_RXDP) == pa) + return HAL_EINPROGRESS; + + rs->rs_status = 0; + rs->rs_flags = 0; + + rs->rs_datalen = ads->ds_rxstatus1 & AR_DataLen; + rs->rs_tstamp = ads->AR_RcvTimestamp; + + /* XXX what about KeyCacheMiss? */ + + rs->rs_rssi = MS(ads->ds_rxstatus4, AR_RxRSSICombined); + rs->rs_rssi_ctl[0] = MS(ads->ds_rxstatus0, AR_RxRSSIAnt00); + rs->rs_rssi_ctl[1] = MS(ads->ds_rxstatus0, AR_RxRSSIAnt01); + rs->rs_rssi_ctl[2] = MS(ads->ds_rxstatus0, AR_RxRSSIAnt02); + rs->rs_rssi_ext[0] = MS(ads->ds_rxstatus4, AR_RxRSSIAnt10); + rs->rs_rssi_ext[1] = MS(ads->ds_rxstatus4, AR_RxRSSIAnt11); + rs->rs_rssi_ext[2] = MS(ads->ds_rxstatus4, AR_RxRSSIAnt12); + + if (ads->ds_rxstatus8 & AR_RxKeyIdxValid) + rs->rs_keyix = MS(ads->ds_rxstatus8, AR_KeyIdx); + else + rs->rs_keyix = HAL_RXKEYIX_INVALID; + + /* NB: caller expected to do rate table mapping */ + rs->rs_rate = RXSTATUS_RATE(ah, ads); + rs->rs_more = (ads->ds_rxstatus1 & AR_RxMore) ? 1 : 0; + + rs->rs_isaggr = (ads->ds_rxstatus8 & AR_RxAggr) ? 1 : 0; + rs->rs_moreaggr = (ads->ds_rxstatus8 & AR_RxMoreAggr) ? 1 : 0; + rs->rs_antenna = MS(ads->ds_rxstatus3, AR_RxAntenna); + + if (ads->ds_rxstatus3 & AR_GI) + rs->rs_flags |= HAL_RX_GI; + if (ads->ds_rxstatus3 & AR_2040) + rs->rs_flags |= HAL_RX_2040; + + if (ads->ds_rxstatus8 & AR_PreDelimCRCErr) + rs->rs_flags |= HAL_RX_DELIM_CRC_PRE; + if (ads->ds_rxstatus8 & AR_PostDelimCRCErr) + rs->rs_flags |= HAL_RX_DELIM_CRC_POST; + if (ads->ds_rxstatus8 & AR_DecryptBusyErr) + rs->rs_flags |= HAL_RX_DECRYPT_BUSY; + if (ads->ds_rxstatus8 & AR_HiRxChain) + rs->rs_flags |= HAL_RX_HI_RX_CHAIN; + + if ((ads->ds_rxstatus8 & AR_RxFrameOK) == 0) { + /* + * These four bits should not be set together. The + * 5416 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_rxstatus8 & AR_CRCErr) + rs->rs_status |= HAL_RXERR_CRC; + else if (ads->ds_rxstatus8 & AR_PHYErr) { + u_int phyerr; + + rs->rs_status |= HAL_RXERR_PHY; + phyerr = MS(ads->ds_rxstatus8, AR_PHYErrCode); + rs->rs_phyerr = phyerr; + } else if (ads->ds_rxstatus8 & AR_DecryptCRCErr) + rs->rs_status |= HAL_RXERR_DECRYPT; + else if (ads->ds_rxstatus8 & 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/ar5416/ar5416_reset.c 2009-05-15 11:11:29.000000000 +0100 @@ -0,0 +1,2895 @@ +/* + * 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: ar5416_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 "ah_eeprom_v14.h" + +#include "ar5416/ar5416.h" +#include "ar5416/ar5416reg.h" +#include "ar5416/ar5416phy.h" +#ifdef AH_SUPPORT_AR9280 +#include "ar5416/ar9280.h" +#endif + +/* Eeprom versioning macros. Returns true if the version is equal or newer than the ver specified */ +#define EEP_MINOR(_ah) \ + (AH_PRIVATE(_ah)->ah_eeversion & AR5416_EEP_VER_MINOR_MASK) +#define IS_EEP_MINOR_V2(_ah) (EEP_MINOR(_ah) >= AR5416_EEP_MINOR_VER_2) +#define IS_EEP_MINOR_V3(_ah) (EEP_MINOR(_ah) >= AR5416_EEP_MINOR_VER_3) + +/* Additional Time delay to wait after activiting the Base band */ +#define BASE_ACTIVATE_DELAY 100 /* 100 usec */ +#define PLL_SETTLE_DELAY 300 /* 300 usec */ +#define RTC_PLL_SETTLE_DELAY 1000 /* 1 ms */ + +static void ar5416InitDMA(struct ath_hal *ah); +static void ar5416InitBB(struct ath_hal *ah, HAL_CHANNEL *chan); +static void ar5416InitIMR(struct ath_hal *ah, HAL_OPMODE opmode); +static void ar5416InitQoS(struct ath_hal *ah); +static void ar5416InitUserSettings(struct ath_hal *ah); + +static HAL_BOOL ar5416SetTransmitPower(struct ath_hal *ah, + HAL_CHANNEL_INTERNAL *chan, uint16_t *rfXpdGain); + +#if 0 +static HAL_BOOL ar5416ChannelChange(struct ath_hal *, HAL_CHANNEL *); +#endif +static void ar5416SetDeltaSlope(struct ath_hal *, HAL_CHANNEL_INTERNAL *); +static void ar5416SpurMitigate(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan); +#ifdef AH_SUPPORT_AR9280 +static void ar9280SpurMitigate(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan); +#endif + +static HAL_BOOL ar5416SetResetPowerOn(struct ath_hal *ah); +static HAL_BOOL ar5416SetReset(struct ath_hal *ah, int type); +static void ar5416InitPLL(struct ath_hal *ah, HAL_CHANNEL *chan); +static HAL_BOOL ar5416SetBoardValues(struct ath_hal *, HAL_CHANNEL_INTERNAL *); +static HAL_BOOL ar5416SetPowerPerRateTable(struct ath_hal *ah, + struct ar5416eeprom *pEepData, + HAL_CHANNEL_INTERNAL *chan, int16_t *ratesArray, + uint16_t cfgCtl, uint16_t AntennaReduction, + uint16_t twiceMaxRegulatoryPower, + uint16_t powerLimit); +static HAL_BOOL ar5416SetPowerCalTable(struct ath_hal *ah, + struct ar5416eeprom *pEepData, + HAL_CHANNEL_INTERNAL *chan, + int16_t *pTxPowerIndexOffset); +static uint16_t ar5416GetMaxEdgePower(uint16_t freq, + CAL_CTL_EDGES *pRdEdgesPower, HAL_BOOL is2GHz); +static void ar5416GetTargetPowers(struct ath_hal *ah, + HAL_CHANNEL_INTERNAL *chan, CAL_TARGET_POWER_HT *powInfo, + uint16_t numChannels, CAL_TARGET_POWER_HT *pNewPower, + uint16_t numRates, HAL_BOOL isHt40Target); +static void ar5416GetTargetPowersLeg(struct ath_hal *ah, + HAL_CHANNEL_INTERNAL *chan, CAL_TARGET_POWER_LEG *powInfo, + uint16_t numChannels, CAL_TARGET_POWER_LEG *pNewPower, + uint16_t numRates, HAL_BOOL isExtTarget); + +static int16_t interpolate(uint16_t target, uint16_t srcLeft, + uint16_t srcRight, int16_t targetLeft, int16_t targetRight); +static void ar5416Set11nRegs(struct ath_hal *ah, HAL_CHANNEL *chan); +static void ar5416GetGainBoundariesAndPdadcs(struct ath_hal *ah, + HAL_CHANNEL_INTERNAL *chan, CAL_DATA_PER_FREQ *pRawDataSet, + uint8_t * bChans, uint16_t availPiers, + uint16_t tPdGainOverlap, int16_t *pMinCalPower, + uint16_t * pPdGainBoundaries, uint8_t * pPDADCValues, + uint16_t numXpdGains); +static HAL_BOOL getLowerUpperIndex(uint8_t target, uint8_t *pList, + uint16_t listSize, uint16_t *indexL, uint16_t *indexR); +static HAL_BOOL ar5416FillVpdTable(uint8_t pwrMin, uint8_t pwrMax, + uint8_t *pPwrList, uint8_t *pVpdList, + uint16_t numIntercepts, uint8_t *pRetVpdList); + +/* + * 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 +ar5416Reset(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; + uint32_t softLedCfg; + uint32_t saveDefAntenna, saveLedState; + uint32_t macStaId1; + uint16_t rfXpdGain[2]; + u_int modesIndex, freqIndex; + HAL_STATUS ecode; + int i, regWrites = 0; + uint32_t powerVal, rssiThrReg; + uint32_t ackTpcPow, ctsTpcPow, chirpTpcPow; + + 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 (!ar5416SetPowerMode(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); + } else { + HALDEBUG(ah, HAL_DEBUG_RESET, + "%s: Ch=%u Max=%d Min=%d\n",__func__, + ichan->channel, ichan->maxTxPower, ichan->minTxPower); + } + 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_VER14_1); + + /* XXX Turn on fast channel change for 5416 */ + /* + * Preserve the bmiss rssi threshold and count threshold + * across resets + */ + rssiThrReg = OS_REG_READ(ah, AR_RSSI_THR); + /* If reg is zero, first time thru set to default val */ + if (rssiThrReg == 0) + rssiThrReg = INIT_RSSI_THR; + + /* + * 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_MAC_LED) & + (AR_MAC_LED_ASSOC | AR_MAC_LED_MODE | + AR_MAC_LED_BLINK_THRESH_SEL | AR_MAC_LED_BLINK_SLOW); + softLedCfg = OS_REG_READ(ah, AR_GPIO_INTR_OUT); + + /* + * Adjust gain parameters before reset if + * there's an outstanding gain updated. + */ + (void) ar5416GetRfgain(ah); + + if (!ar5416ChipReset(ah, chan)) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: chip reset failed\n", __func__); + FAIL(HAL_EIO); + } + + /* Restore bmiss rssi & count thresholds */ + OS_REG_WRITE(ah, AR_RSSI_THR, rssiThrReg); + + /* Setup the indices for the next set of register array writes */ + /* XXX Ignore 11n dynamic mode on the AR5416 for the moment */ + switch (chan->channelFlags & CHANNEL_ALL) { + case CHANNEL_A: + case CHANNEL_A_HT20: + modesIndex = 1; + freqIndex = 1; + break; + case CHANNEL_T: + case CHANNEL_A_HT40PLUS: + case CHANNEL_A_HT40MINUS: + modesIndex = 2; + freqIndex = 1; + break; + case CHANNEL_PUREG: + case CHANNEL_G_HT20: + case CHANNEL_B: /* treat as channel G , no B mode suport in owl */ + modesIndex = 4; + freqIndex = 2; + break; + case CHANNEL_G_HT40PLUS: + case CHANNEL_G_HT40MINUS: + modesIndex = 3; + 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); + + /* + * Write addac shifts + */ + OS_REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_EXTERNAL_RADIO); +#if 0 + /* NB: only required for Sowl */ + ar5416EepromSetAddac(ah, ichan); +#endif + regWrites = ath_hal_ini_write(ah, &AH5416(ah)->ah_ini_addac, 1, + regWrites); + OS_REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_INTERNAL_ADDAC); + + /* XXX Merlin ini fixups */ + /* XXX Merlin 100us delay for shift registers */ + regWrites = ath_hal_ini_write(ah, &ahp->ah_ini_modes, modesIndex, + regWrites); +#ifdef AH_SUPPORT_AR9280 + if (AR_SREV_MERLIN_20_OR_LATER(ah)) { + regWrites = ath_hal_ini_write(ah, &AH9280(ah)->ah_ini_rxgain, + modesIndex, regWrites); + regWrites = ath_hal_ini_write(ah, &AH9280(ah)->ah_ini_txgain, + modesIndex, regWrites); + } +#endif + /* XXX Merlin 100us delay for shift registers */ + regWrites = ath_hal_ini_write(ah, &ahp->ah_ini_common, 1, regWrites); + /* Setup 11n MAC/Phy mode registers */ + ar5416Set11nRegs(ah,chan); + /* XXX updated regWrites? */ + ahp->ah_rfHal->writeRegs(ah, modesIndex, freqIndex, regWrites); +#ifdef AH_SUPPORT_AR9280 + if (AR_SREV_MERLIN_20(ah) && IS_5GHZ_FAST_CLOCK_EN(ah, chan)) { + /* 5GHz channels w/ Fast Clock use different modal values */ + regWrites = ath_hal_ini_write(ah, &AH9280(ah)->ah_ini_xmodes, + modesIndex, regWrites); + } +#endif + + OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__); + + HALDEBUG(ah, HAL_DEBUG_RESET, ">>>2 %s: AR_PHY_DAG_CTRLCCK=0x%x\n", + __func__, OS_REG_READ(ah,AR_PHY_DAG_CTRLCCK)); + HALDEBUG(ah, HAL_DEBUG_RESET, ">>>2 %s: AR_PHY_ADC_CTL=0x%x\n", + __func__, OS_REG_READ(ah,AR_PHY_ADC_CTL)); + + /* Set the mute mask to the correct default */ + if (AH_PRIVATE(ah)->ah_phyRev >= AR_PHY_CHIP_ID_REV_2) + 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 (AH5416(ah)->ah_rx_chainmask == 0x5 || + AH5416(ah)->ah_tx_chainmask == 0x5) + OS_REG_WRITE(ah, AR_PHY_ANALOG_SWAP, AR_PHY_SWAP_ALT_CHAIN); + /* Setup Chain Masks */ + OS_REG_WRITE(ah, AR_PHY_RX_CHAINMASK, AH5416(ah)->ah_rx_chainmask); + OS_REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, AH5416(ah)->ah_rx_chainmask); + OS_REG_WRITE(ah, AR_SELFGEN_MASK, AH5416(ah)->ah_tx_chainmask); + + /* Setup the transmit power values. */ + if (!ar5416SetTransmitPower(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, freqIndex, 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)|| IS_CHAN_HT(chan)) + ar5416SetDeltaSlope(ah, ichan); + +#ifdef AH_SUPPORT_AR9280 + if (AR_SREV_MERLIN_10_OR_LATER(ah)) + ar9280SpurMitigate(ah, ichan); + else +#endif + ar5416SpurMitigate(ah, ichan); + + /* Setup board specific options for EEPROM version 3 */ + if (!ar5416SetBoardValues(ah, ichan)) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: error setting board options\n", __func__); + FAIL(HAL_EIO); + } + + 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_MAC_LED, OS_REG_READ(ah, AR_MAC_LED) | saveLedState); + /* Restore soft Led state to GPIO */ + OS_REG_WRITE(ah, AR_GPIO_INTR_OUT, softLedCfg); + + /* 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__); + + /* 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); + + ar5416InitIMR(ah, opmode); + ar5212SetCoverageClass(ah, AH_PRIVATE(ah)->ah_coverageClass, 1); + ar5416InitQoS(ah); + ar5416InitUserSettings(ah); + + /* + * disable seq number generation in hw + */ + OS_REG_WRITE(ah, AR_STA_ID1, + OS_REG_READ(ah, AR_STA_ID1) | AR_STA_ID1_PRESERVE_SEQNUM); + + ar5416InitDMA(ah); + + /* + * program OBS bus to see MAC interrupts + */ + OS_REG_WRITE(ah, AR_OBS, 8); + +#ifdef AR5416_INT_MITIGATION + OS_REG_WRITE(ah, AR_MIRT, 0); + OS_REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_LAST, 500); + OS_REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_FIRST, 2000); +#endif + + ar5416InitBB(ah, chan); + + /* Setup compression registers */ + ar5212SetCompRegs(ah); /* XXX not needed? */ + + /* + * 5416 baseband will check the per rate power table + * and select the lower of the two + */ + ackTpcPow = 63; + ctsTpcPow = 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); + + if (!ar5416InitCal(ah, chan)) + FAIL(HAL_ESELFTEST); + + 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__); + + 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 +} + +#if 0 +/* + * 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 +ar5416ChannelChange(struct ath_hal *ah, HAL_CHANNEL *chan) +{ + uint32_t ulCount; + uint32_t data, synthDelay, qnum; + uint16_t rfXpdGain[4]; + struct ath_hal_5212 *ahp = AH5212(ah); + 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)) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: frames pending on queue %d\n", __func__, qnum); + return AH_FALSE; + } + } + + /* + * Kill last Baseband Rx Frame - Request analog bus grant + */ + OS_REG_WRITE(ah, AR_PHY_RFBUS_REQ, AR_PHY_RFBUS_REQ_REQUEST); + if (!ath_hal_wait(ah, AR_PHY_RFBUS_GNT, AR_PHY_RFBUS_GRANT_EN, AR_PHY_RFBUS_GRANT_EN)) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: could not kill baseband rx\n", + __func__); + return AH_FALSE; + } + + ar5416Set11nRegs(ah, chan); /* NB: setup 5416-specific regs */ + + /* Change the synth */ + if (!ar5212SetChannel(ah, ichan)) + return AH_FALSE; + + /* Setup the transmit power values. */ + if (!ar5416SetTransmitPower(ah, ichan, rfXpdGain)) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: error init'ing transmit power\n", __func__); + 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); + + /* Release the RFBus Grant */ + OS_REG_WRITE(ah, AR_PHY_RFBUS_REQ, 0); + + /* Write delta slope for OFDM enabled modes (A, G, Turbo) */ + if (IS_CHAN_OFDM(ichan)|| IS_CHAN_HT(chan)) { + if (ahp->ah_eeprom.ee_version >= AR_EEPROM_VER5_3 && + !IS_CHAN_B(chan)) + ar5212SetSpurMitigation(ah, ichan); + ar5416SetDeltaSlope(ah, ichan); + } + + /* XXX spur mitigation for Melin */ + + /* Copy over internal channel flags to public hal channel */ + + 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; + AH_PRIVATE(ah)->ah_curchan->ah_channel_time=0; + AH_PRIVATE(ah)->ah_curchan->ah_tsf_last = ar5212GetTsf64(ah); + ar5212TxEnable(ah,AH_TRUE); + return AH_TRUE; +} +#endif + +static void +ar5416InitDMA(struct ath_hal *ah) +{ + + /* + * set AHB_MODE not to do cacheline prefetches + */ + OS_REG_SET_BIT(ah, AR_AHB_MODE, AR_AHB_PREFETCH_RD_EN); + + /* + * let mac dma reads be in 128 byte chunks + */ + OS_REG_WRITE(ah, AR_TXCFG, + (OS_REG_READ(ah, AR_TXCFG) & ~AR_TXCFG_DMASZ_MASK) | AR_TXCFG_DMASZ_128B); + + /* + * let mac dma writes be in 128 byte chunks + */ + OS_REG_WRITE(ah, AR_RXCFG, + (OS_REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_DMASZ_MASK) | AR_RXCFG_DMASZ_128B); + + /* XXX restore TX trigger level */ + + /* + * Setup receive FIFO threshold to hold off TX activities + */ + OS_REG_WRITE(ah, AR_RXFIFO_CFG, 0x200); + + /* + * reduce the number of usable entries in PCU TXBUF to avoid + * wrap around. + */ + OS_REG_WRITE(ah, AR_PCU_TXBUF_CTRL, AR_PCU_TXBUF_CTRL_USABLE_SIZE); +} + +static void +ar5416InitBB(struct ath_hal *ah, HAL_CHANNEL *chan) +{ + uint32_t synthDelay; + + /* + * 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; + } + + /* Turn on PLL on 5416 */ + HALDEBUG(ah, HAL_DEBUG_RESET, "%s %s channel\n", + __func__, IS_CHAN_5GHZ(chan) ? "5GHz" : "2GHz"); + ar5416InitPLL(ah, chan); + + /* Activate the PHY (includes baseband activate and synthesizer on) */ + OS_REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); + + /* + * If the AP starts the calibration before the base band timeout + * completes we could get rx_clear false triggering. Add 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); + } +} + +static void +ar5416InitIMR(struct ath_hal *ah, HAL_OPMODE opmode) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + + /* + * 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_TXERR | AR_IMR_TXURN + | AR_IMR_RXERR | AR_IMR_RXORN + | AR_IMR_BCNMISC; + +#ifdef AR5416_INT_MITIGATION + ahp->ah_maskReg |= AR_IMR_TXINTM | AR_IMR_RXINTM + | AR_IMR_TXMINTR | AR_IMR_RXMINTR; +#else + ahp->ah_maskReg |= AR_IMR_TXOK | AR_IMR_RXOK; +#endif + 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 */ + +#if 0 + OS_REG_WRITE(ah, AR_IMR_S2, + OS_REG_READ(ah, AR_IMR_S2) | AR_IMR_S2_GTT | AR_IMR_S2_CST); +#endif +} + +static void +ar5416InitQoS(struct ath_hal *ah) +{ + /* QoS support */ + 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)); + + /* + * initialize TXOP for all TIDs + */ + OS_REG_WRITE(ah, AR_TXOP_X, AR_TXOP_X_VAL); + OS_REG_WRITE(ah, AR_TXOP_0_3, 0xFFFFFFFF); + OS_REG_WRITE(ah, AR_TXOP_4_7, 0xFFFFFFFF); + OS_REG_WRITE(ah, AR_TXOP_8_11, 0xFFFFFFFF); + OS_REG_WRITE(ah, AR_TXOP_12_15, 0xFFFFFFFF); +} + +static void +ar5416InitUserSettings(struct ath_hal *ah) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + + /* 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); +#if 0 /* XXX Todo */ + if (ahp->ah_globaltxtimeout != (u_int) -1) + ar5416SetGlobalTxTimeout(ah, ahp->ah_globaltxtimeout); +#endif +} + +/* + * Places the hardware into reset and then pulls it out of reset + */ +HAL_BOOL +ar5416ChipReset(struct ath_hal *ah, HAL_CHANNEL *chan) +{ + uint32_t rfMode = 0; + + OS_MARK(ah, AH_MARK_CHIPRESET, chan ? chan->channel : 0); + /* + * Warm reset is optimistic. + */ + if (AR_SREV_MERLIN_20_OR_LATER(ah) && + ath_hal_eepromGetFlag(ah, AR_EEP_OL_PWRCTRL)) { + if (!ar5416SetResetReg(ah, HAL_RESET_POWER_ON)) + return AH_FALSE; + } else { + if (!ar5416SetResetReg(ah, HAL_RESET_WARM)) + return AH_FALSE; + } + + /* Bring out of sleep mode (AGAIN) */ + if (!ar5416SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE)) + return AH_FALSE; + + ar5416InitPLL(ah, chan); + + /* + * 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. + */ + if (chan != AH_NULL) { + /* treat channel B as channel G , no B mode suport in owl */ + rfMode |= (IS_CHAN_G(chan) || IS_CHAN_B(chan)) ? + AR_PHY_MODE_DYNAMIC : AR_PHY_MODE_OFDM; + if (AR_SREV_MERLIN_20(ah) && IS_5GHZ_FAST_CLOCK_EN(ah, chan)) { + /* phy mode bits for 5GHz channels require Fast Clock */ + rfMode |= AR_PHY_MODE_DYNAMIC + | AR_PHY_MODE_DYN_CCK_DISABLE; + } else if (!AR_SREV_MERLIN_10_OR_LATER(ah)) { + rfMode |= (IS_CHAN_5GHZ(chan)) ? + AR_PHY_MODE_RF5GHZ : AR_PHY_MODE_RF2GHZ; + } + OS_REG_WRITE(ah, AR_PHY_MODE, rfMode); + } + return AH_TRUE; +} + +/* + * Delta slope coefficient computation. + * Required for OFDM operation. + */ +static void +ar5416GetDeltaSlopeValues(struct ath_hal *ah, uint32_t coef_scaled, + uint32_t *coef_mantissa, uint32_t *coef_exponent) +{ +#define COEF_SCALE_S 24 + uint32_t coef_exp, coef_man; + /* + * 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)); + + *coef_mantissa = coef_man >> (COEF_SCALE_S - coef_exp); + *coef_exponent = coef_exp - 16; + +#undef COEF_SCALE_S +} + +void +ar5416SetDeltaSlope(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan) +{ +#define INIT_CLOCKMHZSCALED 0x64000000 + uint32_t coef_scaled, ds_coef_exp, ds_coef_man; + uint32_t clockMhzScaled = INIT_CLOCKMHZSCALED; + + CHAN_CENTERS centers; + + 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 + */ + ar5416GetChannelCenters(ah, chan, ¢ers); + coef_scaled = clockMhzScaled / centers.synth_center; + + ar5416GetDeltaSlopeValues(ah, coef_scaled, &ds_coef_man, &ds_coef_exp); + + 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); + + /* + * For Short GI, + * scaled coeff is 9/10 that of normal coeff + */ + coef_scaled = (9 * coef_scaled)/10; + + ar5416GetDeltaSlopeValues(ah, coef_scaled, &ds_coef_man, &ds_coef_exp); + + /* for short gi */ + OS_REG_RMW_FIELD(ah, AR_PHY_HALFGI, + AR_PHY_HALFGI_DSC_MAN, ds_coef_man); + OS_REG_RMW_FIELD(ah, AR_PHY_HALFGI, + AR_PHY_HALFGI_DSC_EXP, ds_coef_exp); +#undef INIT_CLOCKMHZSCALED +} + +/* + * Convert to baseband spur frequency given input channel frequency + * and compute register settings below. + */ +#define SPUR_RSSI_THRESH 40 + +static void +ar5416SpurMitigate(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan) +{ + static const int pilot_mask_reg[4] = { AR_PHY_TIMING7, AR_PHY_TIMING8, + AR_PHY_PILOT_MASK_01_30, AR_PHY_PILOT_MASK_31_60 }; + static const int chan_mask_reg[4] = { AR_PHY_TIMING9, AR_PHY_TIMING10, + AR_PHY_CHANNEL_MASK_01_30, AR_PHY_CHANNEL_MASK_31_60 }; + static const int inc[4] = { 0, 100, 0, 0 }; + + int bb_spur = AR_NO_SPUR; + int bin, cur_bin; + int spur_freq_sd; + int spur_delta_phase; + int denominator; + int upper, lower, cur_vit_mask; + int tmp, new; + int i; + + int8_t mask_m[123]; + int8_t mask_p[123]; + int8_t mask_amt; + int tmp_mask; + int cur_bb_spur; + HAL_BOOL is2GHz = IS_CHAN_2GHZ(chan); + + OS_MEMZERO(mask_m, sizeof(mask_m)); + OS_MEMZERO(mask_p, sizeof(mask_p)); + + /* + * Need to verify range +/- 9.5 for static ht20, otherwise spur + * is out-of-band and can be ignored. + */ + for (i = 0; i < AR5416_EEPROM_MODAL_SPURS; i++) { + cur_bb_spur = ath_hal_getSpurChan(ah, i, is2GHz); + if (AR_NO_SPUR == cur_bb_spur) + break; + cur_bb_spur = cur_bb_spur - (chan->channel * 10); + if ((cur_bb_spur > -95) && (cur_bb_spur < 95)) { + bb_spur = cur_bb_spur; + break; + } + } + if (AR_NO_SPUR == bb_spur) + return; + + bin = bb_spur * 32; + + tmp = OS_REG_READ(ah, AR_PHY_TIMING_CTRL4_CHAIN(0)); + new = tmp | (AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI | + 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_CHAIN(0), new); + + new = (AR_PHY_SPUR_REG_MASK_RATE_CNTL | + AR_PHY_SPUR_REG_ENABLE_MASK_PPM | + AR_PHY_SPUR_REG_MASK_RATE_SELECT | + AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI | + SM(SPUR_RSSI_THRESH, AR_PHY_SPUR_REG_SPUR_RSSI_THRESH)); + OS_REG_WRITE(ah, AR_PHY_SPUR_REG, new); + /* + * Should offset bb_spur by +/- 10 MHz for dynamic 2040 MHz + * config, no offset for HT20. + * spur_delta_phase = bb_spur/40 * 2**21 for static ht20, + * /80 for dyn2040. + */ + spur_delta_phase = ((bb_spur * 524288) / 100) & + AR_PHY_TIMING11_SPUR_DELTA_PHASE; + /* + * in 11A mode the denominator of spur_freq_sd should be 40 and + * it should be 44 in 11G + */ + denominator = IS_CHAN_2GHZ(chan) ? 440 : 400; + spur_freq_sd = ((bb_spur * 2048) / denominator) & 0x3ff; + + new = (AR_PHY_TIMING11_USE_SPUR_IN_AGC | + SM(spur_freq_sd, AR_PHY_TIMING11_SPUR_FREQ_SD) | + SM(spur_delta_phase, AR_PHY_TIMING11_SPUR_DELTA_PHASE)); + OS_REG_WRITE(ah, AR_PHY_TIMING11, new); + + + /* + * ============================================ + * pilot mask 1 [31:0] = +6..-26, no 0 bin + * pilot mask 2 [19:0] = +26..+7 + * + * channel mask 1 [31:0] = +6..-26, no 0 bin + * channel mask 2 [19:0] = +26..+7 + */ + //cur_bin = -26; + cur_bin = -6000; + upper = bin + 100; + lower = bin - 100; + + for (i = 0; i < 4; i++) { + int pilot_mask = 0; + int chan_mask = 0; + int bp = 0; + for (bp = 0; bp < 30; bp++) { + if ((cur_bin > lower) && (cur_bin < upper)) { + pilot_mask = pilot_mask | 0x1 << bp; + chan_mask = chan_mask | 0x1 << bp; + } + cur_bin += 100; + } + cur_bin += inc[i]; + OS_REG_WRITE(ah, pilot_mask_reg[i], pilot_mask); + OS_REG_WRITE(ah, chan_mask_reg[i], chan_mask); + } + + /* ================================================= + * viterbi mask 1 based on channel magnitude + * four levels 0-3 + * - mask (-27 to 27) (reg 64,0x9900 to 67,0x990c) + * [1 2 2 1] for -9.6 or [1 2 1] for +16 + * - enable_mask_ppm, all bins move with freq + * + * - mask_select, 8 bits for rates (reg 67,0x990c) + * - mask_rate_cntl, 8 bits for rates (reg 67,0x990c) + * choose which mask to use mask or mask2 + */ + + /* + * viterbi mask 2 2nd set for per data rate puncturing + * four levels 0-3 + * - mask_select, 8 bits for rates (reg 67) + * - mask (-27 to 27) (reg 98,0x9988 to 101,0x9994) + * [1 2 2 1] for -9.6 or [1 2 1] for +16 + */ + cur_vit_mask = 6100; + upper = bin + 120; + lower = bin - 120; + + for (i = 0; i < 123; i++) { + if ((cur_vit_mask > lower) && (cur_vit_mask < upper)) { + if ((abs(cur_vit_mask - bin)) < 75) { + mask_amt = 1; + } else { + mask_amt = 0; + } + if (cur_vit_mask < 0) { + mask_m[abs(cur_vit_mask / 100)] = mask_amt; + } else { + mask_p[cur_vit_mask / 100] = mask_amt; + } + } + cur_vit_mask -= 100; + } + + tmp_mask = (mask_m[46] << 30) | (mask_m[47] << 28) + | (mask_m[48] << 26) | (mask_m[49] << 24) + | (mask_m[50] << 22) | (mask_m[51] << 20) + | (mask_m[52] << 18) | (mask_m[53] << 16) + | (mask_m[54] << 14) | (mask_m[55] << 12) + | (mask_m[56] << 10) | (mask_m[57] << 8) + | (mask_m[58] << 6) | (mask_m[59] << 4) + | (mask_m[60] << 2) | (mask_m[61] << 0); + OS_REG_WRITE(ah, AR_PHY_BIN_MASK_1, tmp_mask); + OS_REG_WRITE(ah, AR_PHY_VIT_MASK2_M_46_61, tmp_mask); + + tmp_mask = (mask_m[31] << 28) + | (mask_m[32] << 26) | (mask_m[33] << 24) + | (mask_m[34] << 22) | (mask_m[35] << 20) + | (mask_m[36] << 18) | (mask_m[37] << 16) + | (mask_m[48] << 14) | (mask_m[39] << 12) + | (mask_m[40] << 10) | (mask_m[41] << 8) + | (mask_m[42] << 6) | (mask_m[43] << 4) + | (mask_m[44] << 2) | (mask_m[45] << 0); + OS_REG_WRITE(ah, AR_PHY_BIN_MASK_2, tmp_mask); + OS_REG_WRITE(ah, AR_PHY_MASK2_M_31_45, tmp_mask); + + tmp_mask = (mask_m[16] << 30) | (mask_m[16] << 28) + | (mask_m[18] << 26) | (mask_m[18] << 24) + | (mask_m[20] << 22) | (mask_m[20] << 20) + | (mask_m[22] << 18) | (mask_m[22] << 16) + | (mask_m[24] << 14) | (mask_m[24] << 12) + | (mask_m[25] << 10) | (mask_m[26] << 8) + | (mask_m[27] << 6) | (mask_m[28] << 4) + | (mask_m[29] << 2) | (mask_m[30] << 0); + OS_REG_WRITE(ah, AR_PHY_BIN_MASK_3, tmp_mask); + OS_REG_WRITE(ah, AR_PHY_MASK2_M_16_30, tmp_mask); + + tmp_mask = (mask_m[ 0] << 30) | (mask_m[ 1] << 28) + | (mask_m[ 2] << 26) | (mask_m[ 3] << 24) + | (mask_m[ 4] << 22) | (mask_m[ 5] << 20) + | (mask_m[ 6] << 18) | (mask_m[ 7] << 16) + | (mask_m[ 8] << 14) | (mask_m[ 9] << 12) + | (mask_m[10] << 10) | (mask_m[11] << 8) + | (mask_m[12] << 6) | (mask_m[13] << 4) + | (mask_m[14] << 2) | (mask_m[15] << 0); + OS_REG_WRITE(ah, AR_PHY_MASK_CTL, tmp_mask); + OS_REG_WRITE(ah, AR_PHY_MASK2_M_00_15, tmp_mask); + + tmp_mask = (mask_p[15] << 28) + | (mask_p[14] << 26) | (mask_p[13] << 24) + | (mask_p[12] << 22) | (mask_p[11] << 20) + | (mask_p[10] << 18) | (mask_p[ 9] << 16) + | (mask_p[ 8] << 14) | (mask_p[ 7] << 12) + | (mask_p[ 6] << 10) | (mask_p[ 5] << 8) + | (mask_p[ 4] << 6) | (mask_p[ 3] << 4) + | (mask_p[ 2] << 2) | (mask_p[ 1] << 0); + OS_REG_WRITE(ah, AR_PHY_BIN_MASK2_1, tmp_mask); + OS_REG_WRITE(ah, AR_PHY_MASK2_P_15_01, tmp_mask); + + tmp_mask = (mask_p[30] << 28) + | (mask_p[29] << 26) | (mask_p[28] << 24) + | (mask_p[27] << 22) | (mask_p[26] << 20) + | (mask_p[25] << 18) | (mask_p[24] << 16) + | (mask_p[23] << 14) | (mask_p[22] << 12) + | (mask_p[21] << 10) | (mask_p[20] << 8) + | (mask_p[19] << 6) | (mask_p[18] << 4) + | (mask_p[17] << 2) | (mask_p[16] << 0); + OS_REG_WRITE(ah, AR_PHY_BIN_MASK2_2, tmp_mask); + OS_REG_WRITE(ah, AR_PHY_MASK2_P_30_16, tmp_mask); + + tmp_mask = (mask_p[45] << 28) + | (mask_p[44] << 26) | (mask_p[43] << 24) + | (mask_p[42] << 22) | (mask_p[41] << 20) + | (mask_p[40] << 18) | (mask_p[39] << 16) + | (mask_p[38] << 14) | (mask_p[37] << 12) + | (mask_p[36] << 10) | (mask_p[35] << 8) + | (mask_p[34] << 6) | (mask_p[33] << 4) + | (mask_p[32] << 2) | (mask_p[31] << 0); + OS_REG_WRITE(ah, AR_PHY_BIN_MASK2_3, tmp_mask); + OS_REG_WRITE(ah, AR_PHY_MASK2_P_45_31, tmp_mask); + + tmp_mask = (mask_p[61] << 30) | (mask_p[60] << 28) + | (mask_p[59] << 26) | (mask_p[58] << 24) + | (mask_p[57] << 22) | (mask_p[56] << 20) + | (mask_p[55] << 18) | (mask_p[54] << 16) + | (mask_p[53] << 14) | (mask_p[52] << 12) + | (mask_p[51] << 10) | (mask_p[50] << 8) + | (mask_p[49] << 6) | (mask_p[48] << 4) + | (mask_p[47] << 2) | (mask_p[46] << 0); + OS_REG_WRITE(ah, AR_PHY_BIN_MASK2_4, tmp_mask); + OS_REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask); +} + +#ifdef AH_SUPPORT_AR9280 +#define AR_BASE_FREQ_2GHZ 2300 +#define AR_BASE_FREQ_5GHZ 4900 +#define AR_SPUR_FEEQ_BOUND_HT40 19 +#define AR_SPUR_FEEQ_BOUND_HT20 10 + +static void +ar9280SpurMitigate(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan) +{ + static const int pilot_mask_reg[4] = { AR_PHY_TIMING7, AR_PHY_TIMING8, + AR_PHY_PILOT_MASK_01_30, AR_PHY_PILOT_MASK_31_60 }; + static const int chan_mask_reg[4] = { AR_PHY_TIMING9, AR_PHY_TIMING10, + AR_PHY_CHANNEL_MASK_01_30, AR_PHY_CHANNEL_MASK_31_60 }; + static int inc[4] = { 0, 100, 0, 0 }; + + int bb_spur = AR_NO_SPUR; + int freq; + int bin, cur_bin; + int bb_spur_off, spur_subchannel_sd; + int spur_freq_sd; + int spur_delta_phase; + int denominator; + int upper, lower, cur_vit_mask; + int tmp, newVal; + int i; + CHAN_CENTERS centers; + + int8_t mask_m[123]; + int8_t mask_p[123]; + int8_t mask_amt; + int tmp_mask; + int cur_bb_spur; + HAL_BOOL is2GHz = IS_CHAN_2GHZ(ichan); + + OS_MEMZERO(&mask_m, sizeof(int8_t) * 123); + OS_MEMZERO(&mask_p, sizeof(int8_t) * 123); + + ar5416GetChannelCenters(ah, ichan, ¢ers); + freq = centers.synth_center; + + /* + * Need to verify range +/- 9.38 for static ht20 and +/- 18.75 for ht40, + * otherwise spur is out-of-band and can be ignored. + */ + for (i = 0; i < AR5416_EEPROM_MODAL_SPURS; i++) { + cur_bb_spur = ath_hal_getSpurChan(ah, i, is2GHz); + /* Get actual spur freq in MHz from EEPROM read value */ + if (is2GHz) { + cur_bb_spur = (cur_bb_spur / 10) + AR_BASE_FREQ_2GHZ; + } else { + cur_bb_spur = (cur_bb_spur / 10) + AR_BASE_FREQ_5GHZ; + } + + if (AR_NO_SPUR == cur_bb_spur) + break; + cur_bb_spur = cur_bb_spur - freq; + + if (IS_CHAN_HT40(ichan)) { + if ((cur_bb_spur > -AR_SPUR_FEEQ_BOUND_HT40) && + (cur_bb_spur < AR_SPUR_FEEQ_BOUND_HT40)) { + bb_spur = cur_bb_spur; + break; + } + } else if ((cur_bb_spur > -AR_SPUR_FEEQ_BOUND_HT20) && + (cur_bb_spur < AR_SPUR_FEEQ_BOUND_HT20)) { + bb_spur = cur_bb_spur; + break; + } + } + + if (AR_NO_SPUR == bb_spur) { +#if 1 + /* + * MRC CCK can interfere with beacon detection and cause deaf/mute. + * Disable MRC CCK for now. + */ + OS_REG_CLR_BIT(ah, AR_PHY_FORCE_CLKEN_CCK, AR_PHY_FORCE_CLKEN_CCK_MRC_MUX); +#else + /* Enable MRC CCK if no spur is found in this channel. */ + OS_REG_SET_BIT(ah, AR_PHY_FORCE_CLKEN_CCK, AR_PHY_FORCE_CLKEN_CCK_MRC_MUX); +#endif + return; + } else { + /* + * For Merlin, spur can break CCK MRC algorithm. Disable CCK MRC if spur + * is found in this channel. + */ + OS_REG_CLR_BIT(ah, AR_PHY_FORCE_CLKEN_CCK, AR_PHY_FORCE_CLKEN_CCK_MRC_MUX); + } + + bin = bb_spur * 320; + + tmp = OS_REG_READ(ah, AR_PHY_TIMING_CTRL4_CHAIN(0)); + + newVal = tmp | (AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI | + 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_CHAIN(0), newVal); + + newVal = (AR_PHY_SPUR_REG_MASK_RATE_CNTL | + AR_PHY_SPUR_REG_ENABLE_MASK_PPM | + AR_PHY_SPUR_REG_MASK_RATE_SELECT | + AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI | + SM(SPUR_RSSI_THRESH, AR_PHY_SPUR_REG_SPUR_RSSI_THRESH)); + OS_REG_WRITE(ah, AR_PHY_SPUR_REG, newVal); + + /* Pick control or extn channel to cancel the spur */ + if (IS_CHAN_HT40(ichan)) { + if (bb_spur < 0) { + spur_subchannel_sd = 1; + bb_spur_off = bb_spur + 10; + } else { + spur_subchannel_sd = 0; + bb_spur_off = bb_spur - 10; + } + } else { + spur_subchannel_sd = 0; + bb_spur_off = bb_spur; + } + + /* + * spur_delta_phase = bb_spur/40 * 2**21 for static ht20, + * /80 for dyn2040. + */ + if (IS_CHAN_HT40(ichan)) + spur_delta_phase = ((bb_spur * 262144) / 10) & AR_PHY_TIMING11_SPUR_DELTA_PHASE; + else + spur_delta_phase = ((bb_spur * 524288) / 10) & AR_PHY_TIMING11_SPUR_DELTA_PHASE; + + /* + * in 11A mode the denominator of spur_freq_sd should be 40 and + * it should be 44 in 11G + */ + denominator = IS_CHAN_2GHZ(ichan) ? 44 : 40; + spur_freq_sd = ((bb_spur_off * 2048) / denominator) & 0x3ff; + + newVal = (AR_PHY_TIMING11_USE_SPUR_IN_AGC | + SM(spur_freq_sd, AR_PHY_TIMING11_SPUR_FREQ_SD) | + SM(spur_delta_phase, AR_PHY_TIMING11_SPUR_DELTA_PHASE)); + OS_REG_WRITE(ah, AR_PHY_TIMING11, newVal); + + /* Choose to cancel between control and extension channels */ + newVal = spur_subchannel_sd << AR_PHY_SFCORR_SPUR_SUBCHNL_SD_S; + OS_REG_WRITE(ah, AR_PHY_SFCORR_EXT, newVal); + + /* + * ============================================ + * Set Pilot and Channel Masks + * + * pilot mask 1 [31:0] = +6..-26, no 0 bin + * pilot mask 2 [19:0] = +26..+7 + * + * channel mask 1 [31:0] = +6..-26, no 0 bin + * channel mask 2 [19:0] = +26..+7 + */ + cur_bin = -6000; + upper = bin + 100; + lower = bin - 100; + + for (i = 0; i < 4; i++) { + int pilot_mask = 0; + int chan_mask = 0; + int bp = 0; + for (bp = 0; bp < 30; bp++) { + if ((cur_bin > lower) && (cur_bin < upper)) { + pilot_mask = pilot_mask | 0x1 << bp; + chan_mask = chan_mask | 0x1 << bp; + } + cur_bin += 100; + } + cur_bin += inc[i]; + OS_REG_WRITE(ah, pilot_mask_reg[i], pilot_mask); + OS_REG_WRITE(ah, chan_mask_reg[i], chan_mask); + } + + /* ================================================= + * viterbi mask 1 based on channel magnitude + * four levels 0-3 + * - mask (-27 to 27) (reg 64,0x9900 to 67,0x990c) + * [1 2 2 1] for -9.6 or [1 2 1] for +16 + * - enable_mask_ppm, all bins move with freq + * + * - mask_select, 8 bits for rates (reg 67,0x990c) + * - mask_rate_cntl, 8 bits for rates (reg 67,0x990c) + * choose which mask to use mask or mask2 + */ + + /* + * viterbi mask 2 2nd set for per data rate puncturing + * four levels 0-3 + * - mask_select, 8 bits for rates (reg 67) + * - mask (-27 to 27) (reg 98,0x9988 to 101,0x9994) + * [1 2 2 1] for -9.6 or [1 2 1] for +16 + */ + cur_vit_mask = 6100; + upper = bin + 120; + lower = bin - 120; + + for (i = 0; i < 123; i++) { + if ((cur_vit_mask > lower) && (cur_vit_mask < upper)) { + if ((abs(cur_vit_mask - bin)) < 75) { + mask_amt = 1; + } else { + mask_amt = 0; + } + if (cur_vit_mask < 0) { + mask_m[abs(cur_vit_mask / 100)] = mask_amt; + } else { + mask_p[cur_vit_mask / 100] = mask_amt; + } + } + cur_vit_mask -= 100; + } + + tmp_mask = (mask_m[46] << 30) | (mask_m[47] << 28) + | (mask_m[48] << 26) | (mask_m[49] << 24) + | (mask_m[50] << 22) | (mask_m[51] << 20) + | (mask_m[52] << 18) | (mask_m[53] << 16) + | (mask_m[54] << 14) | (mask_m[55] << 12) + | (mask_m[56] << 10) | (mask_m[57] << 8) + | (mask_m[58] << 6) | (mask_m[59] << 4) + | (mask_m[60] << 2) | (mask_m[61] << 0); + OS_REG_WRITE(ah, AR_PHY_BIN_MASK_1, tmp_mask); + OS_REG_WRITE(ah, AR_PHY_VIT_MASK2_M_46_61, tmp_mask); + + tmp_mask = (mask_m[31] << 28) + | (mask_m[32] << 26) | (mask_m[33] << 24) + | (mask_m[34] << 22) | (mask_m[35] << 20) + | (mask_m[36] << 18) | (mask_m[37] << 16) + | (mask_m[48] << 14) | (mask_m[39] << 12) + | (mask_m[40] << 10) | (mask_m[41] << 8) + | (mask_m[42] << 6) | (mask_m[43] << 4) + | (mask_m[44] << 2) | (mask_m[45] << 0); + OS_REG_WRITE(ah, AR_PHY_BIN_MASK_2, tmp_mask); + OS_REG_WRITE(ah, AR_PHY_MASK2_M_31_45, tmp_mask); + + tmp_mask = (mask_m[16] << 30) | (mask_m[16] << 28) + | (mask_m[18] << 26) | (mask_m[18] << 24) + | (mask_m[20] << 22) | (mask_m[20] << 20) + | (mask_m[22] << 18) | (mask_m[22] << 16) + | (mask_m[24] << 14) | (mask_m[24] << 12) + | (mask_m[25] << 10) | (mask_m[26] << 8) + | (mask_m[27] << 6) | (mask_m[28] << 4) + | (mask_m[29] << 2) | (mask_m[30] << 0); + OS_REG_WRITE(ah, AR_PHY_BIN_MASK_3, tmp_mask); + OS_REG_WRITE(ah, AR_PHY_MASK2_M_16_30, tmp_mask); + + tmp_mask = (mask_m[ 0] << 30) | (mask_m[ 1] << 28) + | (mask_m[ 2] << 26) | (mask_m[ 3] << 24) + | (mask_m[ 4] << 22) | (mask_m[ 5] << 20) + | (mask_m[ 6] << 18) | (mask_m[ 7] << 16) + | (mask_m[ 8] << 14) | (mask_m[ 9] << 12) + | (mask_m[10] << 10) | (mask_m[11] << 8) + | (mask_m[12] << 6) | (mask_m[13] << 4) + | (mask_m[14] << 2) | (mask_m[15] << 0); + OS_REG_WRITE(ah, AR_PHY_MASK_CTL, tmp_mask); + OS_REG_WRITE(ah, AR_PHY_MASK2_M_00_15, tmp_mask); + + tmp_mask = (mask_p[15] << 28) + | (mask_p[14] << 26) | (mask_p[13] << 24) + | (mask_p[12] << 22) | (mask_p[11] << 20) + | (mask_p[10] << 18) | (mask_p[ 9] << 16) + | (mask_p[ 8] << 14) | (mask_p[ 7] << 12) + | (mask_p[ 6] << 10) | (mask_p[ 5] << 8) + | (mask_p[ 4] << 6) | (mask_p[ 3] << 4) + | (mask_p[ 2] << 2) | (mask_p[ 1] << 0); + OS_REG_WRITE(ah, AR_PHY_BIN_MASK2_1, tmp_mask); + OS_REG_WRITE(ah, AR_PHY_MASK2_P_15_01, tmp_mask); + + tmp_mask = (mask_p[30] << 28) + | (mask_p[29] << 26) | (mask_p[28] << 24) + | (mask_p[27] << 22) | (mask_p[26] << 20) + | (mask_p[25] << 18) | (mask_p[24] << 16) + | (mask_p[23] << 14) | (mask_p[22] << 12) + | (mask_p[21] << 10) | (mask_p[20] << 8) + | (mask_p[19] << 6) | (mask_p[18] << 4) + | (mask_p[17] << 2) | (mask_p[16] << 0); + OS_REG_WRITE(ah, AR_PHY_BIN_MASK2_2, tmp_mask); + OS_REG_WRITE(ah, AR_PHY_MASK2_P_30_16, tmp_mask); + + tmp_mask = (mask_p[45] << 28) + | (mask_p[44] << 26) | (mask_p[43] << 24) + | (mask_p[42] << 22) | (mask_p[41] << 20) + | (mask_p[40] << 18) | (mask_p[39] << 16) + | (mask_p[38] << 14) | (mask_p[37] << 12) + | (mask_p[36] << 10) | (mask_p[35] << 8) + | (mask_p[34] << 6) | (mask_p[33] << 4) + | (mask_p[32] << 2) | (mask_p[31] << 0); + OS_REG_WRITE(ah, AR_PHY_BIN_MASK2_3, tmp_mask); + OS_REG_WRITE(ah, AR_PHY_MASK2_P_45_31, tmp_mask); + + tmp_mask = (mask_p[61] << 30) | (mask_p[60] << 28) + | (mask_p[59] << 26) | (mask_p[58] << 24) + | (mask_p[57] << 22) | (mask_p[56] << 20) + | (mask_p[55] << 18) | (mask_p[54] << 16) + | (mask_p[53] << 14) | (mask_p[52] << 12) + | (mask_p[51] << 10) | (mask_p[50] << 8) + | (mask_p[49] << 6) | (mask_p[48] << 4) + | (mask_p[47] << 2) | (mask_p[46] << 0); + OS_REG_WRITE(ah, AR_PHY_BIN_MASK2_4, tmp_mask); + OS_REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask); +} +#endif /* AH_SUPPORT_AR9280 */ + +/* + * 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 +ar5416SetTxPowerLimit(struct ath_hal *ah, uint32_t limit) +{ + uint16_t dummyXpdGains[2]; + + AH_PRIVATE(ah)->ah_powerLimit = AH_MIN(limit, MAX_RATE_POWER); + return ar5416SetTransmitPower(ah, AH_PRIVATE(ah)->ah_curchan, + dummyXpdGains); +} + +HAL_BOOL +ar5416GetChipPowerLimits(struct ath_hal *ah, HAL_CHANNEL *chans, uint32_t nchans) +{ + struct ath_hal_5212 *ahp = AH5212(ah); + int16_t minPower, maxPower; + 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 = AR5416_MAX_RATE_POWER; + chan->minTxPower = 0; + } + } +#ifdef AH_DEBUG + for (i=0; iah_eeprom; + struct ar5416eeprom *pEepData = &ee->ee_base; + + HALASSERT(AH_PRIVATE(ah)->ah_eeversion >= AR_EEPROM_VER14_1); + + /* Setup info for the actual eeprom */ + ath_hal_memzero(ratesArray, sizeof(ratesArray)); + cfgCtl = ath_hal_getctl(ah, (HAL_CHANNEL *)chan); + powerLimit = chan->maxRegTxPower * 2; + twiceAntennaReduction = chan->antennaMax; + twiceMaxRegulatoryPower = AH_MIN(MAX_RATE_POWER, AH_PRIVATE(ah)->ah_powerLimit); + pModal = &pEepData->modalHeader[IS_CHAN_2GHZ(chan)]; + HALDEBUG(ah, HAL_DEBUG_RESET, "%s Channel=%u CfgCtl=%u\n", + __func__,chan->channel, cfgCtl ); + + if (IS_EEP_MINOR_V2(ah)) { + ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc; + } + + if (!ar5416SetPowerPerRateTable(ah, pEepData, chan, + &ratesArray[0],cfgCtl, + twiceAntennaReduction, + twiceMaxRegulatoryPower, powerLimit)) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: unable to set tx power per rate table\n", __func__); + return AH_FALSE; + } + + if (!ar5416SetPowerCalTable(ah, pEepData, chan, &txPowerIndexOffset)) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unable to set power table\n", + __func__); + return AH_FALSE; + } + + maxPower = AH_MAX(ratesArray[rate6mb], ratesArray[rateHt20_0]); + + if (IS_CHAN_2GHZ(chan)) { + maxPower = AH_MAX(maxPower, ratesArray[rate1l]); + } + + if (IS_CHAN_HT40(chan)) { + maxPower = AH_MAX(maxPower, ratesArray[rateHt40_0]); + } + + ahp->ah_tx6PowerInHalfDbm = maxPower; + AH_PRIVATE(ah)->ah_maxPowerLevel = maxPower; + ahp->ah_txPowerIndexOffset = txPowerIndexOffset; + + /* + * txPowerIndexOffset is set by the SetPowerTable() call - + * adjust the rate table (0 offset if rates EEPROM not loaded) + */ + for (i = 0; i < N(ratesArray); i++) { + ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]); + if (ratesArray[i] > AR5416_MAX_RATE_POWER) + ratesArray[i] = AR5416_MAX_RATE_POWER; + } + +#ifdef AH_EEPROM_DUMP + ar5416PrintPowerPerRate(ah, ratesArray); +#endif + + /* Write the OFDM power per rate set */ + OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, + POW_SM(ratesArray[rate18mb], 24) + | POW_SM(ratesArray[rate12mb], 16) + | POW_SM(ratesArray[rate9mb], 8) + | POW_SM(ratesArray[rate6mb], 0) + ); + OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE2, + POW_SM(ratesArray[rate54mb], 24) + | POW_SM(ratesArray[rate48mb], 16) + | POW_SM(ratesArray[rate36mb], 8) + | POW_SM(ratesArray[rate24mb], 0) + ); + + if (IS_CHAN_2GHZ(chan)) { + /* Write the CCK power per rate set */ + OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, + POW_SM(ratesArray[rate2s], 24) + | POW_SM(ratesArray[rate2l], 16) + | POW_SM(ratesArray[rateXr], 8) /* XR target power */ + | POW_SM(ratesArray[rate1l], 0) + ); + OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, + POW_SM(ratesArray[rate11s], 24) + | POW_SM(ratesArray[rate11l], 16) + | POW_SM(ratesArray[rate5_5s], 8) + | POW_SM(ratesArray[rate5_5l], 0) + ); + HALDEBUG(ah, HAL_DEBUG_RESET, + "%s AR_PHY_POWER_TX_RATE3=0x%x AR_PHY_POWER_TX_RATE4=0x%x\n", + __func__, OS_REG_READ(ah,AR_PHY_POWER_TX_RATE3), + OS_REG_READ(ah,AR_PHY_POWER_TX_RATE4)); + } + + /* Write the HT20 power per rate set */ + OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE5, + POW_SM(ratesArray[rateHt20_3], 24) + | POW_SM(ratesArray[rateHt20_2], 16) + | POW_SM(ratesArray[rateHt20_1], 8) + | POW_SM(ratesArray[rateHt20_0], 0) + ); + OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE6, + POW_SM(ratesArray[rateHt20_7], 24) + | POW_SM(ratesArray[rateHt20_6], 16) + | POW_SM(ratesArray[rateHt20_5], 8) + | POW_SM(ratesArray[rateHt20_4], 0) + ); + + if (IS_CHAN_HT40(chan)) { + /* Write the HT40 power per rate set */ + /* Correct PAR difference between HT40 and HT20/LEGACY */ + OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE7, + POW_SM(ratesArray[rateHt40_3] + ht40PowerIncForPdadc, 24) + | POW_SM(ratesArray[rateHt40_2] + ht40PowerIncForPdadc, 16) + | POW_SM(ratesArray[rateHt40_1] + ht40PowerIncForPdadc, 8) + | POW_SM(ratesArray[rateHt40_0] + ht40PowerIncForPdadc, 0) + ); + OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE8, + POW_SM(ratesArray[rateHt40_7] + ht40PowerIncForPdadc, 24) + | POW_SM(ratesArray[rateHt40_6] + ht40PowerIncForPdadc, 16) + | POW_SM(ratesArray[rateHt40_5] + ht40PowerIncForPdadc, 8) + | POW_SM(ratesArray[rateHt40_4] + ht40PowerIncForPdadc, 0) + ); + /* Write the Dup/Ext 40 power per rate set */ + OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, + POW_SM(ratesArray[rateExtOfdm], 24) + | POW_SM(ratesArray[rateExtCck], 16) + | POW_SM(ratesArray[rateDupOfdm], 8) + | POW_SM(ratesArray[rateDupCck], 0) + ); + } + + /* Write the Power subtraction for dynamic chain changing, for per-packet powertx */ + OS_REG_WRITE(ah, AR_PHY_POWER_TX_SUB, + POW_SM(pModal->pwrDecreaseFor3Chain, 6) + | POW_SM(pModal->pwrDecreaseFor2Chain, 0) + ); + return AH_TRUE; +#undef POW_SM +#undef N +} + +/* + * Exported call to check for a recent gain reading and return + * the current state of the thermal calibration gain engine. + */ +HAL_RFGAIN +ar5416GetRfgain(struct ath_hal *ah) +{ + return HAL_RFGAIN_INACTIVE; +} + +/* + * Places all of hardware into reset + */ +HAL_BOOL +ar5416Disable(struct ath_hal *ah) +{ + if (!ar5212SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE)) + return AH_FALSE; + return ar5416SetResetReg(ah, HAL_RESET_COLD); +} + +/* + * 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 +ar5416PhyDisable(struct ath_hal *ah) +{ + return ar5416SetResetReg(ah, HAL_RESET_WARM); +} + +/* + * Write the given reset bit mask into the reset register + */ +HAL_BOOL +ar5416SetResetReg(struct ath_hal *ah, uint32_t type) +{ + /* + * Set force wake + */ + OS_REG_WRITE(ah, AR_RTC_FORCE_WAKE, + AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT); + + switch (type) { + case HAL_RESET_POWER_ON: + return ar5416SetResetPowerOn(ah); + break; + case HAL_RESET_WARM: + case HAL_RESET_COLD: + return ar5416SetReset(ah, type); + break; + default: + return AH_FALSE; + } +} + +static HAL_BOOL +ar5416SetResetPowerOn(struct ath_hal *ah) +{ + /* Power On Reset (Hard Reset) */ + + /* + * Set force wake + * + * If the MAC was running, previously calling + * reset will wake up the MAC but it may go back to sleep + * before we can start polling. + * Set force wake stops that + * This must be called before initiating a hard reset. + */ + OS_REG_WRITE(ah, AR_RTC_FORCE_WAKE, + AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT); + + /* + * RTC reset and clear + */ + OS_REG_WRITE(ah, AR_RTC_RESET, 0); + OS_DELAY(20); + OS_REG_WRITE(ah, AR_RTC_RESET, 1); + + /* + * Poll till RTC is ON + */ + if (!ath_hal_wait(ah, AR_RTC_STATUS, AR_RTC_PM_STATUS_M, AR_RTC_STATUS_ON)) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: RTC not waking up\n", __func__); + return AH_FALSE; + } + + return ar5416SetReset(ah, HAL_RESET_COLD); +} + +static HAL_BOOL +ar5416SetReset(struct ath_hal *ah, int type) +{ + uint32_t tmpReg; + + /* + * Force wake + */ + OS_REG_WRITE(ah, AR_RTC_FORCE_WAKE, + AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT); + + /* + * Reset AHB + */ + tmpReg = OS_REG_READ(ah, AR_INTR_SYNC_CAUSE); + if (tmpReg & (AR_INTR_SYNC_LOCAL_TIMEOUT|AR_INTR_SYNC_RADM_CPL_TIMEOUT)) { + OS_REG_WRITE(ah, AR_INTR_SYNC_ENABLE, 0); + OS_REG_WRITE(ah, AR_RC, AR_RC_AHB|AR_RC_HOSTIF); + } else { + OS_REG_WRITE(ah, AR_RC, AR_RC_AHB); + } + + /* + * Set Mac(BB,Phy) Warm Reset + */ + switch (type) { + case HAL_RESET_WARM: + OS_REG_WRITE(ah, AR_RTC_RC, AR_RTC_RC_MAC_WARM); + break; + case HAL_RESET_COLD: + OS_REG_WRITE(ah, AR_RTC_RC, AR_RTC_RC_MAC_WARM|AR_RTC_RC_MAC_COLD); + break; + default: + HALASSERT(0); + break; + } + + /* + * Clear resets and force wakeup + */ + OS_REG_WRITE(ah, AR_RTC_RC, 0); + if (!ath_hal_wait(ah, AR_RTC_RC, AR_RTC_RC_M, 0)) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: RTC stuck in MAC reset\n", __func__); + return AH_FALSE; + } + + /* Clear AHB reset */ + OS_REG_WRITE(ah, AR_RC, 0); + + /* Set register and descriptor swapping on + * Bigendian platforms on cold reset + */ +#ifdef __BIG_ENDIAN__ + if (type == HAL_RESET_COLD) { + uint32_t mask; + + HALDEBUG(ah, HAL_DEBUG_RESET, + "%s Applying descriptor swap\n", __func__); + + 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)); + } +#endif + + ar5416InitPLL(ah, AH_NULL); + + return AH_TRUE; +} + +#ifndef IS_5GHZ_FAST_CLOCK_EN +#define IS_5GHZ_FAST_CLOCK_EN(ah, chan) AH_FALSE +#endif + +static void +ar5416InitPLL(struct ath_hal *ah, HAL_CHANNEL *chan) +{ + uint32_t pll; + + if (AR_SREV_MERLIN_10_OR_LATER(ah)) { + pll = SM(0x5, AR_RTC_SOWL_PLL_REFDIV); + + if (chan != AH_NULL && IS_CHAN_HALF_RATE(chan)) { + pll |= SM(0x1, AR_RTC_SOWL_PLL_CLKSEL); + } else if (chan && IS_CHAN_QUARTER_RATE(chan)) { + pll |= SM(0x2, AR_RTC_SOWL_PLL_CLKSEL); + } + if (chan != AH_NULL && IS_CHAN_5GHZ(chan)) { + pll |= SM(0x28, AR_RTC_SOWL_PLL_DIV); + + /* + * PLL WAR for Merlin 2.0/2.1 + * When doing fast clock, set PLL to 0x142c + * Else, set PLL to 0x2850 to prevent reset-to-reset variation + */ + if (AR_SREV_MERLIN_20(ah)) { + if (IS_5GHZ_FAST_CLOCK_EN(ah, chan)) { + pll = 0x142c; + } else { + pll = 0x2850; + } + } + } else { + pll |= SM(0x2c, AR_RTC_SOWL_PLL_DIV); + } + } else if (AR_SREV_SOWL_10_OR_LATER(ah)) { + pll = SM(0x5, AR_RTC_SOWL_PLL_REFDIV); + + if (chan != AH_NULL && IS_CHAN_HALF_RATE(chan)) { + pll |= SM(0x1, AR_RTC_SOWL_PLL_CLKSEL); + } else if (chan && IS_CHAN_QUARTER_RATE(chan)) { + pll |= SM(0x2, AR_RTC_SOWL_PLL_CLKSEL); + } + if (chan != AH_NULL && IS_CHAN_5GHZ(chan)) { + pll |= SM(0x50, AR_RTC_SOWL_PLL_DIV); + } else { + pll |= SM(0x58, AR_RTC_SOWL_PLL_DIV); + } + } else { + pll = AR_RTC_PLL_REFDIV_5 | AR_RTC_PLL_DIV2; + + if (chan != AH_NULL && IS_CHAN_HALF_RATE(chan)) { + pll |= SM(0x1, AR_RTC_PLL_CLKSEL); + } else if (chan != AH_NULL && IS_CHAN_QUARTER_RATE(chan)) { + pll |= SM(0x2, AR_RTC_PLL_CLKSEL); + } + if (chan != AH_NULL && IS_CHAN_5GHZ(chan)) { + pll |= SM(0xa, AR_RTC_PLL_DIV); + } else { + pll |= SM(0xb, AR_RTC_PLL_DIV); + } + } + OS_REG_WRITE(ah, AR_RTC_PLL_CONTROL, pll); + + /* TODO: + * For multi-band owl, switch between bands by reiniting the PLL. + */ + + OS_DELAY(RTC_PLL_SETTLE_DELAY); + + OS_REG_WRITE(ah, AR_RTC_SLEEP_CLK, AR_RTC_SLEEP_DERIVED_CLK); +} + +/* + * Read EEPROM header info and program the device for correct operation + * given the channel value. + */ +static HAL_BOOL +ar5416SetBoardValues(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan) +{ + const HAL_EEPROM_v14 *ee = AH_PRIVATE(ah)->ah_eeprom; + const struct ar5416eeprom *eep = &ee->ee_base; + const MODAL_EEP_HEADER *pModal; + int i, regChainOffset; + uint8_t txRxAttenLocal; /* workaround for eeprom versions <= 14.2 */ + + HALASSERT(AH_PRIVATE(ah)->ah_eeversion >= AR_EEPROM_VER14_1); + pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]); + + txRxAttenLocal = IS_CHAN_2GHZ(chan) ? 23 : 44; /* workaround for eeprom versions <= 14.2 */ + + OS_REG_WRITE(ah, AR_PHY_SWITCH_COM, pModal->antCtrlCommon); + for (i = 0; i < AR5416_MAX_CHAINS; i++) { + if (AR_SREV_MERLIN(ah)) { + if (i >= 2) break; + } + if (AR_SREV_OWL_20_OR_LATER(ah) && + (AH5416(ah)->ah_rx_chainmask == 0x5 || + AH5416(ah)->ah_tx_chainmask == 0x5) && i != 0) { + /* Regs are swapped from chain 2 to 1 for 5416 2_0 with + * only chains 0 and 2 populated + */ + regChainOffset = (i == 1) ? 0x2000 : 0x1000; + } else { + regChainOffset = i * 0x1000; + } + + OS_REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset, pModal->antCtrlChain[i]); + OS_REG_WRITE(ah, AR_PHY_TIMING_CTRL4 + regChainOffset, + (OS_REG_READ(ah, AR_PHY_TIMING_CTRL4 + regChainOffset) & + ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) | + SM(pModal->iqCalICh[i], AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) | + SM(pModal->iqCalQCh[i], AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF)); + + /* + * Large signal upgrade. + * XXX update + */ + + if ((i == 0) || AR_SREV_OWL_20_OR_LATER(ah)) { + OS_REG_WRITE(ah, AR_PHY_RXGAIN + regChainOffset, + (OS_REG_READ(ah, AR_PHY_RXGAIN + regChainOffset) & ~AR_PHY_RXGAIN_TXRX_ATTEN) | + SM(IS_EEP_MINOR_V3(ah) ? pModal->txRxAttenCh[i] : txRxAttenLocal, + AR_PHY_RXGAIN_TXRX_ATTEN)); + + OS_REG_WRITE(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + (OS_REG_READ(ah, AR_PHY_GAIN_2GHZ + regChainOffset) & ~AR_PHY_GAIN_2GHZ_RXTX_MARGIN) | + SM(pModal->rxTxMarginCh[i], AR_PHY_GAIN_2GHZ_RXTX_MARGIN)); + } + } + + OS_REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH, pModal->switchSettling); + OS_REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_ADC, pModal->adcDesiredSize); + OS_REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_PGA, pModal->pgaDesiredSize); + OS_REG_WRITE(ah, AR_PHY_RF_CTL4, + SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF) + | SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAB_OFF) + | SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAA_ON) + | SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAB_ON)); + + OS_REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_A2_RX_ON, pModal->txEndToRxOn); + + if (AR_SREV_MERLIN_10_OR_LATER(ah)) { + OS_REG_RMW_FIELD(ah, AR_PHY_CCA, AR9280_PHY_CCA_THRESH62, + pModal->thresh62); + OS_REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, AR_PHY_EXT_CCA0_THRESH62, + pModal->thresh62); + } else { + OS_REG_RMW_FIELD(ah, AR_PHY_CCA, AR_PHY_CCA_THRESH62, + pModal->thresh62); + OS_REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, AR_PHY_EXT_CCA_THRESH62, + pModal->thresh62); + } + + /* Minor Version Specific application */ + if (IS_EEP_MINOR_V2(ah)) { + OS_REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_FRAME_TO_DATA_START, pModal->txFrameToDataStart); + OS_REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_FRAME_TO_PA_ON, pModal->txFrameToPaOn); + } + + if (IS_EEP_MINOR_V3(ah)) { + if (IS_CHAN_HT40(chan)) { + /* Overwrite switch settling with HT40 value */ + OS_REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH, pModal->swSettleHt40); + } + + if ((AR_SREV_OWL_20_OR_LATER(ah)) && + ( AH5416(ah)->ah_rx_chainmask == 0x5 || AH5416(ah)->ah_tx_chainmask == 0x5)){ + /* Reg Offsets are swapped for logical mapping */ + OS_REG_WRITE(ah, AR_PHY_GAIN_2GHZ + 0x1000, (OS_REG_READ(ah, AR_PHY_GAIN_2GHZ + 0x1000) & ~AR_PHY_GAIN_2GHZ_BSW_MARGIN) | + SM(pModal->bswMargin[2], AR_PHY_GAIN_2GHZ_BSW_MARGIN)); + OS_REG_WRITE(ah, AR_PHY_GAIN_2GHZ + 0x1000, (OS_REG_READ(ah, AR_PHY_GAIN_2GHZ + 0x1000) & ~AR_PHY_GAIN_2GHZ_BSW_ATTEN) | + SM(pModal->bswAtten[2], AR_PHY_GAIN_2GHZ_BSW_ATTEN)); + OS_REG_WRITE(ah, AR_PHY_GAIN_2GHZ + 0x2000, (OS_REG_READ(ah, AR_PHY_GAIN_2GHZ + 0x2000) & ~AR_PHY_GAIN_2GHZ_BSW_MARGIN) | + SM(pModal->bswMargin[1], AR_PHY_GAIN_2GHZ_BSW_MARGIN)); + OS_REG_WRITE(ah, AR_PHY_GAIN_2GHZ + 0x2000, (OS_REG_READ(ah, AR_PHY_GAIN_2GHZ + 0x2000) & ~AR_PHY_GAIN_2GHZ_BSW_ATTEN) | + SM(pModal->bswAtten[1], AR_PHY_GAIN_2GHZ_BSW_ATTEN)); + } else { + OS_REG_WRITE(ah, AR_PHY_GAIN_2GHZ + 0x1000, (OS_REG_READ(ah, AR_PHY_GAIN_2GHZ + 0x1000) & ~AR_PHY_GAIN_2GHZ_BSW_MARGIN) | + SM(pModal->bswMargin[1], AR_PHY_GAIN_2GHZ_BSW_MARGIN)); + OS_REG_WRITE(ah, AR_PHY_GAIN_2GHZ + 0x1000, (OS_REG_READ(ah, AR_PHY_GAIN_2GHZ + 0x1000) & ~AR_PHY_GAIN_2GHZ_BSW_ATTEN) | + SM(pModal->bswAtten[1], AR_PHY_GAIN_2GHZ_BSW_ATTEN)); + OS_REG_WRITE(ah, AR_PHY_GAIN_2GHZ + 0x2000, (OS_REG_READ(ah, AR_PHY_GAIN_2GHZ + 0x2000) & ~AR_PHY_GAIN_2GHZ_BSW_MARGIN) | + SM(pModal->bswMargin[2],AR_PHY_GAIN_2GHZ_BSW_MARGIN)); + OS_REG_WRITE(ah, AR_PHY_GAIN_2GHZ + 0x2000, (OS_REG_READ(ah, AR_PHY_GAIN_2GHZ + 0x2000) & ~AR_PHY_GAIN_2GHZ_BSW_ATTEN) | + SM(pModal->bswAtten[2], AR_PHY_GAIN_2GHZ_BSW_ATTEN)); + } + OS_REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ, AR_PHY_GAIN_2GHZ_BSW_MARGIN, pModal->bswMargin[0]); + OS_REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ, AR_PHY_GAIN_2GHZ_BSW_ATTEN, pModal->bswAtten[0]); + } + return AH_TRUE; +} + +/* + * Helper functions common for AP/CB/XB + */ + +/* + * ar5416SetPowerPerRateTable + * + * Sets the transmit power in the baseband for the given + * operating channel and mode. + */ +static HAL_BOOL +ar5416SetPowerPerRateTable(struct ath_hal *ah, struct ar5416eeprom *pEepData, + HAL_CHANNEL_INTERNAL *chan, + int16_t *ratesArray, uint16_t cfgCtl, + uint16_t AntennaReduction, + uint16_t twiceMaxRegulatoryPower, + uint16_t powerLimit) +{ +#define N(a) (sizeof(a)/sizeof(a[0])) +/* Local defines to distinguish between extension and control CTL's */ +#define EXT_ADDITIVE (0x8000) +#define CTL_11A_EXT (CTL_11A | EXT_ADDITIVE) +#define CTL_11G_EXT (CTL_11G | EXT_ADDITIVE) +#define CTL_11B_EXT (CTL_11B | EXT_ADDITIVE) + + uint16_t twiceMaxEdgePower = AR5416_MAX_RATE_POWER; + int i; + int16_t twiceLargestAntenna; + CAL_CTL_DATA *rep; + CAL_TARGET_POWER_LEG targetPowerOfdm, targetPowerCck = {0, {0, 0, 0, 0}}; + CAL_TARGET_POWER_LEG targetPowerOfdmExt = {0, {0, 0, 0, 0}}, targetPowerCckExt = {0, {0, 0, 0, 0}}; + CAL_TARGET_POWER_HT targetPowerHt20, targetPowerHt40 = {0, {0, 0, 0, 0}}; + int16_t scaledPower, minCtlPower; + +#define SUB_NUM_CTL_MODES_AT_5G_40 2 /* excluding HT40, EXT-OFDM */ +#define SUB_NUM_CTL_MODES_AT_2G_40 3 /* excluding HT40, EXT-OFDM, EXT-CCK */ + static const uint16_t ctlModesFor11a[] = { + CTL_11A, CTL_5GHT20, CTL_11A_EXT, CTL_5GHT40 + }; + static const uint16_t ctlModesFor11g[] = { + CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT, CTL_2GHT40 + }; + const uint16_t *pCtlMode; + uint16_t numCtlModes, ctlMode, freq; + CHAN_CENTERS centers; + + ar5416GetChannelCenters(ah, chan, ¢ers); + + /* Compute TxPower reduction due to Antenna Gain */ + + twiceLargestAntenna = AH_MAX(AH_MAX(pEepData->modalHeader[IS_CHAN_2GHZ(chan)].antennaGainCh[0], + pEepData->modalHeader[IS_CHAN_2GHZ(chan)].antennaGainCh[1]), + pEepData->modalHeader[IS_CHAN_2GHZ(chan)].antennaGainCh[2]); +#if 0 + /* Turn it back on if we need to calculate per chain antenna gain reduction */ + /* Use only if the expected gain > 6dbi */ + /* Chain 0 is always used */ + twiceLargestAntenna = pEepData->modalHeader[IS_CHAN_2GHZ(chan)].antennaGainCh[0]; + + /* Look at antenna gains of Chains 1 and 2 if the TX mask is set */ + if (ahp->ah_tx_chainmask & 0x2) + twiceLargestAntenna = AH_MAX(twiceLargestAntenna, + pEepData->modalHeader[IS_CHAN_2GHZ(chan)].antennaGainCh[1]); + + if (ahp->ah_tx_chainmask & 0x4) + twiceLargestAntenna = AH_MAX(twiceLargestAntenna, + pEepData->modalHeader[IS_CHAN_2GHZ(chan)].antennaGainCh[2]); +#endif + twiceLargestAntenna = (int16_t)AH_MIN((AntennaReduction) - twiceLargestAntenna, 0); + + /* XXX setup for 5212 use (really used?) */ + ath_hal_eepromSet(ah, + IS_CHAN_2GHZ(chan) ? AR_EEP_ANTGAINMAX_2 : AR_EEP_ANTGAINMAX_5, + twiceLargestAntenna); + + /* + * scaledPower is the minimum of the user input power level and + * the regulatory allowed power level + */ + scaledPower = AH_MIN(powerLimit, twiceMaxRegulatoryPower + twiceLargestAntenna); + + /* Reduce scaled Power by number of chains active to get to per chain tx power level */ + /* TODO: better value than these? */ + switch (owl_get_ntxchains(AH5416(ah)->ah_tx_chainmask)) { + case 1: + break; + case 2: + scaledPower -= pEepData->modalHeader[IS_CHAN_2GHZ(chan)].pwrDecreaseFor2Chain; + break; + case 3: + scaledPower -= pEepData->modalHeader[IS_CHAN_2GHZ(chan)].pwrDecreaseFor3Chain; + break; + default: + return AH_FALSE; /* Unsupported number of chains */ + } + + scaledPower = AH_MAX(0, scaledPower); + + /* Get target powers from EEPROM - our baseline for TX Power */ + if (IS_CHAN_2GHZ(chan)) { + /* Setup for CTL modes */ + numCtlModes = N(ctlModesFor11g) - SUB_NUM_CTL_MODES_AT_2G_40; /* CTL_11B, CTL_11G, CTL_2GHT20 */ + pCtlMode = ctlModesFor11g; + + ar5416GetTargetPowersLeg(ah, chan, pEepData->calTargetPowerCck, + AR5416_NUM_2G_CCK_TARGET_POWERS, &targetPowerCck, 4, AH_FALSE); + ar5416GetTargetPowersLeg(ah, chan, pEepData->calTargetPower2G, + AR5416_NUM_2G_20_TARGET_POWERS, &targetPowerOfdm, 4, AH_FALSE); + ar5416GetTargetPowers(ah, chan, pEepData->calTargetPower2GHT20, + AR5416_NUM_2G_20_TARGET_POWERS, &targetPowerHt20, 8, AH_FALSE); + + if (IS_CHAN_HT40(chan)) { + numCtlModes = N(ctlModesFor11g); /* All 2G CTL's */ + + ar5416GetTargetPowers(ah, chan, pEepData->calTargetPower2GHT40, + AR5416_NUM_2G_40_TARGET_POWERS, &targetPowerHt40, 8, AH_TRUE); + /* Get target powers for extension channels */ + ar5416GetTargetPowersLeg(ah, chan, pEepData->calTargetPowerCck, + AR5416_NUM_2G_CCK_TARGET_POWERS, &targetPowerCckExt, 4, AH_TRUE); + ar5416GetTargetPowersLeg(ah, chan, pEepData->calTargetPower2G, + AR5416_NUM_2G_20_TARGET_POWERS, &targetPowerOfdmExt, 4, AH_TRUE); + } + } else { + /* Setup for CTL modes */ + numCtlModes = N(ctlModesFor11a) - SUB_NUM_CTL_MODES_AT_5G_40; /* CTL_11A, CTL_5GHT20 */ + pCtlMode = ctlModesFor11a; + + ar5416GetTargetPowersLeg(ah, chan, pEepData->calTargetPower5G, + AR5416_NUM_5G_20_TARGET_POWERS, &targetPowerOfdm, 4, AH_FALSE); + ar5416GetTargetPowers(ah, chan, pEepData->calTargetPower5GHT20, + AR5416_NUM_5G_20_TARGET_POWERS, &targetPowerHt20, 8, AH_FALSE); + + if (IS_CHAN_HT40(chan)) { + numCtlModes = N(ctlModesFor11a); /* All 5G CTL's */ + + ar5416GetTargetPowers(ah, chan, pEepData->calTargetPower5GHT40, + AR5416_NUM_5G_40_TARGET_POWERS, &targetPowerHt40, 8, AH_TRUE); + ar5416GetTargetPowersLeg(ah, chan, pEepData->calTargetPower5G, + AR5416_NUM_5G_20_TARGET_POWERS, &targetPowerOfdmExt, 4, AH_TRUE); + } + } + + /* + * For MIMO, need to apply regulatory caps individually across dynamically + * running modes: CCK, OFDM, HT20, HT40 + * + * The outer loop walks through each possible applicable runtime mode. + * The inner loop walks through each ctlIndex entry in EEPROM. + * The ctl value is encoded as [7:4] == test group, [3:0] == test mode. + * + */ + for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) { + + HAL_BOOL isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) || + (pCtlMode[ctlMode] == CTL_2GHT40); + if (isHt40CtlMode) { + freq = centers.ctl_center; + } else if (pCtlMode[ctlMode] & EXT_ADDITIVE) { + freq = centers.ext_center; + } else { + freq = centers.ctl_center; + } + + /* walk through each CTL index stored in EEPROM */ + for (i = 0; (i < AR5416_NUM_CTLS) && pEepData->ctlIndex[i]; i++) { + uint16_t twiceMinEdgePower; + + /* compare test group from regulatory channel list with test mode from pCtlMode list */ + if ((((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) == pEepData->ctlIndex[i]) || + (((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) == + ((pEepData->ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL))) { + rep = &(pEepData->ctlData[i]); + twiceMinEdgePower = ar5416GetMaxEdgePower(freq, + rep->ctlEdges[owl_get_ntxchains(AH5416(ah)->ah_tx_chainmask) - 1], + IS_CHAN_2GHZ(chan)); + 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 { + /* specific */ + twiceMaxEdgePower = twiceMinEdgePower; + break; + } + } + } + minCtlPower = (uint8_t)AH_MIN(twiceMaxEdgePower, scaledPower); + /* Apply ctl mode to correct target power set */ + switch(pCtlMode[ctlMode]) { + case CTL_11B: + for (i = 0; i < N(targetPowerCck.tPow2x); i++) { + targetPowerCck.tPow2x[i] = (uint8_t)AH_MIN(targetPowerCck.tPow2x[i], minCtlPower); + } + break; + case CTL_11A: + case CTL_11G: + for (i = 0; i < N(targetPowerOfdm.tPow2x); i++) { + targetPowerOfdm.tPow2x[i] = (uint8_t)AH_MIN(targetPowerOfdm.tPow2x[i], minCtlPower); + } + break; + case CTL_5GHT20: + case CTL_2GHT20: + for (i = 0; i < N(targetPowerHt20.tPow2x); i++) { + targetPowerHt20.tPow2x[i] = (uint8_t)AH_MIN(targetPowerHt20.tPow2x[i], minCtlPower); + } + break; + case CTL_11B_EXT: + targetPowerCckExt.tPow2x[0] = (uint8_t)AH_MIN(targetPowerCckExt.tPow2x[0], minCtlPower); + break; + case CTL_11A_EXT: + case CTL_11G_EXT: + targetPowerOfdmExt.tPow2x[0] = (uint8_t)AH_MIN(targetPowerOfdmExt.tPow2x[0], minCtlPower); + break; + case CTL_5GHT40: + case CTL_2GHT40: + for (i = 0; i < N(targetPowerHt40.tPow2x); i++) { + targetPowerHt40.tPow2x[i] = (uint8_t)AH_MIN(targetPowerHt40.tPow2x[i], minCtlPower); + } + break; + default: + return AH_FALSE; + break; + } + } /* end ctl mode checking */ + + /* Set rates Array from collected data */ + ratesArray[rate6mb] = ratesArray[rate9mb] = ratesArray[rate12mb] = ratesArray[rate18mb] = ratesArray[rate24mb] = targetPowerOfdm.tPow2x[0]; + ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1]; + ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2]; + ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3]; + ratesArray[rateXr] = targetPowerOfdm.tPow2x[0]; + + for (i = 0; i < N(targetPowerHt20.tPow2x); i++) { + ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i]; + } + + if (IS_CHAN_2GHZ(chan)) { + ratesArray[rate1l] = targetPowerCck.tPow2x[0]; + ratesArray[rate2s] = ratesArray[rate2l] = targetPowerCck.tPow2x[1]; + ratesArray[rate5_5s] = ratesArray[rate5_5l] = targetPowerCck.tPow2x[2]; + ratesArray[rate11s] = ratesArray[rate11l] = targetPowerCck.tPow2x[3]; + } + if (IS_CHAN_HT40(chan)) { + for (i = 0; i < N(targetPowerHt40.tPow2x); i++) { + ratesArray[rateHt40_0 + i] = targetPowerHt40.tPow2x[i]; + } + ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0]; + ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0]; + ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0]; + if (IS_CHAN_2GHZ(chan)) { + ratesArray[rateExtCck] = targetPowerCckExt.tPow2x[0]; + } + } + return AH_TRUE; +#undef EXT_ADDITIVE +#undef CTL_11A_EXT +#undef CTL_11G_EXT +#undef CTL_11B_EXT +#undef SUB_NUM_CTL_MODES_AT_5G_40 +#undef SUB_NUM_CTL_MODES_AT_2G_40 +#undef N +} + +/************************************************************************** + * fbin2freq + * + * Get channel value from binary representation held in eeprom + * RETURNS: the frequency in MHz + */ +static uint16_t +fbin2freq(uint8_t fbin, HAL_BOOL is2GHz) +{ + /* + * Reserved value 0xFF provides an empty definition both as + * an fbin and as a frequency - do not convert + */ + if (fbin == AR5416_BCHAN_UNUSED) { + return fbin; + } + + return (uint16_t)((is2GHz) ? (2300 + fbin) : (4800 + 5 * fbin)); +} + +/* + * ar5416GetMaxEdgePower + * + * Find the maximum conformance test limit for the given channel and CTL info + */ +static uint16_t +ar5416GetMaxEdgePower(uint16_t freq, CAL_CTL_EDGES *pRdEdgesPower, HAL_BOOL is2GHz) +{ + uint16_t twiceMaxEdgePower = AR5416_MAX_RATE_POWER; + int i; + + /* Get the edge power */ + for (i = 0; (i < AR5416_NUM_BAND_EDGES) && (pRdEdgesPower[i].bChannel != AR5416_BCHAN_UNUSED) ; i++) { + /* + * If there's an exact channel match or an inband flag set + * on the lower channel use the given rdEdgePower + */ + if (freq == fbin2freq(pRdEdgesPower[i].bChannel, is2GHz)) { + twiceMaxEdgePower = MS(pRdEdgesPower[i].tPowerFlag, CAL_CTL_EDGES_POWER); + break; + } else if ((i > 0) && (freq < fbin2freq(pRdEdgesPower[i].bChannel, is2GHz))) { + if (fbin2freq(pRdEdgesPower[i - 1].bChannel, is2GHz) < freq && (pRdEdgesPower[i - 1].tPowerFlag & CAL_CTL_EDGES_FLAG) != 0) { + twiceMaxEdgePower = MS(pRdEdgesPower[i - 1].tPowerFlag, CAL_CTL_EDGES_POWER); + } + /* Leave loop - no more affecting edges possible in this monotonic increasing list */ + break; + } + } + HALASSERT(twiceMaxEdgePower > 0); + return twiceMaxEdgePower; +} + +/************************************************************** + * ar5416GetTargetPowers + * + * Return the rates of target power for the given target power table + * channel, and number of channels + */ +static void +ar5416GetTargetPowers(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan, + CAL_TARGET_POWER_HT *powInfo, uint16_t numChannels, + CAL_TARGET_POWER_HT *pNewPower, uint16_t numRates, + HAL_BOOL isHt40Target) +{ + uint16_t clo, chi; + int i; + int matchIndex = -1, lowIndex = -1; + uint16_t freq; + CHAN_CENTERS centers; + + ar5416GetChannelCenters(ah, chan, ¢ers); + freq = isHt40Target ? centers.synth_center : centers.ctl_center; + + /* Copy the target powers into the temp channel list */ + if (freq <= fbin2freq(powInfo[0].bChannel, IS_CHAN_2GHZ(chan))) { + matchIndex = 0; + } else { + for (i = 0; (i < numChannels) && (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) { + if (freq == fbin2freq(powInfo[i].bChannel, IS_CHAN_2GHZ(chan))) { + matchIndex = i; + break; + } else if ((freq < fbin2freq(powInfo[i].bChannel, IS_CHAN_2GHZ(chan))) && + (freq > fbin2freq(powInfo[i - 1].bChannel, IS_CHAN_2GHZ(chan)))) + { + lowIndex = i - 1; + break; + } + } + if ((matchIndex == -1) && (lowIndex == -1)) { + HALASSERT(freq > fbin2freq(powInfo[i - 1].bChannel, IS_CHAN_2GHZ(chan))); + matchIndex = i - 1; + } + } + + if (matchIndex != -1) { + OS_MEMCPY(pNewPower, &powInfo[matchIndex], sizeof(*pNewPower)); + } else { + HALASSERT(lowIndex != -1); + /* + * Get the lower and upper channels, target powers, + * and interpolate between them. + */ + clo = fbin2freq(powInfo[lowIndex].bChannel, IS_CHAN_2GHZ(chan)); + chi = fbin2freq(powInfo[lowIndex + 1].bChannel, IS_CHAN_2GHZ(chan)); + + for (i = 0; i < numRates; i++) { + pNewPower->tPow2x[i] = (uint8_t)interpolate(freq, clo, chi, + powInfo[lowIndex].tPow2x[i], powInfo[lowIndex + 1].tPow2x[i]); + } + } +} +/************************************************************** + * ar5416GetTargetPowersLeg + * + * Return the four rates of target power for the given target power table + * channel, and number of channels + */ +static void +ar5416GetTargetPowersLeg(struct ath_hal *ah, + HAL_CHANNEL_INTERNAL *chan, + CAL_TARGET_POWER_LEG *powInfo, uint16_t numChannels, + CAL_TARGET_POWER_LEG *pNewPower, uint16_t numRates, + HAL_BOOL isExtTarget) +{ + uint16_t clo, chi; + int i; + int matchIndex = -1, lowIndex = -1; + uint16_t freq; + CHAN_CENTERS centers; + + ar5416GetChannelCenters(ah, chan, ¢ers); + freq = (isExtTarget) ? centers.ext_center :centers.ctl_center; + + /* Copy the target powers into the temp channel list */ + if (freq <= fbin2freq(powInfo[0].bChannel, IS_CHAN_2GHZ(chan))) { + matchIndex = 0; + } else { + for (i = 0; (i < numChannels) && (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) { + if (freq == fbin2freq(powInfo[i].bChannel, IS_CHAN_2GHZ(chan))) { + matchIndex = i; + break; + } else if ((freq < fbin2freq(powInfo[i].bChannel, IS_CHAN_2GHZ(chan))) && + (freq > fbin2freq(powInfo[i - 1].bChannel, IS_CHAN_2GHZ(chan)))) + { + lowIndex = i - 1; + break; + } + } + if ((matchIndex == -1) && (lowIndex == -1)) { + HALASSERT(freq > fbin2freq(powInfo[i - 1].bChannel, IS_CHAN_2GHZ(chan))); + matchIndex = i - 1; + } + } + + if (matchIndex != -1) { + OS_MEMCPY(pNewPower, &powInfo[matchIndex], sizeof(*pNewPower)); + } else { + HALASSERT(lowIndex != -1); + /* + * Get the lower and upper channels, target powers, + * and interpolate between them. + */ + clo = fbin2freq(powInfo[lowIndex].bChannel, IS_CHAN_2GHZ(chan)); + chi = fbin2freq(powInfo[lowIndex + 1].bChannel, IS_CHAN_2GHZ(chan)); + + for (i = 0; i < numRates; i++) { + pNewPower->tPow2x[i] = (uint8_t)interpolate(freq, clo, chi, + powInfo[lowIndex].tPow2x[i], powInfo[lowIndex + 1].tPow2x[i]); + } + } +} + +/************************************************************** + * ar5416SetPowerCalTable + * + * Pull the PDADC piers from cal data and interpolate them across the given + * points as well as from the nearest pier(s) to get a power detector + * linear voltage to power level table. + */ +static HAL_BOOL +ar5416SetPowerCalTable(struct ath_hal *ah, struct ar5416eeprom *pEepData, HAL_CHANNEL_INTERNAL *chan, int16_t *pTxPowerIndexOffset) +{ + CAL_DATA_PER_FREQ *pRawDataset; + uint8_t *pCalBChans = AH_NULL; + uint16_t pdGainOverlap_t2; + static uint8_t pdadcValues[AR5416_NUM_PDADC_VALUES]; + uint16_t gainBoundaries[AR5416_PD_GAINS_IN_MASK]; + uint16_t numPiers, i, j; + int16_t tMinCalPower; + uint16_t numXpdGain, xpdMask; + uint16_t xpdGainValues[AR5416_NUM_PD_GAINS]; + uint32_t reg32, regOffset, regChainOffset; + + ath_hal_memzero(xpdGainValues, sizeof(xpdGainValues)); + + xpdMask = pEepData->modalHeader[IS_CHAN_2GHZ(chan)].xpdGain; + + if (IS_EEP_MINOR_V2(ah)) { + pdGainOverlap_t2 = pEepData->modalHeader[IS_CHAN_2GHZ(chan)].pdGainOverlap; + } else { + pdGainOverlap_t2 = (uint16_t)(MS(OS_REG_READ(ah, AR_PHY_TPCRG5), AR_PHY_TPCRG5_PD_GAIN_OVERLAP)); + } + + if (IS_CHAN_2GHZ(chan)) { + pCalBChans = pEepData->calFreqPier2G; + numPiers = AR5416_NUM_2G_CAL_PIERS; + } else { + pCalBChans = pEepData->calFreqPier5G; + numPiers = AR5416_NUM_5G_CAL_PIERS; + } + + numXpdGain = 0; + /* Calculate the value of xpdgains from the xpdGain Mask */ + for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) { + if ((xpdMask >> (AR5416_PD_GAINS_IN_MASK - i)) & 1) { + if (numXpdGain >= AR5416_NUM_PD_GAINS) { + HALASSERT(0); + break; + } + xpdGainValues[numXpdGain] = (uint16_t)(AR5416_PD_GAINS_IN_MASK - i); + numXpdGain++; + } + } + + /* Write the detector gain biases and their number */ + OS_REG_WRITE(ah, AR_PHY_TPCRG1, (OS_REG_READ(ah, AR_PHY_TPCRG1) & + ~(AR_PHY_TPCRG1_NUM_PD_GAIN | AR_PHY_TPCRG1_PD_GAIN_1 | AR_PHY_TPCRG1_PD_GAIN_2 | AR_PHY_TPCRG1_PD_GAIN_3)) | + SM(numXpdGain - 1, AR_PHY_TPCRG1_NUM_PD_GAIN) | SM(xpdGainValues[0], AR_PHY_TPCRG1_PD_GAIN_1 ) | + SM(xpdGainValues[1], AR_PHY_TPCRG1_PD_GAIN_2) | SM(xpdGainValues[2], AR_PHY_TPCRG1_PD_GAIN_3)); + + for (i = 0; i < AR5416_MAX_CHAINS; i++) { + + if (AR_SREV_OWL_20_OR_LATER(ah) && + ( AH5416(ah)->ah_rx_chainmask == 0x5 || AH5416(ah)->ah_tx_chainmask == 0x5) && (i != 0)) { + /* Regs are swapped from chain 2 to 1 for 5416 2_0 with + * only chains 0 and 2 populated + */ + regChainOffset = (i == 1) ? 0x2000 : 0x1000; + } else { + regChainOffset = i * 0x1000; + } + + if (pEepData->baseEepHeader.txMask & (1 << i)) { + if (IS_CHAN_2GHZ(chan)) { + pRawDataset = pEepData->calPierData2G[i]; + } else { + pRawDataset = pEepData->calPierData5G[i]; + } + + ar5416GetGainBoundariesAndPdadcs(ah, chan, pRawDataset, + pCalBChans, numPiers, + pdGainOverlap_t2, + &tMinCalPower, gainBoundaries, + pdadcValues, numXpdGain); + + if ((i == 0) || AR_SREV_OWL_20_OR_LATER(ah)) { + /* + * 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 + */ + + OS_REG_WRITE(ah, AR_PHY_TPCRG5 + regChainOffset, + 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)); + } + + /* Write the power values into the baseband power table */ + regOffset = AR_PHY_BASE + (672 << 2) + regChainOffset; + + for (j = 0; j < 32; j++) { + reg32 = ((pdadcValues[4*j + 0] & 0xFF) << 0) | + ((pdadcValues[4*j + 1] & 0xFF) << 8) | + ((pdadcValues[4*j + 2] & 0xFF) << 16) | + ((pdadcValues[4*j + 3] & 0xFF) << 24) ; + OS_REG_WRITE(ah, regOffset, reg32); + +#ifdef PDADC_DUMP + ath_hal_printf(ah, "PDADC: Chain %d | PDADC %3d Value %3d | PDADC %3d Value %3d | PDADC %3d Value %3d | PDADC %3d Value %3d |\n", + i, + 4*j, pdadcValues[4*j], + 4*j+1, pdadcValues[4*j + 1], + 4*j+2, pdadcValues[4*j + 2], + 4*j+3, pdadcValues[4*j + 3]); +#endif + regOffset += 4; + } + } + } + *pTxPowerIndexOffset = 0; + + return AH_TRUE; +} + +/************************************************************** + * ar5416GetGainBoundariesAndPdadcs + * + * Uses the data points read from EEPROM to reconstruct the pdadc power table + * Called by ar5416SetPowerCalTable only. + */ +static void +ar5416GetGainBoundariesAndPdadcs(struct ath_hal *ah, + HAL_CHANNEL_INTERNAL *chan, CAL_DATA_PER_FREQ *pRawDataSet, + uint8_t * bChans, uint16_t availPiers, + uint16_t tPdGainOverlap, int16_t *pMinCalPower, uint16_t * pPdGainBoundaries, + uint8_t * pPDADCValues, uint16_t numXpdGains) +{ + + int i, j, k; + int16_t ss; /* potentially -ve index for taking care of pdGainOverlap */ + uint16_t idxL = 0, idxR = 0, numPiers; /* Pier indexes */ + + /* filled out Vpd table for all pdGains (chanL) */ + static uint8_t vpdTableL[AR5416_NUM_PD_GAINS][AR5416_MAX_PWR_RANGE_IN_HALF_DB]; + + /* filled out Vpd table for all pdGains (chanR) */ + static uint8_t vpdTableR[AR5416_NUM_PD_GAINS][AR5416_MAX_PWR_RANGE_IN_HALF_DB]; + + /* filled out Vpd table for all pdGains (interpolated) */ + static uint8_t vpdTableI[AR5416_NUM_PD_GAINS][AR5416_MAX_PWR_RANGE_IN_HALF_DB]; + + uint8_t *pVpdL, *pVpdR, *pPwrL, *pPwrR; + uint8_t minPwrT4[AR5416_NUM_PD_GAINS]; + uint8_t maxPwrT4[AR5416_NUM_PD_GAINS]; + int16_t vpdStep; + int16_t tmpVal; + uint16_t sizeCurrVpdTable, maxIndex, tgtIndex; + HAL_BOOL match; + int16_t minDelta = 0; + CHAN_CENTERS centers; + + ar5416GetChannelCenters(ah, chan, ¢ers); + + /* Trim numPiers for the number of populated channel Piers */ + for (numPiers = 0; numPiers < availPiers; numPiers++) { + if (bChans[numPiers] == AR5416_BCHAN_UNUSED) { + break; + } + } + + /* Find pier indexes around the current channel */ + match = getLowerUpperIndex((uint8_t)FREQ2FBIN(centers.synth_center, IS_CHAN_2GHZ(chan)), + bChans, numPiers, &idxL, &idxR); + + if (match) { + /* Directly fill both vpd tables from the matching index */ + for (i = 0; i < numXpdGains; i++) { + minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0]; + maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4]; + ar5416FillVpdTable(minPwrT4[i], maxPwrT4[i], pRawDataSet[idxL].pwrPdg[i], + pRawDataSet[idxL].vpdPdg[i], AR5416_PD_GAIN_ICEPTS, vpdTableI[i]); + } + } else { + for (i = 0; i < numXpdGains; i++) { + pVpdL = pRawDataSet[idxL].vpdPdg[i]; + pPwrL = pRawDataSet[idxL].pwrPdg[i]; + pVpdR = pRawDataSet[idxR].vpdPdg[i]; + pPwrR = pRawDataSet[idxR].pwrPdg[i]; + + /* Start Vpd interpolation from the max of the minimum powers */ + minPwrT4[i] = AH_MAX(pPwrL[0], pPwrR[0]); + + /* End Vpd interpolation from the min of the max powers */ + maxPwrT4[i] = AH_MIN(pPwrL[AR5416_PD_GAIN_ICEPTS - 1], pPwrR[AR5416_PD_GAIN_ICEPTS - 1]); + HALASSERT(maxPwrT4[i] > minPwrT4[i]); + + /* Fill pier Vpds */ + ar5416FillVpdTable(minPwrT4[i], maxPwrT4[i], pPwrL, pVpdL, AR5416_PD_GAIN_ICEPTS, vpdTableL[i]); + ar5416FillVpdTable(minPwrT4[i], maxPwrT4[i], pPwrR, pVpdR, AR5416_PD_GAIN_ICEPTS, vpdTableR[i]); + + /* Interpolate the final vpd */ + for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) { + vpdTableI[i][j] = (uint8_t)(interpolate((uint16_t)FREQ2FBIN(centers.synth_center, IS_CHAN_2GHZ(chan)), + bChans[idxL], bChans[idxR], vpdTableL[i][j], vpdTableR[i][j])); + } + } + } + *pMinCalPower = (int16_t)(minPwrT4[0] / 2); + + k = 0; /* index for the final table */ + for (i = 0; i < numXpdGains; i++) { + if (i == (numXpdGains - 1)) { + pPdGainBoundaries[i] = (uint16_t)(maxPwrT4[i] / 2); + } else { + pPdGainBoundaries[i] = (uint16_t)((maxPwrT4[i] + minPwrT4[i+1]) / 4); + } + + pPdGainBoundaries[i] = (uint16_t)AH_MIN(AR5416_MAX_RATE_POWER, pPdGainBoundaries[i]); + + /* NB: only applies to owl 1.0 */ + if ((i == 0) && !AR_SREV_OWL_20_OR_LATER(ah) ) { + /* + * fix the gain delta, but get a delta that can be applied to min to + * keep the upper power values accurate, don't think max needs to + * be adjusted because should not be at that area of the table? + */ + minDelta = pPdGainBoundaries[0] - 23; + pPdGainBoundaries[0] = 23; + } + else { + minDelta = 0; + } + + /* Find starting index for this pdGain */ + if (i == 0) { + ss = 0; /* for the first pdGain, start from index 0 */ + } else { + /* need overlap entries extrapolated below. */ + ss = (int16_t)((pPdGainBoundaries[i-1] - (minPwrT4[i] / 2)) - tPdGainOverlap + 1 + minDelta); + } + vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]); + vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); + /* + *-ve ss indicates need to extrapolate data below for this pdGain + */ + while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { + tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep); + pPDADCValues[k++] = (uint8_t)((tmpVal < 0) ? 0 : tmpVal); + ss++; + } + + sizeCurrVpdTable = (uint8_t)((maxPwrT4[i] - minPwrT4[i]) / 2 +1); + tgtIndex = (uint8_t)(pPdGainBoundaries[i] + tPdGainOverlap - (minPwrT4[i] / 2)); + maxIndex = (tgtIndex < sizeCurrVpdTable) ? tgtIndex : sizeCurrVpdTable; + + while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { + pPDADCValues[k++] = vpdTableI[i][ss++]; + } + + vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] - vpdTableI[i][sizeCurrVpdTable - 2]); + vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); + /* + * for last gain, pdGainBoundary == Pmax_t2, so will + * have to extrapolate + */ + if (tgtIndex > maxIndex) { /* need to extrapolate above */ + while ((ss <= tgtIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { + tmpVal = (int16_t)((vpdTableI[i][sizeCurrVpdTable - 1] + + (ss - maxIndex +1) * vpdStep)); + pPDADCValues[k++] = (uint8_t)((tmpVal > 255) ? 255 : tmpVal); + ss++; + } + } /* extrapolated above */ + } /* for all pdGainUsed */ + + /* Fill out pdGainBoundaries - only up to 2 allowed here, but hardware allows up to 4 */ + while (i < AR5416_PD_GAINS_IN_MASK) { + pPdGainBoundaries[i] = pPdGainBoundaries[i-1]; + i++; + } + + while (k < AR5416_NUM_PDADC_VALUES) { + pPDADCValues[k] = pPDADCValues[k-1]; + k++; + } + return; +} + +/************************************************************** + * getLowerUppderIndex + * + * Return indices surrounding the value in sorted integer lists. + * Requirement: the input list must be monotonically increasing + * and populated up to the list size + * Returns: match is set if an index in the array matches exactly + * or a the target is before or after the range of the array. + */ +HAL_BOOL +getLowerUpperIndex(uint8_t target, uint8_t *pList, uint16_t listSize, + uint16_t *indexL, uint16_t *indexR) +{ + uint16_t i; + + /* + * Check first and last elements for beyond ordered array cases. + */ + if (target <= pList[0]) { + *indexL = *indexR = 0; + return AH_TRUE; + } + if (target >= pList[listSize-1]) { + *indexL = *indexR = (uint16_t)(listSize - 1); + return AH_TRUE; + } + + /* look for value being near or between 2 values in list */ + for (i = 0; i < listSize - 1; 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 (pList[i] == target) { + *indexL = *indexR = i; + return AH_TRUE; + } + /* + * Look for value being between current value and next value + * if so return these 2 values + */ + if (target < pList[i + 1]) { + *indexL = i; + *indexR = (uint16_t)(i + 1); + return AH_FALSE; + } + } + HALASSERT(0); + return AH_FALSE; +} + +/************************************************************** + * ar5416FillVpdTable + * + * Fill the Vpdlist for indices Pmax-Pmin + * Note: pwrMin, pwrMax and Vpdlist are all in dBm * 4 + */ +static HAL_BOOL +ar5416FillVpdTable(uint8_t pwrMin, uint8_t pwrMax, uint8_t *pPwrList, + uint8_t *pVpdList, uint16_t numIntercepts, uint8_t *pRetVpdList) +{ + uint16_t i, k; + uint8_t currPwr = pwrMin; + uint16_t idxL = 0, idxR = 0; + + HALASSERT(pwrMax > pwrMin); + for (i = 0; i <= (pwrMax - pwrMin) / 2; i++) { + getLowerUpperIndex(currPwr, pPwrList, numIntercepts, + &(idxL), &(idxR)); + if (idxR < 1) + idxR = 1; /* extrapolate below */ + if (idxL == numIntercepts - 1) + idxL = (uint16_t)(numIntercepts - 2); /* extrapolate above */ + if (pPwrList[idxL] == pPwrList[idxR]) + k = pVpdList[idxL]; + else + k = (uint16_t)( ((currPwr - pPwrList[idxL]) * pVpdList[idxR] + (pPwrList[idxR] - currPwr) * pVpdList[idxL]) / + (pPwrList[idxR] - pPwrList[idxL]) ); + HALASSERT(k < 256); + pRetVpdList[i] = (uint8_t)k; + currPwr += 2; /* half dB steps */ + } + + return AH_TRUE; +} + +/************************************************************************** + * interpolate + * + * Returns signed interpolated or the scaled up interpolated value + */ +static int16_t +interpolate(uint16_t target, uint16_t srcLeft, uint16_t srcRight, + int16_t targetLeft, int16_t targetRight) +{ + int16_t rv; + + if (srcRight == srcLeft) { + rv = targetLeft; + } else { + rv = (int16_t)( ((target - srcLeft) * targetRight + + (srcRight - target) * targetLeft) / (srcRight - srcLeft) ); + } + return rv; +} + +static void +ar5416Set11nRegs(struct ath_hal *ah, HAL_CHANNEL *chan) +{ + uint32_t phymode; + HAL_HT_MACMODE macmode; /* MAC - 20/40 mode */ + + if (!IS_CHAN_HT(chan)) + return; + + /* Enable 11n HT, 20 MHz */ + phymode = AR_PHY_FC_HT_EN | AR_PHY_FC_SHORT_GI_40 + | AR_PHY_FC_SINGLE_HT_LTF1 | AR_PHY_FC_WALSH; + + /* Configure baseband for dynamic 20/40 operation */ + if (IS_CHAN_HT40(chan)) { + phymode |= AR_PHY_FC_DYN2040_EN | AR_PHY_FC_SHORT_GI_40; + + /* Configure control (primary) channel at +-10MHz */ + if ((chan->channelFlags & CHANNEL_HT40PLUS)) + phymode |= AR_PHY_FC_DYN2040_PRI_CH; +#if 0 + /* Configure 20/25 spacing */ + if (ht->ht_extprotspacing == HAL_HT_EXTPROTSPACING_25) + phymode |= AR_PHY_FC_DYN2040_EXT_CH; +#endif + macmode = HAL_HT_MACMODE_2040; + } else + macmode = HAL_HT_MACMODE_20; + OS_REG_WRITE(ah, AR_PHY_TURBO, phymode); + + /* Configure MAC for 20/40 operation */ + ar5416Set11nMac2040(ah, macmode); + + /* global transmit timeout (25 TUs default)*/ + /* XXX - put this elsewhere??? */ + OS_REG_WRITE(ah, AR_GTXTO, 25 << AR_GTXTO_TIMEOUT_LIMIT_S) ; + + /* carrier sense timeout */ + OS_REG_SET_BIT(ah, AR_GTTM, AR_GTTM_CST_USEC); + OS_REG_WRITE(ah, AR_CST, 1 << AR_CST_TIMEOUT_LIMIT_S); +} + +void +ar5416GetChannelCenters(struct ath_hal *ah, + HAL_CHANNEL_INTERNAL *chan, CHAN_CENTERS *centers) +{ + centers->ctl_center = chan->channel; + centers->synth_center = chan->channel; + /* + * In 20/40 phy mode, the center frequency is + * "between" the control and extension channels. + */ + if (chan->channelFlags & CHANNEL_HT40PLUS) { + centers->synth_center += HT40_CHANNEL_CENTER_SHIFT; + centers->ext_center = + centers->synth_center + HT40_CHANNEL_CENTER_SHIFT; + } else if (chan->channelFlags & CHANNEL_HT40MINUS) { + centers->synth_center -= HT40_CHANNEL_CENTER_SHIFT; + centers->ext_center = + centers->synth_center - HT40_CHANNEL_CENTER_SHIFT; + } else { + centers->ext_center = chan->channel; + } +} --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5416/ar5416_xmit.c 2009-05-15 11:11:29.000000000 +0100 @@ -0,0 +1,698 @@ +/* + * 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: ar5416_xmit.c,v 1.1 2009/03/23 17:14:48 sborrill Exp $ + */ +#include "opt_ah.h" + +#include "ah.h" +#include "ah_desc.h" +#include "ah_internal.h" + +#include "ar5416/ar5416.h" +#include "ar5416/ar5416reg.h" +#include "ar5416/ar5416phy.h" +#include "ar5416/ar5416desc.h" + +/* + * Stop transmit on the specified queue + */ +HAL_BOOL +ar5416StopTxDma(struct ath_hal *ah, u_int q) +{ +#define STOP_DMA_TIMEOUT 4000 /* us */ +#define STOP_DMA_ITER 100 /* us */ + u_int i; + + 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 = STOP_DMA_TIMEOUT/STOP_DMA_ITER; i != 0; i--) { + if (ar5212NumTxPending(ah, q) == 0) + break; + OS_DELAY(STOP_DMA_ITER); + } +#ifdef AH_DEBUG + if (i == 0) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: queue %u DMA did not stop in 400 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 */ + + /* ar5416 and up can kill packets at the PCU level */ + if (ar5212NumTxPending(ah, q)) { + uint32_t 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++) { + uint32_t tsfLow = OS_REG_READ(ah, AR_TSF_L32); + OS_REG_WRITE(ah, AR_QUIET2, + SM(10, AR_QUIET2_QUIET_DUR)); + OS_REG_WRITE(ah, AR_QUIET_PERIOD, 100); + OS_REG_WRITE(ah, AR_NEXT_QUIET, tsfLow >> 10); + OS_REG_SET_BIT(ah, AR_TIMER_MODE, AR_TIMER_MODE_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_TIMER_MODE, AR_TIMER_MODE_QUIET); + + /* Verify the transmit q is empty */ + for (i = STOP_DMA_TIMEOUT/STOP_DMA_ITER; i != 0; i--) { + if (ar5212NumTxPending(ah, q) == 0) + break; + OS_DELAY(STOP_DMA_ITER); + } + if (i == 0) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: Failed to stop Tx DMA in %d msec after killing" + " last frame\n", __func__, STOP_DMA_TIMEOUT / 1000); + } + OS_REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_CHAN_IDLE); + } + + OS_REG_WRITE(ah, AR_Q_TXD, 0); + return (i != 0); +#undef STOP_DMA_ITER +#undef STOP_DMA_TIMEOUT +} + +#define VALID_KEY_TYPES \ + ((1 << HAL_KEY_TYPE_CLEAR) | (1 << HAL_KEY_TYPE_WEP)|\ + (1 << HAL_KEY_TYPE_AES) | (1 << HAL_KEY_TYPE_TKIP)) +#define isValidKeyType(_t) ((1 << (_t)) & VALID_KEY_TYPES) + +#define set11nTries(_series, _index) \ + (SM((_series)[_index].Tries, AR_XmitDataTries##_index)) + +#define set11nRate(_series, _index) \ + (SM((_series)[_index].Rate, AR_XmitRate##_index)) + +#define set11nPktDurRTSCTS(_series, _index) \ + (SM((_series)[_index].PktDuration, AR_PacketDur##_index) |\ + ((_series)[_index].RateFlags & HAL_RATESERIES_RTS_CTS ?\ + AR_RTSCTSQual##_index : 0)) + +#define set11nRateFlags(_series, _index) \ + ((_series)[_index].RateFlags & HAL_RATESERIES_2040 ? AR_2040_##_index : 0) \ + |((_series)[_index].RateFlags & HAL_RATESERIES_HALFGI ? AR_GI##_index : 0) \ + |SM((_series)[_index].ChSel, AR_ChainSel##_index) + +/* + * 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_ClrDestMask : 0) + | (flags & HAL_TXDESC_INTREQ ? AR_TxIntrReq : 0) + ; + ads->ds_ctl1 = (type << AR_FrameType_S) + | (flags & HAL_TXDESC_NOACK ? AR_NoAck : 0) + ; + ads->ds_ctl2 = SM(txTries0, AR_XmitDataTries0) + | (flags & HAL_TXDESC_DURENA ? AR_DurUpdateEn : 0) + ; + ads->ds_ctl3 = (txRate0 << AR_XmitRate0_S) + ; + ads->ds_ctl4 = 0; + ads->ds_ctl5 = 0; + ads->ds_ctl6 = 0; + ads->ds_ctl7 = SM(ahp->ah_tx_chainmask, AR_ChainSel0) + | SM(ahp->ah_tx_chainmask, AR_ChainSel1) + | SM(ahp->ah_tx_chainmask, AR_ChainSel2) + | SM(ahp->ah_tx_chainmask, AR_ChainSel3) + ; + ads->ds_ctl8 = 0; + ads->ds_ctl9 = (txPower << 24); /* XXX? */ + ads->ds_ctl10 = (txPower << 24); /* XXX? */ + ads->ds_ctl11 = (txPower << 24); /* XXX? */ + if (keyIx != HAL_TXKEYIX_INVALID) { + /* XXX validate key index */ + ads->ds_ctl1 |= SM(keyIx, AR_DestIdx); + ads->ds_ctl0 |= AR_DestIdxValid; + ads->ds_ctl6 |= SM(ahp->ah_keytype[keyIx], AR_EncrType); + } + 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_RTSEnable : 0) + ; + ads->ds_ctl2 |= SM(rtsctsDuration, AR_BurstDur); + ads->ds_ctl7 |= (rtsctsRate << AR_RTSCTSRate_S); + } + return AH_TRUE; +#undef RTSCTS +} + +HAL_BOOL +ar5416SetupXTxDesc(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 ar5416_desc *ads = AR5416DESC(ds); + + if (txTries1) { + HALASSERT(isValidTxRate(txRate1)); + ads->ds_ctl2 |= SM(txTries1, AR_XmitDataTries1); + ads->ds_ctl3 |= (txRate1 << AR_XmitRate1_S); + } + if (txTries2) { + HALASSERT(isValidTxRate(txRate2)); + ads->ds_ctl2 |= SM(txTries2, AR_XmitDataTries2); + ads->ds_ctl3 |= (txRate2 << AR_XmitRate2_S); + } + if (txTries3) { + HALASSERT(isValidTxRate(txRate3)); + ads->ds_ctl2 |= SM(txTries3, AR_XmitDataTries3); + ads->ds_ctl3 |= (txRate3 << AR_XmitRate3_S); + } + return AH_TRUE; +} + +HAL_BOOL +ar5416FillTxDesc(struct ath_hal *ah, struct ath_desc *ds, + u_int segLen, HAL_BOOL firstSeg, HAL_BOOL lastSeg, + const struct ath_desc *ds0) +{ + struct ar5416_desc *ads = AR5416DESC(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_TxMore); + } 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(AR5416DESC_CONST(ds0)->ds_ctl2); + ads->ds_ctl3 = __bswap32(AR5416DESC_CONST(ds0)->ds_ctl3); +#else + ads->ds_ctl2 = AR5416DESC_CONST(ds0)->ds_ctl2; + ads->ds_ctl3 = AR5416DESC_CONST(ds0)->ds_ctl3; +#endif + } else { /* !firstSeg && !lastSeg */ + /* + * Intermediate descriptor in a multi-descriptor frame. + */ + ads->ds_ctl0 = 0; + ads->ds_ctl1 = segLen | AR_TxMore; + ads->ds_ctl2 = 0; + ads->ds_ctl3 = 0; + } + /* XXX only on last descriptor? */ + OS_MEMZERO(ads->u.tx.status, sizeof(ads->u.tx.status)); + return AH_TRUE; +} + +#if 0 + +HAL_BOOL +ar5416ChainTxDesc(struct ath_hal *ah, struct ath_desc *ds, + u_int pktLen, + u_int hdrLen, + HAL_PKT_TYPE type, + u_int keyIx, + HAL_CIPHER cipher, + uint8_t delims, + u_int segLen, + HAL_BOOL firstSeg, + HAL_BOOL lastSeg) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + uint32_t *ds_txstatus = AR5416_DS_TXSTATUS(ah,ads); + + int isaggr = 0; + + (void) hdrLen; + (void) ah; + + HALASSERT((segLen &~ AR_BufLen) == 0); + + HALASSERT(isValidPktType(type)); + if (type == HAL_PKT_TYPE_AMPDU) { + type = HAL_PKT_TYPE_NORMAL; + isaggr = 1; + } + + if (!firstSeg) { + ath_hal_memzero(ds->ds_hw, AR5416_DESC_TX_CTL_SZ); + } + + ads->ds_ctl0 = (pktLen & AR_FrameLen); + ads->ds_ctl1 = (type << AR_FrameType_S) + | (isaggr ? (AR_IsAggr | AR_MoreAggr) : 0); + ads->ds_ctl2 = 0; + ads->ds_ctl3 = 0; + if (keyIx != HAL_TXKEYIX_INVALID) { + /* XXX validate key index */ + ads->ds_ctl1 |= SM(keyIx, AR_DestIdx); + ads->ds_ctl0 |= AR_DestIdxValid; + } + + ads->ds_ctl6 = SM(keyType[cipher], AR_EncrType); + if (isaggr) { + ads->ds_ctl6 |= SM(delims, AR_PadDelim); + } + + if (firstSeg) { + ads->ds_ctl1 |= segLen | (lastSeg ? 0 : AR_TxMore); + } else if (lastSeg) { /* !firstSeg && lastSeg */ + ads->ds_ctl0 = 0; + ads->ds_ctl1 |= segLen; + } else { /* !firstSeg && !lastSeg */ + /* + * Intermediate descriptor in a multi-descriptor frame. + */ + ads->ds_ctl0 = 0; + ads->ds_ctl1 |= segLen | AR_TxMore; + } + ds_txstatus[0] = ds_txstatus[1] = 0; + ds_txstatus[9] &= ~AR_TxDone; + + return AH_TRUE; +} + +HAL_BOOL +ar5416SetupFirstTxDesc(struct ath_hal *ah, struct ath_desc *ds, + u_int aggrLen, u_int flags, u_int txPower, + u_int txRate0, u_int txTries0, u_int antMode, + u_int rtsctsRate, u_int rtsctsDuration) +{ +#define RTSCTS (HAL_TXDESC_RTSENA|HAL_TXDESC_CTSENA) + struct ar5416_desc *ads = AR5416DESC(ds); + struct ath_hal_5212 *ahp = AH5212(ah); + + HALASSERT(txTries0 != 0); + HALASSERT(isValidTxRate(txRate0)); + HALASSERT((flags & RTSCTS) != RTSCTS); + /* XXX validate antMode */ + + txPower = (txPower + ahp->ah_txPowerIndexOffset ); + if(txPower > 63) txPower=63; + + ads->ds_ctl0 |= (txPower << AR_XmitPower_S) + | (flags & HAL_TXDESC_VEOL ? AR_VEOL : 0) + | (flags & HAL_TXDESC_CLRDMASK ? AR_ClrDestMask : 0) + | (flags & HAL_TXDESC_INTREQ ? AR_TxIntrReq : 0); + ads->ds_ctl1 |= (flags & HAL_TXDESC_NOACK ? AR_NoAck : 0); + ads->ds_ctl2 |= SM(txTries0, AR_XmitDataTries0); + ads->ds_ctl3 |= (txRate0 << AR_XmitRate0_S); + ads->ds_ctl7 = SM(AH5416(ah)->ah_tx_chainmask, AR_ChainSel0) + | SM(AH5416(ah)->ah_tx_chainmask, AR_ChainSel1) + | SM(AH5416(ah)->ah_tx_chainmask, AR_ChainSel2) + | SM(AH5416(ah)->ah_tx_chainmask, AR_ChainSel3); + + /* NB: no V1 WAR */ + ads->ds_ctl8 = 0; + ads->ds_ctl9 = (txPower << 24); + ads->ds_ctl10 = (txPower << 24); + ads->ds_ctl11 = (txPower << 24); + + ads->ds_ctl6 &= ~(0xffff); + ads->ds_ctl6 |= SM(aggrLen, AR_AggrLen); + + if (flags & RTSCTS) { + /* XXX validate rtsctsDuration */ + ads->ds_ctl0 |= (flags & HAL_TXDESC_CTSENA ? AR_CTSEnable : 0) + | (flags & HAL_TXDESC_RTSENA ? AR_RTSEnable : 0); + ads->ds_ctl2 |= SM(rtsctsDuration, AR_BurstDur); + } + + return AH_TRUE; +#undef RTSCTS +} + +HAL_BOOL +ar5416SetupLastTxDesc(struct ath_hal *ah, struct ath_desc *ds, + const struct ath_desc *ds0) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + + ads->ds_ctl1 &= ~AR_MoreAggr; + ads->ds_ctl6 &= ~AR_PadDelim; + + /* hack to copy rate info to last desc for later processing */ +#ifdef AH_NEED_DESC_SWAP + ads->ds_ctl2 = __bswap32(AR5416DESC_CONST(ds0)->ds_ctl2); + ads->ds_ctl3 = __bswap32(AR5416DESC_CONST(ds0)->ds_ctl3); +#else + ads->ds_ctl2 = AR5416DESC_CONST(ds0)->ds_ctl2; + ads->ds_ctl3 = AR5416DESC_CONST(ds0)->ds_ctl3; +#endif + + return AH_TRUE; +} +#endif /* 0 */ + +#ifdef AH_NEED_DESC_SWAP +/* Swap transmit descriptor */ +static __inline void +ar5416SwapTxDesc(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 +ar5416ProcTxDesc(struct ath_hal *ah, + struct ath_desc *ds, struct ath_tx_status *ts) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + uint32_t *ds_txstatus = AR5416_DS_TXSTATUS(ah,ads); + +#ifdef AH_NEED_DESC_SWAP + if ((ds_txstatus[9] & __bswap32(AR_TxDone)) == 0) + return HAL_EINPROGRESS; + ar5416SwapTxDesc(ds); +#else + if ((ds_txstatus[9] & AR_TxDone) == 0) + return HAL_EINPROGRESS; +#endif + + /* Update software copies of the HW status */ + ts->ts_seqnum = MS(ds_txstatus[9], AR_SeqNum); + ts->ts_tstamp = AR_SendTimestamp(ds_txstatus); + + ts->ts_status = 0; + if (ds_txstatus[1] & AR_ExcessiveRetries) + ts->ts_status |= HAL_TXERR_XRETRY; + if (ds_txstatus[1] & AR_Filtered) + ts->ts_status |= HAL_TXERR_FILT; + if (ds_txstatus[1] & AR_FIFOUnderrun) + ts->ts_status |= HAL_TXERR_FIFO; + if (ds_txstatus[9] & AR_TxOpExceeded) + ts->ts_status |= HAL_TXERR_XTXOP; + if (ds_txstatus[1] & AR_TxTimerExpired) + ts->ts_status |= HAL_TXERR_TIMER_EXPIRED; + + ts->ts_flags = 0; + if (ds_txstatus[0] & AR_TxBaStatus) { + ts->ts_flags |= HAL_TX_BA; + ts->ts_ba_low = AR_BaBitmapLow(ds_txstatus); + ts->ts_ba_high = AR_BaBitmapHigh(ds_txstatus); + } + if (ds->ds_ctl1 & AR_IsAggr) + ts->ts_flags |= HAL_TX_AGGR; + if (ds_txstatus[1] & AR_DescCfgErr) + ts->ts_flags |= HAL_TX_DESC_CFG_ERR; + if (ds_txstatus[1] & AR_TxDataUnderrun) + ts->ts_flags |= HAL_TX_DATA_UNDERRUN; + if (ds_txstatus[1] & AR_TxDelimUnderrun) + ts->ts_flags |= HAL_TX_DELIM_UNDERRUN; + + /* + * Extract the transmit rate used and mark the rate as + * ``alternate'' if it wasn't the series 0 rate. + */ + ts->ts_finaltsi = MS(ds_txstatus[9], AR_FinalTxIdx); + 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(ds_txstatus[5], AR_TxRSSICombined); + ts->ts_rssi_ctl[0] = MS(ds_txstatus[0], AR_TxRSSIAnt00); + ts->ts_rssi_ctl[1] = MS(ds_txstatus[0], AR_TxRSSIAnt01); + ts->ts_rssi_ctl[2] = MS(ds_txstatus[0], AR_TxRSSIAnt02); + ts->ts_rssi_ext[0] = MS(ds_txstatus[5], AR_TxRSSIAnt10); + ts->ts_rssi_ext[1] = MS(ds_txstatus[5], AR_TxRSSIAnt11); + ts->ts_rssi_ext[2] = MS(ds_txstatus[5], AR_TxRSSIAnt12); + ts->ts_evm0 = AR_TxEVM0(ds_txstatus); + ts->ts_evm1 = AR_TxEVM1(ds_txstatus); + ts->ts_evm2 = AR_TxEVM2(ds_txstatus); + + ts->ts_shortretry = MS(ds_txstatus[1], AR_RTSFailCnt); + ts->ts_longretry = MS(ds_txstatus[1], 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); + } + + /* + * These fields are not used. Zero these to preserve compatability + * with existing drivers. + */ + ts->ts_virtcol = MS(ads->ds_ctl1, AR_VirtRetryCnt); + ts->ts_antenna = 0; /* We don't switch antennas on Owl*/ + + /* handle tx trigger level changes internally */ + if ((ts->ts_status & HAL_TXERR_FIFO) || + (ts->ts_flags & (HAL_TX_DATA_UNDERRUN | HAL_TX_DELIM_UNDERRUN))) + ar5212UpdateTxTrigLevel(ah, AH_TRUE); + + return HAL_OK; +} + +#if 0 +HAL_BOOL +ar5416SetGlobalTxTimeout(struct ath_hal *ah, u_int tu) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + + if (tu > 0xFFFF) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad global tx timeout %u\n", + __func__, tu); + /* restore default handling */ + ahp->ah_globaltxtimeout = (u_int) -1; + return AH_FALSE; + } + OS_REG_RMW_FIELD(ah, AR_GTXTO, AR_GTXTO_TIMEOUT_LIMIT, tu); + ahp->ah_globaltxtimeout = tu; + return AH_TRUE; +} + +u_int +ar5416GetGlobalTxTimeout(struct ath_hal *ah) +{ + return MS(OS_REG_READ(ah, AR_GTXTO), AR_GTXTO_TIMEOUT_LIMIT); +} + +void +ar5416Set11nRateScenario(struct ath_hal *ah, struct ath_desc *ds, + u_int durUpdateEn, u_int rtsctsRate, + HAL_11N_RATE_SERIES series[], u_int nseries) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + + HALASSERT(nseries == 4); + (void)nseries; + + + ads->ds_ctl2 = set11nTries(series, 0) + | set11nTries(series, 1) + | set11nTries(series, 2) + | set11nTries(series, 3) + | (durUpdateEn ? AR_DurUpdateEn : 0); + + ads->ds_ctl3 = set11nRate(series, 0) + | set11nRate(series, 1) + | set11nRate(series, 2) + | set11nRate(series, 3); + + ads->ds_ctl4 = set11nPktDurRTSCTS(series, 0) + | set11nPktDurRTSCTS(series, 1); + + ads->ds_ctl5 = set11nPktDurRTSCTS(series, 2) + | set11nPktDurRTSCTS(series, 3); + + ads->ds_ctl7 = set11nRateFlags(series, 0) + | set11nRateFlags(series, 1) + | set11nRateFlags(series, 2) + | set11nRateFlags(series, 3) + | SM(rtsctsRate, AR_RTSCTSRate); + + /* + * Enable RTSCTS if any of the series is flagged for RTSCTS, + * but only if CTS is not enabled. + */ + /* + * FIXME : the entire RTS/CTS handling should be moved to this + * function (by passing the global RTS/CTS flags to this function). + * currently it is split between this function and the + * setupFiirstDescriptor. with this current implementation there + * is an implicit assumption that setupFirstDescriptor is called + * before this function. + */ + if (((series[0].RateFlags & HAL_RATESERIES_RTS_CTS) || + (series[1].RateFlags & HAL_RATESERIES_RTS_CTS) || + (series[2].RateFlags & HAL_RATESERIES_RTS_CTS) || + (series[3].RateFlags & HAL_RATESERIES_RTS_CTS) ) && + (ads->ds_ctl0 & AR_CTSEnable) == 0) { + ads->ds_ctl0 |= AR_RTSEnable; + ads->ds_ctl0 &= ~AR_CTSEnable; + } +} + +void +ar5416Set11nAggrMiddle(struct ath_hal *ah, struct ath_desc *ds, u_int numDelims) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + uint32_t *ds_txstatus = AR5416_DS_TXSTATUS(ah,ads); + + ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr); + + ads->ds_ctl6 &= ~AR_PadDelim; + ads->ds_ctl6 |= SM(numDelims, AR_PadDelim); + ads->ds_ctl6 &= ~AR_AggrLen; + + /* + * Clear the TxDone status here, may need to change + * func name to reflect this + */ + ds_txstatus[9] &= ~AR_TxDone; +} + +void +ar5416Clr11nAggr(struct ath_hal *ah, struct ath_desc *ds) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + + ads->ds_ctl1 &= (~AR_IsAggr & ~AR_MoreAggr); + ads->ds_ctl6 &= ~AR_PadDelim; + ads->ds_ctl6 &= ~AR_AggrLen; +} + +void +ar5416Set11nBurstDuration(struct ath_hal *ah, struct ath_desc *ds, + u_int burstDuration) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + + ads->ds_ctl2 &= ~AR_BurstDur; + ads->ds_ctl2 |= SM(burstDuration, AR_BurstDur); +} +#endif --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5416/ar5416desc.h 2009-05-15 11:11:29.000000000 +0100 @@ -0,0 +1,397 @@ +/* + * 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: ar5416desc.h,v 1.1 2009/03/23 17:14:48 sborrill Exp $ + */ +#ifndef _ATH_AR5416_DESC_H_ +#define _ATH_AR5416_DESC_H + +/* + * Hardware-specific descriptor structures. + */ +#include "ah_desc.h" + +/* XXX Need to replace this with a dynamic + * method of determining Owl2 if possible + */ +#define _get_index(_ah) ( IS_5416V1(_ah) ? -4 : 0 ) +#define AR5416_DS_TXSTATUS(_ah, _ads) \ + ((uint32_t*)(&(_ads)->u.tx.status[_get_index(_ah)])) +#define AR5416_DS_TXSTATUS_CONST(_ah, _ads) \ + ((const uint32_t*)(&(_ads)->u.tx.status[_get_index(_ah)])) + +#define AR5416_NUM_TX_STATUS 10 /* Number of TX status words */ +/* Clear the whole descriptor */ +#define AR5416_DESC_TX_CTL_SZ sizeof(struct ar5416_tx_desc) + +struct ar5416_tx_desc { /* tx desc has 12 control words + 10 status words */ + uint32_t ctl2; + uint32_t ctl3; + uint32_t ctl4; + uint32_t ctl5; + uint32_t ctl6; + uint32_t ctl7; + uint32_t ctl8; + uint32_t ctl9; + uint32_t ctl10; + uint32_t ctl11; + uint32_t status[AR5416_NUM_TX_STATUS]; +}; + +struct ar5416_rx_desc { /* rx desc has 2 control words + 9 status words */ + uint32_t status0; + uint32_t status1; + uint32_t status2; + uint32_t status3; + uint32_t status4; + uint32_t status5; + uint32_t status6; + uint32_t status7; + uint32_t status8; +}; + + +struct ar5416_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 ar5416_tx_desc tx; + struct ar5416_rx_desc rx; + } u; +} __packed; +#define AR5416DESC(_ds) ((struct ar5416_desc *)(_ds)) +#define AR5416DESC_CONST(_ds) ((const struct ar5416_desc *)(_ds)) + +#define ds_ctl2 u.tx.ctl2 +#define ds_ctl3 u.tx.ctl3 +#define ds_ctl4 u.tx.ctl4 +#define ds_ctl5 u.tx.ctl5 +#define ds_ctl6 u.tx.ctl6 +#define ds_ctl7 u.tx.ctl7 +#define ds_ctl8 u.tx.ctl8 +#define ds_ctl9 u.tx.ctl9 +#define ds_ctl10 u.tx.ctl10 +#define ds_ctl11 u.tx.ctl11 + +#define ds_rxstatus0 u.rx.status0 +#define ds_rxstatus1 u.rx.status1 +#define ds_rxstatus2 u.rx.status2 +#define ds_rxstatus3 u.rx.status3 +#define ds_rxstatus4 u.rx.status4 +#define ds_rxstatus5 u.rx.status5 +#define ds_rxstatus6 u.rx.status6 +#define ds_rxstatus7 u.rx.status7 +#define ds_rxstatus8 u.rx.status8 + +/*********** + * TX Desc * + ***********/ + +/* ds_ctl0 */ +#define AR_FrameLen 0x00000fff +#define AR_VirtMoreFrag 0x00001000 +#define AR_TxCtlRsvd00 0x0000e000 +#define AR_XmitPower 0x003f0000 +#define AR_XmitPower_S 16 +#define AR_RTSEnable 0x00400000 +#define AR_VEOL 0x00800000 +#define AR_ClrDestMask 0x01000000 +#define AR_TxCtlRsvd01 0x1e000000 +#define AR_TxIntrReq 0x20000000 +#define AR_DestIdxValid 0x40000000 +#define AR_CTSEnable 0x80000000 + +/* ds_ctl1 */ +#define AR_BufLen 0x00000fff +#define AR_TxMore 0x00001000 +#define AR_DestIdx 0x000fe000 +#define AR_DestIdx_S 13 +#define AR_FrameType 0x00f00000 +#define AR_FrameType_S 20 +#define AR_NoAck 0x01000000 +#define AR_InsertTS 0x02000000 +#define AR_CorruptFCS 0x04000000 +#define AR_ExtOnly 0x08000000 +#define AR_ExtAndCtl 0x10000000 +#define AR_MoreAggr 0x20000000 +#define AR_IsAggr 0x40000000 +#define AR_MoreRifs 0x80000000 + +/* ds_ctl2 */ +#define AR_BurstDur 0x00007fff +#define AR_BurstDur_S 0 +#define AR_DurUpdateEn 0x00008000 +#define AR_XmitDataTries0 0x000f0000 +#define AR_XmitDataTries0_S 16 +#define AR_XmitDataTries1 0x00f00000 +#define AR_XmitDataTries1_S 20 +#define AR_XmitDataTries2 0x0f000000 +#define AR_XmitDataTries2_S 24 +#define AR_XmitDataTries3 0xf0000000 +#define AR_XmitDataTries3_S 28 + +/* ds_ctl3 */ +#define AR_XmitRate0 0x000000ff +#define AR_XmitRate0_S 0 +#define AR_XmitRate1 0x0000ff00 +#define AR_XmitRate1_S 8 +#define AR_XmitRate2 0x00ff0000 +#define AR_XmitRate2_S 16 +#define AR_XmitRate3 0xff000000 +#define AR_XmitRate3_S 24 + +/* ds_ctl4 */ +#define AR_PacketDur0 0x00007fff +#define AR_PacketDur0_S 0 +#define AR_RTSCTSQual0 0x00008000 +#define AR_PacketDur1 0x7fff0000 +#define AR_PacketDur1_S 16 +#define AR_RTSCTSQual1 0x80000000 + +/* ds_ctl5 */ +#define AR_PacketDur2 0x00007fff +#define AR_PacketDur2_S 0 +#define AR_RTSCTSQual2 0x00008000 +#define AR_PacketDur3 0x7fff0000 +#define AR_PacketDur3_S 16 +#define AR_RTSCTSQual3 0x80000000 + +/* ds_ctl6 */ +#define AR_AggrLen 0x0000ffff +#define AR_AggrLen_S 0 +#define AR_TxCtlRsvd60 0x00030000 +#define AR_PadDelim 0x03fc0000 +#define AR_PadDelim_S 18 +#define AR_EncrType 0x0c000000 +#define AR_EncrType_S 26 +#define AR_TxCtlRsvd61 0xf0000000 + +/* ds_ctl7 */ +#define AR_2040_0 0x00000001 +#define AR_GI0 0x00000002 +#define AR_ChainSel0 0x0000001c +#define AR_ChainSel0_S 2 +#define AR_2040_1 0x00000020 +#define AR_GI1 0x00000040 +#define AR_ChainSel1 0x00000380 +#define AR_ChainSel1_S 7 +#define AR_2040_2 0x00000400 +#define AR_GI2 0x00000800 +#define AR_ChainSel2 0x00007000 +#define AR_ChainSel2_S 12 +#define AR_2040_3 0x00008000 +#define AR_GI3 0x00010000 +#define AR_ChainSel3 0x000e0000 +#define AR_ChainSel3_S 17 +#define AR_RTSCTSRate 0x0ff00000 +#define AR_RTSCTSRate_S 20 +#define AR_STBC0 0x10000000 +#define AR_STBC1 0x20000000 +#define AR_STBC2 0x40000000 +#define AR_STBC3 0x80000000 + +/************* + * TX Status * + *************/ + +/* ds_status0 */ +#define AR_TxRSSIAnt00 0x000000ff +#define AR_TxRSSIAnt00_S 0 +#define AR_TxRSSIAnt01 0x0000ff00 +#define AR_TxRSSIAnt01_S 8 +#define AR_TxRSSIAnt02 0x00ff0000 +#define AR_TxRSSIAnt02_S 16 +#define AR_TxStatusRsvd00 0x3f000000 +#define AR_TxBaStatus 0x40000000 +#define AR_TxStatusRsvd01 0x80000000 + +/* ds_status1 */ +#define AR_FrmXmitOK 0x00000001 +#define AR_ExcessiveRetries 0x00000002 +#define AR_FIFOUnderrun 0x00000004 +#define AR_Filtered 0x00000008 +#define AR_RTSFailCnt 0x000000f0 +#define AR_RTSFailCnt_S 4 +#define AR_DataFailCnt 0x00000f00 +#define AR_DataFailCnt_S 8 +#define AR_VirtRetryCnt 0x0000f000 +#define AR_VirtRetryCnt_S 12 +#define AR_TxDelimUnderrun 0x00010000 +#define AR_TxDelimUnderrun_S 13 +#define AR_TxDataUnderrun 0x00020000 +#define AR_TxDataUnderrun_S 14 +#define AR_DescCfgErr 0x00040000 +#define AR_DescCfgErr_S 15 +#define AR_TxTimerExpired 0x00080000 +#define AR_TxStatusRsvd10 0xfff00000 + +/* ds_status2 */ +#define AR_SendTimestamp(_ptr) (_ptr)[2] + +/* ds_status3 */ +#define AR_BaBitmapLow(_ptr) (_ptr)[3] + +/* ds_status4 */ +#define AR_BaBitmapHigh(_ptr) (_ptr)[4] + +/* ds_status5 */ +#define AR_TxRSSIAnt10 0x000000ff +#define AR_TxRSSIAnt10_S 0 +#define AR_TxRSSIAnt11 0x0000ff00 +#define AR_TxRSSIAnt11_S 8 +#define AR_TxRSSIAnt12 0x00ff0000 +#define AR_TxRSSIAnt12_S 16 +#define AR_TxRSSICombined 0xff000000 +#define AR_TxRSSICombined_S 24 + +/* ds_status6 */ +#define AR_TxEVM0(_ptr) (_ptr)[6] + +/* ds_status7 */ +#define AR_TxEVM1(_ptr) (_ptr)[7] + +/* ds_status8 */ +#define AR_TxEVM2(_ptr) (_ptr)[8] + +/* ds_status9 */ +#define AR_TxDone 0x00000001 +#define AR_SeqNum 0x00001ffe +#define AR_SeqNum_S 1 +#define AR_TxStatusRsvd80 0x0001e000 +#define AR_TxOpExceeded 0x00020000 +#define AR_TxStatusRsvd81 0x001c0000 +#define AR_FinalTxIdx 0x00600000 +#define AR_FinalTxIdx_S 21 +#define AR_TxStatusRsvd82 0x01800000 +#define AR_PowerMgmt 0x02000000 +#define AR_TxStatusRsvd83 0xfc000000 + +/*********** + * RX Desc * + ***********/ + +/* ds_ctl0 */ +#define AR_RxCTLRsvd00 0xffffffff + +/* ds_ctl1 */ +#define AR_BufLen 0x00000fff +#define AR_RxCtlRsvd00 0x00001000 +#define AR_RxIntrReq 0x00002000 +#define AR_RxCtlRsvd01 0xffffc000 + +/************* + * Rx Status * + *************/ + +/* ds_status0 */ +#define AR_RxRSSIAnt00 0x000000ff +#define AR_RxRSSIAnt00_S 0 +#define AR_RxRSSIAnt01 0x0000ff00 +#define AR_RxRSSIAnt01_S 8 +#define AR_RxRSSIAnt02 0x00ff0000 +#define AR_RxRSSIAnt02_S 16 +/* Rev specific */ +/* Owl 1.x only */ +#define AR_RxStatusRsvd00 0xff000000 +/* Owl 2.x only */ +#define AR_RxRate 0xff000000 +#define AR_RxRate_S 24 + +/* ds_status1 */ +#define AR_DataLen 0x00000fff +#define AR_RxMore 0x00001000 +#define AR_NumDelim 0x003fc000 +#define AR_NumDelim_S 14 +#define AR_RxStatusRsvd10 0xff800000 + +/* ds_status2 */ +#define AR_RcvTimestamp ds_rxstatus2 + +/* ds_status3 */ +#define AR_GI 0x00000001 +#define AR_2040 0x00000002 +/* Rev specific */ +/* Owl 1.x only */ +#define AR_RxRateV1 0x000003fc +#define AR_RxRateV1_S 2 +#define AR_Parallel40 0x00000400 +#define AR_RxStatusRsvd30 0xfffff800 +/* Owl 2.x only */ +#define AR_DupFrame 0x00000004 +#define AR_RxAntenna 0xffffff00 +#define AR_RxAntenna_S 8 + +/* ds_status4 */ +#define AR_RxRSSIAnt10 0x000000ff +#define AR_RxRSSIAnt10_S 0 +#define AR_RxRSSIAnt11 0x0000ff00 +#define AR_RxRSSIAnt11_S 8 +#define AR_RxRSSIAnt12 0x00ff0000 +#define AR_RxRSSIAnt12_S 16 +#define AR_RxRSSICombined 0xff000000 +#define AR_RxRSSICombined_S 24 + +/* ds_status5 */ +#define AR_RxEVM0 ds_rxstatus5 + +/* ds_status6 */ +#define AR_RxEVM1 ds_rxstatus6 + +/* ds_status7 */ +#define AR_RxEVM2 ds_rxstatus7 + +/* ds_status8 */ +#define AR_RxDone 0x00000001 +#define AR_RxFrameOK 0x00000002 +#define AR_CRCErr 0x00000004 +#define AR_DecryptCRCErr 0x00000008 +#define AR_PHYErr 0x00000010 +#define AR_MichaelErr 0x00000020 +#define AR_PreDelimCRCErr 0x00000040 +#define AR_RxStatusRsvd70 0x00000080 +#define AR_RxKeyIdxValid 0x00000100 +#define AR_KeyIdx 0x0000fe00 +#define AR_KeyIdx_S 9 +#define AR_PHYErrCode 0x0000ff00 +#define AR_PHYErrCode_S 8 +#define AR_RxMoreAggr 0x00010000 +#define AR_RxAggr 0x00020000 +#define AR_PostDelimCRCErr 0x00040000 +#define AR_RxStatusRsvd71 0x2ff80000 +#define AR_HiRxChain 0x10000000 +#define AR_DecryptBusyErr 0x40000000 +#define AR_KeyMiss 0x80000000 + +#define TXCTL_OFFSET(ah) 2 +#define TXCTL_NUMWORDS(ah) (AR_SREV_5416_V20_OR_LATER(ah) ? 12 : 8) +#define TXSTATUS_OFFSET(ah) (AR_SREV_5416_V20_OR_LATER(ah) ? 14 : 10) +#define TXSTATUS_NUMWORDS(ah) 10 + +#define RXCTL_OFFSET(ah) 3 +#define RXCTL_NUMWORDS(ah) 1 +#define RXSTATUS_OFFSET(ah) 4 +#define RXSTATUS_NUMWORDS(ah) 9 +#define RXSTATUS_RATE(ah, ads) \ + (AR_SREV_OWL_20_OR_LATER(ah) ? \ + MS((ads)->ds_rxstatus0, AR_RxRate) : \ + ((ads)->ds_rxstatus3 >> 2) & 0xFF) +#define RXSTATUS_DUPLICATE(ah, ads) \ + (AR_SREV_OWL_20_OR_LATER(ah) ? \ + MS((ads)->ds_rxstatus3, AR_Parallel40) : \ + ((ads)->ds_rxstatus3 >> 10) & 0x1) +#endif /* _ATH_AR5416_DESC_H_ */ --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5416/ar5416phy.h 2009-05-15 11:11:29.000000000 +0100 @@ -0,0 +1,250 @@ +/* + * 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: ar5416phy.h,v 1.1 2009/03/23 17:14:48 sborrill Exp $ + */ +#ifndef _DEV_ATH_AR5416PHY_H_ +#define _DEV_ATH_AR5416PHY_H_ + +#include "ar5212/ar5212phy.h" + +#define AR_PHY_CHIP_ID_REV_0 0x80 /* 5416 Rev 0 (owl 1.0) BB */ +#define AR_PHY_CHIP_ID_REV_1 0x81 /* 5416 Rev 1 (owl 2.0) BB */ + +#define RFSILENT_BB 0x00002000 /* shush bb */ +#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 + +/* PLL settling times */ +#define RTC_PLL_SETTLE_DELAY 1000 /* 1 ms */ +#define HT40_CHANNEL_CENTER_SHIFT 10 /* MHz */ + +#define AR_PHY_RFBUS_REQ 0x997C +#define AR_PHY_RFBUS_REQ_EN 0x00000001 + +#define AR_2040_MODE 0x8318 +#define AR_2040_JOINED_RX_CLEAR 0x00000001 // use ctl + ext rx_clear for cca + +#define AR_PHY_FC_TURBO_SHORT 0x00000002 /* Set short symbols to turbo mode setting */ +#define AR_PHY_FC_DYN2040_EN 0x00000004 /* Enable dyn 20/40 mode */ +#define AR_PHY_FC_DYN2040_PRI_ONLY 0x00000008 /* dyn 20/40 - primary only */ +#define AR_PHY_FC_DYN2040_PRI_CH 0x00000010 /* dyn 20/40 - primary ch offset (0=+10MHz, 1=-10MHz)*/ +#define AR_PHY_FC_DYN2040_EXT_CH 0x00000020 /* dyn 20/40 - ext ch spacing (0=20MHz/ 1=25MHz) */ +#define AR_PHY_FC_HT_EN 0x00000040 /* ht enable */ +#define AR_PHY_FC_SHORT_GI_40 0x00000080 /* allow short GI for HT 40 */ +#define AR_PHY_FC_WALSH 0x00000100 /* walsh spatial spreading for 2 chains,2 streams TX */ +#define AR_PHY_FC_SINGLE_HT_LTF1 0x00000200 /* single length (4us) 1st HT long training symbol */ + +#define AR_PHY_TIMING2 0x9810 /* Timing Control 2 */ +#define AR_PHY_TIMING2_USE_FORCE 0x00001000 +#define AR_PHY_TIMING2_FORCE_VAL 0x00000fff + +#define AR_PHY_TIMING_CTRL4_CHAIN(_i) \ + (AR_PHY_TIMING_CTRL4 + ((_i) << 12)) +#define AR_PHY_TIMING_CTRL4_DO_CAL 0x10000 /* perform calibration */ +#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_ENABLE_SPUR_RSSI 0x80000000 +#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_ADC_SERIAL_CTL 0x9830 +#define AR_PHY_SEL_INTERNAL_ADDAC 0x00000000 +#define AR_PHY_SEL_EXTERNAL_RADIO 0x00000001 + +#define AR_PHY_GAIN_2GHZ_BSW_MARGIN 0x00003C00 +#define AR_PHY_GAIN_2GHZ_BSW_MARGIN_S 10 +#define AR_PHY_GAIN_2GHZ_BSW_ATTEN 0x0000001F +#define AR_PHY_GAIN_2GHZ_BSW_ATTEN_S 0 + +#define AR_PHY_EXT_CCA 0x99bc +#define AR_PHY_EXT_CCA_CYCPWR_THR1 0x0000FE00 +#define AR_PHY_EXT_CCA_CYCPWR_THR1_S 9 +#define AR_PHY_EXT_MINCCA_PWR 0xFF800000 +#define AR_PHY_EXT_MINCCA_PWR_S 23 +#define AR_PHY_EXT_CCA_THRESH62 0x007F0000 +#define AR_PHY_EXT_CCA_THRESH62_S 16 +#define AR9280_PHY_EXT_MINCCA_PWR 0x01FF0000 +#define AR9280_PHY_EXT_MINCCA_PWR_S 16 + +#define AR_PHY_HALFGI 0x99D0 /* Timing control 3 */ +#define AR_PHY_HALFGI_DSC_MAN 0x0007FFF0 +#define AR_PHY_HALFGI_DSC_MAN_S 4 +#define AR_PHY_HALFGI_DSC_EXP 0x0000000F +#define AR_PHY_HALFGI_DSC_EXP_S 0 + +#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 + +#define AR_PHY_CALMODE 0x99f0 +/* Calibration Types */ +#define AR_PHY_CALMODE_IQ 0x00000000 +#define AR_PHY_CALMODE_ADC_GAIN 0x00000001 +#define AR_PHY_CALMODE_ADC_DC_PER 0x00000002 +#define AR_PHY_CALMODE_ADC_DC_INIT 0x00000003 +/* Calibration results */ +#define AR_PHY_CAL_MEAS_0(_i) (0x9c10 + ((_i) << 12)) +#define AR_PHY_CAL_MEAS_1(_i) (0x9c14 + ((_i) << 12)) +#define AR_PHY_CAL_MEAS_2(_i) (0x9c18 + ((_i) << 12)) +#define AR_PHY_CAL_MEAS_3(_i) (0x9c1c + ((_i) << 12)) + + +#define AR_PHY_CCA 0x9864 +#define AR_PHY_MINCCA_PWR 0x0FF80000 +#define AR_PHY_MINCCA_PWR_S 19 +#define AR9280_PHY_MINCCA_PWR 0x1FF00000 +#define AR9280_PHY_MINCCA_PWR_S 20 +#define AR9280_PHY_CCA_THRESH62 0x000FF000 +#define AR9280_PHY_CCA_THRESH62_S 12 + +#define AR_PHY_CH1_CCA 0xa864 +#define AR_PHY_CH1_MINCCA_PWR 0x0FF80000 +#define AR_PHY_CH1_MINCCA_PWR_S 19 +#define AR_PHY_CCA_THRESH62 0x0007F000 +#define AR_PHY_CCA_THRESH62_S 12 +#define AR9280_PHY_CH1_MINCCA_PWR 0x1FF00000 +#define AR9280_PHY_CH1_MINCCA_PWR_S 20 + +#define AR_PHY_CH2_CCA 0xb864 +#define AR_PHY_CH2_MINCCA_PWR 0x0FF80000 +#define AR_PHY_CH2_MINCCA_PWR_S 19 + +#define AR_PHY_CH1_EXT_CCA 0xa9bc +#define AR_PHY_CH1_EXT_MINCCA_PWR 0xFF800000 +#define AR_PHY_CH1_EXT_MINCCA_PWR_S 23 +#define AR9280_PHY_CH1_EXT_MINCCA_PWR 0x01FF0000 +#define AR9280_PHY_CH1_EXT_MINCCA_PWR_S 16 + +#define AR_PHY_CH2_EXT_CCA 0xb9bc +#define AR_PHY_CH2_EXT_MINCCA_PWR 0xFF800000 +#define AR_PHY_CH2_EXT_MINCCA_PWR_S 23 + +#define AR_PHY_RX_CHAINMASK 0x99a4 + +#define AR_PHY_NEW_ADC_DC_GAIN_CORR(_i) (0x99b4 + ((_i) << 12)) +#define AR_PHY_NEW_ADC_GAIN_CORR_ENABLE 0x40000000 +#define AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE 0x80000000 +#define AR_PHY_MULTICHAIN_GAIN_CTL 0x99ac + +#define AR_PHY_EXT_CCA0 0x99b8 +#define AR_PHY_EXT_CCA0_THRESH62 0x000000FF +#define AR_PHY_EXT_CCA0_THRESH62_S 0 + +#define AR_PHY_CH1_EXT_CCA 0xa9bc +#define AR_PHY_CH1_EXT_MINCCA_PWR 0xFF800000 +#define AR_PHY_CH1_EXT_MINCCA_PWR_S 23 + +#define AR_PHY_CH2_EXT_CCA 0xb9bc +#define AR_PHY_CH2_EXT_MINCCA_PWR 0xFF800000 +#define AR_PHY_CH2_EXT_MINCCA_PWR_S 23 +#define AR_PHY_ANALOG_SWAP 0xa268 +#define AR_PHY_SWAP_ALT_CHAIN 0x00000040 +#define AR_PHY_CAL_CHAINMASK 0xa39c + +#define AR_PHY_SWITCH_CHAIN_0 0x9960 +#define AR_PHY_SWITCH_COM 0x9964 + +#define AR_PHY_RF_CTL2 0x9824 +#define AR_PHY_TX_FRAME_TO_DATA_START 0x000000FF +#define AR_PHY_TX_FRAME_TO_DATA_START_S 0 +#define AR_PHY_TX_FRAME_TO_PA_ON 0x0000FF00 +#define AR_PHY_TX_FRAME_TO_PA_ON_S 8 + +#define AR_PHY_RF_CTL3 0x9828 +#define AR_PHY_TX_END_TO_A2_RX_ON 0x00FF0000 +#define AR_PHY_TX_END_TO_A2_RX_ON_S 16 + +#define AR_PHY_RF_CTL4 0x9834 +#define AR_PHY_RF_CTL4_TX_END_XPAB_OFF 0xFF000000 +#define AR_PHY_RF_CTL4_TX_END_XPAB_OFF_S 24 +#define AR_PHY_RF_CTL4_TX_END_XPAA_OFF 0x00FF0000 +#define AR_PHY_RF_CTL4_TX_END_XPAA_OFF_S 16 +#define AR_PHY_RF_CTL4_FRAME_XPAB_ON 0x0000FF00 +#define AR_PHY_RF_CTL4_FRAME_XPAB_ON_S 8 +#define AR_PHY_RF_CTL4_FRAME_XPAA_ON 0x000000FF +#define AR_PHY_RF_CTL4_FRAME_XPAA_ON_S 0 + +#define AR_PHY_SYNTH_CONTROL 0x9874 + +#define AR_PHY_FORCE_CLKEN_CCK 0xA22C +#define AR_PHY_FORCE_CLKEN_CCK_MRC_MUX 0x00000040 + +#define AR_PHY_POWER_TX_SUB 0xA3C8 +#define AR_PHY_POWER_TX_RATE5 0xA38C +#define AR_PHY_POWER_TX_RATE6 0xA390 +#define AR_PHY_POWER_TX_RATE7 0xA3CC +#define AR_PHY_POWER_TX_RATE8 0xA3D0 +#define AR_PHY_POWER_TX_RATE9 0xA3D4 + +#define AR_PHY_TPCRG1_PD_GAIN_1 0x00030000 +#define AR_PHY_TPCRG1_PD_GAIN_1_S 16 +#define AR_PHY_TPCRG1_PD_GAIN_2 0x000C0000 +#define AR_PHY_TPCRG1_PD_GAIN_2_S 18 +#define AR_PHY_TPCRG1_PD_GAIN_3 0x00300000 +#define AR_PHY_TPCRG1_PD_GAIN_3_S 20 + +#define AR_PHY_VIT_MASK2_M_46_61 0xa3a0 +#define AR_PHY_MASK2_M_31_45 0xa3a4 +#define AR_PHY_MASK2_M_16_30 0xa3a8 +#define AR_PHY_MASK2_M_00_15 0xa3ac +#define AR_PHY_MASK2_P_15_01 0xa3b8 +#define AR_PHY_MASK2_P_30_16 0xa3bc +#define AR_PHY_MASK2_P_45_31 0xa3c0 +#define AR_PHY_MASK2_P_61_45 0xa3c4 + +#define AR_PHY_SPUR_REG 0x994c +#define AR_PHY_SFCORR_EXT 0x99c0 +#define AR_PHY_SFCORR_EXT_M1_THRESH 0x0000007F +#define AR_PHY_SFCORR_EXT_M1_THRESH_S 0 +#define AR_PHY_SFCORR_EXT_M2_THRESH 0x00003F80 +#define AR_PHY_SFCORR_EXT_M2_THRESH_S 7 +#define AR_PHY_SFCORR_EXT_M1_THRESH_LOW 0x001FC000 +#define AR_PHY_SFCORR_EXT_M1_THRESH_LOW_S 14 +#define AR_PHY_SFCORR_EXT_M2_THRESH_LOW 0x0FE00000 +#define AR_PHY_SFCORR_EXT_M2_THRESH_LOW_S 21 +#define AR_PHY_SFCORR_SPUR_SUBCHNL_SD_S 28 + +/* enable vit puncture per rate, 8 bits, lsb is low rate */ +#define AR_PHY_SPUR_REG_MASK_RATE_CNTL (0xFF << 18) +#define AR_PHY_SPUR_REG_MASK_RATE_CNTL_S 18 + +#define AR_PHY_SPUR_REG_ENABLE_MASK_PPM 0x20000 /* bins move with freq offset */ +#define AR_PHY_SPUR_REG_MASK_RATE_SELECT (0xFF << 9) /* use mask1 or mask2, one per rate */ +#define AR_PHY_SPUR_REG_MASK_RATE_SELECT_S 9 +#define AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI 0x100 +#define AR_PHY_SPUR_REG_SPUR_RSSI_THRESH 0x7F +#define AR_PHY_SPUR_REG_SPUR_RSSI_THRESH_S 0 + +#define AR_PHY_PILOT_MASK_01_30 0xa3b0 +#define AR_PHY_PILOT_MASK_31_60 0xa3b4 + +#define AR_PHY_CHANNEL_MASK_01_30 0x99d4 +#define AR_PHY_CHANNEL_MASK_31_60 0x99d8 + +#define AR_PHY_CL_CAL_CTL 0xA358 /* carrier leak cal control */ +#define AR_PHY_CL_CAL_ENABLE 0x00000002 +#endif /* _DEV_ATH_AR5416PHY_H_ */ --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5416/ar5416reg.h 2009-05-15 11:11:29.000000000 +0100 @@ -0,0 +1,506 @@ +/* + * 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: ar5416reg.h,v 1.1 2009/03/23 17:14:48 sborrill Exp $ + */ +#ifndef _DEV_ATH_AR5416REG_H +#define _DEV_ATH_AR5416REG_H + +#include "ar5212/ar5212reg.h" + +/* + * Register added starting with the AR5416 + */ +#define AR_MIRT 0x0020 /* interrupt rate threshold */ +#define AR_TIMT 0x0028 /* Tx Interrupt mitigation threshold */ +#define AR_RIMT 0x002C /* Rx Interrupt mitigation threshold */ +#define AR_GTXTO 0x0064 /* global transmit timeout */ +#define AR_GTTM 0x0068 /* global transmit timeout mode */ +#define AR_CST 0x006C /* carrier sense timeout */ +#define AR_MAC_LED 0x1f04 /* LED control */ +#define AR5416_PCIE_PM_CTRL 0x4014 +#define AR_AHB_MODE 0x4024 /* AHB mode for dma */ +#define AR_INTR_SYNC_CAUSE_CLR 0x4028 /* clear interrupt */ +#define AR_INTR_SYNC_CAUSE 0x4028 /* check pending interrupts */ +#define AR_INTR_SYNC_ENABLE 0x402c /* enable interrupts */ +#define AR_INTR_ASYNC_MASK 0x4030 /* asynchronous interrupt mask */ +#define AR_INTR_SYNC_MASK 0x4034 /* synchronous interrupt mask */ +#define AR_INTR_ASYNC_CAUSE 0x4038 /* check pending interrupts */ +#define AR_INTR_ASYNC_ENABLE 0x403c /* enable interrupts */ +#define AR5416_PCIE_SERDES 0x4040 +#define AR5416_PCIE_SERDES2 0x4044 +#define AR_GPIO_IN 0x4048 /* GPIO input register */ +#define AR_GPIO_INTR_OUT 0x404c /* GPIO output register */ +#define AR_EEPROM_STATUS_DATA 0x407c +#define AR_OBS 0x4080 +#define AR_RTC_RC 0x7000 /* reset control */ +#define AR_RTC_PLL_CONTROL 0x7014 +#define AR_RTC_RESET 0x7040 /* RTC reset register */ +#define AR_RTC_STATUS 0x7044 /* system sleep status */ +#define AR_RTC_SLEEP_CLK 0x7048 +#define AR_RTC_FORCE_WAKE 0x704c /* control MAC force wake */ +#define AR_RTC_INTR_CAUSE 0x7050 /* RTC interrupt cause/clear */ +#define AR_RTC_INTR_ENABLE 0x7054 /* RTC interrupt enable */ +#define AR_RTC_INTR_MASK 0x7058 /* RTC interrupt mask */ +/* AR9280: rf long shift registers */ +#define AR_AN_RF2G1_CH0 0x7810 +#define AR_AN_RF5G1_CH0 0x7818 +#define AR_AN_RF2G1_CH1 0x7834 +#define AR_AN_RF5G1_CH1 0x783C +#define AR_AN_TOP2 0x7894 +#define AR_AN_SYNTH9 0x7868 +#define AR9285_AN_RF2G3 0x7828 +#define AR9285_AN_TOP3 0x786c +#define AR_RESET_TSF 0x8020 +#define AR_RXFIFO_CFG 0x8114 +#define AR_PHY_ERR_1 0x812c +#define AR_PHY_ERR_MASK_1 0x8130 /* mask for AR_PHY_ERR_1 */ +#define AR_PHY_ERR_2 0x8134 +#define AR_PHY_ERR_MASK_2 0x8138 /* mask for AR_PHY_ERR_2 */ +#define AR_TSFOOR_THRESHOLD 0x813c +#define AR_PHY_ERR_3 0x8168 +#define AR_PHY_ERR_MASK_3 0x816c /* mask for AR_PHY_ERR_3 */ +#define AR_TXOP_X 0x81ec /* txop for legacy non-qos */ +#define AR_TXOP_0_3 0x81f0 /* txop for various tid's */ +#define AR_TXOP_4_7 0x81f4 +#define AR_TXOP_8_11 0x81f8 +#define AR_TXOP_12_15 0x81fc +/* generic timers based on tsf - all uS */ +#define AR_NEXT_TBTT 0x8200 +#define AR_NEXT_DBA 0x8204 +#define AR_NEXT_SWBA 0x8208 +#define AR_NEXT_CFP 0x8208 +#define AR_NEXT_HCF 0x820C +#define AR_NEXT_TIM 0x8210 +#define AR_NEXT_DTIM 0x8214 +#define AR_NEXT_QUIET 0x8218 +#define AR_NEXT_NDP 0x821C +#define AR5416_BEACON_PERIOD 0x8220 +#define AR_DBA_PERIOD 0x8224 +#define AR_SWBA_PERIOD 0x8228 +#define AR_HCF_PERIOD 0x822C +#define AR_TIM_PERIOD 0x8230 +#define AR_DTIM_PERIOD 0x8234 +#define AR_QUIET_PERIOD 0x8238 +#define AR_NDP_PERIOD 0x823C +#define AR_TIMER_MODE 0x8240 +#define AR_SLP32_MODE 0x8244 +#define AR_SLP32_WAKE 0x8248 +#define AR_SLP32_INC 0x824c +#define AR_SLP_CNT 0x8250 /* 32kHz cycles with mac asleep */ +#define AR_SLP_CYCLE_CNT 0x8254 /* absolute number of 32kHz cycles */ +#define AR_SLP_MIB_CTRL 0x8258 +#define AR_2040_MODE 0x8318 +#define AR_EXTRCCNT 0x8328 /* extension channel rx clear count */ +#define AR_SELFGEN_MASK 0x832c /* rx and cal chain masks */ +#define AR_PCU_TXBUF_CTRL 0x8340 + +/* DMA & PCI Registers in PCI space (usable during sleep)*/ +#define AR_RC_AHB 0x00000001 /* AHB reset */ +#define AR_RC_APB 0x00000002 /* APB reset */ +#define AR_RC_HOSTIF 0x00000100 /* host interface reset */ + +#define AR_MIRT_VAL 0x0000ffff /* in uS */ +#define AR_MIRT_VAL_S 16 + +#define AR_TIMT_LAST 0x0000ffff /* Last packet threshold */ +#define AR_TIMT_LAST_S 0 +#define AR_TIMT_FIRST 0xffff0000 /* First packet threshold */ +#define AR_TIMT_FIRST_S 16 + +#define AR_RIMT_LAST 0x0000ffff /* Last packet threshold */ +#define AR_RIMT_LAST_S 0 +#define AR_RIMT_FIRST 0xffff0000 /* First packet threshold */ +#define AR_RIMT_FIRST_S 16 + +#define AR_GTXTO_TIMEOUT_COUNTER 0x0000FFFF // Mask for timeout counter (in TUs) +#define AR_GTXTO_TIMEOUT_LIMIT 0xFFFF0000 // Mask for timeout limit (in TUs) +#define AR_GTXTO_TIMEOUT_LIMIT_S 16 // Shift for timeout limit + +#define AR_GTTM_USEC 0x00000001 // usec strobe +#define AR_GTTM_IGNORE_IDLE 0x00000002 // ignore channel idle +#define AR_GTTM_RESET_IDLE 0x00000004 // reset counter on channel idle low +#define AR_GTTM_CST_USEC 0x00000008 // CST usec strobe + +#define AR_CST_TIMEOUT_COUNTER 0x0000FFFF // Mask for timeout counter (in TUs) +#define AR_CST_TIMEOUT_LIMIT 0xFFFF0000 // Mask for timeout limit (in TUs) +#define AR_CST_TIMEOUT_LIMIT_S 16 // Shift for timeout limit + +/* MAC tx DMA size config */ +#define AR_TXCFG_DMASZ_MASK 0x00000003 +#define AR_TXCFG_DMASZ_4B 0 +#define AR_TXCFG_DMASZ_8B 1 +#define AR_TXCFG_DMASZ_16B 2 +#define AR_TXCFG_DMASZ_32B 3 +#define AR_TXCFG_DMASZ_64B 4 +#define AR_TXCFG_DMASZ_128B 5 +#define AR_TXCFG_DMASZ_256B 6 +#define AR_TXCFG_DMASZ_512B 7 +#define AR_TXCFG_ATIM_TXPOLICY 0x00000800 + +/* MAC rx DMA size config */ +#define AR_RXCFG_DMASZ_MASK 0x00000007 +#define AR_RXCFG_DMASZ_4B 0 +#define AR_RXCFG_DMASZ_8B 1 +#define AR_RXCFG_DMASZ_16B 2 +#define AR_RXCFG_DMASZ_32B 3 +#define AR_RXCFG_DMASZ_64B 4 +#define AR_RXCFG_DMASZ_128B 5 +#define AR_RXCFG_DMASZ_256B 6 +#define AR_RXCFG_DMASZ_512B 7 + +/* MAC Led registers */ +#define AR_MAC_LED_BLINK_SLOW 0x00000008 /* LED slowest blink rate mode */ +#define AR_MAC_LED_BLINK_THRESH_SEL 0x00000070 /* LED blink threshold select */ +#define AR_MAC_LED_MODE 0x00000380 /* LED mode select */ +#define AR_MAC_LED_MODE_S 7 +#define AR_MAC_LED_MODE_PROP 0 /* Blink prop to filtered tx/rx */ +#define AR_MAC_LED_MODE_RPROP 1 /* Blink prop to unfiltered tx/rx */ +#define AR_MAC_LED_MODE_SPLIT 2 /* Blink power for tx/net for rx */ +#define AR_MAC_LED_MODE_RAND 3 /* Blink randomly */ +#define AR_MAC_LED_MODE_POWON 5 /* Power LED on (s/w control) */ +#define AR_MAC_LED_MODE_NETON 6 /* Network LED on (s/w control) */ +#define AR_MAC_LED_ASSOC 0x00000c00 +#define AR_MAC_LED_ASSOC_NONE 0x00000000 /* STA is not associated or trying */ +#define AR_MAC_LED_ASSOC_ACTIVE 0x00000400 /* STA is associated */ +#define AR_MAC_LED_ASSOC_PEND 0x00000800 /* STA is trying to associate */ +#define AR_MAC_LED_ASSOC_S 10 + +#define AR_AHB_EXACT_WR_EN 0x00000000 /* write exact bytes */ +#define AR_AHB_BUF_WR_EN 0x00000001 /* buffer write upto cacheline*/ +#define AR_AHB_EXACT_RD_EN 0x00000000 /* read exact bytes */ +#define AR_AHB_CACHELINE_RD_EN 0x00000002 /* read upto end of cacheline */ +#define AR_AHB_PREFETCH_RD_EN 0x00000004 /* prefetch upto page boundary*/ +#define AR_AHB_PAGE_SIZE_1K 0x00000000 /* set page-size as 1k */ +#define AR_AHB_PAGE_SIZE_2K 0x00000008 /* set page-size as 2k */ +#define AR_AHB_PAGE_SIZE_4K 0x00000010 /* set page-size as 4k */ + +/* MAC PCU Registers */ +#define AR_STA_ID1_PRESERVE_SEQNUM 0x20000000 /* Don't replace seq num */ + +/* Extended PCU DIAG_SW control fields */ +#define AR_DIAG_DUAL_CHAIN_INFO 0x01000000 /* dual chain channel info */ +#define AR_DIAG_RX_ABORT 0x02000000 /* abort rx */ +#define AR_DIAG_SATURATE_CCNT 0x04000000 /* sat. cycle cnts (no shift) */ +#define AR_DIAG_OBS_PT_SEL2 0x08000000 /* observation point sel */ +#define AR_DIAG_RXCLEAR_CTL_LOW 0x10000000 /* force rx_clear(ctl) low/busy */ +#define AR_DIAG_RXCLEAR_EXT_LOW 0x20000000 /* force rx_clear(ext) low/busy */ + +#define AR_TXOP_X_VAL 0x000000FF + +#define AR_RESET_TSF_ONCE 0x01000000 /* reset tsf once; self-clears*/ + +/* Interrupts */ +#define AR_ISR_TXMINTR 0x00080000 /* Maximum interrupt tx rate */ +#define AR_ISR_RXMINTR 0x01000000 /* Maximum interrupt rx rate */ +#define AR_ISR_TXINTM 0x40000000 /* Tx int after mitigation */ +#define AR_ISR_RXINTM 0x80000000 /* Rx int after mitigation */ + +#define AR_ISR_S2_CST 0x00400000 /* Carrier sense timeout */ +#define AR_ISR_S2_GTT 0x00800000 /* Global transmit timeout */ +#define AR_ISR_S2_TSFOOR 0x40000000 /* RX TSF out of range */ + +#define AR_INTR_SPURIOUS 0xffffffff +#define AR_INTR_RTC_IRQ 0x00000001 /* rtc in shutdown state */ +#define AR_INTR_MAC_IRQ 0x00000002 /* pending mac interrupt */ +#define AR_INTR_EEP_PROT_ACCESS 0x00000004 /* eeprom protected access */ +#define AR_INTR_MAC_AWAKE 0x00020000 /* mac is awake */ +#define AR_INTR_MAC_ASLEEP 0x00040000 /* mac is asleep */ + +/* Interrupt Mask Registers */ +#define AR_IMR_TXMINTR 0x00080000 /* Maximum interrupt tx rate */ +#define AR_IMR_RXMINTR 0x01000000 /* Maximum interrupt rx rate */ +#define AR_IMR_TXINTM 0x40000000 /* Tx int after mitigation */ +#define AR_IMR_RXINTM 0x80000000 /* Rx int after mitigation */ + +#define AR_IMR_S2_CST 0x00400000 /* Carrier sense timeout */ +#define AR_IMR_S2_GTT 0x00800000 /* Global transmit timeout */ + +/* synchronous interrupt signals */ +#define AR_INTR_SYNC_RTC_IRQ 0x00000001 +#define AR_INTR_SYNC_MAC_IRQ 0x00000002 +#define AR_INTR_SYNC_EEPROM_ILLEGAL_ACCESS 0x00000004 +#define AR_INTR_SYNC_APB_TIMEOUT 0x00000008 +#define AR_INTR_SYNC_PCI_MODE_CONFLICT 0x00000010 +#define AR_INTR_SYNC_HOST1_FATAL 0x00000020 +#define AR_INTR_SYNC_HOST1_PERR 0x00000040 +#define AR_INTR_SYNC_TRCV_FIFO_PERR 0x00000080 +#define AR_INTR_SYNC_RADM_CPL_EP 0x00000100 +#define AR_INTR_SYNC_RADM_CPL_DLLP_ABORT 0x00000200 +#define AR_INTR_SYNC_RADM_CPL_TLP_ABORT 0x00000400 +#define AR_INTR_SYNC_RADM_CPL_ECRC_ERR 0x00000800 +#define AR_INTR_SYNC_RADM_CPL_TIMEOUT 0x00001000 +#define AR_INTR_SYNC_LOCAL_TIMEOUT 0x00002000 +#define AR_INTR_SYNC_PM_ACCESS 0x00004000 +#define AR_INTR_SYNC_MAC_AWAKE 0x00008000 +#define AR_INTR_SYNC_MAC_ASLEEP 0x00010000 +#define AR_INTR_SYNC_MAC_SLEEP_ACCESS 0x00020000 +#define AR_INTR_SYNC_ALL 0x0003FFFF + +/* default synchronous interrupt signals enabled */ +#define AR_INTR_SYNC_DEFAULT \ + (AR_INTR_SYNC_HOST1_FATAL | AR_INTR_SYNC_HOST1_PERR | \ + AR_INTR_SYNC_RADM_CPL_EP | AR_INTR_SYNC_RADM_CPL_DLLP_ABORT | \ + AR_INTR_SYNC_RADM_CPL_TLP_ABORT | AR_INTR_SYNC_RADM_CPL_ECRC_ERR | \ + AR_INTR_SYNC_RADM_CPL_TIMEOUT | AR_INTR_SYNC_LOCAL_TIMEOUT | \ + AR_INTR_SYNC_MAC_SLEEP_ACCESS) + +/* RTC registers */ +#define AR_RTC_RC_M 0x00000003 +#define AR_RTC_RC_MAC_WARM 0x00000001 +#define AR_RTC_RC_MAC_COLD 0x00000002 +#define AR_RTC_PLL_DIV 0x0000001f +#define AR_RTC_PLL_DIV_S 0 +#define AR_RTC_PLL_DIV2 0x00000020 +#define AR_RTC_PLL_REFDIV_5 0x000000c0 + +#define AR_RTC_SOWL_PLL_DIV 0x000003ff +#define AR_RTC_SOWL_PLL_DIV_S 0 +#define AR_RTC_SOWL_PLL_REFDIV 0x00003C00 +#define AR_RTC_SOWL_PLL_REFDIV_S 10 +#define AR_RTC_SOWL_PLL_CLKSEL 0x0000C000 +#define AR_RTC_SOWL_PLL_CLKSEL_S 14 + +#define AR_RTC_RESET_EN 0x00000001 /* Reset RTC bit */ + +#define AR_RTC_PM_STATUS_M 0x0000000f /* Pwr Mgmt Status */ +#define AR_RTC_STATUS_M 0x0000003f /* RTC Status */ +#define AR_RTC_STATUS_SHUTDOWN 0x00000001 +#define AR_RTC_STATUS_ON 0x00000002 +#define AR_RTC_STATUS_SLEEP 0x00000004 +#define AR_RTC_STATUS_WAKEUP 0x00000008 +#define AR_RTC_STATUS_COLDRESET 0x00000010 /* Not currently used */ +#define AR_RTC_STATUS_PLLCHANGE 0x00000020 /* Not currently used */ + +#define AR_RTC_SLEEP_DERIVED_CLK 0x2 + +#define AR_RTC_FORCE_WAKE_EN 0x00000001 /* enable force wake */ +#define AR_RTC_FORCE_WAKE_ON_INT 0x00000002 /* auto-wake on MAC interrupt */ + +#define AR_RTC_PLL_CLKSEL 0x00000300 +#define AR_RTC_PLL_CLKSEL_S 8 + +/* AR9280: rf long shift registers */ +#define AR_AN_RF2G1_CH0_OB 0x03800000 +#define AR_AN_RF2G1_CH0_OB_S 23 +#define AR_AN_RF2G1_CH0_DB 0x1C000000 +#define AR_AN_RF2G1_CH0_DB_S 26 + +#define AR_AN_RF5G1_CH0_OB5 0x00070000 +#define AR_AN_RF5G1_CH0_OB5_S 16 +#define AR_AN_RF5G1_CH0_DB5 0x00380000 +#define AR_AN_RF5G1_CH0_DB5_S 19 + +#define AR_AN_RF2G1_CH1_OB 0x03800000 +#define AR_AN_RF2G1_CH1_OB_S 23 +#define AR_AN_RF2G1_CH1_DB 0x1C000000 +#define AR_AN_RF2G1_CH1_DB_S 26 + +#define AR_AN_RF5G1_CH1_OB5 0x00070000 +#define AR_AN_RF5G1_CH1_OB5_S 16 +#define AR_AN_RF5G1_CH1_DB5 0x00380000 +#define AR_AN_RF5G1_CH1_DB5_S 19 + +#define AR_AN_TOP2_XPABIAS_LVL 0xC0000000 +#define AR_AN_TOP2_XPABIAS_LVL_S 30 +#define AR_AN_TOP2_LOCALBIAS 0x00200000 +#define AR_AN_TOP2_LOCALBIAS_S 21 +#define AR_AN_TOP2_PWDCLKIND 0x00400000 +#define AR_AN_TOP2_PWDCLKIND_S 22 + +#define AR_AN_SYNTH9_REFDIVA 0xf8000000 +#define AR_AN_SYNTH9_REFDIVA_S 27 + +/* AR9285 Analog registers */ +#define AR9285_AN_RF2G3_OB_0 0x00E00000 +#define AR9285_AN_RF2G3_OB_0_S 21 +#define AR9285_AN_RF2G3_OB_1 0x001C0000 +#define AR9285_AN_RF2G3_OB_1_S 18 +#define AR9285_AN_RF2G3_OB_2 0x00038000 +#define AR9285_AN_RF2G3_OB_2_S 15 +#define AR9285_AN_RF2G3_OB_3 0x00007000 +#define AR9285_AN_RF2G3_OB_3_S 12 +#define AR9285_AN_RF2G3_OB_4 0x00000E00 +#define AR9285_AN_RF2G3_OB_4_S 9 + +#define AR9285_AN_RF2G3_DB1_0 0x000001C0 +#define AR9285_AN_RF2G3_DB1_0_S 6 +#define AR9285_AN_RF2G3_DB1_1 0x00000038 +#define AR9285_AN_RF2G3_DB1_1_S 3 +#define AR9285_AN_RF2G3_DB1_2 0x00000007 +#define AR9285_AN_RF2G3_DB1_2_S 0 +#define AR9285_AN_RF2G4 0x782C +#define AR9285_AN_RF2G4_DB1_3 0xE0000000 +#define AR9285_AN_RF2G4_DB1_3_S 29 +#define AR9285_AN_RF2G4_DB1_4 0x1C000000 +#define AR9285_AN_RF2G4_DB1_4_S 26 + +#define AR9285_AN_RF2G4_DB2_0 0x03800000 +#define AR9285_AN_RF2G4_DB2_0_S 23 +#define AR9285_AN_RF2G4_DB2_1 0x00700000 +#define AR9285_AN_RF2G4_DB2_1_S 20 +#define AR9285_AN_RF2G4_DB2_2 0x000E0000 +#define AR9285_AN_RF2G4_DB2_2_S 17 +#define AR9285_AN_RF2G4_DB2_3 0x0001C000 +#define AR9285_AN_RF2G4_DB2_3_S 14 +#define AR9285_AN_RF2G4_DB2_4 0x00003800 +#define AR9285_AN_RF2G4_DB2_4_S 11 + +#define AR9285_AN_TOP3_XPABIAS_LVL 0x0000000C +#define AR9285_AN_TOP3_XPABIAS_LVL_S 2 + +/* Sleep control */ +#define AR5416_SLEEP1_CAB_TIMEOUT 0xFFE00000 /* Cab timeout (TU) */ +#define AR5416_SLEEP1_CAB_TIMEOUT_S 22 + +#define AR5416_SLEEP2_BEACON_TIMEOUT 0xFFE00000 /* Beacon timeout (TU)*/ +#define AR5416_SLEEP2_BEACON_TIMEOUT_S 22 + +/* Sleep Registers */ +#define AR_SLP32_HALFCLK_LATENCY 0x000FFFFF /* rising <-> falling edge */ +#define AR_SLP32_ENA 0x00100000 +#define AR_SLP32_TSF_WRITE_STATUS 0x00200000 /* tsf update in progress */ + +#define AR_SLP32_WAKE_XTL_TIME 0x0000FFFF /* time to wake crystal */ + +#define AR_SLP32_TST_INC 0x000FFFFF + +#define AR_SLP_MIB_CLEAR 0x00000001 /* clear pending */ +#define AR_SLP_MIB_PENDING 0x00000002 /* clear counters */ + +#define AR_TIMER_MODE_TBTT 0x00000001 +#define AR_TIMER_MODE_DBA 0x00000002 +#define AR_TIMER_MODE_SWBA 0x00000004 +#define AR_TIMER_MODE_HCF 0x00000008 +#define AR_TIMER_MODE_TIM 0x00000010 +#define AR_TIMER_MODE_DTIM 0x00000020 +#define AR_TIMER_MODE_QUIET 0x00000040 +#define AR_TIMER_MODE_NDP 0x00000080 +#define AR_TIMER_MODE_OVERFLOW_INDEX 0x00000700 +#define AR_TIMER_MODE_OVERFLOW_INDEX_S 8 +#define AR_TIMER_MODE_THRESH 0xFFFFF000 +#define AR_TIMER_MODE_THRESH_S 12 + +/* PCU Misc modes */ +#define AR_PCU_FORCE_BSSID_MATCH 0x00000001 /* force bssid to match */ +#define AR_PCU_MIC_NEW_LOC_ENA 0x00000004 /* tx/rx mic keys together */ +#define AR_PCU_TX_ADD_TSF 0x00000008 /* add tx_tsf + int_tsf */ +#define AR_PCU_CCK_SIFS_MODE 0x00000010 /* assume 11b sifs */ +#define AR_PCU_RX_ANT_UPDT 0x00000800 /* KC_RX_ANT_UPDATE */ +#define AR_PCU_TXOP_TBTT_LIMIT_ENA 0x00001000 /* enforce txop / tbtt */ +#define AR_PCU_MISS_BCN_IN_SLEEP 0x00004000 /* count bmiss's when sleeping */ +#define AR_PCU_BUG_12306_FIX_ENA 0x00020000 /* use rx_clear to count sifs */ +#define AR_PCU_FORCE_QUIET_COLL 0x00040000 /* kill xmit for channel change */ +#define AR_PCU_TBTT_PROTECT 0x00200000 /* no xmit upto tbtt+20 uS */ +#define AR_PCU_CLEAR_VMF 0x01000000 /* clear vmf mode (fast cc)*/ +#define AR_PCU_CLEAR_BA_VALID 0x04000000 /* clear ba state */ + +/* GPIO Interrupt */ +#define AR_INTR_GPIO 0x3FF00000 /* gpio interrupted */ +#define AR_INTR_GPIO_S 20 + +#define AR_GPIO_OUT_CTRL 0x000003FF /* 0 = out, 1 = in */ +#define AR_GPIO_OUT_VAL 0x000FFC00 +#define AR_GPIO_OUT_VAL_S 10 +#define AR_GPIO_INTR_CTRL 0x3FF00000 +#define AR_GPIO_INTR_CTRL_S 20 + +#define AR_2040_JOINED_RX_CLEAR 0x00000001 /* use ctl + ext rx_clear for cca */ + +#define AR_PCU_TXBUF_CTRL_SIZE_MASK 0x7FF +#define AR_PCU_TXBUF_CTRL_USABLE_SIZE 0x700 + +/* Eeprom defines */ +#define AR_EEPROM_STATUS_DATA_VAL 0x0000ffff +#define AR_EEPROM_STATUS_DATA_VAL_S 0 +#define AR_EEPROM_STATUS_DATA_BUSY 0x00010000 +#define AR_EEPROM_STATUS_DATA_BUSY_ACCESS 0x00020000 +#define AR_EEPROM_STATUS_DATA_PROT_ACCESS 0x00040000 +#define AR_EEPROM_STATUS_DATA_ABSENT_ACCESS 0x00080000 + +#define AR_SREV_REVISION_OWL_10 0x08 +#define AR_SREV_REVISION_OWL_20 0x09 +#define AR_SREV_REVISION_OWL_22 0x0a + +#define AR_RAD5133_SREV_MAJOR 0xc0 /* Fowl: 2+5G/3x3 */ +#define AR_RAD2133_SREV_MAJOR 0xd0 /* Fowl: 2G/3x3 */ +#define AR_RAD5122_SREV_MAJOR 0xe0 /* Fowl: 5G/2x2 */ +#define AR_RAD2122_SREV_MAJOR 0xf0 /* Fowl: 2+5G/2x2 */ + +/* Test macro for owl 1.0 */ +#define IS_5416V1(_ah) ((_ah)->ah_macRev == AR_SREV_REVISION_OWL_10) +#define IS_5416V2(_ah) ((_ah)->ah_macRev >= AR_SREV_REVISION_OWL_20) +#define IS_5416V2_2(_ah) ((_ah)->ah_macRev == AR_SREV_REVISION_OWL_22) + +/* Expanded Mac Silicon Rev (16 bits starting with Sowl) */ +#define AR_XSREV_ID 0xFFFFFFFF /* Chip ID */ +#define AR_XSREV_ID_S 0 +#define AR_XSREV_VERSION 0xFFFC0000 /* Chip version */ +#define AR_XSREV_VERSION_S 18 +#define AR_XSREV_TYPE 0x0003F000 /* Chip type */ +#define AR_XSREV_TYPE_S 12 +#define AR_XSREV_TYPE_CHAIN 0x00001000 /* Chain Mode (1:3 chains, + * 0:2 chains) */ +#define AR_XSREV_TYPE_HOST_MODE 0x00002000 /* Host Mode (1:PCI, 0:PCIe) */ +#define AR_XSREV_REVISION 0x00000F00 +#define AR_XSREV_REVISION_S 8 + +#define AR_XSREV_VERSION_OWL_PCI 0x0D +#define AR_XSREV_VERSION_OWL_PCIE 0x0C +#define AR_XSREV_REVISION_OWL_10 0 /* Owl 1.0 */ +#define AR_XSREV_REVISION_OWL_20 1 /* Owl 2.0/2.1 */ +#define AR_XSREV_REVISION_OWL_22 2 /* Owl 2.2 */ +#define AR_XSREV_VERSION_SOWL 0x40 +#define AR_XSREV_REVISION_SOWL_10 0 /* Sowl 1.0 */ +#define AR_XSREV_REVISION_SOWL_11 1 /* Sowl 1.1 */ +#define AR_XSREV_VERSION_MERLIN 0x80 /* Merlin Version */ +#define AR_XSREV_REVISION_MERLIN_10 0 /* Merlin 1.0 */ +#define AR_XSREV_REVISION_MERLIN_20 1 /* Merlin 2.0 */ +#define AR_XSREV_REVISION_MERLIN_21 2 /* Merlin 2.1 */ +#define AR_XSREV_VERSION_KITE 0xC0 /* Kite Version */ +#define AR_XSREV_REVISION_KITE_10 0 /* Kite 1.0 */ + +#define AR_SREV_OWL_20_OR_LATER(_ah) \ + (AH_PRIVATE((_ah))->ah_macVersion >= AR_XSREV_VERSION_SOWL || \ + AH_PRIVATE((_ah))->ah_macRev >= AR_XSREV_REVISION_OWL_20) +#define AR_SREV_OWL_22_OR_LATER(_ah) \ + (AH_PRIVATE((_ah))->ah_macVersion >= AR_XSREV_VERSION_SOWL || \ + AH_PRIVATE((_ah))->ah_macRev >= AR_XSREV_REVISION_OWL_22) + +#define AR_SREV_SOWL(_ah) \ + (AH_PRIVATE((_ah))->ah_macVersion == AR_XSREV_VERSION_SOWL) +#define AR_SREV_SOWL_10_OR_LATER(_ah) \ + (AH_PRIVATE((_ah))->ah_macVersion >= AR_XSREV_VERSION_SOWL) +#define AR_SREV_SOWL_11(_ah) \ + (AR_SREV_SOWL(_ah) && \ + AH_PRIVATE((_ah))->ah_macRev == AR_XSREV_REVISION_SOWL_11) + +#define AR_SREV_MERLIN(_ah) \ + (AH_PRIVATE((_ah))->ah_macVersion == AR_XSREV_VERSION_MERLIN) +#define AR_SREV_MERLIN_10_OR_LATER(_ah) \ + (AH_PRIVATE((_ah))->ah_macVersion >= AR_XSREV_VERSION_MERLIN) +#define AR_SREV_MERLIN_20(_ah) \ + (AR_SREV_MERLIN(_ah) && \ + AH_PRIVATE((_ah))->ah_macRev >= AR_XSREV_REVISION_MERLIN_20) +#define AR_SREV_MERLIN_20_OR_LATER(_ah) \ + (AR_SREV_MERLIN_20(_ah) || \ + AH_PRIVATE((_ah))->ah_macVersion > AR_XSREV_VERSION_MERLIN) + +#define AR_SREV_KITE(_ah) \ + (AH_PRIVATE((_ah))->ah_macVersion == AR_XSREV_VERSION_KITE) +#define AR_SREV_KITE_10_OR_LATER(_ah) \ + (AH_PRIVATE((_ah))->ah_macVersion >= AR_XSREV_VERSION_KITE) +#endif /* _DEV_ATH_AR5416REG_H */ --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5416/ar9160.ini 2009-05-15 11:11:29.000000000 +0100 @@ -0,0 +1,699 @@ +/* + * 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: ar9160.ini,v 1.1 2009/03/23 17:14:48 sborrill Exp $ + */ +/* Auto Generated PCI Register Writes. Created: 05/22/08 */ + +static const uint32_t ar9160Modes[][6] = { + { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, + { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, + { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 }, + { 0x000010f0, 0x0000a000, 0x00014000, 0x00016000, 0x0000b000, 0x00014008 }, + { 0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0 }, + { 0x0000801c, 0x128d93a7, 0x128d93cf, 0x12e013d7, 0x12e013ab, 0x098813cf }, + { 0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303 }, + { 0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200 }, + { 0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, + { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 }, + { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, + { 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 }, + { 0x00009844, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0, 0x037216a0 }, + { 0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, + { 0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, + { 0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, + { 0x00009850, 0x6d48b4e2, 0x6d48b4e2, 0x6d48b0e2, 0x6d48b0e2, 0x6d48b0e2 }, + { 0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e }, + { 0x0000985c, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e }, + { 0x00009860, 0x00048d18, 0x00048d18, 0x00048d20, 0x00048d20, 0x00048d18 }, + { 0x0000c864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 }, + { 0x00009868, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0 }, + { 0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 }, + { 0x00009914, 0x000007d0, 0x000007d0, 0x00000898, 0x00000898, 0x000007d0 }, + { 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 }, + { 0x00009924, 0xd00a8a07, 0xd00a8a07, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d }, + { 0x00009944, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020 }, + { 0x00009960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40 }, + { 0x0000a960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40 }, + { 0x0000b960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40 }, + { 0x00009964, 0x00001120, 0x00001120, 0x00001120, 0x00001120, 0x00001120 }, + { 0x0000c968, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce, 0x000003ce }, + { 0x0000c9bc, 0x001a0600, 0x001a0600, 0x001a0c00, 0x001a0c00, 0x001a0c00 }, + { 0x000099c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, 0x038919be }, + { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 }, + { 0x000099c8, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329 }, + { 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 }, + { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 }, + { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a204, 0x00000880, 0x00000880, 0x00000880, 0x00000880, 0x00000880 }, + { 0x0000a208, 0xd6be4788, 0xd6be4788, 0xd03e4788, 0xd03e4788, 0xd03e4788 }, + { 0x0000a20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120 }, + { 0x0000b20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120 }, + { 0x0000c20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120 }, + { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a }, + { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 }, + { 0x0000a274, 0x0a1a9caa, 0x0a1a9caa, 0x0a1a7caa, 0x0a1a7caa, 0x0a1a7caa }, + { 0x0000a300, 0x18010000, 0x18010000, 0x18010000, 0x18010000, 0x18010000 }, + { 0x0000a304, 0x30032602, 0x30032602, 0x2e032402, 0x2e032402, 0x2e032402 }, + { 0x0000a308, 0x48073e06, 0x48073e06, 0x4a0a3c06, 0x4a0a3c06, 0x4a0a3c06 }, + { 0x0000a30c, 0x560b4c0a, 0x560b4c0a, 0x621a540b, 0x621a540b, 0x621a540b }, + { 0x0000a310, 0x641a600f, 0x641a600f, 0x764f6c1b, 0x764f6c1b, 0x764f6c1b }, + { 0x0000a314, 0x7a4f6e1b, 0x7a4f6e1b, 0x845b7a5a, 0x845b7a5a, 0x845b7a5a }, + { 0x0000a318, 0x8c5b7e5a, 0x8c5b7e5a, 0x950f8ccf, 0x950f8ccf, 0x950f8ccf }, + { 0x0000a31c, 0x9d0f96cf, 0x9d0f96cf, 0xa5cf9b4f, 0xa5cf9b4f, 0xa5cf9b4f }, + { 0x0000a320, 0xb51fa69f, 0xb51fa69f, 0xbddfaf1f, 0xbddfaf1f, 0xbddfaf1f }, + { 0x0000a324, 0xcb3fbd07, 0xcb3fbcbf, 0xd1ffc93f, 0xd1ffc93f, 0xd1ffc93f }, + { 0x0000a328, 0x0000d7bf, 0x0000d7bf, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a32c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a330, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a334, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, +}; + +static const uint32_t ar9160Common[][2] = { + { 0x0000000c, 0x00000000 }, + { 0x00000030, 0x00020015 }, + { 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 }, + { 0x00001040, 0x002ffc0f }, + { 0x00001044, 0x002ffc0f }, + { 0x00001048, 0x002ffc0f }, + { 0x0000104c, 0x002ffc0f }, + { 0x00001050, 0x002ffc0f }, + { 0x00001054, 0x002ffc0f }, + { 0x00001058, 0x002ffc0f }, + { 0x0000105c, 0x002ffc0f }, + { 0x00001060, 0x002ffc0f }, + { 0x00001064, 0x002ffc0f }, + { 0x00001230, 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 }, + { 0x00004030, 0x00000002 }, + { 0x0000403c, 0x00000002 }, + { 0x00007010, 0x00000020 }, + { 0x00007038, 0x000004c2 }, + { 0x00008004, 0x00000000 }, + { 0x00008008, 0x00000000 }, + { 0x0000800c, 0x00000000 }, + { 0x00008018, 0x00000700 }, + { 0x00008020, 0x00000000 }, + { 0x00008038, 0x00000000 }, + { 0x0000803c, 0x00000000 }, + { 0x00008048, 0x40000000 }, + { 0x00008054, 0x00000000 }, + { 0x00008058, 0x00000000 }, + { 0x0000805c, 0x000fc78f }, + { 0x00008060, 0x0000000f }, + { 0x00008064, 0x00000000 }, + { 0x000080c0, 0x2a82301a }, + { 0x000080c4, 0x05dc01e0 }, + { 0x000080c8, 0x1f402710 }, + { 0x000080cc, 0x01f40000 }, + { 0x000080d0, 0x00001e00 }, + { 0x000080d4, 0x00000000 }, + { 0x000080d8, 0x00400000 }, + { 0x000080e0, 0xffffffff }, + { 0x000080e4, 0x0000ffff }, + { 0x000080e8, 0x003f3f3f }, + { 0x000080ec, 0x00000000 }, + { 0x000080f0, 0x00000000 }, + { 0x000080f4, 0x00000000 }, + { 0x000080f8, 0x00000000 }, + { 0x000080fc, 0x00020000 }, + { 0x00008100, 0x00020000 }, + { 0x00008104, 0x00000001 }, + { 0x00008108, 0x00000052 }, + { 0x0000810c, 0x00000000 }, + { 0x00008110, 0x00000168 }, + { 0x00008118, 0x000100aa }, + { 0x0000811c, 0x00003210 }, + { 0x00008120, 0x08f04800 }, + { 0x00008124, 0x00000000 }, + { 0x00008128, 0x00000000 }, + { 0x0000812c, 0x00000000 }, + { 0x00008130, 0x00000000 }, + { 0x00008134, 0x00000000 }, + { 0x00008138, 0x00000000 }, + { 0x0000813c, 0x00000000 }, + { 0x00008144, 0x00000000 }, + { 0x00008168, 0x00000000 }, + { 0x0000816c, 0x00000000 }, + { 0x00008170, 0x32143320 }, + { 0x00008174, 0xfaa4fa50 }, + { 0x00008178, 0x00000100 }, + { 0x0000817c, 0x00000000 }, + { 0x000081c4, 0x00000000 }, + { 0x000081d0, 0x00003210 }, + { 0x000081ec, 0x00000000 }, + { 0x000081f0, 0x00000000 }, + { 0x000081f4, 0x00000000 }, + { 0x000081f8, 0x00000000 }, + { 0x000081fc, 0x00000000 }, + { 0x00008200, 0x00000000 }, + { 0x00008204, 0x00000000 }, + { 0x00008208, 0x00000000 }, + { 0x0000820c, 0x00000000 }, + { 0x00008210, 0x00000000 }, + { 0x00008214, 0x00000000 }, + { 0x00008218, 0x00000000 }, + { 0x0000821c, 0x00000000 }, + { 0x00008220, 0x00000000 }, + { 0x00008224, 0x00000000 }, + { 0x00008228, 0x00000000 }, + { 0x0000822c, 0x00000000 }, + { 0x00008230, 0x00000000 }, + { 0x00008234, 0x00000000 }, + { 0x00008238, 0x00000000 }, + { 0x0000823c, 0x00000000 }, + { 0x00008240, 0x00100000 }, + { 0x00008244, 0x0010f400 }, + { 0x00008248, 0x00000100 }, + { 0x0000824c, 0x0001e800 }, + { 0x00008250, 0x00000000 }, + { 0x00008254, 0x00000000 }, + { 0x00008258, 0x00000000 }, + { 0x0000825c, 0x400000ff }, + { 0x00008260, 0x00080922 }, + { 0x00008270, 0x00000000 }, + { 0x00008274, 0x40000000 }, + { 0x00008278, 0x003e4180 }, + { 0x0000827c, 0x00000000 }, + { 0x00008284, 0x0000002c }, + { 0x00008288, 0x0000002c }, + { 0x0000828c, 0x00000000 }, + { 0x00008294, 0x00000000 }, + { 0x00008298, 0x00000000 }, + { 0x00008300, 0x00000000 }, + { 0x00008304, 0x00000000 }, + { 0x00008308, 0x00000000 }, + { 0x0000830c, 0x00000000 }, + { 0x00008310, 0x00000000 }, + { 0x00008314, 0x00000000 }, + { 0x00008318, 0x00000000 }, + { 0x00008328, 0x00000000 }, + { 0x0000832c, 0x00000007 }, + { 0x00008330, 0x00000302 }, + { 0x00008334, 0x00000e00 }, + { 0x00008338, 0x00000000 }, + { 0x0000833c, 0x00000000 }, + { 0x00008340, 0x000107ff }, + { 0x00009808, 0x00000000 }, + { 0x0000980c, 0xad848e19 }, + { 0x00009810, 0x7d14e000 }, + { 0x00009814, 0x9c0a9f6b }, + { 0x0000981c, 0x00000000 }, + { 0x0000982c, 0x0000a000 }, + { 0x00009830, 0x00000000 }, + { 0x0000983c, 0x00200400 }, + { 0x00009840, 0x206a01ae }, + { 0x0000984c, 0x1284233c }, + { 0x00009854, 0x00000859 }, + { 0x00009900, 0x00000000 }, + { 0x00009904, 0x00000000 }, + { 0x00009908, 0x00000000 }, + { 0x0000990c, 0x00000000 }, + { 0x0000991c, 0x10000fff }, + { 0x00009920, 0x05100000 }, + { 0x0000a920, 0x05100000 }, + { 0x0000b920, 0x05100000 }, + { 0x00009928, 0x00000001 }, + { 0x0000992c, 0x00000004 }, + { 0x00009934, 0x1e1f2022 }, + { 0x00009938, 0x0a0b0c0d }, + { 0x0000993c, 0x00000000 }, + { 0x00009948, 0x9280b212 }, + { 0x0000994c, 0x00020028 }, + { 0x00009954, 0x5f3ca3de }, + { 0x00009958, 0x2108ecff }, + { 0x00009940, 0x00750604 }, + { 0x0000c95c, 0x004b6a8e }, + { 0x00009970, 0x190fb515 }, + { 0x00009974, 0x00000000 }, + { 0x00009978, 0x00000001 }, + { 0x0000997c, 0x00000000 }, + { 0x00009980, 0x00000000 }, + { 0x00009984, 0x00000000 }, + { 0x00009988, 0x00000000 }, + { 0x0000998c, 0x00000000 }, + { 0x00009990, 0x00000000 }, + { 0x00009994, 0x00000000 }, + { 0x00009998, 0x00000000 }, + { 0x0000999c, 0x00000000 }, + { 0x000099a0, 0x00000000 }, + { 0x000099a4, 0x00000001 }, + { 0x000099a8, 0x201fff00 }, + { 0x000099ac, 0x006f0000 }, + { 0x000099b0, 0x03051000 }, + { 0x000099dc, 0x00000000 }, + { 0x000099e0, 0x00000200 }, + { 0x000099e4, 0xaaaaaaaa }, + { 0x000099e8, 0x3c466478 }, + { 0x000099ec, 0x0cc80caa }, + { 0x000099fc, 0x00001042 }, + { 0x00009b00, 0x00000000 }, + { 0x00009b04, 0x00000001 }, + { 0x00009b08, 0x00000002 }, + { 0x00009b0c, 0x00000003 }, + { 0x00009b10, 0x00000004 }, + { 0x00009b14, 0x00000005 }, + { 0x00009b18, 0x00000008 }, + { 0x00009b1c, 0x00000009 }, + { 0x00009b20, 0x0000000a }, + { 0x00009b24, 0x0000000b }, + { 0x00009b28, 0x0000000c }, + { 0x00009b2c, 0x0000000d }, + { 0x00009b30, 0x00000010 }, + { 0x00009b34, 0x00000011 }, + { 0x00009b38, 0x00000012 }, + { 0x00009b3c, 0x00000013 }, + { 0x00009b40, 0x00000014 }, + { 0x00009b44, 0x00000015 }, + { 0x00009b48, 0x00000018 }, + { 0x00009b4c, 0x00000019 }, + { 0x00009b50, 0x0000001a }, + { 0x00009b54, 0x0000001b }, + { 0x00009b58, 0x0000001c }, + { 0x00009b5c, 0x0000001d }, + { 0x00009b60, 0x00000020 }, + { 0x00009b64, 0x00000021 }, + { 0x00009b68, 0x00000022 }, + { 0x00009b6c, 0x00000023 }, + { 0x00009b70, 0x00000024 }, + { 0x00009b74, 0x00000025 }, + { 0x00009b78, 0x00000028 }, + { 0x00009b7c, 0x00000029 }, + { 0x00009b80, 0x0000002a }, + { 0x00009b84, 0x0000002b }, + { 0x00009b88, 0x0000002c }, + { 0x00009b8c, 0x0000002d }, + { 0x00009b90, 0x00000030 }, + { 0x00009b94, 0x00000031 }, + { 0x00009b98, 0x00000032 }, + { 0x00009b9c, 0x00000033 }, + { 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 }, + { 0x0000a210, 0x40806333 }, + { 0x0000a214, 0x00106c10 }, + { 0x0000a218, 0x009c4060 }, + { 0x0000a220, 0x018830c6 }, + { 0x0000a224, 0x00000400 }, + { 0x0000a228, 0x001a0bb5 }, + { 0x0000a22c, 0x00000000 }, + { 0x0000a234, 0x20202020 }, + { 0x0000a238, 0x20202020 }, + { 0x0000a23c, 0x13c889af }, + { 0x0000a240, 0x38490a20 }, + { 0x0000a244, 0x00007bb6 }, + { 0x0000a248, 0x0fff3ffc }, + { 0x0000a24c, 0x00000001 }, + { 0x0000a250, 0x0000a000 }, + { 0x0000a254, 0x00000000 }, + { 0x0000a258, 0x0cc75380 }, + { 0x0000a25c, 0x0f0f0f01 }, + { 0x0000a260, 0xdfa91f01 }, + { 0x0000a268, 0x00000001 }, + { 0x0000a26c, 0x0ebae9c6 }, + { 0x0000b26c, 0x0ebae9c6 }, + { 0x0000c26c, 0x0ebae9c6 }, + { 0x0000d270, 0x00820820 }, + { 0x0000a278, 0x1ce739ce }, + { 0x0000a27c, 0x050701ce }, + { 0x0000a338, 0x00000000 }, + { 0x0000a33c, 0x00000000 }, + { 0x0000a340, 0x00000000 }, + { 0x0000a344, 0x00000000 }, + { 0x0000a348, 0x3fffffff }, + { 0x0000a34c, 0x3fffffff }, + { 0x0000a350, 0x3fffffff }, + { 0x0000a354, 0x0003ffff }, + { 0x0000a358, 0x79a8aa33 }, + { 0x0000d35c, 0x07ffffef }, + { 0x0000d360, 0x0fffffe7 }, + { 0x0000d364, 0x17ffffe5 }, + { 0x0000d368, 0x1fffffe4 }, + { 0x0000d36c, 0x37ffffe3 }, + { 0x0000d370, 0x3fffffe3 }, + { 0x0000d374, 0x57ffffe3 }, + { 0x0000d378, 0x5fffffe2 }, + { 0x0000d37c, 0x7fffffe2 }, + { 0x0000d380, 0x7f3c7bba }, + { 0x0000d384, 0xf3307ff0 }, + { 0x0000a388, 0x0c000000 }, + { 0x0000a38c, 0x20202020 }, + { 0x0000a390, 0x20202020 }, + { 0x0000a394, 0x1ce739ce }, + { 0x0000a398, 0x000001ce }, + { 0x0000a39c, 0x00000001 }, + { 0x0000a3a0, 0x00000000 }, + { 0x0000a3a4, 0x00000000 }, + { 0x0000a3a8, 0x00000000 }, + { 0x0000a3ac, 0x00000000 }, + { 0x0000a3b0, 0x00000000 }, + { 0x0000a3b4, 0x00000000 }, + { 0x0000a3b8, 0x00000000 }, + { 0x0000a3bc, 0x00000000 }, + { 0x0000a3c0, 0x00000000 }, + { 0x0000a3c4, 0x00000000 }, + { 0x0000a3c8, 0x00000246 }, + { 0x0000a3cc, 0x20202020 }, + { 0x0000a3d0, 0x20202020 }, + { 0x0000a3d4, 0x20202020 }, + { 0x0000a3dc, 0x1ce739ce }, + { 0x0000a3e0, 0x000001ce }, +}; + +static const uint32_t ar9160Bank0[][2] = { + { 0x000098b0, 0x1e5795e5 }, + { 0x000098e0, 0x02008020 }, +}; + +static const uint32_t ar9160BB_RfGain[][3] = { + { 0x00009a00, 0x00000000, 0x00000000 }, + { 0x00009a04, 0x00000040, 0x00000040 }, + { 0x00009a08, 0x00000080, 0x00000080 }, + { 0x00009a0c, 0x000001a1, 0x00000141 }, + { 0x00009a10, 0x000001e1, 0x00000181 }, + { 0x00009a14, 0x00000021, 0x000001c1 }, + { 0x00009a18, 0x00000061, 0x00000001 }, + { 0x00009a1c, 0x00000168, 0x00000041 }, + { 0x00009a20, 0x000001a8, 0x000001a8 }, + { 0x00009a24, 0x000001e8, 0x000001e8 }, + { 0x00009a28, 0x00000028, 0x00000028 }, + { 0x00009a2c, 0x00000068, 0x00000068 }, + { 0x00009a30, 0x00000189, 0x000000a8 }, + { 0x00009a34, 0x000001c9, 0x00000169 }, + { 0x00009a38, 0x00000009, 0x000001a9 }, + { 0x00009a3c, 0x00000049, 0x000001e9 }, + { 0x00009a40, 0x00000089, 0x00000029 }, + { 0x00009a44, 0x00000170, 0x00000069 }, + { 0x00009a48, 0x000001b0, 0x00000190 }, + { 0x00009a4c, 0x000001f0, 0x000001d0 }, + { 0x00009a50, 0x00000030, 0x00000010 }, + { 0x00009a54, 0x00000070, 0x00000050 }, + { 0x00009a58, 0x00000191, 0x00000090 }, + { 0x00009a5c, 0x000001d1, 0x00000151 }, + { 0x00009a60, 0x00000011, 0x00000191 }, + { 0x00009a64, 0x00000051, 0x000001d1 }, + { 0x00009a68, 0x00000091, 0x00000011 }, + { 0x00009a6c, 0x000001b8, 0x00000051 }, + { 0x00009a70, 0x000001f8, 0x00000198 }, + { 0x00009a74, 0x00000038, 0x000001d8 }, + { 0x00009a78, 0x00000078, 0x00000018 }, + { 0x00009a7c, 0x00000199, 0x00000058 }, + { 0x00009a80, 0x000001d9, 0x00000098 }, + { 0x00009a84, 0x00000019, 0x00000159 }, + { 0x00009a88, 0x00000059, 0x00000199 }, + { 0x00009a8c, 0x00000099, 0x000001d9 }, + { 0x00009a90, 0x000000d9, 0x00000019 }, + { 0x00009a94, 0x000000f9, 0x00000059 }, + { 0x00009a98, 0x000000f9, 0x00000099 }, + { 0x00009a9c, 0x000000f9, 0x000000d9 }, + { 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 }, +}; + +static const uint32_t ar9160Bank1[][2] = { + { 0x000098b0, 0x02108421 }, + { 0x000098ec, 0x00000008 }, +}; + +static const uint32_t ar9160Bank2[][2] = { + { 0x000098b0, 0x0e73ff17 }, + { 0x000098e0, 0x00000420 }, +}; + +static const uint32_t ar9160Bank3[][3] = { + { 0x000098f0, 0x01400018, 0x01c00018 }, +}; + +static const uint32_t ar9160Bank6[][3] = { +/* Reg A G */ + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00e00000, 0x00e00000 }, + { 0x0000989c, 0x005e0000, 0x005e0000 }, + { 0x0000989c, 0x00120000, 0x00120000 }, + { 0x0000989c, 0x00620000, 0x00620000 }, + { 0x0000989c, 0x00020000, 0x00020000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x40ff0000, 0x40ff0000 }, + { 0x0000989c, 0x005f0000, 0x005f0000 }, + { 0x0000989c, 0x00870000, 0x00870000 }, + { 0x0000989c, 0x00f90000, 0x00f90000 }, + { 0x0000989c, 0x007b0000, 0x007b0000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x00f50000, 0x00f50000 }, + { 0x0000989c, 0x00dc0000, 0x00dc0000 }, + { 0x0000989c, 0x00110000, 0x00110000 }, + { 0x0000989c, 0x006100a8, 0x006100a8 }, + { 0x0000989c, 0x004210a2, 0x004210a2 }, + { 0x0000989c, 0x0014008f, 0x0014008f }, + { 0x0000989c, 0x00c40003, 0x00c40003 }, + { 0x0000989c, 0x003000f2, 0x003000f2 }, + { 0x0000989c, 0x00440016, 0x00440016 }, + { 0x0000989c, 0x00410040, 0x00410040 }, + { 0x0000989c, 0x0001805e, 0x0001805e }, + { 0x0000989c, 0x0000c0ab, 0x0000c0ab }, + { 0x0000989c, 0x000000f1, 0x000000f1 }, + { 0x0000989c, 0x00002081, 0x00002081 }, + { 0x0000989c, 0x000000d4, 0x000000d4 }, + { 0x000098d0, 0x0000000f, 0x0010000f }, +}; + +static const uint32_t ar9160Bank6TPC[][3] = { + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00e00000, 0x00e00000 }, + { 0x0000989c, 0x005e0000, 0x005e0000 }, + { 0x0000989c, 0x00120000, 0x00120000 }, + { 0x0000989c, 0x00620000, 0x00620000 }, + { 0x0000989c, 0x00020000, 0x00020000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x40ff0000, 0x40ff0000 }, + { 0x0000989c, 0x005f0000, 0x005f0000 }, + { 0x0000989c, 0x00870000, 0x00870000 }, + { 0x0000989c, 0x00f90000, 0x00f90000 }, + { 0x0000989c, 0x007b0000, 0x007b0000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x00f50000, 0x00f50000 }, + { 0x0000989c, 0x00dc0000, 0x00dc0000 }, + { 0x0000989c, 0x00110000, 0x00110000 }, + { 0x0000989c, 0x006100a8, 0x006100a8 }, + { 0x0000989c, 0x00423022, 0x00423022 }, + { 0x0000989c, 0x2014008f, 0x2014008f }, + { 0x0000989c, 0x00c40002, 0x00c40002 }, + { 0x0000989c, 0x003000f2, 0x003000f2 }, + { 0x0000989c, 0x00440016, 0x00440016 }, + { 0x0000989c, 0x00410040, 0x00410040 }, + { 0x0000989c, 0x0001805e, 0x0001805e }, + { 0x0000989c, 0x0000c0ab, 0x0000c0ab }, + { 0x0000989c, 0x000000e1, 0x000000e1 }, + { 0x0000989c, 0x00007080, 0x00007080 }, + { 0x0000989c, 0x000000d4, 0x000000d4 }, + { 0x000098d0, 0x0000000f, 0x0010000f }, +}; + +static const uint32_t ar9160Bank7[][2] = { + { 0x0000989c, 0x00000500 }, + { 0x0000989c, 0x00000800 }, + { 0x000098cc, 0x0000000e }, +}; + +/* Auto generated PCI Register Writes for SOWL1.0 ADDAC Shift Chain */ +static const uint32_t ar9160Addac[][2] = { + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x000000c0 }, + {0x0000989c, 0x00000018 }, + {0x0000989c, 0x00000004 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x000000c0 }, + {0x0000989c, 0x00000019 }, + {0x0000989c, 0x00000004 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000004 }, + {0x0000989c, 0x00000003 }, + {0x0000989c, 0x00000008 }, + {0x0000989c, 0x00000000 }, + {0x000098cc, 0x00000000 }, +}; + +/* Auto generated PCI Register Writes for SOWL1.1 ADDAC Shift Chain */ +static const uint32_t ar9160Addac_1_1[][2] = { + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x000000c0 }, + {0x0000989c, 0x00000018 }, + {0x0000989c, 0x00000004 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x000000c0 }, + {0x0000989c, 0x00000019 }, + {0x0000989c, 0x00000004 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x000098cc, 0x00000000 }, +}; --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ar5416/ar9160_attach.c 2009-05-15 11:11:29.000000000 +0100 @@ -0,0 +1,307 @@ +/* + * Copyright (c) 2008 Sam Leffler, Errno Consulting + * Copyright (c) 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: ar9160_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 "ar5416/ar5416.h" +#include "ar5416/ar5416reg.h" +#include "ar5416/ar5416phy.h" + +#include "ar5416/ar9160.ini" + +static const HAL_PERCAL_DATA ar9160_iq_cal = { /* multi sample */ + .calName = "IQ", .calType = IQ_MISMATCH_CAL, + .calNumSamples = MAX_CAL_SAMPLES, + .calCountMax = PER_MIN_LOG_COUNT, + .calCollect = ar5416IQCalCollect, + .calPostProc = ar5416IQCalibration +}; +static const HAL_PERCAL_DATA ar9160_adc_gain_cal = { /* multi sample */ + .calName = "ADC Gain", .calType = ADC_GAIN_CAL, + .calNumSamples = MAX_CAL_SAMPLES, + .calCountMax = PER_MIN_LOG_COUNT, + .calCollect = ar5416AdcGainCalCollect, + .calPostProc = ar5416AdcGainCalibration +}; +static const HAL_PERCAL_DATA ar9160_adc_dc_cal = { /* multi sample */ + .calName = "ADC DC", .calType = ADC_DC_CAL, + .calNumSamples = MAX_CAL_SAMPLES, + .calCountMax = PER_MIN_LOG_COUNT, + .calCollect = ar5416AdcDcCalCollect, + .calPostProc = ar5416AdcDcCalibration +}; +static const HAL_PERCAL_DATA ar9160_adc_init_dc_cal = { + .calName = "ADC Init DC", .calType = ADC_DC_INIT_CAL, + .calNumSamples = MIN_CAL_SAMPLES, + .calCountMax = INIT_LOG_COUNT, + .calCollect = ar5416AdcDcCalCollect, + .calPostProc = ar5416AdcDcCalibration +}; + +struct ath_hal *ar9160Attach(uint16_t devid, HAL_SOFTC sc, + HAL_BUS_TAG st, HAL_BUS_HANDLE sh, HAL_STATUS *status); +static void ar9160Detach(struct ath_hal *); +static HAL_BOOL ar9160FillCapabilityInfo(struct ath_hal *ah); + +static void +ar9160AniSetup(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, + .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, + }; + /* NB: ANI is not enabled yet */ + ar5212AniAttach(ah, &aniparams, &aniparams, AH_FALSE); +} + +/* + * Attach for an AR9160 part. + */ +struct ath_hal * +ar9160Attach(uint16_t devid, HAL_SOFTC sc, + HAL_BUS_TAG st, HAL_BUS_HANDLE sh, HAL_STATUS *status) +{ + struct ath_hal_5416 *ahp5416; + struct ath_hal_5212 *ahp; + struct ath_hal *ah; + uint32_t val; + HAL_STATUS ecode; + HAL_BOOL rfStatus; + + 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 */ + ahp5416 = ath_hal_malloc(sizeof (struct ath_hal_5416)); + if (ahp5416 == AH_NULL) { + HALDEBUG(AH_NULL, HAL_DEBUG_ANY, + "%s: cannot allocate memory for state block\n", __func__); + *status = HAL_ENOMEM; + return AH_NULL; + } + ar5416InitState(ahp5416, devid, sc, st, sh, status); + ahp = &ahp5416->ah_5212; + ah = &ahp->ah_priv.h; + + /* XXX override with 9160 specific state */ + /* override 5416 methods for our needs */ + ah->ah_detach = ar9160Detach; + + AH5416(ah)->ah_cal.iqCalData.calData = &ar9160_iq_cal; + AH5416(ah)->ah_cal.adcGainCalData.calData = &ar9160_adc_gain_cal; + AH5416(ah)->ah_cal.adcDcCalData.calData = &ar9160_adc_dc_cal; + AH5416(ah)->ah_cal.adcDcCalInitData.calData = &ar9160_adc_init_dc_cal; + AH5416(ah)->ah_cal.suppCals = ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL; + + if (!ar5416SetResetReg(ah, HAL_RESET_POWER_ON)) { + /* reset chip */ + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: couldn't reset chip\n", + __func__); + ecode = HAL_EIO; + goto bad; + } + + if (!ar5416SetPowerMode(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); + HALDEBUG(ah, HAL_DEBUG_ATTACH, + "%s: ID 0x%x VERSION 0x%x TYPE 0x%x REVISION 0x%x\n", + __func__, MS(val, AR_XSREV_ID), MS(val, AR_XSREV_VERSION), + MS(val, AR_XSREV_TYPE), MS(val, AR_XSREV_REVISION)); + /* NB: include chip type to differentiate from pre-Sowl versions */ + AH_PRIVATE(ah)->ah_macVersion = + (val & AR_XSREV_VERSION) >> AR_XSREV_TYPE_S; + AH_PRIVATE(ah)->ah_macRev = MS(val, AR_XSREV_REVISION); + /* XXX extract pcie info */ + + /* setup common ini data; rf backends handle remainder */ + HAL_INI_INIT(&ahp->ah_ini_modes, ar9160Modes, 6); + HAL_INI_INIT(&ahp->ah_ini_common, ar9160Common, 2); + + HAL_INI_INIT(&AH5416(ah)->ah_ini_bb_rfgain, ar9160BB_RfGain, 3); + HAL_INI_INIT(&AH5416(ah)->ah_ini_bank0, ar9160Bank0, 2); + HAL_INI_INIT(&AH5416(ah)->ah_ini_bank1, ar9160Bank1, 2); + HAL_INI_INIT(&AH5416(ah)->ah_ini_bank2, ar9160Bank2, 2); + HAL_INI_INIT(&AH5416(ah)->ah_ini_bank3, ar9160Bank3, 3); + HAL_INI_INIT(&AH5416(ah)->ah_ini_bank6, ar9160Bank6, 3); + HAL_INI_INIT(&AH5416(ah)->ah_ini_bank7, ar9160Bank7, 2); + if (AR_SREV_SOWL_11(ah)) + HAL_INI_INIT(&AH5416(ah)->ah_ini_addac, ar9160Addac_1_1, 2); + else + HAL_INI_INIT(&AH5416(ah)->ah_ini_addac, ar9160Addac, 2); + + if (!ar5416ChipReset(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 (!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); + switch (AH_PRIVATE(ah)->ah_analog5GhzRev & AR_RADIO_SREV_MAJOR) { + case AR_RAD2133_SREV_MAJOR: /* Sowl: 2G/3x3 */ + case AR_RAD5133_SREV_MAJOR: /* Sowl: 2+5G/3x3 */ + break; + default: + if (AH_PRIVATE(ah)->ah_analog5GhzRev == 0) { + AH_PRIVATE(ah)->ah_analog5GhzRev = + AR_RAD5133_SREV_MAJOR; + 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 + } + HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s: Attaching AR2133 radio\n", + __func__); + rfStatus = ar2133RfAttach(ah, &ecode); + if (!rfStatus) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: RF setup failed, status %u\n", + __func__, ecode); + goto bad; + } + + ecode = ath_hal_v14EepromAttach(ah); + if (ecode != HAL_OK) + goto bad; + + /* + * Got everything we need now to setup the capabilities. + */ + if (!ar9160FillCapabilityInfo(ah)) { + ecode = HAL_EEREAD; + goto bad; + } + + 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; + } + /* XXX How about the serial number ? */ + /* Read Reg Domain */ + AH_PRIVATE(ah)->ah_currentRD = + ath_hal_eepromGet(ah, AR_EEP_REGDMN_0, AH_NULL); + + /* + * ah_miscMode is populated by ar5416FillCapabilityInfo() + * starting from griffin. Set here to make sure that + * AR_MISC_MODE_MIC_NEW_LOC_ENABLE is set before a GTK is + * placed into hardware. + */ + if (ahp->ah_miscMode != 0) + OS_REG_WRITE(ah, AR_MISC_MODE, ahp->ah_miscMode); + + ar9160AniSetup(ah); /* Anti Noise Immunity */ + ar5416InitNfHistBuff(AH5416(ah)->ah_cal.nfCalHist); + + HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s: return\n", __func__); + + return ah; +bad: + if (ahp) + ar9160Detach((struct ath_hal *) ahp); + if (status) + *status = ecode; + return AH_NULL; +} + +void +ar9160Detach(struct ath_hal *ah) +{ + HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s:\n", __func__); + + HALASSERT(ah != AH_NULL); + HALASSERT(ah->ah_magic == AR5416_MAGIC); + + ar5416Detach(ah); +} + +/* + * Fill all software cached or static hardware state information. + * Return failure if capabilities are to come from EEPROM and + * cannot be read. + */ +static HAL_BOOL +ar9160FillCapabilityInfo(struct ath_hal *ah) +{ + HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps; + + if (!ar5416FillCapabilityInfo(ah)) + return AH_FALSE; + pCap->halCSTSupport = AH_TRUE; + pCap->halRifsRxSupport = AH_TRUE; + pCap->halRifsTxSupport = AH_TRUE; + pCap->halRtsAggrLimit = 64*1024; /* 802.11n max */ + pCap->halExtChanDfsSupport = AH_TRUE; + pCap->halAutoSleepSupport = AH_FALSE; /* XXX? */ + return AH_TRUE; +} + +static const char* +ar9160Probe(uint16_t vendorid, uint16_t devid) +{ + if (vendorid == ATHEROS_VENDOR_ID && devid == AR9160_DEVID_PCI) + return "Atheros 9160"; + return AH_NULL; +} +AH_CHIP(AR9160, ar9160Probe, ar9160Attach); --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ah_debug.h 2009-03-23 17:36:56.000000000 +0000 @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2008 Sam Leffler, Errno Consulting + * Copyright (c) 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: ah_debug.h,v 1.1 2009/03/23 17:14:47 sborrill Exp $ + */ +#ifndef _ATH_AH_DEBUG_H_ +#define _ATH_AH_DEBUG_H_ +/* + * Atheros Device Hardware Access Layer (HAL). + * + * Debug mask definitions. + */ +enum { + HAL_DEBUG_REGDOMAIN = 0x00000001, /* regulatory handling */ + HAL_DEBUG_ATTACH = 0x00000002, /* work done in attach */ + HAL_DEBUG_RESET = 0x00000004, /* reset work */ + HAL_DEBUG_NFCAL = 0x00000008, /* noise floor calibration */ + HAL_DEBUG_PERCAL = 0x00000010, /* periodic calibration */ + HAL_DEBUG_ANI = 0x00000020, /* ANI operation */ + HAL_DEBUG_PHYIO = 0x00000040, /* phy i/o operations */ + HAL_DEBUG_REGIO = 0x00000080, /* register i/o operations */ + HAL_DEBUG_RFPARAM = 0x00000100, + HAL_DEBUG_TXQUEUE = 0x00000200, /* tx queue handling */ + HAL_DEBUG_TX = 0x00000400, + HAL_DEBUG_TXDESC = 0x00000800, + HAL_DEBUG_RX = 0x00001000, + HAL_DEBUG_RXDESC = 0x00002000, + HAL_DEBUG_KEYCACHE = 0x00004000, /* keycache handling */ + HAL_DEBUG_EEPROM = 0x00008000, + HAL_DEBUG_BEACON = 0x00010000, /* beacon setup work */ + HAL_DEBUG_POWER = 0x00020000, /* power management */ + HAL_DEBUG_INTERRUPT = 0x00000080, /* interrupt handling */ + + HAL_DEBUG_ANY = 0xffffffff +}; +#endif /* _ATH_AH_DEBUG_H_ */ --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ah_devid.h 2009-03-23 17:36:56.000000000 +0000 @@ -0,0 +1,84 @@ +/* + * 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: ah_devid.h,v 1.1 2009/03/23 17:14:47 sborrill Exp $ + */ + +#ifndef _DEV_ATH_DEVID_H_ +#define _DEV_ATH_DEVID_H_ + +#define ATHEROS_VENDOR_ID 0x168c /* Atheros PCI vendor ID */ +/* + * NB: all Atheros-based devices should have a PCI vendor ID + * of 0x168c, but some vendors, in their infinite wisdom + * do not follow this so we must handle them specially. + */ +#define ATHEROS_3COM_VENDOR_ID 0xa727 /* 3Com 3CRPAG175 vendor ID */ +#define ATHEROS_3COM2_VENDOR_ID 0x10b7 /* 3Com 3CRDAG675 vendor ID */ + +/* AR5210 (for reference) */ +#define AR5210_DEFAULT 0x1107 /* No eeprom HW default */ +#define AR5210_PROD 0x0007 /* Final device ID */ +#define AR5210_AP 0x0207 /* Early AP11s */ + +/* AR5211 */ +#define AR5211_DEFAULT 0x1112 /* No eeprom HW default */ +#define AR5311_DEVID 0x0011 /* Final ar5311 devid */ +#define AR5211_DEVID 0x0012 /* Final ar5211 devid */ +#define AR5211_LEGACY 0xff12 /* Original emulation board */ +#define AR5211_FPGA11B 0xf11b /* 11b emulation board */ + +/* AR5212 */ +#define AR5212_DEFAULT 0x1113 /* No eeprom HW default */ +#define AR5212_DEVID 0x0013 /* Final ar5212 devid */ +#define AR5212_FPGA 0xf013 /* Emulation board */ +#define AR5212_DEVID_IBM 0x1014 /* IBM minipci ID */ +#define AR5212_AR5312_REV2 0x0052 /* AR5312 WMAC (AP31) */ +#define AR5212_AR5312_REV7 0x0057 /* AR5312 WMAC (AP30-040) */ +#define AR5212_AR2313_REV8 0x0058 /* AR2313 WMAC (AP43-030) */ +#define AR5212_AR2315_REV6 0x0086 /* AR2315 WMAC (AP51-Light) */ +#define AR5212_AR2315_REV7 0x0087 /* AR2315 WMAC (AP51-Full) */ +#define AR5212_AR2317_REV1 0x0090 /* AR2317 WMAC (AP61-Light) */ +#define AR5212_AR2317_REV2 0x0091 /* AR2317 WMAC (AP61-Full) */ + +/* AR5212 compatible devid's also attach to 5212 */ +#define AR5212_DEVID_0014 0x0014 +#define AR5212_DEVID_0015 0x0015 +#define AR5212_DEVID_0016 0x0016 +#define AR5212_DEVID_0017 0x0017 +#define AR5212_DEVID_0018 0x0018 +#define AR5212_DEVID_0019 0x0019 +#define AR5212_AR2413 0x001a /* AR2413 aka Griffin-lite */ +#define AR5212_AR5413 0x001b /* Eagle */ +#define AR5212_AR5424 0x001c /* Condor (PCI express) */ +#define AR5212_AR2417 0x001d /* Nala, PCI */ +#define AR5212_DEVID_FF19 0xff19 /* XXX PCI express */ + +/* AR5213 */ +#define AR5213_SREV_1_0 0x0055 +#define AR5213_SREV_REG 0x4020 + +/* AR5416 compatible devid's */ +#define AR5416_DEVID_PCI 0x0023 /* AR5416 PCI (MB/CB) Owl */ +#define AR5416_DEVID_PCIE 0x0024 /* AR5416 PCI-E (XB) Owl */ +#define AR9160_DEVID_PCI 0x0027 /* AR9160 PCI Sowl */ +#define AR9280_DEVID_PCI 0x0029 /* AR9280 PCI Merlin */ +#define AR9280_DEVID_PCIE 0x002a /* AR9280 PCI-E Merlin */ +#define AR9285_DEVID_PCIE 0x002b /* AR9285 PCI-E Kite */ + +#define AR_SUBVENDOR_ID_NOG 0x0e11 /* No 11G subvendor ID */ +#define AR_SUBVENDOR_ID_NEW_A 0x7065 /* Update device to new RD */ +#endif /* _DEV_ATH_DEVID_H */ --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ah_eeprom.h 2009-03-23 17:36:56.000000000 +0000 @@ -0,0 +1,133 @@ +/* + * 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: ah_eeprom.h,v 1.1 2009/03/23 17:14:47 sborrill Exp $ + */ +#ifndef _ATH_AH_EEPROM_H_ +#define _ATH_AH_EEPROM_H_ + +#define AR_EEPROM_VER1 0x1000 /* Version 1.0; 5210 only */ +/* + * Version 3 EEPROMs are all 16K. + * 3.1 adds turbo limit, antenna gain, 16 CTL's, 11g info, + * and 2.4Ghz ob/db for B & G + * 3.2 has more accurate pcdac intercepts and analog chip + * calibration. + * 3.3 adds ctl in-band limit, 32 ctl's, and frequency + * expansion + * 3.4 adds xr power, gainI, and 2.4 turbo params + */ +#define AR_EEPROM_VER3 0x3000 /* Version 3.0; start of 16k EEPROM */ +#define AR_EEPROM_VER3_1 0x3001 /* Version 3.1 */ +#define AR_EEPROM_VER3_2 0x3002 /* Version 3.2 */ +#define AR_EEPROM_VER3_3 0x3003 /* Version 3.3 */ +#define AR_EEPROM_VER3_4 0x3004 /* Version 3.4 */ +#define AR_EEPROM_VER4 0x4000 /* Version 4.x */ +#define AR_EEPROM_VER4_0 0x4000 /* Version 4.0 */ +#define AR_EEPROM_VER4_1 0x4001 /* Version 4.0 */ +#define AR_EEPROM_VER4_2 0x4002 /* Version 4.0 */ +#define AR_EEPROM_VER4_3 0x4003 /* Version 4.0 */ +#define AR_EEPROM_VER4_6 0x4006 /* Version 4.0 */ +#define AR_EEPROM_VER4_7 0x3007 /* Version 4.7 */ +#define AR_EEPROM_VER4_9 0x4009 /* EEPROM EAR futureproofing */ +#define AR_EEPROM_VER5 0x5000 /* Version 5.x */ +#define AR_EEPROM_VER5_0 0x5000 /* Adds new 2413 cal powers and added params */ +#define AR_EEPROM_VER5_1 0x5001 /* Adds capability values */ +#define AR_EEPROM_VER5_3 0x5003 /* Adds spur mitigation table */ +#define AR_EEPROM_VER5_4 0x5004 +/* + * Version 14 EEPROMs came in with AR5416. + * 14.2 adds txFrameToPaOn, txFrameToDataStart, ht40PowerInc + * 14.3 adds bswAtten, bswMargin, swSettle, and base OpFlags for HT20/40 + */ +#define AR_EEPROM_VER14 0xE000 /* Version 14.x */ +#define AR_EEPROM_VER14_1 0xE001 /* Adds 11n support */ +#define AR_EEPROM_VER14_2 0xE002 +#define AR_EEPROM_VER14_3 0xE003 +#define AR_EEPROM_VER14_7 0xE007 +#define AR_EEPROM_VER14_9 0xE009 +#define AR_EEPROM_VER14_16 0xE010 +#define AR_EEPROM_VER14_17 0xE011 +#define AR_EEPROM_VER14_19 0xE013 + +enum { + AR_EEP_RFKILL, /* use ath_hal_eepromGetFlag */ + AR_EEP_AMODE, /* use ath_hal_eepromGetFlag */ + AR_EEP_BMODE, /* use ath_hal_eepromGetFlag */ + AR_EEP_GMODE, /* use ath_hal_eepromGetFlag */ + AR_EEP_TURBO5DISABLE, /* use ath_hal_eepromGetFlag */ + AR_EEP_TURBO2DISABLE, /* use ath_hal_eepromGetFlag */ + AR_EEP_ISTALON, /* use ath_hal_eepromGetFlag */ + AR_EEP_32KHZCRYSTAL, /* use ath_hal_eepromGetFlag */ + AR_EEP_MACADDR, /* uint8_t* */ + AR_EEP_COMPRESS, /* use ath_hal_eepromGetFlag */ + AR_EEP_FASTFRAME, /* use ath_hal_eepromGetFlag */ + AR_EEP_AES, /* use ath_hal_eepromGetFlag */ + AR_EEP_BURST, /* use ath_hal_eepromGetFlag */ + AR_EEP_MAXQCU, /* uint16_t* */ + AR_EEP_KCENTRIES, /* uint16_t* */ + AR_EEP_NFTHRESH_5, /* int16_t* */ + AR_EEP_NFTHRESH_2, /* int16_t* */ + AR_EEP_REGDMN_0, /* uint16_t* */ + AR_EEP_REGDMN_1, /* uint16_t* */ + AR_EEP_OPCAP, /* uint16_t* */ + AR_EEP_OPMODE, /* uint16_t* */ + AR_EEP_RFSILENT, /* uint16_t* */ + AR_EEP_OB_5, /* uint8_t* */ + AR_EEP_DB_5, /* uint8_t* */ + AR_EEP_OB_2, /* uint8_t* */ + AR_EEP_DB_2, /* uint8_t* */ + AR_EEP_TXMASK, /* uint8_t* */ + AR_EEP_RXMASK, /* uint8_t* */ + AR_EEP_RXGAIN_TYPE, /* uint8_t* */ + AR_EEP_TXGAIN_TYPE, /* uint8_t* */ + AR_EEP_OL_PWRCTRL, /* use ath_hal_eepromGetFlag */ + AR_EEP_FSTCLK_5G, /* use ath_hal_eepromGetFlag */ + AR_EEP_ANTGAINMAX_5, /* int8_t* */ + AR_EEP_ANTGAINMAX_2, /* int8_t* */ + AR_EEP_WRITEPROTECT, /* use ath_hal_eepromGetFlag */ +}; + +typedef struct { + uint16_t rdEdge; + uint16_t twice_rdEdgePower; + HAL_BOOL flag; +} RD_EDGES_POWER; + +/* XXX should probably be version-dependent */ +#define SD_NO_CTL 0xf0 +#define NO_CTL 0xff +#define CTL_MODE_M 0x0f +#define CTL_11A 0 +#define CTL_11B 1 +#define CTL_11G 2 +#define CTL_TURBO 3 +#define CTL_108G 4 +#define CTL_2GHT20 5 +#define CTL_5GHT20 6 +#define CTL_2GHT40 7 +#define CTL_5GHT40 8 + +#define AR_NO_SPUR 0x8000 + +/* XXX exposed to chip code */ +#define MAX_RATE_POWER 63 + +HAL_STATUS ath_hal_v1EepromAttach(struct ath_hal *ah); +HAL_STATUS ath_hal_legacyEepromAttach(struct ath_hal *ah); +HAL_STATUS ath_hal_v14EepromAttach(struct ath_hal *ah); +HAL_STATUS ath_hal_v4kEepromAttach(struct ath_hal *ah); +#endif /* _ATH_AH_EEPROM_H_ */ --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ah_eeprom_v1.c 2009-03-23 17:36:56.000000000 +0000 @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2008 Sam Leffler, Errno Consulting + * Copyright (c) 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: ah_eeprom_v1.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_v1.h" + +static HAL_STATUS +v1EepromGet(struct ath_hal *ah, int param, void *val) +{ + HAL_EEPROM_v1 *ee = AH_PRIVATE(ah)->ah_eeprom; + uint32_t sum; + uint16_t eeval; + uint8_t *macaddr; + int i; + + switch (param) { + case AR_EEP_MACADDR: /* Get MAC Address */ + sum = 0; + macaddr = val; + for (i = 0; i < 3; i++) { + if (!ath_hal_eepromRead(ah, AR_EEPROM_MAC(i), &eeval)) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: cannot read EEPROM location %u\n", + __func__, i); + return HAL_EEREAD; + } + sum += eeval; + macaddr[2*i + 0] = eeval >> 8; + macaddr[2*i + 1] = eeval & 0xff; + } + if (sum == 0 || sum == 0xffff*3) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad mac address %s\n", + __func__, ath_hal_ether_sprintf(macaddr)); + return HAL_EEBADMAC; + } + return HAL_OK; + case AR_EEP_REGDMN_0: + *(uint16_t *) val = ee->ee_regDomain[0]; + return HAL_OK; + case AR_EEP_RFKILL: + HALASSERT(val == AH_NULL); + return ee->ee_rfKill ? HAL_OK : HAL_EIO; + case AR_EEP_WRITEPROTECT: + HALASSERT(val == AH_NULL); + return (ee->ee_protect & AR_EEPROM_PROTOTECT_WP_128_191) ? + HAL_OK : HAL_EIO; + default: + HALASSERT(0); + return HAL_EINVAL; + } +} + +static HAL_BOOL +v1EepromSet(struct ath_hal *ah, int param, int v) +{ + return HAL_EINVAL; +} + +static HAL_BOOL +v1EepromDiag(struct ath_hal *ah, int request, + const void *args, uint32_t argsize, void **result, uint32_t *resultsize) +{ + HAL_EEPROM_v1 *ee = AH_PRIVATE(ah)->ah_eeprom; + + switch (request) { + case HAL_DIAG_EEPROM: + *result = ee; + *resultsize = sizeof(*ee); + return AH_TRUE; + } + return AH_FALSE; +} + +static uint16_t +v1EepromGetSpurChan(struct ath_hal *ah, int ix, HAL_BOOL is2GHz) +{ + return AR_NO_SPUR; +} + +/* + * Reclaim any EEPROM-related storage. + */ +static void +v1EepromDetach(struct ath_hal *ah) +{ + HAL_EEPROM_v1 *ee = AH_PRIVATE(ah)->ah_eeprom; + + ath_hal_free(ee); + AH_PRIVATE(ah)->ah_eeprom = AH_NULL; +} + +HAL_STATUS +ath_hal_v1EepromAttach(struct ath_hal *ah) +{ + HAL_EEPROM_v1 *ee = AH_PRIVATE(ah)->ah_eeprom; + uint16_t athvals[AR_EEPROM_ATHEROS_MAX]; /* XXX off stack */ + uint16_t protect, eeprom_version, eeval; + uint32_t sum; + int i, loc; + + HALASSERT(ee == AH_NULL); + + if (!ath_hal_eepromRead(ah, AR_EEPROM_MAGIC, &eeval)) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: cannot read EEPROM magic number\n", __func__); + return HAL_EEREAD; + } + if (eeval != 0x5aa5) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: invalid EEPROM magic number 0x%x\n", __func__, eeval); + return HAL_EEMAGIC; + } + + if (!ath_hal_eepromRead(ah, AR_EEPROM_PROTECT, &protect)) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: cannot read EEPROM protection bits; read locked?\n", + __func__); + return HAL_EEREAD; + } + HALDEBUG(ah, HAL_DEBUG_ATTACH, "EEPROM protect 0x%x\n", protect); + /* XXX check proper access before continuing */ + + if (!ath_hal_eepromRead(ah, AR_EEPROM_VERSION, &eeprom_version)) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: unable to read EEPROM version\n", __func__); + return HAL_EEREAD; + } + if (((eeprom_version>>12) & 0xf) != 1) { + /* + * This code only groks the version 1 EEPROM layout. + */ + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: unsupported EEPROM version 0x%x found\n", + __func__, eeprom_version); + return HAL_EEVERSION; + } + + /* + * Read the Atheros EEPROM entries and calculate the checksum. + */ + sum = 0; + for (i = 0; i < AR_EEPROM_ATHEROS_MAX; i++) { + if (!ath_hal_eepromRead(ah, AR_EEPROM_ATHEROS(i), &athvals[i])) + return HAL_EEREAD; + sum ^= athvals[i]; + } + if (sum != 0xffff) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad EEPROM checksum 0x%x\n", + __func__, sum); + return HAL_EEBADSUM; + } + + /* + * Valid checksum, fetch the regulatory domain and save values. + */ + if (!ath_hal_eepromRead(ah, AR_EEPROM_REG_DOMAIN, &eeval)) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: cannot read regdomain from EEPROM\n", __func__); + return HAL_EEREAD; + } + + ee = ath_hal_malloc(sizeof(HAL_EEPROM_v1)); + if (ee == AH_NULL) { + /* XXX message */ + return HAL_ENOMEM; + } + + ee->ee_version = eeprom_version; + ee->ee_protect = protect; + ee->ee_antenna = athvals[2]; + ee->ee_biasCurrents = athvals[3]; + ee->ee_thresh62 = athvals[4] & 0xff; + ee->ee_xlnaOn = (athvals[4] >> 8) & 0xff; + ee->ee_xpaOn = athvals[5] & 0xff; + ee->ee_xpaOff = (athvals[5] >> 8) & 0xff; + ee->ee_regDomain[0] = (athvals[6] >> 8) & 0xff; + ee->ee_regDomain[1] = athvals[6] & 0xff; + ee->ee_regDomain[2] = (athvals[7] >> 8) & 0xff; + ee->ee_regDomain[3] = athvals[7] & 0xff; + ee->ee_rfKill = athvals[8] & 0x1; + ee->ee_devType = (athvals[8] >> 1) & 0x7; + + for (i = 0, loc = AR_EEPROM_ATHEROS_TP_SETTINGS; i < AR_CHANNELS_MAX; i++, loc += AR_TP_SETTINGS_SIZE) { + struct tpcMap *chan = &ee->ee_tpc[i]; + + /* Copy pcdac and gain_f values from EEPROM */ + chan->pcdac[0] = (athvals[loc] >> 10) & 0x3F; + chan->gainF[0] = (athvals[loc] >> 4) & 0x3F; + chan->pcdac[1] = ((athvals[loc] << 2) & 0x3C) + | ((athvals[loc+1] >> 14) & 0x03); + chan->gainF[1] = (athvals[loc+1] >> 8) & 0x3F; + chan->pcdac[2] = (athvals[loc+1] >> 2) & 0x3F; + chan->gainF[2] = ((athvals[loc+1] << 4) & 0x30) + | ((athvals[loc+2] >> 12) & 0x0F); + chan->pcdac[3] = (athvals[loc+2] >> 6) & 0x3F; + chan->gainF[3] = athvals[loc+2] & 0x3F; + chan->pcdac[4] = (athvals[loc+3] >> 10) & 0x3F; + chan->gainF[4] = (athvals[loc+3] >> 4) & 0x3F; + chan->pcdac[5] = ((athvals[loc+3] << 2) & 0x3C) + | ((athvals[loc+4] >> 14) & 0x03); + chan->gainF[5] = (athvals[loc+4] >> 8) & 0x3F; + chan->pcdac[6] = (athvals[loc+4] >> 2) & 0x3F; + chan->gainF[6] = ((athvals[loc+4] << 4) & 0x30) + | ((athvals[loc+5] >> 12) & 0x0F); + chan->pcdac[7] = (athvals[loc+5] >> 6) & 0x3F; + chan->gainF[7] = athvals[loc+5] & 0x3F; + chan->pcdac[8] = (athvals[loc+6] >> 10) & 0x3F; + chan->gainF[8] = (athvals[loc+6] >> 4) & 0x3F; + chan->pcdac[9] = ((athvals[loc+6] << 2) & 0x3C) + | ((athvals[loc+7] >> 14) & 0x03); + chan->gainF[9] = (athvals[loc+7] >> 8) & 0x3F; + chan->pcdac[10] = (athvals[loc+7] >> 2) & 0x3F; + chan->gainF[10] = ((athvals[loc+7] << 4) & 0x30) + | ((athvals[loc+8] >> 12) & 0x0F); + + /* Copy Regulatory Domain and Rate Information from EEPROM */ + chan->rate36 = (athvals[loc+8] >> 6) & 0x3F; + chan->rate48 = athvals[loc+8] & 0x3F; + chan->rate54 = (athvals[loc+9] >> 10) & 0x3F; + chan->regdmn[0] = (athvals[loc+9] >> 4) & 0x3F; + chan->regdmn[1] = ((athvals[loc+9] << 2) & 0x3C) + | ((athvals[loc+10] >> 14) & 0x03); + chan->regdmn[2] = (athvals[loc+10] >> 8) & 0x3F; + chan->regdmn[3] = (athvals[loc+10] >> 2) & 0x3F; + } + + AH_PRIVATE(ah)->ah_eeprom = ee; + AH_PRIVATE(ah)->ah_eeversion = eeprom_version; + AH_PRIVATE(ah)->ah_eepromDetach = v1EepromDetach; + AH_PRIVATE(ah)->ah_eepromGet = v1EepromGet; + AH_PRIVATE(ah)->ah_eepromSet = v1EepromSet; + AH_PRIVATE(ah)->ah_getSpurChan = v1EepromGetSpurChan; + AH_PRIVATE(ah)->ah_eepromDiag = v1EepromDiag; + return HAL_OK; +} --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ah_eeprom_v1.h 2009-03-23 17:36:56.000000000 +0000 @@ -0,0 +1,99 @@ +/* + * 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: ah_eeprom_v1.h,v 1.1 2009/03/23 17:14:47 sborrill Exp $ + */ +#ifndef _ATH_AH_EEPROM_V1_H_ +#define _ATH_AH_EEPROM_V1_H_ + +#include "ah_eeprom.h" + +/* + * EEPROM defines for Version 1 Crete EEPROM. + * + * The EEPROM is segmented into three sections: + * + * PCI/Cardbus default configuration settings + * Cardbus CIS tuples and vendor-specific data + * Atheros-specific data + * + * EEPROM entries are read 32-bits at a time through the PCI bus + * interface but are all 16-bit values. + * + * Access to the Atheros-specific data is controlled by protection + * bits and the data is checksum'd. The driver reads the Atheros + * data from the EEPROM at attach and caches it in its private state. + * This data includes the local regulatory domain, channel calibration + * settings, and phy-related configuration settings. + */ +#define AR_EEPROM_MAC(i) (0x1f-(i))/* MAC address word */ +#define AR_EEPROM_MAGIC 0x3d /* magic number */ +#define AR_EEPROM_PROTECT 0x3f /* Atheros segment protect register */ +#define AR_EEPROM_PROTOTECT_WP_128_191 0x80 +#define AR_EEPROM_REG_DOMAIN 0xbf /* Current regulatory domain register */ +#define AR_EEPROM_ATHEROS_BASE 0xc0 /* Base of Atheros-specific data */ +#define AR_EEPROM_ATHEROS_MAX 64 /* 64x2=128 bytes of EEPROM settings */ +#define AR_EEPROM_ATHEROS(n) (AR_EEPROM_ATHEROS_BASE+(n)) +#define AR_EEPROM_VERSION AR_EEPROM_ATHEROS(1) +#define AR_EEPROM_ATHEROS_TP_SETTINGS 0x09 /* Transmit power settings */ +#define AR_REG_DOMAINS_MAX 4 /* # of Regulatory Domains */ +#define AR_CHANNELS_MAX 5 /* # of Channel calibration groups */ +#define AR_TP_SETTINGS_SIZE 11 /* # locations/Channel group */ +#define AR_TP_SCALING_ENTRIES 11 /* # entries in transmit power dBm->pcdac */ + +/* + * NB: we store the rfsilent select+polarity data packed + * with the encoding used in later parts so values + * returned to applications are consistent. + */ +#define AR_EEPROM_RFSILENT_GPIO_SEL 0x001c +#define AR_EEPROM_RFSILENT_GPIO_SEL_S 2 +#define AR_EEPROM_RFSILENT_POLARITY 0x0002 +#define AR_EEPROM_RFSILENT_POLARITY_S 1 + +#define AR_I2DBM(x) ((uint8_t)((x * 2) + 3)) + +/* + * Transmit power and channel calibration settings. + */ +struct tpcMap { + uint8_t pcdac[AR_TP_SCALING_ENTRIES]; + uint8_t gainF[AR_TP_SCALING_ENTRIES]; + uint8_t rate36; + uint8_t rate48; + uint8_t rate54; + uint8_t regdmn[AR_REG_DOMAINS_MAX]; +}; + +/* + * Information retrieved from EEPROM. + */ +typedef struct { + uint16_t ee_version; /* Version field */ + uint16_t ee_protect; /* EEPROM protect field */ + uint16_t ee_antenna; /* Antenna Settings */ + uint16_t ee_biasCurrents; /* OB, DB */ + uint8_t ee_thresh62; /* thresh62 */ + uint8_t ee_xlnaOn; /* External LNA timing */ + uint8_t ee_xpaOff; /* Extern output stage timing */ + uint8_t ee_xpaOn; /* Extern output stage timing */ + uint8_t ee_rfKill; /* Single low bit signalling if RF Kill is implemented */ + uint8_t ee_devType; /* Type: PCI, miniPCI, CB */ + uint8_t ee_regDomain[AR_REG_DOMAINS_MAX]; + /* calibrated reg domains */ + struct tpcMap ee_tpc[AR_CHANNELS_MAX]; +} HAL_EEPROM_v1; +#endif /* _ATH_AH_EEPROM_V1_H_ */ --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ah_eeprom_v14.c 2009-03-23 17:36:56.000000000 +0000 @@ -0,0 +1,419 @@ +/* + * Copyright (c) 2008 Sam Leffler, Errno Consulting + * Copyright (c) 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: ah_eeprom_v14.c,v 1.1 2009/03/23 17:14:47 sborrill Exp $ + */ +#include +#include "opt_ah.h" + +#include "ah.h" +#include "ah_internal.h" +#include "ah_eeprom_v14.h" + +static HAL_STATUS +v14EepromGet(struct ath_hal *ah, int param, void *val) +{ +#define CHAN_A_IDX 0 +#define CHAN_B_IDX 1 +#define IS_VERS(op, v) ((pBase->version & AR5416_EEP_VER_MINOR_MASK) op (v)) + HAL_EEPROM_v14 *ee = AH_PRIVATE(ah)->ah_eeprom; + const MODAL_EEP_HEADER *pModal = ee->ee_base.modalHeader; + const BASE_EEP_HEADER *pBase = &ee->ee_base.baseEepHeader; + uint32_t sum; + uint8_t *macaddr; + int i; + + switch (param) { + case AR_EEP_NFTHRESH_5: + *(int16_t *)val = pModal[0].noiseFloorThreshCh[0]; + return HAL_OK; + case AR_EEP_NFTHRESH_2: + *(int16_t *)val = pModal[1].noiseFloorThreshCh[0]; + return HAL_OK; + case AR_EEP_MACADDR: /* Get MAC Address */ + sum = 0; + macaddr = val; + for (i = 0; i < 6; i++) { + macaddr[i] = pBase->macAddr[i]; + sum += pBase->macAddr[i]; + } + if (sum == 0 || sum == 0xffff*3) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad mac address %s\n", + __func__, ath_hal_ether_sprintf(macaddr)); + return HAL_EEBADMAC; + } else + return HAL_OK; + case AR_EEP_REGDMN_0: + return pBase->regDmn[0]; + case AR_EEP_REGDMN_1: + return pBase->regDmn[1]; + case AR_EEP_OPCAP: + return pBase->deviceCap; + case AR_EEP_OPMODE: + return pBase->opCapFlags; + case AR_EEP_RFSILENT: + return pBase->rfSilent; + case AR_EEP_OB_5: + return pModal[CHAN_A_IDX].ob; + case AR_EEP_DB_5: + return pModal[CHAN_A_IDX].db; + case AR_EEP_OB_2: + return pModal[CHAN_B_IDX].ob; + case AR_EEP_DB_2: + return pModal[CHAN_B_IDX].db; + case AR_EEP_TXMASK: + return pBase->txMask; + case AR_EEP_RXMASK: + return pBase->rxMask; + case AR_EEP_RXGAIN_TYPE: + return IS_VERS(>=, AR5416_EEP_MINOR_VER_17) ? + pBase->rxGainType : AR5416_EEP_RXGAIN_ORIG; + case AR_EEP_TXGAIN_TYPE: + return IS_VERS(>=, AR5416_EEP_MINOR_VER_19) ? + pBase->txGainType : AR5416_EEP_TXGAIN_ORIG; + case AR_EEP_FSTCLK_5G: + return IS_VERS(>, AR5416_EEP_MINOR_VER_16) ? + pBase->fastClk5g : AH_TRUE; + case AR_EEP_OL_PWRCTRL: + HALASSERT(val == AH_NULL); + return pBase->openLoopPwrCntl ? HAL_OK : HAL_EIO; + case AR_EEP_AMODE: + HALASSERT(val == AH_NULL); + return pBase->opCapFlags & AR5416_OPFLAGS_11A ? + HAL_OK : HAL_EIO; + case AR_EEP_BMODE: + case AR_EEP_GMODE: + HALASSERT(val == AH_NULL); + return pBase->opCapFlags & AR5416_OPFLAGS_11G ? + HAL_OK : HAL_EIO; + case AR_EEP_32KHZCRYSTAL: + case AR_EEP_COMPRESS: + case AR_EEP_FASTFRAME: /* XXX policy decision, h/w can do it */ + case AR_EEP_WRITEPROTECT: /* NB: no write protect bit */ + HALASSERT(val == AH_NULL); + /* fall thru... */ + case AR_EEP_MAXQCU: /* NB: not in opCapFlags */ + case AR_EEP_KCENTRIES: /* NB: not in opCapFlags */ + return HAL_EIO; + case AR_EEP_AES: + case AR_EEP_BURST: + case AR_EEP_RFKILL: + case AR_EEP_TURBO5DISABLE: + case AR_EEP_TURBO2DISABLE: + HALASSERT(val == AH_NULL); + return HAL_OK; + case AR_EEP_ANTGAINMAX_2: + *(int8_t *) val = ee->ee_antennaGainMax[1]; + return HAL_OK; + case AR_EEP_ANTGAINMAX_5: + *(int8_t *) val = ee->ee_antennaGainMax[0]; + return HAL_OK; + default: + HALASSERT(0); + return HAL_EINVAL; + } +#undef IS_VERS +#undef CHAN_A_IDX +#undef CHAN_B_IDX +} + +static HAL_BOOL +v14EepromSet(struct ath_hal *ah, int param, int v) +{ + HAL_EEPROM_v14 *ee = AH_PRIVATE(ah)->ah_eeprom; + + switch (param) { + case AR_EEP_ANTGAINMAX_2: + ee->ee_antennaGainMax[1] = (int8_t) v; + return HAL_OK; + case AR_EEP_ANTGAINMAX_5: + ee->ee_antennaGainMax[0] = (int8_t) v; + return HAL_OK; + } + return HAL_EINVAL; +} + +static HAL_BOOL +v14EepromDiag(struct ath_hal *ah, int request, + const void *args, uint32_t argsize, void **result, uint32_t *resultsize) +{ + HAL_EEPROM_v14 *ee = AH_PRIVATE(ah)->ah_eeprom; + + switch (request) { + case HAL_DIAG_EEPROM: + *result = &ee->ee_base; + *resultsize = sizeof(ee->ee_base); + return AH_TRUE; + } + return AH_FALSE; +} + +#if 0 +/* XXX conditionalize by target byte order */ +#ifndef bswap16 +static __inline__ uint16_t +__bswap16(uint16_t _x) +{ + return ((uint16_t)( + (((const uint8_t *)(&_x))[0] ) | + (((const uint8_t *)(&_x))[1]<< 8)) + ); +} +#endif +#endif + +/* Do structure specific swaps if Eeprom format is non native to host */ +static void +eepromSwap(struct ar5416eeprom *ee) +{ + uint32_t integer, i, j; + uint16_t word; + MODAL_EEP_HEADER *pModal; + + /* convert Base Eep header */ + word = __bswap16(ee->baseEepHeader.length); + ee->baseEepHeader.length = word; + + word = __bswap16(ee->baseEepHeader.checksum); + ee->baseEepHeader.checksum = word; + + word = __bswap16(ee->baseEepHeader.version); + ee->baseEepHeader.version = word; + + word = __bswap16(ee->baseEepHeader.regDmn[0]); + ee->baseEepHeader.regDmn[0] = word; + + word = __bswap16(ee->baseEepHeader.regDmn[1]); + ee->baseEepHeader.regDmn[1] = word; + + word = __bswap16(ee->baseEepHeader.rfSilent); + ee->baseEepHeader.rfSilent = word; + + word = __bswap16(ee->baseEepHeader.blueToothOptions); + ee->baseEepHeader.blueToothOptions = word; + + word = __bswap16(ee->baseEepHeader.deviceCap); + ee->baseEepHeader.deviceCap = word; + + /* convert Modal Eep header */ + for (j = 0; j < 2; j++) { + pModal = &ee->modalHeader[j]; + + /* XXX linux/ah_osdep.h only defines __bswap32 for BE */ + integer = __bswap32(pModal->antCtrlCommon); + pModal->antCtrlCommon = integer; + + for (i = 0; i < AR5416_MAX_CHAINS; i++) { + integer = __bswap32(pModal->antCtrlChain[i]); + pModal->antCtrlChain[i] = integer; + } + + for (i = 0; i < AR5416_EEPROM_MODAL_SPURS; i++) { + word = __bswap16(pModal->spurChans[i].spurChan); + pModal->spurChans[i].spurChan = word; + } + } +} + +static uint16_t +v14EepromGetSpurChan(struct ath_hal *ah, int ix, HAL_BOOL is2GHz) +{ + HAL_EEPROM_v14 *ee = AH_PRIVATE(ah)->ah_eeprom; + + HALASSERT(0 <= ix && ix < AR5416_EEPROM_MODAL_SPURS); + return ee->ee_base.modalHeader[is2GHz].spurChans[ix].spurChan; +} + +/************************************************************************** + * fbin2freq + * + * Get channel value from binary representation held in eeprom + * RETURNS: the frequency in MHz + */ +static uint16_t +fbin2freq(uint8_t fbin, HAL_BOOL is2GHz) +{ + /* + * Reserved value 0xFF provides an empty definition both as + * an fbin and as a frequency - do not convert + */ + if (fbin == AR5416_BCHAN_UNUSED) + return fbin; + return (uint16_t)((is2GHz) ? (2300 + fbin) : (4800 + 5 * fbin)); +} + +/* + * Copy EEPROM Conformance Testing Limits contents + * into the allocated space + */ +/* USE CTLS from chain zero */ +#define CTL_CHAIN 0 + +static void +v14EepromReadCTLInfo(struct ath_hal *ah, HAL_EEPROM_v14 *ee) +{ + RD_EDGES_POWER *rep = ee->ee_rdEdgesPower; + int i, j; + + HALASSERT(AR5416_NUM_CTLS <= sizeof(ee->ee_rdEdgesPower)/NUM_EDGES); + + for (i = 0; ee->ee_base.ctlIndex[i] != 0 && i < AR5416_NUM_CTLS; i++) { + for (j = 0; j < NUM_EDGES; j ++) { + /* XXX Confirm this is the right thing to do when an invalid channel is stored */ + if (ee->ee_base.ctlData[i].ctlEdges[CTL_CHAIN][j].bChannel == AR5416_BCHAN_UNUSED) { + rep[j].rdEdge = 0; + rep[j].twice_rdEdgePower = 0; + rep[j].flag = 0; + } else { + rep[j].rdEdge = fbin2freq( + ee->ee_base.ctlData[i].ctlEdges[CTL_CHAIN][j].bChannel, + (ee->ee_base.ctlIndex[i] & CTL_MODE_M) != CTL_11A); + rep[j].twice_rdEdgePower = MS(ee->ee_base.ctlData[i].ctlEdges[CTL_CHAIN][j].tPowerFlag, CAL_CTL_EDGES_POWER); + rep[j].flag = MS(ee->ee_base.ctlData[i].ctlEdges[CTL_CHAIN][j].tPowerFlag, CAL_CTL_EDGES_FLAG) != 0; + } + } + rep += NUM_EDGES; + } + ee->ee_numCtls = i; + HALDEBUG(ah, HAL_DEBUG_ATTACH | HAL_DEBUG_EEPROM, + "%s Numctls = %u\n",__func__,i); +} + +/* + * Reclaim any EEPROM-related storage. + */ +static void +v14EepromDetach(struct ath_hal *ah) +{ + HAL_EEPROM_v14 *ee = AH_PRIVATE(ah)->ah_eeprom; + + ath_hal_free(ee); + AH_PRIVATE(ah)->ah_eeprom = AH_NULL; +} + +#define owl_get_eep_ver(_ee) \ + (((_ee)->ee_base.baseEepHeader.version >> 12) & 0xF) +#define owl_get_eep_rev(_ee) \ + (((_ee)->ee_base.baseEepHeader.version) & 0xFFF) + +HAL_STATUS +ath_hal_v14EepromAttach(struct ath_hal *ah) +{ +#define NW(a) (sizeof(a) / sizeof(uint16_t)) + HAL_EEPROM_v14 *ee = AH_PRIVATE(ah)->ah_eeprom; + uint16_t *eep_data, magic; + HAL_BOOL need_swap; + u_int w, off, len; + uint32_t sum; + + HALASSERT(ee == AH_NULL); + + if (!ath_hal_eepromRead(ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s Error reading Eeprom MAGIC\n", __func__); + return HAL_EEREAD; + } + HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s Eeprom Magic = 0x%x\n", + __func__, magic); + if (magic != AR5416_EEPROM_MAGIC) { + HALDEBUG(ah, HAL_DEBUG_ANY, "Bad magic number\n"); + return HAL_EEMAGIC; + } + + ee = ath_hal_malloc(sizeof(HAL_EEPROM_v14)); + if (ee == AH_NULL) { + /* XXX message */ + return HAL_ENOMEM; + } + + eep_data = (uint16_t *)&ee->ee_base; + for (w = 0; w < NW(struct ar5416eeprom); w++) { + off = owl_eep_start_loc + w; /* NB: AP71 starts at 0 */ + if (!ath_hal_eepromRead(ah, off, &eep_data[w])) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s eeprom read error at offset 0x%x\n", + __func__, off); + return HAL_EEREAD; + } + } + /* Convert to eeprom native eeprom endian format */ + if (isBigEndian()) { + for (w = 0; w < NW(struct ar5416eeprom); w++) + eep_data[w] = __bswap16(eep_data[w]); + } + + /* + * At this point, we're in the native eeprom endian format + * Now, determine the eeprom endian by looking at byte 26?? + */ + need_swap = ((ee->ee_base.baseEepHeader.eepMisc & AR5416_EEPMISC_BIG_ENDIAN) != 0) ^ isBigEndian(); + if (need_swap) { + HALDEBUG(ah, HAL_DEBUG_ATTACH | HAL_DEBUG_EEPROM, + "Byte swap EEPROM contents.\n"); + len = __bswap16(ee->ee_base.baseEepHeader.length); + } else { + len = ee->ee_base.baseEepHeader.length; + } + len = AH_MIN(len, sizeof(struct ar5416eeprom)) / sizeof(uint16_t); + + /* Apply the checksum, done in native eeprom format */ + /* XXX - Need to check to make sure checksum calculation is done + * in the correct endian format. Right now, it seems it would + * cast the raw data to host format and do the calculation, which may + * not be correct as the calculation may need to be done in the native + * eeprom format + */ + sum = 0; + for (w = 0; w < len; w++) + sum ^= eep_data[w]; + /* Check CRC - Attach should fail on a bad checksum */ + if (sum != 0xffff) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "Bad EEPROM checksum 0x%x (Len=%u)\n", sum, len); + return HAL_EEBADSUM; + } + + if (need_swap) + eepromSwap(&ee->ee_base); /* byte swap multi-byte data */ + + /* swap words 0+2 so version is at the front */ + magic = eep_data[0]; + eep_data[0] = eep_data[2]; + eep_data[2] = magic; + + HALDEBUG(ah, HAL_DEBUG_ATTACH | HAL_DEBUG_EEPROM, + "%s Eeprom Version %u.%u\n", __func__, + owl_get_eep_ver(ee), owl_get_eep_rev(ee)); + + /* NB: must be after all byte swapping */ + if (owl_get_eep_ver(ee) != AR5416_EEP_VER) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "Bad EEPROM version 0x%x\n", owl_get_eep_ver(ee)); + return HAL_EEBADSUM; + } + + v14EepromReadCTLInfo(ah, ee); /* Get CTLs */ + + AH_PRIVATE(ah)->ah_eeprom = ee; + AH_PRIVATE(ah)->ah_eeversion = ee->ee_base.baseEepHeader.version; + AH_PRIVATE(ah)->ah_eepromDetach = v14EepromDetach; + AH_PRIVATE(ah)->ah_eepromGet = v14EepromGet; + AH_PRIVATE(ah)->ah_eepromSet = v14EepromSet; + AH_PRIVATE(ah)->ah_getSpurChan = v14EepromGetSpurChan; + AH_PRIVATE(ah)->ah_eepromDiag = v14EepromDiag; + return HAL_OK; +#undef NW +} --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ah_eeprom_v14.h 2009-03-23 17:36:56.000000000 +0000 @@ -0,0 +1,271 @@ +/* + * Copyright (c) 2008 Sam Leffler, Errno Consulting + * Copyright (c) 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: ah_eeprom_v14.h,v 1.1 2009/03/23 17:14:47 sborrill Exp $ + */ +#ifndef _AH_EEPROM_V14_H_ +#define _AH_EEPROM_V14_H_ + +#include "ah_eeprom.h" + +/* reg_off = 4 * (eep_off) */ +#define AR5416_EEPROM_S 2 +#define AR5416_EEPROM_OFFSET 0x2000 +#define AR5416_EEPROM_START_ADDR 0x503f1200 +#define AR5416_EEPROM_MAX 0xae0 /* Ignore for the moment used only on the flash implementations */ +#define AR5416_EEPROM_MAGIC 0xa55a +#define AR5416_EEPROM_MAGIC_OFFSET 0x0 + +#define owl_get_ntxchains(_txchainmask) \ + (((_txchainmask >> 2) & 1) + ((_txchainmask >> 1) & 1) + (_txchainmask & 1)) + +#ifdef __LINUX_ARM_ARCH__ /* AP71 */ +#define owl_eep_start_loc 0 +#else +#define owl_eep_start_loc 256 +#endif + +/* End temp defines */ + +#define AR5416_EEP_NO_BACK_VER 0x1 +#define AR5416_EEP_VER 0xE +#define AR5416_EEP_VER_MINOR_MASK 0xFFF +// Adds modal params txFrameToPaOn, txFrametoDataStart, ht40PowerInc +#define AR5416_EEP_MINOR_VER_2 0x2 +// Adds modal params bswAtten, bswMargin, swSettle and base OpFlags for HT20/40 Disable +#define AR5416_EEP_MINOR_VER_3 0x3 +#define AR5416_EEP_MINOR_VER_7 0x7 +#define AR5416_EEP_MINOR_VER_9 0x9 +#define AR5416_EEP_MINOR_VER_16 0x10 +#define AR5416_EEP_MINOR_VER_17 0x11 +#define AR5416_EEP_MINOR_VER_19 0x13 + +// 16-bit offset location start of calibration struct +#define AR5416_EEP_START_LOC 256 +#define AR5416_NUM_5G_CAL_PIERS 8 +#define AR5416_NUM_2G_CAL_PIERS 4 +#define AR5416_NUM_5G_20_TARGET_POWERS 8 +#define AR5416_NUM_5G_40_TARGET_POWERS 8 +#define AR5416_NUM_2G_CCK_TARGET_POWERS 3 +#define AR5416_NUM_2G_20_TARGET_POWERS 4 +#define AR5416_NUM_2G_40_TARGET_POWERS 4 +#define AR5416_NUM_CTLS 24 +#define AR5416_NUM_BAND_EDGES 8 +#define AR5416_NUM_PD_GAINS 4 +#define AR5416_PD_GAINS_IN_MASK 4 +#define AR5416_PD_GAIN_ICEPTS 5 +#define AR5416_EEPROM_MODAL_SPURS 5 +#define AR5416_MAX_RATE_POWER 63 +#define AR5416_NUM_PDADC_VALUES 128 +#define AR5416_NUM_RATES 16 +#define AR5416_BCHAN_UNUSED 0xFF +#define AR5416_MAX_PWR_RANGE_IN_HALF_DB 64 +#define AR5416_EEPMISC_BIG_ENDIAN 0x01 +#define FREQ2FBIN(x,y) ((y) ? ((x) - 2300) : (((x) - 4800) / 5)) +#define AR5416_MAX_CHAINS 3 +#define AR5416_ANT_16S 25 + +#define AR5416_NUM_ANT_CHAIN_FIELDS 7 +#define AR5416_NUM_ANT_COMMON_FIELDS 4 +#define AR5416_SIZE_ANT_CHAIN_FIELD 3 +#define AR5416_SIZE_ANT_COMMON_FIELD 4 +#define AR5416_ANT_CHAIN_MASK 0x7 +#define AR5416_ANT_COMMON_MASK 0xf +#define AR5416_CHAIN_0_IDX 0 +#define AR5416_CHAIN_1_IDX 1 +#define AR5416_CHAIN_2_IDX 2 + +#define AR5416_OPFLAGS_11A 0x01 +#define AR5416_OPFLAGS_11G 0x02 +#define AR5416_OPFLAGS_5G_HT40 0x04 +#define AR5416_OPFLAGS_2G_HT40 0x08 +#define AR5416_OPFLAGS_5G_HT20 0x10 +#define AR5416_OPFLAGS_2G_HT20 0x20 + +/* RF silent fields in EEPROM */ +#define EEP_RFSILENT_ENABLED 0x0001 /* enabled/disabled */ +#define EEP_RFSILENT_ENABLED_S 0 +#define EEP_RFSILENT_POLARITY 0x0002 /* polarity */ +#define EEP_RFSILENT_POLARITY_S 1 +#define EEP_RFSILENT_GPIO_SEL 0x001c /* gpio PIN */ +#define EEP_RFSILENT_GPIO_SEL_S 2 + +/* Rx gain type values */ +#define AR5416_EEP_RXGAIN_23dB_BACKOFF 0 +#define AR5416_EEP_RXGAIN_13dB_BACKOFF 1 +#define AR5416_EEP_RXGAIN_ORIG 2 + +/* Tx gain type values */ +#define AR5416_EEP_TXGAIN_ORIG 0 +#define AR5416_EEP_TXGAIN_HIGH_POWER 1 + +typedef struct spurChanStruct { + uint16_t spurChan; + uint8_t spurRangeLow; + uint8_t spurRangeHigh; +} __packed SPUR_CHAN; + +typedef struct CalTargetPowerLegacy { + uint8_t bChannel; + uint8_t tPow2x[4]; +} __packed CAL_TARGET_POWER_LEG; + +typedef struct CalTargetPowerHt { + uint8_t bChannel; + uint8_t tPow2x[8]; +} __packed CAL_TARGET_POWER_HT; + +typedef struct CalCtlEdges { + uint8_t bChannel; + uint8_t tPowerFlag; /* [0..5] tPower [6..7] flag */ +#define CAL_CTL_EDGES_POWER 0x3f +#define CAL_CTL_EDGES_POWER_S 0 +#define CAL_CTL_EDGES_FLAG 0xc0 +#define CAL_CTL_EDGES_FLAG_S 6 +} __packed CAL_CTL_EDGES; + +/* + * NB: The format in EEPROM has words 0 and 2 swapped (i.e. version + * and length are swapped). We reverse their position after reading + * the data into host memory so the version field is at the same + * offset as in previous EEPROM layouts. This makes utilities that + * inspect the EEPROM contents work without looking at the PCI device + * id which may or may not be reliable. + */ +typedef struct BaseEepHeader { + uint16_t version; /* NB: length in EEPROM */ + uint16_t checksum; + uint16_t length; /* NB: version in EEPROM */ + uint8_t opCapFlags; + uint8_t eepMisc; + uint16_t regDmn[2]; + uint8_t macAddr[6]; + uint8_t rxMask; + uint8_t txMask; + uint16_t rfSilent; + uint16_t blueToothOptions; + uint16_t deviceCap; + uint32_t binBuildNumber; + uint8_t deviceType; + uint8_t pwdclkind; + uint8_t fastClk5g; + uint8_t divChain; + uint8_t rxGainType; + uint8_t dacHiPwrMode; /* use the DAC high power mode (MB91) */ + uint8_t openLoopPwrCntl;/* 1: use open loop power control, + 0: use closed loop power control */ + uint8_t dacLpMode; + uint8_t txGainType; /* high power tx gain table support */ + uint8_t rcChainMask; /* "1" if the card is an HB93 1x2 */ + uint8_t futureBase[24]; +} __packed BASE_EEP_HEADER; // 64 B + +typedef struct ModalEepHeader { + uint32_t antCtrlChain[AR5416_MAX_CHAINS]; // 12 + uint32_t antCtrlCommon; // 4 + int8_t antennaGainCh[AR5416_MAX_CHAINS]; // 3 + uint8_t switchSettling; // 1 + uint8_t txRxAttenCh[AR5416_MAX_CHAINS]; // 3 + uint8_t rxTxMarginCh[AR5416_MAX_CHAINS]; // 3 + uint8_t adcDesiredSize; // 1 + int8_t pgaDesiredSize; // 1 + uint8_t xlnaGainCh[AR5416_MAX_CHAINS]; // 3 + uint8_t txEndToXpaOff; // 1 + uint8_t txEndToRxOn; // 1 + uint8_t txFrameToXpaOn; // 1 + uint8_t thresh62; // 1 + uint8_t noiseFloorThreshCh[AR5416_MAX_CHAINS]; // 3 + uint8_t xpdGain; // 1 + uint8_t xpd; // 1 + int8_t iqCalICh[AR5416_MAX_CHAINS]; // 1 + int8_t iqCalQCh[AR5416_MAX_CHAINS]; // 1 + uint8_t pdGainOverlap; // 1 + uint8_t ob; // 1 + uint8_t db; // 1 + uint8_t xpaBiasLvl; // 1 + uint8_t pwrDecreaseFor2Chain; // 1 + uint8_t pwrDecreaseFor3Chain; // 1 -> 48 B + uint8_t txFrameToDataStart; // 1 + uint8_t txFrameToPaOn; // 1 + uint8_t ht40PowerIncForPdadc; // 1 + uint8_t bswAtten[AR5416_MAX_CHAINS]; // 3 + uint8_t bswMargin[AR5416_MAX_CHAINS]; // 3 + uint8_t swSettleHt40; // 1 + uint8_t xatten2Db[AR5416_MAX_CHAINS]; // 3 -> New for AR9280 (0xa20c/b20c 11:6) + uint8_t xatten2Margin[AR5416_MAX_CHAINS]; // 3 -> New for AR9280 (0xa20c/b20c 21:17) + uint8_t ob_ch1; // 1 -> ob and db become chain specific from AR9280 + uint8_t db_ch1; // 1 + uint8_t flagBits; // 1 +#define AR5416_EEP_FLAG_USEANT1 0x01 /* +1 configured antenna */ +#define AR5416_EEP_FLAG_FORCEXPAON 0x02 /* force XPA bit for 5G */ +#define AR5416_EEP_FLAG_LOCALBIAS 0x04 /* enable local bias */ +#define AR5416_EEP_FLAG_FEMBANDSELECT 0x08 /* FEM band select used */ +#define AR5416_EEP_FLAG_XLNABUFIN 0x10 +#define AR5416_EEP_FLAG_XLNAISEL 0x60 +#define AR5416_EEP_FLAG_XLNAISEL_S 5 +#define AR5416_EEP_FLAG_XLNABUFMODE 0x80 + uint8_t miscBits; // [0..1]: bb_tx_dac_scale_cck + uint16_t xpaBiasLvlFreq[3]; // 3 + uint8_t futureModal[6]; // 6 + + SPUR_CHAN spurChans[AR5416_EEPROM_MODAL_SPURS]; // 20 B +} __packed MODAL_EEP_HEADER; // == 100 B + +typedef struct calDataPerFreqOpLoop { + uint8_t pwrPdg[2][5]; /* power measurement */ + uint8_t vpdPdg[2][5]; /* pdadc voltage at power measurement */ + uint8_t pcdac[2][5]; /* pcdac used for power measurement */ + uint8_t empty[2][5]; /* future use */ +} __packed CAL_DATA_PER_FREQ_OP_LOOP; + +typedef struct CalCtlData { + CAL_CTL_EDGES ctlEdges[AR5416_MAX_CHAINS][AR5416_NUM_BAND_EDGES]; +} __packed CAL_CTL_DATA; + +typedef struct calDataPerFreq { + uint8_t pwrPdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS]; + uint8_t vpdPdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS]; +} __packed CAL_DATA_PER_FREQ; + +struct ar5416eeprom { + BASE_EEP_HEADER baseEepHeader; // 64 B + uint8_t custData[64]; // 64 B + MODAL_EEP_HEADER modalHeader[2]; // 200 B + uint8_t calFreqPier5G[AR5416_NUM_5G_CAL_PIERS]; + uint8_t calFreqPier2G[AR5416_NUM_2G_CAL_PIERS]; + CAL_DATA_PER_FREQ calPierData5G[AR5416_MAX_CHAINS][AR5416_NUM_5G_CAL_PIERS]; + CAL_DATA_PER_FREQ calPierData2G[AR5416_MAX_CHAINS][AR5416_NUM_2G_CAL_PIERS]; + CAL_TARGET_POWER_LEG calTargetPower5G[AR5416_NUM_5G_20_TARGET_POWERS]; + CAL_TARGET_POWER_HT calTargetPower5GHT20[AR5416_NUM_5G_20_TARGET_POWERS]; + CAL_TARGET_POWER_HT calTargetPower5GHT40[AR5416_NUM_5G_40_TARGET_POWERS]; + CAL_TARGET_POWER_LEG calTargetPowerCck[AR5416_NUM_2G_CCK_TARGET_POWERS]; + CAL_TARGET_POWER_LEG calTargetPower2G[AR5416_NUM_2G_20_TARGET_POWERS]; + CAL_TARGET_POWER_HT calTargetPower2GHT20[AR5416_NUM_2G_20_TARGET_POWERS]; + CAL_TARGET_POWER_HT calTargetPower2GHT40[AR5416_NUM_2G_40_TARGET_POWERS]; + uint8_t ctlIndex[AR5416_NUM_CTLS]; + CAL_CTL_DATA ctlData[AR5416_NUM_CTLS]; + uint8_t padding; +} __packed; + +typedef struct { + struct ar5416eeprom ee_base; +#define NUM_EDGES 8 + uint16_t ee_numCtls; + RD_EDGES_POWER ee_rdEdgesPower[NUM_EDGES*AR5416_NUM_CTLS]; + /* XXX these are dynamically calculated for use by shared code */ + int8_t ee_antennaGainMax[2]; +} HAL_EEPROM_v14; +#endif /* _AH_EEPROM_V14_H_ */ --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ah_eeprom_v3.c 2009-03-23 17:36:56.000000000 +0000 @@ -0,0 +1,1876 @@ +/* + * 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: ah_eeprom_v3.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" + +static void +getPcdacInterceptsFromPcdacMinMax(HAL_EEPROM *ee, + uint16_t pcdacMin, uint16_t pcdacMax, uint16_t *vp) +{ + static const uint16_t intercepts3[] = + { 0, 5, 10, 20, 30, 50, 70, 85, 90, 95, 100 }; + static const uint16_t intercepts3_2[] = + { 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 }; + const uint16_t *ip = ee->ee_version < AR_EEPROM_VER3_2 ? + intercepts3 : intercepts3_2; + int i; + + /* loop for the percentages in steps or 5 */ + for (i = 0; i < NUM_INTERCEPTS; i++ ) + *vp++ = (ip[i] * pcdacMax + (100 - ip[i]) * pcdacMin) / 100; +} + +/* + * Get channel value from binary representation held in eeprom + */ +static uint16_t +fbin2freq(HAL_EEPROM *ee, uint16_t fbin) +{ + if (fbin == CHANNEL_UNUSED) /* reserved value, don't convert */ + return fbin; + return ee->ee_version <= AR_EEPROM_VER3_2 ? + (fbin > 62 ? 5100 + 10*62 + 5*(fbin-62) : 5100 + 10*fbin) : + 4800 + 5*fbin; +} + +static uint16_t +fbin2freq_2p4(HAL_EEPROM *ee, uint16_t fbin) +{ + if (fbin == CHANNEL_UNUSED) /* reserved value, don't convert */ + return fbin; + return ee->ee_version <= AR_EEPROM_VER3_2 ? + 2400 + fbin : + 2300 + fbin; +} + +/* + * Now copy EEPROM frequency pier contents into the allocated space + */ +static HAL_BOOL +readEepromFreqPierInfo(struct ath_hal *ah, HAL_EEPROM *ee) +{ +#define EEREAD(_off) do { \ + if (!ath_hal_eepromRead(ah, _off, &eeval)) \ + return AH_FALSE; \ +} while (0) + uint16_t eeval, off; + int i; + + if (ee->ee_version >= AR_EEPROM_VER4_0 && + ee->ee_eepMap && !ee->ee_Amode) { + /* + * V4.0 EEPROMs with map type 1 have frequency pier + * data only when 11a mode is supported. + */ + return AH_TRUE; + } + if (ee->ee_version >= AR_EEPROM_VER3_3) { + off = GROUPS_OFFSET3_3 + GROUP1_OFFSET; + for (i = 0; i < ee->ee_numChannels11a; i += 2) { + EEREAD(off++); + ee->ee_channels11a[i] = (eeval >> 8) & FREQ_MASK_3_3; + ee->ee_channels11a[i+1] = eeval & FREQ_MASK_3_3; + } + } else { + off = GROUPS_OFFSET3_2 + GROUP1_OFFSET; + + EEREAD(off++); + ee->ee_channels11a[0] = (eeval >> 9) & FREQ_MASK; + ee->ee_channels11a[1] = (eeval >> 2) & FREQ_MASK; + ee->ee_channels11a[2] = (eeval << 5) & FREQ_MASK; + + EEREAD(off++); + ee->ee_channels11a[2] |= (eeval >> 11) & 0x1f; + ee->ee_channels11a[3] = (eeval >> 4) & FREQ_MASK; + ee->ee_channels11a[4] = (eeval << 3) & FREQ_MASK; + + EEREAD(off++); + ee->ee_channels11a[4] |= (eeval >> 13) & 0x7; + ee->ee_channels11a[5] = (eeval >> 6) & FREQ_MASK; + ee->ee_channels11a[6] = (eeval << 1) & FREQ_MASK; + + EEREAD(off++); + ee->ee_channels11a[6] |= (eeval >> 15) & 0x1; + ee->ee_channels11a[7] = (eeval >> 8) & FREQ_MASK; + ee->ee_channels11a[8] = (eeval >> 1) & FREQ_MASK; + ee->ee_channels11a[9] = (eeval << 6) & FREQ_MASK; + + EEREAD(off++); + ee->ee_channels11a[9] |= (eeval >> 10) & 0x3f; + } + + for (i = 0; i < ee->ee_numChannels11a; i++) + ee->ee_channels11a[i] = fbin2freq(ee, ee->ee_channels11a[i]); + + return AH_TRUE; +#undef EEREAD +} + +/* + * Rev 4 Eeprom 5112 Power Extract Functions + */ + +/* + * Allocate the power information based on the number of channels + * recorded by the calibration. These values are then initialized. + */ +static HAL_BOOL +eepromAllocExpnPower5112(struct ath_hal *ah, + const EEPROM_POWER_5112 *pCalDataset, + EEPROM_POWER_EXPN_5112 *pPowerExpn) +{ + uint16_t numChannels = pCalDataset->numChannels; + const uint16_t *pChanList = pCalDataset->pChannels; + void *data; + int i, j; + + /* Allocate the channel and Power Data arrays together */ + data = ath_hal_malloc( + roundup(sizeof(uint16_t) * numChannels, sizeof(uint32_t)) + + sizeof(EXPN_DATA_PER_CHANNEL_5112) * numChannels); + if (data == AH_NULL) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s unable to allocate raw data struct (gen3)\n", __func__); + return AH_FALSE; + } + pPowerExpn->pChannels = data; + pPowerExpn->pDataPerChannel = (void *)(((char *)data) + + roundup(sizeof(uint16_t) * numChannels, sizeof(uint32_t))); + + pPowerExpn->numChannels = numChannels; + for (i = 0; i < numChannels; i++) { + pPowerExpn->pChannels[i] = + pPowerExpn->pDataPerChannel[i].channelValue = + pChanList[i]; + for (j = 0; j < NUM_XPD_PER_CHANNEL; j++) { + pPowerExpn->pDataPerChannel[i].pDataPerXPD[j].xpd_gain = j; + pPowerExpn->pDataPerChannel[i].pDataPerXPD[j].numPcdacs = 0; + } + pPowerExpn->pDataPerChannel[i].pDataPerXPD[0].numPcdacs = 4; + pPowerExpn->pDataPerChannel[i].pDataPerXPD[3].numPcdacs = 3; + } + return AH_TRUE; +} + +/* + * Expand the dataSet from the calibration information into the + * final power structure for 5112 + */ +static HAL_BOOL +eepromExpandPower5112(struct ath_hal *ah, + const EEPROM_POWER_5112 *pCalDataset, + EEPROM_POWER_EXPN_5112 *pPowerExpn) +{ + int ii, jj, kk; + int16_t maxPower_t4; + EXPN_DATA_PER_XPD_5112 *pExpnXPD; + /* ptr to array of info held per channel */ + const EEPROM_DATA_PER_CHANNEL_5112 *pCalCh; + uint16_t xgainList[2], xpdMask; + + pPowerExpn->xpdMask = pCalDataset->xpdMask; + + 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, + "%s: too many xpdGains in dataset: %u\n", + __func__, kk); + return AH_FALSE; + } + xgainList[kk++] = jj; + } + } + + pPowerExpn->numChannels = pCalDataset->numChannels; + if (pPowerExpn->numChannels == 0) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: no channels\n", __func__); + return AH_FALSE; + } + + for (ii = 0; ii < pPowerExpn->numChannels; ii++) { + pCalCh = &pCalDataset->pDataPerChannel[ii]; + pPowerExpn->pDataPerChannel[ii].channelValue = + pCalCh->channelValue; + pPowerExpn->pDataPerChannel[ii].maxPower_t4 = + pCalCh->maxPower_t4; + maxPower_t4 = pPowerExpn->pDataPerChannel[ii].maxPower_t4; + + for (jj = 0; jj < NUM_XPD_PER_CHANNEL; jj++) + pPowerExpn->pDataPerChannel[ii].pDataPerXPD[jj].numPcdacs = 0; + if (xgainList[1] == 0xDEAD) { + jj = xgainList[0]; + pExpnXPD = &pPowerExpn->pDataPerChannel[ii].pDataPerXPD[jj]; + pExpnXPD->numPcdacs = 4; + pExpnXPD->pcdac[0] = pCalCh->pcd1_xg0; + pExpnXPD->pcdac[1] = (uint16_t) + (pExpnXPD->pcdac[0] + pCalCh->pcd2_delta_xg0); + pExpnXPD->pcdac[2] = (uint16_t) + (pExpnXPD->pcdac[1] + pCalCh->pcd3_delta_xg0); + pExpnXPD->pcdac[3] = (uint16_t) + (pExpnXPD->pcdac[2] + pCalCh->pcd4_delta_xg0); + + pExpnXPD->pwr_t4[0] = pCalCh->pwr1_xg0; + pExpnXPD->pwr_t4[1] = pCalCh->pwr2_xg0; + pExpnXPD->pwr_t4[2] = pCalCh->pwr3_xg0; + pExpnXPD->pwr_t4[3] = pCalCh->pwr4_xg0; + + } else { + pPowerExpn->pDataPerChannel[ii].pDataPerXPD[xgainList[0]].pcdac[0] = pCalCh->pcd1_xg0; + pPowerExpn->pDataPerChannel[ii].pDataPerXPD[xgainList[1]].pcdac[0] = 20; + pPowerExpn->pDataPerChannel[ii].pDataPerXPD[xgainList[1]].pcdac[1] = 35; + pPowerExpn->pDataPerChannel[ii].pDataPerXPD[xgainList[1]].pcdac[2] = 63; + + jj = xgainList[0]; + pExpnXPD = &pPowerExpn->pDataPerChannel[ii].pDataPerXPD[jj]; + pExpnXPD->numPcdacs = 4; + pExpnXPD->pcdac[1] = (uint16_t) + (pExpnXPD->pcdac[0] + pCalCh->pcd2_delta_xg0); + pExpnXPD->pcdac[2] = (uint16_t) + (pExpnXPD->pcdac[1] + pCalCh->pcd3_delta_xg0); + pExpnXPD->pcdac[3] = (uint16_t) + (pExpnXPD->pcdac[2] + pCalCh->pcd4_delta_xg0); + pExpnXPD->pwr_t4[0] = pCalCh->pwr1_xg0; + pExpnXPD->pwr_t4[1] = pCalCh->pwr2_xg0; + pExpnXPD->pwr_t4[2] = pCalCh->pwr3_xg0; + pExpnXPD->pwr_t4[3] = pCalCh->pwr4_xg0; + + jj = xgainList[1]; + pExpnXPD = &pPowerExpn->pDataPerChannel[ii].pDataPerXPD[jj]; + pExpnXPD->numPcdacs = 3; + + pExpnXPD->pwr_t4[0] = pCalCh->pwr1_xg3; + pExpnXPD->pwr_t4[1] = pCalCh->pwr2_xg3; + pExpnXPD->pwr_t4[2] = pCalCh->pwr3_xg3; + } + } + return AH_TRUE; +} + +static HAL_BOOL +readEepromRawPowerCalInfo5112(struct ath_hal *ah, HAL_EEPROM *ee) +{ +#define EEREAD(_off) do { \ + if (!ath_hal_eepromRead(ah, _off, &eeval)) \ + return AH_FALSE; \ +} while (0) + const uint16_t dbmmask = 0xff; + const uint16_t pcdac_delta_mask = 0x1f; + const uint16_t pcdac_mask = 0x3f; + const uint16_t freqmask = 0xff; + + int i, mode, numPiers; + uint32_t off; + uint16_t eeval; + uint16_t freq[NUM_11A_EEPROM_CHANNELS]; + EEPROM_POWER_5112 eePower; + + HALASSERT(ee->ee_version >= AR_EEPROM_VER4_0); + off = GROUPS_OFFSET3_3; + for (mode = headerInfo11A; mode <= headerInfo11G; mode++) { + numPiers = 0; + switch (mode) { + case headerInfo11A: + if (!ee->ee_Amode) /* no 11a calibration data */ + continue; + while (numPiers < NUM_11A_EEPROM_CHANNELS) { + EEREAD(off++); + if ((eeval & freqmask) == 0) + break; + freq[numPiers++] = fbin2freq(ee, + eeval & freqmask); + + if (((eeval >> 8) & freqmask) == 0) + break; + freq[numPiers++] = fbin2freq(ee, + (eeval>>8) & freqmask); + } + break; + case headerInfo11B: + if (!ee->ee_Bmode) /* no 11b calibration data */ + continue; + for (i = 0; i < NUM_2_4_EEPROM_CHANNELS; i++) + if (ee->ee_calPier11b[i] != CHANNEL_UNUSED) + freq[numPiers++] = ee->ee_calPier11b[i]; + break; + case headerInfo11G: + if (!ee->ee_Gmode) /* no 11g calibration data */ + continue; + for (i = 0; i < NUM_2_4_EEPROM_CHANNELS; i++) + if (ee->ee_calPier11g[i] != CHANNEL_UNUSED) + freq[numPiers++] = ee->ee_calPier11g[i]; + break; + default: + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid mode 0x%x\n", + __func__, mode); + return AH_FALSE; + } + + OS_MEMZERO(&eePower, sizeof(eePower)); + eePower.numChannels = numPiers; + + for (i = 0; i < numPiers; i++) { + eePower.pChannels[i] = freq[i]; + eePower.pDataPerChannel[i].channelValue = freq[i]; + + EEREAD(off++); + eePower.pDataPerChannel[i].pwr1_xg0 = (int16_t) + ((eeval & dbmmask) - ((eeval >> 7) & 0x1)*256); + eePower.pDataPerChannel[i].pwr2_xg0 = (int16_t) + (((eeval >> 8) & dbmmask) - ((eeval >> 15) & 0x1)*256); + + EEREAD(off++); + eePower.pDataPerChannel[i].pwr3_xg0 = (int16_t) + ((eeval & dbmmask) - ((eeval >> 7) & 0x1)*256); + eePower.pDataPerChannel[i].pwr4_xg0 = (int16_t) + (((eeval >> 8) & dbmmask) - ((eeval >> 15) & 0x1)*256); + + EEREAD(off++); + eePower.pDataPerChannel[i].pcd2_delta_xg0 = (uint16_t) + (eeval & pcdac_delta_mask); + eePower.pDataPerChannel[i].pcd3_delta_xg0 = (uint16_t) + ((eeval >> 5) & pcdac_delta_mask); + eePower.pDataPerChannel[i].pcd4_delta_xg0 = (uint16_t) + ((eeval >> 10) & pcdac_delta_mask); + + EEREAD(off++); + eePower.pDataPerChannel[i].pwr1_xg3 = (int16_t) + ((eeval & dbmmask) - ((eeval >> 7) & 0x1)*256); + eePower.pDataPerChannel[i].pwr2_xg3 = (int16_t) + (((eeval >> 8) & dbmmask) - ((eeval >> 15) & 0x1)*256); + + EEREAD(off++); + eePower.pDataPerChannel[i].pwr3_xg3 = (int16_t) + ((eeval & dbmmask) - ((eeval >> 7) & 0x1)*256); + if (ee->ee_version >= AR_EEPROM_VER4_3) { + eePower.pDataPerChannel[i].maxPower_t4 = + eePower.pDataPerChannel[i].pwr4_xg0; + eePower.pDataPerChannel[i].pcd1_xg0 = (uint16_t) + ((eeval >> 8) & pcdac_mask); + } else { + eePower.pDataPerChannel[i].maxPower_t4 = (int16_t) + (((eeval >> 8) & dbmmask) - + ((eeval >> 15) & 0x1)*256); + eePower.pDataPerChannel[i].pcd1_xg0 = 1; + } + } + eePower.xpdMask = ee->ee_xgain[mode]; + + if (!eepromAllocExpnPower5112(ah, &eePower, &ee->ee_modePowerArray5112[mode])) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: did not allocate power struct\n", __func__); + return AH_FALSE; + } + if (!eepromExpandPower5112(ah, &eePower, &ee->ee_modePowerArray5112[mode])) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: did not expand power struct\n", __func__); + return AH_FALSE; + } + } + return AH_TRUE; +#undef EEREAD +} + +static void +freeEepromRawPowerCalInfo5112(struct ath_hal *ah, HAL_EEPROM *ee) +{ + int mode; + void *data; + + for (mode = headerInfo11A; mode <= headerInfo11G; mode++) { + EEPROM_POWER_EXPN_5112 *pPowerExpn = + &ee->ee_modePowerArray5112[mode]; + data = pPowerExpn->pChannels; + if (data != AH_NULL) { + pPowerExpn->pChannels = AH_NULL; + ath_hal_free(data); + } + } +} + +static void +ar2413SetupEEPROMDataset(EEPROM_DATA_STRUCT_2413 *pEEPROMDataset2413, + uint16_t myNumRawChannels, uint16_t *pMyRawChanList) +{ + uint16_t i, channelValue; + uint32_t xpd_mask; + uint16_t numPdGainsUsed; + + pEEPROMDataset2413->numChannels = myNumRawChannels; + + xpd_mask = pEEPROMDataset2413->xpd_mask; + numPdGainsUsed = 0; + if ((xpd_mask >> 0) & 0x1) numPdGainsUsed++; + if ((xpd_mask >> 1) & 0x1) numPdGainsUsed++; + if ((xpd_mask >> 2) & 0x1) numPdGainsUsed++; + if ((xpd_mask >> 3) & 0x1) numPdGainsUsed++; + + for (i = 0; i < myNumRawChannels; i++) { + channelValue = pMyRawChanList[i]; + pEEPROMDataset2413->pChannels[i] = channelValue; + pEEPROMDataset2413->pDataPerChannel[i].channelValue = channelValue; + pEEPROMDataset2413->pDataPerChannel[i].numPdGains = numPdGainsUsed; + } +} + +static HAL_BOOL +ar2413ReadCalDataset(struct ath_hal *ah, HAL_EEPROM *ee, + EEPROM_DATA_STRUCT_2413 *pCalDataset, + uint32_t start_offset, uint32_t maxPiers, uint8_t mode) +{ +#define EEREAD(_off) do { \ + if (!ath_hal_eepromRead(ah, _off, &eeval)) \ + return AH_FALSE; \ +} while (0) + const uint16_t dbm_I_mask = 0x1F; /* 5-bits. 1dB step. */ + const uint16_t dbm_delta_mask = 0xF; /* 4-bits. 0.5dB step. */ + const uint16_t Vpd_I_mask = 0x7F; /* 7-bits. 0-128 */ + const uint16_t Vpd_delta_mask = 0x3F; /* 6-bits. 0-63 */ + const uint16_t freqmask = 0xff; + + uint16_t ii, eeval; + uint16_t idx, numPiers; + uint16_t freq[NUM_11A_EEPROM_CHANNELS]; + + idx = start_offset; + for (numPiers = 0; numPiers < maxPiers;) { + EEREAD(idx++); + if ((eeval & freqmask) == 0) + break; + if (mode == headerInfo11A) + freq[numPiers++] = fbin2freq(ee, (eeval & freqmask)); + else + freq[numPiers++] = fbin2freq_2p4(ee, (eeval & freqmask)); + + if (((eeval >> 8) & freqmask) == 0) + break; + if (mode == headerInfo11A) + freq[numPiers++] = fbin2freq(ee, (eeval >> 8) & freqmask); + else + freq[numPiers++] = fbin2freq_2p4(ee, (eeval >> 8) & freqmask); + } + ar2413SetupEEPROMDataset(pCalDataset, numPiers, &freq[0]); + + idx = start_offset + (maxPiers / 2); + for (ii = 0; ii < pCalDataset->numChannels; ii++) { + EEPROM_DATA_PER_CHANNEL_2413 *currCh = + &(pCalDataset->pDataPerChannel[ii]); + + if (currCh->numPdGains > 0) { + /* + * Read the first NUM_POINTS_OTHER_PDGAINS pwr + * and Vpd values for pdgain_0 + */ + EEREAD(idx++); + currCh->pwr_I[0] = eeval & dbm_I_mask; + currCh->Vpd_I[0] = (eeval >> 5) & Vpd_I_mask; + currCh->pwr_delta_t2[0][0] = + (eeval >> 12) & dbm_delta_mask; + + EEREAD(idx++); + currCh->Vpd_delta[0][0] = eeval & Vpd_delta_mask; + currCh->pwr_delta_t2[1][0] = + (eeval >> 6) & dbm_delta_mask; + currCh->Vpd_delta[1][0] = + (eeval >> 10) & Vpd_delta_mask; + + EEREAD(idx++); + currCh->pwr_delta_t2[2][0] = eeval & dbm_delta_mask; + currCh->Vpd_delta[2][0] = (eeval >> 4) & Vpd_delta_mask; + } + + if (currCh->numPdGains > 1) { + /* + * Read the first NUM_POINTS_OTHER_PDGAINS pwr + * and Vpd values for pdgain_1 + */ + currCh->pwr_I[1] = (eeval >> 10) & dbm_I_mask; + currCh->Vpd_I[1] = (eeval >> 15) & 0x1; + + EEREAD(idx++); + /* upper 6 bits */ + currCh->Vpd_I[1] |= (eeval & 0x3F) << 1; + currCh->pwr_delta_t2[0][1] = + (eeval >> 6) & dbm_delta_mask; + currCh->Vpd_delta[0][1] = + (eeval >> 10) & Vpd_delta_mask; + + EEREAD(idx++); + currCh->pwr_delta_t2[1][1] = eeval & dbm_delta_mask; + currCh->Vpd_delta[1][1] = (eeval >> 4) & Vpd_delta_mask; + currCh->pwr_delta_t2[2][1] = + (eeval >> 10) & dbm_delta_mask; + currCh->Vpd_delta[2][1] = (eeval >> 14) & 0x3; + + EEREAD(idx++); + /* upper 4 bits */ + currCh->Vpd_delta[2][1] |= (eeval & 0xF) << 2; + } else if (currCh->numPdGains == 1) { + /* + * Read the last pwr and Vpd values for pdgain_0 + */ + currCh->pwr_delta_t2[3][0] = + (eeval >> 10) & dbm_delta_mask; + currCh->Vpd_delta[3][0] = (eeval >> 14) & 0x3; + + EEREAD(idx++); + /* upper 4 bits */ + currCh->Vpd_delta[3][0] |= (eeval & 0xF) << 2; + + /* 4 words if numPdGains == 1 */ + } + + if (currCh->numPdGains > 2) { + /* + * Read the first NUM_POINTS_OTHER_PDGAINS pwr + * and Vpd values for pdgain_2 + */ + currCh->pwr_I[2] = (eeval >> 4) & dbm_I_mask; + currCh->Vpd_I[2] = (eeval >> 9) & Vpd_I_mask; + + EEREAD(idx++); + currCh->pwr_delta_t2[0][2] = + (eeval >> 0) & dbm_delta_mask; + currCh->Vpd_delta[0][2] = (eeval >> 4) & Vpd_delta_mask; + currCh->pwr_delta_t2[1][2] = + (eeval >> 10) & dbm_delta_mask; + currCh->Vpd_delta[1][2] = (eeval >> 14) & 0x3; + + EEREAD(idx++); + /* upper 4 bits */ + currCh->Vpd_delta[1][2] |= (eeval & 0xF) << 2; + currCh->pwr_delta_t2[2][2] = + (eeval >> 4) & dbm_delta_mask; + currCh->Vpd_delta[2][2] = (eeval >> 8) & Vpd_delta_mask; + } else if (currCh->numPdGains == 2) { + /* + * Read the last pwr and Vpd values for pdgain_1 + */ + currCh->pwr_delta_t2[3][1] = + (eeval >> 4) & dbm_delta_mask; + currCh->Vpd_delta[3][1] = (eeval >> 8) & Vpd_delta_mask; + + /* 6 words if numPdGains == 2 */ + } + + if (currCh->numPdGains > 3) { + /* + * Read the first NUM_POINTS_OTHER_PDGAINS pwr + * and Vpd values for pdgain_3 + */ + currCh->pwr_I[3] = (eeval >> 14) & 0x3; + + EEREAD(idx++); + /* upper 3 bits */ + currCh->pwr_I[3] |= ((eeval >> 0) & 0x7) << 2; + currCh->Vpd_I[3] = (eeval >> 3) & Vpd_I_mask; + currCh->pwr_delta_t2[0][3] = + (eeval >> 10) & dbm_delta_mask; + currCh->Vpd_delta[0][3] = (eeval >> 14) & 0x3; + + EEREAD(idx++); + /* upper 4 bits */ + currCh->Vpd_delta[0][3] |= (eeval & 0xF) << 2; + currCh->pwr_delta_t2[1][3] = + (eeval >> 4) & dbm_delta_mask; + currCh->Vpd_delta[1][3] = (eeval >> 8) & Vpd_delta_mask; + currCh->pwr_delta_t2[2][3] = (eeval >> 14) & 0x3; + + EEREAD(idx++); + /* upper 2 bits */ + currCh->pwr_delta_t2[2][3] |= ((eeval >> 0) & 0x3) << 2; + currCh->Vpd_delta[2][3] = (eeval >> 2) & Vpd_delta_mask; + currCh->pwr_delta_t2[3][3] = + (eeval >> 8) & dbm_delta_mask; + currCh->Vpd_delta[3][3] = (eeval >> 12) & 0xF; + + EEREAD(idx++); + /* upper 2 bits */ + currCh->Vpd_delta[3][3] |= ((eeval >> 0) & 0x3) << 4; + + /* 12 words if numPdGains == 4 */ + } else if (currCh->numPdGains == 3) { + /* read the last pwr and Vpd values for pdgain_2 */ + currCh->pwr_delta_t2[3][2] = (eeval >> 14) & 0x3; + + EEREAD(idx++); + /* upper 2 bits */ + currCh->pwr_delta_t2[3][2] |= ((eeval >> 0) & 0x3) << 2; + currCh->Vpd_delta[3][2] = (eeval >> 2) & Vpd_delta_mask; + + /* 9 words if numPdGains == 3 */ + } + } + return AH_TRUE; +#undef EEREAD +} + +static void +ar2413SetupRawDataset(RAW_DATA_STRUCT_2413 *pRaw, EEPROM_DATA_STRUCT_2413 *pCal) +{ + uint16_t i, j, kk, channelValue; + uint16_t xpd_mask; + uint16_t numPdGainsUsed; + + pRaw->numChannels = pCal->numChannels; + + xpd_mask = pRaw->xpd_mask; + numPdGainsUsed = 0; + if ((xpd_mask >> 0) & 0x1) numPdGainsUsed++; + if ((xpd_mask >> 1) & 0x1) numPdGainsUsed++; + if ((xpd_mask >> 2) & 0x1) numPdGainsUsed++; + if ((xpd_mask >> 3) & 0x1) numPdGainsUsed++; + + for (i = 0; i < pCal->numChannels; i++) { + channelValue = pCal->pChannels[i]; + + pRaw->pChannels[i] = channelValue; + + pRaw->pDataPerChannel[i].channelValue = channelValue; + pRaw->pDataPerChannel[i].numPdGains = numPdGainsUsed; + + kk = 0; + for (j = 0; j < MAX_NUM_PDGAINS_PER_CHANNEL; j++) { + pRaw->pDataPerChannel[i].pDataPerPDGain[j].pd_gain = j; + if ((xpd_mask >> j) & 0x1) { + pRaw->pDataPerChannel[i].pDataPerPDGain[j].numVpd = NUM_POINTS_OTHER_PDGAINS; + kk++; + if (kk == 1) { + /* + * lowest pd_gain corresponds + * to highest power and thus, + * has one more point + */ + pRaw->pDataPerChannel[i].pDataPerPDGain[j].numVpd = NUM_POINTS_LAST_PDGAIN; + } + } else { + pRaw->pDataPerChannel[i].pDataPerPDGain[j].numVpd = 0; + } + } + } +} + +static HAL_BOOL +ar2413EepromToRawDataset(struct ath_hal *ah, + EEPROM_DATA_STRUCT_2413 *pCal, RAW_DATA_STRUCT_2413 *pRaw) +{ + uint16_t ii, jj, kk, ss; + RAW_DATA_PER_PDGAIN_2413 *pRawXPD; + /* ptr to array of info held per channel */ + EEPROM_DATA_PER_CHANNEL_2413 *pCalCh; + uint16_t xgain_list[MAX_NUM_PDGAINS_PER_CHANNEL]; + uint16_t xpd_mask; + uint32_t numPdGainsUsed; + + HALASSERT(pRaw->xpd_mask == pCal->xpd_mask); + + xgain_list[0] = 0xDEAD; + xgain_list[1] = 0xDEAD; + xgain_list[2] = 0xDEAD; + xgain_list[3] = 0xDEAD; + + numPdGainsUsed = 0; + xpd_mask = pRaw->xpd_mask; + for (jj = 0; jj < MAX_NUM_PDGAINS_PER_CHANNEL; jj++) { + if ((xpd_mask >> (MAX_NUM_PDGAINS_PER_CHANNEL-jj-1)) & 1) + xgain_list[numPdGainsUsed++] = MAX_NUM_PDGAINS_PER_CHANNEL-jj-1; + } + + pRaw->numChannels = pCal->numChannels; + for (ii = 0; ii < pRaw->numChannels; ii++) { + pCalCh = &(pCal->pDataPerChannel[ii]); + pRaw->pDataPerChannel[ii].channelValue = pCalCh->channelValue; + + /* numVpd has already been setup appropriately for the relevant pdGains */ + for (jj = 0; jj < numPdGainsUsed; jj++) { + /* use jj for calDataset and ss for rawDataset */ + ss = xgain_list[jj]; + pRawXPD = &(pRaw->pDataPerChannel[ii].pDataPerPDGain[ss]); + HALASSERT(pRawXPD->numVpd >= 1); + + pRawXPD->pwr_t4[0] = (uint16_t)(4*pCalCh->pwr_I[jj]); + pRawXPD->Vpd[0] = pCalCh->Vpd_I[jj]; + + for (kk = 1; kk < pRawXPD->numVpd; kk++) { + pRawXPD->pwr_t4[kk] = (int16_t)(pRawXPD->pwr_t4[kk-1] + 2*pCalCh->pwr_delta_t2[kk-1][jj]); + pRawXPD->Vpd[kk] = (uint16_t)(pRawXPD->Vpd[kk-1] + pCalCh->Vpd_delta[kk-1][jj]); + } + /* loop over Vpds */ + } + /* loop over pd_gains */ + } + /* loop over channels */ + return AH_TRUE; +} + +static HAL_BOOL +readEepromRawPowerCalInfo2413(struct ath_hal *ah, HAL_EEPROM *ee) +{ + /* NB: index is 1 less than numPdgains */ + static const uint16_t wordsForPdgains[] = { 4, 6, 9, 12 }; + EEPROM_DATA_STRUCT_2413 *pCal = AH_NULL; + RAW_DATA_STRUCT_2413 *pRaw; + int numEEPROMWordsPerChannel; + uint32_t off; + HAL_BOOL ret = AH_FALSE; + + HALASSERT(ee->ee_version >= AR_EEPROM_VER5_0); + HALASSERT(ee->ee_eepMap == 2); + + pCal = ath_hal_malloc(sizeof(EEPROM_DATA_STRUCT_2413)); + if (pCal == AH_NULL) + goto exit; + + off = ee->ee_eepMap2PowerCalStart; + if (ee->ee_Amode) { + OS_MEMZERO(pCal, sizeof(EEPROM_DATA_STRUCT_2413)); + pCal->xpd_mask = ee->ee_xgain[headerInfo11A]; + if (!ar2413ReadCalDataset(ah, ee, pCal, off, + NUM_11A_EEPROM_CHANNELS_2413, headerInfo11A)) { + goto exit; + } + pRaw = &ee->ee_rawDataset2413[headerInfo11A]; + pRaw->xpd_mask = ee->ee_xgain[headerInfo11A]; + ar2413SetupRawDataset(pRaw, pCal); + if (!ar2413EepromToRawDataset(ah, pCal, pRaw)) { + goto exit; + } + /* setup offsets for mode_11a next */ + numEEPROMWordsPerChannel = wordsForPdgains[ + pCal->pDataPerChannel[0].numPdGains - 1]; + off += pCal->numChannels * numEEPROMWordsPerChannel + 5; + } + if (ee->ee_Bmode) { + OS_MEMZERO(pCal, sizeof(EEPROM_DATA_STRUCT_2413)); + pCal->xpd_mask = ee->ee_xgain[headerInfo11B]; + if (!ar2413ReadCalDataset(ah, ee, pCal, off, + NUM_2_4_EEPROM_CHANNELS_2413 , headerInfo11B)) { + goto exit; + } + pRaw = &ee->ee_rawDataset2413[headerInfo11B]; + pRaw->xpd_mask = ee->ee_xgain[headerInfo11B]; + ar2413SetupRawDataset(pRaw, pCal); + if (!ar2413EepromToRawDataset(ah, pCal, pRaw)) { + goto exit; + } + /* setup offsets for mode_11g next */ + numEEPROMWordsPerChannel = wordsForPdgains[ + pCal->pDataPerChannel[0].numPdGains - 1]; + off += pCal->numChannels * numEEPROMWordsPerChannel + 2; + } + if (ee->ee_Gmode) { + OS_MEMZERO(pCal, sizeof(EEPROM_DATA_STRUCT_2413)); + pCal->xpd_mask = ee->ee_xgain[headerInfo11G]; + if (!ar2413ReadCalDataset(ah, ee, pCal, off, + NUM_2_4_EEPROM_CHANNELS_2413, headerInfo11G)) { + goto exit; + } + pRaw = &ee->ee_rawDataset2413[headerInfo11G]; + pRaw->xpd_mask = ee->ee_xgain[headerInfo11G]; + ar2413SetupRawDataset(pRaw, pCal); + if (!ar2413EepromToRawDataset(ah, pCal, pRaw)) { + goto exit; + } + } + ret = AH_TRUE; + exit: + if (pCal != AH_NULL) + ath_hal_free(pCal); + return ret; +} + +/* + * Now copy EEPROM Raw Power Calibration per frequency contents + * into the allocated space + */ +static HAL_BOOL +readEepromRawPowerCalInfo(struct ath_hal *ah, HAL_EEPROM *ee) +{ +#define EEREAD(_off) do { \ + if (!ath_hal_eepromRead(ah, _off, &eeval)) \ + return AH_FALSE; \ +} while (0) + uint16_t eeval, nchan; + uint32_t off; + int i, j, mode; + + if (ee->ee_version >= AR_EEPROM_VER4_0 && ee->ee_eepMap == 1) + return readEepromRawPowerCalInfo5112(ah, ee); + if (ee->ee_version >= AR_EEPROM_VER5_0 && ee->ee_eepMap == 2) + return readEepromRawPowerCalInfo2413(ah, ee); + + /* + * Group 2: read raw power data for all frequency piers + * + * NOTE: Group 2 contains the raw power calibration + * information for each of the channels that + * we recorded above. + */ + for (mode = headerInfo11A; mode <= headerInfo11G; mode++) { + uint16_t *pChannels = AH_NULL; + DATA_PER_CHANNEL *pChannelData = AH_NULL; + + off = ee->ee_version >= AR_EEPROM_VER3_3 ? + GROUPS_OFFSET3_3 : GROUPS_OFFSET3_2; + switch (mode) { + case headerInfo11A: + off += GROUP2_OFFSET; + nchan = ee->ee_numChannels11a; + pChannelData = ee->ee_dataPerChannel11a; + pChannels = ee->ee_channels11a; + break; + case headerInfo11B: + if (!ee->ee_Bmode) + continue; + off += GROUP3_OFFSET; + nchan = ee->ee_numChannels2_4; + pChannelData = ee->ee_dataPerChannel11b; + pChannels = ee->ee_channels11b; + break; + case headerInfo11G: + if (!ee->ee_Gmode) + continue; + off += GROUP4_OFFSET; + nchan = ee->ee_numChannels2_4; + pChannelData = ee->ee_dataPerChannel11g; + pChannels = ee->ee_channels11g; + break; + default: + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid mode 0x%x\n", + __func__, mode); + return AH_FALSE; + } + for (i = 0; i < nchan; i++) { + pChannelData->channelValue = pChannels[i]; + + EEREAD(off++); + pChannelData->pcdacMax = (uint16_t)((eeval >> 10) & PCDAC_MASK); + pChannelData->pcdacMin = (uint16_t)((eeval >> 4) & PCDAC_MASK); + pChannelData->PwrValues[0] = (uint16_t)((eeval << 2) & POWER_MASK); + + EEREAD(off++); + pChannelData->PwrValues[0] |= (uint16_t)((eeval >> 14) & 0x3); + pChannelData->PwrValues[1] = (uint16_t)((eeval >> 8) & POWER_MASK); + pChannelData->PwrValues[2] = (uint16_t)((eeval >> 2) & POWER_MASK); + pChannelData->PwrValues[3] = (uint16_t)((eeval << 4) & POWER_MASK); + + EEREAD(off++); + pChannelData->PwrValues[3] |= (uint16_t)((eeval >> 12) & 0xf); + pChannelData->PwrValues[4] = (uint16_t)((eeval >> 6) & POWER_MASK); + pChannelData->PwrValues[5] = (uint16_t)(eeval & POWER_MASK); + + EEREAD(off++); + pChannelData->PwrValues[6] = (uint16_t)((eeval >> 10) & POWER_MASK); + pChannelData->PwrValues[7] = (uint16_t)((eeval >> 4) & POWER_MASK); + pChannelData->PwrValues[8] = (uint16_t)((eeval << 2) & POWER_MASK); + + EEREAD(off++); + pChannelData->PwrValues[8] |= (uint16_t)((eeval >> 14) & 0x3); + pChannelData->PwrValues[9] = (uint16_t)((eeval >> 8) & POWER_MASK); + pChannelData->PwrValues[10] = (uint16_t)((eeval >> 2) & POWER_MASK); + + getPcdacInterceptsFromPcdacMinMax(ee, + pChannelData->pcdacMin, pChannelData->pcdacMax, + pChannelData->PcdacValues) ; + + for (j = 0; j < pChannelData->numPcdacValues; j++) { + pChannelData->PwrValues[j] = (uint16_t)( + PWR_STEP * pChannelData->PwrValues[j]); + /* Note these values are scaled up. */ + } + pChannelData++; + } + } + return AH_TRUE; +#undef EEREAD +} + +/* + * Copy EEPROM Target Power Calbration per rate contents + * into the allocated space + */ +static HAL_BOOL +readEepromTargetPowerCalInfo(struct ath_hal *ah, HAL_EEPROM *ee) +{ +#define EEREAD(_off) do { \ + if (!ath_hal_eepromRead(ah, _off, &eeval)) \ + return AH_FALSE; \ +} while (0) + uint16_t eeval, enable24; + uint32_t off; + int i, mode, nchan; + + enable24 = ee->ee_Bmode || ee->ee_Gmode; + for (mode = headerInfo11A; mode <= headerInfo11G; mode++) { + TRGT_POWER_INFO *pPowerInfo; + uint16_t *pNumTrgtChannels; + + off = ee->ee_version >= AR_EEPROM_VER4_0 ? + ee->ee_targetPowersStart - GROUP5_OFFSET : + ee->ee_version >= AR_EEPROM_VER3_3 ? + GROUPS_OFFSET3_3 : GROUPS_OFFSET3_2; + switch (mode) { + case headerInfo11A: + off += GROUP5_OFFSET; + nchan = NUM_TEST_FREQUENCIES; + pPowerInfo = ee->ee_trgtPwr_11a; + pNumTrgtChannels = &ee->ee_numTargetPwr_11a; + break; + case headerInfo11B: + if (!enable24) + continue; + off += GROUP6_OFFSET; + nchan = 2; + pPowerInfo = ee->ee_trgtPwr_11b; + pNumTrgtChannels = &ee->ee_numTargetPwr_11b; + break; + case headerInfo11G: + if (!enable24) + continue; + off += GROUP7_OFFSET; + nchan = 3; + pPowerInfo = ee->ee_trgtPwr_11g; + pNumTrgtChannels = &ee->ee_numTargetPwr_11g; + break; + default: + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid mode 0x%x\n", + __func__, mode); + return AH_FALSE; + } + *pNumTrgtChannels = 0; + for (i = 0; i < nchan; i++) { + EEREAD(off++); + if (ee->ee_version >= AR_EEPROM_VER3_3) { + pPowerInfo->testChannel = (eeval >> 8) & 0xff; + } else { + pPowerInfo->testChannel = (eeval >> 9) & 0x7f; + } + + if (pPowerInfo->testChannel != 0) { + /* get the channel value and read rest of info */ + if (mode == headerInfo11A) { + pPowerInfo->testChannel = fbin2freq(ee, pPowerInfo->testChannel); + } else { + pPowerInfo->testChannel = fbin2freq_2p4(ee, pPowerInfo->testChannel); + } + + if (ee->ee_version >= AR_EEPROM_VER3_3) { + pPowerInfo->twicePwr6_24 = (eeval >> 2) & POWER_MASK; + pPowerInfo->twicePwr36 = (eeval << 4) & POWER_MASK; + } else { + pPowerInfo->twicePwr6_24 = (eeval >> 3) & POWER_MASK; + pPowerInfo->twicePwr36 = (eeval << 3) & POWER_MASK; + } + + EEREAD(off++); + if (ee->ee_version >= AR_EEPROM_VER3_3) { + pPowerInfo->twicePwr36 |= (eeval >> 12) & 0xf; + pPowerInfo->twicePwr48 = (eeval >> 6) & POWER_MASK; + pPowerInfo->twicePwr54 = eeval & POWER_MASK; + } else { + pPowerInfo->twicePwr36 |= (eeval >> 13) & 0x7; + pPowerInfo->twicePwr48 = (eeval >> 7) & POWER_MASK; + pPowerInfo->twicePwr54 = (eeval >> 1) & POWER_MASK; + } + (*pNumTrgtChannels)++; + } + pPowerInfo++; + } + } + return AH_TRUE; +#undef EEREAD +} + +/* + * Now copy EEPROM Coformance Testing Limits contents + * into the allocated space + */ +static HAL_BOOL +readEepromCTLInfo(struct ath_hal *ah, HAL_EEPROM *ee) +{ +#define EEREAD(_off) do { \ + if (!ath_hal_eepromRead(ah, _off, &eeval)) \ + return AH_FALSE; \ +} while (0) + RD_EDGES_POWER *rep; + uint16_t eeval; + uint32_t off; + int i, j; + + rep = ee->ee_rdEdgesPower; + + off = GROUP8_OFFSET + + (ee->ee_version >= AR_EEPROM_VER4_0 ? + ee->ee_targetPowersStart - GROUP5_OFFSET : + ee->ee_version >= AR_EEPROM_VER3_3 ? + GROUPS_OFFSET3_3 : GROUPS_OFFSET3_2); + for (i = 0; i < ee->ee_numCtls; i++) { + if (ee->ee_ctl[i] == 0) { + /* Move offset and edges */ + off += (ee->ee_version >= AR_EEPROM_VER3_3 ? 8 : 7); + rep += NUM_EDGES; + continue; + } + if (ee->ee_version >= AR_EEPROM_VER3_3) { + for (j = 0; j < NUM_EDGES; j += 2) { + EEREAD(off++); + rep[j].rdEdge = (eeval >> 8) & FREQ_MASK_3_3; + rep[j+1].rdEdge = eeval & FREQ_MASK_3_3; + } + for (j = 0; j < NUM_EDGES; j += 2) { + EEREAD(off++); + rep[j].twice_rdEdgePower = + (eeval >> 8) & POWER_MASK; + rep[j].flag = (eeval >> 14) & 1; + rep[j+1].twice_rdEdgePower = eeval & POWER_MASK; + rep[j+1].flag = (eeval >> 6) & 1; + } + } else { + EEREAD(off++); + rep[0].rdEdge = (eeval >> 9) & FREQ_MASK; + rep[1].rdEdge = (eeval >> 2) & FREQ_MASK; + rep[2].rdEdge = (eeval << 5) & FREQ_MASK; + + EEREAD(off++); + rep[2].rdEdge |= (eeval >> 11) & 0x1f; + rep[3].rdEdge = (eeval >> 4) & FREQ_MASK; + rep[4].rdEdge = (eeval << 3) & FREQ_MASK; + + EEREAD(off++); + rep[4].rdEdge |= (eeval >> 13) & 0x7; + rep[5].rdEdge = (eeval >> 6) & FREQ_MASK; + rep[6].rdEdge = (eeval << 1) & FREQ_MASK; + + EEREAD(off++); + rep[6].rdEdge |= (eeval >> 15) & 0x1; + rep[7].rdEdge = (eeval >> 8) & FREQ_MASK; + + rep[0].twice_rdEdgePower = (eeval >> 2) & POWER_MASK; + rep[1].twice_rdEdgePower = (eeval << 4) & POWER_MASK; + + EEREAD(off++); + rep[1].twice_rdEdgePower |= (eeval >> 12) & 0xf; + rep[2].twice_rdEdgePower = (eeval >> 6) & POWER_MASK; + rep[3].twice_rdEdgePower = eeval & POWER_MASK; + + EEREAD(off++); + rep[4].twice_rdEdgePower = (eeval >> 10) & POWER_MASK; + rep[5].twice_rdEdgePower = (eeval >> 4) & POWER_MASK; + rep[6].twice_rdEdgePower = (eeval << 2) & POWER_MASK; + + EEREAD(off++); + rep[6].twice_rdEdgePower |= (eeval >> 14) & 0x3; + rep[7].twice_rdEdgePower = (eeval >> 8) & POWER_MASK; + } + + for (j = 0; j < NUM_EDGES; j++ ) { + if (rep[j].rdEdge != 0 || rep[j].twice_rdEdgePower != 0) { + if ((ee->ee_ctl[i] & CTL_MODE_M) == CTL_11A || + (ee->ee_ctl[i] & CTL_MODE_M) == CTL_TURBO) { + rep[j].rdEdge = fbin2freq(ee, rep[j].rdEdge); + } else { + rep[j].rdEdge = fbin2freq_2p4(ee, rep[j].rdEdge); + } + } + } + rep += NUM_EDGES; + } + return AH_TRUE; +#undef EEREAD +} + +/* + * Read the individual header fields for a Rev 3 EEPROM + */ +static HAL_BOOL +readHeaderInfo(struct ath_hal *ah, HAL_EEPROM *ee) +{ +#define EEREAD(_off) do { \ + if (!ath_hal_eepromRead(ah, _off, &eeval)) \ + return AH_FALSE; \ +} while (0) + static const uint32_t headerOffset3_0[] = { + 0x00C2, /* 0 - Mode bits, device type, max turbo power */ + 0x00C4, /* 1 - 2.4 and 5 antenna gain */ + 0x00C5, /* 2 - Begin 11A modal section */ + 0x00D0, /* 3 - Begin 11B modal section */ + 0x00DA, /* 4 - Begin 11G modal section */ + 0x00E4 /* 5 - Begin CTL section */ + }; + static const uint32_t headerOffset3_3[] = { + 0x00C2, /* 0 - Mode bits, device type, max turbo power */ + 0x00C3, /* 1 - 2.4 and 5 antenna gain */ + 0x00D4, /* 2 - Begin 11A modal section */ + 0x00F2, /* 3 - Begin 11B modal section */ + 0x010D, /* 4 - Begin 11G modal section */ + 0x0128 /* 5 - Begin CTL section */ + }; + + static const uint32_t regCapOffsetPre4_0 = 0x00CF; + static const uint32_t regCapOffsetPost4_0 = 0x00CA; + + const uint32_t *header; + uint32_t off; + uint16_t eeval; + int i; + + /* initialize cckOfdmGainDelta for < 4.2 eeprom */ + ee->ee_cckOfdmGainDelta = CCK_OFDM_GAIN_DELTA; + ee->ee_scaledCh14FilterCckDelta = TENX_CH14_FILTER_CCK_DELTA_INIT; + + if (ee->ee_version >= AR_EEPROM_VER3_3) { + header = headerOffset3_3; + ee->ee_numCtls = NUM_CTLS_3_3; + } else { + header = headerOffset3_0; + ee->ee_numCtls = NUM_CTLS; + } + HALASSERT(ee->ee_numCtls <= NUM_CTLS_MAX); + + EEREAD(header[0]); + ee->ee_turbo5Disable = (eeval >> 15) & 0x01; + ee->ee_rfKill = (eeval >> 14) & 0x01; + ee->ee_deviceType = (eeval >> 11) & 0x07; + ee->ee_turbo2WMaxPower5 = (eeval >> 4) & 0x7F; + if (ee->ee_version >= AR_EEPROM_VER4_0) + ee->ee_turbo2Disable = (eeval >> 3) & 0x01; + else + ee->ee_turbo2Disable = 1; + ee->ee_Gmode = (eeval >> 2) & 0x01; + ee->ee_Bmode = (eeval >> 1) & 0x01; + ee->ee_Amode = (eeval & 0x01); + + off = header[1]; + EEREAD(off++); + ee->ee_antennaGainMax[0] = (int8_t)((eeval >> 8) & 0xFF); + ee->ee_antennaGainMax[1] = (int8_t)(eeval & 0xFF); + if (ee->ee_version >= AR_EEPROM_VER4_0) { + EEREAD(off++); + ee->ee_eepMap = (eeval>>14) & 0x3; + ee->ee_disableXr5 = (eeval>>13) & 0x1; + ee->ee_disableXr2 = (eeval>>12) & 0x1; + ee->ee_earStart = eeval & 0xfff; + + EEREAD(off++); + ee->ee_targetPowersStart = eeval & 0xfff; + ee->ee_exist32kHzCrystal = (eeval>>14) & 0x1; + + if (ee->ee_version >= AR_EEPROM_VER5_0) { + off += 2; + EEREAD(off); + ee->ee_eepMap2PowerCalStart = (eeval >> 4) & 0xfff; + /* Properly cal'ed 5.0 devices should be non-zero */ + } + } + + /* Read the moded sections of the EEPROM header in the order A, B, G */ + for (i = headerInfo11A; i <= headerInfo11G; i++) { + /* Set the offset via the index */ + off = header[2 + i]; + + EEREAD(off++); + ee->ee_switchSettling[i] = (eeval >> 8) & 0x7f; + ee->ee_txrxAtten[i] = (eeval >> 2) & 0x3f; + ee->ee_antennaControl[0][i] = (eeval << 4) & 0x3f; + + EEREAD(off++); + ee->ee_antennaControl[0][i] |= (eeval >> 12) & 0x0f; + ee->ee_antennaControl[1][i] = (eeval >> 6) & 0x3f; + ee->ee_antennaControl[2][i] = eeval & 0x3f; + + EEREAD(off++); + ee->ee_antennaControl[3][i] = (eeval >> 10) & 0x3f; + ee->ee_antennaControl[4][i] = (eeval >> 4) & 0x3f; + ee->ee_antennaControl[5][i] = (eeval << 2) & 0x3f; + + EEREAD(off++); + ee->ee_antennaControl[5][i] |= (eeval >> 14) & 0x03; + ee->ee_antennaControl[6][i] = (eeval >> 8) & 0x3f; + ee->ee_antennaControl[7][i] = (eeval >> 2) & 0x3f; + ee->ee_antennaControl[8][i] = (eeval << 4) & 0x3f; + + EEREAD(off++); + ee->ee_antennaControl[8][i] |= (eeval >> 12) & 0x0f; + ee->ee_antennaControl[9][i] = (eeval >> 6) & 0x3f; + ee->ee_antennaControl[10][i] = eeval & 0x3f; + + EEREAD(off++); + ee->ee_adcDesiredSize[i] = (int8_t)((eeval >> 8) & 0xff); + switch (i) { + case headerInfo11A: + ee->ee_ob4 = (eeval >> 5) & 0x07; + ee->ee_db4 = (eeval >> 2) & 0x07; + ee->ee_ob3 = (eeval << 1) & 0x07; + break; + case headerInfo11B: + ee->ee_obFor24 = (eeval >> 4) & 0x07; + ee->ee_dbFor24 = eeval & 0x07; + break; + case headerInfo11G: + ee->ee_obFor24g = (eeval >> 4) & 0x07; + ee->ee_dbFor24g = eeval & 0x07; + break; + } + + if (i == headerInfo11A) { + EEREAD(off++); + ee->ee_ob3 |= (eeval >> 15) & 0x01; + ee->ee_db3 = (eeval >> 12) & 0x07; + ee->ee_ob2 = (eeval >> 9) & 0x07; + ee->ee_db2 = (eeval >> 6) & 0x07; + ee->ee_ob1 = (eeval >> 3) & 0x07; + ee->ee_db1 = eeval & 0x07; + } + + EEREAD(off++); + ee->ee_txEndToXLNAOn[i] = (eeval >> 8) & 0xff; + ee->ee_thresh62[i] = eeval & 0xff; + + EEREAD(off++); + ee->ee_txEndToXPAOff[i] = (eeval >> 8) & 0xff; + ee->ee_txFrameToXPAOn[i] = eeval & 0xff; + + EEREAD(off++); + ee->ee_pgaDesiredSize[i] = (int8_t)((eeval >> 8) & 0xff); + ee->ee_noiseFloorThresh[i] = eeval & 0xff; + if (ee->ee_noiseFloorThresh[i] & 0x80) { + ee->ee_noiseFloorThresh[i] = 0 - + ((ee->ee_noiseFloorThresh[i] ^ 0xff) + 1); + } + + EEREAD(off++); + ee->ee_xlnaGain[i] = (eeval >> 5) & 0xff; + ee->ee_xgain[i] = (eeval >> 1) & 0x0f; + ee->ee_xpd[i] = eeval & 0x01; + if (ee->ee_version >= AR_EEPROM_VER4_0) { + switch (i) { + case headerInfo11A: + ee->ee_fixedBias5 = (eeval >> 13) & 0x1; + break; + case headerInfo11G: + ee->ee_fixedBias2 = (eeval >> 13) & 0x1; + break; + } + } + + if (ee->ee_version >= AR_EEPROM_VER3_3) { + EEREAD(off++); + ee->ee_falseDetectBackoff[i] = (eeval >> 6) & 0x7F; + switch (i) { + case headerInfo11B: + ee->ee_ob2GHz[0] = eeval & 0x7; + ee->ee_db2GHz[0] = (eeval >> 3) & 0x7; + break; + case headerInfo11G: + ee->ee_ob2GHz[1] = eeval & 0x7; + ee->ee_db2GHz[1] = (eeval >> 3) & 0x7; + break; + case headerInfo11A: + ee->ee_xrTargetPower5 = eeval & 0x3f; + break; + } + } + if (ee->ee_version >= AR_EEPROM_VER3_4) { + ee->ee_gainI[i] = (eeval >> 13) & 0x07; + + EEREAD(off++); + ee->ee_gainI[i] |= (eeval << 3) & 0x38; + if (i == headerInfo11G) { + ee->ee_cckOfdmPwrDelta = (eeval >> 3) & 0xFF; + if (ee->ee_version >= AR_EEPROM_VER4_6) + ee->ee_scaledCh14FilterCckDelta = + (eeval >> 11) & 0x1f; + } + if (i == headerInfo11A && + ee->ee_version >= AR_EEPROM_VER4_0) { + ee->ee_iqCalI[0] = (eeval >> 8 ) & 0x3f; + ee->ee_iqCalQ[0] = (eeval >> 3 ) & 0x1f; + } + } else { + ee->ee_gainI[i] = 10; + ee->ee_cckOfdmPwrDelta = TENX_OFDM_CCK_DELTA_INIT; + } + if (ee->ee_version >= AR_EEPROM_VER4_0) { + switch (i) { + case headerInfo11B: + EEREAD(off++); + ee->ee_calPier11b[0] = + fbin2freq_2p4(ee, eeval&0xff); + ee->ee_calPier11b[1] = + fbin2freq_2p4(ee, (eeval >> 8)&0xff); + EEREAD(off++); + ee->ee_calPier11b[2] = + fbin2freq_2p4(ee, eeval&0xff); + if (ee->ee_version >= AR_EEPROM_VER4_1) + ee->ee_rxtxMargin[headerInfo11B] = + (eeval >> 8) & 0x3f; + break; + case headerInfo11G: + EEREAD(off++); + ee->ee_calPier11g[0] = + fbin2freq_2p4(ee, eeval & 0xff); + ee->ee_calPier11g[1] = + fbin2freq_2p4(ee, (eeval >> 8) & 0xff); + + EEREAD(off++); + ee->ee_turbo2WMaxPower2 = eeval & 0x7F; + ee->ee_xrTargetPower2 = (eeval >> 7) & 0x3f; + + EEREAD(off++); + ee->ee_calPier11g[2] = + fbin2freq_2p4(ee, eeval & 0xff); + if (ee->ee_version >= AR_EEPROM_VER4_1) + ee->ee_rxtxMargin[headerInfo11G] = + (eeval >> 8) & 0x3f; + + EEREAD(off++); + ee->ee_iqCalI[1] = (eeval >> 5) & 0x3F; + ee->ee_iqCalQ[1] = eeval & 0x1F; + + if (ee->ee_version >= AR_EEPROM_VER4_2) { + EEREAD(off++); + ee->ee_cckOfdmGainDelta = + (uint8_t)(eeval & 0xFF); + if (ee->ee_version >= AR_EEPROM_VER5_0) { + ee->ee_switchSettlingTurbo[1] = + (eeval >> 8) & 0x7f; + ee->ee_txrxAttenTurbo[1] = + (eeval >> 15) & 0x1; + EEREAD(off++); + ee->ee_txrxAttenTurbo[1] |= + (eeval & 0x1F) << 1; + ee->ee_rxtxMarginTurbo[1] = + (eeval >> 5) & 0x3F; + ee->ee_adcDesiredSizeTurbo[1] = + (eeval >> 11) & 0x1F; + EEREAD(off++); + ee->ee_adcDesiredSizeTurbo[1] |= + (eeval & 0x7) << 5; + ee->ee_pgaDesiredSizeTurbo[1] = + (eeval >> 3) & 0xFF; + } + } + break; + case headerInfo11A: + if (ee->ee_version >= AR_EEPROM_VER4_1) { + EEREAD(off++); + ee->ee_rxtxMargin[headerInfo11A] = + eeval & 0x3f; + if (ee->ee_version >= AR_EEPROM_VER5_0) { + ee->ee_switchSettlingTurbo[0] = + (eeval >> 6) & 0x7f; + ee->ee_txrxAttenTurbo[0] = + (eeval >> 13) & 0x7; + EEREAD(off++); + ee->ee_txrxAttenTurbo[0] |= + (eeval & 0x7) << 3; + ee->ee_rxtxMarginTurbo[0] = + (eeval >> 3) & 0x3F; + ee->ee_adcDesiredSizeTurbo[0] = + (eeval >> 9) & 0x7F; + EEREAD(off++); + ee->ee_adcDesiredSizeTurbo[0] |= + (eeval & 0x1) << 7; + ee->ee_pgaDesiredSizeTurbo[0] = + (eeval >> 1) & 0xFF; + } + } + break; + } + } + } + if (ee->ee_version < AR_EEPROM_VER3_3) { + /* Version 3.1+ specific parameters */ + EEREAD(0xec); + ee->ee_ob2GHz[0] = eeval & 0x7; + ee->ee_db2GHz[0] = (eeval >> 3) & 0x7; + + EEREAD(0xed); + ee->ee_ob2GHz[1] = eeval & 0x7; + ee->ee_db2GHz[1] = (eeval >> 3) & 0x7; + } + + /* Initialize corner cal (thermal tx gain adjust parameters) */ + ee->ee_cornerCal.clip = 4; + ee->ee_cornerCal.pd90 = 1; + ee->ee_cornerCal.pd84 = 1; + ee->ee_cornerCal.gSel = 0; + + /* + * Read the conformance test limit identifiers + * These are used to match regulatory domain testing needs with + * the RD-specific tests that have been calibrated in the EEPROM. + */ + off = header[5]; + for (i = 0; i < ee->ee_numCtls; i += 2) { + EEREAD(off++); + ee->ee_ctl[i] = (eeval >> 8) & 0xff; + ee->ee_ctl[i+1] = eeval & 0xff; + } + + if (ee->ee_version < AR_EEPROM_VER5_3) { + /* XXX only for 5413? */ + ee->ee_spurChans[0][1] = AR_SPUR_5413_1; + ee->ee_spurChans[1][1] = AR_SPUR_5413_2; + ee->ee_spurChans[2][1] = AR_NO_SPUR; + ee->ee_spurChans[0][0] = AR_NO_SPUR; + } else { + /* Read spur mitigation data */ + for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { + EEREAD(off); + ee->ee_spurChans[i][0] = eeval; + EEREAD(off+AR_EEPROM_MODAL_SPURS); + ee->ee_spurChans[i][1] = eeval; + off++; + } + } + + /* for recent changes to NF scale */ + if (ee->ee_version <= AR_EEPROM_VER3_2) { + ee->ee_noiseFloorThresh[headerInfo11A] = -54; + ee->ee_noiseFloorThresh[headerInfo11B] = -1; + ee->ee_noiseFloorThresh[headerInfo11G] = -1; + } + /* to override thresh62 for better 2.4 and 5 operation */ + if (ee->ee_version <= AR_EEPROM_VER3_2) { + ee->ee_thresh62[headerInfo11A] = 15; /* 11A */ + ee->ee_thresh62[headerInfo11B] = 28; /* 11B */ + ee->ee_thresh62[headerInfo11G] = 28; /* 11G */ + } + + /* Check for regulatory capabilities */ + if (ee->ee_version >= AR_EEPROM_VER4_0) { + EEREAD(regCapOffsetPost4_0); + } else { + EEREAD(regCapOffsetPre4_0); + } + + ee->ee_regCap = eeval; + + if (ee->ee_Amode == 0) { + /* Check for valid Amode in upgraded h/w */ + if (ee->ee_version >= AR_EEPROM_VER4_0) { + ee->ee_Amode = (ee->ee_regCap & AR_EEPROM_EEREGCAP_EN_KK_NEW_11A)?1:0; + } else { + ee->ee_Amode = (ee->ee_regCap & AR_EEPROM_EEREGCAP_EN_KK_NEW_11A_PRE4_0)?1:0; + } + } + + if (ee->ee_version >= AR_EEPROM_VER5_1) + EEREAD(AR_EEPROM_CAPABILITIES_OFFSET); + else + eeval = 0; + ee->ee_opCap = eeval; + + EEREAD(AR_EEPROM_REG_DOMAIN); + ee->ee_regdomain = eeval; + + return AH_TRUE; +#undef EEREAD +} + +/* + * Now verify and copy EEPROM contents into the allocated space + */ +static HAL_BOOL +legacyEepromReadContents(struct ath_hal *ah, HAL_EEPROM *ee) +{ + /* Read the header information here */ + if (!readHeaderInfo(ah, ee)) + return AH_FALSE; +#if 0 + /* Require 5112 devices to have EEPROM 4.0 EEP_MAP set */ + if (IS_5112(ah) && !ee->ee_eepMap) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: 5112 devices must have EEPROM 4.0 with the " + "EEP_MAP set\n", __func__); + return AH_FALSE; + } +#endif + /* + * Group 1: frequency pier locations readback + * check that the structure has been populated + * with enough space to hold the channels + * + * NOTE: Group 1 contains the 5 GHz channel numbers + * that have dBm->pcdac calibrated information. + */ + if (!readEepromFreqPierInfo(ah, ee)) + return AH_FALSE; + + /* + * Group 2: readback data for all frequency piers + * + * NOTE: Group 2 contains the raw power calibration + * information for each of the channels that we + * recorded above. + */ + if (!readEepromRawPowerCalInfo(ah, ee)) + return AH_FALSE; + + /* + * Group 5: target power values per rate + * + * NOTE: Group 5 contains the recorded maximum power + * in dB that can be attained for the given rate. + */ + /* Read the power per rate info for test channels */ + if (!readEepromTargetPowerCalInfo(ah, ee)) + return AH_FALSE; + + /* + * Group 8: Conformance Test Limits information + * + * NOTE: Group 8 contains the values to limit the + * maximum transmit power value based on any + * band edge violations. + */ + /* Read the RD edge power limits */ + return readEepromCTLInfo(ah, ee); +} + +static HAL_STATUS +legacyEepromGet(struct ath_hal *ah, int param, void *val) +{ + HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom; + uint8_t *macaddr; + uint16_t eeval; + uint32_t sum; + int i; + + switch (param) { + case AR_EEP_OPCAP: + *(uint16_t *) val = ee->ee_opCap; + return HAL_OK; + case AR_EEP_REGDMN_0: + *(uint16_t *) val = ee->ee_regdomain; + return HAL_OK; + case AR_EEP_RFSILENT: + if (!ath_hal_eepromRead(ah, AR_EEPROM_RFSILENT, &eeval)) + return HAL_EEREAD; + *(uint16_t *) val = eeval; + return HAL_OK; + case AR_EEP_MACADDR: + sum = 0; + macaddr = val; + for (i = 0; i < 3; i++) { + if (!ath_hal_eepromRead(ah, AR_EEPROM_MAC(2-i), &eeval)) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: cannot read EEPROM location %u\n", + __func__, i); + return HAL_EEREAD; + } + sum += eeval; + macaddr[2*i] = eeval >> 8; + macaddr[2*i + 1] = eeval & 0xff; + } + if (sum == 0 || sum == 0xffff*3) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: mac address read failed: %s\n", __func__, + ath_hal_ether_sprintf(macaddr)); + return HAL_EEBADMAC; + } + return HAL_OK; + case AR_EEP_RFKILL: + HALASSERT(val == AH_NULL); + return ee->ee_rfKill ? HAL_OK : HAL_EIO; + case AR_EEP_AMODE: + HALASSERT(val == AH_NULL); + return ee->ee_Amode ? HAL_OK : HAL_EIO; + case AR_EEP_BMODE: + HALASSERT(val == AH_NULL); + return ee->ee_Bmode ? HAL_OK : HAL_EIO; + case AR_EEP_GMODE: + HALASSERT(val == AH_NULL); + return ee->ee_Gmode ? HAL_OK : HAL_EIO; + case AR_EEP_TURBO5DISABLE: + HALASSERT(val == AH_NULL); + return ee->ee_turbo5Disable ? HAL_OK : HAL_EIO; + case AR_EEP_TURBO2DISABLE: + HALASSERT(val == AH_NULL); + return ee->ee_turbo2Disable ? HAL_OK : HAL_EIO; + case AR_EEP_ISTALON: /* Talon detect */ + HALASSERT(val == AH_NULL); + return (ee->ee_version >= AR_EEPROM_VER5_4 && + ath_hal_eepromRead(ah, 0x0b, &eeval) && eeval == 1) ? + HAL_OK : HAL_EIO; + case AR_EEP_32KHZCRYSTAL: + HALASSERT(val == AH_NULL); + return ee->ee_exist32kHzCrystal ? HAL_OK : HAL_EIO; + case AR_EEP_COMPRESS: + HALASSERT(val == AH_NULL); + return (ee->ee_opCap & AR_EEPROM_EEPCAP_COMPRESS_DIS) == 0 ? + HAL_OK : HAL_EIO; + case AR_EEP_FASTFRAME: + HALASSERT(val == AH_NULL); + return (ee->ee_opCap & AR_EEPROM_EEPCAP_FASTFRAME_DIS) == 0 ? + HAL_OK : HAL_EIO; + case AR_EEP_AES: + HALASSERT(val == AH_NULL); + return (ee->ee_opCap & AR_EEPROM_EEPCAP_AES_DIS) == 0 ? + HAL_OK : HAL_EIO; + case AR_EEP_BURST: + HALASSERT(val == AH_NULL); + return (ee->ee_opCap & AR_EEPROM_EEPCAP_BURST_DIS) == 0 ? + HAL_OK : HAL_EIO; + case AR_EEP_MAXQCU: + if (ee->ee_opCap & AR_EEPROM_EEPCAP_MAXQCU) { + *(uint16_t *) val = + MS(ee->ee_opCap, AR_EEPROM_EEPCAP_MAXQCU); + return HAL_OK; + } else + return HAL_EIO; + case AR_EEP_KCENTRIES: + if (ee->ee_opCap & AR_EEPROM_EEPCAP_KC_ENTRIES) { + *(uint16_t *) val = + 1 << MS(ee->ee_opCap, AR_EEPROM_EEPCAP_KC_ENTRIES); + return HAL_OK; + } else + return HAL_EIO; + case AR_EEP_ANTGAINMAX_5: + *(int8_t *) val = ee->ee_antennaGainMax[0]; + return HAL_OK; + case AR_EEP_ANTGAINMAX_2: + *(int8_t *) val = ee->ee_antennaGainMax[1]; + return HAL_OK; + case AR_EEP_WRITEPROTECT: + HALASSERT(val == AH_NULL); + return (ee->ee_protect & AR_EEPROM_PROTECT_WP_128_191) ? + HAL_OK : HAL_EIO; + } + return HAL_EINVAL; +} + +static HAL_BOOL +legacyEepromSet(struct ath_hal *ah, int param, int v) +{ + HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom; + + switch (param) { + case AR_EEP_AMODE: + ee->ee_Amode = v; + return HAL_OK; + case AR_EEP_BMODE: + ee->ee_Bmode = v; + return HAL_OK; + case AR_EEP_GMODE: + ee->ee_Gmode = v; + return HAL_OK; + case AR_EEP_TURBO5DISABLE: + ee->ee_turbo5Disable = v; + return HAL_OK; + case AR_EEP_TURBO2DISABLE: + ee->ee_turbo2Disable = v; + return HAL_OK; + case AR_EEP_COMPRESS: + if (v) + ee->ee_opCap &= ~AR_EEPROM_EEPCAP_COMPRESS_DIS; + else + ee->ee_opCap |= AR_EEPROM_EEPCAP_COMPRESS_DIS; + return HAL_OK; + case AR_EEP_FASTFRAME: + if (v) + ee->ee_opCap &= ~AR_EEPROM_EEPCAP_FASTFRAME_DIS; + else + ee->ee_opCap |= AR_EEPROM_EEPCAP_FASTFRAME_DIS; + return HAL_OK; + case AR_EEP_AES: + if (v) + ee->ee_opCap &= ~AR_EEPROM_EEPCAP_AES_DIS; + else + ee->ee_opCap |= AR_EEPROM_EEPCAP_AES_DIS; + return HAL_OK; + case AR_EEP_BURST: + if (v) + ee->ee_opCap &= ~AR_EEPROM_EEPCAP_BURST_DIS; + else + ee->ee_opCap |= AR_EEPROM_EEPCAP_BURST_DIS; + return HAL_OK; + } + return HAL_EINVAL; +} + +static HAL_BOOL +legacyEepromDiag(struct ath_hal *ah, int request, + const void *args, uint32_t argsize, void **result, uint32_t *resultsize) +{ + HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom; + const EEPROM_POWER_EXPN_5112 *pe; + + switch (request) { + case HAL_DIAG_EEPROM: + *result = ee; + *resultsize = sizeof(*ee); + return AH_TRUE; + case HAL_DIAG_EEPROM_EXP_11A: + case HAL_DIAG_EEPROM_EXP_11B: + case HAL_DIAG_EEPROM_EXP_11G: + pe = &ee->ee_modePowerArray5112[ + request - HAL_DIAG_EEPROM_EXP_11A]; + *result = pe->pChannels; + *resultsize = (*result == AH_NULL) ? 0 : + roundup(sizeof(uint16_t) * pe->numChannels, + sizeof(uint32_t)) + + sizeof(EXPN_DATA_PER_CHANNEL_5112) * pe->numChannels; + return AH_TRUE; + } + return AH_FALSE; +} + +static uint16_t +legacyEepromGetSpurChan(struct ath_hal *ah, int ix, HAL_BOOL is2GHz) +{ + HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom; + + HALASSERT(0 <= ix && ix < AR_EEPROM_MODAL_SPURS); + return ee->ee_spurChans[ix][is2GHz]; +} + +/* + * Reclaim any EEPROM-related storage. + */ +static void +legacyEepromDetach(struct ath_hal *ah) +{ + HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom; + + if (ee->ee_version >= AR_EEPROM_VER4_0 && ee->ee_eepMap == 1) + return freeEepromRawPowerCalInfo5112(ah, ee); + ath_hal_free(ee); + AH_PRIVATE(ah)->ah_eeprom = AH_NULL; +} + +/* + * These are not valid 2.4 channels, either we change 'em + * or we need to change the coding to accept them. + */ +static const uint16_t channels11b[] = { 2412, 2447, 2484 }; +static const uint16_t channels11g[] = { 2312, 2412, 2484 }; + +HAL_STATUS +ath_hal_legacyEepromAttach(struct ath_hal *ah) +{ + HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom; + uint32_t sum, eepMax; + uint16_t eeversion, eeprotect, eeval; + u_int i; + + HALASSERT(ee == AH_NULL); + + if (!ath_hal_eepromRead(ah, AR_EEPROM_VERSION, &eeversion)) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: unable to read EEPROM version\n", __func__); + return HAL_EEREAD; + } + if (eeversion < AR_EEPROM_VER3) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unsupported EEPROM version " + "%u (0x%x) found\n", __func__, eeversion, eeversion); + return HAL_EEVERSION; + } + + if (!ath_hal_eepromRead(ah, AR_EEPROM_PROTECT, &eeprotect)) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: cannot read EEPROM protection " + "bits; read locked?\n", __func__); + return HAL_EEREAD; + } + HALDEBUG(ah, HAL_DEBUG_ATTACH, "EEPROM protect 0x%x\n", eeprotect); + /* XXX check proper access before continuing */ + + /* + * Read the Atheros EEPROM entries and calculate the checksum. + */ + if (!ath_hal_eepromRead(ah, AR_EEPROM_SIZE_UPPER, &eeval)) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: cannot read EEPROM upper size\n" , __func__); + return HAL_EEREAD; + } + if (eeval != 0) { + eepMax = (eeval & AR_EEPROM_SIZE_UPPER_MASK) << + AR_EEPROM_SIZE_ENDLOC_SHIFT; + if (!ath_hal_eepromRead(ah, AR_EEPROM_SIZE_LOWER, &eeval)) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: cannot read EEPROM lower size\n" , __func__); + return HAL_EEREAD; + } + eepMax = (eepMax | eeval) - AR_EEPROM_ATHEROS_BASE; + } else + eepMax = AR_EEPROM_ATHEROS_MAX; + sum = 0; + for (i = 0; i < eepMax; i++) { + if (!ath_hal_eepromRead(ah, AR_EEPROM_ATHEROS(i), &eeval)) { + return HAL_EEREAD; + } + sum ^= eeval; + } + if (sum != 0xffff) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad EEPROM checksum 0x%x\n", + __func__, sum); + return HAL_EEBADSUM; + } + + ee = ath_hal_malloc(sizeof(HAL_EEPROM)); + if (ee == AH_NULL) { + /* XXX message */ + return HAL_ENOMEM; + } + + ee->ee_protect = eeprotect; + ee->ee_version = eeversion; + + ee->ee_numChannels11a = NUM_11A_EEPROM_CHANNELS; + ee->ee_numChannels2_4 = NUM_2_4_EEPROM_CHANNELS; + + for (i = 0; i < NUM_11A_EEPROM_CHANNELS; i ++) + ee->ee_dataPerChannel11a[i].numPcdacValues = NUM_PCDAC_VALUES; + + /* the channel list for 2.4 is fixed, fill this in here */ + for (i = 0; i < NUM_2_4_EEPROM_CHANNELS; i++) { + ee->ee_channels11b[i] = channels11b[i]; + /* XXX 5211 requires a hack though we don't support 11g */ + if (ah->ah_magic == 0x19570405) + ee->ee_channels11g[i] = channels11b[i]; + else + ee->ee_channels11g[i] = channels11g[i]; + ee->ee_dataPerChannel11b[i].numPcdacValues = NUM_PCDAC_VALUES; + ee->ee_dataPerChannel11g[i].numPcdacValues = NUM_PCDAC_VALUES; + } + + if (!legacyEepromReadContents(ah, ee)) { + /* XXX message */ + ath_hal_free(ee); + return HAL_EEREAD; /* XXX */ + } + + AH_PRIVATE(ah)->ah_eeprom = ee; + AH_PRIVATE(ah)->ah_eeversion = eeversion; + AH_PRIVATE(ah)->ah_eepromDetach = legacyEepromDetach; + AH_PRIVATE(ah)->ah_eepromGet = legacyEepromGet; + AH_PRIVATE(ah)->ah_eepromSet = legacyEepromSet; + AH_PRIVATE(ah)->ah_getSpurChan = legacyEepromGetSpurChan; + AH_PRIVATE(ah)->ah_eepromDiag = legacyEepromDiag; + return HAL_OK; +} --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ah_eeprom_v3.h 2009-03-23 17:36:56.000000000 +0000 @@ -0,0 +1,462 @@ +/* + * 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: ah_eeprom_v3.h,v 1.1 2009/03/23 17:14:47 sborrill Exp $ + */ +#ifndef _ATH_AH_EEPROM_V3_H_ +#define _ATH_AH_EEPROM_V3_H_ + +#include "ah_eeprom.h" + +/* EEPROM defines for Version 2 & 3 AR5211 chips */ +#define AR_EEPROM_RFSILENT 0x0f /* RF Silent/Clock Run Enable */ +#define AR_EEPROM_MAC(i) (0x1d+(i)) /* MAC address word */ +#define AR_EEPROM_MAGIC 0x3d /* magic number */ +#define AR_EEPROM_PROTECT 0x3f /* EEPROM protect bits */ +#define AR_EEPROM_PROTECT_PCIE 0x01 /* EEPROM protect bits for Condor/Swan*/ +#define AR_EEPROM_REG_DOMAIN 0xbf /* current regulatory domain */ +#define AR_EEPROM_ATHEROS_BASE 0xc0 /* Base of Atheros-specific data */ +#define AR_EEPROM_ATHEROS(i) (AR_EEPROM_ATHEROS_BASE+(i)) +#define AR_EEPROM_ATHEROS_MAX (0x400-AR_EEPROM_ATHEROS_BASE) +#define AR_EEPROM_VERSION AR_EEPROM_ATHEROS(1) + +/* FLASH(EEPROM) Defines for AR531X chips */ +#define AR_EEPROM_SIZE_LOWER 0x1b /* size info -- lower */ +#define AR_EEPROM_SIZE_UPPER 0x1c /* size info -- upper */ +#define AR_EEPROM_SIZE_UPPER_MASK 0xfff0 +#define AR_EEPROM_SIZE_UPPER_SHIFT 4 +#define AR_EEPROM_SIZE_ENDLOC_SHIFT 12 +#define AR_EEPROM_ATHEROS_MAX_LOC 0x400 +#define AR_EEPROM_ATHEROS_MAX_OFF (AR_EEPROM_ATHEROS_MAX_LOC-AR_EEPROM_ATHEROS_BASE) + +/* regulatory capabilities offsets */ +#define AR_EEPROM_REG_CAPABILITIES_OFFSET 0xCA +#define AR_EEPROM_REG_CAPABILITIES_OFFSET_PRE4_0 0xCF /* prior to 4.0 */ + +/* regulatory capabilities */ +#define AR_EEPROM_EEREGCAP_EN_FCC_MIDBAND 0x0040 +#define AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN 0x0080 +#define AR_EEPROM_EEREGCAP_EN_KK_U2 0x0100 +#define AR_EEPROM_EEREGCAP_EN_KK_MIDBAND 0x0200 +#define AR_EEPROM_EEREGCAP_EN_KK_U1_ODD 0x0400 +#define AR_EEPROM_EEREGCAP_EN_KK_NEW_11A 0x0800 + +/* regulatory capabilities prior to eeprom version 4.0 */ +#define AR_EEPROM_EEREGCAP_EN_KK_U1_ODD_PRE4_0 0x4000 +#define AR_EEPROM_EEREGCAP_EN_KK_NEW_11A_PRE4_0 0x8000 + +/* + * AR2413 (includes AR5413) + */ +#define AR_EEPROM_SERIAL_NUM_OFFSET 0xB0 /* EEPROM serial number */ +#define AR_EEPROM_SERIAL_NUM_SIZE 12 /* EEPROM serial number size */ +#define AR_EEPROM_CAPABILITIES_OFFSET 0xC9 /* EEPROM Location of capabilities */ + +#define AR_EEPROM_EEPCAP_COMPRESS_DIS 0x0001 +#define AR_EEPROM_EEPCAP_AES_DIS 0x0002 +#define AR_EEPROM_EEPCAP_FASTFRAME_DIS 0x0004 +#define AR_EEPROM_EEPCAP_BURST_DIS 0x0008 +#define AR_EEPROM_EEPCAP_MAXQCU 0x01F0 +#define AR_EEPROM_EEPCAP_MAXQCU_S 4 +#define AR_EEPROM_EEPCAP_HEAVY_CLIP_EN 0x0200 +#define AR_EEPROM_EEPCAP_KC_ENTRIES 0xF000 +#define AR_EEPROM_EEPCAP_KC_ENTRIES_S 12 + +/* XXX used to index various EEPROM-derived data structures */ +enum { + headerInfo11A = 0, + headerInfo11B = 1, + headerInfo11G = 2, +}; + +#define GROUPS_OFFSET3_2 0x100 /* groups offset for ver3.2 and earlier */ +#define GROUPS_OFFSET3_3 0x150 /* groups offset for ver3.3 */ +/* relative offset of GROUPi to GROUPS_OFFSET */ +#define GROUP1_OFFSET 0x0 +#define GROUP2_OFFSET 0x5 +#define GROUP3_OFFSET 0x37 +#define GROUP4_OFFSET 0x46 +#define GROUP5_OFFSET 0x55 +#define GROUP6_OFFSET 0x65 +#define GROUP7_OFFSET 0x69 +#define GROUP8_OFFSET 0x6f + +/* RF silent fields in EEPROM */ +#define AR_EEPROM_RFSILENT_GPIO_SEL 0x001c +#define AR_EEPROM_RFSILENT_GPIO_SEL_S 2 +#define AR_EEPROM_RFSILENT_POLARITY 0x0002 +#define AR_EEPROM_RFSILENT_POLARITY_S 1 + +/* Protect Bits RP is read protect, WP is write protect */ +#define AR_EEPROM_PROTECT_RP_0_31 0x0001 +#define AR_EEPROM_PROTECT_WP_0_31 0x0002 +#define AR_EEPROM_PROTECT_RP_32_63 0x0004 +#define AR_EEPROM_PROTECT_WP_32_63 0x0008 +#define AR_EEPROM_PROTECT_RP_64_127 0x0010 +#define AR_EEPROM_PROTECT_WP_64_127 0x0020 +#define AR_EEPROM_PROTECT_RP_128_191 0x0040 +#define AR_EEPROM_PROTECT_WP_128_191 0x0080 +#define AR_EEPROM_PROTECT_RP_192_207 0x0100 +#define AR_EEPROM_PROTECT_WP_192_207 0x0200 +#define AR_EEPROM_PROTECT_RP_208_223 0x0400 +#define AR_EEPROM_PROTECT_WP_208_223 0x0800 +#define AR_EEPROM_PROTECT_RP_224_239 0x1000 +#define AR_EEPROM_PROTECT_WP_224_239 0x2000 +#define AR_EEPROM_PROTECT_RP_240_255 0x4000 +#define AR_EEPROM_PROTECT_WP_240_255 0x8000 + +#define AR_EEPROM_MODAL_SPURS 5 +#define AR_SPUR_5413_1 1640 /* Freq 2464 */ +#define AR_SPUR_5413_2 1200 /* Freq 2420 */ + +/* + * EEPROM fixed point conversion scale factors. + * NB: if you change one be sure to keep the other in sync. + */ +#define EEP_SCALE 100 /* conversion scale to avoid fp arith */ +#define EEP_DELTA 10 /* SCALE/10, to avoid arith divide */ + +#define PWR_MIN 0 +#define PWR_MAX 3150 /* 31.5 * SCALE */ +#define PWR_STEP 50 /* 0.5 * SCALE */ +/* Keep 2 above defines together */ + +#define NUM_11A_EEPROM_CHANNELS 10 +#define NUM_2_4_EEPROM_CHANNELS 3 +#define NUM_PCDAC_VALUES 11 +#define NUM_TEST_FREQUENCIES 8 +#define NUM_EDGES 8 +#define NUM_INTERCEPTS 11 +#define FREQ_MASK 0x7f +#define FREQ_MASK_3_3 0xff /* expanded in version 3.3 */ +#define PCDAC_MASK 0x3f +#define POWER_MASK 0x3f +#define NON_EDGE_FLAG_MASK 0x40 +#define CHANNEL_POWER_INFO 8 +#define OBDB_UNSET 0xffff +#define CHANNEL_UNUSED 0xff +#define SCALE_OC_DELTA(_x) (((_x) * 2) / 10) + +/* Used during pcdac table construction */ +#define PCDAC_START 1 +#define PCDAC_STOP 63 +#define PCDAC_STEP 1 +#define PWR_TABLE_SIZE 64 +#define MAX_RATE_POWER 63 + +/* Used during power/rate table construction */ +#define NUM_CTLS 16 +#define NUM_CTLS_3_3 32 /* expanded in version 3.3 */ +#define NUM_CTLS_MAX NUM_CTLS_3_3 + +typedef struct fullPcdacStruct { + uint16_t channelValue; + uint16_t pcdacMin; + uint16_t pcdacMax; + uint16_t numPcdacValues; + uint16_t PcdacValues[64]; + /* power is 32bit since in dest it is scaled */ + int16_t PwrValues[64]; +} FULL_PCDAC_STRUCT; + +typedef struct dataPerChannel { + uint16_t channelValue; + uint16_t pcdacMin; + uint16_t pcdacMax; + uint16_t numPcdacValues; + uint16_t PcdacValues[NUM_PCDAC_VALUES]; + /* NB: power is 32bit since in dest it is scaled */ + int16_t PwrValues[NUM_PCDAC_VALUES]; +} DATA_PER_CHANNEL; + +/* points to the appropriate pcdac structs in the above struct based on mode */ +typedef struct pcdacsEeprom { + const uint16_t *pChannelList; + uint16_t numChannels; + const DATA_PER_CHANNEL *pDataPerChannel; +} PCDACS_EEPROM; + +typedef struct trgtPowerInfo { + uint16_t twicePwr54; + uint16_t twicePwr48; + uint16_t twicePwr36; + uint16_t twicePwr6_24; + uint16_t testChannel; +} TRGT_POWER_INFO; + +typedef struct trgtPowerAllModes { + uint16_t numTargetPwr_11a; + TRGT_POWER_INFO trgtPwr_11a[NUM_TEST_FREQUENCIES]; + uint16_t numTargetPwr_11g; + TRGT_POWER_INFO trgtPwr_11g[3]; + uint16_t numTargetPwr_11b; + TRGT_POWER_INFO trgtPwr_11b[2]; +} TRGT_POWER_ALL_MODES; + +typedef struct cornerCalInfo { + uint16_t gSel; + uint16_t pd84; + uint16_t pd90; + uint16_t clip; +} CORNER_CAL_INFO; + +/* + * EEPROM version 4 definitions + */ +#define NUM_XPD_PER_CHANNEL 4 +#define NUM_POINTS_XPD0 4 +#define NUM_POINTS_XPD3 3 +#define IDEAL_10dB_INTERCEPT_2G 35 +#define IDEAL_10dB_INTERCEPT_5G 55 + +#define TENX_OFDM_CCK_DELTA_INIT 15 /* power 1.5 dbm */ +#define TENX_CH14_FILTER_CCK_DELTA_INIT 15 /* power 1.5 dbm */ +#define CCK_OFDM_GAIN_DELTA 15 + +#define NUM_TARGET_POWER_LOCATIONS_11B 4 +#define NUM_TARGET_POWER_LOCATIONS_11G 6 + + +typedef struct { + uint16_t xpd_gain; + uint16_t numPcdacs; + uint16_t pcdac[NUM_POINTS_XPD0]; + int16_t pwr_t4[NUM_POINTS_XPD0]; /* or gainF */ +} EXPN_DATA_PER_XPD_5112; + +typedef struct { + uint16_t channelValue; + int16_t maxPower_t4; + EXPN_DATA_PER_XPD_5112 pDataPerXPD[NUM_XPD_PER_CHANNEL]; +} EXPN_DATA_PER_CHANNEL_5112; + +typedef struct { + uint16_t *pChannels; + uint16_t numChannels; + uint16_t xpdMask; /* mask of permitted xpd_gains */ + EXPN_DATA_PER_CHANNEL_5112 *pDataPerChannel; +} EEPROM_POWER_EXPN_5112; + +typedef struct { + uint16_t channelValue; + uint16_t pcd1_xg0; + int16_t pwr1_xg0; + uint16_t pcd2_delta_xg0; + int16_t pwr2_xg0; + uint16_t pcd3_delta_xg0; + int16_t pwr3_xg0; + uint16_t pcd4_delta_xg0; + int16_t pwr4_xg0; + int16_t maxPower_t4; + int16_t pwr1_xg3; /* pcdac = 20 */ + int16_t pwr2_xg3; /* pcdac = 35 */ + int16_t pwr3_xg3; /* pcdac = 63 */ + /* XXX - Should be pwr1_xg2, etc to agree with documentation */ +} EEPROM_DATA_PER_CHANNEL_5112; + +typedef struct { + uint16_t pChannels[NUM_11A_EEPROM_CHANNELS]; + uint16_t numChannels; + uint16_t xpdMask; /* mask of permitted xpd_gains */ + EEPROM_DATA_PER_CHANNEL_5112 pDataPerChannel[NUM_11A_EEPROM_CHANNELS]; +} EEPROM_POWER_5112; + +/* + * EEPROM version 5 definitions (Griffin, et. al.). + */ +#define NUM_2_4_EEPROM_CHANNELS_2413 4 +#define NUM_11A_EEPROM_CHANNELS_2413 10 +#define PWR_TABLE_SIZE_2413 128 + +/* Used during pdadc construction */ +#define MAX_NUM_PDGAINS_PER_CHANNEL 4 +#define NUM_PDGAINS_PER_CHANNEL 2 +#define NUM_POINTS_LAST_PDGAIN 5 +#define NUM_POINTS_OTHER_PDGAINS 4 +#define XPD_GAIN1_GEN5 3 +#define XPD_GAIN2_GEN5 1 +#define MAX_PWR_RANGE_IN_HALF_DB 64 +#define PD_GAIN_BOUNDARY_STRETCH_IN_HALF_DB 4 + +typedef struct { + uint16_t pd_gain; + uint16_t numVpd; + uint16_t Vpd[NUM_POINTS_LAST_PDGAIN]; + int16_t pwr_t4[NUM_POINTS_LAST_PDGAIN]; /* or gainF */ +} RAW_DATA_PER_PDGAIN_2413; + +typedef struct { + uint16_t channelValue; + int16_t maxPower_t4; + uint16_t numPdGains; /* # Pd Gains per channel */ + RAW_DATA_PER_PDGAIN_2413 pDataPerPDGain[MAX_NUM_PDGAINS_PER_CHANNEL]; +} RAW_DATA_PER_CHANNEL_2413; + +/* XXX: assumes NUM_11A_EEPROM_CHANNELS_2413 >= NUM_2_4_EEPROM_CHANNELS_2413 ??? */ +typedef struct { + uint16_t pChannels[NUM_11A_EEPROM_CHANNELS_2413]; + uint16_t numChannels; + uint16_t xpd_mask; /* mask of permitted xpd_gains */ + RAW_DATA_PER_CHANNEL_2413 pDataPerChannel[NUM_11A_EEPROM_CHANNELS_2413]; +} RAW_DATA_STRUCT_2413; + +typedef struct { + uint16_t channelValue; + uint16_t numPdGains; + uint16_t Vpd_I[MAX_NUM_PDGAINS_PER_CHANNEL]; + int16_t pwr_I[MAX_NUM_PDGAINS_PER_CHANNEL]; + uint16_t Vpd_delta[NUM_POINTS_LAST_PDGAIN] + [MAX_NUM_PDGAINS_PER_CHANNEL]; + int16_t pwr_delta_t2[NUM_POINTS_LAST_PDGAIN] + [MAX_NUM_PDGAINS_PER_CHANNEL]; + int16_t maxPower_t4; +} EEPROM_DATA_PER_CHANNEL_2413; + +typedef struct { + uint16_t pChannels[NUM_11A_EEPROM_CHANNELS_2413]; + uint16_t numChannels; + uint16_t xpd_mask; /* mask of permitted xpd_gains */ + EEPROM_DATA_PER_CHANNEL_2413 pDataPerChannel[NUM_11A_EEPROM_CHANNELS_2413]; +} EEPROM_DATA_STRUCT_2413; + +/* + * Information retrieved from EEPROM. + */ +typedef struct { + uint16_t ee_version; /* Version field */ + uint16_t ee_protect; /* EEPROM protect field */ + uint16_t ee_regdomain; /* Regulatory domain */ + + /* General Device Parameters */ + uint16_t ee_turbo5Disable; + uint16_t ee_turbo2Disable; + uint16_t ee_rfKill; + uint16_t ee_deviceType; + uint16_t ee_turbo2WMaxPower5; + uint16_t ee_turbo2WMaxPower2; + uint16_t ee_xrTargetPower5; + uint16_t ee_xrTargetPower2; + uint16_t ee_Amode; + uint16_t ee_regCap; + uint16_t ee_Bmode; + uint16_t ee_Gmode; + int8_t ee_antennaGainMax[2]; + uint16_t ee_xtnd5GSupport; + uint8_t ee_cckOfdmPwrDelta; + uint8_t ee_exist32kHzCrystal; + uint16_t ee_targetPowersStart; + uint16_t ee_fixedBias5; + uint16_t ee_fixedBias2; + uint16_t ee_cckOfdmGainDelta; + uint16_t ee_scaledCh14FilterCckDelta; + uint16_t ee_eepMap; + uint16_t ee_earStart; + + /* 5 GHz / 2.4 GHz CKK / 2.4 GHz OFDM common parameters */ + uint16_t ee_switchSettling[3]; + uint16_t ee_txrxAtten[3]; + uint16_t ee_txEndToXLNAOn[3]; + uint16_t ee_thresh62[3]; + uint16_t ee_txEndToXPAOff[3]; + uint16_t ee_txFrameToXPAOn[3]; + int8_t ee_adcDesiredSize[3]; /* 8-bit signed value */ + int8_t ee_pgaDesiredSize[3]; /* 8-bit signed value */ + int16_t ee_noiseFloorThresh[3]; + uint16_t ee_xlnaGain[3]; + uint16_t ee_xgain[3]; + uint16_t ee_xpd[3]; + uint16_t ee_antennaControl[11][3]; + uint16_t ee_falseDetectBackoff[3]; + uint16_t ee_gainI[3]; + uint16_t ee_rxtxMargin[3]; + + /* new parameters added for the AR2413 */ + HAL_BOOL ee_disableXr5; + HAL_BOOL ee_disableXr2; + uint16_t ee_eepMap2PowerCalStart; + uint16_t ee_capField; + + uint16_t ee_switchSettlingTurbo[2]; + uint16_t ee_txrxAttenTurbo[2]; + int8_t ee_adcDesiredSizeTurbo[2]; + int8_t ee_pgaDesiredSizeTurbo[2]; + uint16_t ee_rxtxMarginTurbo[2]; + + /* 5 GHz parameters */ + uint16_t ee_ob1; + uint16_t ee_db1; + uint16_t ee_ob2; + uint16_t ee_db2; + uint16_t ee_ob3; + uint16_t ee_db3; + uint16_t ee_ob4; + uint16_t ee_db4; + + /* 2.4 GHz parameters */ + uint16_t ee_obFor24; + uint16_t ee_dbFor24; + uint16_t ee_obFor24g; + uint16_t ee_dbFor24g; + uint16_t ee_ob2GHz[2]; + uint16_t ee_db2GHz[2]; + uint16_t ee_numCtls; + uint16_t ee_ctl[NUM_CTLS_MAX]; + uint16_t ee_iqCalI[2]; + uint16_t ee_iqCalQ[2]; + uint16_t ee_calPier11g[NUM_2_4_EEPROM_CHANNELS]; + uint16_t ee_calPier11b[NUM_2_4_EEPROM_CHANNELS]; + + /* corner calibration information */ + CORNER_CAL_INFO ee_cornerCal; + + uint16_t ee_opCap; + + /* 11a info */ + uint16_t ee_channels11a[NUM_11A_EEPROM_CHANNELS]; + uint16_t ee_numChannels11a; + DATA_PER_CHANNEL ee_dataPerChannel11a[NUM_11A_EEPROM_CHANNELS]; + + uint16_t ee_numChannels2_4; + uint16_t ee_channels11g[NUM_2_4_EEPROM_CHANNELS]; + uint16_t ee_channels11b[NUM_2_4_EEPROM_CHANNELS]; + uint16_t ee_spurChans[AR_EEPROM_MODAL_SPURS][2]; + + /* 11g info */ + DATA_PER_CHANNEL ee_dataPerChannel11g[NUM_2_4_EEPROM_CHANNELS]; + + /* 11b info */ + DATA_PER_CHANNEL ee_dataPerChannel11b[NUM_2_4_EEPROM_CHANNELS]; + + TRGT_POWER_ALL_MODES ee_tpow; + + RD_EDGES_POWER ee_rdEdgesPower[NUM_EDGES*NUM_CTLS_MAX]; + + union { + EEPROM_POWER_EXPN_5112 eu_modePowerArray5112[3]; + RAW_DATA_STRUCT_2413 eu_rawDataset2413[3]; + } ee_u; +} HAL_EEPROM; + +/* write-around defines */ +#define ee_numTargetPwr_11a ee_tpow.numTargetPwr_11a +#define ee_trgtPwr_11a ee_tpow.trgtPwr_11a +#define ee_numTargetPwr_11g ee_tpow.numTargetPwr_11g +#define ee_trgtPwr_11g ee_tpow.trgtPwr_11g +#define ee_numTargetPwr_11b ee_tpow.numTargetPwr_11b +#define ee_trgtPwr_11b ee_tpow.trgtPwr_11b +#define ee_modePowerArray5112 ee_u.eu_modePowerArray5112 +#define ee_rawDataset2413 ee_u.eu_rawDataset2413 +#endif /* _ATH_AH_EEPROM_V3_H_ */ --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ah_internal.h 2009-04-17 13:29:53.000000000 +0100 @@ -0,0 +1,794 @@ +/* + * 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: ah_internal.h,v 1.2 2009/03/23 17:17:07 sborrill Exp $ + */ +#ifndef _ATH_AH_INTERAL_H_ +#define _ATH_AH_INTERAL_H_ +/* + * Atheros Device Hardware Access Layer (HAL). + * + * Internal definitions. + */ +#define AH_NULL 0 +#define AH_MIN(a,b) ((a)<(b)?(a):(b)) +#define AH_MAX(a,b) ((a)>(b)?(a):(b)) + +#ifndef NBBY +#define NBBY 8 /* number of bits/byte */ +#endif + +#ifndef roundup +#define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) /* to any y */ +#endif +#ifndef howmany +#define howmany(x, y) (((x)+((y)-1))/(y)) +#endif + +#ifndef offsetof +#define offsetof(type, field) ((size_t)(&((type *)0)->field)) +#endif + +/* + * Remove const in a way that keeps the compiler happy. + * This works for gcc but may require other magic for + * other compilers (not sure where this should reside). + * Note that uintptr_t is C99. + */ +#ifndef __DECONST +#define __DECONST(type, var) ((type)(unsigned long)(const void *)(var)) +#endif + +typedef struct { + uint16_t start; /* first register */ + uint16_t end; /* ending register or zero */ +} HAL_REGRANGE; + +/* + * Transmit power scale factor. + * + * NB: This is not public because we want to discourage the use of + * scaling; folks should use the tx power limit interface. + */ +typedef enum { + HAL_TP_SCALE_MAX = 0, /* no scaling (default) */ + HAL_TP_SCALE_50 = 1, /* 50% of max (-3 dBm) */ + HAL_TP_SCALE_25 = 2, /* 25% of max (-6 dBm) */ + HAL_TP_SCALE_12 = 3, /* 12% of max (-9 dBm) */ + HAL_TP_SCALE_MIN = 4, /* min, but still on */ +} HAL_TP_SCALE; + +typedef enum { + HAL_CAP_RADAR = 0, /* Radar capability */ + HAL_CAP_AR = 1, /* AR capability */ +} HAL_PHYDIAG_CAPS; + +/* + * Each chip or class of chips registers to offer support. + */ +struct ath_hal_chip { + const char *name; + const char *(*probe)(uint16_t vendorid, uint16_t devid); + struct ath_hal *(*attach)(uint16_t devid, HAL_SOFTC, + HAL_BUS_TAG, HAL_BUS_HANDLE, HAL_STATUS *error); +}; +#ifndef AH_CHIP +#define AH_CHIP(_name, _probe, _attach) \ +static struct ath_hal_chip name##_chip = { \ + .name = #_name, \ + .probe = _probe, \ + .attach = _attach \ +}; \ +OS_DATA_SET(ah_chips, name##_chip) +#endif + +/* + * Each RF backend registers to offer support; this is mostly + * used by multi-chip 5212 solutions. Single-chip solutions + * have a fixed idea about which RF to use. + */ +struct ath_hal_rf { + const char *name; + HAL_BOOL (*probe)(struct ath_hal *ah); + HAL_BOOL (*attach)(struct ath_hal *ah, HAL_STATUS *ecode); +}; +#ifndef AH_RF +#define AH_RF(_name, _probe, _attach) \ +static struct ath_hal_rf _name##_rf = { \ + .name = __STRING(_name), \ + .probe = _probe, \ + .attach = _attach \ +}; \ +OS_DATA_SET(ah_rfs, _name##_rf) +#endif + +struct ath_hal_rf *ath_hal_rfprobe(struct ath_hal *ah, HAL_STATUS *ecode); + +/* + * Internal form of a HAL_CHANNEL. Note that the structure + * must be defined such that you can cast references to a + * HAL_CHANNEL so don't shuffle the first two members. + */ +typedef struct { + uint32_t channelFlags; + uint16_t channel; /* NB: must be first for casting */ + uint8_t privFlags; + int8_t maxRegTxPower; + int8_t maxTxPower; + int8_t minTxPower; /* as above... */ + + HAL_BOOL bssSendHere; + uint8_t gainI; + HAL_BOOL iqCalValid; + uint8_t calValid; /* bitmask of cal types */ + int8_t iCoff; + int8_t qCoff; + int16_t rawNoiseFloor; + int16_t noiseFloorAdjust; + int8_t antennaMax; + uint32_t regDmnFlags; /* Flags for channel use in reg */ + uint32_t conformanceTestLimit; /* conformance test limit from reg domain */ + uint16_t mainSpur; /* cached spur value for this cahnnel */ +} HAL_CHANNEL_INTERNAL; + +typedef struct { + uint32_t halChanSpreadSupport : 1, + halSleepAfterBeaconBroken : 1, + halCompressSupport : 1, + halBurstSupport : 1, + halFastFramesSupport : 1, + halChapTuningSupport : 1, + halTurboGSupport : 1, + halTurboPrimeSupport : 1, + halMicAesCcmSupport : 1, + halMicCkipSupport : 1, + halMicTkipSupport : 1, + halTkipMicTxRxKeySupport : 1, + halCipherAesCcmSupport : 1, + halCipherCkipSupport : 1, + halCipherTkipSupport : 1, + halPSPollBroken : 1, + halVEOLSupport : 1, + halBssIdMaskSupport : 1, + halMcastKeySrchSupport : 1, + halTsfAddSupport : 1, + halChanHalfRate : 1, + halChanQuarterRate : 1, + halHTSupport : 1, + halRfSilentSupport : 1, + halHwPhyCounterSupport : 1, + halWowSupport : 1, + halWowMatchPatternExact : 1, + halAutoSleepSupport : 1, + halFastCCSupport : 1, + halBtCoexSupport : 1; + uint32_t halRxStbcSupport : 1, + halTxStbcSupport : 1, + halGTTSupport : 1, + halCSTSupport : 1, + halRifsRxSupport : 1, + halRifsTxSupport : 1, + halExtChanDfsSupport : 1, + halForcePpmSupport : 1, + halEnhancedPmSupport : 1, + halMbssidAggrSupport : 1; + uint32_t halWirelessModes; + uint16_t halTotalQueues; + uint16_t halKeyCacheSize; + uint16_t halLow5GhzChan, halHigh5GhzChan; + uint16_t halLow2GhzChan, halHigh2GhzChan; + int halTstampPrecision; + int halRtsAggrLimit; + uint8_t halTxChainMask; + uint8_t halRxChainMask; + uint8_t halNumGpioPins; + uint8_t halNumAntCfg2GHz; + uint8_t halNumAntCfg5GHz; +} HAL_CAPABILITIES; + +/* + * The ``private area'' follows immediately after the ``public area'' + * in the data structure returned by ath_hal_attach. Private data are + * used by device-independent code such as the regulatory domain support. + * In general, code within the HAL should never depend on data in the + * public area. Instead any public data needed internally should be + * shadowed here. + * + * When declaring a device-specific ath_hal data structure this structure + * is assumed to at the front; e.g. + * + * struct ath_hal_5212 { + * struct ath_hal_private ah_priv; + * ... + * }; + * + * It might be better to manage the method pointers in this structure + * using an indirect pointer to a read-only data structure but this would + * disallow class-style method overriding. + */ +struct ath_hal_private { + struct ath_hal h; /* public area */ + + /* NB: all methods go first to simplify initialization */ + HAL_BOOL (*ah_getChannelEdges)(struct ath_hal*, + uint16_t channelFlags, + uint16_t *lowChannel, uint16_t *highChannel); + u_int (*ah_getWirelessModes)(struct ath_hal*); + HAL_BOOL (*ah_eepromRead)(struct ath_hal *, u_int off, + uint16_t *data); + HAL_BOOL (*ah_eepromWrite)(struct ath_hal *, u_int off, + uint16_t data); + HAL_BOOL (*ah_gpioCfgOutput)(struct ath_hal *, uint32_t gpio); + HAL_BOOL (*ah_gpioCfgInput)(struct ath_hal *, uint32_t gpio); + uint32_t (*ah_gpioGet)(struct ath_hal *, uint32_t gpio); + HAL_BOOL (*ah_gpioSet)(struct ath_hal *, + uint32_t gpio, uint32_t val); + void (*ah_gpioSetIntr)(struct ath_hal*, u_int, uint32_t); + HAL_BOOL (*ah_getChipPowerLimits)(struct ath_hal *, + HAL_CHANNEL *, uint32_t); + int16_t (*ah_getNfAdjust)(struct ath_hal *, + const HAL_CHANNEL_INTERNAL*); + void (*ah_getNoiseFloor)(struct ath_hal *, + int16_t nfarray[]); + + void *ah_eeprom; /* opaque EEPROM state */ + uint16_t ah_eeversion; /* EEPROM version */ + void (*ah_eepromDetach)(struct ath_hal *); + HAL_STATUS (*ah_eepromGet)(struct ath_hal *, int, void *); + HAL_BOOL (*ah_eepromSet)(struct ath_hal *, int, int); + uint16_t (*ah_getSpurChan)(struct ath_hal *, int, HAL_BOOL); + HAL_BOOL (*ah_eepromDiag)(struct ath_hal *, int request, + const void *args, uint32_t argsize, + void **result, uint32_t *resultsize); + + /* + * Device revision information. + */ + uint16_t ah_devid; /* PCI device ID */ + uint16_t ah_subvendorid; /* PCI subvendor ID */ + uint32_t ah_macVersion; /* MAC version id */ + uint16_t ah_macRev; /* MAC revision */ + uint16_t ah_phyRev; /* PHY revision */ + uint16_t ah_analog5GhzRev; /* 2GHz radio revision */ + uint16_t ah_analog2GhzRev; /* 5GHz radio revision */ + + + HAL_OPMODE ah_opmode; /* operating mode from reset */ + HAL_CAPABILITIES ah_caps; /* device capabilities */ + uint32_t ah_diagreg; /* user-specified AR_DIAG_SW */ + int16_t ah_powerLimit; /* tx power cap */ + uint16_t ah_maxPowerLevel; /* calculated max tx power */ + u_int ah_tpScale; /* tx power scale factor */ + uint32_t ah_11nCompat; /* 11n compat controls */ + + /* + * State for regulatory domain handling. + */ + HAL_REG_DOMAIN ah_currentRD; /* Current regulatory domain */ + HAL_CTRY_CODE ah_countryCode; /* current country code */ + HAL_CHANNEL_INTERNAL ah_channels[256]; /* calculated channel list */ + u_int ah_nchan; /* valid channels in list */ + HAL_CHANNEL_INTERNAL *ah_curchan; /* current channel */ + + uint8_t ah_coverageClass; /* coverage class */ + HAL_BOOL ah_regdomainUpdate; /* regdomain is updated? */ + /* + * RF Silent handling; setup according to the EEPROM. + */ + uint16_t ah_rfsilent; /* GPIO pin + polarity */ + HAL_BOOL ah_rfkillEnabled; /* enable/disable RfKill */ + /* + * Diagnostic support for discriminating HIUERR reports. + */ + uint32_t ah_fatalState[6]; /* AR_ISR+shadow regs */ + int ah_rxornIsFatal; /* how to treat HAL_INT_RXORN */ +}; + +#define AH_PRIVATE(_ah) ((struct ath_hal_private *)(_ah)) + +#define ath_hal_getChannelEdges(_ah, _cf, _lc, _hc) \ + AH_PRIVATE(_ah)->ah_getChannelEdges(_ah, _cf, _lc, _hc) +#define ath_hal_getWirelessModes(_ah) \ + AH_PRIVATE(_ah)->ah_getWirelessModes(_ah) +#define ath_hal_eepromRead(_ah, _off, _data) \ + AH_PRIVATE(_ah)->ah_eepromRead(_ah, _off, _data) +#define ath_hal_eepromWrite(_ah, _off, _data) \ + AH_PRIVATE(_ah)->ah_eepromWrite(_ah, _off, _data) +#define ath_hal_gpioCfgOutput(_ah, _gpio) \ + AH_PRIVATE(_ah)->ah_gpioCfgOutput(_ah, _gpio) +#define ath_hal_gpioCfgInput(_ah, _gpio) \ + AH_PRIVATE(_ah)->ah_gpioCfgInput(_ah, _gpio) +#define ath_hal_gpioGet(_ah, _gpio) \ + AH_PRIVATE(_ah)->ah_gpioGet(_ah, _gpio) +#define ath_hal_gpioSet(_ah, _gpio, _val) \ + AH_PRIVATE(_ah)->ah_gpioGet(_ah, _gpio, _val) +#define ath_hal_gpioSetIntr(_ah, _gpio, _ilevel) \ + AH_PRIVATE(_ah)->ah_gpioSetIntr(_ah, _gpio, _ilevel) +#define ath_hal_getpowerlimits(_ah, _chans, _nchan) \ + AH_PRIVATE(_ah)->ah_getChipPowerLimits(_ah, _chans, _nchan) +#define ath_hal_getNfAdjust(_ah, _c) \ + AH_PRIVATE(_ah)->ah_getNfAdjust(_ah, _c) +#define ath_hal_getNoiseFloor(_ah, _nfArray) \ + AH_PRIVATE(_ah)->ah_getNoiseFloor(_ah, _nfArray) + +#define ath_hal_eepromDetach(_ah) \ + AH_PRIVATE(_ah)->ah_eepromDetach(_ah) +#define ath_hal_eepromGet(_ah, _param, _val) \ + AH_PRIVATE(_ah)->ah_eepromGet(_ah, _param, _val) +#define ath_hal_eepromSet(_ah, _param, _val) \ + AH_PRIVATE(_ah)->ah_eepromSet(_ah, _param, _val) +#define ath_hal_eepromGetFlag(_ah, _param) \ + (AH_PRIVATE(_ah)->ah_eepromGet(_ah, _param, AH_NULL) == HAL_OK) +#define ath_hal_getSpurChan(_ah, _ix, _is2G) \ + AH_PRIVATE(_ah)->ah_getSpurChan(_ah, _ix, _is2G) +#define ath_hal_eepromDiag(_ah, _request, _a, _asize, _r, _rsize) \ + AH_PRIVATE(_ah)->ah_eepromDiag(_ah, _request, _a, _asize, _r, _rsize) + +#if !defined(_NET_IF_IEEE80211_H_) && !defined(_NET80211__IEEE80211_H_) +/* + * Stuff that would naturally come from _ieee80211.h + */ +#define IEEE80211_ADDR_LEN 6 + +#define IEEE80211_WEP_KEYLEN 5 /* 40bit */ +#define IEEE80211_WEP_IVLEN 3 /* 24bit */ +#define IEEE80211_WEP_KIDLEN 1 /* 1 octet */ +#define IEEE80211_WEP_CRCLEN 4 /* CRC-32 */ + +#define IEEE80211_CRC_LEN 4 + +#define IEEE80211_MTU 1500 +#define IEEE80211_MAX_LEN (2300 + IEEE80211_CRC_LEN + \ + (IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN + IEEE80211_WEP_CRCLEN)) + +enum { + IEEE80211_T_DS, /* direct sequence spread spectrum */ + IEEE80211_T_FH, /* frequency hopping */ + IEEE80211_T_OFDM, /* frequency division multiplexing */ + IEEE80211_T_TURBO, /* high rate DS */ + IEEE80211_T_HT, /* HT - full GI */ +}; +#define IEEE80211_T_CCK IEEE80211_T_DS /* more common nomenclatur */ +#endif /* _NET_IF_IEEE80211_H_ */ + +/* NB: these are defined privately until XR support is announced */ +enum { + ATHEROS_T_XR = IEEE80211_T_HT+1, /* extended range */ +}; + +#define HAL_TXQ_USE_LOCKOUT_BKOFF_DIS 0x00000001 + +#define INIT_AIFS 2 +#define INIT_CWMIN 15 +#define INIT_CWMIN_11B 31 +#define INIT_CWMAX 1023 +#define INIT_SH_RETRY 10 +#define INIT_LG_RETRY 10 +#define INIT_SSH_RETRY 32 +#define INIT_SLG_RETRY 32 + +typedef struct { + uint32_t tqi_ver; /* HAL TXQ verson */ + HAL_TX_QUEUE tqi_type; /* hw queue type*/ + HAL_TX_QUEUE_SUBTYPE tqi_subtype; /* queue subtype, if applicable */ + HAL_TX_QUEUE_FLAGS tqi_qflags; /* queue flags */ + uint32_t tqi_priority; + uint32_t tqi_aifs; /* aifs */ + uint32_t tqi_cwmin; /* cwMin */ + uint32_t tqi_cwmax; /* cwMax */ + uint16_t tqi_shretry; /* frame short retry limit */ + uint16_t tqi_lgretry; /* frame long retry limit */ + uint32_t tqi_cbrPeriod; + uint32_t tqi_cbrOverflowLimit; + uint32_t tqi_burstTime; + uint32_t tqi_readyTime; + uint32_t tqi_physCompBuf; + uint32_t tqi_intFlags; /* flags for internal use */ +} HAL_TX_QUEUE_INFO; + +extern HAL_BOOL ath_hal_setTxQProps(struct ath_hal *ah, + HAL_TX_QUEUE_INFO *qi, const HAL_TXQ_INFO *qInfo); +extern HAL_BOOL ath_hal_getTxQProps(struct ath_hal *ah, + HAL_TXQ_INFO *qInfo, const HAL_TX_QUEUE_INFO *qi); + +typedef enum { + HAL_ANI_PRESENT, /* is ANI support present */ + HAL_ANI_NOISE_IMMUNITY_LEVEL, /* set level */ + HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, /* enable/disable */ + HAL_ANI_CCK_WEAK_SIGNAL_THR, /* enable/disable */ + HAL_ANI_FIRSTEP_LEVEL, /* set level */ + HAL_ANI_SPUR_IMMUNITY_LEVEL, /* set level */ + HAL_ANI_MODE = 6, /* 0 => manual, 1 => auto (XXX do not change) */ + HAL_ANI_PHYERR_RESET, /* reset phy error stats */ +} HAL_ANI_CMD; + +#define HAL_SPUR_VAL_MASK 0x3FFF +#define HAL_SPUR_CHAN_WIDTH 87 +#define HAL_BIN_WIDTH_BASE_100HZ 3125 +#define HAL_BIN_WIDTH_TURBO_100HZ 6250 +#define HAL_MAX_BINS_ALLOWED 28 + +/* + * A = 5GHZ|OFDM + * T = 5GHZ|OFDM|TURBO + * + * IS_CHAN_A(T) will return TRUE. This is probably + * not the default behavior we want. We should migrate to a better mask -- + * perhaps CHANNEL_ALL. + * + * For now, IS_CHAN_G() masks itself with CHANNEL_108G. + * + */ + +#define IS_CHAN_A(_c) (((_c)->channelFlags & CHANNEL_A) == CHANNEL_A) +#define IS_CHAN_B(_c) (((_c)->channelFlags & CHANNEL_B) == CHANNEL_B) +#define IS_CHAN_G(_c) (((_c)->channelFlags & (CHANNEL_108G|CHANNEL_G)) == CHANNEL_G) +#define IS_CHAN_108G(_c)(((_c)->channelFlags & CHANNEL_108G) == CHANNEL_108G) +#define IS_CHAN_T(_c) (((_c)->channelFlags & CHANNEL_T) == CHANNEL_T) +#define IS_CHAN_PUREG(_c) \ + (((_c)->channelFlags & CHANNEL_PUREG) == CHANNEL_PUREG) + +#define IS_CHAN_TURBO(_c) (((_c)->channelFlags & CHANNEL_TURBO) != 0) +#define IS_CHAN_CCK(_c) (((_c)->channelFlags & CHANNEL_CCK) != 0) +#define IS_CHAN_OFDM(_c) (((_c)->channelFlags & CHANNEL_OFDM) != 0) +#define IS_CHAN_5GHZ(_c) (((_c)->channelFlags & CHANNEL_5GHZ) != 0) +#define IS_CHAN_2GHZ(_c) (((_c)->channelFlags & CHANNEL_2GHZ) != 0) +#define IS_CHAN_PASSIVE(_c) (((_c)->channelFlags & CHANNEL_PASSIVE) != 0) +#define IS_CHAN_HALF_RATE(_c) (((_c)->channelFlags & CHANNEL_HALF) != 0) +#define IS_CHAN_QUARTER_RATE(_c) (((_c)->channelFlags & CHANNEL_QUARTER) != 0) + +#define IS_CHAN_IN_PUBLIC_SAFETY_BAND(_c) ((_c) > 4940 && (_c) < 4990) + +#define CHANNEL_HT40 (CHANNEL_HT40PLUS | CHANNEL_HT40MINUS) +#define CHANNEL_HT (CHANNEL_HT20 | CHANNEL_HT40) +#define IS_CHAN_HT(_c) (((_c)->channelFlags & CHANNEL_HT) != 0) +#define IS_CHAN_HT20(_c) (((_c)->channelFlags & CHANNEL_HT) == CHANNEL_HT20) +#define IS_CHAN_HT40(_c) (((_c)->channelFlags & CHANNEL_HT40) != 0) + +/* + * Deduce if the host cpu has big- or litt-endian byte order. + */ +static __inline__ int +isBigEndian(void) +{ + union { + int32_t i; + char c[4]; + } u; + u.i = 1; + return (u.c[0] == 0); +} + +/* unalligned little endian access */ +#define LE_READ_2(p) \ + ((uint16_t) \ + ((((const uint8_t *)(p))[0] ) | (((const uint8_t *)(p))[1]<< 8))) +#define LE_READ_4(p) \ + ((uint32_t) \ + ((((const uint8_t *)(p))[0] ) | (((const uint8_t *)(p))[1]<< 8) |\ + (((const uint8_t *)(p))[2]<<16) | (((const uint8_t *)(p))[3]<<24))) + +/* + * Register manipulation macros that expect bit field defines + * to follow the convention that an _S suffix is appended for + * a shift count, while the field mask has no suffix. + */ +#define SM(_v, _f) (((_v) << _f##_S) & (_f)) +#define MS(_v, _f) (((_v) & (_f)) >> _f##_S) +#define OS_REG_RMW_FIELD(_a, _r, _f, _v) \ + OS_REG_WRITE(_a, _r, \ + (OS_REG_READ(_a, _r) &~ (_f)) | (((_v) << _f##_S) & (_f))) +#define OS_REG_SET_BIT(_a, _r, _f) \ + OS_REG_WRITE(_a, _r, OS_REG_READ(_a, _r) | (_f)) +#define OS_REG_CLR_BIT(_a, _r, _f) \ + OS_REG_WRITE(_a, _r, OS_REG_READ(_a, _r) &~ (_f)) + +/* + * Regulatory domain support. + */ + +/* + * Return the max allowed antenna gain based on the current + * regulatory domain. + */ +extern u_int ath_hal_getantennareduction(struct ath_hal *, + HAL_CHANNEL *, u_int twiceGain); +/* + * Return the test group for the specific channel based on + * the current regulator domain. + */ +extern u_int ath_hal_getctl(struct ath_hal *, HAL_CHANNEL *); +/* + * Return whether or not a noise floor check is required + * based on the current regulatory domain for the specified + * channel. + */ +extern u_int ath_hal_getnfcheckrequired(struct ath_hal *, HAL_CHANNEL *); + +/* + * Map a public channel definition to the corresponding + * internal data structure. This implicitly specifies + * whether or not the specified channel is ok to use + * based on the current regulatory domain constraints. + */ +extern HAL_CHANNEL_INTERNAL *ath_hal_checkchannel(struct ath_hal *, + const HAL_CHANNEL *); + +/* system-configurable parameters */ +extern int ath_hal_dma_beacon_response_time; /* in TU's */ +extern int ath_hal_sw_beacon_response_time; /* in TU's */ +extern int ath_hal_additional_swba_backoff; /* in TU's */ + +/* wait for the register contents to have the specified value */ +extern HAL_BOOL ath_hal_wait(struct ath_hal *, u_int reg, + uint32_t mask, uint32_t val); + +/* return the first n bits in val reversed */ +extern uint32_t ath_hal_reverseBits(uint32_t val, uint32_t n); + +/* printf interfaces */ +extern void ath_hal_printf(struct ath_hal *, const char*, ...); +extern void ath_hal_vprintf(struct ath_hal *, const char*, va_list); +extern const char* ath_hal_ether_sprintf(const uint8_t *mac); + +/* allocate and free memory */ +extern void *ath_hal_malloc(size_t); +extern void ath_hal_free(void *); + +/* common debugging interfaces */ +#ifdef AH_DEBUG +#include "ah_debug.h" +extern int ath_hal_debug; +extern void HALDEBUG(struct ath_hal *ah, u_int mask, const char* fmt, ...); +#else +#define HALDEBUG(_ah, __m, _fmt, ...) +#endif /* AH_DEBUG */ + +/* + * Register logging definitions shared with ardecode. + */ +#include "ah_decode.h" + +/* + * Common assertion interface. Note: it is a bad idea to generate + * an assertion failure for any recoverable event. Instead catch + * the violation and, if possible, fix it up or recover from it; either + * with an error return value or a diagnostic messages. System software + * does not panic unless the situation is hopeless. + */ +#ifdef AH_ASSERT +extern void ath_hal_assert_failed(const char* filename, + int lineno, const char* msg); + +#define HALASSERT(_x) do { \ + if (!(_x)) { \ + ath_hal_assert_failed(__FILE__, __LINE__, #_x); \ + } \ +} while (0) +#else +#define HALASSERT(_x) +#endif /* AH_ASSERT */ + +/* + * Convert between microseconds and core system clocks. + */ +extern u_int ath_hal_mac_clks(struct ath_hal *ah, u_int usecs); +extern u_int ath_hal_mac_usec(struct ath_hal *ah, u_int clks); + +/* + * Generic get/set capability support. Each chip overrides + * this routine to support chip-specific capabilities. + */ +extern HAL_STATUS ath_hal_getcapability(struct ath_hal *ah, + HAL_CAPABILITY_TYPE type, uint32_t capability, + uint32_t *result); +extern HAL_BOOL ath_hal_setcapability(struct ath_hal *ah, + HAL_CAPABILITY_TYPE type, uint32_t capability, + uint32_t setting, HAL_STATUS *status); + +/* + * Diagnostic interface. This is an open-ended interface that + * is opaque to applications. Diagnostic programs use this to + * retrieve internal data structures, etc. There is no guarantee + * that calling conventions for calls other than HAL_DIAG_REVS + * are stable between HAL releases; a diagnostic application must + * use the HAL revision information to deal with ABI/API differences. + * + * NB: do not renumber these, certain codes are publicly used. + */ +enum { + HAL_DIAG_REVS = 0, /* MAC/PHY/Radio revs */ + HAL_DIAG_EEPROM = 1, /* EEPROM contents */ + HAL_DIAG_EEPROM_EXP_11A = 2, /* EEPROM 5112 power exp for 11a */ + HAL_DIAG_EEPROM_EXP_11B = 3, /* EEPROM 5112 power exp for 11b */ + HAL_DIAG_EEPROM_EXP_11G = 4, /* EEPROM 5112 power exp for 11g */ + HAL_DIAG_ANI_CURRENT = 5, /* ANI current channel state */ + HAL_DIAG_ANI_OFDM = 6, /* ANI OFDM timing error stats */ + HAL_DIAG_ANI_CCK = 7, /* ANI CCK timing error stats */ + HAL_DIAG_ANI_STATS = 8, /* ANI statistics */ + HAL_DIAG_RFGAIN = 9, /* RfGain GAIN_VALUES */ + HAL_DIAG_RFGAIN_CURSTEP = 10, /* RfGain GAIN_OPTIMIZATION_STEP */ + HAL_DIAG_PCDAC = 11, /* PCDAC table */ + HAL_DIAG_TXRATES = 12, /* Transmit rate table */ + HAL_DIAG_REGS = 13, /* Registers */ + HAL_DIAG_ANI_CMD = 14, /* ANI issue command (XXX do not change!) */ + HAL_DIAG_SETKEY = 15, /* Set keycache backdoor */ + HAL_DIAG_RESETKEY = 16, /* Reset keycache backdoor */ + HAL_DIAG_EEREAD = 17, /* Read EEPROM word */ + HAL_DIAG_EEWRITE = 18, /* Write EEPROM word */ + /* 19 was HAL_DIAG_TXCONT, 20-23 were for radar */ + HAL_DIAG_REGREAD = 24, /* Reg reads */ + HAL_DIAG_REGWRITE = 25, /* Reg writes */ + HAL_DIAG_GET_REGBASE = 26, /* Get register base */ + HAL_DIAG_RDWRITE = 27, /* Write regulatory domain */ + HAL_DIAG_RDREAD = 28, /* Get regulatory domain */ + HAL_DIAG_FATALERR = 29, /* Read cached interrupt state */ + HAL_DIAG_11NCOMPAT = 30, /* 11n compatibility tweaks */ + HAL_DIAG_ANI_PARAMS = 31, /* ANI noise immunity parameters */ + HAL_DIAG_CHECK_HANGS = 32, /* check h/w hangs */ +}; + +enum { + HAL_BB_HANG_DFS = 0x0001, + HAL_BB_HANG_RIFS = 0x0002, + HAL_BB_HANG_RX_CLEAR = 0x0004, + HAL_BB_HANG_UNKNOWN = 0x0080, + + HAL_MAC_HANG_SIG1 = 0x0100, + HAL_MAC_HANG_SIG2 = 0x0200, + HAL_MAC_HANG_UNKNOWN = 0x8000, + + HAL_BB_HANGS = HAL_BB_HANG_DFS + | HAL_BB_HANG_RIFS + | HAL_BB_HANG_RX_CLEAR + | HAL_BB_HANG_UNKNOWN, + HAL_MAC_HANGS = HAL_MAC_HANG_SIG1 + | HAL_MAC_HANG_SIG2 + | HAL_MAC_HANG_UNKNOWN, +}; + +/* + * Device revision information. + */ +typedef struct { + uint16_t ah_devid; /* PCI device ID */ + uint16_t ah_subvendorid; /* PCI subvendor ID */ + uint32_t ah_macVersion; /* MAC version id */ + uint16_t ah_macRev; /* MAC revision */ + uint16_t ah_phyRev; /* PHY revision */ + uint16_t ah_analog5GhzRev; /* 2GHz radio revision */ + uint16_t ah_analog2GhzRev; /* 5GHz radio revision */ +} HAL_REVS; + +/* + * Argument payload for HAL_DIAG_SETKEY. + */ +typedef struct { + HAL_KEYVAL dk_keyval; + uint16_t dk_keyix; /* key index */ + uint8_t dk_mac[IEEE80211_ADDR_LEN]; + int dk_xor; /* XOR key data */ +} HAL_DIAG_KEYVAL; + +/* + * Argument payload for HAL_DIAG_EEWRITE. + */ +typedef struct { + uint16_t ee_off; /* eeprom offset */ + uint16_t ee_data; /* write data */ +} HAL_DIAG_EEVAL; + + +typedef struct { + u_int offset; /* reg offset */ + uint32_t val; /* reg value */ +} HAL_DIAG_REGVAL; + +/* + * 11n compatibility tweaks. + */ +#define HAL_DIAG_11N_SERVICES 0x00000003 +#define HAL_DIAG_11N_SERVICES_S 0 +#define HAL_DIAG_11N_TXSTOMP 0x0000000c +#define HAL_DIAG_11N_TXSTOMP_S 2 + +typedef struct { + 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; + int32_t cckTrigHigh; + int32_t cckTrigLow; + int32_t rssiThrLow; + int32_t rssiThrHigh; + + int period; /* update listen period */ +} HAL_ANI_PARAMS; + +extern HAL_BOOL ath_hal_getdiagstate(struct ath_hal *ah, int request, + const void *args, uint32_t argsize, + void **result, uint32_t *resultsize); + +/* + * Setup a h/w rate table for use. + */ +extern void ath_hal_setupratetable(struct ath_hal *ah, HAL_RATE_TABLE *rt); + +/* + * Common routine for implementing getChanNoise api. + */ +extern int16_t ath_hal_getChanNoise(struct ath_hal *ah, HAL_CHANNEL *chan); + +/* + * Initialization support. + */ +typedef struct { + const uint32_t *data; + int rows, cols; +} HAL_INI_ARRAY; + +#define HAL_INI_INIT(_ia, _data, _cols) do { \ + (_ia)->data = (const uint32_t *)(_data); \ + (_ia)->rows = sizeof(_data) / sizeof((_data)[0]); \ + (_ia)->cols = (_cols); \ +} while (0) +#define HAL_INI_VAL(_ia, _r, _c) \ + ((_ia)->data[((_r)*(_ia)->cols) + (_c)]) + +/* + * OS_DELAY() does a PIO READ on the PCI bus which allows + * other cards' DMA reads to complete in the middle of our reset. + */ +#define DMA_YIELD(x) do { \ + if ((++(x) % 64) == 0) \ + OS_DELAY(1); \ +} while (0) + +#define HAL_INI_WRITE_ARRAY(ah, regArray, col, regWr) do { \ + int r; \ + for (r = 0; r < N(regArray); r++) { \ + OS_REG_WRITE(ah, (regArray)[r][0], (regArray)[r][col]); \ + DMA_YIELD(regWr); \ + } \ +} while (0) + +#define HAL_INI_WRITE_BANK(ah, regArray, bankData, regWr) do { \ + int r; \ + for (r = 0; r < N(regArray); r++) { \ + OS_REG_WRITE(ah, (regArray)[r][0], (bankData)[r]); \ + DMA_YIELD(regWr); \ + } \ +} while (0) + +extern int ath_hal_ini_write(struct ath_hal *ah, const HAL_INI_ARRAY *ia, + int col, int regWr); +extern void ath_hal_ini_bank_setup(uint32_t data[], const HAL_INI_ARRAY *ia, + int col); +extern int ath_hal_ini_bank_write(struct ath_hal *ah, const HAL_INI_ARRAY *ia, + const uint32_t data[], int regWr); + +#define WLAN_CTRL_FRAME_SIZE (2+2+6+4) /* ACK+FCS */ +#endif /* _ATH_AH_INTERAL_H_ */ --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ah_regdomain.c 2009-03-23 17:36:56.000000000 +0000 @@ -0,0 +1,2861 @@ +/* + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2005-2006 Atheros Communications, Inc. + * All rights reserved. + * + * 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: ah_regdomain.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.h" +#include "ah_devid.h" + +/* + * XXX this code needs a audit+review + */ + +/* used throughout this file... */ +#define N(a) (sizeof (a) / sizeof (a[0])) + +#define HAL_MODE_11A_TURBO HAL_MODE_108A +#define HAL_MODE_11G_TURBO HAL_MODE_108G + +/* 10MHz is half the 11A bandwidth used to determine upper edge freq + of the outdoor channel */ +#define HALF_MAXCHANBW 10 + +/* + * BMLEN defines the size of the bitmask used to hold frequency + * band specifications. Note this must agree with the BM macro + * definition that's used to setup initializers. See also further + * comments below. + */ +#define BMLEN 2 /* 2 x 64 bits in each channel bitmask */ +typedef uint64_t chanbmask_t[BMLEN]; + +#define W0(_a) \ + (((_a) >= 0 && (_a) < 64 ? (((uint64_t) 1)<<(_a)) : (uint64_t) 0)) +#define W1(_a) \ + (((_a) > 63 && (_a) < 128 ? (((uint64_t) 1)<<((_a)-64)) : (uint64_t) 0)) +#define BM1(_fa) { W0(_fa), W1(_fa) } +#define BM2(_fa, _fb) { W0(_fa) | W0(_fb), W1(_fa) | W1(_fb) } +#define BM3(_fa, _fb, _fc) \ + { W0(_fa) | W0(_fb) | W0(_fc), W1(_fa) | W1(_fb) | W1(_fc) } +#define BM4(_fa, _fb, _fc, _fd) \ + { W0(_fa) | W0(_fb) | W0(_fc) | W0(_fd), \ + W1(_fa) | W1(_fb) | W1(_fc) | W1(_fd) } +#define BM5(_fa, _fb, _fc, _fd, _fe) \ + { W0(_fa) | W0(_fb) | W0(_fc) | W0(_fd) | W0(_fe), \ + W1(_fa) | W1(_fb) | W1(_fc) | W1(_fd) | W1(_fe) } +#define BM6(_fa, _fb, _fc, _fd, _fe, _ff) \ + { W0(_fa) | W0(_fb) | W0(_fc) | W0(_fd) | W0(_fe) | W0(_ff), \ + W1(_fa) | W1(_fb) | W1(_fc) | W1(_fd) | W1(_fe) | W1(_ff) } +#define BM7(_fa, _fb, _fc, _fd, _fe, _ff, _fg) \ + { W0(_fa) | W0(_fb) | W0(_fc) | W0(_fd) | W0(_fe) | W0(_ff) | \ + W0(_fg),\ + W1(_fa) | W1(_fb) | W1(_fc) | W1(_fd) | W1(_fe) | W1(_ff) | \ + W1(_fg) } +#define BM8(_fa, _fb, _fc, _fd, _fe, _ff, _fg, _fh) \ + { W0(_fa) | W0(_fb) | W0(_fc) | W0(_fd) | W0(_fe) | W0(_ff) | \ + W0(_fg) | W0(_fh) , \ + W1(_fa) | W1(_fb) | W1(_fc) | W1(_fd) | W1(_fe) | W1(_ff) | \ + W1(_fg) | W1(_fh) } + +/* + * Country/Region Codes + * Numbering from ISO 3166 + */ +enum { + CTRY_ALBANIA = 8, /* Albania */ + CTRY_ALGERIA = 12, /* Algeria */ + CTRY_ARGENTINA = 32, /* Argentina */ + CTRY_ARMENIA = 51, /* Armenia */ + CTRY_AUSTRALIA = 36, /* Australia */ + CTRY_AUSTRIA = 40, /* Austria */ + CTRY_AZERBAIJAN = 31, /* Azerbaijan */ + CTRY_BAHRAIN = 48, /* Bahrain */ + CTRY_BELARUS = 112, /* Belarus */ + CTRY_BELGIUM = 56, /* Belgium */ + CTRY_BELIZE = 84, /* Belize */ + CTRY_BOLIVIA = 68, /* Bolivia */ + CTRY_BRAZIL = 76, /* Brazil */ + CTRY_BRUNEI_DARUSSALAM = 96, /* Brunei Darussalam */ + CTRY_BULGARIA = 100, /* Bulgaria */ + CTRY_CANADA = 124, /* Canada */ + CTRY_CHILE = 152, /* Chile */ + CTRY_CHINA = 156, /* People's Republic of China */ + CTRY_COLOMBIA = 170, /* Colombia */ + CTRY_COSTA_RICA = 188, /* Costa Rica */ + CTRY_CROATIA = 191, /* Croatia */ + CTRY_CYPRUS = 196, + CTRY_CZECH = 203, /* Czech Republic */ + CTRY_DENMARK = 208, /* Denmark */ + CTRY_DOMINICAN_REPUBLIC = 214, /* Dominican Republic */ + CTRY_ECUADOR = 218, /* Ecuador */ + CTRY_EGYPT = 818, /* Egypt */ + CTRY_EL_SALVADOR = 222, /* El Salvador */ + CTRY_ESTONIA = 233, /* Estonia */ + CTRY_FAEROE_ISLANDS = 234, /* Faeroe Islands */ + CTRY_FINLAND = 246, /* Finland */ + CTRY_FRANCE = 250, /* France */ + CTRY_FRANCE2 = 255, /* France2 */ + CTRY_GEORGIA = 268, /* Georgia */ + CTRY_GERMANY = 276, /* Germany */ + CTRY_GREECE = 300, /* Greece */ + CTRY_GUATEMALA = 320, /* Guatemala */ + CTRY_HONDURAS = 340, /* Honduras */ + CTRY_HONG_KONG = 344, /* Hong Kong S.A.R., P.R.C. */ + CTRY_HUNGARY = 348, /* Hungary */ + CTRY_ICELAND = 352, /* Iceland */ + CTRY_INDIA = 356, /* India */ + CTRY_INDONESIA = 360, /* Indonesia */ + CTRY_IRAN = 364, /* Iran */ + CTRY_IRAQ = 368, /* Iraq */ + CTRY_IRELAND = 372, /* Ireland */ + CTRY_ISRAEL = 376, /* Israel */ + CTRY_ITALY = 380, /* Italy */ + CTRY_JAMAICA = 388, /* Jamaica */ + CTRY_JAPAN = 392, /* Japan */ + CTRY_JAPAN1 = 393, /* Japan (JP1) */ + CTRY_JAPAN2 = 394, /* Japan (JP0) */ + CTRY_JAPAN3 = 395, /* Japan (JP1-1) */ + CTRY_JAPAN4 = 396, /* Japan (JE1) */ + CTRY_JAPAN5 = 397, /* Japan (JE2) */ + CTRY_JAPAN6 = 399, /* Japan (JP6) */ + + CTRY_JAPAN7 = 4007, /* Japan (J7) */ + CTRY_JAPAN8 = 4008, /* Japan (J8) */ + CTRY_JAPAN9 = 4009, /* Japan (J9) */ + + CTRY_JAPAN10 = 4010, /* Japan (J10) */ + CTRY_JAPAN11 = 4011, /* Japan (J11) */ + CTRY_JAPAN12 = 4012, /* Japan (J12) */ + + CTRY_JAPAN13 = 4013, /* Japan (J13) */ + CTRY_JAPAN14 = 4014, /* Japan (J14) */ + CTRY_JAPAN15 = 4015, /* Japan (J15) */ + + CTRY_JAPAN16 = 4016, /* Japan (J16) */ + CTRY_JAPAN17 = 4017, /* Japan (J17) */ + CTRY_JAPAN18 = 4018, /* Japan (J18) */ + + CTRY_JAPAN19 = 4019, /* Japan (J19) */ + CTRY_JAPAN20 = 4020, /* Japan (J20) */ + CTRY_JAPAN21 = 4021, /* Japan (J21) */ + + CTRY_JAPAN22 = 4022, /* Japan (J22) */ + CTRY_JAPAN23 = 4023, /* Japan (J23) */ + CTRY_JAPAN24 = 4024, /* Japan (J24) */ + + CTRY_JORDAN = 400, /* Jordan */ + CTRY_KAZAKHSTAN = 398, /* Kazakhstan */ + CTRY_KENYA = 404, /* Kenya */ + CTRY_KOREA_NORTH = 408, /* North Korea */ + CTRY_KOREA_ROC = 410, /* South Korea */ + CTRY_KOREA_ROC2 = 411, /* South Korea */ + CTRY_KOREA_ROC3 = 412, /* South Korea */ + CTRY_KUWAIT = 414, /* Kuwait */ + CTRY_LATVIA = 428, /* Latvia */ + CTRY_LEBANON = 422, /* Lebanon */ + CTRY_LIBYA = 434, /* Libya */ + CTRY_LIECHTENSTEIN = 438, /* Liechtenstein */ + CTRY_LITHUANIA = 440, /* Lithuania */ + CTRY_LUXEMBOURG = 442, /* Luxembourg */ + CTRY_MACAU = 446, /* Macau */ + CTRY_MACEDONIA = 807, /* the Former Yugoslav Republic of Macedonia */ + CTRY_MALAYSIA = 458, /* Malaysia */ + CTRY_MALTA = 470, /* Malta */ + CTRY_MEXICO = 484, /* Mexico */ + CTRY_MONACO = 492, /* Principality of Monaco */ + CTRY_MOROCCO = 504, /* Morocco */ + CTRY_NETHERLANDS = 528, /* Netherlands */ + CTRY_NEW_ZEALAND = 554, /* New Zealand */ + CTRY_NICARAGUA = 558, /* Nicaragua */ + CTRY_NORWAY = 578, /* Norway */ + CTRY_OMAN = 512, /* Oman */ + CTRY_PAKISTAN = 586, /* Islamic Republic of Pakistan */ + CTRY_PANAMA = 591, /* Panama */ + CTRY_PARAGUAY = 600, /* Paraguay */ + CTRY_PERU = 604, /* Peru */ + CTRY_PHILIPPINES = 608, /* Republic of the Philippines */ + CTRY_POLAND = 616, /* Poland */ + CTRY_PORTUGAL = 620, /* Portugal */ + CTRY_PUERTO_RICO = 630, /* Puerto Rico */ + CTRY_QATAR = 634, /* Qatar */ + CTRY_ROMANIA = 642, /* Romania */ + CTRY_RUSSIA = 643, /* Russia */ + CTRY_SAUDI_ARABIA = 682, /* Saudi Arabia */ + CTRY_SINGAPORE = 702, /* Singapore */ + CTRY_SLOVAKIA = 703, /* Slovak Republic */ + CTRY_SLOVENIA = 705, /* Slovenia */ + CTRY_SOUTH_AFRICA = 710, /* South Africa */ + CTRY_SPAIN = 724, /* Spain */ + CTRY_SR9 = 5000, /* Ubiquiti SR9 (900MHz/GSM) */ + CTRY_SWEDEN = 752, /* Sweden */ + CTRY_SWITZERLAND = 756, /* Switzerland */ + CTRY_SYRIA = 760, /* Syria */ + CTRY_TAIWAN = 158, /* Taiwan */ + CTRY_THAILAND = 764, /* Thailand */ + CTRY_TRINIDAD_Y_TOBAGO = 780, /* Trinidad y Tobago */ + CTRY_TUNISIA = 788, /* Tunisia */ + CTRY_TURKEY = 792, /* Turkey */ + CTRY_UAE = 784, /* U.A.E. */ + CTRY_UKRAINE = 804, /* Ukraine */ + CTRY_UNITED_KINGDOM = 826, /* United Kingdom */ + CTRY_UNITED_STATES = 840, /* United States */ + CTRY_UNITED_STATES_FCC49 = 842, /* United States (Public Safety)*/ + CTRY_URUGUAY = 858, /* Uruguay */ + CTRY_UZBEKISTAN = 860, /* Uzbekistan */ + CTRY_VENEZUELA = 862, /* Venezuela */ + CTRY_VIET_NAM = 704, /* Viet Nam */ + CTRY_XR9 = 5001, /* Ubiquiti XR9 (900MHz/GSM) */ + CTRY_GZ901 = 5002, /* Zcomax GZ-901 (900MHz/GSM) */ + CTRY_YEMEN = 887, /* Yemen */ + CTRY_ZIMBABWE = 716 /* Zimbabwe */ +}; + + +/* + * Mask to check whether a domain is a multidomain or a single domain + */ +#define MULTI_DOMAIN_MASK 0xFF00 + +/* + * Enumerated Regulatory Domain Information 8 bit values indicate that + * the regdomain is really a pair of unitary regdomains. 12 bit values + * are the real unitary regdomains and are the only ones which have the + * frequency bitmasks and flags set. + */ +enum { + /* + * The following regulatory domain definitions are + * found in the EEPROM. Each regulatory domain + * can operate in either a 5GHz or 2.4GHz wireless mode or + * both 5GHz and 2.4GHz wireless modes. + * In general, the value holds no special + * meaning and is used to decode into either specific + * 2.4GHz or 5GHz wireless mode for that particular + * regulatory domain. + */ + NO_ENUMRD = 0x00, + NULL1_WORLD = 0x03, /* For 11b-only countries (no 11a allowed) */ + NULL1_ETSIB = 0x07, /* Israel */ + NULL1_ETSIC = 0x08, + FCC1_FCCA = 0x10, /* USA */ + FCC1_WORLD = 0x11, /* Hong Kong */ + FCC4_FCCA = 0x12, /* USA - Public Safety */ + FCC5_FCCB = 0x13, /* USA w/ 1/2 and 1/4 width channels */ + + FCC2_FCCA = 0x20, /* Canada */ + FCC2_WORLD = 0x21, /* Australia & HK */ + FCC2_ETSIC = 0x22, + FRANCE_RES = 0x31, /* Legacy France for OEM */ + FCC3_FCCA = 0x3A, /* USA & Canada w/5470 band, 11h, DFS enabled */ + FCC3_WORLD = 0x3B, /* USA & Canada w/5470 band, 11h, DFS enabled */ + + ETSI1_WORLD = 0x37, + ETSI3_ETSIA = 0x32, /* France (optional) */ + ETSI2_WORLD = 0x35, /* Hungary & others */ + ETSI3_WORLD = 0x36, /* France & others */ + ETSI4_WORLD = 0x30, + ETSI4_ETSIC = 0x38, + ETSI5_WORLD = 0x39, + ETSI6_WORLD = 0x34, /* Bulgaria */ + ETSI_RESERVED = 0x33, /* Reserved (Do not used) */ + + MKK1_MKKA = 0x40, /* Japan (JP1) */ + MKK1_MKKB = 0x41, /* Japan (JP0) */ + APL4_WORLD = 0x42, /* Singapore */ + MKK2_MKKA = 0x43, /* Japan with 4.9G channels */ + APL_RESERVED = 0x44, /* Reserved (Do not used) */ + APL2_WORLD = 0x45, /* Korea */ + APL2_APLC = 0x46, + APL3_WORLD = 0x47, + MKK1_FCCA = 0x48, /* Japan (JP1-1) */ + APL2_APLD = 0x49, /* Korea with 2.3G channels */ + MKK1_MKKA1 = 0x4A, /* Japan (JE1) */ + MKK1_MKKA2 = 0x4B, /* Japan (JE2) */ + MKK1_MKKC = 0x4C, /* Japan (MKK1_MKKA,except Ch14) */ + + APL3_FCCA = 0x50, + APL1_WORLD = 0x52, /* Latin America */ + APL1_FCCA = 0x53, + APL1_APLA = 0x54, + APL1_ETSIC = 0x55, + APL2_ETSIC = 0x56, /* Venezuela */ + APL5_WORLD = 0x58, /* Chile */ + APL6_WORLD = 0x5B, /* Singapore */ + APL7_FCCA = 0x5C, /* Taiwan 5.47 Band */ + APL8_WORLD = 0x5D, /* Malaysia 5GHz */ + APL9_WORLD = 0x5E, /* Korea 5GHz */ + + /* + * World mode SKUs + */ + WOR0_WORLD = 0x60, /* World0 (WO0 SKU) */ + WOR1_WORLD = 0x61, /* World1 (WO1 SKU) */ + WOR2_WORLD = 0x62, /* World2 (WO2 SKU) */ + WOR3_WORLD = 0x63, /* World3 (WO3 SKU) */ + WOR4_WORLD = 0x64, /* World4 (WO4 SKU) */ + WOR5_ETSIC = 0x65, /* World5 (WO5 SKU) */ + + WOR01_WORLD = 0x66, /* World0-1 (WW0-1 SKU) */ + WOR02_WORLD = 0x67, /* World0-2 (WW0-2 SKU) */ + EU1_WORLD = 0x68, /* Same as World0-2 (WW0-2 SKU), except active scan ch1-13. No ch14 */ + + WOR9_WORLD = 0x69, /* World9 (WO9 SKU) */ + WORA_WORLD = 0x6A, /* WorldA (WOA SKU) */ + + MKK3_MKKB = 0x80, /* Japan UNI-1 even + MKKB */ + MKK3_MKKA2 = 0x81, /* Japan UNI-1 even + MKKA2 */ + MKK3_MKKC = 0x82, /* Japan UNI-1 even + MKKC */ + + MKK4_MKKB = 0x83, /* Japan UNI-1 even + UNI-2 + MKKB */ + MKK4_MKKA2 = 0x84, /* Japan UNI-1 even + UNI-2 + MKKA2 */ + MKK4_MKKC = 0x85, /* Japan UNI-1 even + UNI-2 + MKKC */ + + MKK5_MKKB = 0x86, /* Japan UNI-1 even + UNI-2 + mid-band + MKKB */ + MKK5_MKKA2 = 0x87, /* Japan UNI-1 even + UNI-2 + mid-band + MKKA2 */ + MKK5_MKKC = 0x88, /* Japan UNI-1 even + UNI-2 + mid-band + MKKC */ + + MKK6_MKKB = 0x89, /* Japan UNI-1 even + UNI-1 odd MKKB */ + MKK6_MKKA2 = 0x8A, /* Japan UNI-1 even + UNI-1 odd + MKKA2 */ + MKK6_MKKC = 0x8B, /* Japan UNI-1 even + UNI-1 odd + MKKC */ + + MKK7_MKKB = 0x8C, /* Japan UNI-1 even + UNI-1 odd + UNI-2 + MKKB */ + MKK7_MKKA2 = 0x8D, /* Japan UNI-1 even + UNI-1 odd + UNI-2 + MKKA2 */ + MKK7_MKKC = 0x8E, /* Japan UNI-1 even + UNI-1 odd + UNI-2 + MKKC */ + + MKK8_MKKB = 0x8F, /* Japan UNI-1 even + UNI-1 odd + UNI-2 + mid-band + MKKB */ + MKK8_MKKA2 = 0x90, /* Japan UNI-1 even + UNI-1 odd + UNI-2 + mid-band + MKKA2 */ + MKK8_MKKC = 0x91, /* Japan UNI-1 even + UNI-1 odd + UNI-2 + mid-band + MKKC */ + + /* Following definitions are used only by s/w to map old + * Japan SKUs. + */ + MKK3_MKKA = 0xF0, /* Japan UNI-1 even + MKKA */ + MKK3_MKKA1 = 0xF1, /* Japan UNI-1 even + MKKA1 */ + MKK3_FCCA = 0xF2, /* Japan UNI-1 even + FCCA */ + MKK4_MKKA = 0xF3, /* Japan UNI-1 even + UNI-2 + MKKA */ + MKK4_MKKA1 = 0xF4, /* Japan UNI-1 even + UNI-2 + MKKA1 */ + MKK4_FCCA = 0xF5, /* Japan UNI-1 even + UNI-2 + FCCA */ + MKK9_MKKA = 0xF6, /* Japan UNI-1 even + 4.9GHz */ + MKK10_MKKA = 0xF7, /* Japan UNI-1 even + UNI-2 + 4.9GHz */ + + /* + * Regulator domains ending in a number (e.g. APL1, + * MK1, ETSI4, etc) apply to 5GHz channel and power + * information. Regulator domains ending in a letter + * (e.g. APLA, FCCA, etc) apply to 2.4GHz channel and + * power information. + */ + APL1 = 0x0150, /* LAT & Asia */ + APL2 = 0x0250, /* LAT & Asia */ + APL3 = 0x0350, /* Taiwan */ + APL4 = 0x0450, /* Jordan */ + APL5 = 0x0550, /* Chile */ + APL6 = 0x0650, /* Singapore */ + APL8 = 0x0850, /* Malaysia */ + APL9 = 0x0950, /* Korea (South) ROC 3 */ + + ETSI1 = 0x0130, /* Europe & others */ + ETSI2 = 0x0230, /* Europe & others */ + ETSI3 = 0x0330, /* Europe & others */ + ETSI4 = 0x0430, /* Europe & others */ + ETSI5 = 0x0530, /* Europe & others */ + ETSI6 = 0x0630, /* Europe & others */ + ETSIA = 0x0A30, /* France */ + ETSIB = 0x0B30, /* Israel */ + ETSIC = 0x0C30, /* Latin America */ + + FCC1 = 0x0110, /* US & others */ + FCC2 = 0x0120, /* Canada, Australia & New Zealand */ + FCC3 = 0x0160, /* US w/new middle band & DFS */ + FCC4 = 0x0165, /* US Public Safety */ + FCC5 = 0x0166, /* US w/ 1/2 and 1/4 width channels */ + FCCA = 0x0A10, + FCCB = 0x0A11, /* US w/ 1/2 and 1/4 width channels */ + + APLD = 0x0D50, /* South Korea */ + + MKK1 = 0x0140, /* Japan (UNI-1 odd)*/ + MKK2 = 0x0240, /* Japan (4.9 GHz + UNI-1 odd) */ + MKK3 = 0x0340, /* Japan (UNI-1 even) */ + MKK4 = 0x0440, /* Japan (UNI-1 even + UNI-2) */ + MKK5 = 0x0540, /* Japan (UNI-1 even + UNI-2 + mid-band) */ + MKK6 = 0x0640, /* Japan (UNI-1 odd + UNI-1 even) */ + MKK7 = 0x0740, /* Japan (UNI-1 odd + UNI-1 even + UNI-2 */ + MKK8 = 0x0840, /* Japan (UNI-1 odd + UNI-1 even + UNI-2 + mid-band) */ + MKK9 = 0x0940, /* Japan (UNI-1 even + 4.9 GHZ) */ + MKK10 = 0x0B40, /* Japan (UNI-1 even + UNI-2 + 4.9 GHZ) */ + MKKA = 0x0A40, /* Japan */ + MKKC = 0x0A50, + + NULL1 = 0x0198, + WORLD = 0x0199, + SR9_WORLD = 0x0298, + XR9_WORLD = 0x0299, + GZ901_WORLD = 0x029a, + DEBUG_REG_DMN = 0x01ff, +}; + +#define WORLD_SKU_MASK 0x00F0 +#define WORLD_SKU_PREFIX 0x0060 + +enum { /* conformance test limits */ + FCC = 0x10, + MKK = 0x40, + ETSI = 0x30, +}; + +/* + * The following are flags for different requirements per reg domain. + * These requirements are either inhereted from the reg domain pair or + * from the unitary reg domain if the reg domain pair flags value is 0 + */ +enum { + NO_REQ = 0x00000000, /* NB: must be zero */ + DISALLOW_ADHOC_11A = 0x00000001, + DISALLOW_ADHOC_11A_TURB = 0x00000002, + NEED_NFC = 0x00000004, + ADHOC_PER_11D = 0x00000008, /* Start Ad-Hoc mode */ + ADHOC_NO_11A = 0x00000010, + LIMIT_FRAME_4MS = 0x00000020, /* 4msec limit on frame length*/ + NO_HOSTAP = 0x00000040, /* No HOSTAP mode opereation */ +}; + +/* + * The following describe the bit masks for different passive scan + * capability/requirements per regdomain. + */ +#define NO_PSCAN 0x0ULL /* NB: must be zero */ +#define PSCAN_FCC 0x0000000000000001ULL +#define PSCAN_FCC_T 0x0000000000000002ULL +#define PSCAN_ETSI 0x0000000000000004ULL +#define PSCAN_MKK1 0x0000000000000008ULL +#define PSCAN_MKK2 0x0000000000000010ULL +#define PSCAN_MKKA 0x0000000000000020ULL +#define PSCAN_MKKA_G 0x0000000000000040ULL +#define PSCAN_ETSIA 0x0000000000000080ULL +#define PSCAN_ETSIB 0x0000000000000100ULL +#define PSCAN_ETSIC 0x0000000000000200ULL +#define PSCAN_WWR 0x0000000000000400ULL +#define PSCAN_MKKA1 0x0000000000000800ULL +#define PSCAN_MKKA1_G 0x0000000000001000ULL +#define PSCAN_MKKA2 0x0000000000002000ULL +#define PSCAN_MKKA2_G 0x0000000000004000ULL +#define PSCAN_MKK3 0x0000000000008000ULL +#define PSCAN_DEFER 0x7FFFFFFFFFFFFFFFULL +#define IS_ECM_CHAN 0x8000000000000000ULL + +/* + * THE following table is the mapping of regdomain pairs specified by + * an 8 bit regdomain value to the individual unitary reg domains + */ +typedef struct { + HAL_REG_DOMAIN regDmnEnum; /* 16 bit reg domain pair */ + HAL_REG_DOMAIN regDmn5GHz; /* 5GHz reg domain */ + HAL_REG_DOMAIN regDmn2GHz; /* 2GHz reg domain */ + uint32_t flags5GHz; /* Requirements flags (AdHoc + disallow, noise floor cal needed, + etc) */ + uint32_t flags2GHz; /* Requirements flags (AdHoc + disallow, noise floor cal needed, + etc) */ + uint64_t pscanMask; /* Passive Scan flags which + can override unitary domain + passive scan flags. This + value is used as a mask on + the unitary flags*/ + uint16_t singleCC; /* Country code of single country if + a one-on-one mapping exists */ +} REG_DMN_PAIR_MAPPING; + +static REG_DMN_PAIR_MAPPING regDomainPairs[] = { + {NO_ENUMRD, DEBUG_REG_DMN, DEBUG_REG_DMN, NO_REQ, NO_REQ, PSCAN_DEFER, 0 }, + {NULL1_WORLD, NULL1, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0 }, + {NULL1_ETSIB, NULL1, ETSIB, NO_REQ, NO_REQ, PSCAN_DEFER, 0 }, + {NULL1_ETSIC, NULL1, ETSIC, NO_REQ, NO_REQ, PSCAN_DEFER, 0 }, + + {FCC2_FCCA, FCC2, FCCA, NO_REQ, NO_REQ, PSCAN_DEFER, 0 }, + {FCC2_WORLD, FCC2, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0 }, + {FCC2_ETSIC, FCC2, ETSIC, NO_REQ, NO_REQ, PSCAN_DEFER, 0 }, + {FCC3_FCCA, FCC3, FCCA, NO_REQ, NO_REQ, PSCAN_DEFER, 0 }, + {FCC3_WORLD, FCC3, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0 }, + {FCC4_FCCA, FCC4, FCCA, DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER, 0 }, + {FCC5_FCCB, FCC5, FCCB, NO_REQ, NO_REQ, PSCAN_DEFER, 0 }, + + {ETSI1_WORLD, ETSI1, WORLD, DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER, 0 }, + {ETSI2_WORLD, ETSI2, WORLD, DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER, 0 }, + {ETSI3_WORLD, ETSI3, WORLD, DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER, 0 }, + {ETSI4_WORLD, ETSI4, WORLD, DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER, 0 }, + {ETSI5_WORLD, ETSI5, WORLD, DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER, 0 }, + {ETSI6_WORLD, ETSI6, WORLD, DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER, 0 }, + + {ETSI3_ETSIA, ETSI3, WORLD, DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER, 0 }, + {FRANCE_RES, ETSI3, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0 }, + + {FCC1_WORLD, FCC1, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0 }, + {FCC1_FCCA, FCC1, FCCA, NO_REQ, NO_REQ, PSCAN_DEFER, 0 }, + {APL1_WORLD, APL1, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0 }, + {APL2_WORLD, APL2, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0 }, + {APL3_WORLD, APL3, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0 }, + {APL4_WORLD, APL4, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0 }, + {APL5_WORLD, APL5, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0 }, + {APL6_WORLD, APL6, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0 }, + {APL8_WORLD, APL8, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0 }, + {APL9_WORLD, APL9, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0 }, + + {APL3_FCCA, APL3, FCCA, NO_REQ, NO_REQ, PSCAN_DEFER, 0 }, + {APL1_ETSIC, APL1, ETSIC, NO_REQ, NO_REQ, PSCAN_DEFER, 0 }, + {APL2_ETSIC, APL2, ETSIC, NO_REQ, NO_REQ, PSCAN_DEFER, 0 }, + {APL2_APLD, APL2, APLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0 }, + + {MKK1_MKKA, MKK1, MKKA, DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, PSCAN_MKK1 | PSCAN_MKKA, CTRY_JAPAN }, + {MKK1_MKKB, MKK1, MKKA, DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB | NEED_NFC| LIMIT_FRAME_4MS, NEED_NFC, PSCAN_MKK1 | PSCAN_MKKA | PSCAN_MKKA_G, CTRY_JAPAN1 }, + {MKK1_FCCA, MKK1, FCCA, DISALLOW_ADHOC_11A_TURB | NEED_NFC| LIMIT_FRAME_4MS, NEED_NFC, PSCAN_MKK1, CTRY_JAPAN2 }, + {MKK1_MKKA1, MKK1, MKKA, DISALLOW_ADHOC_11A_TURB | NEED_NFC| LIMIT_FRAME_4MS, NEED_NFC, PSCAN_MKK1 | PSCAN_MKKA1 | PSCAN_MKKA1_G, CTRY_JAPAN4 }, + {MKK1_MKKA2, MKK1, MKKA, DISALLOW_ADHOC_11A_TURB | NEED_NFC| LIMIT_FRAME_4MS, NEED_NFC, PSCAN_MKK1 | PSCAN_MKKA2 | PSCAN_MKKA2_G, CTRY_JAPAN5 }, + {MKK1_MKKC, MKK1, MKKC, DISALLOW_ADHOC_11A_TURB | NEED_NFC| LIMIT_FRAME_4MS, NEED_NFC, PSCAN_MKK1, CTRY_JAPAN6 }, + + /* MKK2 */ + {MKK2_MKKA, MKK2, MKKA, DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB | NEED_NFC| LIMIT_FRAME_4MS, NEED_NFC, PSCAN_MKK2 | PSCAN_MKKA | PSCAN_MKKA_G, CTRY_JAPAN3 }, + + /* MKK3 */ + {MKK3_MKKA, MKK3, MKKA, DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC , PSCAN_MKKA, 0 }, + {MKK3_MKKB, MKK3, MKKA, DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, PSCAN_MKKA | PSCAN_MKKA_G, CTRY_JAPAN7 }, + {MKK3_MKKA1, MKK3, MKKA, DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, PSCAN_MKKA1 | PSCAN_MKKA1_G, 0 }, + {MKK3_MKKA2,MKK3, MKKA, DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, PSCAN_MKKA2 | PSCAN_MKKA2_G, CTRY_JAPAN8 }, + {MKK3_MKKC, MKK3, MKKC, DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, NO_PSCAN, CTRY_JAPAN9 }, + {MKK3_FCCA, MKK3, FCCA, DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, NO_PSCAN, 0 }, + + /* MKK4 */ + {MKK4_MKKB, MKK4, MKKA, DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, PSCAN_MKK3 | PSCAN_MKKA | PSCAN_MKKA_G, CTRY_JAPAN10 }, + {MKK4_MKKA1, MKK4, MKKA, DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, PSCAN_MKK3 | PSCAN_MKKA1 | PSCAN_MKKA1_G, 0 }, + {MKK4_MKKA2, MKK4, MKKA, DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, PSCAN_MKK3 |PSCAN_MKKA2 | PSCAN_MKKA2_G, CTRY_JAPAN11 }, + {MKK4_MKKC, MKK4, MKKC, DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, PSCAN_MKK3, CTRY_JAPAN12 }, + {MKK4_FCCA, MKK4, FCCA, DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, PSCAN_MKK3, 0 }, + + /* MKK5 */ + {MKK5_MKKB, MKK5, MKKA, DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, PSCAN_MKK3 | PSCAN_MKKA | PSCAN_MKKA_G, CTRY_JAPAN13 }, + {MKK5_MKKA2,MKK5, MKKA, DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, PSCAN_MKK3 | PSCAN_MKKA2 | PSCAN_MKKA2_G, CTRY_JAPAN14 }, + {MKK5_MKKC, MKK5, MKKC, DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, PSCAN_MKK3, CTRY_JAPAN15 }, + + /* MKK6 */ + {MKK6_MKKB, MKK6, MKKA, DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, PSCAN_MKK1 | PSCAN_MKKA | PSCAN_MKKA_G, CTRY_JAPAN16 }, + {MKK6_MKKA2, MKK6, MKKA, DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, PSCAN_MKK1 | PSCAN_MKKA2 | PSCAN_MKKA2_G, CTRY_JAPAN17 }, + {MKK6_MKKC, MKK6, MKKC, DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, PSCAN_MKK1, CTRY_JAPAN18 }, + + /* MKK7 */ + {MKK7_MKKB, MKK7, MKKA, DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, PSCAN_MKK1 | PSCAN_MKK3 | PSCAN_MKKA | PSCAN_MKKA_G, CTRY_JAPAN19 }, + {MKK7_MKKA2, MKK7, MKKA, DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, PSCAN_MKK1 | PSCAN_MKK3 | PSCAN_MKKA2 | PSCAN_MKKA2_G, CTRY_JAPAN20 }, + {MKK7_MKKC, MKK7, MKKC, DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, PSCAN_MKK1 | PSCAN_MKK3, CTRY_JAPAN21 }, + + /* MKK8 */ + {MKK8_MKKB, MKK8, MKKA, DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, PSCAN_MKK1 | PSCAN_MKK3 | PSCAN_MKKA | PSCAN_MKKA_G, CTRY_JAPAN22 }, + {MKK8_MKKA2,MKK8, MKKA, DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, PSCAN_MKK1 | PSCAN_MKK3 | PSCAN_MKKA2 | PSCAN_MKKA2_G, CTRY_JAPAN23 }, + {MKK8_MKKC, MKK8, MKKC, DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, PSCAN_MKK1 | PSCAN_MKK3 , CTRY_JAPAN24 }, + + {MKK9_MKKA, MKK9, MKKA, DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, PSCAN_MKK3 | PSCAN_MKKA | PSCAN_MKKA_G, 0 }, + {MKK10_MKKA, MKK10, MKKA, DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, PSCAN_MKK3 | PSCAN_MKKA | PSCAN_MKKA_G, 0 }, + + /* These are super domains */ + {WOR0_WORLD, WOR0_WORLD, WOR0_WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0 }, + {WOR1_WORLD, WOR1_WORLD, WOR1_WORLD, DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER, 0 }, + {WOR2_WORLD, WOR2_WORLD, WOR2_WORLD, DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER, 0 }, + {WOR3_WORLD, WOR3_WORLD, WOR3_WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0 }, + {WOR4_WORLD, WOR4_WORLD, WOR4_WORLD, DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER, 0 }, + {WOR5_ETSIC, WOR5_ETSIC, WOR5_ETSIC, DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER, 0 }, + {WOR01_WORLD, WOR01_WORLD, WOR01_WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0 }, + {WOR02_WORLD, WOR02_WORLD, WOR02_WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0 }, + {EU1_WORLD, EU1_WORLD, EU1_WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0 }, + {WOR9_WORLD, WOR9_WORLD, WOR9_WORLD, DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER, 0 }, + {WORA_WORLD, WORA_WORLD, WORA_WORLD, DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER, 0 }, + {SR9_WORLD, NULL1, SR9_WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, CTRY_SR9 }, + {XR9_WORLD, NULL1, XR9_WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, CTRY_XR9 }, + {GZ901_WORLD, NULL1, GZ901_WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, CTRY_GZ901 }, +}; + +/* + * The following tables are the master list for all different freqeuncy + * bands with the complete matrix of all possible flags and settings + * for each band if it is used in ANY reg domain. + */ + +#define DEF_REGDMN FCC1_FCCA +#define DEF_DMN_5 FCC1 +#define DEF_DMN_2 FCCA +#define COUNTRY_ERD_FLAG 0x8000 +#define WORLDWIDE_ROAMING_FLAG 0x4000 +#define SUPER_DOMAIN_MASK 0x0fff +#define COUNTRY_CODE_MASK 0x3fff + +#define YES AH_TRUE +#define NO AH_FALSE + +typedef struct { + HAL_CTRY_CODE countryCode; + HAL_REG_DOMAIN regDmnEnum; + HAL_BOOL allow11g; + HAL_BOOL allow11aTurbo; + HAL_BOOL allow11gTurbo; + HAL_BOOL allow11ng20; + HAL_BOOL allow11ng40; + HAL_BOOL allow11na20; + HAL_BOOL allow11na40; + uint16_t outdoorChanStart; +} COUNTRY_CODE_TO_ENUM_RD; + +static COUNTRY_CODE_TO_ENUM_RD allCountries[] = { + {CTRY_DEBUG, NO_ENUMRD, YES, YES, YES, YES,YES, YES,YES, 7000 }, + {CTRY_DEFAULT, DEF_REGDMN, YES, YES, YES, YES,YES, YES,YES, 7000 }, + {CTRY_ALBANIA, NULL1_WORLD, YES, NO, YES, YES, NO, NO, NO, 7000 }, + {CTRY_ALGERIA, NULL1_WORLD, YES, NO, YES, YES, NO, NO, NO, 7000 }, + {CTRY_ARGENTINA, APL3_WORLD, NO, NO, NO, NO, NO, NO, NO, 7000 }, + {CTRY_ARMENIA, ETSI4_WORLD, YES, NO, YES, YES,YES, NO, NO, 7000 }, + {CTRY_AUSTRALIA, FCC2_WORLD, YES, YES, YES, YES,YES, YES,YES, 7000 }, + {CTRY_AUSTRIA, ETSI1_WORLD, YES, NO, YES, YES,YES, YES,YES, 7000 }, + {CTRY_AZERBAIJAN, ETSI4_WORLD, YES, YES, YES, YES,YES, YES,YES, 7000 }, + {CTRY_BAHRAIN, APL6_WORLD, YES, NO, YES, YES,YES, YES, NO, 7000 }, + {CTRY_BELARUS, NULL1_WORLD, YES, NO, YES, YES,YES, YES, NO, 7000 }, + {CTRY_BELGIUM, ETSI1_WORLD, YES, NO, YES, YES,YES, YES,YES, 7000 }, + {CTRY_BELIZE, APL1_ETSIC, YES, YES, YES, YES,YES, YES,YES, 7000 }, + {CTRY_BOLIVIA, APL1_ETSIC, YES, YES, YES, YES,YES, YES,YES, 7000 }, + {CTRY_BRAZIL, FCC3_WORLD, YES, NO, NO, YES, NO, YES, NO, 7000 }, + {CTRY_BRUNEI_DARUSSALAM,APL1_WORLD, YES, YES, YES, YES,YES, YES,YES, 7000 }, + {CTRY_BULGARIA, ETSI6_WORLD, YES, NO, YES, YES,YES, YES,YES, 7000 }, + {CTRY_CANADA, FCC2_FCCA, YES, YES, YES, YES,YES, YES,YES, 7000 }, + {CTRY_CHILE, APL6_WORLD, YES, YES, YES, YES,YES, YES,YES, 7000 }, + {CTRY_CHINA, APL1_WORLD, YES, YES, YES, YES,YES, YES,YES, 7000 }, + {CTRY_COLOMBIA, FCC1_FCCA, YES, NO, YES, YES,YES, YES, NO, 7000 }, + {CTRY_COSTA_RICA, NULL1_WORLD, YES, NO, YES, YES,YES, YES, NO, 7000 }, + {CTRY_CROATIA, ETSI3_WORLD, YES, NO, YES, YES,YES, YES, NO, 7000 }, + {CTRY_CYPRUS, ETSI1_WORLD, YES, YES, YES, YES,YES, YES,YES, 7000 }, + {CTRY_CZECH, ETSI1_WORLD, YES, NO, YES, YES,YES, YES,YES, 7000 }, + {CTRY_DENMARK, ETSI1_WORLD, YES, NO, YES, YES,YES, YES,YES, 7000 }, + {CTRY_DOMINICAN_REPUBLIC,FCC1_FCCA, YES, YES, YES, YES,YES, YES,YES, 7000 }, + {CTRY_ECUADOR, NULL1_WORLD, NO, NO, NO, NO, NO, NO, NO, 7000 }, + {CTRY_EGYPT, ETSI3_WORLD, YES, NO, YES, YES,YES, YES, NO, 7000 }, + {CTRY_EL_SALVADOR, NULL1_WORLD, YES, NO, YES, YES,YES, NO, NO, 7000 }, + {CTRY_ESTONIA, ETSI1_WORLD, YES, NO, YES, YES,YES, YES,YES, 7000 }, + {CTRY_FINLAND, ETSI1_WORLD, YES, NO, YES, YES,YES, YES,YES, 7000 }, + {CTRY_FRANCE, ETSI1_WORLD, YES, NO, YES, YES,YES, YES,YES, 7000 }, + {CTRY_FRANCE2, ETSI3_WORLD, YES, NO, YES, YES,YES, YES,YES, 7000 }, + {CTRY_GEORGIA, ETSI4_WORLD, YES, YES, YES, YES,YES, YES,YES, 7000 }, + {CTRY_GERMANY, ETSI1_WORLD, YES, NO, YES, YES,YES, YES,YES, 7000 }, + {CTRY_GREECE, ETSI1_WORLD, YES, NO, YES, YES,YES, YES,YES, 7000 }, + {CTRY_GUATEMALA, FCC1_FCCA, YES, YES, YES, YES,YES, YES,YES, 7000 }, + {CTRY_GZ901, GZ901_WORLD, YES, NO, NO, NO, NO, NO, NO, 7000 }, + {CTRY_HONDURAS, NULL1_WORLD, YES, NO, YES, YES,YES, YES, NO, 7000 }, + {CTRY_HONG_KONG, FCC2_WORLD, YES, YES, YES, YES,YES, YES,YES, 7000 }, + {CTRY_HUNGARY, ETSI1_WORLD, YES, NO, YES, YES,YES, YES,YES, 7000 }, + {CTRY_ICELAND, ETSI1_WORLD, YES, NO, YES, YES,YES, YES,YES, 7000 }, + {CTRY_INDIA, APL6_WORLD, YES, NO, YES, YES,YES, YES, NO, 7000 }, + {CTRY_INDONESIA, APL1_WORLD, YES, NO, YES, YES,YES, YES, NO, 7000 }, + {CTRY_IRAN, APL1_WORLD, YES, YES, YES, YES,YES, YES,YES, 7000 }, + {CTRY_IRELAND, ETSI1_WORLD, YES, NO, YES, YES,YES, YES,YES, 7000 }, + {CTRY_ISRAEL, NULL1_WORLD, YES, NO, YES, YES,YES, YES, NO, 7000 }, + {CTRY_ITALY, ETSI1_WORLD, YES, NO, YES, YES,YES, YES,YES, 7000 }, + {CTRY_JAPAN, MKK1_MKKA, YES, NO, NO, YES, NO, YES, NO, 7000 }, + {CTRY_JAPAN1, MKK1_MKKB, YES, NO, NO, NO, NO, NO, NO, 7000 }, + {CTRY_JAPAN2, MKK1_FCCA, YES, NO, NO, NO, NO, NO, NO, 7000 }, + {CTRY_JAPAN3, MKK2_MKKA, YES, NO, NO, NO, NO, NO, NO, 7000 }, + {CTRY_JAPAN4, MKK1_MKKA1, YES, NO, NO, NO, NO, NO, NO, 7000 }, + {CTRY_JAPAN5, MKK1_MKKA2, YES, NO, NO, NO, NO, NO, NO, 7000 }, + {CTRY_JAPAN6, MKK1_MKKC, YES, NO, NO, NO, NO, NO, NO, 7000 }, + + {CTRY_JAPAN7, MKK3_MKKB, YES, NO, NO, NO, NO, NO, NO, 7000 }, + {CTRY_JAPAN8, MKK3_MKKA2, YES, NO, NO, NO, NO, NO, NO, 7000 }, + {CTRY_JAPAN9, MKK3_MKKC, YES, NO, NO, NO, NO, NO, NO, 7000 }, + + {CTRY_JAPAN10, MKK4_MKKB, YES, NO, NO, NO, NO, NO, NO, 7000 }, + {CTRY_JAPAN11, MKK4_MKKA2, YES, NO, NO, NO, NO, NO, NO, 7000 }, + {CTRY_JAPAN12, MKK4_MKKC, YES, NO, NO, NO, NO, NO, NO, 7000 }, + + {CTRY_JAPAN13, MKK5_MKKB, YES, NO, NO, NO, NO, NO, NO, 7000 }, + {CTRY_JAPAN14, MKK5_MKKA2, YES, NO, NO, NO, NO, NO, NO, 7000 }, + {CTRY_JAPAN15, MKK5_MKKC, YES, NO, NO, NO, NO, NO, NO, 7000 }, + + {CTRY_JAPAN16, MKK6_MKKB, YES, NO, NO, NO, NO, NO, NO, 7000 }, + {CTRY_JAPAN17, MKK6_MKKA2, YES, NO, NO, NO, NO, NO, NO, 7000 }, + {CTRY_JAPAN18, MKK6_MKKC, YES, NO, NO, NO, NO, NO, NO, 7000 }, + + {CTRY_JAPAN19, MKK7_MKKB, YES, NO, NO, NO, NO, NO, NO, 7000 }, + {CTRY_JAPAN20, MKK7_MKKA2, YES, NO, NO, YES, NO, YES, NO, 7000 }, + {CTRY_JAPAN21, MKK7_MKKC, YES, NO, NO, NO, NO, NO, NO, 7000 }, + + {CTRY_JAPAN22, MKK8_MKKB, YES, NO, NO, NO, NO, NO, NO, 7000 }, + {CTRY_JAPAN23, MKK8_MKKA2, YES, NO, NO, NO, NO, NO, NO, 7000 }, + {CTRY_JAPAN24, MKK8_MKKC, YES, NO, NO, NO, NO, NO, NO, 7000 }, + + {CTRY_JORDAN, APL4_WORLD, YES, NO, YES, YES,YES, YES, NO, 7000 }, + {CTRY_KAZAKHSTAN, NULL1_WORLD, YES, NO, YES, YES,YES, NO, NO, 7000 }, + {CTRY_KOREA_NORTH, APL2_WORLD, YES, YES, YES, YES,YES, YES,YES, 7000 }, + {CTRY_KOREA_ROC, APL2_WORLD, YES, NO, NO, YES, NO, YES, NO, 7000 }, + {CTRY_KOREA_ROC2, APL2_WORLD, YES, NO, NO, YES, NO, YES, NO, 7000 }, + {CTRY_KOREA_ROC3, APL9_WORLD, YES, NO, NO, YES, NO, YES, NO, 7000 }, + {CTRY_KUWAIT, NULL1_WORLD, YES, NO, YES, YES,YES, YES, NO, 7000 }, + {CTRY_LATVIA, ETSI1_WORLD, YES, NO, YES, YES,YES, YES,YES, 7000 }, + {CTRY_LEBANON, NULL1_WORLD, YES, NO, YES, YES,YES, YES, NO, 7000 }, + {CTRY_LIECHTENSTEIN,ETSI1_WORLD, YES, NO, YES, YES,YES, YES,YES, 7000 }, + {CTRY_LITHUANIA, ETSI1_WORLD, YES, NO, YES, YES,YES, YES,YES, 7000 }, + {CTRY_LUXEMBOURG, ETSI1_WORLD, YES, NO, YES, YES,YES, YES,YES, 7000 }, + {CTRY_MACAU, FCC2_WORLD, YES, YES, YES, YES,YES, YES,YES, 7000 }, + {CTRY_MACEDONIA, NULL1_WORLD, YES, NO, YES, YES,YES, NO, NO, 7000 }, + {CTRY_MALAYSIA, APL8_WORLD, YES, NO, NO, YES, NO, YES, NO, 7000 }, + {CTRY_MALTA, ETSI1_WORLD, YES, NO, YES, YES,YES, YES,YES, 7000 }, + {CTRY_MEXICO, FCC1_FCCA, YES, YES, YES, YES,YES, YES,YES, 7000 }, + {CTRY_MONACO, ETSI4_WORLD, YES, YES, YES, YES,YES, YES,YES, 7000 }, + {CTRY_MOROCCO, NULL1_WORLD, YES, NO, YES, YES,YES, NO, NO, 7000 }, + {CTRY_NETHERLANDS, ETSI1_WORLD, YES, NO, YES, YES,YES, YES,YES, 7000 }, + {CTRY_NEW_ZEALAND, FCC2_ETSIC, YES, NO, YES, YES,YES, YES,YES, 7000 }, + {CTRY_NORWAY, ETSI1_WORLD, YES, NO, YES, YES,YES, YES,YES, 7000 }, + {CTRY_OMAN, APL6_WORLD, YES, NO, YES, YES,YES, YES, NO, 7000 }, + {CTRY_PAKISTAN, NULL1_WORLD, YES, NO, YES, YES,YES, NO, NO, 7000 }, + {CTRY_PANAMA, FCC1_FCCA, YES, YES, YES, YES,YES, YES,YES, 7000 }, + {CTRY_PERU, APL1_WORLD, YES, NO, YES, YES,YES, YES, NO, 7000 }, + {CTRY_PHILIPPINES, FCC3_WORLD, YES, YES, YES, YES,YES, YES,YES, 7000 }, + {CTRY_POLAND, ETSI1_WORLD, YES, NO, YES, YES,YES, YES,YES, 7000 }, + {CTRY_PORTUGAL, ETSI1_WORLD, YES, NO, YES, YES,YES, YES,YES, 7000 }, + {CTRY_PUERTO_RICO, FCC1_FCCA, YES, YES, YES, YES,YES, YES,YES, 7000 }, + {CTRY_QATAR, NULL1_WORLD, YES, NO, YES, YES,YES, NO, NO, 7000 }, + {CTRY_ROMANIA, NULL1_WORLD, YES, NO, YES, YES,YES, NO, NO, 7000 }, + {CTRY_RUSSIA, NULL1_WORLD, YES, NO, YES, YES,YES, NO, NO, 7000 }, + {CTRY_SAUDI_ARABIA,FCC2_WORLD, YES, NO, YES, YES,YES, YES, NO, 7000 }, + {CTRY_SINGAPORE, APL6_WORLD, YES, YES, YES, YES,YES, YES,YES, 7000 }, + {CTRY_SLOVAKIA, ETSI1_WORLD, YES, NO, YES, YES,YES, YES,YES, 7000 }, + {CTRY_SLOVENIA, ETSI1_WORLD, YES, NO, YES, YES,YES, YES,YES, 7000 }, + {CTRY_SOUTH_AFRICA,FCC3_WORLD, YES, NO, YES, YES,YES, YES, NO, 7000 }, + {CTRY_SPAIN, ETSI1_WORLD, YES, NO, YES, YES,YES, YES,YES, 7000 }, + {CTRY_SR9, SR9_WORLD, YES, NO, NO, NO, NO, NO, NO, 7000 }, + {CTRY_SWEDEN, ETSI1_WORLD, YES, NO, YES, YES,YES, YES,YES, 7000 }, + {CTRY_SWITZERLAND, ETSI1_WORLD, YES, NO, YES, YES,YES, YES,YES, 7000 }, + {CTRY_SYRIA, NULL1_WORLD, YES, NO, YES, YES,YES, YES, NO, 7000 }, + {CTRY_TAIWAN, APL3_FCCA, YES, YES, YES, YES,YES, YES,YES, 7000 }, + {CTRY_THAILAND, NULL1_WORLD, YES, NO, YES, YES,YES, NO, NO, 7000 }, + {CTRY_TRINIDAD_Y_TOBAGO,ETSI4_WORLD,YES, NO, YES, YES,YES, YES, NO, 7000 }, + {CTRY_TUNISIA, ETSI3_WORLD, YES, NO, YES, YES,YES, YES, NO, 7000 }, + {CTRY_TURKEY, ETSI3_WORLD, YES, NO, YES, YES,YES, YES, NO, 7000 }, + {CTRY_UKRAINE, NULL1_WORLD, YES, NO, YES, YES,YES, NO, NO, 7000 }, + {CTRY_UAE, NULL1_WORLD, YES, NO, YES, YES,YES, NO, NO, 7000 }, + {CTRY_UNITED_KINGDOM, ETSI1_WORLD, YES, NO, YES, YES,YES, YES, NO, 7000 }, + {CTRY_UNITED_STATES, FCC1_FCCA, YES, YES, YES, YES,YES, YES,YES, 5825 }, + {CTRY_UNITED_STATES_FCC49,FCC4_FCCA,YES, YES, YES, YES,YES, YES,YES, 7000 }, + {CTRY_URUGUAY, FCC1_WORLD, YES, NO, YES, YES,YES, YES, NO, 7000 }, + {CTRY_UZBEKISTAN, FCC3_FCCA, YES, YES, YES, YES,YES, YES,YES, 7000 }, + {CTRY_VENEZUELA, APL2_ETSIC, YES, NO, YES, YES,YES, YES, NO, 7000 }, + {CTRY_VIET_NAM, NULL1_WORLD, YES, NO, YES, YES,YES, NO, NO, 7000 }, + {CTRY_XR9, XR9_WORLD, YES, NO, NO, NO, NO, NO, NO, 7000 }, + {CTRY_YEMEN, NULL1_WORLD, YES, NO, YES, YES,YES, NO, NO, 7000 }, + {CTRY_ZIMBABWE, NULL1_WORLD, YES, NO, YES, YES,YES, NO, NO, 7000 } +}; + +/* Bit masks for DFS per regdomain */ +enum { + NO_DFS = 0x0000000000000000ULL, /* NB: must be zero */ + DFS_FCC3 = 0x0000000000000001ULL, + DFS_ETSI = 0x0000000000000002ULL, + DFS_MKK4 = 0x0000000000000004ULL, +}; + +#define AFTER(x) ((x)+1) + +/* + * Frequency band collections are defined using bitmasks. Each bit + * in a mask is the index of an entry in one of the following tables. + * Bitmasks are BMLEN*64 bits so if a table grows beyond that the bit + * vectors must be enlarged or the tables split somehow (e.g. split + * 1/2 and 1/4 rate channels into a separate table). + * + * Beware of ordering; the indices are defined relative to the preceding + * entry so if things get off there will be confusion. A good way to + * check the indices is to collect them in a switch statement in a stub + * function so the compiler checks for duplicates. + */ + +typedef struct { + uint16_t lowChannel; /* Low channel center in MHz */ + uint16_t highChannel; /* High Channel center in MHz */ + uint8_t powerDfs; /* Max power (dBm) for channel + range when using DFS */ + uint8_t antennaMax; /* Max allowed antenna gain */ + uint8_t channelBW; /* Bandwidth of the channel */ + uint8_t channelSep; /* Channel separation within + the band */ + uint64_t useDfs; /* Use DFS in the RegDomain + if corresponding bit is set */ + uint64_t usePassScan; /* Use Passive Scan in the RegDomain + if corresponding bit is set */ + uint8_t regClassId; /* Regulatory class id */ +} REG_DMN_FREQ_BAND; + +/* + * 5GHz 11A channel tags + */ +static REG_DMN_FREQ_BAND regDmn5GhzFreq[] = { + { 4915, 4925, 23, 0, 10, 5, NO_DFS, PSCAN_MKK2, 16 }, +#define F1_4915_4925 0 + { 4935, 4945, 23, 0, 10, 5, NO_DFS, PSCAN_MKK2, 16 }, +#define F1_4935_4945 AFTER(F1_4915_4925) + { 4920, 4980, 23, 0, 20, 20, NO_DFS, PSCAN_MKK2, 7 }, +#define F1_4920_4980 AFTER(F1_4935_4945) + { 4942, 4987, 27, 6, 5, 5, NO_DFS, PSCAN_FCC, 0 }, +#define F1_4942_4987 AFTER(F1_4920_4980) + { 4945, 4985, 30, 6, 10, 5, NO_DFS, PSCAN_FCC, 0 }, +#define F1_4945_4985 AFTER(F1_4942_4987) + { 4950, 4980, 33, 6, 20, 5, NO_DFS, PSCAN_FCC, 0 }, +#define F1_4950_4980 AFTER(F1_4945_4985) + { 5035, 5040, 23, 0, 10, 5, NO_DFS, PSCAN_MKK2, 12 }, +#define F1_5035_5040 AFTER(F1_4950_4980) + { 5040, 5080, 23, 0, 20, 20, NO_DFS, PSCAN_MKK2, 2 }, +#define F1_5040_5080 AFTER(F1_5035_5040) + { 5055, 5055, 23, 0, 10, 5, NO_DFS, PSCAN_MKK2, 12 }, +#define F1_5055_5055 AFTER(F1_5040_5080) + + { 5120, 5240, 5, 6, 20, 20, NO_DFS, NO_PSCAN, 0 }, +#define F1_5120_5240 AFTER(F1_5055_5055) + { 5120, 5240, 5, 6, 10, 10, NO_DFS, NO_PSCAN, 0 }, +#define F2_5120_5240 AFTER(F1_5120_5240) + { 5120, 5240, 5, 6, 5, 5, NO_DFS, NO_PSCAN, 0 }, +#define F3_5120_5240 AFTER(F2_5120_5240) + + { 5170, 5230, 23, 0, 20, 20, NO_DFS, PSCAN_MKK1 | PSCAN_MKK2, 1 }, +#define F1_5170_5230 AFTER(F3_5120_5240) + { 5170, 5230, 20, 0, 20, 20, NO_DFS, PSCAN_MKK1 | PSCAN_MKK2, 1 }, +#define F2_5170_5230 AFTER(F1_5170_5230) + + { 5180, 5240, 15, 0, 20, 20, NO_DFS, PSCAN_FCC | PSCAN_ETSI, 0 }, +#define F1_5180_5240 AFTER(F2_5170_5230) + { 5180, 5240, 17, 6, 20, 20, NO_DFS, PSCAN_FCC, 1 }, +#define F2_5180_5240 AFTER(F1_5180_5240) + { 5180, 5240, 18, 0, 20, 20, NO_DFS, PSCAN_FCC | PSCAN_ETSI, 0 }, +#define F3_5180_5240 AFTER(F2_5180_5240) + { 5180, 5240, 20, 0, 20, 20, NO_DFS, PSCAN_FCC | PSCAN_ETSI, 0 }, +#define F4_5180_5240 AFTER(F3_5180_5240) + { 5180, 5240, 23, 0, 20, 20, NO_DFS, PSCAN_FCC | PSCAN_ETSI, 0 }, +#define F5_5180_5240 AFTER(F4_5180_5240) + { 5180, 5240, 23, 6, 20, 20, NO_DFS, PSCAN_FCC, 0 }, +#define F6_5180_5240 AFTER(F5_5180_5240) + { 5180, 5240, 17, 6, 20, 10, NO_DFS, PSCAN_FCC, 1 }, +#define F7_5180_5240 AFTER(F6_5180_5240) + { 5180, 5240, 17, 6, 20, 5, NO_DFS, PSCAN_FCC, 1 }, +#define F8_5180_5240 AFTER(F7_5180_5240) + + { 5180, 5320, 20, 6, 20, 20, DFS_ETSI, PSCAN_ETSI, 0 }, +#define F1_5180_5320 AFTER(F8_5180_5240) + + { 5240, 5280, 23, 0, 20, 20, DFS_FCC3, PSCAN_FCC | PSCAN_ETSI, 0 }, +#define F1_5240_5280 AFTER(F1_5180_5320) + + { 5260, 5280, 23, 0, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_FCC | PSCAN_ETSI, 0 }, +#define F1_5260_5280 AFTER(F1_5240_5280) + + { 5260, 5320, 18, 0, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_FCC | PSCAN_ETSI, 0 }, +#define F1_5260_5320 AFTER(F1_5260_5280) + + { 5260, 5320, 20, 0, 20, 20, DFS_FCC3 | DFS_ETSI | DFS_MKK4, PSCAN_FCC | PSCAN_ETSI | PSCAN_MKK3 , 0 }, +#define F2_5260_5320 AFTER(F1_5260_5320) + + { 5260, 5320, 20, 6, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_FCC, 2 }, +#define F3_5260_5320 AFTER(F2_5260_5320) + { 5260, 5320, 23, 6, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_FCC, 2 }, +#define F4_5260_5320 AFTER(F3_5260_5320) + { 5260, 5320, 23, 6, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_FCC, 0 }, +#define F5_5260_5320 AFTER(F4_5260_5320) + { 5260, 5320, 30, 0, 20, 20, NO_DFS, NO_PSCAN, 0 }, +#define F6_5260_5320 AFTER(F5_5260_5320) + { 5260, 5320, 23, 6, 20, 10, DFS_FCC3 | DFS_ETSI, PSCAN_FCC, 2 }, +#define F7_5260_5320 AFTER(F6_5260_5320) + { 5260, 5320, 23, 6, 20, 5, DFS_FCC3 | DFS_ETSI, PSCAN_FCC, 2 }, +#define F8_5260_5320 AFTER(F7_5260_5320) + + { 5260, 5700, 5, 6, 20, 20, DFS_FCC3 | DFS_ETSI, NO_PSCAN, 0 }, +#define F1_5260_5700 AFTER(F8_5260_5320) + { 5260, 5700, 5, 6, 10, 10, DFS_FCC3 | DFS_ETSI, NO_PSCAN, 0 }, +#define F2_5260_5700 AFTER(F1_5260_5700) + { 5260, 5700, 5, 6, 5, 5, DFS_FCC3 | DFS_ETSI, NO_PSCAN, 0 }, +#define F3_5260_5700 AFTER(F2_5260_5700) + + { 5280, 5320, 17, 6, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_FCC, 0 }, +#define F1_5280_5320 AFTER(F3_5260_5700) + + { 5500, 5620, 30, 6, 20, 20, DFS_ETSI, PSCAN_ETSI, 0 }, +#define F1_5500_5620 AFTER(F1_5280_5320) + + { 5500, 5700, 20, 6, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_FCC, 4 }, +#define F1_5500_5700 AFTER(F1_5500_5620) + { 5500, 5700, 27, 0, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_FCC | PSCAN_ETSI, 0 }, +#define F2_5500_5700 AFTER(F1_5500_5700) + { 5500, 5700, 30, 0, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_FCC | PSCAN_ETSI, 0 }, +#define F3_5500_5700 AFTER(F2_5500_5700) + { 5500, 5700, 23, 0, 20, 20, DFS_FCC3 | DFS_ETSI | DFS_MKK4, PSCAN_MKK3 | PSCAN_FCC, 0 }, +#define F4_5500_5700 AFTER(F3_5500_5700) + + { 5745, 5805, 23, 0, 20, 20, NO_DFS, NO_PSCAN, 0 }, +#define F1_5745_5805 AFTER(F4_5500_5700) + { 5745, 5805, 30, 6, 20, 20, NO_DFS, NO_PSCAN, 0 }, +#define F2_5745_5805 AFTER(F1_5745_5805) + { 5745, 5805, 30, 6, 20, 20, DFS_ETSI, PSCAN_ETSI, 0 }, +#define F3_5745_5805 AFTER(F2_5745_5805) + { 5745, 5825, 5, 6, 20, 20, NO_DFS, NO_PSCAN, 0 }, +#define F1_5745_5825 AFTER(F3_5745_5805) + { 5745, 5825, 17, 0, 20, 20, NO_DFS, NO_PSCAN, 0 }, +#define F2_5745_5825 AFTER(F1_5745_5825) + { 5745, 5825, 20, 0, 20, 20, NO_DFS, NO_PSCAN, 0 }, +#define F3_5745_5825 AFTER(F2_5745_5825) + { 5745, 5825, 30, 0, 20, 20, NO_DFS, NO_PSCAN, 0 }, +#define F4_5745_5825 AFTER(F3_5745_5825) + { 5745, 5825, 30, 6, 20, 20, NO_DFS, NO_PSCAN, 3 }, +#define F5_5745_5825 AFTER(F4_5745_5825) + { 5745, 5825, 30, 6, 20, 20, NO_DFS, NO_PSCAN, 0 }, +#define F6_5745_5825 AFTER(F5_5745_5825) + { 5745, 5825, 5, 6, 10, 10, NO_DFS, NO_PSCAN, 0 }, +#define F7_5745_5825 AFTER(F6_5745_5825) + { 5745, 5825, 5, 6, 5, 5, NO_DFS, NO_PSCAN, 0 }, +#define F8_5745_5825 AFTER(F7_5745_5825) + { 5745, 5825, 30, 6, 20, 10, NO_DFS, NO_PSCAN, 3 }, +#define F9_5745_5825 AFTER(F8_5745_5825) + { 5745, 5825, 30, 6, 20, 5, NO_DFS, NO_PSCAN, 3 }, +#define F10_5745_5825 AFTER(F9_5745_5825) + + /* + * Below are the world roaming channels + * All WWR domains have no power limit, instead use the card's CTL + * or max power settings. + */ + { 4920, 4980, 30, 0, 20, 20, NO_DFS, PSCAN_WWR, 0 }, +#define W1_4920_4980 AFTER(F10_5745_5825) + { 5040, 5080, 30, 0, 20, 20, NO_DFS, PSCAN_WWR, 0 }, +#define W1_5040_5080 AFTER(W1_4920_4980) + { 5170, 5230, 30, 0, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, 0 }, +#define W1_5170_5230 AFTER(W1_5040_5080) + { 5180, 5240, 30, 0, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, 0 }, +#define W1_5180_5240 AFTER(W1_5170_5230) + { 5260, 5320, 30, 0, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, 0 }, +#define W1_5260_5320 AFTER(W1_5180_5240) + { 5745, 5825, 30, 0, 20, 20, NO_DFS, PSCAN_WWR, 0 }, +#define W1_5745_5825 AFTER(W1_5260_5320) + { 5500, 5700, 30, 0, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, 0 }, +#define W1_5500_5700 AFTER(W1_5745_5825) + { 5260, 5320, 30, 0, 20, 20, NO_DFS, NO_PSCAN, 0 }, +#define W2_5260_5320 AFTER(W1_5500_5700) + { 5180, 5240, 30, 0, 20, 20, NO_DFS, NO_PSCAN, 0 }, +#define W2_5180_5240 AFTER(W2_5260_5320) + { 5825, 5825, 30, 0, 20, 20, NO_DFS, PSCAN_WWR, 0 }, +#define W2_5825_5825 AFTER(W2_5180_5240) +}; + +/* + * 5GHz Turbo (dynamic & static) tags + */ +static REG_DMN_FREQ_BAND regDmn5GhzTurboFreq[] = { + { 5130, 5210, 5, 6, 40, 40, NO_DFS, NO_PSCAN, 0}, +#define T1_5130_5210 0 + { 5250, 5330, 5, 6, 40, 40, DFS_FCC3, NO_PSCAN, 0}, +#define T1_5250_5330 AFTER(T1_5130_5210) + { 5370, 5490, 5, 6, 40, 40, NO_DFS, NO_PSCAN, 0}, +#define T1_5370_5490 AFTER(T1_5250_5330) + { 5530, 5650, 5, 6, 40, 40, DFS_FCC3, NO_PSCAN, 0}, +#define T1_5530_5650 AFTER(T1_5370_5490) + + { 5150, 5190, 5, 6, 40, 40, NO_DFS, NO_PSCAN, 0}, +#define T1_5150_5190 AFTER(T1_5530_5650) + { 5230, 5310, 5, 6, 40, 40, DFS_FCC3, NO_PSCAN, 0}, +#define T1_5230_5310 AFTER(T1_5150_5190) + { 5350, 5470, 5, 6, 40, 40, NO_DFS, NO_PSCAN, 0}, +#define T1_5350_5470 AFTER(T1_5230_5310) + { 5510, 5670, 5, 6, 40, 40, DFS_FCC3, NO_PSCAN, 0}, +#define T1_5510_5670 AFTER(T1_5350_5470) + + { 5200, 5240, 17, 6, 40, 40, NO_DFS, NO_PSCAN, 0}, +#define T1_5200_5240 AFTER(T1_5510_5670) + { 5200, 5240, 23, 6, 40, 40, NO_DFS, NO_PSCAN, 0}, +#define T2_5200_5240 AFTER(T1_5200_5240) + { 5210, 5210, 17, 6, 40, 40, NO_DFS, NO_PSCAN, 0}, +#define T1_5210_5210 AFTER(T2_5200_5240) + { 5210, 5210, 23, 0, 40, 40, NO_DFS, NO_PSCAN, 0}, +#define T2_5210_5210 AFTER(T1_5210_5210) + + { 5280, 5280, 23, 6, 40, 40, DFS_FCC3, PSCAN_FCC_T, 0}, +#define T1_5280_5280 AFTER(T2_5210_5210) + { 5280, 5280, 20, 6, 40, 40, DFS_FCC3, PSCAN_FCC_T, 0}, +#define T2_5280_5280 AFTER(T1_5280_5280) + { 5250, 5250, 17, 0, 40, 40, DFS_FCC3, PSCAN_FCC_T, 0}, +#define T1_5250_5250 AFTER(T2_5280_5280) + { 5290, 5290, 20, 0, 40, 40, DFS_FCC3, PSCAN_FCC_T, 0}, +#define T1_5290_5290 AFTER(T1_5250_5250) + { 5250, 5290, 20, 0, 40, 40, DFS_FCC3, PSCAN_FCC_T, 0}, +#define T1_5250_5290 AFTER(T1_5290_5290) + { 5250, 5290, 23, 6, 40, 40, DFS_FCC3, PSCAN_FCC_T, 0}, +#define T2_5250_5290 AFTER(T1_5250_5290) + + { 5540, 5660, 20, 6, 40, 40, DFS_FCC3, PSCAN_FCC_T, 0}, +#define T1_5540_5660 AFTER(T2_5250_5290) + { 5760, 5800, 20, 0, 40, 40, NO_DFS, NO_PSCAN, 0}, +#define T1_5760_5800 AFTER(T1_5540_5660) + { 5760, 5800, 30, 6, 40, 40, NO_DFS, NO_PSCAN, 0}, +#define T2_5760_5800 AFTER(T1_5760_5800) + + { 5765, 5805, 30, 6, 40, 40, NO_DFS, NO_PSCAN, 0}, +#define T1_5765_5805 AFTER(T2_5760_5800) + + /* + * Below are the WWR frequencies + */ + { 5210, 5250, 15, 0, 40, 40, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, 0}, +#define WT1_5210_5250 AFTER(T1_5765_5805) + { 5290, 5290, 18, 0, 40, 40, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, 0}, +#define WT1_5290_5290 AFTER(WT1_5210_5250) + { 5540, 5660, 20, 0, 40, 40, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, 0}, +#define WT1_5540_5660 AFTER(WT1_5290_5290) + { 5760, 5800, 20, 0, 40, 40, NO_DFS, PSCAN_WWR, 0}, +#define WT1_5760_5800 AFTER(WT1_5540_5660) +}; + +/* + * 2GHz 11b channel tags + */ +static REG_DMN_FREQ_BAND regDmn2GhzFreq[] = { + { 2312, 2372, 5, 6, 20, 5, NO_DFS, NO_PSCAN, 0}, +#define F1_2312_2372 0 + { 2312, 2372, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, +#define F2_2312_2372 AFTER(F1_2312_2372) + + { 2412, 2472, 5, 6, 20, 5, NO_DFS, NO_PSCAN, 0}, +#define F1_2412_2472 AFTER(F2_2312_2372) + { 2412, 2472, 20, 0, 20, 5, NO_DFS, PSCAN_MKKA, 0}, +#define F2_2412_2472 AFTER(F1_2412_2472) + { 2412, 2472, 30, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, +#define F3_2412_2472 AFTER(F2_2412_2472) + + { 2412, 2462, 27, 6, 20, 5, NO_DFS, NO_PSCAN, 0}, +#define F1_2412_2462 AFTER(F3_2412_2472) + { 2412, 2462, 20, 0, 20, 5, NO_DFS, PSCAN_MKKA, 0}, +#define F2_2412_2462 AFTER(F1_2412_2462) + + { 2432, 2442, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, +#define F1_2432_2442 AFTER(F2_2412_2462) + + { 2457, 2472, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, +#define F1_2457_2472 AFTER(F1_2432_2442) + + { 2467, 2472, 20, 0, 20, 5, NO_DFS, PSCAN_MKKA2 | PSCAN_MKKA, 0}, +#define F1_2467_2472 AFTER(F1_2457_2472) + + { 2484, 2484, 5, 6, 20, 5, NO_DFS, NO_PSCAN, 0}, +#define F1_2484_2484 AFTER(F1_2467_2472) + { 2484, 2484, 20, 0, 20, 5, NO_DFS, PSCAN_MKKA | PSCAN_MKKA1 | PSCAN_MKKA2, 0}, +#define F2_2484_2484 AFTER(F1_2484_2484) + + { 2512, 2732, 5, 6, 20, 5, NO_DFS, NO_PSCAN, 0}, +#define F1_2512_2732 AFTER(F2_2484_2484) + + /* + * WWR have powers opened up to 20dBm. + * Limits should often come from CTL/Max powers + */ + { 2312, 2372, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, +#define W1_2312_2372 AFTER(F1_2512_2732) + { 2412, 2412, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, +#define W1_2412_2412 AFTER(W1_2312_2372) + { 2417, 2432, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, +#define W1_2417_2432 AFTER(W1_2412_2412) + { 2437, 2442, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, +#define W1_2437_2442 AFTER(W1_2417_2432) + { 2447, 2457, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, +#define W1_2447_2457 AFTER(W1_2437_2442) + { 2462, 2462, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, +#define W1_2462_2462 AFTER(W1_2447_2457) + { 2467, 2467, 20, 0, 20, 5, NO_DFS, PSCAN_WWR | IS_ECM_CHAN, 0}, +#define W1_2467_2467 AFTER(W1_2462_2462) + { 2467, 2467, 20, 0, 20, 5, NO_DFS, NO_PSCAN | IS_ECM_CHAN, 0}, +#define W2_2467_2467 AFTER(W1_2467_2467) + { 2472, 2472, 20, 0, 20, 5, NO_DFS, PSCAN_WWR | IS_ECM_CHAN, 0}, +#define W1_2472_2472 AFTER(W2_2467_2467) + { 2472, 2472, 20, 0, 20, 5, NO_DFS, NO_PSCAN | IS_ECM_CHAN, 0}, +#define W2_2472_2472 AFTER(W1_2472_2472) + { 2484, 2484, 20, 0, 20, 5, NO_DFS, PSCAN_WWR | IS_ECM_CHAN, 0}, +#define W1_2484_2484 AFTER(W2_2472_2472) + { 2484, 2484, 20, 0, 20, 5, NO_DFS, NO_PSCAN | IS_ECM_CHAN, 0}, +#define W2_2484_2484 AFTER(W1_2484_2484) +}; + +/* + * 2GHz 11g channel tags + */ +static REG_DMN_FREQ_BAND regDmn2Ghz11gFreq[] = { + { 2312, 2372, 5, 6, 20, 5, NO_DFS, NO_PSCAN, 0}, +#define G1_2312_2372 0 + { 2312, 2372, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, +#define G2_2312_2372 AFTER(G1_2312_2372) + { 2312, 2372, 5, 6, 10, 5, NO_DFS, NO_PSCAN, 0}, +#define G3_2312_2372 AFTER(G2_2312_2372) + { 2312, 2372, 5, 6, 5, 5, NO_DFS, NO_PSCAN, 0}, +#define G4_2312_2372 AFTER(G3_2312_2372) + + { 2412, 2472, 5, 6, 20, 5, NO_DFS, NO_PSCAN, 0}, +#define G1_2412_2472 AFTER(G4_2312_2372) + { 2412, 2472, 20, 0, 20, 5, NO_DFS, PSCAN_MKKA_G, 0}, +#define G2_2412_2472 AFTER(G1_2412_2472) + { 2412, 2472, 30, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, +#define G3_2412_2472 AFTER(G2_2412_2472) + { 2412, 2472, 5, 6, 10, 5, NO_DFS, NO_PSCAN, 0}, +#define G4_2412_2472 AFTER(G3_2412_2472) + { 2412, 2472, 5, 6, 5, 5, NO_DFS, NO_PSCAN, 0}, +#define G5_2412_2472 AFTER(G4_2412_2472) + + { 2412, 2462, 27, 6, 20, 5, NO_DFS, NO_PSCAN, 0}, +#define G1_2412_2462 AFTER(G5_2412_2472) + { 2412, 2462, 20, 0, 20, 5, NO_DFS, PSCAN_MKKA_G, 0}, +#define G2_2412_2462 AFTER(G1_2412_2462) + { 2412, 2462, 27, 6, 10, 5, NO_DFS, NO_PSCAN, 0}, +#define G3_2412_2462 AFTER(G2_2412_2462) + { 2412, 2462, 27, 6, 5, 5, NO_DFS, NO_PSCAN, 0}, +#define G4_2412_2462 AFTER(G3_2412_2462) + + { 2432, 2442, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, +#define G1_2432_2442 AFTER(G4_2412_2462) + + { 2457, 2472, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, +#define G1_2457_2472 AFTER(G1_2432_2442) + + { 2512, 2732, 5, 6, 20, 5, NO_DFS, NO_PSCAN, 0}, +#define G1_2512_2732 AFTER(G1_2457_2472) + { 2512, 2732, 5, 6, 10, 5, NO_DFS, NO_PSCAN, 0}, +#define G2_2512_2732 AFTER(G1_2512_2732) + { 2512, 2732, 5, 6, 5, 5, NO_DFS, NO_PSCAN, 0}, +#define G3_2512_2732 AFTER(G2_2512_2732) + + { 2467, 2472, 20, 0, 20, 5, NO_DFS, PSCAN_MKKA2 | PSCAN_MKKA, 0 }, +#define G1_2467_2472 AFTER(G3_2512_2732) + + /* + * WWR open up the power to 20dBm + */ + { 2312, 2372, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, +#define WG1_2312_2372 AFTER(G1_2467_2472) + { 2412, 2412, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, +#define WG1_2412_2412 AFTER(WG1_2312_2372) + { 2417, 2432, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, +#define WG1_2417_2432 AFTER(WG1_2412_2412) + { 2437, 2442, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, +#define WG1_2437_2442 AFTER(WG1_2417_2432) + { 2447, 2457, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, +#define WG1_2447_2457 AFTER(WG1_2437_2442) + { 2462, 2462, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, +#define WG1_2462_2462 AFTER(WG1_2447_2457) + { 2467, 2467, 20, 0, 20, 5, NO_DFS, PSCAN_WWR | IS_ECM_CHAN, 0}, +#define WG1_2467_2467 AFTER(WG1_2462_2462) + { 2467, 2467, 20, 0, 20, 5, NO_DFS, NO_PSCAN | IS_ECM_CHAN, 0}, +#define WG2_2467_2467 AFTER(WG1_2467_2467) + { 2472, 2472, 20, 0, 20, 5, NO_DFS, PSCAN_WWR | IS_ECM_CHAN, 0}, +#define WG1_2472_2472 AFTER(WG2_2467_2467) + { 2472, 2472, 20, 0, 20, 5, NO_DFS, NO_PSCAN | IS_ECM_CHAN, 0}, +#define WG2_2472_2472 AFTER(WG1_2472_2472) + + /* + * Mapping for 900MHz cards like Ubiquiti SR9 and XR9 + * and ZComax GZ-901. + */ + { 2422, 2437, 30, 0, 5, 5, NO_DFS, PSCAN_FCC, 0 }, +#define S1_907_922_5 AFTER(WG2_2472_2472) + { 2422, 2437, 30, 0, 10, 5, NO_DFS, PSCAN_FCC, 0 }, +#define S1_907_922_10 AFTER(S1_907_922_5) + { 2427, 2432, 30, 0, 20, 5, NO_DFS, PSCAN_FCC, 0 }, +#define S1_912_917 AFTER(S1_907_922_10) + { 2427, 2442, 30, 0, 5, 5, NO_DFS, PSCAN_FCC, 0 }, +#define S2_907_922_5 AFTER(S1_912_917) + { 2427, 2442, 30, 0, 10, 5, NO_DFS, PSCAN_FCC, 0 }, +#define S2_907_922_10 AFTER(S2_907_922_5) + { 2432, 2437, 30, 0, 20, 5, NO_DFS, PSCAN_FCC, 0 }, +#define S2_912_917 AFTER(S2_907_922_10) + { 2452, 2467, 30, 0, 5, 5, NO_DFS, PSCAN_FCC, 0 }, +#define S1_908_923_5 AFTER(S2_912_917) + { 2457, 2467, 30, 0, 10, 5, NO_DFS, PSCAN_FCC, 0 }, +#define S1_913_918_10 AFTER(S1_908_923_5) + { 2457, 2467, 30, 0, 20, 5, NO_DFS, PSCAN_FCC, 0 }, +#define S1_913_918 AFTER(S1_913_918_10) +}; + +/* + * 2GHz Dynamic turbo tags + */ +static REG_DMN_FREQ_BAND regDmn2Ghz11gTurboFreq[] = { + { 2312, 2372, 5, 6, 40, 40, NO_DFS, NO_PSCAN, 0}, +#define T1_2312_2372 0 + { 2437, 2437, 5, 6, 40, 40, NO_DFS, NO_PSCAN, 0}, +#define T1_2437_2437 AFTER(T1_2312_2372) + { 2437, 2437, 20, 6, 40, 40, NO_DFS, NO_PSCAN, 0}, +#define T2_2437_2437 AFTER(T1_2437_2437) + { 2437, 2437, 18, 6, 40, 40, NO_DFS, PSCAN_WWR, 0}, +#define T3_2437_2437 AFTER(T2_2437_2437) + { 2512, 2732, 5, 6, 40, 40, NO_DFS, NO_PSCAN, 0}, +#define T1_2512_2732 AFTER(T3_2437_2437) +}; + +typedef struct regDomain { + uint16_t regDmnEnum; /* value from EnumRd table */ + uint8_t conformanceTestLimit; + uint32_t flags; /* Requirement flags (AdHoc disallow, + noise floor cal needed, etc) */ + uint64_t dfsMask; /* DFS bitmask for 5Ghz tables */ + uint64_t pscan; /* Bitmask for passive scan */ + chanbmask_t chan11a; /* 11a channels */ + chanbmask_t chan11a_turbo; /* 11a static turbo channels */ + chanbmask_t chan11a_dyn_turbo; /* 11a dynamic turbo channels */ + chanbmask_t chan11a_half; /* 11a 1/2 width channels */ + chanbmask_t chan11a_quarter; /* 11a 1/4 width channels */ + chanbmask_t chan11b; /* 11b channels */ + chanbmask_t chan11g; /* 11g channels */ + chanbmask_t chan11g_turbo; /* 11g dynamic turbo channels */ + chanbmask_t chan11g_half; /* 11g 1/2 width channels */ + chanbmask_t chan11g_quarter; /* 11g 1/4 width channels */ +} REG_DOMAIN; + +static REG_DOMAIN regDomains[] = { + + {.regDmnEnum = DEBUG_REG_DMN, + .conformanceTestLimit = FCC, + .dfsMask = DFS_FCC3, + .chan11a = BM3(F1_5120_5240, F1_5260_5700, F1_5745_5825), + .chan11a_half = BM3(F2_5120_5240, F2_5260_5700, F7_5745_5825), + .chan11a_quarter = BM3(F3_5120_5240, F3_5260_5700, F8_5745_5825), + .chan11a_turbo = BM8(T1_5130_5210, + T1_5250_5330, + T1_5370_5490, + T1_5530_5650, + T1_5150_5190, + T1_5230_5310, + T1_5350_5470, + T1_5510_5670), + .chan11a_dyn_turbo = BM4(T1_5200_5240, + T1_5280_5280, + T1_5540_5660, + T1_5765_5805), + .chan11b = BM4(F1_2312_2372, + F1_2412_2472, + F1_2484_2484, + F1_2512_2732), + .chan11g = BM3(G1_2312_2372, G1_2412_2472, G1_2512_2732), + .chan11g_turbo = BM3(T1_2312_2372, T1_2437_2437, T1_2512_2732), + .chan11g_half = BM3(G2_2312_2372, G4_2412_2472, G2_2512_2732), + .chan11g_quarter = BM3(G3_2312_2372, G5_2412_2472, G3_2512_2732), + }, + + {.regDmnEnum = APL1, + .conformanceTestLimit = FCC, + .chan11a = BM1(F4_5745_5825), + }, + + {.regDmnEnum = APL2, + .conformanceTestLimit = FCC, + .chan11a = BM1(F1_5745_5805), + }, + + {.regDmnEnum = APL3, + .conformanceTestLimit = FCC, + .chan11a = BM2(F1_5280_5320, F2_5745_5805), + }, + + {.regDmnEnum = APL4, + .conformanceTestLimit = FCC, + .chan11a = BM2(F4_5180_5240, F3_5745_5825), + }, + + {.regDmnEnum = APL5, + .conformanceTestLimit = FCC, + .chan11a = BM1(F2_5745_5825), + }, + + {.regDmnEnum = APL6, + .conformanceTestLimit = ETSI, + .dfsMask = DFS_ETSI, + .pscan = PSCAN_FCC_T | PSCAN_FCC, + .chan11a = BM3(F4_5180_5240, F2_5260_5320, F3_5745_5825), + .chan11a_turbo = BM3(T2_5210_5210, T1_5250_5290, T1_5760_5800), + }, + + {.regDmnEnum = APL8, + .conformanceTestLimit = ETSI, + .flags = DISALLOW_ADHOC_11A|DISALLOW_ADHOC_11A_TURB, + .chan11a = BM2(F6_5260_5320, F4_5745_5825), + }, + + {.regDmnEnum = APL9, + .conformanceTestLimit = ETSI, + .dfsMask = DFS_ETSI, + .pscan = PSCAN_ETSI, + .flags = DISALLOW_ADHOC_11A|DISALLOW_ADHOC_11A_TURB, + .chan11a = BM3(F1_5180_5320, F1_5500_5620, F3_5745_5805), + }, + + {.regDmnEnum = ETSI1, + .conformanceTestLimit = ETSI, + .dfsMask = DFS_ETSI, + .pscan = PSCAN_ETSI, + .flags = DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, + .chan11a = BM3(W2_5180_5240, F2_5260_5320, F2_5500_5700), + }, + + {.regDmnEnum = ETSI2, + .conformanceTestLimit = ETSI, + .dfsMask = DFS_ETSI, + .pscan = PSCAN_ETSI, + .flags = DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, + .chan11a = BM1(F3_5180_5240), + }, + + {.regDmnEnum = ETSI3, + .conformanceTestLimit = ETSI, + .dfsMask = DFS_ETSI, + .pscan = PSCAN_ETSI, + .flags = DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, + .chan11a = BM2(W2_5180_5240, F2_5260_5320), + }, + + {.regDmnEnum = ETSI4, + .conformanceTestLimit = ETSI, + .dfsMask = DFS_ETSI, + .pscan = PSCAN_ETSI, + .flags = DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, + .chan11a = BM2(F3_5180_5240, F1_5260_5320), + }, + + {.regDmnEnum = ETSI5, + .conformanceTestLimit = ETSI, + .dfsMask = DFS_ETSI, + .pscan = PSCAN_ETSI, + .flags = DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, + .chan11a = BM1(F1_5180_5240), + }, + + {.regDmnEnum = ETSI6, + .conformanceTestLimit = ETSI, + .dfsMask = DFS_ETSI, + .pscan = PSCAN_ETSI, + .flags = DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, + .chan11a = BM3(F5_5180_5240, F1_5260_5280, F3_5500_5700), + }, + + {.regDmnEnum = FCC1, + .conformanceTestLimit = FCC, + .chan11a = BM3(F2_5180_5240, F4_5260_5320, F5_5745_5825), + .chan11a_turbo = BM3(T1_5210_5210, T2_5250_5290, T2_5760_5800), + .chan11a_dyn_turbo = BM3(T1_5200_5240, T1_5280_5280, T1_5765_5805), + }, + + {.regDmnEnum = FCC2, + .conformanceTestLimit = FCC, + .chan11a = BM3(F6_5180_5240, F5_5260_5320, F6_5745_5825), + .chan11a_dyn_turbo = BM3(T2_5200_5240, T1_5280_5280, T1_5765_5805), + }, + + {.regDmnEnum = FCC3, + .conformanceTestLimit = FCC, + .dfsMask = DFS_FCC3, + .pscan = PSCAN_FCC | PSCAN_FCC_T, + .chan11a = BM4(F2_5180_5240, + F3_5260_5320, + F1_5500_5700, + F5_5745_5825), + .chan11a_turbo = BM4(T1_5210_5210, + T1_5250_5250, + T1_5290_5290, + T2_5760_5800), + .chan11a_dyn_turbo = BM3(T1_5200_5240, T2_5280_5280, T1_5540_5660), + }, + + {.regDmnEnum = FCC4, + .conformanceTestLimit = FCC, + .dfsMask = DFS_FCC3, + .pscan = PSCAN_FCC | PSCAN_FCC_T, + .chan11a = BM1(F1_4950_4980), + .chan11a_half = BM1(F1_4945_4985), + .chan11a_quarter = BM1(F1_4942_4987), + }, + + /* FCC1 w/ 1/2 and 1/4 width channels */ + {.regDmnEnum = FCC5, + .conformanceTestLimit = FCC, + .chan11a = BM3(F2_5180_5240, F4_5260_5320, F5_5745_5825), + .chan11a_turbo = BM3(T1_5210_5210, T2_5250_5290, T2_5760_5800), + .chan11a_dyn_turbo = BM3(T1_5200_5240, T1_5280_5280, T1_5765_5805), + .chan11a_half = BM3(F7_5180_5240, F7_5260_5320, F9_5745_5825), + .chan11a_quarter = BM3(F8_5180_5240, F8_5260_5320,F10_5745_5825), + }, + + {.regDmnEnum = MKK1, + .conformanceTestLimit = MKK, + .pscan = PSCAN_MKK1, + .flags = DISALLOW_ADHOC_11A_TURB, + .chan11a = BM1(F1_5170_5230), + }, + + {.regDmnEnum = MKK2, + .conformanceTestLimit = MKK, + .pscan = PSCAN_MKK2, + .flags = DISALLOW_ADHOC_11A_TURB, + .chan11a = BM3(F1_4920_4980, F1_5040_5080, F1_5170_5230), + .chan11a_half = BM4(F1_4915_4925, + F1_4935_4945, + F1_5035_5040, + F1_5055_5055), + }, + + /* UNI-1 even */ + {.regDmnEnum = MKK3, + .conformanceTestLimit = MKK, + .pscan = PSCAN_MKK3, + .flags = DISALLOW_ADHOC_11A_TURB, + .chan11a = BM1(F4_5180_5240), + }, + + /* UNI-1 even + UNI-2 */ + {.regDmnEnum = MKK4, + .conformanceTestLimit = MKK, + .dfsMask = DFS_MKK4, + .pscan = PSCAN_MKK3, + .flags = DISALLOW_ADHOC_11A_TURB, + .chan11a = BM2(F4_5180_5240, F2_5260_5320), + }, + + /* UNI-1 even + UNI-2 + mid-band */ + {.regDmnEnum = MKK5, + .conformanceTestLimit = MKK, + .dfsMask = DFS_MKK4, + .pscan = PSCAN_MKK3, + .flags = DISALLOW_ADHOC_11A_TURB, + .chan11a = BM3(F4_5180_5240, F2_5260_5320, F4_5500_5700), + }, + + /* UNI-1 odd + even */ + {.regDmnEnum = MKK6, + .conformanceTestLimit = MKK, + .pscan = PSCAN_MKK1, + .flags = DISALLOW_ADHOC_11A_TURB, + .chan11a = BM2(F2_5170_5230, F4_5180_5240), + }, + + /* UNI-1 odd + UNI-1 even + UNI-2 */ + {.regDmnEnum = MKK7, + .conformanceTestLimit = MKK, + .dfsMask = DFS_MKK4, + .pscan = PSCAN_MKK1 | PSCAN_MKK3, + .flags = DISALLOW_ADHOC_11A_TURB, + .chan11a = BM3(F1_5170_5230, F4_5180_5240, F2_5260_5320), + }, + + /* UNI-1 odd + UNI-1 even + UNI-2 + mid-band */ + {.regDmnEnum = MKK8, + .conformanceTestLimit = MKK, + .dfsMask = DFS_MKK4, + .pscan = PSCAN_MKK1 | PSCAN_MKK3, + .flags = DISALLOW_ADHOC_11A_TURB, + .chan11a = BM4(F1_5170_5230, + F4_5180_5240, + F2_5260_5320, + F4_5500_5700), + }, + + /* UNI-1 even + 4.9 GHZ */ + {.regDmnEnum = MKK9, + .conformanceTestLimit = MKK, + .pscan = PSCAN_MKK3, + .flags = DISALLOW_ADHOC_11A_TURB, + .chan11a = BM7(F1_4915_4925, + F1_4935_4945, + F1_4920_4980, + F1_5035_5040, + F1_5055_5055, + F1_5040_5080, + F4_5180_5240), + }, + + /* UNI-1 even + UNI-2 + 4.9 GHZ */ + {.regDmnEnum = MKK10, + .conformanceTestLimit = MKK, + .dfsMask = DFS_MKK4, + .pscan = PSCAN_MKK3, + .flags = DISALLOW_ADHOC_11A_TURB, + .chan11a = BM8(F1_4915_4925, + F1_4935_4945, + F1_4920_4980, + F1_5035_5040, + F1_5055_5055, + F1_5040_5080, + F4_5180_5240, + F2_5260_5320), + }, + + /* Defined here to use when 2G channels are authorised for country K2 */ + {.regDmnEnum = APLD, + .conformanceTestLimit = NO_CTL, + .chan11b = BM2(F2_2312_2372,F2_2412_2472), + .chan11g = BM2(G2_2312_2372,G2_2412_2472), + }, + + {.regDmnEnum = ETSIA, + .conformanceTestLimit = NO_CTL, + .pscan = PSCAN_ETSIA, + .flags = DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, + .chan11b = BM1(F1_2457_2472), + .chan11g = BM1(G1_2457_2472), + .chan11g_turbo = BM1(T2_2437_2437) + }, + + {.regDmnEnum = ETSIB, + .conformanceTestLimit = ETSI, + .pscan = PSCAN_ETSIB, + .flags = DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, + .chan11b = BM1(F1_2432_2442), + .chan11g = BM1(G1_2432_2442), + .chan11g_turbo = BM1(T2_2437_2437) + }, + + {.regDmnEnum = ETSIC, + .conformanceTestLimit = ETSI, + .pscan = PSCAN_ETSIC, + .flags = DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, + .chan11b = BM1(F3_2412_2472), + .chan11g = BM1(G3_2412_2472), + .chan11g_turbo = BM1(T2_2437_2437) + }, + + {.regDmnEnum = FCCA, + .conformanceTestLimit = FCC, + .chan11b = BM1(F1_2412_2462), + .chan11g = BM1(G1_2412_2462), + .chan11g_turbo = BM1(T2_2437_2437), + }, + + /* FCCA w/ 1/2 and 1/4 width channels */ + {.regDmnEnum = FCCB, + .conformanceTestLimit = FCC, + .chan11b = BM1(F1_2412_2462), + .chan11g = BM1(G1_2412_2462), + .chan11g_turbo = BM1(T2_2437_2437), + .chan11g_half = BM1(G3_2412_2462), + .chan11g_quarter = BM1(G4_2412_2462), + }, + + {.regDmnEnum = MKKA, + .conformanceTestLimit = MKK, + .pscan = PSCAN_MKKA | PSCAN_MKKA_G + | PSCAN_MKKA1 | PSCAN_MKKA1_G + | PSCAN_MKKA2 | PSCAN_MKKA2_G, + .flags = DISALLOW_ADHOC_11A_TURB, + .chan11b = BM3(F2_2412_2462, F1_2467_2472, F2_2484_2484), + .chan11g = BM2(G2_2412_2462, G1_2467_2472), + .chan11g_turbo = BM1(T2_2437_2437) + }, + + {.regDmnEnum = MKKC, + .conformanceTestLimit = MKK, + .chan11b = BM1(F2_2412_2472), + .chan11g = BM1(G2_2412_2472), + .chan11g_turbo = BM1(T2_2437_2437) + }, + + {.regDmnEnum = WORLD, + .conformanceTestLimit = ETSI, + .chan11b = BM1(F2_2412_2472), + .chan11g = BM1(G2_2412_2472), + .chan11g_turbo = BM1(T2_2437_2437) + }, + + {.regDmnEnum = WOR0_WORLD, + .conformanceTestLimit = NO_CTL, + .dfsMask = DFS_FCC3 | DFS_ETSI, + .pscan = PSCAN_WWR, + .flags = ADHOC_PER_11D, + .chan11a = BM5(W1_5260_5320, + W1_5180_5240, + W1_5170_5230, + W1_5745_5825, + W1_5500_5700), + .chan11a_turbo = BM3(WT1_5210_5250, + WT1_5290_5290, + WT1_5760_5800), + .chan11b = BM8(W1_2412_2412, + W1_2437_2442, + W1_2462_2462, + W1_2472_2472, + W1_2417_2432, + W1_2447_2457, + W1_2467_2467, + W1_2484_2484), + .chan11g = BM7(WG1_2412_2412, + WG1_2437_2442, + WG1_2462_2462, + WG1_2472_2472, + WG1_2417_2432, + WG1_2447_2457, + WG1_2467_2467), + .chan11g_turbo = BM1(T3_2437_2437) + }, + + {.regDmnEnum = WOR01_WORLD, + .conformanceTestLimit = NO_CTL, + .dfsMask = DFS_FCC3 | DFS_ETSI, + .pscan = PSCAN_WWR, + .flags = ADHOC_PER_11D, + .chan11a = BM5(W1_5260_5320, + W1_5180_5240, + W1_5170_5230, + W1_5745_5825, + W1_5500_5700), + .chan11a_turbo = BM3(WT1_5210_5250, + WT1_5290_5290, + WT1_5760_5800), + .chan11b = BM5(W1_2412_2412, + W1_2437_2442, + W1_2462_2462, + W1_2417_2432, + W1_2447_2457), + .chan11g = BM5(WG1_2412_2412, + WG1_2437_2442, + WG1_2462_2462, + WG1_2417_2432, + WG1_2447_2457), + .chan11g_turbo = BM1(T3_2437_2437)}, + + {.regDmnEnum = WOR02_WORLD, + .conformanceTestLimit = NO_CTL, + .dfsMask = DFS_FCC3 | DFS_ETSI, + .pscan = PSCAN_WWR, + .flags = ADHOC_PER_11D, + .chan11a = BM5(W1_5260_5320, + W1_5180_5240, + W1_5170_5230, + W1_5745_5825, + W1_5500_5700), + .chan11a_turbo = BM3(WT1_5210_5250, + WT1_5290_5290, + WT1_5760_5800), + .chan11b = BM7(W1_2412_2412, + W1_2437_2442, + W1_2462_2462, + W1_2472_2472, + W1_2417_2432, + W1_2447_2457, + W1_2467_2467), + .chan11g = BM7(WG1_2412_2412, + WG1_2437_2442, + WG1_2462_2462, + WG1_2472_2472, + WG1_2417_2432, + WG1_2447_2457, + WG1_2467_2467), + .chan11g_turbo = BM1(T3_2437_2437)}, + + {.regDmnEnum = EU1_WORLD, + .conformanceTestLimit = NO_CTL, + .dfsMask = DFS_FCC3 | DFS_ETSI, + .pscan = PSCAN_WWR, + .flags = ADHOC_PER_11D, + .chan11a = BM5(W1_5260_5320, + W1_5180_5240, + W1_5170_5230, + W1_5745_5825, + W1_5500_5700), + .chan11a_turbo = BM3(WT1_5210_5250, + WT1_5290_5290, + WT1_5760_5800), + .chan11b = BM7(W1_2412_2412, + W1_2437_2442, + W1_2462_2462, + W2_2472_2472, + W1_2417_2432, + W1_2447_2457, + W2_2467_2467), + .chan11g = BM7(WG1_2412_2412, + WG1_2437_2442, + WG1_2462_2462, + WG2_2472_2472, + WG1_2417_2432, + WG1_2447_2457, + WG2_2467_2467), + .chan11g_turbo = BM1(T3_2437_2437)}, + + {.regDmnEnum = WOR1_WORLD, + .conformanceTestLimit = NO_CTL, + .dfsMask = DFS_FCC3 | DFS_ETSI, + .pscan = PSCAN_WWR, + .flags = ADHOC_NO_11A, + .chan11a = BM5(W1_5260_5320, + W1_5180_5240, + W1_5170_5230, + W1_5745_5825, + W1_5500_5700), + .chan11b = BM8(W1_2412_2412, + W1_2437_2442, + W1_2462_2462, + W1_2472_2472, + W1_2417_2432, + W1_2447_2457, + W1_2467_2467, + W1_2484_2484), + .chan11g = BM7(WG1_2412_2412, + WG1_2437_2442, + WG1_2462_2462, + WG1_2472_2472, + WG1_2417_2432, + WG1_2447_2457, + WG1_2467_2467), + .chan11g_turbo = BM1(T3_2437_2437) + }, + + {.regDmnEnum = WOR2_WORLD, + .conformanceTestLimit = NO_CTL, + .dfsMask = DFS_FCC3 | DFS_ETSI, + .pscan = PSCAN_WWR, + .flags = ADHOC_NO_11A, + .chan11a = BM5(W1_5260_5320, + W1_5180_5240, + W1_5170_5230, + W1_5745_5825, + W1_5500_5700), + .chan11a_turbo = BM3(WT1_5210_5250, + WT1_5290_5290, + WT1_5760_5800), + .chan11b = BM8(W1_2412_2412, + W1_2437_2442, + W1_2462_2462, + W1_2472_2472, + W1_2417_2432, + W1_2447_2457, + W1_2467_2467, + W1_2484_2484), + .chan11g = BM7(WG1_2412_2412, + WG1_2437_2442, + WG1_2462_2462, + WG1_2472_2472, + WG1_2417_2432, + WG1_2447_2457, + WG1_2467_2467), + .chan11g_turbo = BM1(T3_2437_2437)}, + + {.regDmnEnum = WOR3_WORLD, + .conformanceTestLimit = NO_CTL, + .dfsMask = DFS_FCC3 | DFS_ETSI, + .pscan = PSCAN_WWR, + .flags = ADHOC_PER_11D, + .chan11a = BM4(W1_5260_5320, + W1_5180_5240, + W1_5170_5230, + W1_5745_5825), + .chan11a_turbo = BM3(WT1_5210_5250, + WT1_5290_5290, + WT1_5760_5800), + .chan11b = BM7(W1_2412_2412, + W1_2437_2442, + W1_2462_2462, + W1_2472_2472, + W1_2417_2432, + W1_2447_2457, + W1_2467_2467), + .chan11g = BM7(WG1_2412_2412, + WG1_2437_2442, + WG1_2462_2462, + WG1_2472_2472, + WG1_2417_2432, + WG1_2447_2457, + WG1_2467_2467), + .chan11g_turbo = BM1(T3_2437_2437)}, + + {.regDmnEnum = WOR4_WORLD, + .conformanceTestLimit = NO_CTL, + .dfsMask = DFS_FCC3 | DFS_ETSI, + .pscan = PSCAN_WWR, + .flags = ADHOC_NO_11A, + .chan11a = BM4(W2_5260_5320, + W2_5180_5240, + F2_5745_5805, + W2_5825_5825), + .chan11a_turbo = BM3(WT1_5210_5250, + WT1_5290_5290, + WT1_5760_5800), + .chan11b = BM5(W1_2412_2412, + W1_2437_2442, + W1_2462_2462, + W1_2417_2432, + W1_2447_2457), + .chan11g = BM5(WG1_2412_2412, + WG1_2437_2442, + WG1_2462_2462, + WG1_2417_2432, + WG1_2447_2457), + .chan11g_turbo = BM1(T3_2437_2437)}, + + {.regDmnEnum = WOR5_ETSIC, + .conformanceTestLimit = NO_CTL, + .dfsMask = DFS_FCC3 | DFS_ETSI, + .pscan = PSCAN_WWR, + .flags = ADHOC_NO_11A, + .chan11a = BM3(W1_5260_5320, W2_5180_5240, F6_5745_5825), + .chan11b = BM7(W1_2412_2412, + W1_2437_2442, + W1_2462_2462, + W2_2472_2472, + W1_2417_2432, + W1_2447_2457, + W2_2467_2467), + .chan11g = BM7(WG1_2412_2412, + WG1_2437_2442, + WG1_2462_2462, + WG2_2472_2472, + WG1_2417_2432, + WG1_2447_2457, + WG2_2467_2467), + .chan11g_turbo = BM1(T3_2437_2437)}, + + {.regDmnEnum = WOR9_WORLD, + .conformanceTestLimit = NO_CTL, + .dfsMask = DFS_FCC3 | DFS_ETSI, + .pscan = PSCAN_WWR, + .flags = ADHOC_NO_11A, + .chan11a = BM4(W1_5260_5320, + W1_5180_5240, + W1_5745_5825, + W1_5500_5700), + .chan11a_turbo = BM3(WT1_5210_5250, + WT1_5290_5290, + WT1_5760_5800), + .chan11b = BM5(W1_2412_2412, + W1_2437_2442, + W1_2462_2462, + W1_2417_2432, + W1_2447_2457), + .chan11g = BM5(WG1_2412_2412, + WG1_2437_2442, + WG1_2462_2462, + WG1_2417_2432, + WG1_2447_2457), + .chan11g_turbo = BM1(T3_2437_2437)}, + + {.regDmnEnum = WORA_WORLD, + .conformanceTestLimit = NO_CTL, + .dfsMask = DFS_FCC3 | DFS_ETSI, + .pscan = PSCAN_WWR, + .flags = ADHOC_NO_11A, + .chan11a = BM4(W1_5260_5320, + W1_5180_5240, + W1_5745_5825, + W1_5500_5700), + .chan11b = BM7(W1_2412_2412, + W1_2437_2442, + W1_2462_2462, + W1_2472_2472, + W1_2417_2432, + W1_2447_2457, + W1_2467_2467), + .chan11g = BM7(WG1_2412_2412, + WG1_2437_2442, + WG1_2462_2462, + WG1_2472_2472, + WG1_2417_2432, + WG1_2447_2457, + WG1_2467_2467), + .chan11g_turbo = BM1(T3_2437_2437)}, + + {.regDmnEnum = SR9_WORLD, + .conformanceTestLimit = NO_CTL, + .pscan = PSCAN_FCC | PSCAN_FCC_T, + .chan11g = BM1(S1_912_917), + .chan11g_half = BM1(S1_907_922_10), + .chan11g_quarter = BM1(S1_907_922_5), + }, + + {.regDmnEnum = XR9_WORLD, + .conformanceTestLimit = NO_CTL, + .pscan = PSCAN_FCC | PSCAN_FCC_T, + .chan11g = BM1(S2_912_917), + .chan11g_half = BM1(S2_907_922_10), + .chan11g_quarter = BM1(S2_907_922_5), + }, + + {.regDmnEnum = GZ901_WORLD, + .conformanceTestLimit = NO_CTL, + .pscan = PSCAN_FCC | PSCAN_FCC_T, + .chan11g = BM1(S1_913_918), + .chan11g_half = BM1(S1_913_918_10), + .chan11g_quarter = BM1(S1_908_923_5), + }, + + {.regDmnEnum = NULL1, + .conformanceTestLimit = NO_CTL, + } +}; + +struct cmode { + u_int mode; + u_int flags; +}; + +static const struct cmode modes[] = { + { HAL_MODE_TURBO, CHANNEL_ST}, /* NB: 11a Static Turbo */ + { HAL_MODE_11A, CHANNEL_A}, + { HAL_MODE_11B, CHANNEL_B}, + { HAL_MODE_11G, CHANNEL_G}, + { HAL_MODE_11G_TURBO, CHANNEL_108G}, + { HAL_MODE_11A_TURBO, CHANNEL_108A}, + { HAL_MODE_11A_QUARTER_RATE, CHANNEL_A | CHANNEL_QUARTER}, + { HAL_MODE_11A_HALF_RATE, CHANNEL_A | CHANNEL_HALF}, + { HAL_MODE_11G_QUARTER_RATE, CHANNEL_G | CHANNEL_QUARTER}, + { HAL_MODE_11G_HALF_RATE, CHANNEL_G | CHANNEL_HALF}, + { HAL_MODE_11NG_HT20, CHANNEL_G_HT20}, + { HAL_MODE_11NG_HT40PLUS, CHANNEL_G_HT40PLUS}, + { HAL_MODE_11NG_HT40MINUS, CHANNEL_G_HT40MINUS}, + { HAL_MODE_11NA_HT20, CHANNEL_A_HT20}, + { HAL_MODE_11NA_HT40PLUS, CHANNEL_A_HT40PLUS}, + { HAL_MODE_11NA_HT40MINUS, CHANNEL_A_HT40MINUS}, +}; + +static int +chansort(const void *a, const void *b) +{ +#define CHAN_FLAGS (CHANNEL_ALL|CHANNEL_HALF|CHANNEL_QUARTER) + const HAL_CHANNEL_INTERNAL *ca = a; + const HAL_CHANNEL_INTERNAL *cb = b; + + return (ca->channel == cb->channel) ? + (ca->channelFlags & CHAN_FLAGS) - + (cb->channelFlags & CHAN_FLAGS) : + ca->channel - cb->channel; +#undef CHAN_FLAGS +} +typedef int ath_hal_cmp_t(const void *, const void *); +static void ath_hal_sort(void *a, size_t n, size_t es, ath_hal_cmp_t *cmp); +static COUNTRY_CODE_TO_ENUM_RD* findCountry(HAL_CTRY_CODE countryCode); +static HAL_BOOL getWmRD(struct ath_hal *ah, COUNTRY_CODE_TO_ENUM_RD *country, uint16_t channelFlag, REG_DOMAIN *rd); + + +static uint16_t +getEepromRD(struct ath_hal *ah) +{ + return AH_PRIVATE(ah)->ah_currentRD &~ WORLDWIDE_ROAMING_FLAG; +} + +/* + * Test to see if the bitmask array is all zeros + */ +static HAL_BOOL +isChanBitMaskZero(const uint64_t *bitmask) +{ +#if BMLEN > 2 +#error "add more cases" +#endif +#if BMLEN > 1 + if (bitmask[1] != 0) + return AH_FALSE; +#endif + return (bitmask[0] == 0); +} + +/* + * Return whether or not the regulatory domain/country in EEPROM + * is acceptable. + */ +static HAL_BOOL +isEepromValid(struct ath_hal *ah) +{ + uint16_t rd = getEepromRD(ah); + int i; + + if (rd & COUNTRY_ERD_FLAG) { + uint16_t cc = rd &~ COUNTRY_ERD_FLAG; + for (i = 0; i < N(allCountries); i++) + if (allCountries[i].countryCode == cc) + return AH_TRUE; + } else { + for (i = 0; i < N(regDomainPairs); i++) + if (regDomainPairs[i].regDmnEnum == rd) + return AH_TRUE; + } + HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, + "%s: invalid regulatory domain/country code 0x%x\n", __func__, rd); + return AH_FALSE; +} + +/* + * Returns whether or not the specified country code + * is allowed by the EEPROM setting + */ +static HAL_BOOL +isCountryCodeValid(struct ath_hal *ah, HAL_CTRY_CODE cc) +{ + uint16_t rd; + + /* Default setting requires no checks */ + if (cc == CTRY_DEFAULT) + return AH_TRUE; +#ifdef AH_DEBUG_COUNTRY + if (cc == CTRY_DEBUG) + return AH_TRUE; +#endif + rd = getEepromRD(ah); + HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, "%s: EEPROM regdomain 0x%x\n", + __func__, rd); + + if (rd & COUNTRY_ERD_FLAG) { + /* EEP setting is a country - config shall match */ + HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, + "%s: EEPROM setting is country code %u\n", __func__, + rd &~ COUNTRY_ERD_FLAG); + return (cc == (rd & ~COUNTRY_ERD_FLAG)); + } else if (rd == DEBUG_REG_DMN || rd == NO_ENUMRD) { + /* Set to Debug or AllowAnyCountry mode - allow any setting */ + HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, "%s: rd %d allowed\n", + __func__, rd); + return AH_TRUE; +#ifdef AH_SUPPORT_11D + } else if ((rd & WORLD_SKU_MASK) == WORLD_SKU_PREFIX) { + int i; + for (i=0; i < N(allCountries); i++) { + if (cc == allCountries[i].countryCode) + return AH_TRUE; + } +#endif + } else { + int i; + for (i = 0; i < N(allCountries); i++) { + if (cc == allCountries[i].countryCode && + allCountries[i].regDmnEnum == rd) + return AH_TRUE; + } + } + return AH_FALSE; +} + +/* + * Return the mask of available modes based on the hardware + * capabilities and the specified country code and reg domain. + */ +static u_int +ath_hal_getwmodesnreg(struct ath_hal *ah, + const COUNTRY_CODE_TO_ENUM_RD *country, const REG_DOMAIN *rd5GHz) +{ +#define HAL_MODE_11G_ALL \ + (HAL_MODE_11G | HAL_MODE_11G_TURBO | HAL_MODE_11G_QUARTER_RATE | \ + HAL_MODE_11G_HALF_RATE) +#define HAL_MODE_11A_ALL \ + (HAL_MODE_11A | HAL_MODE_11A_TURBO | HAL_MODE_TURBO | \ + HAL_MODE_11A_QUARTER_RATE | HAL_MODE_11A_HALF_RATE) + u_int modesAvail; + + /* Get modes that HW is capable of */ + modesAvail = ath_hal_getWirelessModes(ah); + + HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, + "%s: wireless modes 0x%x cc %u rd %u\n", + __func__, modesAvail, country->countryCode, country->regDmnEnum); + + /* Check country regulations for allowed modes */ + if (!country->allow11g && (modesAvail & HAL_MODE_11G_ALL)) { + HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, + "%s: disallow all 11g\n", __func__); + modesAvail &= ~HAL_MODE_11G_ALL; + } + if (isChanBitMaskZero(rd5GHz->chan11a) && + (modesAvail & HAL_MODE_11A_ALL)) { + HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, + "%s: disallow all 11a\n", __func__); + modesAvail &= ~HAL_MODE_11A_ALL; + } + if ((modesAvail & (HAL_MODE_11A_TURBO | HAL_MODE_TURBO)) && + !country->allow11aTurbo) { + HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, + "%s: disallow 11aTurbo\n", __func__); + modesAvail &= ~(HAL_MODE_11A_TURBO | HAL_MODE_TURBO); + } + if ((modesAvail & HAL_MODE_11G_TURBO) && !country->allow11gTurbo) { + HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, + "%s: disallow 11gTurbo\n", __func__); + modesAvail &= ~HAL_MODE_11G_TURBO; + } + + /* Check 11n operation */ + if ((modesAvail & HAL_MODE_11NG_HT20) && !country->allow11ng20) { + HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, + "%s: disallow 11g HT20\n", __func__); + modesAvail &= ~HAL_MODE_11NG_HT20; + } + if ((modesAvail & HAL_MODE_11NA_HT20) && !country->allow11na20) { + HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, + "%s: disallow 11a HT20\n", __func__); + modesAvail &= ~HAL_MODE_11NA_HT20; + } + if ((modesAvail & HAL_MODE_11NG_HT40PLUS) && !country->allow11ng40) { + HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, + "%s: disallow 11g HT40+\n", __func__); + modesAvail &= ~HAL_MODE_11NG_HT40PLUS; + } + if ((modesAvail & HAL_MODE_11NG_HT40MINUS) && !country->allow11ng40) { + HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, + "%s: disallow 11g HT40-\n", __func__); + modesAvail &= ~HAL_MODE_11NG_HT40MINUS; + } + if ((modesAvail & HAL_MODE_11NA_HT40PLUS) && !country->allow11na40) { + HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, + "%s: disallow 11a HT40+\n", __func__); + modesAvail &= ~HAL_MODE_11NA_HT40PLUS; + } + if ((modesAvail & HAL_MODE_11NA_HT40MINUS) && !country->allow11na40) { + HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, + "%s: disallow 11a HT40-\n", __func__); + modesAvail &= ~HAL_MODE_11NA_HT40MINUS; + } + + return modesAvail; +#undef HAL_MODE_11A_ALL +#undef HAL_MODE_11G_ALL +} + +/* + * Return the mask of available modes based on the hardware + * capabilities and the specified country code. + */ + +u_int +ath_hal_getwirelessmodes(struct ath_hal *ah, HAL_CTRY_CODE cc) +{ + COUNTRY_CODE_TO_ENUM_RD *country = AH_NULL; + u_int mode = 0; + REG_DOMAIN rd; + + country = findCountry(cc); + if (country != AH_NULL) { + if (getWmRD(ah, country, ~CHANNEL_2GHZ, &rd)) + mode = ath_hal_getwmodesnreg(ah, country, &rd); + } + return mode; +} + +/* + * Return if device is public safety. + */ +HAL_BOOL +ath_hal_ispublicsafetysku(struct ath_hal *ah) +{ + uint16_t rd = getEepromRD(ah); + + switch (rd) { + case FCC4_FCCA: + case CTRY_UNITED_STATES_FCC49 | COUNTRY_ERD_FLAG: + return AH_TRUE; + case DEBUG_REG_DMN: + case NO_ENUMRD: + if (AH_PRIVATE(ah)->ah_countryCode == CTRY_UNITED_STATES_FCC49) + return AH_TRUE; + break; + } + return AH_FALSE; +} + +/* + * Return if device is actually operating in 900 MHz band. + */ +HAL_BOOL +ath_hal_isgsmsku(struct ath_hal *ah) +{ + uint16_t rd = getEepromRD(ah); + + switch (rd) { + case SR9_WORLD: + case XR9_WORLD: + case GZ901_WORLD: + case CTRY_SR9 | COUNTRY_ERD_FLAG: + case CTRY_XR9 | COUNTRY_ERD_FLAG: + case CTRY_GZ901 | COUNTRY_ERD_FLAG: + return AH_TRUE; + case DEBUG_REG_DMN: + case NO_ENUMRD: + return AH_PRIVATE(ah)->ah_countryCode == CTRY_SR9 + || AH_PRIVATE(ah)->ah_countryCode == CTRY_XR9 + || AH_PRIVATE(ah)->ah_countryCode == CTRY_GZ901 + ; + } + return AH_FALSE; +} + +/* + * Find the pointer to the country element in the country table + * corresponding to the country code + */ +static COUNTRY_CODE_TO_ENUM_RD* +findCountry(HAL_CTRY_CODE countryCode) +{ + int i; + + for (i = 0; i < N(allCountries); i++) { + if (allCountries[i].countryCode == countryCode) + return &allCountries[i]; + } + return AH_NULL; /* Not found */ +} + +/* + * Calculate a default country based on the EEPROM setting. + */ +static HAL_CTRY_CODE +getDefaultCountry(struct ath_hal *ah) +{ + uint16_t rd; + int i; + + rd = getEepromRD(ah); + if (rd & COUNTRY_ERD_FLAG) { + COUNTRY_CODE_TO_ENUM_RD *country = AH_NULL; + uint16_t cc = rd & ~COUNTRY_ERD_FLAG; + + country = findCountry(cc); + if (country != AH_NULL) + return cc; + } + /* + * Check reg domains that have only one country + */ + for (i = 0; i < N(regDomainPairs); i++) + if (regDomainPairs[i].regDmnEnum == rd) { + if (regDomainPairs[i].singleCC != 0) + return regDomainPairs[i].singleCC; + else + i = N(regDomainPairs); + } + return CTRY_DEFAULT; +} + +static HAL_BOOL +isValidRegDmn(int regDmn, REG_DOMAIN *rd) +{ + int i; + + for (i = 0; i < N(regDomains); i++) { + if (regDomains[i].regDmnEnum == regDmn) { + if (rd != AH_NULL) { + OS_MEMCPY(rd, ®Domains[i], + sizeof(REG_DOMAIN)); + } + return AH_TRUE; + } + } + return AH_FALSE; +} + +static HAL_BOOL +isValidRegDmnPair(int regDmnPair) +{ + int i; + + if (regDmnPair == NO_ENUMRD) + return AH_FALSE; + for (i = 0; i < N(regDomainPairs); i++) { + if (regDomainPairs[i].regDmnEnum == regDmnPair) + return AH_TRUE; + } + return AH_FALSE; +} + +/* + * Return the Wireless Mode Regulatory Domain based + * on the country code and the wireless mode. + */ +static HAL_BOOL +getWmRD(struct ath_hal *ah, COUNTRY_CODE_TO_ENUM_RD *country, + uint16_t channelFlag, REG_DOMAIN *rd) +{ + int regDmn; + REG_DMN_PAIR_MAPPING *regPair; + uint64_t flags; + + if (country->countryCode == CTRY_DEFAULT) { + uint16_t rdnum = getEepromRD(ah); + + if ((rdnum & COUNTRY_ERD_FLAG) == 0) { + if (isValidRegDmn(rdnum, AH_NULL) || + isValidRegDmnPair(rdnum)) + regDmn = rdnum; + else + regDmn = country->regDmnEnum; + } else + regDmn = country->regDmnEnum; + } else + regDmn = country->regDmnEnum; + regPair = AH_NULL; + flags = NO_REQ; + if ((regDmn & MULTI_DOMAIN_MASK) == 0) { + int i; + + for (i = 0; i < N(regDomainPairs); i++) { + if (regDomainPairs[i].regDmnEnum == regDmn) { + regPair = ®DomainPairs[i]; + break; + } + } + if (regPair == AH_NULL) { + HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, + "%s: Failed to find reg domain pair %u\n", + __func__, regDmn); + return AH_FALSE; + } + if (channelFlag & CHANNEL_2GHZ) { + regDmn = regPair->regDmn2GHz; + flags = regPair->flags2GHz; + } else { + regDmn = regPair->regDmn5GHz; + flags = regPair->flags5GHz; + } + } + + /* + * We either started with a unitary reg domain or we've found the + * unitary reg domain of the pair + */ + if (isValidRegDmn(regDmn, rd)) { + if (regPair != AH_NULL) + rd->pscan &= regPair->pscanMask; + if ((country->regDmnEnum & MULTI_DOMAIN_MASK) == 0 && + flags != NO_REQ) + rd->flags = flags; + return AH_TRUE; + } else { + HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, + "%s: Failed to find unitary reg domain %u\n", __func__, + country->regDmnEnum); + return AH_FALSE; + } +} + +static HAL_BOOL +IS_BIT_SET(int bit, const uint64_t bitmask[]) +{ + int byteOffset, bitnum; + uint64_t val; + + byteOffset = bit/64; + bitnum = bit - byteOffset*64; + val = ((uint64_t) 1) << bitnum; + return (bitmask[byteOffset] & val) != 0; +} + +/* Add given regclassid into regclassids array upto max of maxregids */ +static void +ath_add_regclassid(uint8_t *regclassids, u_int maxregids, + u_int *nregids, uint8_t regclassid) +{ + int i; + + /* Is regclassid valid? */ + if (regclassid == 0) + return; + + for (i = 0; i < maxregids; i++) { + if (regclassids[i] == regclassid) /* already present */ + return; + if (regclassids[i] == 0) { /* free slot */ + regclassids[i] = regclassid; + (*nregids)++; + return; + } + } +} + +/* + * Setup the channel list based on the information in the EEPROM and + * any supplied country code. Note that we also do a bunch of EEPROM + * verification here and setup certain regulatory-related access + * control data used later on. + */ + +HAL_BOOL +ath_hal_init_channels(struct ath_hal *ah, + HAL_CHANNEL *chans, u_int maxchans, u_int *nchans, + uint8_t *regclassids, u_int maxregids, u_int *nregids, + HAL_CTRY_CODE cc, u_int modeSelect, + HAL_BOOL enableOutdoor, HAL_BOOL enableExtendedChannels) +{ +#define CHANNEL_HALF_BW 10 +#define CHANNEL_QUARTER_BW 5 + u_int modesAvail; + uint16_t maxChan; + COUNTRY_CODE_TO_ENUM_RD *country = AH_NULL; + REG_DOMAIN rd5GHz, rd2GHz; + const struct cmode *cm; + HAL_CHANNEL_INTERNAL *ichans = &AH_PRIVATE(ah)->ah_channels[0]; + int next, b; + uint8_t ctl; + + HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, "%s: cc %u mode 0x%x%s%s\n", + __func__, cc, modeSelect, enableOutdoor? " Enable outdoor" : " ", + enableExtendedChannels ? " Enable ecm" : ""); + + /* + * Validate the EEPROM setting and setup defaults + */ + if (!isEepromValid(ah)) { + /* + * Don't return any channels if the EEPROM has an + * invalid regulatory domain/country code setting. + */ + HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, + "%s: invalid EEPROM contents\n",__func__); + return AH_FALSE; + } + + AH_PRIVATE(ah)->ah_countryCode = getDefaultCountry(ah); + +#ifndef AH_SUPPORT_11D + if (AH_PRIVATE(ah)->ah_countryCode == CTRY_DEFAULT) { +#endif + /* + * We now have enough state to validate any country code + * passed in by the caller. + */ + if (!isCountryCodeValid(ah, cc)) { + /* NB: Atheros silently ignores invalid country codes */ + HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, + "%s: invalid country code %d\n", __func__, cc); + return AH_FALSE; + } + AH_PRIVATE(ah)->ah_countryCode = cc & COUNTRY_CODE_MASK; +#ifndef AH_SUPPORT_11D + } +#endif + + /* Get pointers to the country element and the reg domain elements */ + country = findCountry(AH_PRIVATE(ah)->ah_countryCode); + + if (country == AH_NULL) { + HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, "NULL Country!, cc= %d\n", + AH_PRIVATE(ah)->ah_countryCode); + return AH_FALSE; + } + + if (!getWmRD(ah, country, ~CHANNEL_2GHZ, &rd5GHz)) { + HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, + "%s: no unitary 5GHz regdomain for country %u\n", + __func__, AH_PRIVATE(ah)->ah_countryCode); + return AH_FALSE; + } + if (!getWmRD(ah, country, CHANNEL_2GHZ, &rd2GHz)) { + HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, + "%s: no unitary 2GHz regdomain for country %u\n", + __func__, AH_PRIVATE(ah)->ah_countryCode); + return AH_FALSE; + } + + modesAvail = ath_hal_getwmodesnreg(ah, country, &rd5GHz); + maxChan = !enableOutdoor ? country->outdoorChanStart : 7000; + + if (maxchans > N(AH_PRIVATE(ah)->ah_channels)) + maxchans = N(AH_PRIVATE(ah)->ah_channels); + next = 0; + for (cm = modes; cm < &modes[N(modes)]; cm++) { + uint16_t c, c_hi, c_lo; + uint64_t *channelBM = AH_NULL; + REG_DOMAIN *rd = AH_NULL; + REG_DMN_FREQ_BAND *fband = AH_NULL,*freqs; + int low_adj, hi_adj, channelSep, lastc; + + if ((cm->mode & modeSelect) == 0) { + HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, + "%s: skip mode 0x%x flags 0x%x\n", + __func__, cm->mode, cm->flags); + continue; + } + if ((cm->mode & modesAvail) == 0) { + HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, + "%s: !avail mode 0x%x (0x%x) flags 0x%x\n", + __func__, modesAvail, cm->mode, cm->flags); + continue; + } + if (!ath_hal_getChannelEdges(ah, cm->flags, &c_lo, &c_hi)) { + /* channel not supported by hardware, skip it */ + HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, + "%s: channels 0x%x not supported by hardware\n", + __func__,cm->flags); + continue; + } + switch (cm->mode) { + case HAL_MODE_TURBO: + rd = &rd5GHz; + channelBM = rd->chan11a_turbo; + freqs = ®Dmn5GhzTurboFreq[0]; + ctl = rd->conformanceTestLimit | CTL_TURBO; + break; + case HAL_MODE_11A: + case HAL_MODE_11A_HALF_RATE: + case HAL_MODE_11A_QUARTER_RATE: + case HAL_MODE_11NA_HT20: + case HAL_MODE_11NA_HT40PLUS: + case HAL_MODE_11NA_HT40MINUS: + rd = &rd5GHz; + if (cm->mode == HAL_MODE_11A_HALF_RATE) + channelBM = rd->chan11a_half; + else if (cm->mode == HAL_MODE_11A_QUARTER_RATE) + channelBM = rd->chan11a_quarter; + else + channelBM = rd->chan11a; + freqs = ®Dmn5GhzFreq[0]; + ctl = rd->conformanceTestLimit; + break; + case HAL_MODE_11B: + rd = &rd2GHz; + channelBM = rd->chan11b; + freqs = ®Dmn2GhzFreq[0]; + ctl = rd->conformanceTestLimit | CTL_11B; + break; + case HAL_MODE_11G: + case HAL_MODE_11G_HALF_RATE: + case HAL_MODE_11G_QUARTER_RATE: + case HAL_MODE_11NG_HT20: + case HAL_MODE_11NG_HT40PLUS: + case HAL_MODE_11NG_HT40MINUS: + rd = &rd2GHz; + if (cm->mode == HAL_MODE_11G_HALF_RATE) + channelBM = rd->chan11g_half; + else if (cm->mode == HAL_MODE_11G_QUARTER_RATE) + channelBM = rd->chan11g_quarter; + else + channelBM = rd->chan11g; + freqs = ®Dmn2Ghz11gFreq[0]; + ctl = rd->conformanceTestLimit | CTL_11G; + break; + case HAL_MODE_11G_TURBO: + rd = &rd2GHz; + channelBM = rd->chan11g_turbo; + freqs = ®Dmn2Ghz11gTurboFreq[0]; + ctl = rd->conformanceTestLimit | CTL_108G; + break; + case HAL_MODE_11A_TURBO: + rd = &rd5GHz; + channelBM = rd->chan11a_dyn_turbo; + freqs = ®Dmn5GhzTurboFreq[0]; + ctl = rd->conformanceTestLimit | CTL_108G; + break; + default: + HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, + "%s: Unkonwn HAL mode 0x%x\n", __func__, cm->mode); + continue; + } + if (isChanBitMaskZero(channelBM)) + continue; + /* + * Setup special handling for HT40 channels; e.g. + * 5G HT40 channels require 40Mhz channel separation. + */ + hi_adj = (cm->mode == HAL_MODE_11NA_HT40PLUS || + cm->mode == HAL_MODE_11NG_HT40PLUS) ? -20 : 0; + low_adj = (cm->mode == HAL_MODE_11NA_HT40MINUS || + cm->mode == HAL_MODE_11NG_HT40MINUS) ? 20 : 0; + channelSep = (cm->mode == HAL_MODE_11NA_HT40PLUS || + cm->mode == HAL_MODE_11NA_HT40MINUS) ? 40 : 0; + + for (b = 0; b < 64*BMLEN; b++) { + if (!IS_BIT_SET(b, channelBM)) + continue; + fband = &freqs[b]; + lastc = 0; + + ath_add_regclassid(regclassids, maxregids, + nregids, fband->regClassId); + + for (c = fband->lowChannel + low_adj; + c <= fband->highChannel + hi_adj; + c += fband->channelSep) { + HAL_CHANNEL_INTERNAL icv; + + if (!(c_lo <= c && c <= c_hi)) { + HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, + "%s: c %u out of range [%u..%u]\n", + __func__, c, c_lo, c_hi); + continue; + } + if (((c+fband->channelSep)/2) > (maxChan+HALF_MAXCHANBW)) { + HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, + "%s: c %u > maxChan %u\n", + __func__, c, maxChan); + continue; + } + if (next >= maxchans){ + HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, + "%s: too many channels for channel table\n", + __func__); + goto done; + } + if ((fband->usePassScan & IS_ECM_CHAN) && + !enableExtendedChannels) { + HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, + "Skipping ecm channel\n"); + continue; + } + /* XXX needs to be in ath_hal_checkchannel */ + if ((rd->flags & NO_HOSTAP) && + (AH_PRIVATE(ah)->ah_opmode == HAL_M_HOSTAP)) { + HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, + "Skipping HOSTAP channel\n"); + continue; + } + /* + * Make sure that channel separation + * meets the requirement. + */ + if (lastc && channelSep && + (c-lastc) < channelSep) + continue; + + OS_MEMZERO(&icv, sizeof(icv)); + icv.channel = c; + icv.channelFlags = cm->flags; + icv.maxRegTxPower = fband->powerDfs; + icv.antennaMax = fband->antennaMax; + icv.regDmnFlags = rd->flags; + icv.conformanceTestLimit = ctl; + if (fband->usePassScan & rd->pscan) + icv.channelFlags |= CHANNEL_PASSIVE; + else + icv.channelFlags &= ~CHANNEL_PASSIVE; + lastc = c; + if (fband->useDfs & rd->dfsMask) { + /* DFS and HT40 don't mix */ + if (cm->mode == HAL_MODE_11NA_HT40PLUS || + cm->mode == HAL_MODE_11NA_HT40MINUS) + continue; + icv.privFlags = CHANNEL_DFS; + } else + icv.privFlags = 0; + if (rd->flags & LIMIT_FRAME_4MS) + icv.privFlags |= CHANNEL_4MS_LIMIT; + + ichans[next++] = icv; + } + } + } +done: + if (next != 0) { + int i; + + /* XXX maxchans set above so this cannot happen? */ + if (next > N(AH_PRIVATE(ah)->ah_channels)) { + HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, + "%s: too many channels %u; truncating to %u\n", + __func__, next, + (int) N(AH_PRIVATE(ah)->ah_channels)); + next = N(AH_PRIVATE(ah)->ah_channels); + } + + /* + * Keep a private copy of the channel list so we can + * constrain future requests to only these channels + */ + ath_hal_sort(ichans, next, sizeof(HAL_CHANNEL_INTERNAL), + chansort); + AH_PRIVATE(ah)->ah_nchan = next; + + /* + * Copy the channel list to the public channel list + */ + for (i = 0; i < next; i++) { + chans[i].channel = ichans[i].channel; + chans[i].channelFlags = ichans[i].channelFlags; + chans[i].privFlags = ichans[i].privFlags; + chans[i].maxRegTxPower = ichans[i].maxRegTxPower; + } + /* + * Retrieve power limits. + */ + ath_hal_getpowerlimits(ah, chans, next); + for (i = 0; i < next; i++) { + ichans[i].maxTxPower = chans[i].maxTxPower; + ichans[i].minTxPower = chans[i].minTxPower; + } + } + *nchans = next; + /* XXX copy private setting to public area */ + ah->ah_countryCode = AH_PRIVATE(ah)->ah_countryCode; + return (next != 0); +#undef CHANNEL_HALF_BW +#undef CHANNEL_QUARTER_BW +} + +/* + * Return whether or not the specified channel is ok to use + * based on the current regulatory domain constraints and + * DFS interference. + */ +HAL_CHANNEL_INTERNAL * +ath_hal_checkchannel(struct ath_hal *ah, const HAL_CHANNEL *c) +{ +#define CHAN_FLAGS (CHANNEL_ALL|CHANNEL_HALF|CHANNEL_QUARTER) + HAL_CHANNEL_INTERNAL *base, *cc; + /* NB: be wary of user-specified channel flags */ + int flags = c->channelFlags & CHAN_FLAGS; + int n, lim, d; + + /* + * Check current channel to avoid the lookup. + */ + cc = AH_PRIVATE(ah)->ah_curchan; + if (cc != AH_NULL && cc->channel == c->channel && + (cc->channelFlags & CHAN_FLAGS) == flags) { + if ((cc->privFlags & CHANNEL_INTERFERENCE) && + (cc->channelFlags & CHANNEL_DFS)) + return AH_NULL; + else + return cc; + } + + /* binary search based on known sorting order */ + base = AH_PRIVATE(ah)->ah_channels; + n = AH_PRIVATE(ah)->ah_nchan; + /* binary search based on known sorting order */ + for (lim = n; lim != 0; lim >>= 1) { + cc = &base[lim>>1]; + d = c->channel - cc->channel; + if (d == 0) { + if ((cc->channelFlags & CHAN_FLAGS) == flags) { + if ((cc->privFlags & CHANNEL_INTERFERENCE) && + (cc->channelFlags & CHANNEL_DFS)) + return AH_NULL; + else + return cc; + } + d = flags - (cc->channelFlags & CHAN_FLAGS); + } + if (d > 0) { + base = cc + 1; + lim--; + } + } + HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, "%s: no match for %u/0x%x\n", + __func__, c->channel, c->channelFlags); + return AH_NULL; +#undef CHAN_FLAGS +} + +/* + * Return the max allowed antenna gain and apply any regulatory + * domain specific changes. + * + * NOTE: a negative reduction is possible in RD's that only + * measure radiated power (e.g., ETSI) which would increase + * that actual conducted output power (though never beyond + * the calibrated target power). + */ +u_int +ath_hal_getantennareduction(struct ath_hal *ah, HAL_CHANNEL *chan, u_int twiceGain) +{ + HAL_CHANNEL_INTERNAL *ichan=AH_NULL; + int8_t antennaMax; + + if ((ichan = ath_hal_checkchannel(ah, chan)) != AH_NULL) { + antennaMax = twiceGain - ichan->antennaMax*2; + return (antennaMax < 0) ? 0 : antennaMax; + } else { + /* Failed to find the correct index - may be a debug channel */ + return 0; + } +} + + +/* XXX - maybe move ctl decision into channel set area or + into the tables so no decision is needed in the code */ + +#define isWwrSKU(_ah) \ + ((getEepromRD((_ah)) & WORLD_SKU_MASK) == WORLD_SKU_PREFIX || \ + getEepromRD(_ah) == WORLD) + + +/* + * Return the test group from the specified channel from + * the regulatory table. + * + * TODO: CTL for 11B CommonMode when regulatory domain is unknown + */ +u_int +ath_hal_getctl(struct ath_hal *ah, HAL_CHANNEL *chan) +{ + u_int ctl = NO_CTL; + HAL_CHANNEL_INTERNAL *ichan; + + /* Special CTL to signify WWR SKU without a known country */ + if (AH_PRIVATE(ah)->ah_countryCode == CTRY_DEFAULT && isWwrSKU(ah)) { + if (IS_CHAN_B(chan)) { + ctl = SD_NO_CTL | CTL_11B; + } else if (IS_CHAN_G(chan)) { + ctl = SD_NO_CTL | CTL_11G; + } else if (IS_CHAN_108G(chan)) { + ctl = SD_NO_CTL | CTL_108G; + } else if (IS_CHAN_T(chan)) { + ctl = SD_NO_CTL | CTL_TURBO; + } else { + ctl = SD_NO_CTL | CTL_11A; + } + } else { + if ((ichan = ath_hal_checkchannel(ah, chan)) != AH_NULL) { + ctl = ichan->conformanceTestLimit; + /* limit 11G OFDM power */ + if (IS_CHAN_PUREG(chan) && + (ctl & CTL_MODE_M) == CTL_11B) + ctl = (ctl &~ CTL_MODE_M) | CTL_11G; + } + } + return ctl; +} + +/* + * Return whether or not a noise floor check is required in + * the current regulatory domain for the specified channel. + */ +HAL_BOOL +ath_hal_getnfcheckrequired(struct ath_hal *ah, HAL_CHANNEL *chan) +{ + HAL_CHANNEL_INTERNAL *ichan; + + if ((ichan = ath_hal_checkchannel(ah, chan)) != AH_NULL) + return ((ichan->regDmnFlags & NEED_NFC) ? AH_TRUE : AH_FALSE); + return AH_FALSE; +} + +/* + * Insertion sort. + */ +#define swap(_a, _b, _size) { \ + uint8_t *s = _b; \ + int i = _size; \ + do { \ + uint8_t tmp = *_a; \ + *_a++ = *s; \ + *s++ = tmp; \ + } while (--i); \ + _a -= _size; \ +} + +static void +ath_hal_sort(void *a, size_t n, size_t size, ath_hal_cmp_t *cmp) +{ + uint8_t *aa = a; + uint8_t *ai, *t; + + for (ai = aa+size; --n >= 1; ai += size) + for (t = ai; t > aa; t -= size) { + uint8_t *u = t - size; + if (cmp(u, t) <= 0) + break; + swap(u, t, size); + } +} --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ah_soc.h 2009-03-23 17:36:56.000000000 +0000 @@ -0,0 +1,91 @@ +/* + * 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: ah_soc.h,v 1.1 2009/03/23 17:14:47 sborrill Exp $ + */ +#ifndef _ATH_AH_SOC_H_ +#define _ATH_AH_SOC_H_ +/* + * Atheros System on Chip (SoC) public definitions. + */ + +/* + * This is board-specific data that is stored in a "known" + * location in flash. To find the start of this data search + * back from the (aliased) end of flash by 0x1000 bytes at a + * time until you find the string "5311", which marks the + * start of Board Configuration. Typically one gives up if + * more than 500KB is searched. + */ +struct ar531x_boarddata { + uint32_t magic; /* board data is valid */ +#define AR531X_BD_MAGIC 0x35333131 /* "5311", for all 531x platforms */ + uint16_t cksum; /* checksum (starting with BD_REV 2) */ + uint16_t rev; /* revision of this struct */ +#define BD_REV 4 + char boardName[64]; /* Name of board */ + uint16_t major; /* Board major number */ + uint16_t minor; /* Board minor number */ + uint32_t config; /* Board configuration */ +#define BD_ENET0 0x00000001 /* ENET0 is stuffed */ +#define BD_ENET1 0x00000002 /* ENET1 is stuffed */ +#define BD_UART1 0x00000004 /* UART1 is stuffed */ +#define BD_UART0 0x00000008 /* UART0 is stuffed (dma) */ +#define BD_RSTFACTORY 0x00000010 /* Reset factory defaults stuffed */ +#define BD_SYSLED 0x00000020 /* System LED stuffed */ +#define BD_EXTUARTCLK 0x00000040 /* External UART clock */ +#define BD_CPUFREQ 0x00000080 /* cpu freq is valid in nvram */ +#define BD_SYSFREQ 0x00000100 /* sys freq is set in nvram */ +#define BD_WLAN0 0x00000200 /* Enable WLAN0 */ +#define BD_MEMCAP 0x00000400 /* CAP SDRAM @ memCap for testing */ +#define BD_DISWATCHDOG 0x00000800 /* disable system watchdog */ +#define BD_WLAN1 0x00001000 /* Enable WLAN1 (ar5212) */ +#define BD_ISCASPER 0x00002000 /* FLAG for AR2312 */ +#define BD_WLAN0_2G_EN 0x00004000 /* FLAG for radio0_2G */ +#define BD_WLAN0_5G_EN 0x00008000 /* FLAG for radio0_2G */ +#define BD_WLAN1_2G_EN 0x00020000 /* FLAG for radio0_2G */ +#define BD_WLAN1_5G_EN 0x00040000 /* FLAG for radio0_2G */ + uint16_t resetConfigGpio; /* Reset factory GPIO pin */ + uint16_t sysLedGpio; /* System LED GPIO pin */ + + uint32_t cpuFreq; /* CPU core frequency in Hz */ + uint32_t sysFreq; /* System frequency in Hz */ + uint32_t cntFreq; /* Calculated C0_COUNT frequency */ + + uint8_t wlan0Mac[6]; + uint8_t enet0Mac[6]; + uint8_t enet1Mac[6]; + + uint16_t pciId; /* Pseudo PCIID for common code */ + uint16_t memCap; /* cap bank1 in MB */ + + /* version 3 */ + uint8_t wlan1Mac[6]; /* (ar5212) */ +}; + +/* + * Board support data. The driver is required to locate + * and fill-in this information before passing a reference to + * this structure as the HAL_BUS_TAG parameter supplied to + * ath_hal_attach. + */ +struct ar531x_config { + const struct ar531x_boarddata *board; /* board config data */ + const char *radio; /* radio config data */ + int unit; /* unit number [0, 1] */ + void *tag; /* bus space tag */ +}; +#endif /* _ATH_AH_SOC_H_ */ --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ah_decode.h 2009-03-23 17:36:56.000000000 +0000 @@ -0,0 +1,55 @@ +/* + * 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: ah_decode.h,v 1.1 2009/03/23 17:14:47 sborrill Exp $ + */ +#ifndef _ATH_AH_DECODE_H_ +#define _ATH_AH_DECODE_H_ +/* + * Register tracing support. + * + * Setting hw.ath.hal.alq=1 enables tracing of all register reads and + * writes to the file /tmp/ath_hal.log. The file format is a simple + * fixed-size array of records. When done logging set hw.ath.hal.alq=0 + * and then decode the file with the arcode program (that is part of the + * HAL). If you start+stop tracing the data will be appended to an + * existing file. + */ +struct athregrec { + uint32_t op : 8, + reg : 24; + uint32_t val; +}; + +enum { + OP_READ = 0, /* register read */ + OP_WRITE = 1, /* register write */ + OP_DEVICE = 2, /* device identification */ + OP_MARK = 3, /* application marker */ +}; + +enum { + AH_MARK_RESET, /* ar*Reset entry, bChannelChange */ + AH_MARK_RESET_LINE, /* ar*_reset.c, line %d */ + AH_MARK_RESET_DONE, /* ar*Reset exit, error code */ + AH_MARK_CHIPRESET, /* ar*ChipReset, channel num */ + AH_MARK_PERCAL, /* ar*PerCalibration, channel num */ + AH_MARK_SETCHANNEL, /* ar*SetChannel, channel num */ + AH_MARK_ANI_RESET, /* ar*AniReset, opmode */ + AH_MARK_ANI_POLL, /* ar*AniReset, listen time */ + AH_MARK_ANI_CONTROL, /* ar*AniReset, cmd */ +}; +#endif /* _ATH_AH_DECODE_H_ */ --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ah.h 2009-03-23 17:36:56.000000000 +0000 @@ -0,0 +1,899 @@ +/* + * 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: ah.h,v 1.1 2009/03/23 17:14:47 sborrill Exp $ + */ + +#ifndef _ATH_AH_H_ +#define _ATH_AH_H_ +/* + * Atheros Hardware Access Layer + * + * Clients of the HAL call ath_hal_attach to obtain a reference to an ath_hal + * structure for use with the device. Hardware-related operations that + * follow must call back into the HAL through interface, supplying the + * reference as the first parameter. + */ + +#include "ah_osdep.h" + +/* + * __ahdecl is analogous to _cdecl; it defines the calling + * convention used within the HAL. For most systems this + * can just default to be empty and the compiler will (should) + * use _cdecl. For systems where _cdecl is not compatible this + * must be defined. See linux/ah_osdep.h for an example. + */ +#ifndef __ahdecl +#define __ahdecl +#endif + +/* + * Status codes that may be returned by the HAL. Note that + * interfaces that return a status code set it only when an + * error occurs--i.e. you cannot check it for success. + */ +typedef enum { + HAL_OK = 0, /* No error */ + HAL_ENXIO = 1, /* No hardware present */ + HAL_ENOMEM = 2, /* Memory allocation failed */ + HAL_EIO = 3, /* Hardware didn't respond as expected */ + HAL_EEMAGIC = 4, /* EEPROM magic number invalid */ + HAL_EEVERSION = 5, /* EEPROM version invalid */ + HAL_EELOCKED = 6, /* EEPROM unreadable */ + HAL_EEBADSUM = 7, /* EEPROM checksum invalid */ + HAL_EEREAD = 8, /* EEPROM read problem */ + HAL_EEBADMAC = 9, /* EEPROM mac address invalid */ + HAL_EESIZE = 10, /* EEPROM size not supported */ + HAL_EEWRITE = 11, /* Attempt to change write-locked EEPROM */ + HAL_EINVAL = 12, /* Invalid parameter to function */ + HAL_ENOTSUPP = 13, /* Hardware revision not supported */ + HAL_ESELFTEST = 14, /* Hardware self-test failed */ + HAL_EINPROGRESS = 15, /* Operation incomplete */ +} HAL_STATUS; + +typedef enum { + AH_FALSE = 0, /* NB: lots of code assumes false is zero */ + AH_TRUE = 1, +} HAL_BOOL; + +typedef enum { + HAL_CAP_REG_DMN = 0, /* current regulatory domain */ + HAL_CAP_CIPHER = 1, /* hardware supports cipher */ + HAL_CAP_TKIP_MIC = 2, /* handle TKIP MIC in hardware */ + HAL_CAP_TKIP_SPLIT = 3, /* hardware TKIP uses split keys */ + HAL_CAP_PHYCOUNTERS = 4, /* hardware PHY error counters */ + HAL_CAP_DIVERSITY = 5, /* hardware supports fast diversity */ + HAL_CAP_KEYCACHE_SIZE = 6, /* number of entries in key cache */ + HAL_CAP_NUM_TXQUEUES = 7, /* number of hardware xmit queues */ + HAL_CAP_VEOL = 9, /* hardware supports virtual EOL */ + HAL_CAP_PSPOLL = 10, /* hardware has working PS-Poll support */ + HAL_CAP_DIAG = 11, /* hardware diagnostic support */ + HAL_CAP_COMPRESSION = 12, /* hardware supports compression */ + HAL_CAP_BURST = 13, /* hardware supports packet bursting */ + HAL_CAP_FASTFRAME = 14, /* hardware supoprts fast frames */ + HAL_CAP_TXPOW = 15, /* global tx power limit */ + HAL_CAP_TPC = 16, /* per-packet tx power control */ + HAL_CAP_PHYDIAG = 17, /* hardware phy error diagnostic */ + HAL_CAP_BSSIDMASK = 18, /* hardware supports bssid mask */ + HAL_CAP_MCAST_KEYSRCH = 19, /* hardware has multicast key search */ + HAL_CAP_TSF_ADJUST = 20, /* hardware has beacon tsf adjust */ + /* 21 was HAL_CAP_XR */ + HAL_CAP_WME_TKIPMIC = 22, /* hardware can support TKIP MIC when WMM is turned on */ + /* 23 was HAL_CAP_CHAN_HALFRATE */ + /* 24 was HAL_CAP_CHAN_QUARTERRATE */ + HAL_CAP_RFSILENT = 25, /* hardware has rfsilent support */ + HAL_CAP_TPC_ACK = 26, /* ack txpower with per-packet tpc */ + HAL_CAP_TPC_CTS = 27, /* cts txpower with per-packet tpc */ + HAL_CAP_11D = 28, /* 11d beacon support for changing cc */ + HAL_CAP_INTMIT = 29, /* interference mitigation */ + HAL_CAP_RXORN_FATAL = 30, /* HAL_INT_RXORN treated as fatal */ + HAL_CAP_HT = 31, /* hardware can support HT */ + HAL_CAP_TX_CHAINMASK = 32, /* mask of TX chains supported */ + HAL_CAP_RX_CHAINMASK = 33, /* mask of RX chains supported */ + HAL_CAP_RXTSTAMP_PREC = 34, /* rx desc tstamp precision (bits) */ + HAL_CAP_BB_HANG = 35, /* can baseband hang */ + HAL_CAP_MAC_HANG = 36, /* can MAC hang */ +} HAL_CAPABILITY_TYPE; + +/* + * "States" for setting the LED. These correspond to + * the possible 802.11 operational states and there may + * be a many-to-one mapping between these states and the + * actual hardware state for the LED's (i.e. the hardware + * may have fewer states). + */ +typedef enum { + HAL_LED_INIT = 0, + HAL_LED_SCAN = 1, + HAL_LED_AUTH = 2, + HAL_LED_ASSOC = 3, + HAL_LED_RUN = 4 +} HAL_LED_STATE; + +/* + * Transmit queue types/numbers. These are used to tag + * each transmit queue in the hardware and to identify a set + * of transmit queues for operations such as start/stop dma. + */ +typedef enum { + HAL_TX_QUEUE_INACTIVE = 0, /* queue is inactive/unused */ + HAL_TX_QUEUE_DATA = 1, /* data xmit q's */ + HAL_TX_QUEUE_BEACON = 2, /* beacon xmit q */ + HAL_TX_QUEUE_CAB = 3, /* "crap after beacon" xmit q */ + HAL_TX_QUEUE_UAPSD = 4, /* u-apsd power save xmit q */ +} HAL_TX_QUEUE; + +#define HAL_NUM_TX_QUEUES 10 /* max possible # of queues */ + +/* + * Transmit queue subtype. These map directly to + * WME Access Categories (except for UPSD). Refer + * to Table 5 of the WME spec. + */ +typedef enum { + HAL_WME_AC_BK = 0, /* background access category */ + HAL_WME_AC_BE = 1, /* best effort access category*/ + HAL_WME_AC_VI = 2, /* video access category */ + HAL_WME_AC_VO = 3, /* voice access category */ + HAL_WME_UPSD = 4, /* uplink power save */ +} HAL_TX_QUEUE_SUBTYPE; + +/* + * Transmit queue flags that control various + * operational parameters. + */ +typedef enum { + /* + * Per queue interrupt enables. When set the associated + * interrupt may be delivered for packets sent through + * the queue. Without these enabled no interrupts will + * be delivered for transmits through the queue. + */ + HAL_TXQ_TXOKINT_ENABLE = 0x0001, /* enable TXOK interrupt */ + HAL_TXQ_TXERRINT_ENABLE = 0x0001, /* enable TXERR interrupt */ + HAL_TXQ_TXDESCINT_ENABLE = 0x0002, /* enable TXDESC interrupt */ + HAL_TXQ_TXEOLINT_ENABLE = 0x0004, /* enable TXEOL interrupt */ + HAL_TXQ_TXURNINT_ENABLE = 0x0008, /* enable TXURN interrupt */ + /* + * Enable hardware compression for packets sent through + * the queue. The compression buffer must be setup and + * packets must have a key entry marked in the tx descriptor. + */ + HAL_TXQ_COMPRESSION_ENABLE = 0x0010, /* enable h/w compression */ + /* + * Disable queue when veol is hit or ready time expires. + * By default the queue is disabled only on reaching the + * physical end of queue (i.e. a null link ptr in the + * descriptor chain). + */ + HAL_TXQ_RDYTIME_EXP_POLICY_ENABLE = 0x0020, + /* + * Schedule frames on delivery of a DBA (DMA Beacon Alert) + * event. Frames will be transmitted only when this timer + * fires, e.g to transmit a beacon in ap or adhoc modes. + */ + HAL_TXQ_DBA_GATED = 0x0040, /* schedule based on DBA */ + /* + * Each transmit queue has a counter that is incremented + * each time the queue is enabled and decremented when + * the list of frames to transmit is traversed (or when + * the ready time for the queue expires). This counter + * must be non-zero for frames to be scheduled for + * transmission. The following controls disable bumping + * this counter under certain conditions. Typically this + * is used to gate frames based on the contents of another + * queue (e.g. CAB traffic may only follow a beacon frame). + * These are meaningful only when frames are scheduled + * with a non-ASAP policy (e.g. DBA-gated). + */ + HAL_TXQ_CBR_DIS_QEMPTY = 0x0080, /* disable on this q empty */ + HAL_TXQ_CBR_DIS_BEMPTY = 0x0100, /* disable on beacon q empty */ + + /* + * Fragment burst backoff policy. Normally the no backoff + * is done after a successful transmission, the next fragment + * is sent at SIFS. If this flag is set backoff is done + * after each fragment, regardless whether it was ack'd or + * not, after the backoff count reaches zero a normal channel + * access procedure is done before the next transmit (i.e. + * wait AIFS instead of SIFS). + */ + HAL_TXQ_FRAG_BURST_BACKOFF_ENABLE = 0x00800000, + /* + * Disable post-tx backoff following each frame. + */ + HAL_TXQ_BACKOFF_DISABLE = 0x00010000, /* disable post backoff */ + /* + * DCU arbiter lockout control. This controls how + * lower priority tx queues are handled with respect to + * to a specific queue when multiple queues have frames + * to send. No lockout means lower priority queues arbitrate + * concurrently with this queue. Intra-frame lockout + * means lower priority queues are locked out until the + * current frame transmits (e.g. including backoffs and bursting). + * Global lockout means nothing lower can arbitrary so + * long as there is traffic activity on this queue (frames, + * backoff, etc). + */ + HAL_TXQ_ARB_LOCKOUT_INTRA = 0x00020000, /* intra-frame lockout */ + HAL_TXQ_ARB_LOCKOUT_GLOBAL = 0x00040000, /* full lockout s */ + + HAL_TXQ_IGNORE_VIRTCOL = 0x00080000, /* ignore virt collisions */ + HAL_TXQ_SEQNUM_INC_DIS = 0x00100000, /* disable seqnum increment */ +} HAL_TX_QUEUE_FLAGS; + +typedef struct { + uint32_t tqi_ver; /* hal TXQ version */ + HAL_TX_QUEUE_SUBTYPE tqi_subtype; /* subtype if applicable */ + HAL_TX_QUEUE_FLAGS tqi_qflags; /* flags (see above) */ + uint32_t tqi_priority; /* (not used) */ + uint32_t tqi_aifs; /* aifs */ + uint32_t tqi_cwmin; /* cwMin */ + uint32_t tqi_cwmax; /* cwMax */ + uint16_t tqi_shretry; /* rts retry limit */ + uint16_t tqi_lgretry; /* long retry limit (not used)*/ + uint32_t tqi_cbrPeriod; /* CBR period (us) */ + uint32_t tqi_cbrOverflowLimit; /* threshold for CBROVF int */ + uint32_t tqi_burstTime; /* max burst duration (us) */ + uint32_t tqi_readyTime; /* frame schedule time (us) */ + uint32_t tqi_compBuf; /* comp buffer phys addr */ +} HAL_TXQ_INFO; + +#define HAL_TQI_NONVAL 0xffff + +/* token to use for aifs, cwmin, cwmax */ +#define HAL_TXQ_USEDEFAULT ((uint32_t) -1) + +/* compression definitions */ +#define HAL_COMP_BUF_MAX_SIZE 9216 /* 9K */ +#define HAL_COMP_BUF_ALIGN_SIZE 512 + +/* + * Transmit packet types. This belongs in ah_desc.h, but + * is here so we can give a proper type to various parameters + * (and not require everyone include the file). + * + * NB: These values are intentionally assigned for + * direct use when setting up h/w descriptors. + */ +typedef enum { + HAL_PKT_TYPE_NORMAL = 0, + HAL_PKT_TYPE_ATIM = 1, + HAL_PKT_TYPE_PSPOLL = 2, + HAL_PKT_TYPE_BEACON = 3, + HAL_PKT_TYPE_PROBE_RESP = 4, + HAL_PKT_TYPE_CHIRP = 5, + HAL_PKT_TYPE_GRP_POLL = 6, + HAL_PKT_TYPE_AMPDU = 7, +} HAL_PKT_TYPE; + +/* Rx Filter Frame Types */ +typedef enum { + HAL_RX_FILTER_UCAST = 0x00000001, /* Allow unicast frames */ + HAL_RX_FILTER_MCAST = 0x00000002, /* Allow multicast frames */ + HAL_RX_FILTER_BCAST = 0x00000004, /* Allow broadcast frames */ + HAL_RX_FILTER_CONTROL = 0x00000008, /* Allow control frames */ + HAL_RX_FILTER_BEACON = 0x00000010, /* Allow beacon frames */ + HAL_RX_FILTER_PROM = 0x00000020, /* Promiscuous mode */ + HAL_RX_FILTER_PROBEREQ = 0x00000080, /* Allow probe request frames */ + HAL_RX_FILTER_PHYERR = 0x00000100, /* Allow phy errors */ + HAL_RX_FILTER_PHYRADAR = 0x00000200, /* Allow phy radar errors */ + HAL_RX_FILTER_COMPBAR = 0x00000400, /* Allow compressed BAR */ +} HAL_RX_FILTER; + +typedef enum { + HAL_PM_AWAKE = 0, + HAL_PM_FULL_SLEEP = 1, + HAL_PM_NETWORK_SLEEP = 2, + HAL_PM_UNDEFINED = 3 +} HAL_POWER_MODE; + +/* + * NOTE WELL: + * These are mapped to take advantage of the common locations for many of + * the bits on all of the currently supported MAC chips. This is to make + * the ISR as efficient as possible, while still abstracting HW differences. + * When new hardware breaks this commonality this enumerated type, as well + * as the HAL functions using it, must be modified. All values are directly + * mapped unless commented otherwise. + */ +typedef enum { + HAL_INT_RX = 0x00000001, /* Non-common mapping */ + HAL_INT_RXDESC = 0x00000002, + HAL_INT_RXNOFRM = 0x00000008, + HAL_INT_RXEOL = 0x00000010, + HAL_INT_RXORN = 0x00000020, + HAL_INT_TX = 0x00000040, /* Non-common mapping */ + HAL_INT_TXDESC = 0x00000080, + HAL_INT_TXURN = 0x00000800, + HAL_INT_MIB = 0x00001000, + HAL_INT_RXPHY = 0x00004000, + HAL_INT_RXKCM = 0x00008000, + HAL_INT_SWBA = 0x00010000, + HAL_INT_BMISS = 0x00040000, + HAL_INT_BNR = 0x00100000, /* Non-common mapping */ + HAL_INT_TIM = 0x00200000, /* Non-common mapping */ + HAL_INT_DTIM = 0x00400000, /* Non-common mapping */ + HAL_INT_DTIMSYNC= 0x00800000, /* Non-common mapping */ + HAL_INT_GPIO = 0x01000000, + HAL_INT_CABEND = 0x02000000, /* Non-common mapping */ + HAL_INT_TSFOOR = 0x04000000, /* Non-common mapping */ + HAL_INT_CST = 0x10000000, /* Non-common mapping */ + HAL_INT_GTT = 0x20000000, /* Non-common mapping */ + HAL_INT_FATAL = 0x40000000, /* Non-common mapping */ +#define HAL_INT_GLOBAL 0x80000000 /* Set/clear IER */ + HAL_INT_BMISC = HAL_INT_TIM + | HAL_INT_DTIM + | HAL_INT_DTIMSYNC + | HAL_INT_CABEND, + + /* Interrupt bits that map directly to ISR/IMR bits */ + HAL_INT_COMMON = HAL_INT_RXNOFRM + | HAL_INT_RXDESC + | HAL_INT_RXEOL + | HAL_INT_RXORN + | HAL_INT_TXURN + | HAL_INT_TXDESC + | HAL_INT_MIB + | HAL_INT_RXPHY + | HAL_INT_RXKCM + | HAL_INT_SWBA + | HAL_INT_BMISS + | HAL_INT_GPIO, +} HAL_INT; + +typedef enum { + HAL_RFGAIN_INACTIVE = 0, + HAL_RFGAIN_READ_REQUESTED = 1, + HAL_RFGAIN_NEED_CHANGE = 2 +} HAL_RFGAIN; + +/* + * Channels are specified by frequency. + */ +typedef struct { + uint32_t channelFlags; /* see below */ + uint16_t channel; /* setting in Mhz */ + uint8_t privFlags; + int8_t maxRegTxPower; /* max regulatory tx power in dBm */ + int8_t maxTxPower; /* max true tx power in 0.5 dBm */ + int8_t minTxPower; /* min true tx power in 0.5 dBm */ +} HAL_CHANNEL; + +/* channelFlags */ +#define CHANNEL_CW_INT 0x00002 /* CW interference detected on channel */ +#define CHANNEL_TURBO 0x00010 /* Turbo Channel */ +#define CHANNEL_CCK 0x00020 /* CCK channel */ +#define CHANNEL_OFDM 0x00040 /* OFDM channel */ +#define CHANNEL_2GHZ 0x00080 /* 2 GHz spectrum channel */ +#define CHANNEL_5GHZ 0x00100 /* 5 GHz spectrum channel */ +#define CHANNEL_PASSIVE 0x00200 /* Only passive scan allowed in the channel */ +#define CHANNEL_DYN 0x00400 /* dynamic CCK-OFDM channel */ +#define CHANNEL_STURBO 0x02000 /* Static turbo, no 11a-only usage */ +#define CHANNEL_HALF 0x04000 /* Half rate channel */ +#define CHANNEL_QUARTER 0x08000 /* Quarter rate channel */ +#define CHANNEL_HT20 0x10000 /* 11n 20MHZ channel */ +#define CHANNEL_HT40PLUS 0x20000 /* 11n 40MHZ channel w/ ext chan above */ +#define CHANNEL_HT40MINUS 0x40000 /* 11n 40MHZ channel w/ ext chan below */ + +/* privFlags */ +#define CHANNEL_INTERFERENCE 0x01 /* Software use: channel interference + used for as AR as well as RADAR + interference detection */ +#define CHANNEL_DFS 0x02 /* DFS required on channel */ +#define CHANNEL_4MS_LIMIT 0x04 /* 4msec packet limit on this channel */ +#define CHANNEL_DFS_CLEAR 0x08 /* if channel has been checked for DFS */ + +#define CHANNEL_A (CHANNEL_5GHZ|CHANNEL_OFDM) +#define CHANNEL_B (CHANNEL_2GHZ|CHANNEL_CCK) +#define CHANNEL_PUREG (CHANNEL_2GHZ|CHANNEL_OFDM) +#ifdef notdef +#define CHANNEL_G (CHANNEL_2GHZ|CHANNEL_DYN) +#else +#define CHANNEL_G (CHANNEL_2GHZ|CHANNEL_OFDM) +#endif +#define CHANNEL_T (CHANNEL_5GHZ|CHANNEL_OFDM|CHANNEL_TURBO) +#define CHANNEL_ST (CHANNEL_T|CHANNEL_STURBO) +#define CHANNEL_108G (CHANNEL_2GHZ|CHANNEL_OFDM|CHANNEL_TURBO) +#define CHANNEL_108A CHANNEL_T +#define CHANNEL_G_HT20 (CHANNEL_G|CHANNEL_HT20) +#define CHANNEL_A_HT20 (CHANNEL_A|CHANNEL_HT20) +#define CHANNEL_G_HT40PLUS (CHANNEL_G|CHANNEL_HT40PLUS) +#define CHANNEL_G_HT40MINUS (CHANNEL_G|CHANNEL_HT40MINUS) +#define CHANNEL_A_HT40PLUS (CHANNEL_A|CHANNEL_HT40PLUS) +#define CHANNEL_A_HT40MINUS (CHANNEL_A|CHANNEL_HT40MINUS) +#define CHANNEL_ALL \ + (CHANNEL_OFDM | CHANNEL_CCK| CHANNEL_2GHZ | CHANNEL_5GHZ | \ + CHANNEL_TURBO | CHANNEL_HT20 | CHANNEL_HT40PLUS | CHANNEL_HT40MINUS) +#define CHANNEL_ALL_NOTURBO (CHANNEL_ALL &~ CHANNEL_TURBO) + +#define HAL_ANTENNA_MIN_MODE 0 +#define HAL_ANTENNA_FIXED_A 1 +#define HAL_ANTENNA_FIXED_B 2 +#define HAL_ANTENNA_MAX_MODE 3 + +typedef struct { + uint32_t ackrcv_bad; + uint32_t rts_bad; + uint32_t rts_good; + uint32_t fcs_bad; + uint32_t beacons; +} HAL_MIB_STATS; + +typedef uint16_t HAL_CTRY_CODE; /* country code */ +typedef uint16_t HAL_REG_DOMAIN; /* regulatory domain code */ + +enum { + CTRY_DEBUG = 0x1ff, /* debug country code */ + CTRY_DEFAULT = 0 /* default country code */ +}; + +enum { + HAL_MODE_11A = 0x001, /* 11a channels */ + HAL_MODE_TURBO = 0x002, /* 11a turbo-only channels */ + HAL_MODE_11B = 0x004, /* 11b channels */ + HAL_MODE_PUREG = 0x008, /* 11g channels (OFDM only) */ +#ifdef notdef + HAL_MODE_11G = 0x010, /* 11g channels (OFDM/CCK) */ +#else + HAL_MODE_11G = 0x008, /* XXX historical */ +#endif + HAL_MODE_108G = 0x020, /* 11g+Turbo channels */ + HAL_MODE_108A = 0x040, /* 11a+Turbo channels */ + HAL_MODE_11A_HALF_RATE = 0x200, /* 11a half width channels */ + HAL_MODE_11A_QUARTER_RATE = 0x400, /* 11a quarter width channels */ + HAL_MODE_11G_HALF_RATE = 0x800, /* 11g half width channels */ + HAL_MODE_11G_QUARTER_RATE = 0x1000, /* 11g quarter width channels */ + HAL_MODE_11NG_HT20 = 0x008000, + HAL_MODE_11NA_HT20 = 0x010000, + HAL_MODE_11NG_HT40PLUS = 0x020000, + HAL_MODE_11NG_HT40MINUS = 0x040000, + HAL_MODE_11NA_HT40PLUS = 0x080000, + HAL_MODE_11NA_HT40MINUS = 0x100000, + HAL_MODE_ALL = 0xffffff +}; + +typedef struct { + int rateCount; /* NB: for proper padding */ + uint8_t rateCodeToIndex[144]; /* back mapping */ + struct { + uint8_t valid; /* valid for rate control use */ + uint8_t phy; /* CCK/OFDM/XR */ + uint32_t rateKbps; /* transfer rate in kbs */ + uint8_t rateCode; /* rate for h/w descriptors */ + uint8_t shortPreamble; /* mask for enabling short + * preamble in CCK rate code */ + uint8_t dot11Rate; /* value for supported rates + * info element of MLME */ + uint8_t controlRate; /* index of next lower basic + * rate; used for dur. calcs */ + uint16_t lpAckDuration; /* long preamble ACK duration */ + uint16_t spAckDuration; /* short preamble ACK duration*/ + } info[32]; +} HAL_RATE_TABLE; + +typedef struct { + u_int rs_count; /* number of valid entries */ + uint8_t rs_rates[32]; /* rates */ +} HAL_RATE_SET; + +/* + * 802.11n specific structures and enums + */ +typedef enum { + HAL_CHAINTYPE_TX = 1, /* Tx chain type */ + HAL_CHAINTYPE_RX = 2, /* RX chain type */ +} HAL_CHAIN_TYPE; + +typedef struct { + u_int Tries; + u_int Rate; + u_int PktDuration; + u_int ChSel; + u_int RateFlags; +#define HAL_RATESERIES_RTS_CTS 0x0001 /* use rts/cts w/this series */ +#define HAL_RATESERIES_2040 0x0002 /* use ext channel for series */ +#define HAL_RATESERIES_HALFGI 0x0004 /* use half-gi for series */ +} HAL_11N_RATE_SERIES; + +typedef enum { + HAL_HT_MACMODE_20 = 0, /* 20 MHz operation */ + HAL_HT_MACMODE_2040 = 1, /* 20/40 MHz operation */ +} HAL_HT_MACMODE; + +typedef enum { + HAL_HT_PHYMODE_20 = 0, /* 20 MHz operation */ + HAL_HT_PHYMODE_2040 = 1, /* 20/40 MHz operation */ +} HAL_HT_PHYMODE; + +typedef enum { + HAL_HT_EXTPROTSPACING_20 = 0, /* 20 MHz spacing */ + HAL_HT_EXTPROTSPACING_25 = 1, /* 25 MHz spacing */ +} HAL_HT_EXTPROTSPACING; + + +typedef enum { + HAL_RX_CLEAR_CTL_LOW = 0x1, /* force control channel to appear busy */ + HAL_RX_CLEAR_EXT_LOW = 0x2, /* force extension channel to appear busy */ +} HAL_HT_RXCLEAR; + +/* + * Antenna switch control. By default antenna selection + * enables multiple (2) antenna use. To force use of the + * A or B antenna only specify a fixed setting. Fixing + * the antenna will also disable any diversity support. + */ +typedef enum { + HAL_ANT_VARIABLE = 0, /* variable by programming */ + HAL_ANT_FIXED_A = 1, /* fixed antenna A */ + HAL_ANT_FIXED_B = 2, /* fixed antenna B */ +} HAL_ANT_SETTING; + +typedef enum { + HAL_M_STA = 1, /* infrastructure station */ + HAL_M_IBSS = 0, /* IBSS (adhoc) station */ + HAL_M_HOSTAP = 6, /* Software Access Point */ + HAL_M_MONITOR = 8 /* Monitor mode */ +} HAL_OPMODE; + +typedef struct { + uint8_t kv_type; /* one of HAL_CIPHER */ + uint8_t kv_pad; + uint16_t kv_len; /* length in bits */ + uint8_t kv_val[16]; /* enough for 128-bit keys */ + uint8_t kv_mic[8]; /* TKIP MIC key */ + uint8_t kv_txmic[8]; /* TKIP TX MIC key (optional) */ +} HAL_KEYVAL; + +typedef enum { + HAL_CIPHER_WEP = 0, + HAL_CIPHER_AES_OCB = 1, + HAL_CIPHER_AES_CCM = 2, + HAL_CIPHER_CKIP = 3, + HAL_CIPHER_TKIP = 4, + HAL_CIPHER_CLR = 5, /* no encryption */ + + HAL_CIPHER_MIC = 127 /* TKIP-MIC, not a cipher */ +} HAL_CIPHER; + +enum { + HAL_SLOT_TIME_6 = 6, /* NB: for turbo mode */ + HAL_SLOT_TIME_9 = 9, + HAL_SLOT_TIME_20 = 20, +}; + +/* + * Per-station beacon timer state. Note that the specified + * beacon interval (given in TU's) can also include flags + * to force a TSF reset and to enable the beacon xmit logic. + * If bs_cfpmaxduration is non-zero the hardware is setup to + * coexist with a PCF-capable AP. + */ +typedef struct { + uint32_t bs_nexttbtt; /* next beacon in TU */ + uint32_t bs_nextdtim; /* next DTIM in TU */ + uint32_t bs_intval; /* beacon interval+flags */ +#define HAL_BEACON_PERIOD 0x0000ffff /* beacon interval period */ +#define HAL_BEACON_ENA 0x00800000 /* beacon xmit enable */ +#define HAL_BEACON_RESET_TSF 0x01000000 /* clear TSF */ + uint32_t bs_dtimperiod; + uint16_t bs_cfpperiod; /* CFP period in TU */ + uint16_t bs_cfpmaxduration; /* max CFP duration in TU */ + uint32_t bs_cfpnext; /* next CFP in TU */ + uint16_t bs_timoffset; /* byte offset to TIM bitmap */ + uint16_t bs_bmissthreshold; /* beacon miss threshold */ + uint32_t bs_sleepduration; /* max sleep duration */ +} HAL_BEACON_STATE; + +/* + * Like HAL_BEACON_STATE but for non-station mode setup. + * NB: see above flag definitions for bt_intval. + */ +typedef struct { + uint32_t bt_intval; /* beacon interval+flags */ + uint32_t bt_nexttbtt; /* next beacon in TU */ + uint32_t bt_nextatim; /* next ATIM in TU */ + uint32_t bt_nextdba; /* next DBA in 1/8th TU */ + uint32_t bt_nextswba; /* next SWBA in 1/8th TU */ + uint32_t bt_flags; /* timer enables */ +#define HAL_BEACON_TBTT_EN 0x00000001 +#define HAL_BEACON_DBA_EN 0x00000002 +#define HAL_BEACON_SWBA_EN 0x00000004 +} HAL_BEACON_TIMERS; + +/* + * Per-node statistics maintained by the driver for use in + * optimizing signal quality and other operational aspects. + */ +typedef struct { + uint32_t ns_avgbrssi; /* average beacon rssi */ + uint32_t ns_avgrssi; /* average data rssi */ + uint32_t ns_avgtxrssi; /* average tx rssi */ +} HAL_NODE_STATS; + +#define HAL_RSSI_EP_MULTIPLIER (1<<7) /* pow2 to optimize out * and / */ + +struct ath_desc; +struct ath_tx_status; +struct ath_rx_status; + +/* + * Hardware Access Layer (HAL) API. + * + * Clients of the HAL call ath_hal_attach to obtain a reference to an + * ath_hal structure for use with the device. Hardware-related operations + * that follow must call back into the HAL through interface, supplying + * the reference as the first parameter. Note that before using the + * reference returned by ath_hal_attach the caller should verify the + * ABI version number. + */ +struct ath_hal { + uint32_t ah_magic; /* consistency check magic number */ + uint32_t ah_abi; /* HAL ABI version */ +#define HAL_ABI_VERSION 0x08112800 /* YYMMDDnn */ + uint16_t ah_devid; /* PCI device ID */ + uint16_t ah_subvendorid; /* PCI subvendor ID */ + HAL_SOFTC ah_sc; /* back pointer to driver/os state */ + HAL_BUS_TAG ah_st; /* params for register r+w */ + HAL_BUS_HANDLE ah_sh; + HAL_CTRY_CODE ah_countryCode; + + uint32_t ah_macVersion; /* MAC version id */ + uint16_t ah_macRev; /* MAC revision */ + uint16_t ah_phyRev; /* PHY revision */ + /* NB: when only one radio is present the rev is in 5Ghz */ + uint16_t ah_analog5GhzRev;/* 5GHz radio revision */ + uint16_t ah_analog2GhzRev;/* 2GHz radio revision */ + + const HAL_RATE_TABLE *__ahdecl(*ah_getRateTable)(struct ath_hal *, + u_int mode); + void __ahdecl(*ah_detach)(struct ath_hal*); + + /* Reset functions */ + HAL_BOOL __ahdecl(*ah_reset)(struct ath_hal *, HAL_OPMODE, + HAL_CHANNEL *, HAL_BOOL bChannelChange, + HAL_STATUS *status); + HAL_BOOL __ahdecl(*ah_phyDisable)(struct ath_hal *); + HAL_BOOL __ahdecl(*ah_disable)(struct ath_hal *); + void __ahdecl(*ah_setPCUConfig)(struct ath_hal *); + HAL_BOOL __ahdecl(*ah_perCalibration)(struct ath_hal*, HAL_CHANNEL *, + HAL_BOOL *); + HAL_BOOL __ahdecl(*ah_perCalibrationN)(struct ath_hal *, HAL_CHANNEL *, + u_int chainMask, HAL_BOOL longCal, HAL_BOOL *isCalDone); + HAL_BOOL __ahdecl(*ah_resetCalValid)(struct ath_hal *, HAL_CHANNEL *); + HAL_BOOL __ahdecl(*ah_setTxPowerLimit)(struct ath_hal *, uint32_t); + + /* Transmit functions */ + HAL_BOOL __ahdecl(*ah_updateTxTrigLevel)(struct ath_hal*, + HAL_BOOL incTrigLevel); + int __ahdecl(*ah_setupTxQueue)(struct ath_hal *, HAL_TX_QUEUE, + const HAL_TXQ_INFO *qInfo); + HAL_BOOL __ahdecl(*ah_setTxQueueProps)(struct ath_hal *, int q, + const HAL_TXQ_INFO *qInfo); + HAL_BOOL __ahdecl(*ah_getTxQueueProps)(struct ath_hal *, int q, + HAL_TXQ_INFO *qInfo); + HAL_BOOL __ahdecl(*ah_releaseTxQueue)(struct ath_hal *ah, u_int q); + HAL_BOOL __ahdecl(*ah_resetTxQueue)(struct ath_hal *ah, u_int q); + uint32_t __ahdecl(*ah_getTxDP)(struct ath_hal*, u_int); + HAL_BOOL __ahdecl(*ah_setTxDP)(struct ath_hal*, u_int, uint32_t txdp); + uint32_t __ahdecl(*ah_numTxPending)(struct ath_hal *, u_int q); + HAL_BOOL __ahdecl(*ah_startTxDma)(struct ath_hal*, u_int); + HAL_BOOL __ahdecl(*ah_stopTxDma)(struct ath_hal*, u_int); + HAL_BOOL __ahdecl(*ah_setupTxDesc)(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); + HAL_BOOL __ahdecl(*ah_setupXTxDesc)(struct ath_hal *, struct ath_desc*, + u_int txRate1, u_int txTries1, + u_int txRate2, u_int txTries2, + u_int txRate3, u_int txTries3); + HAL_BOOL __ahdecl(*ah_fillTxDesc)(struct ath_hal *, struct ath_desc *, + u_int segLen, HAL_BOOL firstSeg, + HAL_BOOL lastSeg, const struct ath_desc *); + HAL_STATUS __ahdecl(*ah_procTxDesc)(struct ath_hal *, + struct ath_desc *, struct ath_tx_status *); + void __ahdecl(*ah_getTxIntrQueue)(struct ath_hal *, uint32_t *); + void __ahdecl(*ah_reqTxIntrDesc)(struct ath_hal *, struct ath_desc*); + + /* Receive Functions */ + uint32_t __ahdecl(*ah_getRxDP)(struct ath_hal*); + void __ahdecl(*ah_setRxDP)(struct ath_hal*, uint32_t rxdp); + void __ahdecl(*ah_enableReceive)(struct ath_hal*); + HAL_BOOL __ahdecl(*ah_stopDmaReceive)(struct ath_hal*); + void __ahdecl(*ah_startPcuReceive)(struct ath_hal*); + void __ahdecl(*ah_stopPcuReceive)(struct ath_hal*); + void __ahdecl(*ah_setMulticastFilter)(struct ath_hal*, + uint32_t filter0, uint32_t filter1); + HAL_BOOL __ahdecl(*ah_setMulticastFilterIndex)(struct ath_hal*, + uint32_t index); + HAL_BOOL __ahdecl(*ah_clrMulticastFilterIndex)(struct ath_hal*, + uint32_t index); + uint32_t __ahdecl(*ah_getRxFilter)(struct ath_hal*); + void __ahdecl(*ah_setRxFilter)(struct ath_hal*, uint32_t); + HAL_BOOL __ahdecl(*ah_setupRxDesc)(struct ath_hal *, struct ath_desc *, + uint32_t size, u_int flags); + HAL_STATUS __ahdecl(*ah_procRxDesc)(struct ath_hal *, + struct ath_desc *, uint32_t phyAddr, + struct ath_desc *next, uint64_t tsf, + struct ath_rx_status *); + void __ahdecl(*ah_rxMonitor)(struct ath_hal *, + const HAL_NODE_STATS *, HAL_CHANNEL *); + void __ahdecl(*ah_procMibEvent)(struct ath_hal *, + const HAL_NODE_STATS *); + + /* Misc Functions */ + HAL_STATUS __ahdecl(*ah_getCapability)(struct ath_hal *, + HAL_CAPABILITY_TYPE, uint32_t capability, + uint32_t *result); + HAL_BOOL __ahdecl(*ah_setCapability)(struct ath_hal *, + HAL_CAPABILITY_TYPE, uint32_t capability, + uint32_t setting, HAL_STATUS *); + HAL_BOOL __ahdecl(*ah_getDiagState)(struct ath_hal *, int request, + const void *args, uint32_t argsize, + void **result, uint32_t *resultsize); + void __ahdecl(*ah_getMacAddress)(struct ath_hal *, uint8_t *); + HAL_BOOL __ahdecl(*ah_setMacAddress)(struct ath_hal *, const uint8_t*); + void __ahdecl(*ah_getBssIdMask)(struct ath_hal *, uint8_t *); + HAL_BOOL __ahdecl(*ah_setBssIdMask)(struct ath_hal *, const uint8_t*); + HAL_BOOL __ahdecl(*ah_setRegulatoryDomain)(struct ath_hal*, + uint16_t, HAL_STATUS *); + void __ahdecl(*ah_setLedState)(struct ath_hal*, HAL_LED_STATE); + void __ahdecl(*ah_writeAssocid)(struct ath_hal*, + const uint8_t *bssid, uint16_t assocId); + HAL_BOOL __ahdecl(*ah_gpioCfgOutput)(struct ath_hal *, uint32_t gpio); + HAL_BOOL __ahdecl(*ah_gpioCfgInput)(struct ath_hal *, uint32_t gpio); + uint32_t __ahdecl(*ah_gpioGet)(struct ath_hal *, uint32_t gpio); + HAL_BOOL __ahdecl(*ah_gpioSet)(struct ath_hal *, + uint32_t gpio, uint32_t val); + void __ahdecl(*ah_gpioSetIntr)(struct ath_hal*, u_int, uint32_t); + uint32_t __ahdecl(*ah_getTsf32)(struct ath_hal*); + uint64_t __ahdecl(*ah_getTsf64)(struct ath_hal*); + void __ahdecl(*ah_resetTsf)(struct ath_hal*); + HAL_BOOL __ahdecl(*ah_detectCardPresent)(struct ath_hal*); + void __ahdecl(*ah_updateMibCounters)(struct ath_hal*, + HAL_MIB_STATS*); + HAL_RFGAIN __ahdecl(*ah_getRfGain)(struct ath_hal*); + u_int __ahdecl(*ah_getDefAntenna)(struct ath_hal*); + void __ahdecl(*ah_setDefAntenna)(struct ath_hal*, u_int); + HAL_ANT_SETTING __ahdecl(*ah_getAntennaSwitch)(struct ath_hal*); + HAL_BOOL __ahdecl(*ah_setAntennaSwitch)(struct ath_hal*, + HAL_ANT_SETTING); + HAL_BOOL __ahdecl(*ah_setSifsTime)(struct ath_hal*, u_int); + u_int __ahdecl(*ah_getSifsTime)(struct ath_hal*); + HAL_BOOL __ahdecl(*ah_setSlotTime)(struct ath_hal*, u_int); + u_int __ahdecl(*ah_getSlotTime)(struct ath_hal*); + HAL_BOOL __ahdecl(*ah_setAckTimeout)(struct ath_hal*, u_int); + u_int __ahdecl(*ah_getAckTimeout)(struct ath_hal*); + HAL_BOOL __ahdecl(*ah_setAckCTSRate)(struct ath_hal*, u_int); + u_int __ahdecl(*ah_getAckCTSRate)(struct ath_hal*); + HAL_BOOL __ahdecl(*ah_setCTSTimeout)(struct ath_hal*, u_int); + u_int __ahdecl(*ah_getCTSTimeout)(struct ath_hal*); + HAL_BOOL __ahdecl(*ah_setDecompMask)(struct ath_hal*, uint16_t, int); + void __ahdecl(*ah_setCoverageClass)(struct ath_hal*, uint8_t, int); + + /* Key Cache Functions */ + uint32_t __ahdecl(*ah_getKeyCacheSize)(struct ath_hal*); + HAL_BOOL __ahdecl(*ah_resetKeyCacheEntry)(struct ath_hal*, uint16_t); + HAL_BOOL __ahdecl(*ah_isKeyCacheEntryValid)(struct ath_hal *, + uint16_t); + HAL_BOOL __ahdecl(*ah_setKeyCacheEntry)(struct ath_hal*, + uint16_t, const HAL_KEYVAL *, + const uint8_t *, int); + HAL_BOOL __ahdecl(*ah_setKeyCacheEntryMac)(struct ath_hal*, + uint16_t, const uint8_t *); + + /* Power Management Functions */ + HAL_BOOL __ahdecl(*ah_setPowerMode)(struct ath_hal*, + HAL_POWER_MODE mode, int setChip); + HAL_POWER_MODE __ahdecl(*ah_getPowerMode)(struct ath_hal*); + int16_t __ahdecl(*ah_getChanNoise)(struct ath_hal *, HAL_CHANNEL *); + + /* Beacon Management Functions */ + void __ahdecl(*ah_setBeaconTimers)(struct ath_hal*, + const HAL_BEACON_TIMERS *); + /* NB: deprecated, use ah_setBeaconTimers instead */ + void __ahdecl(*ah_beaconInit)(struct ath_hal *, + uint32_t nexttbtt, uint32_t intval); + void __ahdecl(*ah_setStationBeaconTimers)(struct ath_hal*, + const HAL_BEACON_STATE *); + void __ahdecl(*ah_resetStationBeaconTimers)(struct ath_hal*); + + /* Interrupt functions */ + HAL_BOOL __ahdecl(*ah_isInterruptPending)(struct ath_hal*); + HAL_BOOL __ahdecl(*ah_getPendingInterrupts)(struct ath_hal*, HAL_INT*); + HAL_INT __ahdecl(*ah_getInterrupts)(struct ath_hal*); + HAL_INT __ahdecl(*ah_setInterrupts)(struct ath_hal*, HAL_INT); +}; + +/* + * Check the PCI vendor ID and device ID against Atheros' values + * and return a printable description for any Atheros hardware. + * AH_NULL is returned if the ID's do not describe Atheros hardware. + */ +extern const char *__ahdecl ath_hal_probe(uint16_t vendorid, uint16_t devid); + +/* + * Attach the HAL for use with the specified device. The device is + * defined by the PCI device ID. The caller provides an opaque pointer + * to an upper-layer data structure (HAL_SOFTC) that is stored in the + * HAL state block for later use. Hardware register accesses are done + * using the specified bus tag and handle. On successful return a + * reference to a state block is returned that must be supplied in all + * subsequent HAL calls. Storage associated with this reference is + * dynamically allocated and must be freed by calling the ah_detach + * method when the client is done. If the attach operation fails a + * null (AH_NULL) reference will be returned and a status code will + * be returned if the status parameter is non-zero. + */ +extern struct ath_hal * __ahdecl ath_hal_attach(uint16_t devid, HAL_SOFTC, + HAL_BUS_TAG, HAL_BUS_HANDLE, HAL_STATUS* status); + +/* + * Return a list of channels available for use with the hardware. + * The list is based on what the hardware is capable of, the specified + * country code, the modeSelect mask, and whether or not outdoor + * channels are to be permitted. + * + * The channel list is returned in the supplied array. maxchans + * defines the maximum size of this array. nchans contains the actual + * number of channels returned. If a problem occurred or there were + * no channels that met the criteria then AH_FALSE is returned. + */ +extern HAL_BOOL __ahdecl ath_hal_init_channels(struct ath_hal *, + HAL_CHANNEL *chans, u_int maxchans, u_int *nchans, + uint8_t *regclassids, u_int maxregids, u_int *nregids, + HAL_CTRY_CODE cc, u_int modeSelect, + HAL_BOOL enableOutdoor, HAL_BOOL enableExtendedChannels); + +/* + * Calibrate noise floor data following a channel scan or similar. + * This must be called prior retrieving noise floor data. + */ +extern void __ahdecl ath_hal_process_noisefloor(struct ath_hal *ah); + +/* + * Return bit mask of wireless modes supported by the hardware. + */ +extern u_int __ahdecl ath_hal_getwirelessmodes(struct ath_hal*, HAL_CTRY_CODE); + +/* + * Calculate the transmit duration of a frame. + */ +extern uint16_t __ahdecl ath_hal_computetxtime(struct ath_hal *, + const HAL_RATE_TABLE *rates, uint32_t frameLen, + uint16_t rateix, HAL_BOOL shortPreamble); + +/* + * Return if device is public safety. + */ +extern HAL_BOOL __ahdecl ath_hal_ispublicsafetysku(struct ath_hal *); + +/* + * Return if device is operating in 900 MHz band. + */ +extern HAL_BOOL ath_hal_isgsmsku(struct ath_hal *); + +/* + * Convert between IEEE channel number and channel frequency + * using the specified channel flags; e.g. CHANNEL_2GHZ. + */ +extern int __ahdecl ath_hal_mhz2ieee(struct ath_hal *, u_int mhz, u_int flags); +#endif /* _ATH_AH_H_ */ --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ah.c 2009-03-23 17:36:56.000000000 +0000 @@ -0,0 +1,887 @@ +/* + * 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: ah.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" + +/* linker set of registered chips */ +OS_SET_DECLARE(ah_chips, struct ath_hal_chip); + +/* + * Check the set of registered chips to see if any recognize + * the device as one they can support. + */ +const char* +ath_hal_probe(uint16_t vendorid, uint16_t devid) +{ + struct ath_hal_chip * const *pchip; + + OS_SET_FOREACH(pchip, ah_chips) { + const char *name = (*pchip)->probe(vendorid, devid); + if (name != AH_NULL) + return name; + } + return AH_NULL; +} + +/* + * Attach detects device chip revisions, initializes the hwLayer + * function list, reads EEPROM information, + * selects reset vectors, and performs a short self test. + * Any failures will return an error that should cause a hardware + * disable. + */ +struct ath_hal* +ath_hal_attach(uint16_t devid, HAL_SOFTC sc, + HAL_BUS_TAG st, HAL_BUS_HANDLE sh, HAL_STATUS *error) +{ + struct ath_hal_chip * const *pchip; + + OS_SET_FOREACH(pchip, ah_chips) { + struct ath_hal_chip *chip = *pchip; + struct ath_hal *ah; + + /* XXX don't have vendorid, assume atheros one works */ + if (chip->probe(ATHEROS_VENDOR_ID, devid) == AH_NULL) + continue; + ah = chip->attach(devid, sc, st, sh, error); + if (ah != AH_NULL) { + /* copy back private state to public area */ + ah->ah_devid = AH_PRIVATE(ah)->ah_devid; + ah->ah_subvendorid = AH_PRIVATE(ah)->ah_subvendorid; + ah->ah_macVersion = AH_PRIVATE(ah)->ah_macVersion; + ah->ah_macRev = AH_PRIVATE(ah)->ah_macRev; + ah->ah_phyRev = AH_PRIVATE(ah)->ah_phyRev; + ah->ah_analog5GhzRev = AH_PRIVATE(ah)->ah_analog5GhzRev; + ah->ah_analog2GhzRev = AH_PRIVATE(ah)->ah_analog2GhzRev; + return ah; + } + } + return AH_NULL; +} + +/* linker set of registered RF backends */ +OS_SET_DECLARE(ah_rfs, struct ath_hal_rf); + +/* + * Check the set of registered RF backends to see if + * any recognize the device as one they can support. + */ +struct ath_hal_rf * +ath_hal_rfprobe(struct ath_hal *ah, HAL_STATUS *ecode) +{ +#ifdef AH_HAS_RF + struct ath_hal_rf * const *prf; + + OS_SET_FOREACH(prf, ah_rfs) { + struct ath_hal_rf *rf = *prf; + if (rf->probe(ah)) + return rf; + } + *ecode = HAL_ENOTSUPP; +#endif + return AH_NULL; +} + +/* + * Poll the register looking for a specific value. + */ +HAL_BOOL +ath_hal_wait(struct ath_hal *ah, u_int reg, uint32_t mask, uint32_t val) +{ +#define AH_TIMEOUT 1000 + int i; + + for (i = 0; i < AH_TIMEOUT; i++) { + if ((OS_REG_READ(ah, reg) & mask) == val) + return AH_TRUE; + OS_DELAY(10); + } + HALDEBUG(ah, HAL_DEBUG_REGIO | HAL_DEBUG_PHYIO, + "%s: timeout on reg 0x%x: 0x%08x & 0x%08x != 0x%08x\n", + __func__, reg, OS_REG_READ(ah, reg), mask, val); + return AH_FALSE; +#undef AH_TIMEOUT +} + +/* + * Reverse the bits starting at the low bit for a value of + * bit_count in size + */ +uint32_t +ath_hal_reverseBits(uint32_t val, uint32_t n) +{ + uint32_t retval; + int i; + + for (i = 0, retval = 0; i < n; i++) { + retval = (retval << 1) | (val & 1); + val >>= 1; + } + return retval; +} + +/* + * Compute the time to transmit a frame of length frameLen bytes + * using the specified rate, phy, and short preamble setting. + */ +uint16_t +ath_hal_computetxtime(struct ath_hal *ah, + const HAL_RATE_TABLE *rates, uint32_t frameLen, uint16_t rateix, + HAL_BOOL shortPreamble) +{ + uint32_t bitsPerSymbol, numBits, numSymbols, phyTime, txTime; + uint32_t kbps; + + kbps = rates->info[rateix].rateKbps; + /* + * index can be invalid duting dynamic Turbo transitions. + */ + if(kbps == 0) return 0; + switch (rates->info[rateix].phy) { + + case IEEE80211_T_CCK: +#define CCK_SIFS_TIME 10 +#define CCK_PREAMBLE_BITS 144 +#define CCK_PLCP_BITS 48 + phyTime = CCK_PREAMBLE_BITS + CCK_PLCP_BITS; + if (shortPreamble && rates->info[rateix].shortPreamble) + phyTime >>= 1; + numBits = frameLen << 3; + txTime = CCK_SIFS_TIME + phyTime + + ((numBits * 1000)/kbps); + break; +#undef CCK_SIFS_TIME +#undef CCK_PREAMBLE_BITS +#undef CCK_PLCP_BITS + + case IEEE80211_T_OFDM: +#define OFDM_SIFS_TIME 16 +#define OFDM_PREAMBLE_TIME 20 +#define OFDM_PLCP_BITS 22 +#define OFDM_SYMBOL_TIME 4 + +#define OFDM_SIFS_TIME_HALF 32 +#define OFDM_PREAMBLE_TIME_HALF 40 +#define OFDM_PLCP_BITS_HALF 22 +#define OFDM_SYMBOL_TIME_HALF 8 + +#define OFDM_SIFS_TIME_QUARTER 64 +#define OFDM_PREAMBLE_TIME_QUARTER 80 +#define OFDM_PLCP_BITS_QUARTER 22 +#define OFDM_SYMBOL_TIME_QUARTER 16 + + if (AH_PRIVATE(ah)->ah_curchan && + IS_CHAN_QUARTER_RATE(AH_PRIVATE(ah)->ah_curchan)) { + bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME_QUARTER) / 1000; + HALASSERT(bitsPerSymbol != 0); + + numBits = OFDM_PLCP_BITS + (frameLen << 3); + numSymbols = howmany(numBits, bitsPerSymbol); + txTime = OFDM_SIFS_TIME_QUARTER + + OFDM_PREAMBLE_TIME_QUARTER + + (numSymbols * OFDM_SYMBOL_TIME_QUARTER); + } else if (AH_PRIVATE(ah)->ah_curchan && + IS_CHAN_HALF_RATE(AH_PRIVATE(ah)->ah_curchan)) { + bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME_HALF) / 1000; + HALASSERT(bitsPerSymbol != 0); + + numBits = OFDM_PLCP_BITS + (frameLen << 3); + numSymbols = howmany(numBits, bitsPerSymbol); + txTime = OFDM_SIFS_TIME_HALF + + OFDM_PREAMBLE_TIME_HALF + + (numSymbols * OFDM_SYMBOL_TIME_HALF); + } else { /* full rate channel */ + bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME) / 1000; + HALASSERT(bitsPerSymbol != 0); + + numBits = OFDM_PLCP_BITS + (frameLen << 3); + numSymbols = howmany(numBits, bitsPerSymbol); + txTime = OFDM_SIFS_TIME + OFDM_PREAMBLE_TIME + + (numSymbols * OFDM_SYMBOL_TIME); + } + break; + +#undef OFDM_SIFS_TIME +#undef OFDM_PREAMBLE_TIME +#undef OFDM_PLCP_BITS +#undef OFDM_SYMBOL_TIME + + case IEEE80211_T_TURBO: +#define TURBO_SIFS_TIME 8 +#define TURBO_PREAMBLE_TIME 14 +#define TURBO_PLCP_BITS 22 +#define TURBO_SYMBOL_TIME 4 + /* we still save OFDM rates in kbps - so double them */ + bitsPerSymbol = ((kbps << 1) * TURBO_SYMBOL_TIME) / 1000; + HALASSERT(bitsPerSymbol != 0); + + numBits = TURBO_PLCP_BITS + (frameLen << 3); + numSymbols = howmany(numBits, bitsPerSymbol); + txTime = TURBO_SIFS_TIME + TURBO_PREAMBLE_TIME + + (numSymbols * TURBO_SYMBOL_TIME); + break; +#undef TURBO_SIFS_TIME +#undef TURBO_PREAMBLE_TIME +#undef TURBO_PLCP_BITS +#undef TURBO_SYMBOL_TIME + + default: + HALDEBUG(ah, HAL_DEBUG_PHYIO, + "%s: unknown phy %u (rate ix %u)\n", + __func__, rates->info[rateix].phy, rateix); + txTime = 0; + break; + } + return txTime; +} + +static __inline int +mapgsm(u_int freq, u_int flags) +{ + freq *= 10; + if (flags & CHANNEL_QUARTER) + freq += 5; + else if (flags & CHANNEL_HALF) + freq += 10; + else + freq += 20; + return (freq - 24220) / 5; +} + +static __inline int +mappsb(u_int freq, u_int flags) +{ + return ((freq * 10) + (((freq % 5) == 2) ? 5 : 0) - 49400) / 5; +} + +/* + * Convert GHz frequency to IEEE channel number. + */ +int +ath_hal_mhz2ieee(struct ath_hal *ah, u_int freq, u_int flags) +{ + if (flags & CHANNEL_2GHZ) { /* 2GHz band */ + if (freq == 2484) + return 14; + if (freq < 2484) { + if (ath_hal_isgsmsku(ah)) + return mapgsm(freq, flags); + return ((int)freq - 2407) / 5; + } else + return 15 + ((freq - 2512) / 20); + } else if (flags & CHANNEL_5GHZ) {/* 5Ghz band */ + if (ath_hal_ispublicsafetysku(ah) && + IS_CHAN_IN_PUBLIC_SAFETY_BAND(freq)) { + return mappsb(freq, flags); + } else if ((flags & CHANNEL_A) && (freq <= 5000)) { + return (freq - 4000) / 5; + } else { + return (freq - 5000) / 5; + } + } else { /* either, guess */ + if (freq == 2484) + return 14; + if (freq < 2484) { + if (ath_hal_isgsmsku(ah)) + return mapgsm(freq, flags); + return ((int)freq - 2407) / 5; + } + if (freq < 5000) { + if (ath_hal_ispublicsafetysku(ah) && + IS_CHAN_IN_PUBLIC_SAFETY_BAND(freq)) { + return mappsb(freq, flags); + } else if (freq > 4900) { + return (freq - 4000) / 5; + } else { + return 15 + ((freq - 2512) / 20); + } + } + return (freq - 5000) / 5; + } +} + +typedef enum { + WIRELESS_MODE_11a = 0, + WIRELESS_MODE_TURBO = 1, + WIRELESS_MODE_11b = 2, + WIRELESS_MODE_11g = 3, + WIRELESS_MODE_108g = 4, + + WIRELESS_MODE_MAX +} WIRELESS_MODE; + +static WIRELESS_MODE +ath_hal_chan2wmode(struct ath_hal *ah, const HAL_CHANNEL *chan) +{ + if (IS_CHAN_CCK(chan)) + return WIRELESS_MODE_11b; + if (IS_CHAN_G(chan)) + return WIRELESS_MODE_11g; + if (IS_CHAN_108G(chan)) + return WIRELESS_MODE_108g; + if (IS_CHAN_TURBO(chan)) + return WIRELESS_MODE_TURBO; + return WIRELESS_MODE_11a; +} + +/* + * Convert between microseconds and core system clocks. + */ + /* 11a Turbo 11b 11g 108g */ +static const uint8_t CLOCK_RATE[] = { 40, 80, 22, 44, 88 }; + +u_int +ath_hal_mac_clks(struct ath_hal *ah, u_int usecs) +{ + const HAL_CHANNEL *c = (const HAL_CHANNEL *) AH_PRIVATE(ah)->ah_curchan; + u_int clks; + + /* NB: ah_curchan may be null when called attach time */ + if (c != AH_NULL) { + clks = usecs * CLOCK_RATE[ath_hal_chan2wmode(ah, c)]; + if (IS_CHAN_HT40(c)) + clks <<= 1; + else if (IS_CHAN_HALF_RATE(c)) + clks >>= 1; + else if (IS_CHAN_QUARTER_RATE(c)) + clks >>= 2; + } else + clks = usecs * CLOCK_RATE[WIRELESS_MODE_11b]; + return clks; +} + +u_int +ath_hal_mac_usec(struct ath_hal *ah, u_int clks) +{ + const HAL_CHANNEL *c = (const HAL_CHANNEL *) AH_PRIVATE(ah)->ah_curchan; + u_int usec; + + /* NB: ah_curchan may be null when called attach time */ + if (c != AH_NULL) { + usec = clks / CLOCK_RATE[ath_hal_chan2wmode(ah, c)]; + if (IS_CHAN_HT40(c)) + usec >>= 1; + else if (IS_CHAN_HALF_RATE(c)) + usec <<= 1; + else if (IS_CHAN_QUARTER_RATE(c)) + usec <<= 2; + } else + usec = clks / CLOCK_RATE[WIRELESS_MODE_11b]; + return usec; +} + +/* + * Setup a h/w rate table's reverse lookup table and + * fill in ack durations. This routine is called for + * each rate table returned through the ah_getRateTable + * method. The reverse lookup tables are assumed to be + * initialized to zero (or at least the first entry). + * We use this as a key that indicates whether or not + * we've previously setup the reverse lookup table. + * + * XXX not reentrant, but shouldn't matter + */ +void +ath_hal_setupratetable(struct ath_hal *ah, HAL_RATE_TABLE *rt) +{ +#define N(a) (sizeof(a)/sizeof(a[0])) + int i; + + if (rt->rateCodeToIndex[0] != 0) /* already setup */ + return; + for (i = 0; i < N(rt->rateCodeToIndex); i++) + rt->rateCodeToIndex[i] = (uint8_t) -1; + for (i = 0; i < rt->rateCount; i++) { + uint8_t code = rt->info[i].rateCode; + uint8_t cix = rt->info[i].controlRate; + + HALASSERT(code < N(rt->rateCodeToIndex)); + rt->rateCodeToIndex[code] = i; + HALASSERT((code | rt->info[i].shortPreamble) < + N(rt->rateCodeToIndex)); + rt->rateCodeToIndex[code | rt->info[i].shortPreamble] = i; + /* + * XXX for 11g the control rate to use for 5.5 and 11 Mb/s + * depends on whether they are marked as basic rates; + * the static tables are setup with an 11b-compatible + * 2Mb/s rate which will work but is suboptimal + */ + rt->info[i].lpAckDuration = ath_hal_computetxtime(ah, rt, + WLAN_CTRL_FRAME_SIZE, cix, AH_FALSE); + rt->info[i].spAckDuration = ath_hal_computetxtime(ah, rt, + WLAN_CTRL_FRAME_SIZE, cix, AH_TRUE); + } +#undef N +} + +HAL_STATUS +ath_hal_getcapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, + uint32_t capability, uint32_t *result) +{ + const HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps; + + switch (type) { + case HAL_CAP_REG_DMN: /* regulatory domain */ + *result = AH_PRIVATE(ah)->ah_currentRD; + return HAL_OK; + case HAL_CAP_CIPHER: /* cipher handled in hardware */ + case HAL_CAP_TKIP_MIC: /* handle TKIP MIC in hardware */ + return HAL_ENOTSUPP; + case HAL_CAP_TKIP_SPLIT: /* hardware TKIP uses split keys */ + return HAL_ENOTSUPP; + case HAL_CAP_PHYCOUNTERS: /* hardware PHY error counters */ + return pCap->halHwPhyCounterSupport ? HAL_OK : HAL_ENXIO; + case HAL_CAP_WME_TKIPMIC: /* hardware can do TKIP MIC when WMM is turned on */ + return HAL_ENOTSUPP; + case HAL_CAP_DIVERSITY: /* hardware supports fast diversity */ + return HAL_ENOTSUPP; + case HAL_CAP_KEYCACHE_SIZE: /* hardware key cache size */ + *result = pCap->halKeyCacheSize; + return HAL_OK; + case HAL_CAP_NUM_TXQUEUES: /* number of hardware tx queues */ + *result = pCap->halTotalQueues; + return HAL_OK; + case HAL_CAP_VEOL: /* hardware supports virtual EOL */ + return pCap->halVEOLSupport ? HAL_OK : HAL_ENOTSUPP; + case HAL_CAP_PSPOLL: /* hardware PS-Poll support works */ + return pCap->halPSPollBroken ? HAL_ENOTSUPP : HAL_OK; + case HAL_CAP_COMPRESSION: + return pCap->halCompressSupport ? HAL_OK : HAL_ENOTSUPP; + case HAL_CAP_BURST: + return pCap->halBurstSupport ? HAL_OK : HAL_ENOTSUPP; + case HAL_CAP_FASTFRAME: + return pCap->halFastFramesSupport ? HAL_OK : HAL_ENOTSUPP; + case HAL_CAP_DIAG: /* hardware diagnostic support */ + *result = AH_PRIVATE(ah)->ah_diagreg; + return HAL_OK; + case HAL_CAP_TXPOW: /* global tx power limit */ + switch (capability) { + case 0: /* facility is supported */ + return HAL_OK; + case 1: /* current limit */ + *result = AH_PRIVATE(ah)->ah_powerLimit; + return HAL_OK; + case 2: /* current max tx power */ + *result = AH_PRIVATE(ah)->ah_maxPowerLevel; + return HAL_OK; + case 3: /* scale factor */ + *result = AH_PRIVATE(ah)->ah_tpScale; + return HAL_OK; + } + return HAL_ENOTSUPP; + case HAL_CAP_BSSIDMASK: /* hardware supports bssid mask */ + return pCap->halBssIdMaskSupport ? HAL_OK : HAL_ENOTSUPP; + case HAL_CAP_MCAST_KEYSRCH: /* multicast frame keycache search */ + return pCap->halMcastKeySrchSupport ? HAL_OK : HAL_ENOTSUPP; + case HAL_CAP_TSF_ADJUST: /* hardware has beacon tsf adjust */ + return HAL_ENOTSUPP; + case HAL_CAP_RFSILENT: /* rfsilent support */ + switch (capability) { + case 0: /* facility is supported */ + return pCap->halRfSilentSupport ? HAL_OK : HAL_ENOTSUPP; + case 1: /* current setting */ + return AH_PRIVATE(ah)->ah_rfkillEnabled ? + HAL_OK : HAL_ENOTSUPP; + case 2: /* rfsilent config */ + *result = AH_PRIVATE(ah)->ah_rfsilent; + return HAL_OK; + } + return HAL_ENOTSUPP; + case HAL_CAP_11D: +#ifdef AH_SUPPORT_11D + return HAL_OK; +#else + return HAL_ENOTSUPP; +#endif + case HAL_CAP_RXORN_FATAL: /* HAL_INT_RXORN treated as fatal */ + return AH_PRIVATE(ah)->ah_rxornIsFatal ? HAL_OK : HAL_ENOTSUPP; + case HAL_CAP_HT: + return pCap->halHTSupport ? HAL_OK : HAL_ENOTSUPP; + case HAL_CAP_TX_CHAINMASK: /* mask of TX chains supported */ + *result = pCap->halTxChainMask; + return HAL_OK; + case HAL_CAP_RX_CHAINMASK: /* mask of RX chains supported */ + *result = pCap->halRxChainMask; + return HAL_OK; + case HAL_CAP_RXTSTAMP_PREC: /* rx desc tstamp precision (bits) */ + *result = pCap->halTstampPrecision; + return HAL_OK; + default: + return HAL_EINVAL; + } +} + +HAL_BOOL +ath_hal_setcapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, + uint32_t capability, uint32_t setting, HAL_STATUS *status) +{ + + switch (type) { + case HAL_CAP_TXPOW: + switch (capability) { + case 3: + if (setting <= HAL_TP_SCALE_MIN) { + AH_PRIVATE(ah)->ah_tpScale = setting; + return AH_TRUE; + } + break; + } + break; + case HAL_CAP_RFSILENT: /* rfsilent support */ + /* + * NB: allow even if halRfSilentSupport is false + * in case the EEPROM is misprogrammed. + */ + switch (capability) { + case 1: /* current setting */ + AH_PRIVATE(ah)->ah_rfkillEnabled = (setting != 0); + return AH_TRUE; + case 2: /* rfsilent config */ + /* XXX better done per-chip for validation? */ + AH_PRIVATE(ah)->ah_rfsilent = setting; + return AH_TRUE; + } + break; + case HAL_CAP_REG_DMN: /* regulatory domain */ + AH_PRIVATE(ah)->ah_currentRD = setting; + return AH_TRUE; + case HAL_CAP_RXORN_FATAL: /* HAL_INT_RXORN treated as fatal */ + AH_PRIVATE(ah)->ah_rxornIsFatal = setting; + return AH_TRUE; + default: + break; + } + if (status) + *status = HAL_EINVAL; + return AH_FALSE; +} + +/* + * Common support for getDiagState method. + */ + +static u_int +ath_hal_getregdump(struct ath_hal *ah, const HAL_REGRANGE *regs, + void *dstbuf, int space) +{ + uint32_t *dp = dstbuf; + int i; + + for (i = 0; space >= 2*sizeof(uint32_t); i++) { + u_int r = regs[i].start; + u_int e = regs[i].end; + *dp++ = (r<<16) | e; + space -= sizeof(uint32_t); + do { + *dp++ = OS_REG_READ(ah, r); + r += sizeof(uint32_t); + space -= sizeof(uint32_t); + } while (r <= e && space >= sizeof(uint32_t)); + } + return (char *) dp - (char *) dstbuf; +} + +HAL_BOOL +ath_hal_getdiagstate(struct ath_hal *ah, int request, + const void *args, uint32_t argsize, + void **result, uint32_t *resultsize) +{ + switch (request) { + case HAL_DIAG_REVS: + *result = &AH_PRIVATE(ah)->ah_devid; + *resultsize = sizeof(HAL_REVS); + return AH_TRUE; + case HAL_DIAG_REGS: + *resultsize = ath_hal_getregdump(ah, args, *result,*resultsize); + return AH_TRUE; + case HAL_DIAG_FATALERR: + *result = &AH_PRIVATE(ah)->ah_fatalState[0]; + *resultsize = sizeof(AH_PRIVATE(ah)->ah_fatalState); + return AH_TRUE; + case HAL_DIAG_EEREAD: + if (argsize != sizeof(uint16_t)) + return AH_FALSE; + if (!ath_hal_eepromRead(ah, *(const uint16_t *)args, *result)) + return AH_FALSE; + *resultsize = sizeof(uint16_t); + return AH_TRUE; +#ifdef AH_PRIVATE_DIAG + case HAL_DIAG_SETKEY: { + const HAL_DIAG_KEYVAL *dk; + + if (argsize != sizeof(HAL_DIAG_KEYVAL)) + return AH_FALSE; + dk = (const HAL_DIAG_KEYVAL *)args; + return ah->ah_setKeyCacheEntry(ah, dk->dk_keyix, + &dk->dk_keyval, dk->dk_mac, dk->dk_xor); + } + case HAL_DIAG_RESETKEY: + if (argsize != sizeof(uint16_t)) + return AH_FALSE; + return ah->ah_resetKeyCacheEntry(ah, *(const uint16_t *)args); +#ifdef AH_SUPPORT_WRITE_EEPROM + case HAL_DIAG_EEWRITE: { + const HAL_DIAG_EEVAL *ee; + if (argsize != sizeof(HAL_DIAG_EEVAL)) + return AH_FALSE; + ee = (const HAL_DIAG_EEVAL *)args; + return ath_hal_eepromWrite(ah, ee->ee_off, ee->ee_data); + } +#endif /* AH_SUPPORT_WRITE_EEPROM */ +#endif /* AH_PRIVATE_DIAG */ + case HAL_DIAG_11NCOMPAT: + if (argsize == 0) { + *resultsize = sizeof(uint32_t); + *((uint32_t *)(*result)) = + AH_PRIVATE(ah)->ah_11nCompat; + } else if (argsize == sizeof(uint32_t)) { + AH_PRIVATE(ah)->ah_11nCompat = *(const uint32_t *)args; + } else + return AH_FALSE; + return AH_TRUE; + } + return AH_FALSE; +} + +/* + * Set the properties of the tx queue with the parameters + * from qInfo. + */ +HAL_BOOL +ath_hal_setTxQProps(struct ath_hal *ah, + HAL_TX_QUEUE_INFO *qi, const HAL_TXQ_INFO *qInfo) +{ + uint32_t cw; + + if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) { + HALDEBUG(ah, HAL_DEBUG_TXQUEUE, + "%s: inactive queue\n", __func__); + return AH_FALSE; + } + /* XXX validate parameters */ + qi->tqi_ver = qInfo->tqi_ver; + qi->tqi_subtype = qInfo->tqi_subtype; + qi->tqi_qflags = qInfo->tqi_qflags; + qi->tqi_priority = qInfo->tqi_priority; + if (qInfo->tqi_aifs != HAL_TXQ_USEDEFAULT) + qi->tqi_aifs = AH_MIN(qInfo->tqi_aifs, 255); + else + qi->tqi_aifs = INIT_AIFS; + if (qInfo->tqi_cwmin != HAL_TXQ_USEDEFAULT) { + cw = AH_MIN(qInfo->tqi_cwmin, 1024); + /* make sure that the CWmin is of the form (2^n - 1) */ + qi->tqi_cwmin = 1; + while (qi->tqi_cwmin < cw) + qi->tqi_cwmin = (qi->tqi_cwmin << 1) | 1; + } else + qi->tqi_cwmin = qInfo->tqi_cwmin; + if (qInfo->tqi_cwmax != HAL_TXQ_USEDEFAULT) { + cw = AH_MIN(qInfo->tqi_cwmax, 1024); + /* make sure that the CWmax is of the form (2^n - 1) */ + qi->tqi_cwmax = 1; + while (qi->tqi_cwmax < cw) + qi->tqi_cwmax = (qi->tqi_cwmax << 1) | 1; + } else + qi->tqi_cwmax = INIT_CWMAX; + /* Set retry limit values */ + if (qInfo->tqi_shretry != 0) + qi->tqi_shretry = AH_MIN(qInfo->tqi_shretry, 15); + else + qi->tqi_shretry = INIT_SH_RETRY; + if (qInfo->tqi_lgretry != 0) + qi->tqi_lgretry = AH_MIN(qInfo->tqi_lgretry, 15); + else + qi->tqi_lgretry = INIT_LG_RETRY; + qi->tqi_cbrPeriod = qInfo->tqi_cbrPeriod; + qi->tqi_cbrOverflowLimit = qInfo->tqi_cbrOverflowLimit; + qi->tqi_burstTime = qInfo->tqi_burstTime; + qi->tqi_readyTime = qInfo->tqi_readyTime; + + switch (qInfo->tqi_subtype) { + case HAL_WME_UPSD: + if (qi->tqi_type == HAL_TX_QUEUE_DATA) + qi->tqi_intFlags = HAL_TXQ_USE_LOCKOUT_BKOFF_DIS; + break; + default: + break; /* NB: silence compiler */ + } + return AH_TRUE; +} + +HAL_BOOL +ath_hal_getTxQProps(struct ath_hal *ah, + HAL_TXQ_INFO *qInfo, const HAL_TX_QUEUE_INFO *qi) +{ + if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) { + HALDEBUG(ah, HAL_DEBUG_TXQUEUE, + "%s: inactive queue\n", __func__); + return AH_FALSE; + } + + qInfo->tqi_qflags = qi->tqi_qflags; + qInfo->tqi_ver = qi->tqi_ver; + qInfo->tqi_subtype = qi->tqi_subtype; + qInfo->tqi_qflags = qi->tqi_qflags; + qInfo->tqi_priority = qi->tqi_priority; + qInfo->tqi_aifs = qi->tqi_aifs; + qInfo->tqi_cwmin = qi->tqi_cwmin; + qInfo->tqi_cwmax = qi->tqi_cwmax; + qInfo->tqi_shretry = qi->tqi_shretry; + qInfo->tqi_lgretry = qi->tqi_lgretry; + qInfo->tqi_cbrPeriod = qi->tqi_cbrPeriod; + qInfo->tqi_cbrOverflowLimit = qi->tqi_cbrOverflowLimit; + qInfo->tqi_burstTime = qi->tqi_burstTime; + qInfo->tqi_readyTime = qi->tqi_readyTime; + return AH_TRUE; +} + + /* 11a Turbo 11b 11g 108g */ +static const int16_t NOISE_FLOOR[] = { -96, -93, -98, -96, -93 }; + +/* + * Read the current channel noise floor and return. + * If nf cal hasn't finished, channel noise floor should be 0 + * and we return a nominal value based on band and frequency. + * + * NB: This is a private routine used by per-chip code to + * implement the ah_getChanNoise method. + */ +int16_t +ath_hal_getChanNoise(struct ath_hal *ah, HAL_CHANNEL *chan) +{ + HAL_CHANNEL_INTERNAL *ichan; + + ichan = ath_hal_checkchannel(ah, chan); + if (ichan == AH_NULL) { + HALDEBUG(ah, HAL_DEBUG_NFCAL, + "%s: invalid channel %u/0x%x; no mapping\n", + __func__, chan->channel, chan->channelFlags); + return 0; + } + if (ichan->rawNoiseFloor == 0) { + WIRELESS_MODE mode = ath_hal_chan2wmode(ah, chan); + + HALASSERT(mode < WIRELESS_MODE_MAX); + return NOISE_FLOOR[mode] + ath_hal_getNfAdjust(ah, ichan); + } else + return ichan->rawNoiseFloor + ichan->noiseFloorAdjust; +} + +/* + * Process all valid raw noise floors into the dBm noise floor values. + * Though our device has no reference for a dBm noise floor, we perform + * a relative minimization of NF's based on the lowest NF found across a + * channel scan. + */ +void +ath_hal_process_noisefloor(struct ath_hal *ah) +{ + HAL_CHANNEL_INTERNAL *c; + int16_t correct2, correct5; + int16_t lowest2, lowest5; + int i; + + /* + * Find the lowest 2GHz and 5GHz noise floor values after adjusting + * for statistically recorded NF/channel deviation. + */ + correct2 = lowest2 = 0; + correct5 = lowest5 = 0; + for (i = 0; i < AH_PRIVATE(ah)->ah_nchan; i++) { + WIRELESS_MODE mode; + int16_t nf; + + c = &AH_PRIVATE(ah)->ah_channels[i]; + if (c->rawNoiseFloor >= 0) + continue; + mode = ath_hal_chan2wmode(ah, (HAL_CHANNEL *) c); + HALASSERT(mode < WIRELESS_MODE_MAX); + nf = c->rawNoiseFloor + NOISE_FLOOR[mode] + + ath_hal_getNfAdjust(ah, c); + if (IS_CHAN_5GHZ(c)) { + if (nf < lowest5) { + lowest5 = nf; + correct5 = NOISE_FLOOR[mode] - + (c->rawNoiseFloor + ath_hal_getNfAdjust(ah, c)); + } + } else { + if (nf < lowest2) { + lowest2 = nf; + correct2 = NOISE_FLOOR[mode] - + (c->rawNoiseFloor + ath_hal_getNfAdjust(ah, c)); + } + } + } + + /* Correct the channels to reach the expected NF value */ + for (i = 0; i < AH_PRIVATE(ah)->ah_nchan; i++) { + c = &AH_PRIVATE(ah)->ah_channels[i]; + if (c->rawNoiseFloor >= 0) + continue; + /* Apply correction factor */ + c->noiseFloorAdjust = ath_hal_getNfAdjust(ah, c) + + (IS_CHAN_5GHZ(c) ? correct5 : correct2); + HALDEBUG(ah, HAL_DEBUG_NFCAL, "%u/0x%x raw nf %d adjust %d\n", + c->channel, c->channelFlags, c->rawNoiseFloor, + c->noiseFloorAdjust); + } +} + +/* + * INI support routines. + */ + +int +ath_hal_ini_write(struct ath_hal *ah, const HAL_INI_ARRAY *ia, + int col, int regWr) +{ + int r; + + for (r = 0; r < ia->rows; r++) { + OS_REG_WRITE(ah, HAL_INI_VAL(ia, r, 0), + HAL_INI_VAL(ia, r, col)); + DMA_YIELD(regWr); + } + return regWr; +} + +void +ath_hal_ini_bank_setup(uint32_t data[], const HAL_INI_ARRAY *ia, int col) +{ + int r; + + for (r = 0; r < ia->rows; r++) + data[r] = HAL_INI_VAL(ia, r, col); +} + +int +ath_hal_ini_bank_write(struct ath_hal *ah, const HAL_INI_ARRAY *ia, + const uint32_t data[], int regWr) +{ + int r; + + for (r = 0; r < ia->rows; r++) { + OS_REG_WRITE(ah, HAL_INI_VAL(ia, r, 0), data[r]); + DMA_YIELD(regWr); + } + return regWr; +} --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/dist/ah_desc.h 2009-03-23 17:36:56.000000000 +0000 @@ -0,0 +1,217 @@ +/* + * 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: ah_desc.h,v 1.1 2009/03/23 17:14:47 sborrill Exp $ + */ + +#ifndef _DEV_ATH_DESC_H +#define _DEV_ATH_DESC_H + +#include "opt_ah.h" /* NB: required for AH_SUPPORT_AR5416 */ + +/* + * Transmit descriptor status. This structure is filled + * in only after the tx descriptor process method finds a + * ``done'' descriptor; at which point it returns something + * other than HAL_EINPROGRESS. + * + * Note that ts_antenna may not be valid for all h/w. It + * should be used only if non-zero. + */ +struct ath_tx_status { + uint16_t ts_seqnum; /* h/w assigned sequence number */ + uint16_t ts_tstamp; /* h/w assigned timestamp */ + uint8_t ts_status; /* frame status, 0 => xmit ok */ + uint8_t ts_rate; /* h/w transmit rate index */ +#define HAL_TXSTAT_ALTRATE 0x80 /* alternate xmit rate used */ + int8_t ts_rssi; /* tx ack RSSI */ + uint8_t ts_shortretry; /* # short retries */ + uint8_t ts_longretry; /* # long retries */ + uint8_t ts_virtcol; /* virtual collision count */ + uint8_t ts_antenna; /* antenna information */ + uint8_t ts_finaltsi; /* final transmit series index */ +#ifdef AH_SUPPORT_AR5416 + /* 802.11n status */ + uint8_t ts_flags; /* misc flags */ + int8_t ts_rssi_ctl[3]; /* tx ack RSSI [ctl, chain 0-2] */ + int8_t ts_rssi_ext[3]; /* tx ack RSSI [ext, chain 0-2] */ +/* #define ts_rssi ts_rssi_combined */ + uint32_t ts_ba_low; /* blockack bitmap low */ + uint32_t ts_ba_high; /* blockack bitmap high */ + uint32_t ts_evm0; /* evm bytes */ + uint32_t ts_evm1; + uint32_t ts_evm2; +#endif /* AH_SUPPORT_AR5416 */ +}; + +/* bits found in ts_status */ +#define HAL_TXERR_XRETRY 0x01 /* excessive retries */ +#define HAL_TXERR_FILT 0x02 /* blocked by tx filtering */ +#define HAL_TXERR_FIFO 0x04 /* fifo underrun */ +#define HAL_TXERR_XTXOP 0x08 /* txop exceeded */ +#define HAL_TXERR_TIMER_EXPIRED 0x10 /* Tx timer expired */ + +/* bits found in ts_flags */ +#define HAL_TX_BA 0x01 /* Block Ack seen */ +#define HAL_TX_AGGR 0x02 /* Aggregate */ +#define HAL_TX_DESC_CFG_ERR 0x10 /* Error in 20/40 desc config */ +#define HAL_TX_DATA_UNDERRUN 0x20 /* Tx buffer underrun */ +#define HAL_TX_DELIM_UNDERRUN 0x40 /* Tx delimiter underrun */ + +/* + * Receive descriptor status. This structure is filled + * in only after the rx descriptor process method finds a + * ``done'' descriptor; at which point it returns something + * other than HAL_EINPROGRESS. + * + * If rx_status is zero, then the frame was received ok; + * otherwise the error information is indicated and rs_phyerr + * contains a phy error code if HAL_RXERR_PHY is set. In general + * the frame contents is undefined when an error occurred thought + * for some errors (e.g. a decryption error), it may be meaningful. + * + * Note that the receive timestamp is expanded using the TSF to + * at least 15 bits (regardless of what the h/w provides directly). + * Newer hardware supports a full 32-bits; use HAL_CAP_32TSTAMP to + * find out if the hardware is capable. + * + * rx_rssi is in units of dbm above the noise floor. This value + * is measured during the preamble and PLCP; i.e. with the initial + * 4us of detection. The noise floor is typically a consistent + * -96dBm absolute power in a 20MHz channel. + */ +struct ath_rx_status { + uint16_t rs_datalen; /* rx frame length */ + uint8_t rs_status; /* rx status, 0 => recv ok */ + uint8_t rs_phyerr; /* phy error code */ + int8_t rs_rssi; /* rx frame RSSI (combined for 11n) */ + uint8_t rs_keyix; /* key cache index */ + uint8_t rs_rate; /* h/w receive rate index */ + uint8_t rs_more; /* more descriptors follow */ + uint32_t rs_tstamp; /* h/w assigned timestamp */ + uint32_t rs_antenna; /* antenna information */ +#ifdef AH_SUPPORT_AR5416 + /* 802.11n status */ + int8_t rs_rssi_ctl[3]; /* rx frame RSSI [ctl, chain 0-2] */ + int8_t rs_rssi_ext[3]; /* rx frame RSSI [ext, chain 0-2] */ + uint8_t rs_isaggr; /* is part of the aggregate */ + uint8_t rs_moreaggr; /* more frames in aggr to follow */ + uint8_t rs_num_delims; /* number of delims in aggr */ + uint8_t rs_flags; /* misc flags */ + uint32_t rs_evm0; /* evm bytes */ + uint32_t rs_evm1; + uint32_t rs_evm2; +#endif /* AH_SUPPORT_AR5416 */ +}; + +/* bits found in rs_status */ +#define HAL_RXERR_CRC 0x01 /* CRC error on frame */ +#define HAL_RXERR_PHY 0x02 /* PHY error, rs_phyerr is valid */ +#define HAL_RXERR_FIFO 0x04 /* fifo overrun */ +#define HAL_RXERR_DECRYPT 0x08 /* non-Michael decrypt error */ +#define HAL_RXERR_MIC 0x10 /* Michael MIC decrypt error */ + +/* bits found in rs_flags */ +#define HAL_RX_MORE 0x01 /* more descriptors follow */ +#define HAL_RX_MORE_AGGR 0x02 /* more frames in aggr */ +#define HAL_RX_GI 0x04 /* full gi */ +#define HAL_RX_2040 0x08 /* 40 Mhz */ +#define HAL_RX_DELIM_CRC_PRE 0x10 /* crc error in delimiter pre */ +#define HAL_RX_DELIM_CRC_POST 0x20 /* crc error in delim after */ +#define HAL_RX_DECRYPT_BUSY 0x40 /* decrypt was too slow */ +#define HAL_RX_HI_RX_CHAIN 0x80 /* SM power save: hi Rx chain control */ + +enum { + HAL_PHYERR_UNDERRUN = 0, /* Transmit underrun */ + HAL_PHYERR_TIMING = 1, /* Timing error */ + HAL_PHYERR_PARITY = 2, /* Illegal parity */ + HAL_PHYERR_RATE = 3, /* Illegal rate */ + HAL_PHYERR_LENGTH = 4, /* Illegal length */ + HAL_PHYERR_RADAR = 5, /* Radar detect */ + HAL_PHYERR_SERVICE = 6, /* Illegal service */ + HAL_PHYERR_TOR = 7, /* Transmit override receive */ + /* NB: these are specific to the 5212 */ + HAL_PHYERR_OFDM_TIMING = 17, /* */ + HAL_PHYERR_OFDM_SIGNAL_PARITY = 18, /* */ + HAL_PHYERR_OFDM_RATE_ILLEGAL = 19, /* */ + HAL_PHYERR_OFDM_LENGTH_ILLEGAL = 20, /* */ + HAL_PHYERR_OFDM_POWER_DROP = 21, /* */ + HAL_PHYERR_OFDM_SERVICE = 22, /* */ + HAL_PHYERR_OFDM_RESTART = 23, /* */ + HAL_PHYERR_CCK_TIMING = 25, /* */ + HAL_PHYERR_CCK_HEADER_CRC = 26, /* */ + HAL_PHYERR_CCK_RATE_ILLEGAL = 27, /* */ + HAL_PHYERR_CCK_SERVICE = 30, /* */ + HAL_PHYERR_CCK_RESTART = 31, /* */ +}; + +/* value found in rs_keyix to mark invalid entries */ +#define HAL_RXKEYIX_INVALID ((uint8_t) -1) +/* value used to specify no encryption key for xmit */ +#define HAL_TXKEYIX_INVALID ((u_int) -1) + +/* XXX rs_antenna definitions */ + +/* + * Definitions for the software frame/packet descriptors used by + * the Atheros HAL. This definition obscures hardware-specific + * details from the driver. Drivers are expected to fillin the + * portions of a descriptor that are not opaque then use HAL calls + * to complete the work. Status for completed frames is returned + * in a device-independent format. + */ +#ifdef AH_SUPPORT_AR5416 +#define HAL_DESC_HW_SIZE 20 +#else +#define HAL_DESC_HW_SIZE 4 +#endif /* AH_SUPPORT_AR5416 */ + +struct ath_desc { + /* + * The following definitions are passed directly + * the hardware and managed by the HAL. Drivers + * should not touch those elements marked opaque. + */ + uint32_t ds_link; /* phys address of next descriptor */ + uint32_t ds_data; /* phys address of data buffer */ + uint32_t ds_ctl0; /* opaque DMA control 0 */ + uint32_t ds_ctl1; /* opaque DMA control 1 */ + uint32_t ds_hw[HAL_DESC_HW_SIZE]; /* opaque h/w region */ + union { + struct ath_tx_status tx;/* xmit status */ + struct ath_rx_status rx;/* recv status */ + } ds_us; +}; + +#define ds_txstat ds_us.tx +#define ds_rxstat ds_us.rx + +/* flags passed to tx descriptor setup methods */ +#define HAL_TXDESC_CLRDMASK 0x0001 /* clear destination filter mask */ +#define HAL_TXDESC_NOACK 0x0002 /* don't wait for ACK */ +#define HAL_TXDESC_RTSENA 0x0004 /* enable RTS */ +#define HAL_TXDESC_CTSENA 0x0008 /* enable CTS */ +#define HAL_TXDESC_INTREQ 0x0010 /* enable per-descriptor interrupt */ +#define HAL_TXDESC_VEOL 0x0020 /* mark virtual EOL */ +/* NB: this only affects frame, not any RTS/CTS */ +#define HAL_TXDESC_DURENA 0x0040 /* enable h/w write of duration field */ +#define HAL_TXDESC_EXT_ONLY 0x0080 /* send on ext channel only (11n) */ +#define HAL_TXDESC_EXT_AND_CTL 0x0100 /* send on ext + ctl channels (11n) */ +#define HAL_TXDESC_VMF 0x0200 /* virtual more frag */ + +/* flags passed to rx descriptor setup methods */ +#define HAL_RXDESC_INTREQ 0x0020 /* enable per-descriptor interrupt */ +#endif /* _DEV_ATH_DESC_H */ --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/ic/ah_osdep.c 2009-03-23 17:36:56.000000000 +0000 @@ -0,0 +1,487 @@ +/*- + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + * + * $Id: ah_osdep.c,v 1.2 2009/03/23 17:17:07 sborrill Exp $ + */ + +#include +__KERNEL_RCSID(0, "$NetBSD: ah_osdep.c,v 1.1 2008/12/11 05:37:40 alc Exp $"); + +#include "opt_athhal.h" + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include + +#ifdef __mips__ +#include + +#define ENTER lwp_t *savlwp = curlwp; curlwp = cpu_info_store.ci_curlwp; +#define EXIT curlwp = savlwp; +#else +#define ENTER /* nothing */ +#define EXIT /* nothing */ +#endif + +extern void ath_hal_printf(struct ath_hal *, const char*, ...); +extern void ath_hal_vprintf(struct ath_hal *, const char*, va_list); +extern const char* ath_hal_ether_sprintf(const u_int8_t *mac); +extern void *ath_hal_malloc(size_t); +extern void ath_hal_free(void *); +#ifdef ATHHAL_ASSERT +extern void ath_hal_assert_failed(const char* filename, + int lineno, const char* msg); +#endif +#ifdef ATHHAL_DEBUG +extern void HALDEBUG(struct ath_hal *ah, const char* fmt, ...); +extern void HALDEBUGn(struct ath_hal *ah, u_int level, const char* fmt, ...); +#endif /* ATHHAL_DEBUG */ + +#ifdef ATHHAL_DEBUG +static int ath_hal_debug = 0; +#endif /* ATHHAL_DEBUG */ + +int ath_hal_dma_beacon_response_time = 2; /* in TU's */ +int ath_hal_sw_beacon_response_time = 10; /* in TU's */ +int ath_hal_additional_swba_backoff = 0; /* in TU's */ + +SYSCTL_SETUP(sysctl_ath_hal, "sysctl ath.hal subtree setup") +{ + int rc; + const struct sysctlnode *cnode, *rnode; + + if ((rc = sysctl_createv(clog, 0, NULL, &rnode, CTLFLAG_PERMANENT, + CTLTYPE_NODE, "hw", NULL, NULL, 0, NULL, 0, CTL_HW, CTL_EOL)) != 0) + goto err; + + if ((rc = sysctl_createv(clog, 0, &rnode, &rnode, CTLFLAG_PERMANENT, + CTLTYPE_NODE, "ath", SYSCTL_DESCR("Atheros driver parameters"), + NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL)) != 0) + goto err; + + if ((rc = sysctl_createv(clog, 0, &rnode, &rnode, CTLFLAG_PERMANENT, + CTLTYPE_NODE, "hal", SYSCTL_DESCR("Atheros HAL parameters"), + NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL)) != 0) + goto err; + +#if 0 + if ((rc = sysctl_createv(clog, 0, &rnode, &cnode, + CTLFLAG_PERMANENT|CTLFLAG_READONLY, CTLTYPE_STRING, "version", + SYSCTL_DESCR("Atheros HAL version"), NULL, 0, &ath_hal_version, 0, + CTL_CREATE, CTL_EOL)) != 0) + goto err; +#endif + + if ((rc = sysctl_createv(clog, 0, &rnode, &cnode, + CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, "dma_brt", + SYSCTL_DESCR("Atheros HAL DMA beacon response time"), NULL, 0, + &ath_hal_dma_beacon_response_time, 0, CTL_CREATE, CTL_EOL)) != 0) + goto err; + + if ((rc = sysctl_createv(clog, 0, &rnode, &cnode, + CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, "sw_brt", + SYSCTL_DESCR("Atheros HAL software beacon response time"), NULL, 0, + &ath_hal_sw_beacon_response_time, 0, CTL_CREATE, CTL_EOL)) != 0) + goto err; + + if ((rc = sysctl_createv(clog, 0, &rnode, &cnode, + CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, "swba_backoff", + SYSCTL_DESCR("Atheros HAL additional SWBA backoff time"), NULL, 0, + &ath_hal_additional_swba_backoff, 0, CTL_CREATE, CTL_EOL)) != 0) + goto err; + +#ifdef ATHHAL_DEBUG + if ((rc = sysctl_createv(clog, 0, &rnode, &cnode, + CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, "debug", + SYSCTL_DESCR("Atheros HAL debugging printfs"), NULL, 0, + &ath_hal_debug, 0, CTL_CREATE, CTL_EOL)) != 0) + goto err; +#endif /* ATHHAL_DEBUG */ + return; +err: + printf("%s: sysctl_createv failed (rc = %d)\n", __func__, rc); +} + +MALLOC_DEFINE(M_ATH_HAL, "ath_hal", "ath hal data"); + +void* +ath_hal_malloc(size_t size) +{ + void *ret; + ENTER + ret = malloc(size, M_ATH_HAL, M_NOWAIT | M_ZERO); + EXIT + return ret; +} + +void +ath_hal_free(void* p) +{ + ENTER + free(p, M_ATH_HAL); + EXIT +} + +void +ath_hal_vprintf(struct ath_hal *ah, const char* fmt, va_list ap) +{ + ENTER + vprintf(fmt, ap); + EXIT +} + +void +ath_hal_printf(struct ath_hal *ah, const char* fmt, ...) +{ + va_list ap; + ENTER + va_start(ap, fmt); + ath_hal_vprintf(ah, fmt, ap); + va_end(ap); + EXIT +} + +const char* +ath_hal_ether_sprintf(const u_int8_t *mac) +{ + const char *ret; + ENTER + ret = ether_sprintf(mac); + EXIT + return ret; +} + +#ifdef ATHHAL_DEBUG +void +HALDEBUG(struct ath_hal *ah, const char* fmt, ...) +{ + if (ath_hal_debug) { + va_list ap; + ENTER + va_start(ap, fmt); + ath_hal_vprintf(ah, fmt, ap); + va_end(ap); + EXIT + } +} + +void +HALDEBUGn(struct ath_hal *ah, u_int level, const char* fmt, ...) +{ + if (ath_hal_debug >= level) { + va_list ap; + ENTER + va_start(ap, fmt); + ath_hal_vprintf(ah, fmt, ap); + va_end(ap); + EXIT + } +} +#endif /* ATHHAL_DEBUG */ + +#ifdef ATHHAL_DEBUG_ALQ +/* + * ALQ register tracing support. + * + * Setting hw.ath.hal.alq=1 enables tracing of all register reads and + * writes to the file /tmp/ath_hal.log. The file format is a simple + * fixed-size array of records. When done logging set hw.ath.hal.alq=0 + * and then decode the file with the arcode program (that is part of the + * HAL). If you start+stop tracing the data will be appended to an + * existing file. + * + * NB: doesn't handle multiple devices properly; only one DEVICE record + * is emitted and the different devices are not identified. + */ +#include +#include +#include + +static struct alq *ath_hal_alq; +static int ath_hal_alq_emitdev; /* need to emit DEVICE record */ +static u_int ath_hal_alq_lost; /* count of lost records */ +static const char *ath_hal_logfile = "/tmp/ath_hal.log"; +static u_int ath_hal_alq_qsize = 64*1024; + +static int +ath_hal_setlogging(int enable) +{ + int error; + + if (enable) { + error = kauth_authorize_network(curlwp->l_cred, + KAUTH_NETWORK_INTERFACE, + KAUTH_REQ_NETWORK_INTERFACE_SETPRIV, NULL, NULL, NULL); + if (error == 0) { + error = alq_open(&ath_hal_alq, ath_hal_logfile, + curproc->p_ucred, + sizeof (struct athregrec), ath_hal_alq_qsize); + ath_hal_alq_lost = 0; + ath_hal_alq_emitdev = 1; + printf("ath_hal: logging to %s enabled\n", + ath_hal_logfile); + } + } else { + if (ath_hal_alq) + alq_close(ath_hal_alq); + ath_hal_alq = NULL; + printf("ath_hal: logging disabled\n"); + error = 0; + } + return (error); +} + +static int +sysctl_hw_ath_hal_log(SYSCTL_HANDLER_ARGS) +{ + int error, enable; + + enable = (ath_hal_alq != NULL); + error = sysctl_handle_int(oidp, &enable, 0, req); + if (error || !req->newptr) + return (error); + else + return (ath_hal_setlogging(enable)); +} +SYSCTL_PROC(_hw_ath_hal, OID_AUTO, alq, CTLTYPE_INT|CTLFLAG_RW, + 0, 0, sysctl_hw_ath_hal_log, "I", "Enable HAL register logging"); +SYSCTL_INT(_hw_ath_hal, OID_AUTO, alq_size, CTLFLAG_RW, + &ath_hal_alq_qsize, 0, "In-memory log size (#records)"); +SYSCTL_INT(_hw_ath_hal, OID_AUTO, alq_lost, CTLFLAG_RW, + &ath_hal_alq_lost, 0, "Register operations not logged"); + +static struct ale * +ath_hal_alq_get(struct ath_hal *ah) +{ + struct ale *ale; + + if (ath_hal_alq_emitdev) { + ale = alq_get(ath_hal_alq, ALQ_NOWAIT); + if (ale) { + struct athregrec *r = + (struct athregrec *) ale->ae_data; + r->op = OP_DEVICE; + r->reg = 0; + r->val = ah->ah_devid; + alq_post(ath_hal_alq, ale); + ath_hal_alq_emitdev = 0; + } else + ath_hal_alq_lost++; + } + ale = alq_get(ath_hal_alq, ALQ_NOWAIT); + if (!ale) + ath_hal_alq_lost++; + return ale; +} + +void +ath_hal_reg_write(struct ath_hal *ah, u_int32_t reg, u_int32_t val) +{ + bus_space_tag_t t = BUSTAG(ah); + ENTER + + if (ath_hal_alq) { + struct ale *ale = ath_hal_alq_get(ah); + if (ale) { + struct athregrec *r = (struct athregrec *) ale->ae_data; + r->op = OP_WRITE; + r->reg = reg; + r->val = val; + alq_post(ath_hal_alq, ale); + } + } +#if _BYTE_ORDER == _BIG_ENDIAN + if (reg >= 0x4000 && reg < 0x5000) + bus_space_write_4(t, h, reg, val); + else +#endif + bus_space_write_stream_4(t, h, reg, val); + + EXIT +} + +u_int32_t +ath_hal_reg_read(struct ath_hal *ah, u_int32_t reg) +{ + u_int32_t val; + bus_space_handle_t h = BUSHANDLE(ah); + bus_space_tag_t t = BUSTAG(ah); + ENTER + +#if _BYTE_ORDER == _BIG_ENDIAN + if (reg >= 0x4000 && reg < 0x5000) + val = bus_space_read_4(t, h, reg); + else +#endif + val = bus_space_read_stream_4(t, h, reg); + + if (ath_hal_alq) { + struct ale *ale = ath_hal_alq_get(ah); + if (ale) { + struct athregrec *r = (struct athregrec *) ale->ae_data; + r->op = OP_READ; + r->reg = reg; + r->val = val; + alq_post(ath_hal_alq, ale); + } + } + + EXIT + return val; +} + +void +OS_MARK(struct ath_hal *ah, u_int id, u_int32_t v) +{ + if (ath_hal_alq) { + struct ale *ale = ath_hal_alq_get(ah); + ENTER + if (ale) { + struct athregrec *r = (struct athregrec *) ale->ae_data; + r->op = OP_MARK; + r->reg = id; + r->val = v; + alq_post(ath_hal_alq, ale); + } + EXIT + } +} +#elif defined(ATHHAL_DEBUG) || defined(AH_REGOPS_FUNC) +/* + * Memory-mapped device register read/write. These are here + * as routines when debugging support is enabled and/or when + * explicitly configured to use function calls. The latter is + * for architectures that might need to do something before + * referencing memory (e.g. remap an i/o window). + * + * NB: see the comments in ah_osdep.h about byte-swapping register + * reads and writes to understand what's going on below. + */ + +void +ath_hal_reg_write(struct ath_hal *ah, u_int32_t reg, u_int32_t val) +{ + bus_space_handle_t h = BUSHANDLE(ah); + bus_space_tag_t t = BUSTAG(ah); + ENTER + +#if _BYTE_ORDER == _BIG_ENDIAN + if (reg >= 0x4000 && reg < 0x5000) + bus_space_write_4(t, h, reg, val); + else +#endif + bus_space_write_stream_4(t, h, reg, val); + EXIT +} + +u_int32_t +ath_hal_reg_read(struct ath_hal *ah, u_int32_t reg) +{ + bus_space_handle_t h = BUSHANDLE(ah); + bus_space_tag_t t = BUSTAG(ah); + uint32_t ret; + ENTER + +#if _BYTE_ORDER == _BIG_ENDIAN + if (reg >= 0x4000 && reg < 0x5000) + ret = bus_space_read_4(t, h, reg); + else +#endif + ret = bus_space_read_stream_4(t, h, reg); + EXIT + + return ret; +} +#endif /* ATHHAL_DEBUG || AH_REGOPS_FUNC */ + +#ifdef ATHHAL_ASSERT +void +ath_hal_assert_failed(const char* filename, int lineno, const char *msg) +{ + ENTER + printf("Atheros HAL assertion failure: %s: line %u: %s\n", + filename, lineno, msg); + panic("ath_hal_assert"); +} +#endif /* ATHHAL_ASSERT */ + +/* + * Delay n microseconds. + */ +void +ath_hal_delay(int n) +{ + ENTER + DELAY(n); + EXIT +} + +u_int32_t +ath_hal_getuptime(struct ath_hal *ah) +{ + struct bintime bt; + uint32_t ret; + ENTER + getbinuptime(&bt); + ret = (bt.sec * 1000) + + (((uint64_t)1000 * (uint32_t)(bt.frac >> 32)) >> 32); + EXIT + return ret; +} + +void +ath_hal_memzero(void *dst, size_t n) +{ + ENTER + (void)memset(dst, 0, n); + EXIT +} + +void * +ath_hal_memcpy(void *dst, const void *src, size_t n) +{ + void *ret; + ENTER + ret = memcpy(dst, src, n); + EXIT + return ret; +} --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/ic/ah_osdep.h 2009-03-23 17:36:56.000000000 +0000 @@ -0,0 +1,151 @@ +/*- + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + * + * $Id: ah_osdep.h,v 1.1 2009/03/23 17:14:48 sborrill Exp $ + */ + +#ifndef _ATH_AH_OSDEP_H_ +#define _ATH_AH_OSDEP_H_ +/* + * Atheros Hardware Access Layer (HAL) OS Dependent Definitions. + */ +#include +#include +#include +#include + +#include + +/* + * Delay n microseconds. + */ +extern void ath_hal_delay(int); +#define OS_DELAY(_n) ath_hal_delay(_n) + +#define OS_INLINE __inline +#define OS_MEMZERO(_a, _n) ath_hal_memzero((_a), (_n)) +extern void ath_hal_memzero(void *, size_t); +#define OS_MEMCPY(_d, _s, _n) ath_hal_memcpy(_d,_s,_n) +extern void *ath_hal_memcpy(void *, const void *, size_t); + +#define abs(_a) __builtin_abs(_a) + +struct ath_hal; +extern u_int32_t ath_hal_getuptime(struct ath_hal *); +#define OS_GETUPTIME(_ah) ath_hal_getuptime(_ah) + +/* + * WiSoC boards overload the bus tag with information about the + * board layout. We must extract the bus space tag from that + * indirect structure. For everyone else the tag is passed in + * directly. + * XXX cache indirect ref privately + */ +#ifdef AH_SUPPORT_AR5312 +#define BUSTAG(ah) \ + ((bus_space_tag_t) ((struct ar531x_config *)((ah)->ah_st))->tag) +#define BUSHANDLE(ah) ((bus_space_handle_t)((ah)->ah_sh)) + +#elif defined(AH_REGOPS_FUNC) +#define BUSTAG(ah) (*(bus_space_tag_t *) (ah)->ah_st) +#define BUSHANDLE(ah) (*(bus_space_handle_t *)((ah)->ah_sh)) +#define HALTAG(t) (HAL_BUS_TAG) &(t) +#define HALHANDLE(h) (HAL_BUS_HANDLE) &(h) +#else +#define BUSTAG(ah) ((bus_space_tag_t) (ah)->ah_st) +#define BUSHANDLE(ah) ((bus_space_handle_t) ((ah)->ah_sh)) +#define HALTAG(t) (HAL_BUS_TAG) (t) +#define HALHANDLE(h) (HAL_BUS_HANDLE) (h) +#endif + +/* + * Register read/write; we assume the registers will always + * be memory-mapped. Note that register accesses are done + * using target-specific functions when debugging is enabled + * (ATHHAL_DEBUG) or we are explicitly configured this way. The + * latter is used on some platforms where the full i/o space + * cannot be directly mapped. + */ +#if defined(ATHHAL_DEBUG) || defined(AH_REGOPS_FUNC) || defined(ATHHAL_DEBUG_ALQ) +#define OS_REG_WRITE(_ah, _reg, _val) ath_hal_reg_write(_ah, _reg, _val) +#define OS_REG_READ(_ah, _reg) ath_hal_reg_read(_ah, _reg) + +extern void ath_hal_reg_write(struct ath_hal *ah, u_int reg, u_int32_t val); +extern u_int32_t ath_hal_reg_read(struct ath_hal *ah, u_int reg); +#else +/* + * The hardware registers are native little-endian byte order. + * Big-endian hosts are handled by enabling hardware byte-swap + * of register reads and writes at reset. But the PCI clock + * domain registers are not byte swapped! Thus, on big-endian + * platforms we have to byte-swap thoese registers specifically. + * Most of this code is collapsed at compile time because the + * register values are constants. + */ +#define AH_LITTLE_ENDIAN 1234 +#define AH_BIG_ENDIAN 4321 + +#if _BYTE_ORDER == _BIG_ENDIAN +#define OS_REG_WRITE(_ah, _reg, _val) do { \ + if ( (_reg) >= 0x4000 && (_reg) < 0x5000) \ + bus_space_write_4((_ah)->ah_st, (_ah)->ah_sh, \ + (_reg), (_val)); \ + else \ + bus_space_write_stream_4((_ah)->ah_st, (_ah)->ah_sh, \ + (_reg), (_val)); \ +} while (0) +#define OS_REG_READ(_ah, _reg) \ + (((_reg) >= 0x4000 && (_reg) < 0x5000) ? \ + bus_space_read_4((_ah)->ah_st, (_ah)->ah_sh, (_reg)) : \ + bus_space_read_stream_4((_ah)->ah_st, (_ah)->ah_sh, (_reg))) +#else /* _BYTE_ORDER == _LITTLE_ENDIAN */ +#define OS_REG_WRITE(_ah, _reg, _val) \ + bus_space_write_4((_ah)->ah_st, (_ah)->ah_sh, (_reg), (_val)) +#define OS_REG_READ(_ah, _reg) \ + ((u_int32_t) bus_space_read_4((_ah)->ah_st, (_ah)->ah_sh, (_reg))) +#endif /* _BYTE_ORDER */ +#endif /* ATHHAL_DEBUG || AH_REGFUNC || ATHHAL_DEBUG_ALQ */ + +#ifdef ATHHAL_DEBUG_ALQ +extern void OS_MARK(struct ath_hal *, u_int id, u_int32_t value); +#else +#define OS_MARK(_ah, _id, _v) +#endif + +typedef void * HAL_SOFTC; /* pointer to driver/OS state */ +typedef bus_space_tag_t HAL_BUS_TAG; /* opaque bus i/o id tag */ +typedef bus_space_handle_t HAL_BUS_HANDLE; /* opaque bus i/o handle */ + +#define OS_SET_DECLARE(set, ptype) __link_set_decl(set, ptype) +#define OS_DATA_SET(set, sym) __link_set_add_rodata(set, sym) +#define OS_SET_FOREACH(pvar, set) __link_set_foreach(pvar, set) + +#define __bswap16(x) bswap16(x) +#define __bswap32(x) bswap32(x) + +#endif /* _ATH_AH_OSDEP_H_ */ --- /dev/null 2009-05-15 14:10:01.000000000 +0100 +++ sys/external/isc/atheros_hal/ic/opt_ah.h 2009-03-23 17:36:56.000000000 +0000 @@ -0,0 +1,91 @@ +/* $NetBSD: opt_ah.h,v 1.1 2008/12/11 05:37:40 alc Exp $ */ + +/*- + * Copyright (c) 2008 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef OPT_AH_H +#define OPT_AH_H + +#include "opt_athhal.h" + +#ifdef ATHHAL_ASSERT +#define AH_ASSERT 1 +#endif + +#ifdef ATHHAL_DEBUG +#define AH_DEBUG 1 +#endif + +#ifdef ATHHAL_DEBUG_ALQ +#define AH_DEBUG_ALQ 1 +#endif + +#ifdef ATHHAL_AR5210 +#define AH_SUPPORT_5210 1 +#endif + +#ifdef ATHHAL_AR5211 +#define AH_SUPPORT_5211 1 +#endif + +#ifdef ATHHAL_AR5212 +#define AH_SUPPORT_5212 1 +#endif + +#ifdef ATHHAL_AR5311 +#define AH_SUPPORT_5311 1 +#endif + +#ifdef ATHHAL_AR5312 +#define AH_SUPPORT_AR5312 1 +#endif + +#ifdef ATHHAL_AR2316 +#define AH_SUPPORT_2316 1 +#endif + +#ifdef ATHHAL_AR2317 +#define AH_SUPPORT_2317 1 +#endif + +#ifdef ATHHAL_AR5416 +#define AH_SUPPORT_AR5416 1 +#endif + +#ifdef ATHHAL_AR9280 +#define AH_SUPPORT_AR9280 1 +#endif + +#if defined(ATHHAL_RF2316) || \ + defined(ATHHAL_RF2317) || \ + defined(ATHHAL_RF2413) || \ + defined(ATHHAL_RF2425) || \ + defined(ATHHAL_RF5111) || \ + defined(ATHHAL_RF5112) || \ + defined(ATHHAL_RF5413) +#define AH_HAS_RF +#endif + +#endif /* OPT_AH_H */ Index: sys/net80211/ieee80211_var.h =================================================================== RCS file: /cvsroot/src/sys/net80211/ieee80211_var.h,v retrieving revision 1.26 diff -u -r1.26 ieee80211_var.h --- sys/net80211/ieee80211_var.h 4 Mar 2007 06:03:19 -0000 1.26 +++ sys/net80211/ieee80211_var.h 16 May 2009 11:24:22 -0000 @@ -282,7 +282,7 @@ #define IEEE80211_C_BURST 0x02000000 /* CAPABILITY: frame bursting */ #define IEEE80211_C_WME 0x04000000 /* CAPABILITY: WME avail */ #define IEEE80211_C_WDS 0x08000000 /* CAPABILITY: 4-addr support */ -/* 0x10000000 reserved */ +#define IEEE80211_C_WME_TKIPMIC 0x10000000 /* CAPABILITY: TKIP MIC for QoS frame */ #define IEEE80211_C_BGSCAN 0x20000000 /* CAPABILITY: bg scanning */ #define IEEE80211_C_TXFRAG 0x40000000 /* CAPABILITY: tx fragments */ /* XXX protection/barker? */