summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsam <sam@FreeBSD.org>2008-11-28 00:03:41 +0000
committersam <sam@FreeBSD.org>2008-11-28 00:03:41 +0000
commite0752b627b8facba40d9f4daae09c6833bb1daec (patch)
tree5e6c67d27f7d4af49cc3aea5c9d7528a2243d63d
downloadFreeBSD-src-e0752b627b8facba40d9f4daae09c6833bb1daec.zip
FreeBSD-src-e0752b627b8facba40d9f4daae09c6833bb1daec.tar.gz
virgin import of ath hal
-rw-r--r--COPYRIGHT18
-rw-r--r--Makefile101
-rw-r--r--README47
-rw-r--r--ah.c1029
-rw-r--r--ah.h914
-rw-r--r--ah_debug.h49
-rw-r--r--ah_decode.h55
-rw-r--r--ah_desc.h219
-rw-r--r--ah_devid.h84
-rw-r--r--ah_eeprom.h127
-rw-r--r--ah_eeprom_v14.c415
-rw-r--r--ah_eeprom_v14.h271
-rw-r--r--ah_eeprom_v3.c1877
-rw-r--r--ah_eeprom_v3.h462
-rw-r--r--ah_internal.h741
-rw-r--r--ah_regdomain.c2572
-rw-r--r--ah_soc.h91
-rw-r--r--ar5210/ar5210.h354
-rw-r--r--ar5210/ar5210_attach.c497
-rw-r--r--ar5210/ar5210_beacon.c194
-rw-r--r--ar5210/ar5210_interrupts.c137
-rw-r--r--ar5210/ar5210_keycache.c159
-rw-r--r--ar5210/ar5210_misc.c604
-rw-r--r--ar5210/ar5210_phy.c88
-rw-r--r--ar5210/ar5210_power.c137
-rw-r--r--ar5210/ar5210_recv.c269
-rw-r--r--ar5210/ar5210_reset.c988
-rw-r--r--ar5210/ar5210_xmit.c626
-rw-r--r--ar5210/ar5210desc.h130
-rw-r--r--ar5210/ar5210phy.h59
-rw-r--r--ar5210/ar5210reg.h401
-rw-r--r--ar5210/ar5k_0007.ini194
-rw-r--r--ar5211/ar5211.h302
-rw-r--r--ar5211/ar5211_attach.c505
-rw-r--r--ar5211/ar5211_beacon.c176
-rw-r--r--ar5211/ar5211_interrupts.c161
-rw-r--r--ar5211/ar5211_keycache.c181
-rw-r--r--ar5211/ar5211_misc.c640
-rw-r--r--ar5211/ar5211_phy.c107
-rw-r--r--ar5211/ar5211_power.c139
-rw-r--r--ar5211/ar5211_recv.c248
-rw-r--r--ar5211/ar5211_reset.c2126
-rw-r--r--ar5211/ar5211_xmit.c682
-rw-r--r--ar5211/ar5211desc.h134
-rw-r--r--ar5211/ar5211phy.h94
-rw-r--r--ar5211/ar5211reg.h853
-rwxr-xr-xar5211/boss.ini358
-rw-r--r--ar5212/ar2316.c753
-rw-r--r--ar5212/ar2317.c736
-rw-r--r--ar5212/ar2413.c745
-rw-r--r--ar5212/ar2425.c724
-rw-r--r--ar5212/ar5111.c707
-rw-r--r--ar5212/ar5112.c877
-rw-r--r--ar5212/ar5212.h601
-rw-r--r--ar5212/ar5212.ini2171
-rw-r--r--ar5212/ar5212_ani.c968
-rw-r--r--ar5212/ar5212_attach.c886
-rw-r--r--ar5212/ar5212_beacon.c256
-rw-r--r--ar5212/ar5212_eeprom.c56
-rw-r--r--ar5212/ar5212_gpio.c131
-rw-r--r--ar5212/ar5212_interrupts.c207
-rw-r--r--ar5212/ar5212_keycache.c288
-rw-r--r--ar5212/ar5212_misc.c1033
-rw-r--r--ar5212/ar5212_phy.c200
-rw-r--r--ar5212/ar5212_power.c178
-rw-r--r--ar5212/ar5212_recv.c289
-rw-r--r--ar5212/ar5212_reset.c2959
-rw-r--r--ar5212/ar5212_xmit.c944
-rw-r--r--ar5212/ar5212desc.h177
-rw-r--r--ar5212/ar5212phy.h348
-rw-r--r--ar5212/ar5212reg.h994
-rw-r--r--ar5212/ar5311reg.h49
-rw-r--r--ar5212/ar5413.c783
-rw-r--r--ar5312/ar5312.h80
-rw-r--r--ar5312/ar5312_attach.c363
-rw-r--r--ar5312/ar5312_eeprom.c47
-rw-r--r--ar5312/ar5312_gpio.c131
-rw-r--r--ar5312/ar5312_interrupts.c47
-rw-r--r--ar5312/ar5312_misc.c165
-rw-r--r--ar5312/ar5312_power.c125
-rw-r--r--ar5312/ar5312_reset.c924
-rw-r--r--ar5312/ar5312phy.h31
-rw-r--r--ar5312/ar5312reg.h139
-rw-r--r--ar5312/ar5315_gpio.c130
-rw-r--r--ar5416/ar2133.c410
-rw-r--r--ar5416/ar5416.h288
-rw-r--r--ar5416/ar5416.ini688
-rw-r--r--ar5416/ar5416_attach.c494
-rw-r--r--ar5416/ar5416_beacon.c249
-rw-r--r--ar5416/ar5416_eeprom.c47
-rw-r--r--ar5416/ar5416_gpio.c115
-rw-r--r--ar5416/ar5416_interrupts.c262
-rw-r--r--ar5416/ar5416_keycache.c69
-rw-r--r--ar5416/ar5416_misc.c500
-rw-r--r--ar5416/ar5416_phy.c129
-rw-r--r--ar5416/ar5416_power.c176
-rw-r--r--ar5416/ar5416_recv.c178
-rw-r--r--ar5416/ar5416_reset.c3867
-rw-r--r--ar5416/ar5416_xmit.c701
-rw-r--r--ar5416/ar5416desc.h397
-rw-r--r--ar5416/ar5416phy.h240
-rw-r--r--ar5416/ar5416reg.h510
-rwxr-xr-xar5416/ar9160.ini699
-rw-r--r--ar5416/ar9160_attach.c309
-rw-r--r--linux/Makefile373
-rw-r--r--linux/Makefile.inc604
-rw-r--r--linux/ah_osdep.c566
-rw-r--r--linux/ah_osdep.h205
-rw-r--r--public/alpha-elf.inc57
-rw-r--r--public/ap30.inc50
-rw-r--r--public/ap43.inc50
-rw-r--r--public/ap51.inc50
-rw-r--r--public/ap61.inc50
-rw-r--r--public/arm9-le-thumb-elf.inc59
-rw-r--r--public/armv4-be-elf.inc55
-rw-r--r--public/armv4-le-elf.inc55
-rw-r--r--public/i386-elf.inc39
-rw-r--r--public/mips-be-elf.inc56
-rw-r--r--public/mips-le-elf.inc53
-rw-r--r--public/mips1-be-elf.inc53
-rw-r--r--public/mips1-le-elf.inc53
-rw-r--r--public/mipsisa32-be-elf.inc57
-rw-r--r--public/mipsisa32-le-elf.inc55
-rw-r--r--public/powerpc-be-eabi.inc57
-rw-r--r--public/powerpc-be-elf.inc53
-rw-r--r--public/powerpc-le-eabi.inc56
-rw-r--r--public/sh4-le-elf.inc43
-rw-r--r--public/sparc-be-elf.inc53
-rw-r--r--public/sparc64-be-elf.inc64
-rw-r--r--public/wackelf.c103
-rw-r--r--public/wisoc.inc50
-rw-r--r--public/x86_64-elf.inc44
-rw-r--r--public/xscale-be-elf.inc62
-rw-r--r--public/xscale-le-elf.inc63
-rw-r--r--version.h19
135 files changed, 54392 insertions, 0 deletions
diff --git a/COPYRIGHT b/COPYRIGHT
new file mode 100644
index 0000000..58bf05c
--- /dev/null
+++ b/COPYRIGHT
@@ -0,0 +1,18 @@
+All files are under this license where not stated.
+
+/*
+ * 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.
+ */
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..e905578
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,101 @@
+#
+# 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: Makefile,v 1.6 2008/11/10 01:23:57 sam Exp $
+#
+
+nop:
+
+#
+# Release-related support.
+#
+FILES= COPYRIGHT README \
+ ah.h ah_desc.h ah_devid.h ah_soc.h version.h \
+ public/[a-z]*.inc public/*.hal.o.uu public/*.opt_ah.h \
+ public/wackelf.c \
+ ${NULL}
+#
+# Tag the tree and build a release tarball suitable for open
+# distribution (e.g. to sourceforge). The tag is date-based.
+#
+release:
+ DATE=`date +'%Y%m%d'`; TAG="ATH_HAL_$${DATE}"; \
+ cvs tag -F $${TAG} ${FILES} && make rerelease TAG=$${TAG}
+
+#
+# Rebuild a release tarball using an existing tag.
+#
+rerelease:
+ if [ -z "${TAG}" ]; then \
+ echo "You must specify a TAG to do a re-release"; \
+ exit 1; \
+ fi; \
+ expr "${TAG}" : '^ATH_HAL_' || { \
+ echo "TAG must be of the form ATH_HAL_YYYYMMDD"; \
+ exit 1; \
+ }; \
+ DATE=`echo "${TAG}" | sed 's/^ATH_HAL_//'`; \
+ DIR="ath_hal-$${DATE}"; \
+ rm -rf $${DIR}; \
+ mkdir $${DIR} && \
+ cvs export -d $${DIR} -r ${TAG} hal && \
+ tar zcf $${DIR}.tgz --exclude=CVS $${DIR} && \
+ rm -rf $${DIR}
+
+#
+# Build a release-like tarball suitable for open distribution
+# using the current contents of the local directory. This is
+# useful for distributing private changes that are not committed
+# to cvs. Note that this should not be used to construct
+# distributions as there is no cvs history or tag to use in
+# tracking issues.
+#
+tarball:
+ DATE=`date +'%Y%m%d'`; DIR="ath_hal-$${DATE}"; \
+ ln -s . $${DIR}; \
+ TARFILES=`for i in ${FILES}; do echo $${DIR}/$$i; done`; \
+ tar zcf $${DIR}.tgz --exclude=CVS $${TARFILES}; \
+ rm -f $${DIR};
+
+#
+# Build a source distribution. Be sure to
+# first tag the source files using src_tag then follow this with
+# src_release to construct the tarball. Tags and filenames are
+# constructed from the contents of version.h (as opposed to the
+# current date) so be sure this file is up to date prior to rolling
+# a release. Note that a source release does NOT include the
+# pre-built binary hal files; it is assumed the recipient can/will
+# do this themselves.
+#
+
+# tag the source code according to the current version
+src_tag:
+ TAG=`awk '/ATH_HAL_VERSION/ \
+ { gsub("\\"","",$$3); \
+ gsub("[-.]", "_", $$3); print "v" $$3; }' version.h`; \
+ cvs tag ${TAGOPTS} $${TAG}; \
+ cvs tag -d $${TAG} */*.uu */*opt_ah.h
+# create a tarball of the source for the current tagged version
+src_release:
+ TAG=`awk '/ATH_HAL_VERSION/ \
+ { gsub("\\"","",$$3); \
+ gsub("[-.]", "_", $$3); print "v" $$3; }' version.h`; \
+ DIR=`awk '/ATH_HAL_VERSION/ \
+ { gsub("\\"","",$$3); print "hal-" $$3; }' version.h`; \
+ rm -rf $${DIR}; mkdir $${DIR}; \
+ cvs export -d $${DIR} -r $${TAG} hal; \
+ tar zcf $${DIR}.tgz --exclude=CVS $${DIR}; \
+ rm -rf $${DIR};
diff --git a/README b/README
new file mode 100644
index 0000000..f6d03d1
--- /dev/null
+++ b/README
@@ -0,0 +1,47 @@
+$Id: README,v 1.1.1.1 2008/08/20 04:41:19 sam Exp $
+
+Atheros Hardware Access Layer (HAL)
+===================================
+
+Read the file COPYRIGHT for the complete copyright.
+
+This code manages much of the chip-specific operation of the Atheros
+driver.
+
+Atheros Hardware
+================
+There are many generations of Atheros 802.11 wireless devices that
+are typically referred to by their programming model:
+
+5210 supports 11a only
+5211 supports both 11a and 11b
+5212 supports 11a, 11b, and 11g
+
+These parts have been incorporated in a variety of retail products
+including cardbus cards and mini-pci cards. In addition many laptop
+vendors use Atheros mini-pci cards for their builtin wireless
+support.
+
+The Atheros PCI vendor id is 0x168c. The file ah_devid.h lists most
+known PCI device id's but is not exhaustive. Some vendors program
+their own vendor and/or device id's to aid in BIOS-locking mini-pci
+cards in laptops.
+
+Atheros SoC Hardware
+====================
+In addition to the cardbus/pci devices Atheros makes System on Chip
+(SoC) parts that integrate a MIPS cpu core and one or more MAC and
+radio parts. Support for these parts is necessarily built
+for the embedded MIPS processor where the code is to be run.
+
+Caveats
+=======
+The binary hal builds provided here include no floating point and
+are operating system-independent. However due to toolchain
+peculiarities the .o files may be wrongly rejected by development
+tools. If that happens it may be possible to patch the file header
+so that the native toolchain will accept the files. In particular
+this has been observed for various Linux MIPS installations for the
+SoC parts. If you have issues consult the associated .inc file in
+the public directory; it explains exactly how the binary file was
+created (e.g. toolchain and compilation options).
diff --git a/ah.c b/ah.c
new file mode 100644
index 0000000..c531b78d
--- /dev/null
+++ b/ah.c
@@ -0,0 +1,1029 @@
+/*
+ * 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.13 2008/11/10 04:08:00 sam Exp $
+ */
+#include "opt_ah.h"
+
+#include "ah.h"
+#include "ah_internal.h"
+#include "ah_devid.h"
+
+#ifdef AH_SUPPORT_AR5210
+extern struct ath_hal *ar5210Attach(uint16_t, HAL_SOFTC,
+ HAL_BUS_TAG, HAL_BUS_HANDLE, HAL_STATUS*);
+#endif
+#ifdef AH_SUPPORT_AR5211
+extern struct ath_hal *ar5211Attach(uint16_t, HAL_SOFTC,
+ HAL_BUS_TAG, HAL_BUS_HANDLE, HAL_STATUS*);
+#endif
+#ifdef AH_SUPPORT_AR5212
+extern struct ath_hal *ar5212Attach(uint16_t, HAL_SOFTC,
+ HAL_BUS_TAG, HAL_BUS_HANDLE, HAL_STATUS*);
+#endif
+#ifdef AH_SUPPORT_AR5312
+extern struct ath_hal *ar5312Attach(uint16_t, HAL_SOFTC,
+ HAL_BUS_TAG, HAL_BUS_HANDLE, HAL_STATUS*);
+#endif
+#ifdef AH_SUPPORT_AR5416
+extern struct ath_hal *ar5416Attach(uint16_t, HAL_SOFTC,
+ HAL_BUS_TAG, HAL_BUS_HANDLE, HAL_STATUS*);
+#endif
+#ifdef AH_SUPPORT_AR9160
+extern struct ath_hal *ar9160Attach(uint16_t, HAL_SOFTC,
+ HAL_BUS_TAG, HAL_BUS_HANDLE, HAL_STATUS*);
+#endif
+
+#include "version.h"
+char ath_hal_version[] = ATH_HAL_VERSION;
+const char* ath_hal_buildopts[] = {
+#ifdef AH_SUPPORT_AR5210
+ "AR5210",
+#endif
+#ifdef AH_SUPPORT_AR5211
+ "AR5211",
+#endif
+#ifdef AH_SUPPORT_AR5212
+ "AR5212",
+#endif
+#ifdef AH_SUPPORT_AR5312
+ "AR5312",
+#endif
+#ifdef AH_SUPPORT_AR5416
+ "AR5416",
+#endif
+#ifdef AH_SUPPORT_AR9180
+ "AR9180",
+#endif
+#ifdef AH_SUPPORT_5111
+ "RF5111",
+#endif
+#ifdef AH_SUPPORT_5112
+ "RF5112",
+#endif
+#ifdef AH_SUPPORT_2413
+ "RF2413",
+#endif
+#ifdef AH_SUPPORT_5413
+ "RF5413",
+#endif
+#ifdef AH_SUPPORT_2316
+ "RF2316",
+#endif
+#ifdef AH_SUPPORT_2317
+ "RF2317",
+#endif
+#ifdef AH_SUPPORT_2133
+ "RF2133",
+#endif
+#ifdef AH_SUPPORT_2425
+ "RF2425",
+#endif
+#ifdef AH_SUPPORT_2417
+ "RF2417",
+#endif
+#ifdef AH_DEBUG
+ "DEBUG",
+#endif
+#ifdef AH_ASSERT
+ "ASSERT",
+#endif
+#ifdef AH_DEBUG_ALQ
+ "DEBUG_ALQ",
+#endif
+#ifdef AH_REGOPS_FUNC
+ "REGOPS_FUNC",
+#endif
+#ifdef AH_PRIVATE_DIAG
+ "PRIVATE_DIAG",
+#endif
+#ifdef AH_DEBUG_COUNTRY
+ "DEBUG_COUNTRY",
+#endif
+#ifdef AH_NEED_DESC_SWAP
+ "TX_DESC_SWAP",
+#endif
+#ifdef AH_DISABLE_WME
+ "DISABLE_WME",
+#endif
+#ifdef AH_SUPPORT_11D
+ "11D",
+#endif
+ AH_NULL
+};
+
+static const char*
+ath_hal_devname(uint16_t devid)
+{
+ switch (devid) {
+ case AR5210_PROD:
+ case AR5210_DEFAULT:
+ return "Atheros 5210";
+
+ case AR5211_DEVID:
+ case AR5311_DEVID:
+ case AR5211_DEFAULT:
+ return "Atheros 5211";
+ case AR5211_FPGA11B:
+ return "Atheros 5211 (FPGA)";
+
+ case AR5212_FPGA:
+ return "Atheros 5212 (FPGA)";
+ case AR5212_AR5312_REV2:
+ case AR5212_AR5312_REV7:
+ return "Atheros 5312 WiSoC";
+ case AR5212_AR2315_REV6:
+ case AR5212_AR2315_REV7:
+ return "Atheros 2315 WiSoC";
+ case AR5212_AR2317_REV1:
+ return "Atheros 2317 WiSoC";
+ case AR5212_AR2313_REV8:
+ return "Atheros 2313 WiSoC";
+ 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";
+ case AR5416_DEVID_PCI:
+ case AR5416_DEVID_PCIE:
+ return "Atheros 5416";
+ case AR9160_DEVID_PCI:
+ return "Atheros 9160";
+ }
+ return AH_NULL;
+}
+
+const char*
+ath_hal_probe(uint16_t vendorid, uint16_t devid)
+{
+ return (vendorid == ATHEROS_VENDOR_ID ||
+ vendorid == ATHEROS_3COM_VENDOR_ID ||
+ vendorid == ATHEROS_3COM2_VENDOR_ID ?
+ ath_hal_devname(devid) : 0);
+}
+
+/*
+ * 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 *ah=AH_NULL;
+
+ switch (devid) {
+#ifdef AH_SUPPORT_AR5210
+ case AR5210_AP:
+ case AR5210_PROD:
+ case AR5210_DEFAULT:
+ ah = ar5210Attach(devid, sc, st, sh, error);
+ break;
+#endif
+#ifdef AH_SUPPORT_AR5211
+ case AR5211_DEVID:
+ case AR5311_DEVID:
+ case AR5211_FPGA11B:
+ case AR5211_DEFAULT:
+ ah = ar5211Attach(devid, sc, st, sh, error);
+ break;
+#endif
+#ifdef AH_SUPPORT_AR5212
+ case AR5212_DEVID_IBM:
+ case AR5212_AR2413:
+ case AR5212_AR2417:
+ case AR5212_AR5413:
+ case AR5212_AR5424:
+ case AR5212_DEVID_FF19: /* XXX PCI Express extra */
+ devid = AR5212_DEVID;
+ /* fall thru... */
+ case AR5212_DEVID:
+ case AR5212_FPGA:
+ case AR5212_DEFAULT:
+ ah = ar5212Attach(devid, sc, st, sh, error);
+ break;
+#endif
+#ifdef AH_SUPPORT_AR5312
+ case AR5212_AR5312_REV2:
+ case AR5212_AR5312_REV7:
+ case AR5212_AR2313_REV8:
+ case AR5212_AR2315_REV6:
+ case AR5212_AR2315_REV7:
+ case AR5212_AR2317_REV1:
+ ah = ar5312Attach(devid, sc, st, sh, error);
+ break;
+#endif
+#ifdef AH_SUPPORT_AR5416
+ case AR5416_DEVID_PCI:
+ case AR5416_DEVID_PCIE:
+ ah = ar5416Attach(devid, sc, st, sh, error);
+ break;
+#endif
+#ifdef AH_SUPPORT_AR9160
+ case AR9160_DEVID_PCI:
+ ah = ar9160Attach(devid, sc, st, sh, error);
+ break;
+#endif
+ default:
+ ah = AH_NULL;
+ *error = HAL_ENXIO;
+ break;
+ }
+ 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;
+}
+
+/*
+ * 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
+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) {
+ 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) {
+ 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_CHAN_HALFRATE:
+ return pCap->halChanHalfRate ? HAL_OK : HAL_ENOTSUPP;
+ case HAL_CAP_CHAN_QUARTERRATE:
+ return pCap->halChanQuarterRate ? HAL_OK : 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);
+#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;
+}
diff --git a/ah.h b/ah.h
new file mode 100644
index 0000000..e5d47bd
--- /dev/null
+++ b/ah.h
@@ -0,0 +1,914 @@
+/*
+ * 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.13 2008/11/10 04:08:00 sam 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.
+ */
+
+/*
+ * Bus i/o type definitions. We define a platform-independent
+ * set of types that are mapped to platform-dependent data for
+ * register read/write operations. We use types that are large
+ * enough to hold a pointer; smaller data should fit and only
+ * require type coercion to work. Larger data can be stored
+ * elsewhere and a reference passed for the bus tag and/or handle.
+ */
+typedef void* HAL_SOFTC; /* pointer to driver/OS state */
+typedef void* HAL_BUS_TAG; /* opaque bus i/o id tag */
+typedef void* HAL_BUS_HANDLE; /* opaque bus i/o handle */
+
+#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 */
+ HAL_CAP_CHAN_HALFRATE = 23, /* hardware can support half rate channels */
+ HAL_CAP_CHAN_QUARTERRATE = 24, /* hardware can support quarter rate channels */
+ 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 rate channels */
+ HAL_MODE_11A_QUARTER_RATE = 0x400, /* 11A quarter rate 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 0x08110600 /* 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_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);
+
+/*
+ * Return a version string for the HAL release.
+ */
+extern char ath_hal_version[];
+/*
+ * Return a NULL-terminated array of build/configuration options.
+ */
+extern const char* ath_hal_buildopts[];
+#endif /* _ATH_AH_H_ */
diff --git a/ah_debug.h b/ah_debug.h
new file mode 100644
index 0000000..e3b15ad
--- /dev/null
+++ b/ah_debug.h
@@ -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 2008/10/12 16:44:34 sam 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_ */
diff --git a/ah_decode.h b/ah_decode.h
new file mode 100644
index 0000000..bd595ae
--- /dev/null
+++ b/ah_decode.h
@@ -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.4 2008/11/10 04:08:00 sam 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_ */
diff --git a/ah_desc.h b/ah_desc.h
new file mode 100644
index 0000000..50e010e
--- /dev/null
+++ b/ah_desc.h
@@ -0,0 +1,219 @@
+/*
+ * 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.5 2008/11/10 04:08:00 sam 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. 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 */
+};
+
+struct ath_desc_status {
+ 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 */
diff --git a/ah_devid.h b/ah_devid.h
new file mode 100644
index 0000000..204cf3f
--- /dev/null
+++ b/ah_devid.h
@@ -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.4 2008/10/06 18:32:46 sam 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 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 */
diff --git a/ah_eeprom.h b/ah_eeprom.h
new file mode 100644
index 0000000..fb57c49
--- /dev/null
+++ b/ah_eeprom.h
@@ -0,0 +1,127 @@
+/*
+ * 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.6 2008/11/10 04:08:00 sam Exp $
+ */
+#ifndef _ATH_AH_EEPROM_H_
+#define _ATH_AH_EEPROM_H_
+
+/*
+ * 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_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_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_1 0xE001 /* 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, /* uint8_t* */
+ AR_EEP_NFTHRESH_2, /* uint8_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_legacyEepromAttach(struct ath_hal *ah);
+HAL_STATUS ath_hal_v14EepromAttach(struct ath_hal *ah);
+#endif /* _ATH_AH_EEPROM_H_ */
diff --git a/ah_eeprom_v14.c b/ah_eeprom_v14.c
new file mode 100644
index 0000000..67bcded
--- /dev/null
+++ b/ah_eeprom_v14.c
@@ -0,0 +1,415 @@
+/*
+ * 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.3 2008/11/10 04:08:00 sam Exp $
+ */
+#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:
+ *(int8_t *)val = pModal[0].noiseFloorThreshCh[0];
+ return HAL_OK;
+ case AR_EEP_NFTHRESH_2:
+ *(int8_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;
+ }
+ 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;
+}
+
+/* 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
+
+/* 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
+}
diff --git a/ah_eeprom_v14.h b/ah_eeprom_v14.h
new file mode 100644
index 0000000..90e2c74
--- /dev/null
+++ b/ah_eeprom_v14.h
@@ -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.3 2008/11/10 04:08:00 sam 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_ */
diff --git a/ah_eeprom_v3.c b/ah_eeprom_v3.c
new file mode 100644
index 0000000..717578d
--- /dev/null
+++ b/ah_eeprom_v3.c
@@ -0,0 +1,1877 @@
+/*
+ * 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.3 2008/11/10 04:08:00 sam 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)
+{
+ const static uint16_t intercepts3[] =
+ { 0, 5, 10, 20, 30, 50, 70, 85, 90, 95, 100 };
+ const static 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;
+}
+
+/*
+ * TODO: Need to talk to Praveen about this, these are
+ * not valid 2.4 channels, either we change these
+ * or I need to change the beanie coding to accept these
+ */
+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;
+}
diff --git a/ah_eeprom_v3.h b/ah_eeprom_v3.h
new file mode 100644
index 0000000..9f30c72
--- /dev/null
+++ b/ah_eeprom_v3.h
@@ -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.2 2008/11/10 04:08:00 sam 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_ */
diff --git a/ah_internal.h b/ah_internal.h
new file mode 100644
index 0000000..78eba8d
--- /dev/null
+++ b/ah_internal.h
@@ -0,0 +1,741 @@
+/*
+ * 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.17 2008/11/10 04:08:00 sam 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
+#ifndef _UINTPTR_T
+#if AH_WORDSIZE == 64
+typedef unsigned long int uintptr_t;
+#else
+typedef unsigned int uintptr_t;
+#endif
+#endif
+#define __DECONST(type, var) ((type)(uintptr_t)(const void *)(var))
+#endif
+
+typedef struct {
+ uint16_t start; /* first register */
+ uint16_t end; /* ending register or zero */
+} HAL_REGRANGE;
+
+/*
+ * Transmit power scale factor.
+ */
+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;
+
+
+/*
+ * 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.
+ */
+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_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_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*, ...)
+ __printflike(2,3);
+extern void ath_hal_vprintf(struct ath_hal *, const char*, __va_list)
+ __printflike(2, 0);
+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, ...)
+ __printflike(3,4);
+#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_ */
diff --git a/ah_regdomain.c b/ah_regdomain.c
new file mode 100644
index 0000000..2a6f2c5
--- /dev/null
+++ b/ah_regdomain.c
@@ -0,0 +1,2572 @@
+/*
+ * 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.17 2008/11/10 04:08:00 sam 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
+
+/*
+ * Used to set the RegDomain bitmask which chooses which frequency
+ * band specs are used.
+ */
+
+#define BMLEN 2 /* Use 2 64 bit uint for channel bitmask
+ NB: Must agree with macro below (BM) */
+#define BMZERO {(uint64_t) 0, (uint64_t) 0} /* BMLEN zeros */
+
+#define BM(_fa, _fb, _fc, _fd, _fe, _ff, _fg, _fh, _fi, _fj, _fk, _fl) \
+ {((((_fa >= 0) && (_fa < 64)) ? (((uint64_t) 1) << _fa) : (uint64_t) 0) | \
+ (((_fb >= 0) && (_fb < 64)) ? (((uint64_t) 1) << _fb) : (uint64_t) 0) | \
+ (((_fc >= 0) && (_fc < 64)) ? (((uint64_t) 1) << _fc) : (uint64_t) 0) | \
+ (((_fd >= 0) && (_fd < 64)) ? (((uint64_t) 1) << _fd) : (uint64_t) 0) | \
+ (((_fe >= 0) && (_fe < 64)) ? (((uint64_t) 1) << _fe) : (uint64_t) 0) | \
+ (((_ff >= 0) && (_ff < 64)) ? (((uint64_t) 1) << _ff) : (uint64_t) 0) | \
+ (((_fg >= 0) && (_fg < 64)) ? (((uint64_t) 1) << _fg) : (uint64_t) 0) | \
+ (((_fh >= 0) && (_fh < 64)) ? (((uint64_t) 1) << _fh) : (uint64_t) 0) | \
+ (((_fi >= 0) && (_fi < 64)) ? (((uint64_t) 1) << _fi) : (uint64_t) 0) | \
+ (((_fj >= 0) && (_fj < 64)) ? (((uint64_t) 1) << _fj) : (uint64_t) 0) | \
+ (((_fk >= 0) && (_fk < 64)) ? (((uint64_t) 1) << _fk) : (uint64_t) 0) | \
+ (((_fl >= 0) && (_fl < 64)) ? (((uint64_t) 1) << _fl) : (uint64_t) 0) | \
+ ((((_fa > 63) && (_fa < 128)) ? (((uint64_t) 1) << (_fa - 64)) : (uint64_t) 0) | \
+ (((_fb > 63) && (_fb < 128)) ? (((uint64_t) 1) << (_fb - 64)) : (uint64_t) 0) | \
+ (((_fc > 63) && (_fc < 128)) ? (((uint64_t) 1) << (_fc - 64)) : (uint64_t) 0) | \
+ (((_fd > 63) && (_fd < 128)) ? (((uint64_t) 1) << (_fd - 64)) : (uint64_t) 0) | \
+ (((_fe > 63) && (_fe < 128)) ? (((uint64_t) 1) << (_fe - 64)) : (uint64_t) 0) | \
+ (((_ff > 63) && (_ff < 128)) ? (((uint64_t) 1) << (_ff - 64)) : (uint64_t) 0) | \
+ (((_fg > 63) && (_fg < 128)) ? (((uint64_t) 1) << (_fg - 64)) : (uint64_t) 0) | \
+ (((_fh > 63) && (_fh < 128)) ? (((uint64_t) 1) << (_fh - 64)) : (uint64_t) 0) | \
+ (((_fi > 63) && (_fi < 128)) ? (((uint64_t) 1) << (_fi - 64)) : (uint64_t) 0) | \
+ (((_fj > 63) && (_fj < 128)) ? (((uint64_t) 1) << (_fj - 64)) : (uint64_t) 0) | \
+ (((_fk > 63) && (_fk < 128)) ? (((uint64_t) 1) << (_fk - 64)) : (uint64_t) 0) | \
+ (((_fl > 63) && (_fl < 128)) ? (((uint64_t) 1) << (_fl - 64)) : (uint64_t) 0)))}
+
+/*
+ * Country/Region Codes
+ * Numbering from ISO 3166
+ */
+enum CountryCode {
+ 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_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_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 EnumRd {
+ /*
+ * 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 */
+
+ 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 */
+ FCCA = 0x0A10,
+
+ 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,
+ 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,
+ DISALLOW_ADHOC_11A = 0x00000001,
+ DISALLOW_ADHOC_11A_TURB = 0x00000002,
+ NEED_NFC = 0x00000004,
+
+ ADHOC_PER_11D = 0x00000008, /* Start Ad-Hoc mode */
+ ADHOC_NO_11A = 0x00000010,
+
+ PUBLIC_SAFETY_DOMAIN = 0x00000020, /* public safety domain */
+ LIMIT_FRAME_4MS = 0x00000040, /* 4msec limit on the frame length */
+
+ NO_HOSTAP = 0x00000080, /* No HOSTAP mode opereation */
+};
+
+/*
+ * The following describe the bit masks for different passive scan
+ * capability/requirements per regdomain.
+ */
+#define NO_PSCAN 0x0ULL
+#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 reg_dmn_pair_mapping {
+ 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 },
+
+ {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, },
+
+ {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 },
+};
+
+/*
+ * The following table of vendor specific regdomain pairs and
+ * additional flags used to modify the flags5GHz and flags2GHz
+ * of the original regdomain
+ */
+
+#define NO_INTERSECT_REQ 0xFFFFFFFF
+#define NO_UNION_REQ 0
+#define MAX_MAPS 2
+
+struct ccmap {
+ char isoName[3];
+ HAL_CTRY_CODE countryCode;
+};
+
+
+/*
+ * The following table is 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_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_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_YEMEN, NULL1_WORLD, YES, NO, YES, YES,YES, NO, NO, 7000 },
+ {CTRY_ZIMBABWE, NULL1_WORLD, YES, NO, YES, YES,YES, NO, NO, 7000 }
+};
+
+typedef struct RegDmnFreqBand {
+ 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;
+
+/* Bit masks for DFS per regdomain */
+
+enum {
+ NO_DFS = 0x0000000000000000ULL,
+ DFS_FCC3 = 0x0000000000000001ULL,
+ DFS_ETSI = 0x0000000000000002ULL,
+ DFS_MKK4 = 0x0000000000000004ULL,
+};
+
+/* The table of frequency bands is indexed by a bitmask. The ordering
+ * must be consistent with the enum below. When adding a new
+ * frequency band, be sure to match the location in the enum with the
+ * comments
+ */
+
+/*
+ * 5GHz 11A channel tags
+ */
+
+enum {
+ F1_4915_4925,
+ F1_4935_4945,
+ F1_4920_4980,
+ F1_4942_4987,
+ F1_4945_4985,
+ F1_4950_4980,
+ F1_5035_5040,
+ F1_5040_5080,
+ F1_5055_5055,
+
+ F1_5120_5240,
+
+ F1_5170_5230,
+ F2_5170_5230,
+
+ F1_5180_5240,
+ F2_5180_5240,
+ F3_5180_5240,
+ F4_5180_5240,
+ F5_5180_5240,
+ F6_5180_5240,
+
+ F1_5180_5320,
+
+ F1_5240_5280,
+
+ F1_5260_5280,
+
+ F1_5260_5320,
+ F2_5260_5320,
+ F3_5260_5320,
+ F4_5260_5320,
+ F5_5260_5320,
+ F6_5260_5320,
+
+ F1_5260_5700,
+
+ F1_5280_5320,
+
+ F1_5500_5620,
+
+ F1_5500_5700,
+ F2_5500_5700,
+ F3_5500_5700,
+ F4_5500_5700,
+
+ F1_5745_5805,
+ F2_5745_5805,
+ F3_5745_5805,
+
+ F1_5745_5825,
+ F2_5745_5825,
+ F3_5745_5825,
+ F4_5745_5825,
+ F5_5745_5825,
+ F6_5745_5825,
+
+ W1_4920_4980,
+ W1_5040_5080,
+ W1_5170_5230,
+ W1_5180_5240,
+ W1_5260_5320,
+ W1_5745_5825,
+ W1_5500_5700,
+ W2_5260_5320,
+ W2_5180_5240,
+ W2_5825_5825,
+};
+
+static REG_DMN_FREQ_BAND regDmn5GhzFreq[] = {
+ { 4915, 4925, 23, 0, 10, 5, NO_DFS, PSCAN_MKK2, 16 }, /* F1_4915_4925 */
+ { 4935, 4945, 23, 0, 10, 5, NO_DFS, PSCAN_MKK2, 16 }, /* F1_4935_4945 */
+ { 4920, 4980, 23, 0, 20, 20, NO_DFS, PSCAN_MKK2, 7 }, /* F1_4920_4980 */
+ { 4942, 4987, 27, 6, 5, 5, NO_DFS, PSCAN_FCC, 0 }, /* F1_4942_4987 */
+ { 4945, 4985, 30, 6, 10, 5, NO_DFS, PSCAN_FCC, 0 }, /* F1_4945_4985 */
+ { 4950, 4980, 33, 6, 20, 5, NO_DFS, PSCAN_FCC, 0 }, /* F1_4950_4980 */
+ { 5035, 5040, 23, 0, 10, 5, NO_DFS, PSCAN_MKK2, 12 }, /* F1_5035_5040 */
+ { 5040, 5080, 23, 0, 20, 20, NO_DFS, PSCAN_MKK2, 2 }, /* F1_5040_5080 */
+ { 5055, 5055, 23, 0, 10, 5, NO_DFS, PSCAN_MKK2, 12 }, /* F1_5055_5055 */
+
+ { 5120, 5240, 5, 6, 20, 20, NO_DFS, NO_PSCAN, 0 }, /* F1_5120_5240 */
+
+ { 5170, 5230, 23, 0, 20, 20, NO_DFS, PSCAN_MKK1 | PSCAN_MKK2, 1 }, /* F1_5170_5230 */
+ { 5170, 5230, 20, 0, 20, 20, NO_DFS, PSCAN_MKK1 | PSCAN_MKK2, 1 }, /* F2_5170_5230 */
+
+ { 5180, 5240, 15, 0, 20, 20, NO_DFS, PSCAN_FCC | PSCAN_ETSI, 0 }, /* F1_5180_5240 */
+ { 5180, 5240, 17, 6, 20, 20, NO_DFS, PSCAN_FCC, 1 }, /* F2_5180_5240 */
+ { 5180, 5240, 18, 0, 20, 20, NO_DFS, PSCAN_FCC | PSCAN_ETSI, 0 }, /* F3_5180_5240 */
+ { 5180, 5240, 20, 0, 20, 20, NO_DFS, PSCAN_FCC | PSCAN_ETSI, 0 }, /* F4_5180_5240 */
+ { 5180, 5240, 23, 0, 20, 20, NO_DFS, PSCAN_FCC | PSCAN_ETSI, 0 }, /* F5_5180_5240 */
+ { 5180, 5240, 23, 6, 20, 20, NO_DFS, PSCAN_FCC, 0 }, /* F6_5180_5240 */
+
+ { 5180, 5320, 20, 6, 20, 20, DFS_ETSI, PSCAN_ETSI, 0 }, /* F1_5180_5320 */
+
+ { 5240, 5280, 23, 0, 20, 20, DFS_FCC3, PSCAN_FCC | PSCAN_ETSI, 0 }, /* F1_5240_5280 */
+
+ { 5260, 5280, 23, 0, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_FCC | PSCAN_ETSI, 0 }, /* F1_5260_5280 */
+
+ { 5260, 5320, 18, 0, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_FCC | PSCAN_ETSI, 0 }, /* F1_5260_5320 */
+
+ { 5260, 5320, 20, 0, 20, 20, DFS_FCC3 | DFS_ETSI | DFS_MKK4, PSCAN_FCC | PSCAN_ETSI | PSCAN_MKK3 , 0 },
+ /* F2_5260_5320 */
+
+ { 5260, 5320, 20, 6, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_FCC, 2 }, /* F3_5260_5320 */
+ { 5260, 5320, 23, 6, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_FCC, 2 }, /* F4_5260_5320 */
+ { 5260, 5320, 23, 6, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_FCC, 0 }, /* F5_5260_5320 */
+ { 5260, 5320, 30, 0, 20, 20, NO_DFS, NO_PSCAN, 0 }, /* F6_5260_5320 */
+
+ { 5260, 5700, 5, 6, 20, 20, DFS_FCC3 | DFS_ETSI, NO_PSCAN, 0 }, /* F1_5260_5700 */
+
+ { 5280, 5320, 17, 6, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_FCC, 0 }, /* F1_5280_5320 */
+
+ { 5500, 5620, 30, 6, 20, 20, DFS_ETSI, PSCAN_ETSI, 0 }, /* F1_5500_5620 */
+
+ { 5500, 5700, 20, 6, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_FCC, 4 }, /* F1_5500_5700 */
+ { 5500, 5700, 27, 0, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_FCC | PSCAN_ETSI, 0 }, /* F2_5500_5700 */
+ { 5500, 5700, 30, 0, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_FCC | PSCAN_ETSI, 0 }, /* F3_5500_5700 */
+ { 5500, 5700, 23, 0, 20, 20, DFS_FCC3 | DFS_ETSI | DFS_MKK4, PSCAN_MKK3 | PSCAN_FCC, 0 },
+ /* F4_5500_5700 */
+
+ { 5745, 5805, 23, 0, 20, 20, NO_DFS, NO_PSCAN, 0 }, /* F1_5745_5805 */
+ { 5745, 5805, 30, 6, 20, 20, NO_DFS, NO_PSCAN, 0 }, /* F2_5745_5805 */
+ { 5745, 5805, 30, 6, 20, 20, DFS_ETSI, PSCAN_ETSI, 0 }, /* F3_5745_5805 */
+ { 5745, 5825, 5, 6, 20, 20, NO_DFS, NO_PSCAN, 0 }, /* F1_5745_5825 */
+ { 5745, 5825, 17, 0, 20, 20, NO_DFS, NO_PSCAN, 0 }, /* F2_5745_5825 */
+ { 5745, 5825, 20, 0, 20, 20, NO_DFS, NO_PSCAN, 0 }, /* F3_5745_5825 */
+ { 5745, 5825, 30, 0, 20, 20, NO_DFS, NO_PSCAN, 0 }, /* F4_5745_5825 */
+ { 5745, 5825, 30, 6, 20, 20, NO_DFS, NO_PSCAN, 3 }, /* F5_5745_5825 */
+ { 5745, 5825, 30, 6, 20, 20, NO_DFS, NO_PSCAN, 0 }, /* F6_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 }, /* W1_4920_4980 */
+ { 5040, 5080, 30, 0, 20, 20, NO_DFS, PSCAN_WWR, 0 }, /* W1_5040_5080 */
+ { 5170, 5230, 30, 0, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, 0 }, /* W1_5170_5230 */
+ { 5180, 5240, 30, 0, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, 0 }, /* W1_5180_5240 */
+ { 5260, 5320, 30, 0, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, 0 }, /* W1_5260_5320 */
+ { 5745, 5825, 30, 0, 20, 20, NO_DFS, PSCAN_WWR, 0 }, /* W1_5745_5825 */
+ { 5500, 5700, 30, 0, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, 0 }, /* W1_5500_5700 */
+ { 5260, 5320, 30, 0, 20, 20, NO_DFS, NO_PSCAN, 0 }, /* W2_5260_5320 */
+ { 5180, 5240, 30, 0, 20, 20, NO_DFS, NO_PSCAN, 0 }, /* W2_5180_5240 */
+ { 5825, 5825, 30, 0, 20, 20, NO_DFS, PSCAN_WWR, 0 }, /* W2_5825_5825 */
+};
+
+/*
+ * 5GHz Turbo (dynamic & static) tags
+ */
+
+enum {
+ T1_5130_5210,
+ T1_5250_5330,
+ T1_5370_5490,
+ T1_5530_5650,
+
+ T1_5150_5190,
+ T1_5230_5310,
+ T1_5350_5470,
+ T1_5510_5670,
+
+ T1_5200_5240,
+ T2_5200_5240,
+ T1_5210_5210,
+ T2_5210_5210,
+
+ T1_5280_5280,
+ T2_5280_5280,
+ T1_5250_5250,
+ T1_5290_5290,
+ T1_5250_5290,
+ T2_5250_5290,
+
+ T1_5540_5660,
+ T1_5760_5800,
+ T2_5760_5800,
+
+ T1_5765_5805,
+
+ WT1_5210_5250,
+ WT1_5290_5290,
+ WT1_5540_5660,
+ WT1_5760_5800,
+};
+
+static REG_DMN_FREQ_BAND regDmn5GhzTurboFreq[] = {
+ { 5130, 5210, 5, 6, 40, 40, NO_DFS, NO_PSCAN, 0}, /* T1_5130_5210 */
+ { 5250, 5330, 5, 6, 40, 40, DFS_FCC3, NO_PSCAN, 0}, /* T1_5250_5330 */
+ { 5370, 5490, 5, 6, 40, 40, NO_DFS, NO_PSCAN, 0}, /* T1_5370_5490 */
+ { 5530, 5650, 5, 6, 40, 40, DFS_FCC3, NO_PSCAN, 0}, /* T1_5530_5650 */
+
+ { 5150, 5190, 5, 6, 40, 40, NO_DFS, NO_PSCAN, 0}, /* T1_5150_5190 */
+ { 5230, 5310, 5, 6, 40, 40, DFS_FCC3, NO_PSCAN, 0}, /* T1_5230_5310 */
+ { 5350, 5470, 5, 6, 40, 40, NO_DFS, NO_PSCAN, 0}, /* T1_5350_5470 */
+ { 5510, 5670, 5, 6, 40, 40, DFS_FCC3, NO_PSCAN, 0}, /* T1_5510_5670 */
+
+ { 5200, 5240, 17, 6, 40, 40, NO_DFS, NO_PSCAN, 0}, /* T1_5200_5240 */
+ { 5200, 5240, 23, 6, 40, 40, NO_DFS, NO_PSCAN, 0}, /* T2_5200_5240 */
+ { 5210, 5210, 17, 6, 40, 40, NO_DFS, NO_PSCAN, 0}, /* T1_5210_5210 */
+ { 5210, 5210, 23, 0, 40, 40, NO_DFS, NO_PSCAN, 0}, /* T2_5210_5210 */
+
+ { 5280, 5280, 23, 6, 40, 40, DFS_FCC3, PSCAN_FCC_T, 0}, /* T1_5280_5280 */
+ { 5280, 5280, 20, 6, 40, 40, DFS_FCC3, PSCAN_FCC_T, 0}, /* T2_5280_5280 */
+ { 5250, 5250, 17, 0, 40, 40, DFS_FCC3, PSCAN_FCC_T, 0}, /* T1_5250_5250 */
+ { 5290, 5290, 20, 0, 40, 40, DFS_FCC3, PSCAN_FCC_T, 0}, /* T1_5290_5290 */
+ { 5250, 5290, 20, 0, 40, 40, DFS_FCC3, PSCAN_FCC_T, 0}, /* T1_5250_5290 */
+ { 5250, 5290, 23, 6, 40, 40, DFS_FCC3, PSCAN_FCC_T, 0}, /* T2_5250_5290 */
+
+ { 5540, 5660, 20, 6, 40, 40, DFS_FCC3, PSCAN_FCC_T, 0}, /* T1_5540_5660 */
+ { 5760, 5800, 20, 0, 40, 40, NO_DFS, NO_PSCAN, 0}, /* T1_5760_5800 */
+ { 5760, 5800, 30, 6, 40, 40, NO_DFS, NO_PSCAN, 0}, /* T2_5760_5800 */
+
+ { 5765, 5805, 30, 6, 40, 40, NO_DFS, NO_PSCAN, 0}, /* T1_5765_5805 */
+
+ /*
+ * Below are the WWR frequencies
+ */
+
+ { 5210, 5250, 15, 0, 40, 40, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, 0}, /* WT1_5210_5250 */
+ { 5290, 5290, 18, 0, 40, 40, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, 0}, /* WT1_5290_5290 */
+ { 5540, 5660, 20, 0, 40, 40, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, 0}, /* WT1_5540_5660 */
+ { 5760, 5800, 20, 0, 40, 40, NO_DFS, PSCAN_WWR, 0}, /* WT1_5760_5800 */
+};
+
+/*
+ * 2GHz 11b channel tags
+ */
+enum {
+ F1_2312_2372,
+ F2_2312_2372,
+
+ F1_2412_2472,
+ F2_2412_2472,
+ F3_2412_2472,
+
+ F1_2412_2462,
+ F2_2412_2462,
+
+ F1_2432_2442,
+
+ F1_2457_2472,
+
+ F1_2467_2472,
+
+ F1_2484_2484,
+ F2_2484_2484,
+
+ F1_2512_2732,
+
+ W1_2312_2372,
+ W1_2412_2412,
+ W1_2417_2432,
+ W1_2437_2442,
+ W1_2447_2457,
+ W1_2462_2462,
+ W1_2467_2467,
+ W2_2467_2467,
+ W1_2472_2472,
+ W2_2472_2472,
+ W1_2484_2484,
+ W2_2484_2484,
+};
+
+static REG_DMN_FREQ_BAND regDmn2GhzFreq[] = {
+ { 2312, 2372, 5, 6, 20, 5, NO_DFS, NO_PSCAN, 0}, /* F1_2312_2372 */
+ { 2312, 2372, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, /* F2_2312_2372 */
+
+ { 2412, 2472, 5, 6, 20, 5, NO_DFS, NO_PSCAN, 0}, /* F1_2412_2472 */
+ { 2412, 2472, 20, 0, 20, 5, NO_DFS, PSCAN_MKKA, 0}, /* F2_2412_2472 */
+ { 2412, 2472, 30, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, /* F3_2412_2472 */
+
+ { 2412, 2462, 27, 6, 20, 5, NO_DFS, NO_PSCAN, 0}, /* F1_2412_2462 */
+ { 2412, 2462, 20, 0, 20, 5, NO_DFS, PSCAN_MKKA, 0}, /* F2_2412_2462 */
+
+ { 2432, 2442, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, /* F1_2432_2442 */
+
+ { 2457, 2472, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, /* F1_2457_2472 */
+
+ { 2467, 2472, 20, 0, 20, 5, NO_DFS, PSCAN_MKKA2 | PSCAN_MKKA, 0}, /* F1_2467_2472 */
+
+ { 2484, 2484, 5, 6, 20, 5, NO_DFS, NO_PSCAN, 0}, /* F1_2484_2484 */
+ { 2484, 2484, 20, 0, 20, 5, NO_DFS, PSCAN_MKKA | PSCAN_MKKA1 | PSCAN_MKKA2, 0}, /* F2_2484_2484 */
+
+ { 2512, 2732, 5, 6, 20, 5, NO_DFS, NO_PSCAN, 0}, /* F1_2512_2732 */
+
+ /*
+ * 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}, /* W1_2312_2372 */
+ { 2412, 2412, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, /* W1_2412_2412 */
+ { 2417, 2432, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, /* W1_2417_2432 */
+ { 2437, 2442, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, /* W1_2437_2442 */
+ { 2447, 2457, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, /* W1_2447_2457 */
+ { 2462, 2462, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, /* W1_2462_2462 */
+ { 2467, 2467, 20, 0, 20, 5, NO_DFS, PSCAN_WWR | IS_ECM_CHAN, 0}, /* W1_2467_2467 */
+ { 2467, 2467, 20, 0, 20, 5, NO_DFS, NO_PSCAN | IS_ECM_CHAN, 0}, /* W2_2467_2467 */
+ { 2472, 2472, 20, 0, 20, 5, NO_DFS, PSCAN_WWR | IS_ECM_CHAN, 0}, /* W1_2472_2472 */
+ { 2472, 2472, 20, 0, 20, 5, NO_DFS, NO_PSCAN | IS_ECM_CHAN, 0}, /* W2_2472_2472 */
+ { 2484, 2484, 20, 0, 20, 5, NO_DFS, PSCAN_WWR | IS_ECM_CHAN, 0}, /* W1_2484_2484 */
+ { 2484, 2484, 20, 0, 20, 5, NO_DFS, NO_PSCAN | IS_ECM_CHAN, 0}, /* W2_2484_2484 */
+};
+
+/*
+ * 2GHz 11g channel tags
+ */
+
+enum {
+ G1_2312_2372,
+ G2_2312_2372,
+
+ G1_2412_2472,
+ G2_2412_2472,
+ G3_2412_2472,
+
+ G1_2412_2462,
+ G2_2412_2462,
+
+ G1_2432_2442,
+
+ G1_2457_2472,
+
+ G1_2512_2732,
+
+ G1_2467_2472 ,
+
+ WG1_2312_2372,
+ WG1_2412_2412,
+ WG1_2417_2432,
+ WG1_2437_2442,
+ WG1_2447_2457,
+ WG1_2462_2462,
+ WG1_2467_2467,
+ WG2_2467_2467,
+ WG1_2472_2472,
+ WG2_2472_2472,
+
+ S1_907_922_5,
+ S1_907_922_10,
+ S1_912_917,
+
+ S2_907_922_5,
+ S2_907_922_10,
+ S2_912_917,
+};
+
+static REG_DMN_FREQ_BAND regDmn2Ghz11gFreq[] = {
+ { 2312, 2372, 5, 6, 20, 5, NO_DFS, NO_PSCAN, 0}, /* G1_2312_2372 */
+ { 2312, 2372, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, /* G2_2312_2372 */
+
+ { 2412, 2472, 5, 6, 20, 5, NO_DFS, NO_PSCAN, 0}, /* G1_2412_2472 */
+ { 2412, 2472, 20, 0, 20, 5, NO_DFS, PSCAN_MKKA_G, 0}, /* G2_2412_2472 */
+ { 2412, 2472, 30, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, /* G3_2412_2472 */
+
+ { 2412, 2462, 27, 6, 20, 5, NO_DFS, NO_PSCAN, 0}, /* G1_2412_2462 */
+ { 2412, 2462, 20, 0, 20, 5, NO_DFS, PSCAN_MKKA_G, 0}, /* G2_2412_2462 */
+
+ { 2432, 2442, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, /* G1_2432_2442 */
+
+ { 2457, 2472, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, /* G1_2457_2472 */
+
+ { 2512, 2732, 5, 6, 20, 5, NO_DFS, NO_PSCAN, 0}, /* G1_2512_2732 */
+
+ { 2467, 2472, 20, 0, 20, 5, NO_DFS, PSCAN_MKKA2 | PSCAN_MKKA, 0 }, /* G1_2467_2472 */
+
+ /*
+ * WWR open up the power to 20dBm
+ */
+
+ { 2312, 2372, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, /* WG1_2312_2372 */
+ { 2412, 2412, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, /* WG1_2412_2412 */
+ { 2417, 2432, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, /* WG1_2417_2432 */
+ { 2437, 2442, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, /* WG1_2437_2442 */
+ { 2447, 2457, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, /* WG1_2447_2457 */
+ { 2462, 2462, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, /* WG1_2462_2462 */
+ { 2467, 2467, 20, 0, 20, 5, NO_DFS, PSCAN_WWR | IS_ECM_CHAN, 0}, /* WG1_2467_2467 */
+ { 2467, 2467, 20, 0, 20, 5, NO_DFS, NO_PSCAN | IS_ECM_CHAN, 0}, /* WG2_2467_2467 */
+ { 2472, 2472, 20, 0, 20, 5, NO_DFS, PSCAN_WWR | IS_ECM_CHAN, 0}, /* WG1_2472_2472 */
+ { 2472, 2472, 20, 0, 20, 5, NO_DFS, NO_PSCAN | IS_ECM_CHAN, 0}, /* WG2_2472_2472 */
+};
+
+/*
+ * 2GHz Dynamic turbo tags
+ */
+
+enum {
+ T1_2312_2372,
+ T1_2437_2437,
+ T2_2437_2437,
+ T3_2437_2437,
+ T1_2512_2732
+};
+
+static REG_DMN_FREQ_BAND regDmn2Ghz11gTurboFreq[] = {
+ { 2312, 2372, 5, 6, 40, 40, NO_DFS, NO_PSCAN, 0}, /* T1_2312_2372 */
+ { 2437, 2437, 5, 6, 40, 40, NO_DFS, NO_PSCAN, 0}, /* T1_2437_2437 */
+ { 2437, 2437, 20, 6, 40, 40, NO_DFS, NO_PSCAN, 0}, /* T2_2437_2437 */
+ { 2437, 2437, 18, 6, 40, 40, NO_DFS, PSCAN_WWR, 0}, /* T3_2437_2437 */
+ { 2512, 2732, 5, 6, 40, 40, NO_DFS, NO_PSCAN, 0}, /* T1_2512_2732 */
+};
+
+typedef struct regDomain {
+ uint16_t regDmnEnum; /* value from EnumRd table */
+ uint8_t conformanceTestLimit;
+ uint64_t dfsMask; /* DFS bitmask for 5Ghz tables */
+ uint64_t pscan; /* Bitmask for passive scan */
+ uint32_t flags; /* Requirement flags (AdHoc disallow, noise
+ floor cal needed, etc) */
+ uint64_t chan11a[BMLEN];/* 128 bit bitmask for channel/band
+ selection */
+ uint64_t chan11a_turbo[BMLEN];/* 128 bit bitmask for channel/band
+ selection */
+ uint64_t chan11a_dyn_turbo[BMLEN]; /* 128 bit bitmask for channel/band
+ selection */
+ uint64_t chan11b[BMLEN];/* 128 bit bitmask for channel/band
+ selection */
+ uint64_t chan11g[BMLEN];/* 128 bit bitmask for channel/band
+ selection */
+ uint64_t chan11g_turbo[BMLEN];/* 128 bit bitmask for channel/band
+ selection */
+} REG_DOMAIN;
+
+static REG_DOMAIN regDomains[] = {
+
+ {DEBUG_REG_DMN, FCC, DFS_FCC3, NO_PSCAN, NO_REQ,
+ BM(F1_5120_5240, F1_5260_5700, F1_5745_5825, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BM(T1_5130_5210, T1_5250_5330, T1_5370_5490, T1_5530_5650, T1_5150_5190, T1_5230_5310, T1_5350_5470, T1_5510_5670, -1, -1, -1, -1),
+ BM(T1_5200_5240, T1_5280_5280, T1_5540_5660, T1_5765_5805, -1, -1, -1, -1, -1, -1, -1, -1),
+ BM(F1_2312_2372, F1_2412_2472, F1_2484_2484, F1_2512_2732, -1, -1, -1, -1, -1, -1, -1, -1),
+ BM(G1_2312_2372, G1_2412_2472, G1_2512_2732, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BM(T1_2312_2372, T1_2437_2437, T1_2512_2732, -1, -1, -1, -1, -1, -1, -1, -1, -1)},
+
+ {APL1, FCC, NO_DFS, NO_PSCAN, NO_REQ,
+ BM(F4_5745_5825, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BMZERO},
+
+ {APL2, FCC, NO_DFS, NO_PSCAN, NO_REQ,
+ BM(F1_5745_5805, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BMZERO},
+
+ {APL3, FCC, NO_DFS, NO_PSCAN, NO_REQ,
+ BM(F1_5280_5320, F2_5745_5805, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BMZERO},
+
+ {APL4, FCC, NO_DFS, NO_PSCAN, NO_REQ,
+ BM(F4_5180_5240, F3_5745_5825, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BMZERO},
+
+ {APL5, FCC, NO_DFS, NO_PSCAN, NO_REQ,
+ BM(F2_5745_5825, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BMZERO},
+
+ {APL6, ETSI, DFS_ETSI, PSCAN_FCC_T | PSCAN_FCC , NO_REQ,
+ BM(F4_5180_5240, F2_5260_5320, F3_5745_5825, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BM(T2_5210_5210, T1_5250_5290, T1_5760_5800, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BMZERO},
+
+ {APL8, ETSI, NO_DFS, NO_PSCAN, DISALLOW_ADHOC_11A|DISALLOW_ADHOC_11A_TURB,
+ BM(F6_5260_5320, F4_5745_5825, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BMZERO},
+
+ {APL9, ETSI, DFS_ETSI, PSCAN_ETSI, DISALLOW_ADHOC_11A|DISALLOW_ADHOC_11A_TURB,
+ BM(F1_5180_5320, F1_5500_5620, F3_5745_5805, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BMZERO},
+
+ {ETSI1, ETSI, DFS_ETSI, PSCAN_ETSI, DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB,
+ BM(W2_5180_5240, F2_5260_5320, F2_5500_5700, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BMZERO},
+
+ {ETSI2, ETSI, DFS_ETSI, PSCAN_ETSI, DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB,
+ BM(F3_5180_5240, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BMZERO},
+
+ {ETSI3, ETSI, DFS_ETSI, PSCAN_ETSI, DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB,
+ BM(W2_5180_5240, F2_5260_5320, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BMZERO},
+
+ {ETSI4, ETSI, DFS_ETSI, PSCAN_ETSI, DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB,
+ BM(F3_5180_5240, F1_5260_5320, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BMZERO},
+
+ {ETSI5, ETSI, DFS_ETSI, PSCAN_ETSI, DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB,
+ BM(F1_5180_5240, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BMZERO},
+
+ {ETSI6, ETSI, DFS_ETSI, PSCAN_ETSI, DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB,
+ BM(F5_5180_5240, F1_5260_5280, F3_5500_5700, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BMZERO},
+
+ {FCC1, FCC, NO_DFS, NO_PSCAN, NO_REQ,
+ BM(F2_5180_5240, F4_5260_5320, F5_5745_5825, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BM(T1_5210_5210, T2_5250_5290, T2_5760_5800, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BM(T1_5200_5240, T1_5280_5280, T1_5765_5805, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BMZERO,
+ BMZERO,
+ BMZERO},
+
+ {FCC2, FCC, NO_DFS, NO_PSCAN, NO_REQ,
+ BM(F6_5180_5240, F5_5260_5320, F6_5745_5825, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BM(-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BM(T2_5200_5240, T1_5280_5280, T1_5765_5805, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BMZERO,
+ BMZERO,
+ BMZERO},
+
+ {FCC3, FCC, DFS_FCC3, PSCAN_FCC | PSCAN_FCC_T, NO_REQ,
+ BM(F2_5180_5240, F3_5260_5320, F1_5500_5700, F5_5745_5825, -1, -1, -1, -1, -1, -1, -1, -1),
+ BM(T1_5210_5210, T1_5250_5250, T1_5290_5290, T2_5760_5800, -1, -1, -1, -1, -1, -1, -1, -1),
+ BM(T1_5200_5240, T2_5280_5280, T1_5540_5660, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BMZERO,
+ BMZERO,
+ BMZERO},
+
+ {FCC4, FCC, DFS_FCC3, PSCAN_FCC | PSCAN_FCC_T, NO_REQ,
+ BM(F1_4942_4987, F1_4945_4985, F1_4950_4980, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BMZERO},
+
+ {MKK1, MKK, NO_DFS, PSCAN_MKK1, DISALLOW_ADHOC_11A_TURB,
+ BM(F1_5170_5230, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BMZERO},
+
+ {MKK2, MKK, NO_DFS, PSCAN_MKK2, DISALLOW_ADHOC_11A_TURB,
+ BM(F1_4915_4925, F1_4935_4945, F1_4920_4980, F1_5035_5040, F1_5055_5055, F1_5040_5080, F1_5170_5230, -1, -1, -1, -1, -1),
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BMZERO},
+
+ /* UNI-1 even */
+ {MKK3, MKK, NO_DFS, PSCAN_MKK3, DISALLOW_ADHOC_11A_TURB,
+ BM(F4_5180_5240, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BMZERO},
+
+ /* UNI-1 even + UNI-2 */
+ {MKK4, MKK, DFS_MKK4, PSCAN_MKK3, DISALLOW_ADHOC_11A_TURB,
+ BM(F4_5180_5240, F2_5260_5320, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BMZERO},
+
+ /* UNI-1 even + UNI-2 + mid-band */
+ {MKK5, MKK, DFS_MKK4, PSCAN_MKK3, DISALLOW_ADHOC_11A_TURB,
+ BM(F4_5180_5240, F2_5260_5320, F4_5500_5700, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BMZERO},
+
+ /* UNI-1 odd + even */
+ {MKK6, MKK, NO_DFS, PSCAN_MKK1, DISALLOW_ADHOC_11A_TURB,
+ BM(F2_5170_5230, F4_5180_5240, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BMZERO},
+
+ /* UNI-1 odd + UNI-1 even + UNI-2 */
+ {MKK7, MKK, DFS_MKK4, PSCAN_MKK1 | PSCAN_MKK3 , DISALLOW_ADHOC_11A_TURB,
+ BM(F1_5170_5230, F4_5180_5240, F2_5260_5320, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BMZERO},
+
+ /* UNI-1 odd + UNI-1 even + UNI-2 + mid-band */
+ {MKK8, MKK, DFS_MKK4, PSCAN_MKK1 | PSCAN_MKK3 , DISALLOW_ADHOC_11A_TURB,
+ BM(F1_5170_5230, F4_5180_5240, F2_5260_5320, F4_5500_5700, -1, -1, -1, -1, -1, -1, -1, -1),
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BMZERO},
+
+ /* UNI-1 even + 4.9 GHZ */
+ {MKK9, MKK, NO_DFS, PSCAN_MKK3, DISALLOW_ADHOC_11A_TURB,
+ BM(F1_4915_4925, F1_4935_4945, F1_4920_4980, F1_5035_5040, F1_5055_5055, F1_5040_5080, F4_5180_5240, -1, -1, -1, -1, -1),
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BMZERO},
+
+ /* UNI-1 even + UNI-2 + 4.9 GHZ */
+ {MKK10, MKK, DFS_MKK4, PSCAN_MKK3, DISALLOW_ADHOC_11A_TURB,
+ BM(F1_4915_4925, F1_4935_4945, F1_4920_4980, F1_5035_5040, F1_5055_5055, F1_5040_5080, F4_5180_5240, F2_5260_5320, -1, -1, -1, -1),
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BMZERO},
+
+ /* Defined here to use when 2G channels are authorised for country K2 */
+ {APLD, NO_CTL, NO_DFS, NO_PSCAN, NO_REQ,
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BM(F2_2312_2372,F2_2412_2472, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BM(G2_2312_2372,G2_2412_2472, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BMZERO},
+
+ {ETSIA, NO_CTL, NO_DFS, PSCAN_ETSIA, DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB,
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BM(F1_2457_2472,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BM(G1_2457_2472,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BM(T2_2437_2437,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)},
+
+ {ETSIB, ETSI, NO_DFS, PSCAN_ETSIB, DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB,
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BM(F1_2432_2442,-1,-1,-1,-1,-1,-1,-1, -1, -1, -1, -1),
+ BM(G1_2432_2442,-1,-1,-1,-1,-1,-1,-1, -1, -1, -1, -1),
+ BM(T2_2437_2437,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)},
+
+ {ETSIC, ETSI, NO_DFS, PSCAN_ETSIC, DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB,
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BM(F3_2412_2472,-1,-1,-1,-1,-1,-1,-1, -1, -1, -1, -1),
+ BM(G3_2412_2472,-1,-1,-1,-1,-1,-1,-1, -1, -1, -1, -1),
+ BM(T2_2437_2437,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)},
+
+ {FCCA, FCC, NO_DFS, NO_PSCAN, NO_REQ,
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BM(F1_2412_2462,-1,-1,-1,-1,-1,-1,-1, -1, -1, -1, -1),
+ BM(G1_2412_2462,-1,-1,-1,-1,-1,-1,-1, -1, -1, -1, -1),
+ BM(T2_2437_2437,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)},
+
+ {MKKA, MKK, NO_DFS, PSCAN_MKKA | PSCAN_MKKA_G | PSCAN_MKKA1 | PSCAN_MKKA1_G | PSCAN_MKKA2 | PSCAN_MKKA2_G, DISALLOW_ADHOC_11A_TURB,
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BM(F2_2412_2462, F1_2467_2472, F2_2484_2484, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BM(G2_2412_2462, G1_2467_2472, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BM(T2_2437_2437,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)},
+
+ {MKKC, MKK, NO_DFS, NO_PSCAN, NO_REQ,
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BM(F2_2412_2472,-1,-1,-1,-1,-1,-1,-1, -1, -1, -1, -1),
+ BM(G2_2412_2472,-1,-1,-1,-1,-1,-1,-1, -1, -1, -1, -1),
+ BM(T2_2437_2437,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)},
+
+ {WORLD, ETSI, NO_DFS, NO_PSCAN, NO_REQ,
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BM(F2_2412_2472,-1,-1,-1,-1,-1,-1,-1, -1, -1, -1, -1),
+ BM(G2_2412_2472,-1,-1,-1,-1,-1,-1,-1, -1, -1, -1, -1),
+ BM(T2_2437_2437,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)},
+
+ {WOR0_WORLD, NO_CTL, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, ADHOC_PER_11D,
+ BM(W1_5260_5320, W1_5180_5240, W1_5170_5230, W1_5745_5825, W1_5500_5700, -1, -1, -1, -1, -1, -1, -1),
+ BM(WT1_5210_5250, WT1_5290_5290, WT1_5760_5800, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BMZERO,
+ BM(W1_2412_2412,W1_2437_2442,W1_2462_2462,W1_2472_2472,W1_2417_2432, W1_2447_2457, W1_2467_2467, W1_2484_2484, -1, -1, -1, -1),
+ BM(WG1_2412_2412,WG1_2437_2442,WG1_2462_2462,WG1_2472_2472,WG1_2417_2432,WG1_2447_2457,WG1_2467_2467, -1, -1, -1, -1, -1),
+ BM(T3_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)},
+
+ {WOR01_WORLD, NO_CTL, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, ADHOC_PER_11D,
+ BM(W1_5260_5320, W1_5180_5240, W1_5170_5230, W1_5745_5825, W1_5500_5700, -1, -1, -1, -1, -1, -1, -1),
+ BM(WT1_5210_5250, WT1_5290_5290, WT1_5760_5800, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BMZERO,
+ BM(W1_2412_2412, W1_2437_2442, W1_2462_2462, W1_2417_2432, W1_2447_2457, -1, -1, -1, -1, -1, -1, -1),
+ BM(WG1_2412_2412, WG1_2437_2442, WG1_2462_2462, WG1_2417_2432, WG1_2447_2457, -1, -1, -1, -1, -1, -1, -1),
+ BM(T3_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)},
+
+ {WOR02_WORLD, NO_CTL, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, ADHOC_PER_11D,
+ BM(W1_5260_5320, W1_5180_5240,W1_5170_5230,W1_5745_5825,W1_5500_5700, -1, -1, -1, -1, -1, -1, -1),
+ BM(WT1_5210_5250, WT1_5290_5290, WT1_5760_5800, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BMZERO,
+ BM(W1_2412_2412,W1_2437_2442,W1_2462_2462, W1_2472_2472,W1_2417_2432, W1_2447_2457, W1_2467_2467, -1, -1, -1, -1, -1),
+ BM(WG1_2412_2412,WG1_2437_2442,WG1_2462_2462, WG1_2472_2472,WG1_2417_2432, WG1_2447_2457, WG1_2467_2467, -1, -1, -1, -1, -1),
+ BM(T3_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)},
+
+ {EU1_WORLD, NO_CTL, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, ADHOC_PER_11D,
+ BM(W1_5260_5320, W1_5180_5240,W1_5170_5230,W1_5745_5825,W1_5500_5700, -1, -1, -1, -1, -1, -1, -1),
+ BM(WT1_5210_5250, WT1_5290_5290, WT1_5760_5800, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BMZERO,
+ BM(W1_2412_2412,W1_2437_2442,W1_2462_2462, W2_2472_2472,W1_2417_2432, W1_2447_2457, W2_2467_2467, -1, -1, -1, -1, -1),
+ BM(WG1_2412_2412,WG1_2437_2442,WG1_2462_2462, WG2_2472_2472,WG1_2417_2432, WG1_2447_2457, WG2_2467_2467, -1, -1, -1, -1, -1),
+ BM(T3_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)},
+
+ {WOR1_WORLD, NO_CTL, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, ADHOC_NO_11A,
+ BM(W1_5260_5320, W1_5180_5240, W1_5170_5230, W1_5745_5825, W1_5500_5700, -1, -1, -1, -1, -1, -1, -1),
+ BMZERO,
+ BMZERO,
+ BM(W1_2412_2412,W1_2437_2442,W1_2462_2462,W1_2472_2472,W1_2417_2432, W1_2447_2457, W1_2467_2467, W1_2484_2484, -1, -1, -1, -1),
+ BM(WG1_2412_2412,WG1_2437_2442,WG1_2462_2462,WG1_2472_2472,WG1_2417_2432,WG1_2447_2457,WG1_2467_2467, -1, -1, -1, -1, -1),
+ BM(T3_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)},
+
+ {WOR2_WORLD, NO_CTL, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, ADHOC_NO_11A,
+ BM(W1_5260_5320, W1_5180_5240, W1_5170_5230, W1_5745_5825, W1_5500_5700, -1, -1, -1, -1, -1, -1, -1),
+ BM(WT1_5210_5250, WT1_5290_5290, WT1_5760_5800, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BMZERO,
+ BM(W1_2412_2412,W1_2437_2442,W1_2462_2462,W1_2472_2472,W1_2417_2432, W1_2447_2457, W1_2467_2467, W1_2484_2484, -1, -1, -1, -1),
+ BM(WG1_2412_2412,WG1_2437_2442,WG1_2462_2462,WG1_2472_2472,WG1_2417_2432,WG1_2447_2457,WG1_2467_2467, -1, -1, -1, -1, -1),
+ BM(T3_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)},
+
+ {WOR3_WORLD, NO_CTL, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, ADHOC_PER_11D,
+ BM(W1_5260_5320, W1_5180_5240, W1_5170_5230, W1_5745_5825, -1, -1, -1, -1, -1, -1, -1, -1),
+ BM(WT1_5210_5250, WT1_5290_5290, WT1_5760_5800, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BMZERO,
+ BM(W1_2412_2412,W1_2437_2442,W1_2462_2462,W1_2472_2472,W1_2417_2432, W1_2447_2457, W1_2467_2467, -1, -1, -1, -1, -1),
+ BM(WG1_2412_2412,WG1_2437_2442,WG1_2462_2462,WG1_2472_2472,WG1_2417_2432,WG1_2447_2457,WG1_2467_2467,-1, -1, -1, -1, -1),
+ BM(T3_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)},
+
+ {WOR4_WORLD, NO_CTL, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, ADHOC_NO_11A,
+ BM(W2_5260_5320, W2_5180_5240, F2_5745_5805, W2_5825_5825, -1, -1, -1, -1, -1, -1, -1, -1),
+ BM(WT1_5210_5250, WT1_5290_5290, WT1_5760_5800, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BMZERO,
+ BM(W1_2412_2412,W1_2437_2442,W1_2462_2462, W1_2417_2432,W1_2447_2457,-1, -1, -1, -1, -1, -1, -1),
+ BM(WG1_2412_2412,WG1_2437_2442,WG1_2462_2462, WG1_2417_2432,WG1_2447_2457,-1, -1, -1, -1, -1, -1, -1),
+ BM(T3_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)},
+
+ {WOR5_ETSIC, NO_CTL, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, ADHOC_NO_11A,
+ BM(W1_5260_5320, W2_5180_5240, F6_5745_5825, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BMZERO,
+ BMZERO,
+ BM(W1_2412_2412, W1_2437_2442, W1_2462_2462, W2_2472_2472, W1_2417_2432, W1_2447_2457, W2_2467_2467, -1, -1, -1, -1, -1),
+ BM(WG1_2412_2412, WG1_2437_2442, WG1_2462_2462, WG2_2472_2472, WG1_2417_2432, WG1_2447_2457, WG2_2467_2467, -1, -1, -1, -1, -1),
+ BM(T3_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)},
+
+ {WOR9_WORLD, NO_CTL, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, ADHOC_NO_11A,
+ BM(W1_5260_5320, W1_5180_5240, W1_5745_5825, W1_5500_5700, -1, -1, -1, -1, -1, -1, -1, -1),
+ BM(WT1_5210_5250, WT1_5290_5290, WT1_5760_5800, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BMZERO,
+ BM(W1_2412_2412, W1_2437_2442, W1_2462_2462, W1_2417_2432, W1_2447_2457, -1, -1, -1, -1, -1, -1, -1),
+ BM(WG1_2412_2412, WG1_2437_2442, WG1_2462_2462, WG1_2417_2432, WG1_2447_2457, -1, -1, -1, -1, -1, -1, -1),
+ BM(T3_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)},
+
+ {WORA_WORLD, NO_CTL, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, ADHOC_NO_11A,
+ BM(W1_5260_5320, W1_5180_5240, W1_5745_5825, W1_5500_5700, -1, -1, -1, -1, -1, -1, -1, -1),
+ BMZERO,
+ BMZERO,
+ BM(W1_2412_2412, W1_2437_2442, W1_2462_2462, W1_2472_2472, W1_2417_2432, W1_2447_2457, W1_2467_2467, -1, -1, -1, -1, -1),
+ BM(WG1_2412_2412, WG1_2437_2442, WG1_2462_2462, WG1_2472_2472, WG1_2417_2432, WG1_2447_2457, WG1_2467_2467, -1, -1, -1, -1, -1),
+ BM(T3_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)},
+
+ {NULL1, NO_CTL, NO_DFS, NO_PSCAN, NO_REQ,
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BMZERO}
+};
+
+struct cmode {
+ u_int mode;
+ u_int flags;
+};
+
+static const struct cmode modes[] = {
+ { HAL_MODE_TURBO, CHANNEL_ST}, /* TURBO means 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_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(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, COUNTRY_CODE_TO_ENUM_RD *country,
+ REG_DOMAIN *rd5GHz)
+{
+ 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 ((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;
+ }
+ if ((modesAvail & HAL_MODE_11G) && !country->allow11g) {
+ HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
+ "%s: disallow 11g\n", __func__);
+ modesAvail &= ~HAL_MODE_11G;
+ }
+ if ((modesAvail & HAL_MODE_11A) && isChanBitMaskZero(rd5GHz->chan11a)) {
+ HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
+ "%s: disallow 11a\n", __func__);
+ modesAvail &= ~HAL_MODE_11A;
+ }
+
+ 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;
+}
+
+/*
+ * 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;
+}
+
+/*
+ * 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, &regDomains[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 = &regDomainPairs[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;
+ int is_quarterchan_cap, is_halfchan_cap;
+
+ 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;
+ is_halfchan_cap = AH_PRIVATE(ah)->ah_caps.halChanHalfRate;
+ is_quarterchan_cap = AH_PRIVATE(ah)->ah_caps.halChanQuarterRate;
+
+ 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 = &regDmn5GhzTurboFreq[0];
+ ctl = rd->conformanceTestLimit | CTL_TURBO;
+ break;
+ case HAL_MODE_11A:
+ case HAL_MODE_11NA_HT20:
+ case HAL_MODE_11NA_HT40PLUS:
+ case HAL_MODE_11NA_HT40MINUS:
+ rd = &rd5GHz;
+ channelBM = rd->chan11a;
+ freqs = &regDmn5GhzFreq[0];
+ ctl = rd->conformanceTestLimit;
+ break;
+ case HAL_MODE_11B:
+ rd = &rd2GHz;
+ channelBM = rd->chan11b;
+ freqs = &regDmn2GhzFreq[0];
+ ctl = rd->conformanceTestLimit | CTL_11B;
+ break;
+ case HAL_MODE_11G:
+ case HAL_MODE_11NG_HT20:
+ case HAL_MODE_11NG_HT40PLUS:
+ case HAL_MODE_11NG_HT40MINUS:
+ rd = &rd2GHz;
+ channelBM = rd->chan11g;
+ freqs = &regDmn2Ghz11gFreq[0];
+ ctl = rd->conformanceTestLimit | CTL_11G;
+ break;
+ case HAL_MODE_11G_TURBO:
+ rd = &rd2GHz;
+ channelBM = rd->chan11g_turbo;
+ freqs = &regDmn2Ghz11gTurboFreq[0];
+ ctl = rd->conformanceTestLimit | CTL_108G;
+ break;
+ case HAL_MODE_11A_TURBO:
+ rd = &rd5GHz;
+ channelBM = rd->chan11a_dyn_turbo;
+ freqs = &regDmn5GhzTurboFreq[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 ((fband->channelBW == CHANNEL_HALF_BW) &&
+ !is_halfchan_cap) {
+ HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
+ "%s: Skipping %u half rate channel\n",
+ __func__, c);
+ continue;
+ }
+
+ if ((fband->channelBW == CHANNEL_QUARTER_BW) &&
+ !is_quarterchan_cap) {
+ HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
+ "%s: Skipping %u quarter rate channel\n",
+ __func__, c);
+ 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;
+ switch (fband->channelBW) {
+ case CHANNEL_HALF_BW:
+ icv.channelFlags |= CHANNEL_HALF;
+ break;
+ case CHANNEL_QUARTER_BW:
+ icv.channelFlags |= CHANNEL_QUARTER;
+ break;
+ }
+
+ 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;
+
+ HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
+ "%s: channel %u/0x%x (0x%x) requested\n",
+ __func__, c->channel, c->channelFlags, flags);
+
+ /*
+ * 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);
+ }
+ HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, "%s: channel %u/0x%x d %d\n",
+ __func__, cc->channel, cc->channelFlags, d);
+ 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);
+ }
+}
diff --git a/ah_soc.h b/ah_soc.h
new file mode 100644
index 0000000..50fbc62
--- /dev/null
+++ b/ah_soc.h
@@ -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.4 2008/11/10 04:08:00 sam 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_ */
diff --git a/ar5210/ar5210.h b/ar5210/ar5210.h
new file mode 100644
index 0000000..8f1c3b1
--- /dev/null
+++ b/ar5210/ar5210.h
@@ -0,0 +1,354 @@
+/*
+ * 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.6 2008/11/10 04:08:02 sam 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) )
+
+/*
+ * 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];
+};
+
+/* NB: this is in ah_eeprom.h which isn't used for 5210 support */
+#ifndef MAX_RATE_POWER
+#define MAX_RATE_POWER 60
+#endif
+
+#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 */
+
+ /*
+ * Information retrieved from EEPROM
+ */
+ uint16_t ah_eeversion; /* EEPROM Version field */
+ uint16_t ah_eeprotect; /* EEPROM protection settings */
+ uint16_t ah_antenna; /* Antenna Settings */
+ uint16_t ah_biasCurrents; /* OB, DB */
+ uint8_t ah_thresh62; /* thresh62 */
+ uint8_t ah_xlnaOn; /* External LNA timing */
+ uint8_t ah_xpaOff; /* Extern output stage timing */
+ uint8_t ah_xpaOn; /* Extern output stage timing */
+ uint8_t ah_rfKill; /* Single low bit signalling if RF Kill is implemented */
+ uint8_t ah_devType; /* Type: PCI, miniPCI, CB */
+ uint8_t ah_regDomain[AR_REG_DOMAINS_MAX];
+ /* calibrated reg domains */
+ struct tpcMap ah_tpc[AR_CHANNELS_MAX];
+ 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 struct ath_hal *ar5210Attach(uint16_t, HAL_SOFTC,
+ HAL_BUS_TAG, HAL_BUS_HANDLE, HAL_STATUS *);
+extern void ar5210Detach(struct ath_hal *);
+
+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 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_ */
diff --git a/ar5210/ar5210_attach.c b/ar5210/ar5210_attach.c
new file mode 100644
index 0000000..5311908
--- /dev/null
+++ b/ar5210/ar5210_attach.c
@@ -0,0 +1,497 @@
+/*
+ * 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.7 2008/11/10 04:08:02 sam Exp $
+ */
+#include "opt_ah.h"
+
+#ifdef AH_SUPPORT_AR5210
+
+#include "ah.h"
+#include "ah_internal.h"
+
+#include "ar5210/ar5210.h"
+#include "ar5210/ar5210reg.h"
+#include "ar5210/ar5210phy.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_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_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.
+ */
+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;
+ u_int i, loc;
+ uint32_t revid, pcicfg, sum;
+ uint16_t athvals[AR_EEPROM_ATHEROS_MAX], eeval;
+ HAL_STATUS ecode;
+
+ 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 = 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 in our state block.
+ */
+ pcicfg = OS_REG_READ(ah, AR_PCICFG);
+ OS_REG_WRITE(ah, AR_PCICFG, pcicfg | AR_PCICFG_EEPROMSEL);
+
+ if (!ar5210EepromRead(ah, AR_EEPROM_MAGIC, &eeval)) {
+ HALDEBUG(ah, HAL_DEBUG_ANY,
+ "%s: cannot read EEPROM magic number\n", __func__);
+ ecode = HAL_EEREAD;
+ goto eebad;
+ }
+ if (eeval != 0x5aa5) {
+ HALDEBUG(ah, HAL_DEBUG_ANY,
+ "%s: invalid EEPROM magic number 0x%x\n", __func__, eeval);
+ ecode = HAL_EEMAGIC;
+ goto eebad;
+ }
+
+ if (!ar5210EepromRead(ah, AR_EEPROM_PROTECT, &eeval)) {
+ HALDEBUG(ah, HAL_DEBUG_ANY,
+ "%s: cannot read EEPROM protection bits; read locked?\n",
+ __func__);
+ ecode = HAL_EEREAD;
+ goto eebad;
+ }
+ HALDEBUG(ah, HAL_DEBUG_ATTACH, "EEPROM protect 0x%x\n", eeval);
+ ahp->ah_eeprotect = eeval;
+ /* XXX check proper access before continuing */
+
+ if (!ar5210EepromRead(ah, AR_EEPROM_VERSION, &eeval)) {
+ HALDEBUG(ah, HAL_DEBUG_ANY,
+ "%s: unable to read EEPROM version\n", __func__);
+ ecode = HAL_EEREAD;
+ goto eebad;
+ }
+ ahp->ah_eeversion = (eeval>>12) & 0xf;
+ if (ahp->ah_eeversion != 1) {
+ /*
+ * This driver only groks the version 1 EEPROM layout.
+ */
+ HALDEBUG(ah, HAL_DEBUG_ANY,
+ "%s: unsupported EEPROM version %u (0x%x) found\n",
+ __func__, ahp->ah_eeversion, eeval);
+ ecode = HAL_EEVERSION;
+ goto eebad;
+ }
+
+ /*
+ * Read the Atheros EEPROM entries and calculate the checksum.
+ */
+ sum = 0;
+ for (i = 0; i < AR_EEPROM_ATHEROS_MAX; i++) {
+ if (!ar5210EepromRead(ah, AR_EEPROM_ATHEROS(i), &athvals[i])) {
+ ecode = HAL_EEREAD;
+ goto eebad;
+ }
+ sum ^= athvals[i];
+ }
+ if (sum != 0xffff) {
+ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad EEPROM checksum 0x%x\n",
+ __func__, sum);
+ ecode = HAL_EEBADSUM;
+ goto eebad;
+ }
+
+ /*
+ * Valid checksum, fetch the regulatory domain and save values.
+ */
+ if (!ar5210EepromRead(ah, AR_EEPROM_REG_DOMAIN, &eeval)) {
+ HALDEBUG(ah, HAL_DEBUG_ANY,
+ "%s: cannot read regdomain from EEPROM\n", __func__);
+ ecode = HAL_EEREAD;
+ goto eebad;
+ }
+
+ AH_PRIVATE(ah)->ah_currentRD = eeval & 0xff;
+ ahp->ah_antenna = athvals[2];
+ ahp->ah_biasCurrents = athvals[3];
+ ahp->ah_thresh62 = athvals[4] & 0xff;
+ ahp->ah_xlnaOn = (athvals[4] >> 8) & 0xff;
+ ahp->ah_xpaOn = athvals[5] & 0xff;
+ ahp->ah_xpaOff = (athvals[5] >> 8) & 0xff;
+ ahp->ah_regDomain[0] = (athvals[6] >> 8) & 0xff;
+ ahp->ah_regDomain[1] = athvals[6] & 0xff;
+ ahp->ah_regDomain[2] = (athvals[7] >> 8) & 0xff;
+ ahp->ah_regDomain[3] = athvals[7] & 0xff;
+ ahp->ah_rfKill = athvals[8] & 0x1;
+ ahp->ah_devType = (athvals[8] >> 1) & 0x7;
+ AH_PRIVATE(ah)->ah_getNfAdjust = ar5210GetNfAdjust;
+
+ for (i = 0, loc = AR_EEPROM_ATHEROS_TP_SETTINGS; i < AR_CHANNELS_MAX; i++, loc += AR_TP_SETTINGS_SIZE) {
+ struct tpcMap *chan = &ahp->ah_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;
+ }
+ /*
+ * Got everything we need now to setup the capabilities.
+ */
+ (void) ar5210FillCapabilityInfo(ah);
+
+ sum = 0;
+ for (i = 0; i < 3; i++) {
+ if (!ar5210EepromRead(ah, AR_EEPROM_MAC(i), &eeval)) {
+ HALDEBUG(ah, HAL_DEBUG_ANY,
+ "%s: cannot read EEPROM location %u\n", __func__, i);
+ ecode = HAL_EEREAD;
+ goto bad;
+ }
+ sum += eeval;
+ ahp->ah_macaddr[2*i + 0] = eeval >> 8;
+ ahp->ah_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(ahp->ah_macaddr));
+ ecode = HAL_EEBADMAC;
+ goto eebad;
+ }
+
+ OS_REG_WRITE(ah, AR_PCICFG, pcicfg); /* disable EEPROM access */
+
+ 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_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 = 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 (AH5210(ah)->ah_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;
+}
+#endif /* AH_SUPPORT_AR5210 */
diff --git a/ar5210/ar5210_beacon.c b/ar5210/ar5210_beacon.c
new file mode 100644
index 0000000..f718187
--- /dev/null
+++ b/ar5210/ar5210_beacon.c
@@ -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: ar5210_beacon.c,v 1.4 2008/11/10 04:08:02 sam Exp $
+ */
+#include "opt_ah.h"
+
+#ifdef AH_SUPPORT_AR5210
+
+#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
+}
+#endif /* AH_SUPPORT_AR5210 */
diff --git a/ar5210/ar5210_interrupts.c b/ar5210/ar5210_interrupts.c
new file mode 100644
index 0000000..81543e9
--- /dev/null
+++ b/ar5210/ar5210_interrupts.c
@@ -0,0 +1,137 @@
+/*
+ * 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.4 2008/11/10 04:08:02 sam Exp $
+ */
+#include "opt_ah.h"
+
+#ifdef AH_SUPPORT_AR5210
+
+#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;
+}
+#endif /* AH_SUPPORT_AR5210 */
diff --git a/ar5210/ar5210_keycache.c b/ar5210/ar5210_keycache.c
new file mode 100644
index 0000000..7ee93e1
--- /dev/null
+++ b/ar5210/ar5210_keycache.c
@@ -0,0 +1,159 @@
+/*
+ * 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.4 2008/11/10 04:08:02 sam Exp $
+ */
+#include "opt_ah.h"
+
+#ifdef AH_SUPPORT_AR5210
+
+#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);
+}
+#endif /* AH_SUPPORT_AR5210 */
diff --git a/ar5210/ar5210_misc.c b/ar5210/ar5210_misc.c
new file mode 100644
index 0000000..03f118e
--- /dev/null
+++ b/ar5210/ar5210_misc.c
@@ -0,0 +1,604 @@
+/*
+ * 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.4 2008/11/10 04:08:02 sam Exp $
+ */
+#include "opt_ah.h"
+
+#ifdef AH_SUPPORT_AR5210
+
+#include "ah.h"
+#include "ah_internal.h"
+
+#include "ar5210/ar5210.h"
+#include "ar5210/ar5210reg.h"
+#include "ar5210/ar5210phy.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;
+}
+
+/*
+ * 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)<<AR_BSS_ID1_AID_S));
+ if (assocId == 0)
+ OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_NO_PSPOLL);
+ else
+ OS_REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_NO_PSPOLL);
+}
+
+/*
+ * Get the current hardware tsf for stamlme.
+ */
+uint64_t
+ar5210GetTsf64(struct ath_hal *ah)
+{
+ uint32_t low1, low2, u32;
+
+ /* sync multi-word read */
+ low1 = OS_REG_READ(ah, AR_TSF_L32);
+ u32 = OS_REG_READ(ah, AR_TSF_U32);
+ low2 = OS_REG_READ(ah, AR_TSF_L32);
+ if (low2 < low1) { /* roll over */
+ /*
+ * If we are not preempted this will work. If we are
+ * then we re-reading AR_TSF_U32 does no good as the
+ * low bits will be meaningless. Likewise reading
+ * L32, U32, U32, then comparing the last two reads
+ * to check for rollover
+ * doesn't help if preempted--so we take this approach
+ * as it costs one less PCI read which can be noticeable
+ * when doing things like timestamping packets in
+ * monitor mode.
+ */
+ u32++;
+ }
+ return (((uint64_t) u32) << 32) | ((uint64_t) low2);
+}
+
+/*
+ * Get the current hardware tsf for stamlme.
+ */
+uint32_t
+ar5210GetTsf32(struct ath_hal *ah)
+{
+ return OS_REG_READ(ah, AR_TSF_L32);
+}
+
+/*
+ * Reset the current hardware tsf for stamlme
+ */
+void
+ar5210ResetTsf(struct ath_hal *ah)
+{
+ uint32_t val = OS_REG_READ(ah, AR_BEACON);
+
+ OS_REG_WRITE(ah, AR_BEACON, val | AR_BEACON_RESET_TSF);
+}
+
+/*
+ * Grab a semi-random value from hardware registers - may not
+ * change often
+ */
+uint32_t
+ar5210GetRandomSeed(struct ath_hal *ah)
+{
+ uint32_t nf;
+
+ nf = (OS_REG_READ(ah, AR_PHY_BASE + (25 << 2)) >> 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);
+}
+#endif /* AH_SUPPORT_AR5210 */
diff --git a/ar5210/ar5210_phy.c b/ar5210/ar5210_phy.c
new file mode 100644
index 0000000..0980100
--- /dev/null
+++ b/ar5210/ar5210_phy.c
@@ -0,0 +1,88 @@
+/*
+ * 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.3 2008/11/10 01:19:37 sam Exp $
+ */
+#include "opt_ah.h"
+
+#ifdef AH_SUPPORT_AR5210
+
+#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 },
+/* 9 Mb */ { AH_TRUE, OFDM, 9000, 0x0f, 0x00, 18, 0 },
+/* 12 Mb */ { AH_TRUE, OFDM, 12000, 0x0a, 0x00, (0x80|24), 2 },
+/* 18 Mb */ { AH_TRUE, OFDM, 18000, 0x0e, 0x00, 36, 2 },
+/* 24 Mb */ { AH_TRUE, OFDM, 24000, 0x09, 0x00, (0x80|48), 4 },
+/* 36 Mb */ { AH_TRUE, OFDM, 36000, 0x0d, 0x00, 72, 4 },
+/* 48 Mb */ { AH_TRUE, OFDM, 48000, 0x08, 0x00, 96, 4 },
+/* 54 Mb */ { AH_TRUE, OFDM, 54000, 0x0c, 0x00, 108, 4 }
+ },
+};
+
+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 },
+/* 9 Mb */ { AH_TRUE, TURBO, 9000, 0x0f, 0x00, 18, 0 },
+/* 12 Mb */ { AH_TRUE, TURBO, 12000, 0x0a, 0x00, (0x80|24), 2 },
+/* 18 Mb */ { AH_TRUE, TURBO, 18000, 0x0e, 0x00, 36, 2 },
+/* 24 Mb */ { AH_TRUE, TURBO, 24000, 0x09, 0x00, (0x80|48), 4 },
+/* 36 Mb */ { AH_TRUE, TURBO, 36000, 0x0d, 0x00, 72, 4 },
+/* 48 Mb */ { AH_TRUE, TURBO, 48000, 0x08, 0x00, 96, 4 },
+/* 54 Mb */ { AH_TRUE, TURBO, 54000, 0x0c, 0x00, 108, 4 }
+ },
+};
+
+#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;
+}
+#endif /* AH_SUPPORT_AR5210 */
diff --git a/ar5210/ar5210_power.c b/ar5210/ar5210_power.c
new file mode 100644
index 0000000..dcece25
--- /dev/null
+++ b/ar5210/ar5210_power.c
@@ -0,0 +1,137 @@
+/*
+ * 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.4 2008/11/10 04:08:02 sam Exp $
+ */
+#include "opt_ah.h"
+
+#ifdef AH_SUPPORT_AR5210
+
+#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);
+}
+#endif /* AH_SUPPORT_AR5210 */
diff --git a/ar5210/ar5210_recv.c b/ar5210/ar5210_recv.c
new file mode 100644
index 0000000..3cc6aee
--- /dev/null
+++ b/ar5210/ar5210_recv.c
@@ -0,0 +1,269 @@
+/*
+ * 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.4 2008/11/10 04:08:02 sam Exp $
+ */
+#include "opt_ah.h"
+
+#ifdef AH_SUPPORT_AR5210
+
+#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<<ix)));
+ }
+ return AH_TRUE;
+}
+
+/*
+ * Set multicast filter by index
+ */
+HAL_BOOL
+ar5210SetMulticastFilterIndex(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<<ix)));
+ }
+ return AH_TRUE;
+}
+
+/*
+ * Return the receive packet filter.
+ */
+uint32_t
+ar5210GetRxFilter(struct ath_hal *ah)
+{
+ /* XXX can't be sure if promiscuous mode is set because of PHYRADAR */
+ return OS_REG_READ(ah, AR_RX_FILTER);
+}
+
+/*
+ * Turn off/on bits in the receive packet filter.
+ */
+void
+ar5210SetRxFilter(struct ath_hal *ah, uint32_t bits)
+{
+ if (bits & HAL_RX_FILTER_PHYRADAR) {
+ /* must enable promiscuous mode to get radar */
+ bits = (bits &~ HAL_RX_FILTER_PHYRADAR) | AR_RX_FILTER_PROMISCUOUS;
+ }
+ OS_REG_WRITE(ah, AR_RX_FILTER, bits);
+}
+
+/*
+ * Initialize RX descriptor, by clearing the status and clearing
+ * the size. This is not strictly HW dependent, but we want the
+ * control and status words to be opaque above the hal.
+ */
+HAL_BOOL
+ar5210SetupRxDesc(struct ath_hal *ah, struct ath_desc *ds,
+ uint32_t size, u_int flags)
+{
+ struct ar5210_desc *ads = AR5210DESC(ds);
+
+ (void) flags;
+
+ ads->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;
+}
+#endif /* AH_SUPPORT_AR5210 */
diff --git a/ar5210/ar5210_reset.c b/ar5210/ar5210_reset.c
new file mode 100644
index 0000000..26a98a8
--- /dev/null
+++ b/ar5210/ar5210_reset.c
@@ -0,0 +1,988 @@
+/*
+ * 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.5 2008/11/10 04:08:02 sam Exp $
+ */
+#include "opt_ah.h"
+
+#ifdef AH_SUPPORT_AR5210
+
+#include "ah.h"
+#include "ah_internal.h"
+
+#include "ar5210/ar5210.h"
+#include "ar5210/ar5210reg.h"
+#include "ar5210/ar5210phy.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 delay);
+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);
+ 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) |
+ (ahp->ah_xlnaOn << 8));
+ OS_REG_WRITE(ah, AR_PHY(13),
+ (ahp->ah_xpaOff << 24) | (ahp->ah_xpaOff << 16) |
+ (ahp->ah_xpaOn << 8) | ahp->ah_xpaOn);
+ OS_REG_WRITE(ah, AR_PHY(17),
+ (OS_REG_READ(ah, AR_PHY(17)) & 0xFFFFC07F) |
+ ((ahp->ah_antenna >> 1) & 0x3F80));
+ OS_REG_WRITE(ah, AR_PHY(18),
+ (OS_REG_READ(ah, AR_PHY(18)) & 0xFFFC0FFF) |
+ ((ahp->ah_antenna << 10) & 0x3F000));
+ OS_REG_WRITE(ah, AR_PHY(25),
+ (OS_REG_READ(ah, AR_PHY(25)) & 0xFFF80FFF) |
+ ((ahp->ah_thresh62 << 12) & 0x7F000));
+ OS_REG_WRITE(ah, AR_PHY(68),
+ (OS_REG_READ(ah, AR_PHY(68)) & 0xFFFFFFFC) |
+ (ahp->ah_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
+ar5210PerCalibration(struct ath_hal *ah, HAL_CHANNEL *chan, HAL_BOOL *isIQdone)
+{
+ 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);
+
+ *isIQdone = AH_TRUE;
+
+ 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 delay)
+{
+ 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(delay);
+
+ 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, 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, 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, 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])
+{
+ struct ath_hal_5210 *ahp = AH5210(ah);
+ uint8_t gainFRD, gainF36, gainF48, gainF54;
+ uint8_t dBmRD, dBm36, dBm48, dBm54, dontcare;
+ uint32_t rd, group;
+ struct tpcMap *pRD;
+
+ /* Set OB/DB Values regardless of channel */
+ cp[15] = (ahp->ah_biasCurrents >> 4) & 0x7;
+ cp[16] = ahp->ah_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(ahp->ah_eeversion == 1);
+
+ /* Match regulatory domain */
+ for (rd = 0; rd < AR_REG_DOMAINS_MAX; rd++)
+ if (AH_PRIVATE(ah)->ah_currentRD == ahp->ah_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 = &ahp->ah_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, 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 */
+ 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;
+}
+#endif /* AH_SUPPORT_AR5210 */
diff --git a/ar5210/ar5210_xmit.c b/ar5210/ar5210_xmit.c
new file mode 100644
index 0000000..8d27912
--- /dev/null
+++ b/ar5210/ar5210_xmit.c
@@ -0,0 +1,626 @@
+/*
+ * 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.5 2008/11/10 04:08:02 sam Exp $
+ */
+#include "opt_ah.h"
+
+#ifdef AH_SUPPORT_AR5210
+
+#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<<HAL_PKT_TYPE_NORMAL)|(1<<HAL_PKT_TYPE_ATIM)|\
+ (1<<HAL_PKT_TYPE_PSPOLL)|(1<<HAL_PKT_TYPE_PROBE_RESP)|\
+ (1<<HAL_PKT_TYPE_BEACON))
+#define isValidPktType(_t) ((1<<(_t)) & VALID_PKT_TYPES)
+#define VALID_TX_RATES \
+ ((1<<0x0b)|(1<<0x0f)|(1<<0x0a)|(1<<0x0e)|(1<<0x09)|(1<<0x0d)|\
+ (1<<0x08)|(1<<0x0c)|(1<<0x1b)|(1<<0x1a)|(1<<0x1e)|(1<<0x19)|\
+ (1<<0x1d)|(1<<0x18)|(1<<0x1c))
+#define isValidTxRate(_r) ((1<<(_r)) & VALID_TX_RATES)
+
+HAL_BOOL
+ar5210SetupTxDesc(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)
+{
+ struct ar5210_desc *ads = AR5210DESC(ds);
+ uint32_t frtype;
+
+ (void) txPower;
+ (void) rtsctsDuration;
+
+ HALASSERT(txTries0 != 0);
+ HALASSERT(isValidPktType(type));
+ HALASSERT(isValidTxRate(txRate0));
+
+ if (type == HAL_PKT_TYPE_BEACON || type == HAL_PKT_TYPE_PROBE_RESP)
+ frtype = AR_Frm_NoDelay;
+ else
+ frtype = type << 26;
+ ads->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;
+}
+#endif /* AH_SUPPORT_AR5210 */
diff --git a/ar5210/ar5210desc.h b/ar5210/ar5210desc.h
new file mode 100644
index 0000000..6f105e1
--- /dev/null
+++ b/ar5210/ar5210desc.h
@@ -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.5 2008/11/10 04:08:02 sam 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 /* encrypt 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_ */
diff --git a/ar5210/ar5210phy.h b/ar5210/ar5210phy.h
new file mode 100644
index 0000000..6211613
--- /dev/null
+++ b/ar5210/ar5210phy.h
@@ -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.4 2008/11/10 01:19:37 sam 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 */
diff --git a/ar5210/ar5210reg.h b/ar5210/ar5210reg.h
new file mode 100644
index 0000000..dc49fcd
--- /dev/null
+++ b/ar5210/ar5210reg.h
@@ -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.4 2008/11/10 01:19:37 sam 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 */
diff --git a/ar5210/ar5k_0007.ini b/ar5210/ar5k_0007.ini
new file mode 100644
index 0000000..b0285e9
--- /dev/null
+++ b/ar5210/ar5k_0007.ini
@@ -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.2 2008/11/10 01:19:37 sam 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 },
diff --git a/ar5211/ar5211.h b/ar5211/ar5211.h
new file mode 100644
index 0000000..5ee0646
--- /dev/null
+++ b/ar5211/ar5211.h
@@ -0,0 +1,302 @@
+/*
+ * 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.7 2008/11/10 04:08:02 sam 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 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 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_ */
diff --git a/ar5211/ar5211_attach.c b/ar5211/ar5211_attach.c
new file mode 100644
index 0000000..cf658ec
--- /dev/null
+++ b/ar5211/ar5211_attach.c
@@ -0,0 +1,505 @@
+/*
+ * 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.8 2008/11/10 04:08:02 sam Exp $
+ */
+#include "opt_ah.h"
+
+#ifdef AH_SUPPORT_AR5211
+
+#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_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_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;
+
+ if (AH_PRIVATE(ah)->ah_currentRD == 1)
+ return AH_FALSE;
+
+ /* 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;
+}
+#endif /* AH_SUPPORT_AR5211 */
diff --git a/ar5211/ar5211_beacon.c b/ar5211/ar5211_beacon.c
new file mode 100644
index 0000000..de14198
--- /dev/null
+++ b/ar5211/ar5211_beacon.c
@@ -0,0 +1,176 @@
+/*
+ * 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.4 2008/11/10 04:08:02 sam Exp $
+ */
+#include "opt_ah.h"
+
+#ifdef AH_SUPPORT_AR5211
+
+#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_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
+}
+#endif /* AH_SUPPORT_AR5211 */
diff --git a/ar5211/ar5211_interrupts.c b/ar5211/ar5211_interrupts.c
new file mode 100644
index 0000000..3381dc5
--- /dev/null
+++ b/ar5211/ar5211_interrupts.c
@@ -0,0 +1,161 @@
+/*
+ * 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.5 2008/11/10 04:08:02 sam Exp $
+ */
+#include "opt_ah.h"
+
+#ifdef AH_SUPPORT_AR5211
+
+#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;
+ /*
+ * RXORN can hang the receive path so we force a hardware
+ */
+ 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;
+}
+#endif /* AH_SUPPORT_AR5211 */
diff --git a/ar5211/ar5211_keycache.c b/ar5211/ar5211_keycache.c
new file mode 100644
index 0000000..2a7ce28
--- /dev/null
+++ b/ar5211/ar5211_keycache.c
@@ -0,0 +1,181 @@
+/*
+ * 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.4 2008/11/10 04:08:02 sam Exp $
+ */
+#include "opt_ah.h"
+
+#ifdef AH_SUPPORT_AR5211
+
+#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);
+}
+#endif /* AH_SUPPORT_AR5211 */
diff --git a/ar5211/ar5211_misc.c b/ar5211/ar5211_misc.c
new file mode 100644
index 0000000..caeef5b
--- /dev/null
+++ b/ar5211/ar5211_misc.c
@@ -0,0 +1,640 @@
+/*
+ * 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.6 2008/11/10 04:08:02 sam Exp $
+ */
+#include "opt_ah.h"
+
+#ifdef AH_SUPPORT_AR5211
+
+#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;
+}
+
+/*
+ * 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)<<AR_BSS_ID1_AID_S));
+}
+
+/*
+ * Get the current hardware tsf for stamlme.
+ */
+uint64_t
+ar5211GetTsf64(struct ath_hal *ah)
+{
+ uint32_t low1, low2, u32;
+
+ /* sync multi-word read */
+ low1 = OS_REG_READ(ah, AR_TSF_L32);
+ u32 = OS_REG_READ(ah, AR_TSF_U32);
+ low2 = OS_REG_READ(ah, AR_TSF_L32);
+ if (low2 < low1) { /* roll over */
+ /*
+ * If we are not preempted this will work. If we are
+ * then we re-reading AR_TSF_U32 does no good as the
+ * low bits will be meaningless. Likewise reading
+ * L32, U32, U32, then comparing the last two reads
+ * to check for rollover
+ * doesn't help if preempted--so we take this approach
+ * as it costs one less PCI read which can be noticeable
+ * when doing things like timestamping packets in
+ * monitor mode.
+ */
+ u32++;
+ }
+ return (((uint64_t) u32) << 32) | ((uint64_t) low2);
+}
+
+/*
+ * Get the current hardware tsf for stamlme.
+ */
+uint32_t
+ar5211GetTsf32(struct ath_hal *ah)
+{
+ return OS_REG_READ(ah, AR_TSF_L32);
+}
+
+/*
+ * Reset the current hardware tsf for stamlme
+ */
+void
+ar5211ResetTsf(struct ath_hal *ah)
+{
+ uint32_t val = OS_REG_READ(ah, AR_BEACON);
+
+ OS_REG_WRITE(ah, AR_BEACON, val | AR_BEACON_RESET_TSF);
+}
+
+/*
+ * Grab a semi-random value from hardware registers - may not
+ * change often
+ */
+uint32_t
+ar5211GetRandomSeed(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
+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;
+}
+#endif /* AH_SUPPORT_AR5211 */
diff --git a/ar5211/ar5211_phy.c b/ar5211/ar5211_phy.c
new file mode 100644
index 0000000..b3be093
--- /dev/null
+++ b/ar5211/ar5211_phy.c
@@ -0,0 +1,107 @@
+/*
+ * 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.3 2008/11/10 01:19:37 sam Exp $
+ */
+#include "opt_ah.h"
+
+#ifdef AH_SUPPORT_AR5211
+
+#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 },
+/* 9 Mb */ { AH_TRUE, OFDM, 9000, 0x0f, 0x00, 18, 0 },
+/* 12 Mb */ { AH_TRUE, OFDM, 12000, 0x0a, 0x00, (0x80|24), 2 },
+/* 18 Mb */ { AH_TRUE, OFDM, 18000, 0x0e, 0x00, 36, 2 },
+/* 24 Mb */ { AH_TRUE, OFDM, 24000, 0x09, 0x00, (0x80|48), 4 },
+/* 36 Mb */ { AH_TRUE, OFDM, 36000, 0x0d, 0x00, 72, 4 },
+/* 48 Mb */ { AH_TRUE, OFDM, 48000, 0x08, 0x00, 96, 4 },
+/* 54 Mb */ { AH_TRUE, OFDM, 54000, 0x0c, 0x00, 108, 4 }
+ },
+};
+
+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 },
+/* 9 Mb */ { AH_TRUE, TURBO, 9000, 0x0f, 0x00, 18, 0 },
+/* 12 Mb */ { AH_TRUE, TURBO, 12000, 0x0a, 0x00, (0x80|24), 2 },
+/* 18 Mb */ { AH_TRUE, TURBO, 18000, 0x0e, 0x00, 36, 2 },
+/* 24 Mb */ { AH_TRUE, TURBO, 24000, 0x09, 0x00, (0x80|48), 4 },
+/* 36 Mb */ { AH_TRUE, TURBO, 36000, 0x0d, 0x00, 72, 4 },
+/* 48 Mb */ { AH_TRUE, TURBO, 48000, 0x08, 0x00, 96, 4 },
+/* 54 Mb */ { AH_TRUE, TURBO, 54000, 0x0c, 0x00, 108, 4 }
+ },
+};
+
+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 },
+/* 2 Mb */ { AH_TRUE, CCK, 2000, 0x0a, 0x04, (0x80| 4), 1 },
+/* 5.5 Mb */ { AH_TRUE, CCK, 5500, 0x09, 0x04, (0x80|11), 1 },
+/* 11 Mb */ { AH_TRUE, CCK, 11000, 0x08, 0x04, (0x80|22), 1 }
+ },
+};
+
+#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;
+}
+#endif /* AH_SUPPORT_AR5211 */
diff --git a/ar5211/ar5211_power.c b/ar5211/ar5211_power.c
new file mode 100644
index 0000000..8a40e97
--- /dev/null
+++ b/ar5211/ar5211_power.c
@@ -0,0 +1,139 @@
+/*
+ * 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.4 2008/11/10 04:08:02 sam Exp $
+ */
+#include "opt_ah.h"
+
+#ifdef AH_SUPPORT_AR5211
+
+#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);
+}
+#endif /* AH_SUPPORT_AR5211 */
diff --git a/ar5211/ar5211_recv.c b/ar5211/ar5211_recv.c
new file mode 100644
index 0000000..8cb801e
--- /dev/null
+++ b/ar5211/ar5211_recv.c
@@ -0,0 +1,248 @@
+/*
+ * 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.4 2008/11/10 04:08:02 sam Exp $
+ */
+#include "opt_ah.h"
+
+#ifdef AH_SUPPORT_AR5211
+
+#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<<ix)));
+ }
+ return AH_TRUE;
+}
+
+/*
+ * Set multicast filter by index
+ */
+HAL_BOOL
+ar5211SetMulticastFilterIndex(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<<ix)));
+ }
+ return AH_TRUE;
+}
+
+/*
+ * Get receive filter.
+ */
+uint32_t
+ar5211GetRxFilter(struct ath_hal *ah)
+{
+ return OS_REG_READ(ah, AR_RX_FILTER);
+}
+
+/*
+ * Set receive filter.
+ */
+void
+ar5211SetRxFilter(struct ath_hal *ah, uint32_t bits)
+{
+ OS_REG_WRITE(ah, AR_RX_FILTER, bits);
+}
+
+/*
+ * Initialize RX descriptor, by clearing the status and clearing
+ * the size. This is not strictly HW dependent, but we want the
+ * control and status words to be opaque above the hal.
+ */
+HAL_BOOL
+ar5211SetupRxDesc(struct ath_hal *ah, struct ath_desc *ds,
+ uint32_t size, u_int flags)
+{
+ struct ar5211_desc *ads = AR5211DESC(ds);
+
+ ads->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;
+}
+#endif /* AH_SUPPORT_AR5211 */
diff --git a/ar5211/ar5211_reset.c b/ar5211/ar5211_reset.c
new file mode 100644
index 0000000..87d6fac
--- /dev/null
+++ b/ar5211/ar5211_reset.c
@@ -0,0 +1,2126 @@
+/*
+ * 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.6 2008/11/10 04:08:03 sam Exp $
+ */
+#include "opt_ah.h"
+
+#ifdef AH_SUPPORT_AR5211
+/*
+ * 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
+const static 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 solution,
+ * 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. This will result 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<<q);
+
+ for (q = 0; q < HAL_NUM_TX_QUEUES; q++)
+ ar5211ResetTxQueue(ah, q);
+
+ /* Setup QCU0 transmit interrupt masks (TX_ERR, TX_OK, TX_DESC, TX_URN) */
+ OS_REG_WRITE(ah, AR_IMR_S0,
+ (AR_IMR_S0_QCU_TXOK & AR_QCU_0) |
+ (AR_IMR_S0_QCU_TXDESC & (AR_QCU_0<<AR_IMR_S0_QCU_TXDESC_S)));
+ OS_REG_WRITE(ah, AR_IMR_S1, (AR_IMR_S1_QCU_TXERR & AR_QCU_0));
+ OS_REG_WRITE(ah, AR_IMR_S2, (AR_IMR_S2_QCU_TXURN & AR_QCU_0));
+
+ /*
+ * GBL_EIFS must always be written after writing
+ * to any QCUMASK register.
+ */
+ OS_REG_WRITE(ah, AR_D_GBL_IFS_EIFS, OS_REG_READ(ah, AR_D_GBL_IFS_EIFS));
+
+ /* Now set up the Interrupt Mask Register and save it for future use */
+ OS_REG_WRITE(ah, AR_IMR, INIT_INTERRUPT_MASK);
+ ahp->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
+ar5211PerCalibration(struct ath_hal *ah, HAL_CHANNEL *chan, HAL_BOOL *isIQdone)
+{
+ 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);
+ }
+ }
+
+ /* 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);
+ *isIQdone = !ahp->ah_bIQCalibration;
+
+ 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;
+ 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__);
+ 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, lowerIndex=0, lowerPower=0;
+ uint16_t upperChannel, 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, 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, uPwr; /* 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);
+}
+#endif /* AH_SUPPORT_AR5211 */
diff --git a/ar5211/ar5211_xmit.c b/ar5211/ar5211_xmit.c
new file mode 100644
index 0000000..d40549a
--- /dev/null
+++ b/ar5211/ar5211_xmit.c
@@ -0,0 +1,682 @@
+/*
+ * 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.6 2008/11/10 04:08:03 sam Exp $
+ */
+#include "opt_ah.h"
+
+#ifdef AH_SUPPORT_AR5211
+
+#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;
+ }
+
+#ifndef AH_DISABLE_WME
+ /*
+ * This is a really not the right way to do it, but
+ * it does get the lockout bits and backoff set for the
+ * high-pri WME queues for testing. We need to either extend
+ * the meaning of queueInfo->mode, or create something like
+ * queueInfo->dcumode.
+ */
+ if (qi->tqi_intFlags & HAL_TXQ_USE_LOCKOUT_BKOFF_DIS) {
+ OS_REG_WRITE(ah, AR_DMISC(q),
+ OS_REG_READ(ah, AR_DMISC(q)) |
+ SM(AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL,
+ AR_D_MISC_ARB_LOCKOUT_CNTRL)|
+ AR_D_MISC_POST_FR_BKOFF_DIS);
+ }
+#endif
+
+ /*
+ * 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<<q)) == 0);
+
+ 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 frames pending on the specified queue.
+ */
+uint32_t
+ar5211NumTxPending(struct ath_hal *ah, u_int q)
+{
+ uint32_t n;
+
+ HALASSERT(q < HAL_NUM_TX_QUEUES);
+ HALASSERT(AH5211(ah)->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<<q)))
+ n = 1; /* arbitrarily pick 1 */
+ return n;
+}
+
+/*
+ * Stop transmit on the specified queue
+ */
+HAL_BOOL
+ar5211StopTxDma(struct ath_hal *ah, u_int q)
+{
+ int i;
+
+ HALASSERT(q < HAL_NUM_TX_QUEUES);
+ HALASSERT(AH5211(ah)->ah_txq[q].tqi_type != HAL_TX_QUEUE_INACTIVE);
+
+ OS_REG_WRITE(ah, AR_Q_TXD, 1<<q);
+ for (i = 0; i < 10000; i++) {
+ if (ar5211NumTxPending(ah, q) == 0)
+ break;
+ OS_DELAY(10);
+ }
+ OS_REG_WRITE(ah, AR_Q_TXD, 0);
+
+ return (i < 10000);
+}
+
+/*
+ * Descriptor Access Functions
+ */
+
+#define VALID_PKT_TYPES \
+ ((1<<HAL_PKT_TYPE_NORMAL)|(1<<HAL_PKT_TYPE_ATIM)|\
+ (1<<HAL_PKT_TYPE_PSPOLL)|(1<<HAL_PKT_TYPE_PROBE_RESP)|\
+ (1<<HAL_PKT_TYPE_BEACON))
+#define isValidPktType(_t) ((1<<(_t)) & VALID_PKT_TYPES)
+#define VALID_TX_RATES \
+ ((1<<0x0b)|(1<<0x0f)|(1<<0x0a)|(1<<0x0e)|(1<<0x09)|(1<<0x0d)|\
+ (1<<0x08)|(1<<0x0c)|(1<<0x1b)|(1<<0x1a)|(1<<0x1e)|(1<<0x19)|\
+ (1<<0x1d)|(1<<0x18)|(1<<0x1c))
+#define isValidTxRate(_r) ((1<<(_r)) & VALID_TX_RATES)
+
+HAL_BOOL
+ar5211SetupTxDesc(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)
+{
+ struct ar5211_desc *ads = AR5211DESC(ds);
+
+ (void) hdrLen;
+ (void) txPower;
+ (void) rtsctsRate; (void) rtsctsDuration;
+
+ HALASSERT(txTries0 != 0);
+ HALASSERT(isValidPktType(type));
+ HALASSERT(isValidTxRate(txRate0));
+ /* XXX validate antMode */
+
+ ads->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;
+}
+#endif /* AH_SUPPORT_AR5211 */
diff --git a/ar5211/ar5211desc.h b/ar5211/ar5211desc.h
new file mode 100644
index 0000000..9fa6e29
--- /dev/null
+++ b/ar5211/ar5211desc.h
@@ -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.5 2008/11/10 04:08:03 sam 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_ */
diff --git a/ar5211/ar5211phy.h b/ar5211/ar5211phy.h
new file mode 100644
index 0000000..8bd7051
--- /dev/null
+++ b/ar5211/ar5211phy.h
@@ -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.4 2008/11/10 01:19:38 sam 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 */
diff --git a/ar5211/ar5211reg.h b/ar5211/ar5211reg.h
new file mode 100644
index 0000000..babd565
--- /dev/null
+++ b/ar5211/ar5211reg.h
@@ -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.4 2008/11/10 01:19:38 sam 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 */
diff --git a/ar5211/boss.ini b/ar5211/boss.ini
new file mode 100755
index 0000000..a041c44
--- /dev/null
+++ b/ar5211/boss.ini
@@ -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.3 2008/11/10 04:08:03 sam 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 },
+};
+
diff --git a/ar5212/ar2316.c b/ar5212/ar2316.c
new file mode 100644
index 0000000..9279864
--- /dev/null
+++ b/ar5212/ar2316.c
@@ -0,0 +1,753 @@
+/*
+ * 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.8 2008/11/10 04:08:03 sam Exp $
+ */
+#include "opt_ah.h"
+
+#ifdef AH_SUPPORT_2316
+
+#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, idxR;
+
+ 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, idxR;
+ 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 i, reg32, regoffset, tpcrg1;
+ int numPdGainsUsed;
+
+ 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);
+
+#if 0
+ OS_REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN,
+ (pRawDataset->pDataPerChannel[0].numPdGains - 1));
+#endif
+ 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);
+
+ /*
+ * 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; (i<numChannels) && (chan->channel > 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
+ */
+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;
+}
+#endif /* AH_SUPPORT_2316 */
diff --git a/ar5212/ar2317.c b/ar5212/ar2317.c
new file mode 100644
index 0000000..3f11d8f
--- /dev/null
+++ b/ar5212/ar2317.c
@@ -0,0 +1,736 @@
+/*
+ * 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.7 2008/11/10 04:08:03 sam Exp $
+ */
+#include "opt_ah.h"
+
+#ifdef AH_SUPPORT_2317
+
+#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_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, idxR;
+
+ 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, idxR;
+ 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 i, reg32, regoffset, tpcrg1;
+ int numPdGainsUsed;
+
+ 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);
+
+ /*
+ * 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.
+ */
+#if 0
+ OS_REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN,
+ (pRawDataset->pDataPerChannel[0].numPdGains - 1));
+#endif
+ 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);
+
+ /*
+ * 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; (i<numChannels) && (chan->channel > 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
+ */
+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;
+}
+#endif /* AH_SUPPORT_2317 */
diff --git a/ar5212/ar2413.c b/ar5212/ar2413.c
new file mode 100644
index 0000000..803c77b
--- /dev/null
+++ b/ar5212/ar2413.c
@@ -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: ar2413.c,v 1.7 2008/11/10 04:08:03 sam Exp $
+ */
+#include "opt_ah.h"
+
+#ifdef AH_SUPPORT_2413
+
+#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, idxR;
+
+ 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, idxR;
+ 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 i, reg32, regoffset, tpcrg1;
+ int numPdGainsUsed;
+
+ 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);
+
+#if 0
+ OS_REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN,
+ (pRawDataset->pDataPerChannel[0].numPdGains - 1));
+#endif
+ 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);
+
+ /*
+ * 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; (i<numChannels) && (chan->channel > 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
+ */
+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;
+}
+#endif /* AH_SUPPORT_2413 */
diff --git a/ar5212/ar2425.c b/ar5212/ar2425.c
new file mode 100644
index 0000000..5bd64d5
--- /dev/null
+++ b/ar5212/ar2425.c
@@ -0,0 +1,724 @@
+/*
+ * 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.7 2008/11/10 04:08:03 sam Exp $
+ */
+#include "opt_ah.h"
+
+#ifdef AH_SUPPORT_2425
+
+#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
+#ifdef AH_SUPPORT_2417
+#define AH_5212_2417
+#endif
+#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);
+#if 0
+ uint16_t ob2GHz = 0, db2GHz = 0;
+#endif
+ struct ar2425State *priv = AR2425(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);
+#if 0
+ /* Setup rf parameters */
+ switch (chan->channelFlags & CHANNEL_ALL) {
+ case CHANNEL_B:
+ ob2GHz = ahp->ah_obFor24;
+ db2GHz = ahp->ah_dbFor24;
+ break;
+ case CHANNEL_G:
+ case CHANNEL_108G:
+ ob2GHz = ahp->ah_obFor24g;
+ db2GHz = ahp->ah_dbFor24g;
+ break;
+ default:
+ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel flags 0x%x\n",
+ __func__, chan->channelFlags);
+ return AH_FALSE;
+ }
+#endif
+ /* 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);
+#if 0
+ ar5212ModifyRfBuffer(priv->Bank6Data, ob2GHz, 3, 193, 0);
+ ar5212ModifyRfBuffer(priv->Bank6Data, db2GHz, 3, 190, 0);
+#endif
+ /* 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);
+#ifdef AH_SUPPORT_2417
+ if (IS_2417(ah)) {
+ HALASSERT(N(ar5212Bank6_2425) == N(ar5212Bank6_2417));
+ HAL_INI_WRITE_BANK(ah, ar5212Bank6_2417, priv->Bank6Data,
+ regWrites);
+ } else
+#endif /* AH_SUPPORT_2417 */
+ 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, idxR;
+
+ 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, idxR;
+ 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; (i<numChannels) && (chan->channel > 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
+ */
+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;
+}
+#endif /* AH_SUPPORT_2425 */
diff --git a/ar5212/ar5111.c b/ar5212/ar5111.c
new file mode 100644
index 0000000..984ad58
--- /dev/null
+++ b/ar5212/ar5111.c
@@ -0,0 +1,707 @@
+/*
+ * 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.7 2008/11/10 04:08:03 sam Exp $
+ */
+#include "opt_ah.h"
+
+#ifdef AH_SUPPORT_5111
+
+#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;
+
+ const static 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, uPwr; /* 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
+ */
+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;
+}
+#endif /* AH_SUPPORT_5111 */
diff --git a/ar5212/ar5112.c b/ar5212/ar5112.c
new file mode 100644
index 0000000..ec9d034
--- /dev/null
+++ b/ar5212/ar5112.c
@@ -0,0 +1,877 @@
+/*
+ * 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.7 2008/11/10 04:08:03 sam Exp $
+ */
+#include "opt_ah.h"
+
+#ifdef AH_SUPPORT_5112
+
+#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; i<NUM_XPD_PER_CHANNEL; i++) {
+ if (data->pDataPerXPD[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; i<NUM_POINTS_XPD0; i++) {
+ if (data->pDataPerXPD[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;
+ (i<numChannels) && (chan->channel > 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
+ */
+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;
+}
+#endif /* AH_SUPPORT_5112 */
diff --git a/ar5212/ar5212.h b/ar5212/ar5212.h
new file mode 100644
index 0000000..d8f9aa4
--- /dev/null
+++ b/ar5212/ar5212.h
@@ -0,0 +1,601 @@
+/*
+ * 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.9 2008/11/10 04:08:03 sam 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];
+ /* decomp mask array */
+ uint8_t ah_decompMask[HAL_DECOMP_MASK_SIZE];
+ HAL_POWER_MODE ah_powerMode;
+ HAL_ANT_SETTING ah_diversityControl; /* antenna 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 */
+ 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 */
+ /*
+ * XXX
+ * 11g-specific stuff; belongs in the driver.
+ */
+ uint8_t ah_gBeaconRate; /* fixed rate for G beacons */
+ /*
+ * 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 */
+ HAL_BOOL ah_eepEnabled; /* EEPROM bit for capability */
+ /*
+ * 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];
+
+ /*
+ * Tx queue interrupt state.
+ */
+ uint32_t ah_intrTxqs;
+
+ HAL_BOOL ah_isHb63; /* cached HB63 check */
+};
+#define AH5212(_ah) ((struct ath_hal_5212 *)(_ah))
+
+#define IS_5112(ah) \
+ ((AH_PRIVATE(ah)->ah_analog5GhzRev&0xf0) >= AR_RAD5112_SREV_MAJOR \
+ && (AH_PRIVATE(ah)->ah_analog5GhzRev&0xf0) < AR_RAD2316_SREV_MAJOR )
+#define IS_RAD5112_REV1(ah) \
+ ((AH_PRIVATE(ah)->ah_analog5GhzRev&0x0f) < (AR_RAD5112_SREV_2_0&0x0f))
+#define IS_RADX112_REV2(ah) \
+ (IS_5112(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 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_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 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)
+
+extern HAL_BOOL ar5111RfAttach(struct ath_hal *, HAL_STATUS *);
+extern HAL_BOOL ar5112RfAttach(struct ath_hal *, HAL_STATUS *);
+extern HAL_BOOL ar2413RfAttach(struct ath_hal *, HAL_STATUS *);
+extern HAL_BOOL ar5413RfAttach(struct ath_hal *, HAL_STATUS *);
+extern HAL_BOOL ar2316RfAttach(struct ath_hal *, HAL_STATUS *);
+extern HAL_BOOL ar2317RfAttach(struct ath_hal *, HAL_STATUS *);
+extern HAL_BOOL ar2425RfAttach(struct ath_hal *, HAL_STATUS *);
+
+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 struct ath_hal * ar5212Attach(uint16_t devid, HAL_SOFTC sc,
+ 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 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 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_ */
diff --git a/ar5212/ar5212.ini b/ar5212/ar5212.ini
new file mode 100644
index 0000000..d53dbe2
--- /dev/null
+++ b/ar5212/ar5212.ini
@@ -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.3 2008/11/10 04:08:03 sam 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 */
diff --git a/ar5212/ar5212_ani.c b/ar5212/ar5212_ani.c
new file mode 100644
index 0000000..8d9d8c0
--- /dev/null
+++ b/ar5212/ar5212_ani.c
@@ -0,0 +1,968 @@
+/*
+ * 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.5 2008/11/10 04:08:03 sam Exp $
+ */
+#include "opt_ah.h"
+
+#ifdef AH_SUPPORT_AR5212
+
+#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 < params->maxNoiseImmunityLevel) {
+ ar5212AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL,
+ aniState->noiseImmunityLevel + 1);
+ return;
+ }
+ /* then, raise spur immunity level, up to max */
+ if (aniState->spurImmunityLevel < params->maxSpurImmunityLevel) {
+ 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) {
+ 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 < params->maxFirstepLevel) {
+ 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)
+ ar5212AniControl(ah,
+ HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION,
+ AH_TRUE);
+ if (aniState->firstepLevel < params->maxFirstepLevel)
+ 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)
+ ar5212AniControl(ah,
+ HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION,
+ AH_FALSE);
+ if (aniState->firstepLevel > 0)
+ 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 < params->maxNoiseImmunityLevel) {
+ 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 < params->maxFirstepLevel)
+ 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)
+ 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!
+ */
+ HALDEBUG(ah, HAL_DEBUG_ANI,
+ "%s: Writing ofdmbase=%u cckbase=%u\n", __func__,
+ params->ofdmPhyErrBase, params->cckPhyErrBase);
+ 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) {
+ ar5212AniControl(ah,
+ HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION,
+ AH_TRUE);
+ return;
+ }
+ if (aniState->firstepLevel > 0) {
+ ar5212AniControl(ah, HAL_ANI_FIRSTEP_LEVEL,
+ aniState->firstepLevel - 1);
+ return;
+ }
+ } else {
+ /*
+ * Beacon rssi is low, reduce firstep level.
+ */
+ if (aniState->firstepLevel > 0) {
+ ar5212AniControl(ah, HAL_ANI_FIRSTEP_LEVEL,
+ aniState->firstepLevel - 1);
+ return;
+ }
+ }
+ }
+ /* then lower spur immunity level, down to zero */
+ if (aniState->spurImmunityLevel > 0) {
+ 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) {
+ 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) {
+ ar5212AniOfdmErrTrigger(ah);
+ ar5212AniRestart(ah, aniState);
+ } else if (aniState->cckPhyErrCount > aniState->listenTime *
+ params->cckTrigHigh / 1000) {
+ ar5212AniCckErrTrigger(ah);
+ ar5212AniRestart(ah, aniState);
+ }
+ }
+}
+#endif /* AH_SUPPORT_AR5212 */
diff --git a/ar5212/ar5212_attach.c b/ar5212/ar5212_attach.c
new file mode 100644
index 0000000..413a002
--- /dev/null
+++ b/ar5212/ar5212_attach.c
@@ -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: ar5212_attach.c,v 1.12 2008/11/10 04:08:03 sam Exp $
+ */
+#include "opt_ah.h"
+
+#ifdef AH_SUPPORT_AR5212
+
+#if !defined(AH_SUPPORT_5112) && \
+ !defined(AH_SUPPORT_5111) && \
+ !defined(AH_SUPPORT_2413) && \
+ !defined(AH_SUPPORT_5413) && \
+ !defined(AH_SUPPORT_AR5312)
+#error "No 5212 RF support defined"
+#endif
+
+#include "ah.h"
+#include "ah_internal.h"
+#include "ah_devid.h"
+
+#include "ar5212/ar5212.h"
+#include "ar5212/ar5212reg.h"
+#include "ar5212/ar5212phy.h"
+#ifdef AH_SUPPORT_AR5311
+#include "ar5212/ar5311reg.h"
+#endif
+
+#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_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_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_diversityControl = HAL_ANT_VARIABLE;
+ 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_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);
+
+ /*
+ * 11g-specific stuff
+ */
+ ahp->ah_gBeaconRate = 0; /* adhoc beacon fixed rate */
+#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.
+ */
+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;
+ uint32_t val;
+ uint16_t eeval;
+ 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 */
+ 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);
+ /* 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 = 0x51;
+ break;
+ }
+ if (IS_5413(ah)) { /* Eagle */
+ AH_PRIVATE(ah)->ah_analog5GhzRev = 0x62;
+ break;
+ }
+ if (IS_2425(ah) || IS_2417(ah)) {/* Swan or Nala */
+ AH_PRIVATE(ah)->ah_analog5GhzRev = 0xA2;
+ 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_5413(ah) && IS_5112(ah) && 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;
+ }
+
+ rfStatus = AH_FALSE;
+ if (IS_5413(ah)) {
+#ifdef AH_SUPPORT_5413
+ rfStatus = ar5413RfAttach(ah, &ecode);
+#else
+ ecode = HAL_ENOTSUPP;
+#endif
+ }
+ else if (IS_2413(ah))
+#ifdef AH_SUPPORT_2413
+ rfStatus = ar2413RfAttach(ah, &ecode);
+#else
+ ecode = HAL_ENOTSUPP;
+#endif
+ else if (IS_5112(ah))
+#ifdef AH_SUPPORT_5112
+ rfStatus = ar5112RfAttach(ah, &ecode);
+#else
+ ecode = HAL_ENOTSUPP;
+#endif
+ else if (IS_2425(ah) || IS_2417(ah))
+#ifdef AH_SUPPORT_2425
+ rfStatus = ar2425RfAttach(ah, &ecode);
+#else
+ ecode = HAL_ENOTSUPP;
+#endif
+ else
+#ifdef AH_SUPPORT_5111
+ rfStatus = ar5111RfAttach(ah, &ecode);
+#else
+ ecode = HAL_ENOTSUPP;
+#endif
+ if (!rfStatus) {
+ 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;
+ if (IS_5112(ah) || IS_2413(ah) || IS_5413(ah) || IS_2425(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;
+
+ if (IS_5112(ah)) {
+ pCap->halChanHalfRate = AH_TRUE;
+ pCap->halChanQuarterRate = AH_TRUE;
+ } else {
+ /* 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;
+ }
+
+ /* 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
+}
+#endif /* AH_SUPPORT_AR5212 */
diff --git a/ar5212/ar5212_beacon.c b/ar5212/ar5212_beacon.c
new file mode 100644
index 0000000..db604c9
--- /dev/null
+++ b/ar5212/ar5212_beacon.c
@@ -0,0 +1,256 @@
+/*
+ * 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.6 2008/11/10 04:08:03 sam Exp $
+ */
+#include "opt_ah.h"
+
+#ifdef AH_SUPPORT_AR5212
+
+#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
+}
+#endif /* AH_SUPPORT_AR5212 */
diff --git a/ar5212/ar5212_eeprom.c b/ar5212/ar5212_eeprom.c
new file mode 100644
index 0000000..433deff
--- /dev/null
+++ b/ar5212/ar5212_eeprom.c
@@ -0,0 +1,56 @@
+/*
+ * 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.6 2008/11/10 04:08:03 sam Exp $
+ */
+#include "opt_ah.h"
+
+#ifdef AH_SUPPORT_AR5212
+
+#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"
+#ifdef AH_SUPPORT_AR5311
+#include "ar5212/ar5311reg.h"
+#endif
+
+/*
+ * 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;
+}
+#endif /* AH_SUPPORT_AR5212 */
diff --git a/ar5212/ar5212_gpio.c b/ar5212/ar5212_gpio.c
new file mode 100644
index 0000000..85bbf3b
--- /dev/null
+++ b/ar5212/ar5212_gpio.c
@@ -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: ar5212_gpio.c,v 1.3 2008/11/10 04:08:03 sam Exp $
+ */
+#include "opt_ah.h"
+
+#ifdef AH_SUPPORT_AR5212
+
+#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"
+#ifdef AH_SUPPORT_AR5311
+#include "ar5212/ar5311reg.h"
+#endif
+
+#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);
+}
+
+#endif /* AH_SUPPORT_AR5212 */
diff --git a/ar5212/ar5212_interrupts.c b/ar5212/ar5212_interrupts.c
new file mode 100644
index 0000000..8383645
--- /dev/null
+++ b/ar5212/ar5212_interrupts.c
@@ -0,0 +1,207 @@
+/*
+ * 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.5 2008/11/10 04:08:03 sam Exp $
+ */
+#include "opt_ah.h"
+
+#ifdef AH_SUPPORT_AR5212
+
+#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);
+ }
+
+ /*
+ * RXORN can hang the receive path so we force a hardware
+ */
+ 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;
+}
+#endif /* AH_SUPPORT_AR5212 */
diff --git a/ar5212/ar5212_keycache.c b/ar5212/ar5212_keycache.c
new file mode 100644
index 0000000..864daba
--- /dev/null
+++ b/ar5212/ar5212_keycache.c
@@ -0,0 +1,288 @@
+/*
+ * 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.4 2008/11/10 04:08:03 sam Exp $
+ */
+#include "opt_ah.h"
+
+#ifdef AH_SUPPORT_AR5212
+
+#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;
+}
+#endif /* AH_SUPPORT_AR5212 */
diff --git a/ar5212/ar5212_misc.c b/ar5212/ar5212_misc.c
new file mode 100644
index 0000000..5f01104
--- /dev/null
+++ b/ar5212/ar5212_misc.c
@@ -0,0 +1,1033 @@
+/*
+ * 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.8 2008/11/10 04:08:03 sam Exp $
+ */
+#include "opt_ah.h"
+
+#ifdef AH_SUPPORT_AR5212
+
+#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"
+#ifdef AH_SUPPORT_AR5311
+#include "ar5212/ar5311reg.h"
+#endif
+
+#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;
+}
+
+/*
+ * 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 (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;
+ }
+ 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)<<AR_BSS_ID1_AID_S));
+}
+
+/*
+ * Get the current hardware tsf for stamlme
+ */
+uint64_t
+ar5212GetTsf64(struct ath_hal *ah)
+{
+ uint32_t low1, low2, u32;
+
+ /* sync multi-word read */
+ low1 = OS_REG_READ(ah, AR_TSF_L32);
+ u32 = OS_REG_READ(ah, AR_TSF_U32);
+ low2 = OS_REG_READ(ah, AR_TSF_L32);
+ if (low2 < low1) { /* roll over */
+ /*
+ * If we are not preempted this will work. If we are
+ * then we re-reading AR_TSF_U32 does no good as the
+ * low bits will be meaningless. Likewise reading
+ * L32, U32, U32, then comparing the last two reads
+ * to check for rollover
+ * doesn't help if preempted--so we take this approach
+ * as it costs one less PCI read which can be noticeable
+ * when doing things like timestamping packets in
+ * monitor mode.
+ */
+ u32++;
+ }
+ return (((uint64_t) u32) << 32) | ((uint64_t) low2);
+}
+
+/*
+ * Get the current hardware tsf for stamlme
+ */
+uint32_t
+ar5212GetTsf32(struct ath_hal *ah)
+{
+ return OS_REG_READ(ah, AR_TSF_L32);
+}
+
+/*
+ * Reset the current hardware tsf for stamlme.
+ */
+void
+ar5212ResetTsf(struct ath_hal *ah)
+{
+
+ uint32_t val = OS_REG_READ(ah, AR_BEACON);
+
+ OS_REG_WRITE(ah, AR_BEACON, val | 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, val | AR_BEACON_RESET_TSF);
+}
+
+/*
+ * Set or clear hardware basic rate bit
+ * Set hardware basic rate set if basic rate is found
+ * and basic rate is equal or less than 2Mbps
+ */
+void
+ar5212SetBasicRate(struct ath_hal *ah, HAL_RATE_SET *rs)
+{
+ HAL_CHANNEL_INTERNAL *chan = AH_PRIVATE(ah)->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_diversityControl;
+}
+
+HAL_BOOL
+ar5212SetAntennaSwitch(struct ath_hal *ah, HAL_ANT_SETTING settings)
+{
+ const HAL_CHANNEL_INTERNAL *chan = AH_PRIVATE(ah)->ah_curchan;
+
+ if (chan == AH_NULL) {
+ AH5212(ah)->ah_diversityControl = settings;
+ return AH_TRUE;
+ }
+ return ar5212SetAntennaSwitchInternal(ah, settings, chan);
+}
+
+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_5112(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_5112(ah) || IS_2417(ah) ? 0x14 : 0x18);
+ OS_REG_RMW_FIELD(ah, AR_USEC, AR_USEC_USEC32, IS_5112(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_5112(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_5112(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 (OS_REG_READ(ah, AR_PHY_CCK_DETECT) &
+ AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV) ?
+ 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:
+ 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);
+ 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;
+}
+#endif /* AH_SUPPORT_AR5212 */
diff --git a/ar5212/ar5212_phy.c b/ar5212/ar5212_phy.c
new file mode 100644
index 0000000..48469ad
--- /dev/null
+++ b/ar5212/ar5212_phy.c
@@ -0,0 +1,200 @@
+/*
+ * 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.4 2008/11/10 01:19:38 sam Exp $
+ */
+#include "opt_ah.h"
+
+#ifdef AH_SUPPORT_AR5212
+
+#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 },
+/* 9 Mb */ { AH_TRUE, OFDM, 9000, 0x0f, 0x00, 18, 0 },
+/* 12 Mb */ { AH_TRUE, OFDM, 12000, 0x0a, 0x00, (0x80|24), 2 },
+/* 18 Mb */ { AH_TRUE, OFDM, 18000, 0x0e, 0x00, 36, 2 },
+/* 24 Mb */ { AH_TRUE, OFDM, 24000, 0x09, 0x00, (0x80|48), 4 },
+/* 36 Mb */ { AH_TRUE, OFDM, 36000, 0x0d, 0x00, 72, 4 },
+/* 48 Mb */ { AH_TRUE, OFDM, 48000, 0x08, 0x00, 96, 4 },
+/* 54 Mb */ { AH_TRUE, OFDM, 54000, 0x0c, 0x00, 108, 4 }
+ },
+};
+
+HAL_RATE_TABLE ar5212_11a_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 },
+/* 9 Mb */ { AH_TRUE, OFDM, 4500, 0x0f, 0x00, 9, 0 },
+/* 12 Mb */ { AH_TRUE, OFDM, 6000, 0x0a, 0x00, (0x80|12), 2 },
+/* 18 Mb */ { AH_TRUE, OFDM, 9000, 0x0e, 0x00, 18, 2 },
+/* 24 Mb */ { AH_TRUE, OFDM, 12000, 0x09, 0x00, (0x80|24), 4 },
+/* 36 Mb */ { AH_TRUE, OFDM, 18000, 0x0d, 0x00, 36, 4 },
+/* 48 Mb */ { AH_TRUE, OFDM, 24000, 0x08, 0x00, 48, 4 },
+/* 54 Mb */ { AH_TRUE, OFDM, 27000, 0x0c, 0x00, 54, 4 }
+ },
+};
+
+HAL_RATE_TABLE ar5212_11a_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 },
+/* 9 Mb */ { AH_TRUE, OFDM, 2250, 0x0f, 0x00, 4, 0 },
+/* 12 Mb */ { AH_TRUE, OFDM, 3000, 0x0a, 0x00, (0x80|6), 2 },
+/* 18 Mb */ { AH_TRUE, OFDM, 4500, 0x0e, 0x00, 9, 2 },
+/* 24 Mb */ { AH_TRUE, OFDM, 6000, 0x09, 0x00, (0x80|12), 4 },
+/* 36 Mb */ { AH_TRUE, OFDM, 9000, 0x0d, 0x00, 18, 4 },
+/* 48 Mb */ { AH_TRUE, OFDM, 12000, 0x08, 0x00, 24, 4 },
+/* 54 Mb */ { AH_TRUE, OFDM, 13500, 0x0c, 0x00, 27, 4 }
+ },
+};
+
+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 },
+/* 12 Mb */ { AH_TRUE, TURBO, 12000, 0x0a, 0x00, (0x80|24), 2 },
+/* 18 Mb */ { AH_TRUE, TURBO, 18000, 0x0e, 0x00, 36, 2 },
+/* 24 Mb */ { AH_TRUE, TURBO, 24000, 0x09, 0x00, (0x80|48), 3 },
+/* 36 Mb */ { AH_TRUE, TURBO, 36000, 0x0d, 0x00, 72, 3 },
+/* 48 Mb */ { AH_TRUE, TURBO, 48000, 0x08, 0x00, 96, 3 },
+/* 54 Mb */ { AH_TRUE, TURBO, 54000, 0x0c, 0x00, 108, 3 }
+ },
+};
+
+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 },
+/* 9 Mb */ { AH_TRUE, TURBO, 9000, 0x0f, 0x00, 18, 0 },
+/* 12 Mb */ { AH_TRUE, TURBO, 12000, 0x0a, 0x00, (0x80|24), 2 },
+/* 18 Mb */ { AH_TRUE, TURBO, 18000, 0x0e, 0x00, 36, 2 },
+/* 24 Mb */ { AH_TRUE, TURBO, 24000, 0x09, 0x00, (0x80|48), 4 },
+/* 36 Mb */ { AH_TRUE, TURBO, 36000, 0x0d, 0x00, 72, 4 },
+/* 48 Mb */ { AH_TRUE, TURBO, 48000, 0x08, 0x00, 96, 4 },
+/* 54 Mb */ { AH_TRUE, TURBO, 54000, 0x0c, 0x00, 108, 4 }
+ },
+};
+
+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 },
+/* 2 Mb */ { AH_TRUE, CCK, 2000, 0x1a, 0x04, (0x80| 4), 1 },
+/* 5.5 Mb */ { AH_TRUE, CCK, 5500, 0x19, 0x04, (0x80|11), 1 },
+/* 11 Mb */ { AH_TRUE, CCK, 11000, 0x18, 0x04, (0x80|22), 1 }
+ },
+};
+
+
+/* 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 },
+/* 2 Mb */ { AH_TRUE, CCK, 2000, 0x1a, 0x04, (0x80| 4), 1 },
+/* 5.5 Mb */ { AH_TRUE, CCK, 5500, 0x19, 0x04, (0x80|11), 2 },
+/* 11 Mb */ { AH_TRUE, CCK, 11000, 0x18, 0x04, (0x80|22), 3 },
+/* remove rates 6, 9 from rate ctrl */
+/* 6 Mb */ { AH_FALSE, OFDM, 6000, 0x0b, 0x00, 12, 4 },
+/* 9 Mb */ { AH_FALSE, OFDM, 9000, 0x0f, 0x00, 18, 4 },
+/* 12 Mb */ { AH_TRUE, OFDM, 12000, 0x0a, 0x00, 24, 6 },
+/* 18 Mb */ { AH_TRUE, OFDM, 18000, 0x0e, 0x00, 36, 6 },
+/* 24 Mb */ { AH_TRUE, OFDM, 24000, 0x09, 0x00, 48, 8 },
+/* 36 Mb */ { AH_TRUE, OFDM, 36000, 0x0d, 0x00, 72, 8 },
+/* 48 Mb */ { AH_TRUE, OFDM, 48000, 0x08, 0x00, 96, 8 },
+/* 54 Mb */ { AH_TRUE, OFDM, 54000, 0x0c, 0x00, 108, 8 }
+ },
+};
+
+#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:
+ rt = &ar5212_11a_half_table;
+ break;
+ case HAL_MODE_11A_QUARTER_RATE:
+ rt = &ar5212_11a_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;
+}
+#endif /* AH_SUPPORT_AR5212 */
diff --git a/ar5212/ar5212_power.c b/ar5212/ar5212_power.c
new file mode 100644
index 0000000..c7d90e4
--- /dev/null
+++ b/ar5212/ar5212_power.c
@@ -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: ar5212_power.c,v 1.4 2008/11/10 04:08:03 sam Exp $
+ */
+#include "opt_ah.h"
+
+#ifdef AH_SUPPORT_AR5212
+
+#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
+#endif /* AH_SUPPORT_AR5212 */
diff --git a/ar5212/ar5212_recv.c b/ar5212/ar5212_recv.c
new file mode 100644
index 0000000..765fd2e
--- /dev/null
+++ b/ar5212/ar5212_recv.c
@@ -0,0 +1,289 @@
+/*
+ * 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.4 2008/11/10 04:08:03 sam Exp $
+ */
+#include "opt_ah.h"
+
+#ifdef AH_SUPPORT_AR5212
+
+#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<<ix)));
+ }
+ return AH_TRUE;
+}
+
+/*
+ * Set multicast filter by index
+ */
+HAL_BOOL
+ar5212SetMulticastFilterIndex(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<<ix)));
+ }
+ return AH_TRUE;
+}
+
+/*
+ * Get the receive filter.
+ */
+uint32_t
+ar5212GetRxFilter(struct ath_hal *ah)
+{
+ uint32_t bits = OS_REG_READ(ah, AR_RX_FILTER);
+ uint32_t phybits = OS_REG_READ(ah, AR_PHY_ERR);
+ if (phybits & AR_PHY_ERR_RADAR)
+ bits |= HAL_RX_FILTER_PHYRADAR;
+ if (phybits & (AR_PHY_ERR_OFDM_TIMING|AR_PHY_ERR_CCK_TIMING))
+ bits |= HAL_RX_FILTER_PHYERR;
+ return bits;
+}
+
+/*
+ * Set the receive filter.
+ */
+void
+ar5212SetRxFilter(struct ath_hal *ah, uint32_t bits)
+{
+ uint32_t phybits;
+
+ OS_REG_WRITE(ah, AR_RX_FILTER,
+ bits &~ (HAL_RX_FILTER_PHYRADAR|HAL_RX_FILTER_PHYERR));
+ phybits = 0;
+ if (bits & HAL_RX_FILTER_PHYRADAR)
+ phybits |= AR_PHY_ERR_RADAR;
+ if (bits & HAL_RX_FILTER_PHYERR)
+ phybits |= AR_PHY_ERR_OFDM_TIMING | AR_PHY_ERR_CCK_TIMING;
+ OS_REG_WRITE(ah, AR_PHY_ERR, phybits);
+ if (phybits) {
+ OS_REG_WRITE(ah, AR_RXCFG,
+ OS_REG_READ(ah, AR_RXCFG) | AR_RXCFG_ZLFDMA);
+ } else {
+ OS_REG_WRITE(ah, AR_RXCFG,
+ OS_REG_READ(ah, AR_RXCFG) &~ AR_RXCFG_ZLFDMA);
+ }
+}
+
+/*
+ * Initialize RX descriptor, by clearing the status and setting
+ * the size (and any other flags).
+ */
+HAL_BOOL
+ar5212SetupRxDesc(struct ath_hal *ah, struct ath_desc *ds,
+ uint32_t size, u_int flags)
+{
+ struct ar5212_desc *ads = AR5212DESC(ds);
+
+ HALASSERT((size &~ AR_BufLen) == 0);
+
+ ads->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;
+}
+#endif /* AH_SUPPORT_AR5212 */
diff --git a/ar5212/ar5212_reset.c b/ar5212/ar5212_reset.c
new file mode 100644
index 0000000..11bf2d2
--- /dev/null
+++ b/ar5212/ar5212_reset.c
@@ -0,0 +1,2959 @@
+/*
+ * 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.12 2008/11/10 04:08:03 sam Exp $
+ */
+#include "opt_ah.h"
+
+#ifdef AH_SUPPORT_AR5212
+
+#include "ah.h"
+#include "ah_internal.h"
+#include "ah_devid.h"
+
+#include "ar5212/ar5212.h"
+#include "ar5212/ar5212reg.h"
+#include "ar5212/ar5212phy.h"
+#ifdef AH_SUPPORT_AR5311
+#include "ar5212/ar5311reg.h"
+#endif
+
+#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);
+static void ar5212RequestRfgain(struct ath_hal *);
+static HAL_BOOL ar5212InvalidGainReadback(struct ath_hal *, GAIN_VALUES *);
+static HAL_BOOL ar5212IsGainAdjustNeeded(struct ath_hal *, const GAIN_VALUES *);
+static int32_t ar5212AdjustGain(struct ath_hal *, GAIN_VALUES *);
+void ar5212SetRateDurationTable(struct ath_hal *, HAL_CHANNEL *);
+static uint32_t ar5212GetRfField(uint32_t *rfBuf, uint32_t numBits,
+ uint32_t firstBit, uint32_t column);
+static void ar5212GetGainFCorrection(struct ath_hal *ah);
+HAL_BOOL ar5212SetXrMode(struct ath_hal *ah, HAL_OPMODE opmode,HAL_CHANNEL *chan);
+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_5112(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)) {
+ 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_5112(ah) || IS_2413(ah) || IS_2425(ah) || IS_2417(ah)) {
+ rfMode = AR_PHY_MODE_AR5112;
+ if (IS_CHAN_CCK(chan) || IS_CHAN_G(chan)) {
+ phyPLL = AR_PHY_PLL_CTL_44_5112;
+ } else {
+ if (IS_CHAN_HALF_RATE(chan)) {
+ phyPLL = AR_PHY_PLL_CTL_40_5112_HALF;
+ } else if (IS_CHAN_QUARTER_RATE(chan)) {
+ phyPLL = AR_PHY_PLL_CTL_40_5112_QUARTER;
+ } else {
+ phyPLL = AR_PHY_PLL_CTL_40_5112;
+ }
+ }
+ } else {
+ rfMode = AR_PHY_MODE_AR5111;
+ if (IS_CHAN_CCK(chan) || IS_CHAN_G(chan)) {
+ phyPLL = AR_PHY_PLL_CTL_44;
+ } else {
+ if (IS_CHAN_HALF_RATE(chan)) {
+ phyPLL = AR_PHY_PLL_CTL_40_HALF;
+ } else if (IS_CHAN_QUARTER_RATE(chan)) {
+ phyPLL = AR_PHY_PLL_CTL_40_QUARTER;
+ } else {
+ phyPLL = AR_PHY_PLL_CTL_40;
+ }
+ }
+ }
+ 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
+ar5212PerCalibration(struct ath_hal *ah, HAL_CHANNEL *chan, HAL_BOOL *isIQdone)
+{
+#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);
+ *isIQdone = 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);
+
+ /* XXX EAR */
+ if ((ahp->ah_bIQCalibration == IQ_CAL_DONE) ||
+ (ahp->ah_bIQCalibration == IQ_CAL_INACTIVE))
+ *isIQdone = 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;
+ *isIQdone = 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 */
+
+ /* Check noise floor results */
+ ar5212GetNf(ah, ichan);
+ if ((ichan->channelFlags & CHANNEL_CW_INT) == 0) {
+ /* Perform calibration for 5Ghz channels and any OFDM on 5112 */
+ if ((IS_CHAN_5GHZ(chan) ||
+ (IS_5112(ah) && IS_CHAN_OFDM(chan))) &&
+ !(IS_2413(ah) || IS_5413(ah) || IS_2417(ah)))
+ ar5212RequestRfgain(ah);
+
+ /* XXX EAR */
+ } 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
+}
+
+/*
+ * 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);
+ }
+ 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]);
+ }
+}
+
+#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;
+}
+
+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);
+
+ 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);
+ } 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_diversityControl = 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_2413(ah) || IS_5112(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_5112(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_diversityControl, 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; i<nchans; i++) {
+ chan = &chans[i];
+ if (!ar5212SetRateTable(ah, (HAL_CHANNEL *) chan, tpcInDb, powerLimit,
+ AH_FALSE, &minPower, &maxPower)) {
+ HALDEBUG(ah, HAL_DEBUG_ANY,
+ "%s: unable to find max/min power\n",__func__);
+ return AH_FALSE;
+ }
+ if (maxPower < chan->maxTxPower)
+ chan->maxTxPower = maxPower;
+ if (minPower < chan->minTxPower)
+ chan->minTxPower = minPower;
+ }
+#ifdef AH_DEBUG
+ for (i=0; i<nchans; i++) {
+ HALDEBUG(ah, HAL_DEBUG_RESET,
+ "Chan %d: MaxPow = %d MinPow = %d\n",
+ chans[i].channel,chans[i].maxTxPower, chans[i].minTxPower);
+ }
+#endif
+ return AH_TRUE;
+}
+
+/*
+ * Correct for the gain-delta between ofdm and cck mode target
+ * powers. Write the results to the rate table and the power table.
+ *
+ * Conventions :
+ * 1. rpow[ii] is the integer value of 2*(desired power
+ * for the rate ii in dBm) to provide 0.5dB resolution. rate
+ * mapping is as following :
+ * [0..7] --> 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, chi, 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, chi, 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 */
+}
+
+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 */
+ }
+};
+
+const static 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_5112(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;
+ }
+}
+
+static HAL_BOOL
+ar5212InvalidGainReadback(struct ath_hal *ah, GAIN_VALUES *gv)
+{
+ uint32_t gStep, g, mixOvr;
+ uint32_t L1, L2, L3, L4;
+
+ if (IS_5112(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
+ */
+static 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;
+}
+
+/*
+ * 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_5112(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_5112(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;
+}
+
+/*
+ * 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_5112(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;
+ }
+ }
+}
+
+/*
+ * Perform analog "swizzling" of parameters into their location
+ */
+void
+ar5212ModifyRfBuffer(uint32_t *rfBuf, uint32_t reg32, uint32_t numBits,
+ uint32_t firstBit, uint32_t column)
+{
+ 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++;
+ }
+}
+
+/*
+ * 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;
+
+ 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;
+
+ 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);
+ return;
+}
+
+#endif /* AH_SUPPORT_AR5212 */
diff --git a/ar5212/ar5212_xmit.c b/ar5212/ar5212_xmit.c
new file mode 100644
index 0000000..b2afe34
--- /dev/null
+++ b/ar5212/ar5212_xmit.c
@@ -0,0 +1,944 @@
+/*
+ * 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.7 2008/11/10 04:08:03 sam Exp $
+ */
+#include "opt_ah.h"
+
+#ifdef AH_SUPPORT_AR5212
+
+#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;
+ }
+
+#ifndef AH_DISABLE_WME
+ /*
+ * Yes, this is a hack and not the right way to do it, but
+ * it does get the lockout bits and backoff set for the
+ * high-pri WME queues for testing. We need to either extend
+ * the meaning of queueInfo->mode, or create something like
+ * queueInfo->dcumode.
+ */
+ if (qi->tqi_intFlags & HAL_TXQ_USE_LOCKOUT_BKOFF_DIS) {
+ dmisc |= SM(AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL,
+ AR_D_MISC_ARB_LOCKOUT_CNTRL)
+ | AR_D_MISC_POST_FR_BKOFF_DIS;
+ }
+#endif
+ 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 */
+ }
+#ifdef DEBUG
+ if (npend && (AH5212(ah)->ah_txq[q].tqi_type == HAL_TX_QUEUE_CAB)) {
+ if (OS_REG_READ(ah, AR_Q_RDYTIMESHDN) & (1 << q)) {
+ isrPrintf("RTSD on CAB queue\n");
+ /* Clear the ReadyTime shutdown status bits */
+ OS_REG_WRITE(ah, AR_Q_RDYTIMESHDN, 1 << q);
+ }
+ }
+#endif
+ 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<<HAL_PKT_TYPE_NORMAL)|(1<<HAL_PKT_TYPE_ATIM)|\
+ (1<<HAL_PKT_TYPE_PSPOLL)|(1<<HAL_PKT_TYPE_PROBE_RESP)|\
+ (1<<HAL_PKT_TYPE_BEACON))
+#define isValidPktType(_t) ((1<<(_t)) & VALID_PKT_TYPES)
+#define VALID_TX_RATES \
+ ((1<<0x0b)|(1<<0x0f)|(1<<0x0a)|(1<<0x0e)|(1<<0x09)|(1<<0x0d)|\
+ (1<<0x08)|(1<<0x0c)|(1<<0x1b)|(1<<0x1a)|(1<<0x1e)|(1<<0x19)|\
+ (1<<0x1d)|(1<<0x18)|(1<<0x1c))
+#define isValidTxRate(_r) ((1<<(_r)) & VALID_TX_RATES)
+
+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)
+{
+#define RTSCTS (HAL_TXDESC_RTSENA|HAL_TXDESC_CTSENA)
+ struct ar5212_desc *ads = AR5212DESC(ds);
+ struct ath_hal_5212 *ahp = AH5212(ah);
+
+ (void) hdrLen;
+
+ HALASSERT(txTries0 != 0);
+ HALASSERT(isValidPktType(type));
+ HALASSERT(isValidTxRate(txRate0));
+ HALASSERT((flags & RTSCTS) != RTSCTS);
+ /* XXX validate antMode */
+
+ txPower = (txPower + ahp->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);
+}
+#endif /* AH_SUPPORT_AR5212 */
diff --git a/ar5212/ar5212desc.h b/ar5212/ar5212desc.h
new file mode 100644
index 0000000..9885c9f
--- /dev/null
+++ b/ar5212/ar5212desc.h
@@ -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.4 2008/11/10 04:08:03 sam 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_ */
diff --git a/ar5212/ar5212phy.h b/ar5212/ar5212phy.h
new file mode 100644
index 0000000..fd76fd1
--- /dev/null
+++ b/ar5212/ar5212phy.h
@@ -0,0 +1,348 @@
+/*
+ * 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.5 2008/11/04 01:08:40 sam 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_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_40_HALF 0x1aa /* 40 MHz for 11a, turbos (Half)*/
+#define AR_PHY_PLL_CTL_40_QUARTER 0x2aa /* 40 MHz for 11a, turbos (Quarter)*/
+#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_5112_HALF 0x1ea /* 40 MHz for 11a, turbos (Half)*/
+#define AR_PHY_PLL_CTL_40_5112_QUARTER 0x2ea /* 40 MHz for 11a, turbos (Quarter)*/
+#define AR_PHY_PLL_CTL_40_5413 0x04 /* 40 MHz for 11a, turbos with 5413 */
+
+#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_ */
diff --git a/ar5212/ar5212reg.h b/ar5212/ar5212reg.h
new file mode 100644
index 0000000..9d5754c
--- /dev/null
+++ b/ar5212/ar5212reg.h
@@ -0,0 +1,994 @@
+/*
+ * 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.4 2008/10/12 17:07:17 sam 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_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_RAD2112_SREV_MAJOR 0x40 /* 2112 Major Rev */
+#define AR_RAD2413_SREV_MAJOR 0x50 /* 2413 Major Rev */
+#define AR_RAD5413_SREV_MAJOR 0x60 /* 5413 Major Rev */
+#define AR_RAD5424_SREV_MAJOR 0xa0 /* Mostly same as 5413 Major Rev */
+#define AR_RAD2316_SREV_MAJOR 0x70 /* 2316 Major Rev */
+#define AR_RAD2317_SREV_MAJOR 0x80 /* 2317 Major Rev */
+#define AR_RAD5112_SREV_2_0 0x35 /* AR5112 Revision 2.0 */
+#define AR_RAD2112_SREV_2_0 0x45 /* AR2112 Revision 2.0 */
+#define AR_RAD5112_SREV_2_1 0x36 /* AR5112 Revision 2.1 */
+#define AR_RAD2112_SREV_2_1 0x46 /* AR2112 Revision 2.1 */
+
+#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_ */
diff --git a/ar5212/ar5311reg.h b/ar5212/ar5311reg.h
new file mode 100644
index 0000000..ebf9b64
--- /dev/null
+++ b/ar5212/ar5311reg.h
@@ -0,0 +1,49 @@
+/*
+ * 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.3 2008/10/06 18:32:50 sam 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 */
+
+#endif /* _DEV_ATH_AR5311REG_H_ */
diff --git a/ar5212/ar5413.c b/ar5212/ar5413.c
new file mode 100644
index 0000000..ee87659
--- /dev/null
+++ b/ar5212/ar5413.c
@@ -0,0 +1,783 @@
+/*
+ * 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.7 2008/11/10 04:08:03 sam Exp $
+ */
+#include "opt_ah.h"
+
+#ifdef AH_SUPPORT_5413
+
+#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, idxR;
+
+ 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, idxR;
+ 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 i, reg32, regoffset, tpcrg1;
+ int numPdGainsUsed;
+
+ 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);
+
+#if 0
+ OS_REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN,
+ (pRawDataset->pDataPerChannel[0].numPdGains - 1));
+#endif
+ 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);
+
+ /*
+ * 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; (i<numChannels) && (chan->channel > 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
+ */
+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;
+}
+#endif /* AH_SUPPORT_5413 */
diff --git a/ar5312/ar5312.h b/ar5312/ar5312.h
new file mode 100644
index 0000000..08edf2f
--- /dev/null
+++ b/ar5312/ar5312.h
@@ -0,0 +1,80 @@
+/*
+ * 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.4 2008/11/10 04:08:04 sam 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 struct ath_hal * ar5312Attach(uint16_t devid, HAL_SOFTC sc,
+ HAL_BUS_TAG st, HAL_BUS_HANDLE sh, HAL_STATUS *status);
+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);
+
+#endif /* _ATH_AR3212_H_ */
diff --git a/ar5312/ar5312_attach.c b/ar5312/ar5312_attach.c
new file mode 100644
index 0000000..52d2132
--- /dev/null
+++ b/ar5312/ar5312_attach.c
@@ -0,0 +1,363 @@
+/*
+ * 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.6 2008/11/10 04:08:04 sam Exp $
+ */
+#include "opt_ah.h"
+
+#ifdef AH_SUPPORT_AR5312
+
+#if !defined(AH_SUPPORT_5112) && \
+ !defined(AH_SUPPORT_5111) && \
+ !defined(AH_SUPPORT_2316) && \
+ !defined(AH_SUPPORT_2317)
+#error "No 5312 RF support defined"
+#endif
+
+#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"
+
+/*
+ * These are not valid 2.4 channels, either we change these
+ * or we need to change the coding to accept these
+ */
+static const uint16_t channels11b[] = { 2412, 2447, 2484 };
+static const uint16_t channels11g[] = { 2312, 2412, 2484 };
+
+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 AR3212 part.
+ */
+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;
+ uint32_t val;
+ uint16_t eeval;
+ HAL_STATUS ecode;
+ HAL_BOOL rfStatus;
+
+ 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);
+#ifdef AH_DEBUG
+ /* NB: silently accept anything in release code per Atheros */
+ if ((AH_PRIVATE(ah)->ah_analog5GhzRev & 0xF0) !=
+ AR_RAD5111_SREV_MAJOR &&
+ (AH_PRIVATE(ah)->ah_analog5GhzRev & 0xF0) !=
+ AR_RAD5112_SREV_MAJOR &&
+ (AH_PRIVATE(ah)->ah_analog5GhzRev & 0xF0) !=
+ AR_RAD2111_SREV_MAJOR &&
+ (AH_PRIVATE(ah)->ah_analog5GhzRev & 0xF0) !=
+ AR_RAD2112_SREV_MAJOR) {
+ ath_hal_printf(ah, "%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_5112(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;
+ }
+
+ rfStatus = AH_FALSE;
+ if (IS_2317(ah))
+#if defined AH_SUPPORT_2317
+ rfStatus = ar2317RfAttach(ah, &ecode);
+#else
+ ecode = HAL_ENOTSUPP;
+#endif
+ else if (IS_2316(ah))
+#if defined AH_SUPPORT_2316
+ rfStatus = ar2316RfAttach(ah, &ecode);
+#else
+ ecode = HAL_ENOTSUPP;
+#endif
+ else if (IS_5112(ah))
+#ifdef AH_SUPPORT_5112
+ rfStatus = ar5112RfAttach(ah, &ecode);
+#else
+ ecode = HAL_ENOTSUPP;
+#endif
+ else
+#ifdef AH_SUPPORT_5111
+ rfStatus = ar5111RfAttach(ah, &ecode);
+#else
+ ecode = HAL_ENOTSUPP;
+#endif
+ if (!rfStatus) {
+ 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;
+}
+#endif /* AH_SUPPORT_AR5312 */
diff --git a/ar5312/ar5312_eeprom.c b/ar5312/ar5312_eeprom.c
new file mode 100644
index 0000000..c14b8b2
--- /dev/null
+++ b/ar5312/ar5312_eeprom.c
@@ -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.4 2008/11/10 04:08:04 sam 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 */
diff --git a/ar5312/ar5312_gpio.c b/ar5312/ar5312_gpio.c
new file mode 100644
index 0000000..02ed565
--- /dev/null
+++ b/ar5312/ar5312_gpio.c
@@ -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.3 2008/11/10 04:08:04 sam 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 */
diff --git a/ar5312/ar5312_interrupts.c b/ar5312/ar5312_interrupts.c
new file mode 100644
index 0000000..c40191e
--- /dev/null
+++ b/ar5312/ar5312_interrupts.c
@@ -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.2 2008/11/10 01:19:39 sam 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 */
diff --git a/ar5312/ar5312_misc.c b/ar5312/ar5312_misc.c
new file mode 100644
index 0000000..12e173b
--- /dev/null
+++ b/ar5312/ar5312_misc.c
@@ -0,0 +1,165 @@
+/*
+ * 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.3 2008/11/10 04:08:04 sam 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_5112(ah) || IS_2413(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_5112(ah) || IS_2413(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_5112(ah) || IS_2413(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_5112(ah) || IS_2413(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_5112(ah) || IS_2413(ah)) ? 0x14 : 0x18);
+ }
+ }
+}
+
+#endif /* AH_SUPPORT_AR5312 */
diff --git a/ar5312/ar5312_power.c b/ar5312/ar5312_power.c
new file mode 100644
index 0000000..1cc4ed6
--- /dev/null
+++ b/ar5312/ar5312_power.c
@@ -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.4 2008/11/10 04:08:04 sam 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 */
diff --git a/ar5312/ar5312_reset.c b/ar5312/ar5312_reset.c
new file mode 100644
index 0000000..8490431
--- /dev/null
+++ b/ar5312/ar5312_reset.c
@@ -0,0 +1,924 @@
+/*
+ * 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.9 2008/11/10 04:08:04 sam 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
+ */
+ 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_5112(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_5112(ah) || IS_2413(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 {
+ if (IS_CHAN_HALF_RATE(chan)) {
+ phyPLL = AR_PHY_PLL_CTL_40_5112_HALF;
+ } else if (IS_CHAN_QUARTER_RATE(chan)) {
+ phyPLL = AR_PHY_PLL_CTL_40_5112_QUARTER;
+ } else {
+ phyPLL = AR_PHY_PLL_CTL_40_5112;
+ }
+ }
+ }
+ } else {
+ rfMode = AR_PHY_MODE_AR5111;
+ if (IS_CHAN_CCK(chan) || IS_CHAN_G(chan)) {
+ phyPLL = AR_PHY_PLL_CTL_44;
+ } else {
+ if (IS_CHAN_HALF_RATE(chan)) {
+ phyPLL = AR_PHY_PLL_CTL_40_HALF;
+ } else if (IS_CHAN_QUARTER_RATE(chan)) {
+ phyPLL = AR_PHY_PLL_CTL_40_QUARTER;
+ } else {
+ phyPLL = AR_PHY_PLL_CTL_40;
+ }
+ }
+ }
+ 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 */
diff --git a/ar5312/ar5312phy.h b/ar5312/ar5312phy.h
new file mode 100644
index 0000000..9f867c7
--- /dev/null
+++ b/ar5312/ar5312phy.h
@@ -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.3 2008/10/06 18:32:50 sam 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_ */
diff --git a/ar5312/ar5312reg.h b/ar5312/ar5312reg.h
new file mode 100644
index 0000000..ff79cd3
--- /dev/null
+++ b/ar5312/ar5312reg.h
@@ -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.4 2008/11/10 04:08:04 sam 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_ */
diff --git a/ar5312/ar5315_gpio.c b/ar5312/ar5315_gpio.c
new file mode 100644
index 0000000..2aca97a
--- /dev/null
+++ b/ar5312/ar5315_gpio.c
@@ -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.3 2008/11/10 04:08:04 sam 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 */
diff --git a/ar5416/ar2133.c b/ar5416/ar2133.c
new file mode 100644
index 0000000..9fb95df
--- /dev/null
+++ b/ar5416/ar2133.c
@@ -0,0 +1,410 @@
+/*
+ * 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.10 2008/11/10 04:08:04 sam Exp $
+ */
+#include "opt_ah.h"
+
+#ifdef AH_SUPPORT_2133
+
+#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, &centers);
+ 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; i<NUM_XPD_PER_CHANNEL; i++) {
+ if (data->pDataPerXPD[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; i<NUM_POINTS_XPD0; i++) {
+ if (data->pDataPerXPD[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;
+ (i<numChannels) && (chan->channel > 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
+}
+
+/*
+ * 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;
+
+ return AH_TRUE;
+}
+#endif /* AH_SUPPORT_2133 */
diff --git a/ar5416/ar5416.h b/ar5416/ar5416.h
new file mode 100644
index 0000000..db7a821
--- /dev/null
+++ b/ar5416/ar5416.h
@@ -0,0 +1,288 @@
+/*
+ * 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.16 2008/11/10 04:08:04 sam Exp $
+ */
+#ifndef _ATH_AR5416_H_
+#define _ATH_AR5416_H_
+
+#include "ar5212/ar5212.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_NUM_NF_READINGS 6 /* (3 chains * (ctl + ext) */
+#define AR5416_CCA_MAX_GOOD_VALUE -85
+#define AR5416_CCA_MAX_HIGH_VALUE -62
+#define AR5416_CCA_MIN_BAD_VALUE -140
+
+#define INIT_CAL(_perCal) do { \
+ (_perCal)->calState = CAL_WAITING; \
+ (_perCal)->calNext = AH_NULL; \
+} while (0)
+
+#define INSERT_CAL(_ahp, _perCal) do { \
+ if ((_ahp)->ah_cal_last == AH_NULL) { \
+ (_ahp)->ah_cal_list = (_ahp)->ah_cal_last = (_perCal); \
+ ((_ahp)->ah_cal_last)->calNext = (_perCal); \
+ } else { \
+ ((_ahp)->ah_cal_last)->calNext = (_perCal); \
+ (_ahp)->ah_cal_last = (_perCal); \
+ (_perCal)->calNext = (_ahp)->ah_cal_list; \
+ } \
+} while (0)
+
+typedef enum cal_types {
+ 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_state {
+ 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 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_clksel;
+ 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;
+ /*
+ * Periodic calibration state.
+ */
+ HAL_CAL_TYPE ah_suppCals;
+ HAL_CAL_LIST ah_iqCalData;
+ HAL_CAL_LIST ah_adcGainCalData;
+ HAL_CAL_LIST ah_adcDcCalInitData;
+ HAL_CAL_LIST ah_adcDcCalData;
+ HAL_CAL_LIST *ah_cal_list;
+ HAL_CAL_LIST *ah_cal_last;
+ HAL_CAL_LIST *ah_cal_curr;
+#define AR5416_MAX_CHAINS 3 /* XXX dup's eeprom def */
+ HAL_CAL_SAMPLE ah_caldata[4][AR5416_MAX_CHAINS];
+ int ah_calSamples;
+ /*
+ * Noise floor cal histogram support.
+ * XXX be nice to re-use space in ar5212
+ */
+ struct ar5212NfCalHist ah_nfCalHist[AR5416_NUM_NF_READINGS];
+};
+#define AH5416(_ah) ((struct ath_hal_5416 *)(_ah))
+
+/* IQ Cal aliases */
+#define ah_totalPowerMeasI(i) ah_caldata[0][i].u
+#define ah_totalPowerMeasQ(i) ah_caldata[1][i].u
+#define ah_totalIqCorrMeas(i) ah_caldata[2][i].s
+/* Adc Gain Cal aliases */
+#define ah_totalAdcIOddPhase(i) ah_caldata[0][i].u
+#define ah_totalAdcIEvenPhase(i) ah_caldata[1][i].u
+#define ah_totalAdcQOddPhase(i) ah_caldata[2][i].u
+#define ah_totalAdcQEvenPhase(i) ah_caldata[3][i].u
+/* Adc DC Offset Cal aliases */
+#define ah_totalAdcDcOffsetIOddPhase(i) ah_caldata[0][i].s
+#define ah_totalAdcDcOffsetIEvenPhase(i) ah_caldata[1][i].s
+#define ah_totalAdcDcOffsetQOddPhase(i) ah_caldata[2][i].s
+#define ah_totalAdcDcOffsetQEvenPhase(i) ah_caldata[3][i].s
+
+#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 HAL_BOOL ar5416AniAttach(struct ath_hal *ah);
+extern void ar5416AniDetach(struct ath_hal *ah);
+
+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 ar5416PerCalibration(struct ath_hal *, HAL_CHANNEL *,
+ HAL_BOOL *isIQdone);
+extern void ar5416ResetCalValid(struct ath_hal *ah, HAL_CHANNEL *chan,
+ HAL_BOOL *isIQdone);
+extern void ar5416IQCalCollect(struct ath_hal *ah);
+extern void ar5416IQCalibration(struct ath_hal *ah, uint8_t numChains);
+extern void ar5416AdcGainCalCollect(struct ath_hal *ah);
+extern void ar5416AdcGainCalibration(struct ath_hal *ah, uint8_t numChains);
+extern void ar5416AdcDcCalCollect(struct ath_hal *ah);
+extern void ar5416AdcDcCalibration(struct ath_hal *ah, uint8_t numChains);
+extern void ar5416InitNfHistBuff(struct ar5212NfCalHist *h);
+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_ */
diff --git a/ar5416/ar5416.ini b/ar5416/ar5416.ini
new file mode 100644
index 0000000..6e96f68
--- /dev/null
+++ b/ar5416/ar5416.ini
@@ -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.3 2008/11/10 04:08:04 sam 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 },
+};
diff --git a/ar5416/ar5416_attach.c b/ar5416/ar5416_attach.c
new file mode 100644
index 0000000..6d489ff
--- /dev/null
+++ b/ar5416/ar5416_attach.c
@@ -0,0 +1,494 @@
+/*
+ * 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.19 2008/11/10 04:08:04 sam Exp $
+ */
+#include "opt_ah.h"
+
+#ifdef AH_SUPPORT_AR5416
+
+#if !defined(AH_SUPPORT_2133)
+#error "No 5416 RF support defined"
+#endif
+
+#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_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;
+
+ /* 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;
+
+ /*
+ * XXX - Do we need a board specific chain mask?
+ * Start by setting all Owl devices to 2x2
+ */
+ AH5416(ah)->ah_rx_chainmask = AR5416_DEFAULT_RXCHAINMASK;
+ AH5416(ah)->ah_tx_chainmask = AR5416_DEFAULT_TXCHAINMASK;
+ AH5416(ah)->ah_clksel = 0; /* XXX */
+ /* NB: ah_keytype is initialized to zero which is ok */
+#if 0
+ ah->ah_descinfo.rxctl_numwords = RXCTL_NUMWORDS(ah);
+ ah->ah_descinfo.rxctl_offset = RXCTL_OFFSET(ah);
+ ah->ah_descinfo.rxstatus_numwords = RXSTATUS_NUMWORDS(ah);
+ ah->ah_descinfo.rxstatus_offset = RXSTATUS_OFFSET(ah);
+
+ ah->ah_descinfo.txctl_numwords = TXCTL_NUMWORDS(ah);
+ ah->ah_descinfo.txctl_offset = TXCTL_OFFSET(ah);
+ ah->ah_descinfo.txstatus_numwords = TXSTATUS_NUMWORDS(ah);
+ ah->ah_descinfo.txstatus_offset = TXSTATUS_OFFSET(ah);
+#endif
+}
+
+/*
+ * 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;
+ }
+
+ ar5212InitializeGainValues(ah); /* gain ladder */
+ ar5416AniSetup(ah); /* Anti Noise Immunity */
+ ar5416InitNfHistBuff(AH5416(ah)->ah_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);
+
+ ar5212AniDetach(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;
+}
+#endif /* AH_SUPPORT_AR5416 */
diff --git a/ar5416/ar5416_beacon.c b/ar5416/ar5416_beacon.c
new file mode 100644
index 0000000..43d0317
--- /dev/null
+++ b/ar5416/ar5416_beacon.c
@@ -0,0 +1,249 @@
+/*
+ * 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.7 2008/11/10 04:08:04 sam Exp $
+ */
+#include "opt_ah.h"
+
+#ifdef AH_SUPPORT_AR5416
+
+#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 ar5212SetStaBeaconTimers 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
+}
+#endif /* AH_SUPPORT_AR5416 */
diff --git a/ar5416/ar5416_eeprom.c b/ar5416/ar5416_eeprom.c
new file mode 100644
index 0000000..5c84e85
--- /dev/null
+++ b/ar5416/ar5416_eeprom.c
@@ -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: ar5416_eeprom.c,v 1.6 2008/11/10 04:08:04 sam Exp $
+ */
+#include "opt_ah.h"
+
+#ifdef AH_SUPPORT_AR5416
+
+#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;
+}
+#endif /* AH_SUPPORT_AR5416 */
diff --git a/ar5416/ar5416_gpio.c b/ar5416/ar5416_gpio.c
new file mode 100644
index 0000000..e47b48b
--- /dev/null
+++ b/ar5416/ar5416_gpio.c
@@ -0,0 +1,115 @@
+/*
+ * 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.3 2008/11/10 04:08:04 sam Exp $
+ */
+#include "opt_ah.h"
+
+#ifdef AH_SUPPORT_AR5416
+
+#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);
+}
+#endif /* AH_SUPPORT_AR5416 */
diff --git a/ar5416/ar5416_interrupts.c b/ar5416/ar5416_interrupts.c
new file mode 100644
index 0000000..406dc07
--- /dev/null
+++ b/ar5416/ar5416_interrupts.c
@@ -0,0 +1,262 @@
+/*
+ * 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.6 2008/11/10 04:08:04 sam Exp $
+ */
+#include "opt_ah.h"
+
+#ifdef AH_SUPPORT_AR5416
+
+#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;
+}
+#endif /* AH_SUPPORT_AR5416 */
diff --git a/ar5416/ar5416_keycache.c b/ar5416/ar5416_keycache.c
new file mode 100644
index 0000000..7fdb9cd
--- /dev/null
+++ b/ar5416/ar5416_keycache.c
@@ -0,0 +1,69 @@
+/*
+ * 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.3 2008/11/10 04:08:04 sam Exp $
+ */
+#include "opt_ah.h"
+
+#ifdef AH_SUPPORT_AR5416
+
+#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;
+}
+#endif /* AH_SUPPORT_AR5416 */
diff --git a/ar5416/ar5416_misc.c b/ar5416/ar5416_misc.c
new file mode 100644
index 0000000..b04d931
--- /dev/null
+++ b/ar5416/ar5416_misc.c
@@ -0,0 +1,500 @@
+/*
+ * 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.9 2008/11/10 04:08:04 sam Exp $
+ */
+#include "opt_ah.h"
+
+#ifdef AH_SUPPORT_AR5416
+
+#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);
+ 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
+#endif /* AH_SUPPORT_AR5416 */
diff --git a/ar5416/ar5416_phy.c b/ar5416/ar5416_phy.c
new file mode 100644
index 0000000..ab91e53
--- /dev/null
+++ b/ar5416/ar5416_phy.c
@@ -0,0 +1,129 @@
+/*
+ * 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.3 2008/11/10 01:19:39 sam Exp $
+ */
+#include "opt_ah.h"
+
+#ifdef AH_SUPPORT_AR5416
+
+#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 },
+/* 2 Mb */ { AH_TRUE, CCK, 2000, 0x1a, 0x04, (0x80| 4), 1 },
+/* 5.5 Mb */ { AH_TRUE, CCK, 5500, 0x19, 0x04, (0x80|11), 2 },
+/* 11 Mb */ { AH_TRUE, CCK, 11000, 0x18, 0x04, (0x80|22), 3 },
+/* We remove rates 6, 9 from rate ctrl */
+/* 6 Mb */ { AH_FALSE, OFDM, 6000, 0x0b, 0x00, 12, 4 },
+/* 9 Mb */ { AH_FALSE, OFDM, 9000, 0x0f, 0x00, 18, 4 },
+/* 12 Mb */ { AH_TRUE, OFDM, 12000, 0x0a, 0x00, 24, 6 },
+/* 18 Mb */ { AH_TRUE, OFDM, 18000, 0x0e, 0x00, 36, 6 },
+/* 24 Mb */ { AH_TRUE, OFDM, 24000, 0x09, 0x00, 48, 8 },
+/* 36 Mb */ { AH_TRUE, OFDM, 36000, 0x0d, 0x00, 72, 8 },
+/* 48 Mb */ { AH_TRUE, OFDM, 48000, 0x08, 0x00, 96, 8 },
+/* 54 Mb */ { AH_TRUE, OFDM, 54000, 0x0c, 0x00, 108, 8 },
+/* 6.5 Mb */ { AH_TRUE, HT, 6500, 0x80, 0x00, 0, 8 },
+/* 13 Mb */ { AH_TRUE, HT, 13000, 0x81, 0x00, 1, 8 },
+/*19.5 Mb */ { AH_TRUE, HT, 19500, 0x82, 0x00, 2, 8 },
+/* 26 Mb */ { AH_TRUE, HT, 26000, 0x83, 0x00, 3, 8 },
+/* 39 Mb */ { AH_TRUE, HT, 39000, 0x84, 0x00, 4, 8 },
+/* 52 Mb */ { AH_TRUE, HT, 52000, 0x85, 0x00, 5, 8 },
+/*58.5 Mb */ { AH_TRUE, HT, 58500, 0x86, 0x00, 6, 8 },
+/* 65 Mb */ { AH_TRUE, HT, 65000, 0x87, 0x00, 7, 8 },
+/* 13 Mb */ { AH_TRUE, HT, 13000, 0x88, 0x00, 8, 8 },
+/* 26 Mb */ { AH_TRUE, HT, 26000, 0x89, 0x00, 9, 8 },
+/* 39 Mb */ { AH_TRUE, HT, 39000, 0x8a, 0x00, 10, 8 },
+/* 52 Mb */ { AH_TRUE, HT, 52000, 0x8b, 0x00, 11, 8 },
+/* 78 Mb */ { AH_TRUE, HT, 78000, 0x8c, 0x00, 12, 8 },
+/* 104 Mb */ { AH_TRUE, HT, 104000, 0x8d, 0x00, 13, 8 },
+/* 117 Mb */ { AH_TRUE, HT, 117000, 0x8e, 0x00, 14, 8 },
+/* 130 Mb */ { AH_TRUE, HT, 130000, 0x8f, 0x00, 15, 8 },
+ },
+};
+
+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 },
+/* 9 Mb */ { AH_TRUE, OFDM, 9000, 0x0f, 0x00, 18, 0 },
+/* 12 Mb */ { AH_TRUE, OFDM, 12000, 0x0a, 0x00, (0x80|24), 2 },
+/* 18 Mb */ { AH_TRUE, OFDM, 18000, 0x0e, 0x00, 36, 2 },
+/* 24 Mb */ { AH_TRUE, OFDM, 24000, 0x09, 0x00, (0x80|48), 4 },
+/* 36 Mb */ { AH_TRUE, OFDM, 36000, 0x0d, 0x00, 72, 8 },
+/* 48 Mb */ { AH_TRUE, OFDM, 48000, 0x08, 0x00, 96, 8 },
+/* 54 Mb */ { AH_TRUE, OFDM, 54000, 0x0c, 0x00, 108, 8 },
+/* 6.5 Mb */ { AH_TRUE, HT, 6500, 0x80, 0x00, 0, 8 },
+/* 13 Mb */ { AH_TRUE, HT, 13000, 0x81, 0x00, 1, 8 },
+/*19.5 Mb */ { AH_TRUE, HT, 19500, 0x82, 0x00, 2, 8 },
+/* 26 Mb */ { AH_TRUE, HT, 26000, 0x83, 0x00, 3, 8 },
+/* 39 Mb */ { AH_TRUE, HT, 39000, 0x84, 0x00, 4, 8 },
+/* 52 Mb */ { AH_TRUE, HT, 52000, 0x85, 0x00, 5, 8 },
+/*58.5 Mb */ { AH_TRUE, HT, 58500, 0x86, 0x00, 6, 8 },
+/* 65 Mb */ { AH_TRUE, HT, 65000, 0x87, 0x00, 7, 8 },
+/* 13 Mb */ { AH_TRUE, HT, 13000, 0x88, 0x00, 8, 8 },
+/* 26 Mb */ { AH_TRUE, HT, 26000, 0x89, 0x00, 9, 8 },
+/* 39 Mb */ { AH_TRUE, HT, 39000, 0x8a, 0x00, 10, 8 },
+/* 52 Mb */ { AH_TRUE, HT, 52000, 0x8b, 0x00, 11, 8 },
+/* 78 Mb */ { AH_TRUE, HT, 78000, 0x8c, 0x00, 12, 8 },
+/* 104 Mb */ { AH_TRUE, HT, 104000, 0x8d, 0x00, 13, 8 },
+/* 117 Mb */ { AH_TRUE, HT, 117000, 0x8e, 0x00, 14, 8 },
+/* 130 Mb */ { AH_TRUE, HT, 130000, 0x8f, 0x00, 15, 8 },
+ },
+};
+
+#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;
+}
+#endif /* AH_SUPPORT_AR5416 */
diff --git a/ar5416/ar5416_power.c b/ar5416/ar5416_power.c
new file mode 100644
index 0000000..b27d0ed
--- /dev/null
+++ b/ar5416/ar5416_power.c
@@ -0,0 +1,176 @@
+/*
+ * 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.5 2008/11/10 04:08:04 sam Exp $
+ */
+#include "opt_ah.h"
+
+#ifdef AH_SUPPORT_AR5416
+
+#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;
+ }
+}
+#endif /* AH_SUPPORT_AR5416 */
diff --git a/ar5416/ar5416_recv.c b/ar5416/ar5416_recv.c
new file mode 100644
index 0000000..59f0711
--- /dev/null
+++ b/ar5416/ar5416_recv.c
@@ -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.5 2008/11/10 04:08:04 sam Exp $
+ */
+#include "opt_ah.h"
+
+#ifdef AH_SUPPORT_AR5416
+
+#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);
+
+ OS_REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT);
+
+ HALDEBUG(ah, HAL_DEBUG_RX, "%s: Start PCU Receive \n", __func__);
+ ar5212EnableMibCounters(ah);
+ /* NB: restore current settings */
+ ar5212AniReset(ah, ahp->ah_curchan, ahp->ah_opmode, AH_TRUE);
+}
+
+/*
+ * 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;
+}
+#endif /* AH_SUPPORT_AR5416 */
diff --git a/ar5416/ar5416_reset.c b/ar5416/ar5416_reset.c
new file mode 100644
index 0000000..65cfe58
--- /dev/null
+++ b/ar5416/ar5416_reset.c
@@ -0,0 +1,3867 @@
+/*
+ * 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.20 2008/11/10 04:08:05 sam Exp $
+ */
+#include "opt_ah.h"
+
+#ifdef AH_SUPPORT_AR5416
+
+#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 ar5416InitCal(struct ath_hal *ah, HAL_CHANNEL *chan);
+
+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 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 *);
+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
+
+/* Owl specific stuff */
+#define NUM_NOISEFLOOR_READINGS 6 /* 3 chains * (ctl + ext) */
+
+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);
+
+static void ar5416GetNoiseFloor(struct ath_hal *ah,
+ int16_t nfarray[NUM_NOISEFLOOR_READINGS]);
+
+/*
+ * 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, to avoid this
+ * we add delay an extra BASE_ACTIVATE_DELAY usecs to ensure this
+ * 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;
+}
+
+/*
+ * 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 ath_hal_5416 *ahp = AH5416(ah);
+
+ switch (calType & ahp->ah_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 ath_hal_5416 *ahp = AH5416(ah);
+
+ /* Reset data structures shared between different calibrations */
+ OS_MEMZERO(ahp->ah_caldata, sizeof(ahp->ah_caldata));
+ ahp->ah_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);
+ 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 */
+ ahp->ah_cal_list = ahp->ah_cal_last =
+ ahp->ah_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 */
+ ahp->ah_cal_list = ahp->ah_cal_last =
+ ahp->ah_cal_curr = AH_NULL;
+ return AH_TRUE;
+}
+#endif
+
+/*
+ * Initialize Calibration infrastructure.
+ */
+static HAL_BOOL
+ar5416InitCal(struct ath_hal *ah, HAL_CHANNEL *chan)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ HAL_CHANNEL_INTERNAL *ichan;
+
+ ichan = ath_hal_checkchannel(ah, chan);
+ HALASSERT(ichan != AH_NULL);
+
+ /* 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 */
+ ahp->ah_cal_list = ahp->ah_cal_last =
+ ahp->ah_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(&ahp->ah_adcDcCalInitData);
+ INSERT_CAL(ahp, &ahp->ah_adcDcCalInitData);
+ }
+ /* Initialize current pointer to first element in list */
+ ahp->ah_cal_curr = ahp->ah_cal_list;
+
+ if (ahp->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(&ahp->ah_adcGainCalData);
+ INSERT_CAL(ahp, &ahp->ah_adcGainCalData);
+ HALDEBUG(ah, HAL_DEBUG_PERCAL,
+ "%s: enable ADC Gain Calibration.\n", __func__);
+ }
+ if (ar5416IsCalSupp(ah, chan, ADC_DC_CAL)) {
+ INIT_CAL(&ahp->ah_adcDcCalData);
+ INSERT_CAL(ahp, &ahp->ah_adcDcCalData);
+ HALDEBUG(ah, HAL_DEBUG_PERCAL,
+ "%s: enable ADC DC Calibration.\n", __func__);
+ }
+ if (ar5416IsCalSupp(ah, chan, IQ_MISMATCH_CAL)) {
+ INIT_CAL(&ahp->ah_iqCalData);
+ INSERT_CAL(ahp, &ahp->ah_iqCalData);
+ HALDEBUG(ah, HAL_DEBUG_PERCAL,
+ "%s: enable IQ Calibration.\n", __func__);
+ }
+ /* Initialize current pointer to first element in list */
+ ahp->ah_cal_curr = ahp->ah_cal_list;
+
+ /* Kick off measurements for the first cal */
+ if (ahp->ah_cal_curr != AH_NULL)
+ ar5416ResetMeasurement(ah, ahp->ah_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.
+ */
+void
+ar5416ResetCalValid(struct ath_hal *ah, HAL_CHANNEL *chan, HAL_BOOL *isCalDone)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan);
+ HAL_CAL_LIST *currCal = ahp->ah_cal_curr;
+
+ *isCalDone = AH_TRUE;
+
+ if (!AR_SREV_SOWL_10_OR_LATER(ah))
+ return;
+ if (currCal == AH_NULL)
+ return;
+ if (ichan == AH_NULL) {
+ HALDEBUG(ah, HAL_DEBUG_ANY,
+ "%s: invalid channel %u/0x%x; no mapping\n",
+ __func__, chan->channel, chan->channelFlags);
+ return;
+ }
+ /*
+ * 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;
+ }
+
+ /* Verify Cal is supported on this channel */
+ if (!ar5416IsCalSupp(ah, chan, currCal->calData->calType))
+ return;
+
+ 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;
+
+ /* Indicate to upper layers that we need polling for Howl/Sowl */
+ *isCalDone = AH_FALSE;
+}
+
+/*
+ * 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 ath_hal_5416 *ahp = AH5416(ah);
+
+ /* 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__, ahp->ah_calSamples,
+ currCal->calData->calNumSamples);
+ /*
+ * Collect measurements for active chains.
+ */
+ currCal->calData->calCollect(ah);
+ if (++ahp->ah_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.
+ */
+static HAL_BOOL
+_ar5416PerCalibration(struct ath_hal *ah, HAL_CHANNEL *chan,
+ uint8_t rxchainmask, HAL_BOOL longcal, HAL_BOOL *isCalDone)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ HAL_CAL_LIST *currCal = ahp->ah_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) {
+ ahp->ah_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);
+ HAL_CAL_LIST *curCal = ahp->ah_cal_curr;
+
+ if (curCal != AH_NULL && curCal->calData->calType == IQ_MISMATCH_CAL) {
+ return _ar5416PerCalibration(ah, chan, ahp->ah_rx_chainmask,
+ AH_TRUE, isIQdone);
+ } else {
+ HAL_BOOL isCalDone;
+
+ *isIQdone = AH_FALSE;
+ return _ar5416PerCalibration(ah, chan, ahp->ah_rx_chainmask,
+ AH_TRUE, &isCalDone);
+ }
+}
+
+/*
+ * Collect data from HW to later perform IQ Mismatch Calibration
+ */
+void
+ar5416IQCalCollect(struct ath_hal *ah)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ int i;
+
+ /*
+ * Accumulate IQ cal measures for active chains
+ */
+ for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+ ahp->ah_totalPowerMeasI(i) +=
+ OS_REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
+ ahp->ah_totalPowerMeasQ(i) +=
+ OS_REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
+ ahp->ah_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",
+ ahp->ah_calSamples, i, ahp->ah_totalPowerMeasI(i),
+ ahp->ah_totalPowerMeasQ(i), ahp->ah_totalIqCorrMeas(i));
+ }
+}
+
+/*
+ * Use HW data to do IQ Mismatch Calibration
+ */
+void
+ar5416IQCalibration(struct ath_hal *ah, uint8_t numChains)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ int i;
+
+ for (i = 0; i < numChains; i++) {
+ uint32_t powerMeasI = ahp->ah_totalPowerMeasI(i);
+ uint32_t powerMeasQ = ahp->ah_totalPowerMeasQ(i);
+ uint32_t iqCorrMeas = ahp->ah_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);
+}
+
+/*
+ * Collect data from HW to later perform ADC Gain Calibration
+ */
+void
+ar5416AdcGainCalCollect(struct ath_hal *ah)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ int i;
+
+ /*
+ * Accumulate ADC Gain cal measures for active chains
+ */
+ for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+ ahp->ah_totalAdcIOddPhase(i) +=
+ OS_REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
+ ahp->ah_totalAdcIEvenPhase(i) +=
+ OS_REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
+ ahp->ah_totalAdcQOddPhase(i) +=
+ OS_REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
+ ahp->ah_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",
+ ahp->ah_calSamples, i, ahp->ah_totalAdcIOddPhase(i),
+ ahp->ah_totalAdcIEvenPhase(i), ahp->ah_totalAdcQOddPhase(i),
+ ahp->ah_totalAdcQEvenPhase(i));
+ }
+}
+
+/*
+ * Use HW data to do ADC Gain Calibration
+ */
+void
+ar5416AdcGainCalibration(struct ath_hal *ah, uint8_t numChains)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ uint32_t i;
+
+ for (i = 0; i < numChains; i++) {
+ uint32_t iOddMeasOffset = ahp->ah_totalAdcIOddPhase(i);
+ uint32_t iEvenMeasOffset = ahp->ah_totalAdcIEvenPhase(i);
+ uint32_t qOddMeasOffset = ahp->ah_totalAdcQOddPhase(i);
+ uint32_t qEvenMeasOffset = ahp->ah_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);
+}
+
+void
+ar5416AdcDcCalCollect(struct ath_hal *ah)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ int i;
+
+ for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+ ahp->ah_totalAdcDcOffsetIOddPhase(i) += (int32_t)
+ OS_REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
+ ahp->ah_totalAdcDcOffsetIEvenPhase(i) += (int32_t)
+ OS_REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
+ ahp->ah_totalAdcDcOffsetQOddPhase(i) += (int32_t)
+ OS_REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
+ ahp->ah_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",
+ ahp->ah_calSamples, i,
+ ahp->ah_totalAdcDcOffsetIOddPhase(i),
+ ahp->ah_totalAdcDcOffsetIEvenPhase(i),
+ ahp->ah_totalAdcDcOffsetQOddPhase(i),
+ ahp->ah_totalAdcDcOffsetQEvenPhase(i));
+ }
+}
+
+void
+ar5416AdcDcCalibration(struct ath_hal *ah, uint8_t numChains)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ const HAL_PERCAL_DATA *calData = ahp->ah_cal_curr->calData;
+ uint32_t numSamples;
+ int i;
+
+ numSamples = (1 << (calData->calCountMax + 5)) * calData->calNumSamples;
+ for (i = 0; i < numChains; i++) {
+ uint32_t iOddMeasOffset = ahp->ah_totalAdcDcOffsetIOddPhase(i);
+ uint32_t iEvenMeasOffset = ahp->ah_totalAdcDcOffsetIEvenPhase(i);
+ int32_t qOddMeasOffset = ahp->ah_totalAdcDcOffsetQOddPhase(i);
+ int32_t qEvenMeasOffset = ahp->ah_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);
+}
+
+#ifdef AH_SUPPORT_AR9280
+static void
+ar9280GetNoiseFloor(struct ath_hal *ah, int16_t nfarray[NUM_NOISEFLOOR_READINGS])
+{
+ int16_t nf;
+
+ nf = MS(OS_REG_READ(ah, AR_PHY_CCA), AR9280_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_CH1_CCA), AR9280_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[1] = nf;
+
+ nf = MS(OS_REG_READ(ah, AR_PHY_EXT_CCA), AR9280_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[3] = nf;
+
+ nf = MS(OS_REG_READ(ah, AR_PHY_CH1_EXT_CCA), AR9280_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[4] = nf;
+}
+#endif /* AH_SUPPORT_AR9280 */
+
+static void
+ar5416GetNoiseFloor(struct ath_hal *ah, int16_t nfarray[NUM_NOISEFLOOR_READINGS])
+{
+ 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;
+ }
+}
+
+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, otherwise Vista station
+ * would conduct a bad performance
+ */
+ 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_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 */
+#ifdef AH_SUPPORT_AR9280
+ if (AR_SREV_MERLIN_10_OR_LATER(ah))
+ ar9280GetNoiseFloor(ah, nfarray);
+ else
+#endif
+ ar5416GetNoiseFloor(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_nfCalHist, nfarray);
+ chan->rawNoiseFloor = nf;
+ }
+ return nf;
+}
+
+/*
+ * 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, &centers);
+ 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, &centers);
+ 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
+ */
+ 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; i<nchans; i++) {
+ HALDEBUG(ah, HAL_DEBUG_RESET,
+ "Chan %d: MaxPow = %d MinPow = %d\n",
+ chans[i].channel,chans[i].maxTxPower, chans[i].minTxPower);
+ }
+#endif
+ return AH_TRUE;
+}
+
+/* XXX gag, this is sick */
+typedef enum Ar5416_Rates {
+ rate6mb, rate9mb, rate12mb, rate18mb,
+ rate24mb, rate36mb, rate48mb, rate54mb,
+ rate1l, rate2l, rate2s, rate5_5l,
+ rate5_5s, rate11l, rate11s, rateXr,
+ rateHt20_0, rateHt20_1, rateHt20_2, rateHt20_3,
+ rateHt20_4, rateHt20_5, rateHt20_6, rateHt20_7,
+ rateHt40_0, rateHt40_1, rateHt40_2, rateHt40_3,
+ rateHt40_4, rateHt40_5, rateHt40_6, rateHt40_7,
+ rateDupCck, rateDupOfdm, rateExtCck, rateExtOfdm,
+ Ar5416RateSize
+} AR5416_RATES;
+
+/**************************************************************
+ * ar5416SetTransmitPower
+ *
+ * Set the transmit power in the baseband for the given
+ * operating channel and mode.
+ */
+static HAL_BOOL
+ar5416SetTransmitPower(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan, uint16_t *rfXpdGain)
+{
+#define POW_SM(_r, _s) (((_r) & 0x3f) << (_s))
+#define N(a) (sizeof (a) / sizeof (a[0]))
+
+ MODAL_EEP_HEADER *pModal;
+ struct ath_hal_5212 *ahp = AH5212(ah);
+ int16_t ratesArray[Ar5416RateSize];
+ int16_t txPowerIndexOffset = 0;
+ uint8_t ht40PowerIncForPdadc = 2;
+ int i;
+
+ uint16_t cfgCtl;
+ uint16_t powerLimit;
+ uint16_t twiceAntennaReduction;
+ uint16_t twiceMaxRegulatoryPower;
+ int16_t maxPower;
+ HAL_EEPROM_v14 *ee = AH_PRIVATE(ah)->ah_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 : 38; /* 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_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.
+ */
+
+ 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, &centers);
+
+ /* 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, &centers);
+ 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, &centers);
+ 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, idxR, 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, &centers);
+
+ /* 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]);
+
+ 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, idxR;
+
+ 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;
+ }
+}
+#endif /* AH_SUPPORT_AR5416 */
diff --git a/ar5416/ar5416_xmit.c b/ar5416/ar5416_xmit.c
new file mode 100644
index 0000000..84be68c
--- /dev/null
+++ b/ar5416/ar5416_xmit.c
@@ -0,0 +1,701 @@
+/*
+ * 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.8 2008/11/10 04:08:05 sam Exp $
+ */
+#include "opt_ah.h"
+
+#ifdef AH_SUPPORT_AR5416
+
+#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<<HAL_PKT_TYPE_NORMAL)|(1<<HAL_PKT_TYPE_ATIM)|\
+ (1<<HAL_PKT_TYPE_PSPOLL)|(1<<HAL_PKT_TYPE_PROBE_RESP)|\
+ (1<<HAL_PKT_TYPE_BEACON)|(1<<HAL_PKT_TYPE_AMPDU))
+#define isValidPktType(_t) ((1<<(_t)) & VALID_PKT_TYPES)
+#define VALID_TX_RATES \
+ ((1<<0x0b)|(1<<0x0f)|(1<<0x0a)|(1<<0x0e)|(1<<0x09)|(1<<0x0d)|\
+ (1<<0x08)|(1<<0x0c)|(1<<0x1b)|(1<<0x1a)|(1<<0x1e)|(1<<0x19)|\
+ (1<<0x1d)|(1<<0x18)|(1<<0x1c))
+#define isValidTxRate(_r) ((1<<(_r)) & VALID_TX_RATES)
+
+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)
+{
+#define RTSCTS (HAL_TXDESC_RTSENA|HAL_TXDESC_CTSENA)
+ struct ar5416_desc *ads = AR5416DESC(ds);
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ (void) hdrLen;
+
+ HALASSERT(txTries0 != 0);
+ HALASSERT(isValidPktType(type));
+ HALASSERT(isValidTxRate(txRate0));
+ HALASSERT((flags & RTSCTS) != RTSCTS);
+ /* XXX validate antMode */
+
+ txPower = (txPower + AH5212(ah)->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
+#endif /* AH_SUPPORT_AR5416 */
diff --git a/ar5416/ar5416desc.h b/ar5416/ar5416desc.h
new file mode 100644
index 0000000..dab2a53
--- /dev/null
+++ b/ar5416/ar5416desc.h
@@ -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.6 2008/11/10 04:08:05 sam 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_ */
diff --git a/ar5416/ar5416phy.h b/ar5416/ar5416phy.h
new file mode 100644
index 0000000..a747b6f
--- /dev/null
+++ b/ar5416/ar5416phy.h
@@ -0,0 +1,240 @@
+/*
+ * 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.8 2008/11/06 22:08:01 sam 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_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
+
+#endif /* _DEV_ATH_AR5416PHY_H_ */
diff --git a/ar5416/ar5416reg.h b/ar5416/ar5416reg.h
new file mode 100644
index 0000000..f7d1254
--- /dev/null
+++ b/ar5416/ar5416reg.h
@@ -0,0 +1,510 @@
+/*
+ * 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.9 2008/11/06 22:07:22 sam 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)
+
+#define AR_SREV_VERSION_HOWL 0x014
+#define AR_SREV_HOWL(_ah) \
+ (AH_PRIVATE((_ah))->ah_macVersion == AR_SREV_VERSION_HOWL)
+
+/* 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 */
diff --git a/ar5416/ar9160.ini b/ar5416/ar9160.ini
new file mode 100755
index 0000000..85f09a3
--- /dev/null
+++ b/ar5416/ar9160.ini
@@ -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.5 2008/11/10 04:08:05 sam 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 },
+};
diff --git a/ar5416/ar9160_attach.c b/ar5416/ar9160_attach.c
new file mode 100644
index 0000000..4cf8992
--- /dev/null
+++ b/ar5416/ar9160_attach.c
@@ -0,0 +1,309 @@
+/*
+ * 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.10 2008/11/10 04:08:05 sam Exp $
+ */
+#include "opt_ah.h"
+
+#ifdef AH_SUPPORT_AR9160
+
+#if !defined(AH_SUPPORT_AR5416)
+#error "No 5416 support defined"
+#endif
+#if !defined(AH_SUPPORT_2133)
+#error "No 2133 RF support defined"
+#endif
+
+#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_iqCalData.calData = &ar9160_iq_cal;
+ AH5416(ah)->ah_adcGainCalData.calData = &ar9160_adc_gain_cal;
+ AH5416(ah)->ah_adcDcCalData.calData = &ar9160_adc_dc_cal;
+ AH5416(ah)->ah_adcDcCalInitData.calData = &ar9160_adc_init_dc_cal;
+ AH5416(ah)->ah_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);
+
+ ar5212InitializeGainValues(ah); /* gain ladder */
+ ar9160AniSetup(ah); /* Anti Noise Immunity */
+ ar5416InitNfHistBuff(AH5416(ah)->ah_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;
+}
+#endif /* AH_SUPPORT_AR9160 */
diff --git a/linux/Makefile b/linux/Makefile
new file mode 100644
index 0000000..b2b4a02
--- /dev/null
+++ b/linux/Makefile
@@ -0,0 +1,373 @@
+#
+# 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: Makefile,v 1.3 2008/11/10 03:37:38 sam Exp $
+#
+DEPTH= ..
+
+#
+# Makefile for building the Atheros/MADWIFI HAL from source code with gmake
+#
+HAL= ${DEPTH}
+PUBLIC= ${HAL}/public
+DEBUG_OPTS=AH_DEBUG=1 AH_ASSERT=1
+
+#
+ifdef TARGET
+ALL= ${TARGET}
+else
+ALL= i386-elf \
+ x86_64-elf \
+ alpha-elf \
+ arm-elf \
+ mipsisa32-be-elf mips3-elf mips2-elf mips1-elf \
+ powerpc-eabi powerpc-elf \
+ sh4-elf sparc-elf soc
+endif
+#
+
+all: ${ALL}
+
+release:
+ for i in ${ALL}; do \
+ ${MAKE} $$i-release; \
+ done
+
+debug:
+ for i in ${ALL}; do \
+ ${MAKE} $$i-debug; \
+ done
+
+clean:
+ for i in ${ALL}; do \
+ ${MAKE} $$i-clean; \
+ done
+
+#
+# XXX someone with some gmake foo should be able to do this right...
+#
+i386-elf: ${PUBLIC}/i386-elf.inc
+ ${MAKE} -f Makefile.inc TARGET=i386-elf
+i386-elf-release:
+ ${MAKE} -f Makefile.inc TARGET=i386-elf release
+i386-elf-debug:
+ ${MAKE} -f Makefile.inc TARGET=i386-elf ${DEBUG_OPTS} debug
+i386-elf-clean:
+ ${MAKE} -f Makefile.inc TARGET=i386-elf clean
+
+x86_64-elf: ${PUBLIC}/x86_64-elf.inc
+ ${MAKE} -f Makefile.inc TARGET=x86_64-elf
+x86_64-elf-release:
+ ${MAKE} -f Makefile.inc TARGET=x86_64-elf release
+x86_64-elf-debug:
+ ${MAKE} -f Makefile.inc TARGET=x86_64-elf ${DEBUG_OPTS} debug
+x86_64-elf-clean:
+ ${MAKE} -f Makefile.inc TARGET=x86_64-elf clean
+
+alpha-elf: ${PUBLIC}/alpha-elf.inc
+ ${MAKE} -f Makefile.inc TARGET=alpha-elf
+alpha-elf-release:
+ ${MAKE} -f Makefile.inc TARGET=alpha-elf release
+alpha-elf-debug:
+ ${MAKE} -f Makefile.inc TARGET=alpha-elf ${DEBUG_OPTS} debug
+alpha-elf-clean:
+ ${MAKE} -f Makefile.inc TARGET=alpha-elf clean
+
+arm-elf: armv4-be-elf armv4-le-elf arm9-le-thumb-elf xscale-elf
+arm-elf-release: armv4-be-elf-release armv4-le-elf-release \
+ arm9-le-thumb-elf-release xscale-elf-release
+arm-elf-debug: armv4-be-elf-debug armv4-le-elf-debug \
+ arm9-le-thumb-elf-debug xscale-elf-debug
+arm-elf-clean: armv4-be-elf-clean armv4-le-elf-clean \
+ arm9-le-thumb-elf-clean xscale-elf-clean
+
+armv4-be-elf: ${PUBLIC}/armv4-be-elf.inc
+ ${MAKE} -f Makefile.inc TARGET=armv4-be-elf
+armv4-be-elf-release:
+ ${MAKE} -f Makefile.inc TARGET=armv4-be-elf release
+armv4-be-elf-debug:
+ ${MAKE} -f Makefile.inc TARGET=armv4-be-elf ${DEBUG_OPTS} debug
+armv4-be-elf-clean:
+ ${MAKE} -f Makefile.inc TARGET=armv4-be-elf clean
+armv4-le-elf: ${PUBLIC}/armv4-le-elf.inc
+ ${MAKE} -f Makefile.inc TARGET=armv4-le-elf
+armv4-le-elf-release:
+ ${MAKE} -f Makefile.inc TARGET=armv4-le-elf release
+armv4-le-elf-debug:
+ ${MAKE} -f Makefile.inc TARGET=armv4-le-elf ${DEBUG_OPTS} debug
+armv4-le-elf-clean:
+ ${MAKE} -f Makefile.inc TARGET=armv4-le-elf clean
+arm9-le-thumb-elf: ${PUBLIC}/arm9-le-thumb-elf.inc
+ ${MAKE} -f Makefile.inc TARGET=arm9-le-thumb-elf
+arm9-le-thumb-elf-release:
+ ${MAKE} -f Makefile.inc TARGET=arm9-le-thumb-elf release
+arm9-le-thumb-elf-debug:
+ ${MAKE} -f Makefile.inc TARGET=arm9-le-thumb-elf ${DEBUG_OPTS} debug
+arm9-le-thumb-elf-clean:
+ ${MAKE} -f Makefile.inc TARGET=arm9-le-thumb-elf clean
+
+xscale-elf: xscale-be-elf xscale-le-elf
+xscale-elf-release: xscale-be-elf-release xscale-le-elf-release
+xscale-elf-debug: xscale-be-elf-debug xscale-le-elf-debug
+xscale-elf-clean: xscale-be-elf-clean xscale-le-elf-clean
+
+xscale-be-elf: ${PUBLIC}/xscale-be-elf.inc
+ ${MAKE} -f Makefile.inc TARGET=xscale-be-elf
+xscale-be-elf-release:
+ ${MAKE} -f Makefile.inc TARGET=xscale-be-elf release
+xscale-be-elf-debug:
+ ${MAKE} -f Makefile.inc TARGET=xscale-be-elf ${DEBUG_OPTS} debug
+xscale-be-elf-clean:
+ ${MAKE} -f Makefile.inc TARGET=xscale-be-elf clean
+xscale-le-elf: ${PUBLIC}/xscale-le-elf.inc
+ ${MAKE} -f Makefile.inc TARGET=xscale-le-elf
+xscale-le-elf-release:
+ ${MAKE} -f Makefile.inc TARGET=xscale-le-elf release
+xscale-le-elf-debug:
+ ${MAKE} -f Makefile.inc TARGET=xscale-le-elf ${DEBUG_OPTS} debug
+xscale-le-elf-clean:
+ ${MAKE} -f Makefile.inc TARGET=xscale-le-elf clean
+
+mipsisa32-be-elf: mips3-be-elf
+mipsisa32-be-elf-release: mips3-be-elf-release
+mipsisa32-be-elf-debug: mips3-be-elf-debug
+mipsisa32-be-elf-clean: mips3-be-elf-clean
+
+mips3-elf: mips3-be-elf mips3-le-elf
+mips3-elf-release: mips3-be-elf-release mips3-le-elf-release
+mips3-elf-debug: mips3-be-elf-debug mips3-le-elf-debug
+mips3-elf-clean: mips3-be-elf-clean mips3-le-elf-clean
+
+# NB: the .inc file naming is historical and needs changing
+mips3-be-elf: ${PUBLIC}/mipsisa32-be-elf.inc
+ ${MAKE} -f Makefile.inc TARGET=mipsisa32-be-elf
+mips3-be-elf-release:
+ ${MAKE} -f Makefile.inc TARGET=mipsisa32-be-elf release
+mips3-be-elf-debug:
+ ${MAKE} -f Makefile.inc TARGET=mipsisa32-be-elf ${DEBUG_OPTS} debug
+mips3-be-elf-clean:
+ ${MAKE} -f Makefile.inc TARGET=mipsisa32-be-elf clean
+
+mips3-le-elf: ${PUBLIC}/mipsisa32-le-elf.inc
+ ${MAKE} -f Makefile.inc TARGET=mipsisa32-le-elf
+mips3-le-elf-release:
+ ${MAKE} -f Makefile.inc TARGET=mipsisa32-le-elf release
+mips3-le-elf-debug:
+ ${MAKE} -f Makefile.inc TARGET=mipsisa32-le-elf ${DEBUG_OPTS} debug
+mips3-le-elf-clean:
+ ${MAKE} -f Makefile.inc TARGET=mipsisa32-le-elf clean
+
+# NB: the .inc file naming is historical and needs changing
+mips2-elf: mips2-be-elf mips2-le-elf
+mips2-elf-release: mips2-be-elf-release mips2-le-elf-release
+mips2-elf-debug: mips2-be-elf-debug mips2-le-elf-debug
+mips2-elf-clean: mips2-be-elf-clean mips2-le-elf-clean
+
+mips2-be-elf: ${PUBLIC}/mips-be-elf.inc
+ ${MAKE} -f Makefile.inc TARGET=mips-be-elf
+mips2-be-elf-release:
+ ${MAKE} -f Makefile.inc TARGET=mips-be-elf release
+mips2-be-elf-debug:
+ ${MAKE} -f Makefile.inc TARGET=mips-be-elf ${DEBUG_OPTS} debug
+mips2-be-elf-clean:
+ ${MAKE} -f Makefile.inc TARGET=mips-be-elf clean
+
+mips2-le-elf: ${PUBLIC}/mips-le-elf.inc
+ ${MAKE} -f Makefile.inc TARGET=mips-le-elf
+mips2-le-elf-release:
+ ${MAKE} -f Makefile.inc TARGET=mips-le-elf release
+mips2-le-elf-debug:
+ ${MAKE} -f Makefile.inc TARGET=mips-le-elf ${DEBUG_OPTS} debug
+mips2-le-elf-clean:
+ ${MAKE} -f Makefile.inc TARGET=mips-le-elf clean
+
+mips1-elf: mips1-be-elf mips1-le-elf
+mips1-elf-release: mips1-be-elf-release mips1-le-elf-release
+mips1-elf-debug: mips1-be-elf-debug mips1-le-elf-debug
+mips1-elf-clean: mips1-be-elf-clean mips1-le-elf-clean
+
+mips1-be-elf: ${PUBLIC}/mips1-be-elf.inc
+ ${MAKE} -f Makefile.inc TARGET=mips1-be-elf
+mips1-be-elf-release:
+ ${MAKE} -f Makefile.inc TARGET=mips1-be-elf release
+mips1-be-elf-debug:
+ ${MAKE} -f Makefile.inc TARGET=mips1-be-elf ${DEBUG_OPTS} debug
+mips1-be-elf-clean:
+ ${MAKE} -f Makefile.inc TARGET=mips1-be-elf clean
+
+mips1-le-elf: ${PUBLIC}/mips1-le-elf.inc
+ ${MAKE} -f Makefile.inc TARGET=mips1-le-elf
+mips1-le-elf-release:
+ ${MAKE} -f Makefile.inc TARGET=mips1-le-elf release
+mips1-le-elf-debug:
+ ${MAKE} -f Makefile.inc TARGET=mips1-le-elf ${DEBUG_OPTS} debug
+mips1-le-elf-clean:
+ ${MAKE} -f Makefile.inc TARGET=mips1-le-elf clean
+
+powerpc-eabi: powerpc-be-eabi powerpc-le-eabi
+powerpc-eabi-release: powerpc-be-eabi-release powerpc-le-eabi-release
+powerpc-eabi-debug: powerpc-be-eabi-debug powerpc-le-eabi-debug
+powerpc-eabi-clean: powerpc-be-eabi-clean powerpc-le-eabi-clean
+
+powerpc-be-eabi: ${PUBLIC}/powerpc-be-eabi.inc
+ ${MAKE} -f Makefile.inc TARGET=powerpc-be-eabi
+powerpc-be-eabi-release:
+ ${MAKE} -f Makefile.inc TARGET=powerpc-be-eabi release
+powerpc-be-eabi-debug:
+ ${MAKE} -f Makefile.inc TARGET=powerpc-be-eabi ${DEBUG_OPTS} debug
+powerpc-be-eabi-clean:
+ ${MAKE} -f Makefile.inc TARGET=powerpc-be-eabi clean
+powerpc-le-eabi: ${PUBLIC}/powerpc-le-eabi.inc
+ ${MAKE} -f Makefile.inc TARGET=powerpc-le-eabi
+powerpc-le-eabi-release:
+ ${MAKE} -f Makefile.inc TARGET=powerpc-le-eabi release
+powerpc-le-eabi-debug:
+ ${MAKE} -f Makefile.inc TARGET=powerpc-le-eabi ${DEBUG_OPTS} debug
+powerpc-le-eabi-clean:
+ ${MAKE} -f Makefile.inc TARGET=powerpc-le-eabi clean
+
+powerpc-elf: powerpc-be-elf
+powerpc-elf-release: powerpc-be-elf-release
+powerpc-elf-debug: powerpc-be-elf-debug
+powerpc-elf-clean: powerpc-be-elf-clean
+
+powerpc-be-elf: ${PUBLIC}/powerpc-be-elf.inc
+ ${MAKE} -f Makefile.inc TARGET=powerpc-be-elf
+powerpc-be-elf-release:
+ ${MAKE} -f Makefile.inc TARGET=powerpc-be-elf release
+powerpc-be-elf-debug:
+ ${MAKE} -f Makefile.inc TARGET=powerpc-be-elf ${DEBUG_OPTS} debug
+powerpc-be-elf-clean:
+ ${MAKE} -f Makefile.inc TARGET=powerpc-be-elf clean
+
+sh4-elf: sh4-le-elf
+sh4-elf-release: sh4-le-elf-release
+sh4-elf-debug: sh4-le-elf-debug
+sh4-elf-clean: sh4-le-elf-clean
+
+sh4-le-elf: ${PUBLIC}/sh4-le-elf.inc
+ ${MAKE} -f Makefile.inc TARGET=sh4-le-elf
+sh4-le-elf-release:
+ ${MAKE} -f Makefile.inc TARGET=sh4-le-elf release
+sh4-le-elf-debug:
+ ${MAKE} -f Makefile.inc TARGET=sh4-le-elf ${DEBUG_OPTS} debug
+sh4-le-elf-clean:
+ ${MAKE} -f Makefile.inc TARGET=sh4-le-elf clean
+
+sparc-elf: sparc64-be-elf sparc-be-elf
+sparc-elf-release: sparc64-be-elf-release sparc-be-elf-release
+sparc-elf-debug: sparc64-be-elf-debug sparc-be-elf-debug
+sparc-elf-clean: sparc64-be-elf-clean sparc-be-elf-clean
+
+sparc64-be-elf: ${PUBLIC}/sparc64-be-elf.inc
+ ${MAKE} -f Makefile.inc TARGET=sparc64-be-elf
+sparc64-be-elf-release:
+ ${MAKE} -f Makefile.inc TARGET=sparc64-be-elf release
+sparc64-be-elf-debug:
+ ${MAKE} -f Makefile.inc TARGET=sparc64-be-elf ${DEBUG_OPTS} debug
+sparc64-be-elf-clean:
+ ${MAKE} -f Makefile.inc TARGET=sparc64-be-elf clean
+
+sparc-be-elf: ${PUBLIC}/sparc-be-elf.inc
+ ${MAKE} -f Makefile.inc TARGET=sparc-be-elf
+sparc-be-elf-release:
+ ${MAKE} -f Makefile.inc TARGET=sparc-be-elf release
+sparc-be-elf-debug:
+ ${MAKE} -f Makefile.inc TARGET=sparc-be-elf ${DEBUG_OPTS} debug
+sparc-be-elf-clean:
+ ${MAKE} -f Makefile.inc TARGET=sparc-be-elf clean
+
+#
+# SoC builds
+#
+# Use the ap43 build for an ap48 board
+#
+soc: ap30 ap43 ap51 ap61 wisoc
+soc-release: ap30-release ap43-release ap51-release ap61-release wisoc-release
+soc-debug: ap30-debug ap43-debug ap51-debug ap61-debug wisoc-debug
+soc-clean: ap30-clean ap43-clean ap51-clean ap61-clean wisoc-clean
+
+ap30: ${PUBLIC}/ap30.inc
+ ${MAKE} -f Makefile.inc TARGET=ap30 \
+ AH_SUPPORT_AR5312=1 AH_NEED_DESC_SWAP=1
+ap30-release: ${PUBLIC}/ap30.inc
+ ${MAKE} -f Makefile.inc TARGET=ap30 \
+ AH_SUPPORT_AR5312=1 AH_NEED_DESC_SWAP=1 release
+ap30-debug: ${PUBLIC}/ap30.inc
+ ${MAKE} -f Makefile.inc TARGET=ap30 \
+ AH_SUPPORT_AR5312=1 AH_NEED_DESC_SWAP=1 ${DEBUG_OPTS} debug
+ap30-clean:
+ ${MAKE} -f Makefile.inc TARGET=ap30 clean
+
+ap43: ${PUBLIC}/ap43.inc
+ ${MAKE} -f Makefile.inc TARGET=ap43 AH_SUPPORT_AR5312=1
+ap43-release: ${PUBLIC}/ap43.inc
+ ${MAKE} -f Makefile.inc TARGET=ap43 AH_SUPPORT_AR5312=1 release
+ap43-debug: ${PUBLIC}/ap43.inc
+ ${MAKE} -f Makefile.inc TARGET=ap43 AH_SUPPORT_AR5312=1 ${DEBUG_OPTS} debug
+ap43-clean:
+ ${MAKE} -f Makefile.inc TARGET=ap43 clean
+
+ap51: ${PUBLIC}/ap51.inc
+ ${MAKE} -f Makefile.inc TARGET=ap51 \
+ AH_SUPPORT_2316=1 AH_SUPPORT_5111=0 AH_SUPPORT_5112=0 \
+ AH_SUPPORT_AR5312=1 AH_NEED_DESC_SWAP=1
+ap51-release: ${PUBLIC}/ap51.inc
+ ${MAKE} -f Makefile.inc TARGET=ap51 \
+ AH_SUPPORT_2316=1 AH_SUPPORT_5111=0 AH_SUPPORT_5112=0 \
+ AH_SUPPORT_AR5312=1 AH_NEED_DESC_SWAP=1 release
+ap51-debug: ${PUBLIC}/ap51.inc
+ ${MAKE} -f Makefile.inc TARGET=ap51 \
+ AH_SUPPORT_2316=1 AH_SUPPORT_5111=0 AH_SUPPORT_5112=0 \
+ AH_SUPPORT_AR5312=1 AH_NEED_DESC_SWAP=1 ${DEBUG_OPTS} debug
+ap51-clean:
+ ${MAKE} -f Makefile.inc TARGET=ap51 clean
+
+ap61: ${PUBLIC}/ap61.inc
+ ${MAKE} -f Makefile.inc TARGET=ap61 \
+ AH_SUPPORT_2317=1 AH_SUPPORT_5111=0 AH_SUPPORT_5112=0 \
+ AH_SUPPORT_AR5312=1
+ap61-release: ${PUBLIC}/ap61.inc
+ ${MAKE} -f Makefile.inc TARGET=ap61 \
+ AH_SUPPORT_2317=1 AH_SUPPORT_5111=0 AH_SUPPORT_5112=0 \
+ AH_SUPPORT_AR5312=1 release
+ap61-debug: ${PUBLIC}/ap61.inc
+ ${MAKE} -f Makefile.inc TARGET=ap61 \
+ AH_SUPPORT_2317=1 AH_SUPPORT_5111=0 AH_SUPPORT_5112=0 \
+ AH_SUPPORT_AR5312=1 ${DEBUG_OPTS} debug
+ap61-clean:
+ ${MAKE} -f Makefile.inc TARGET=ap61 clean
+
+wisoc: ${PUBLIC}/wisoc.inc
+ ${MAKE} -f Makefile.inc TARGET=wisoc \
+ AH_SUPPORT_2316=1 \
+ AH_SUPPORT_2317=1 \
+ AH_NEED_DESC_SWAP=1 \
+ AH_SUPPORT_AR5312=1
+wisoc-release: ${PUBLIC}/wisoc.inc
+ ${MAKE} -f Makefile.inc TARGET=wisoc \
+ AH_SUPPORT_2316=1 \
+ AH_SUPPORT_2317=1 \
+ AH_NEED_DESC_SWAP=1 \
+ AH_SUPPORT_AR5312=1 release
+wisoc-debug: ${PUBLIC}/wisoc.inc
+ ${MAKE} -f Makefile.inc TARGET=wisoc \
+ AH_SUPPORT_2316=1 \
+ AH_SUPPORT_2317=1 \
+ AH_NEED_DESC_SWAP=1 \
+ AH_SUPPORT_AR5312=1 ${DEBUG_OPTS} debug
+wisoc-clean:
+ ${MAKE} -f Makefile.inc TARGET=wisoc clean
diff --git a/linux/Makefile.inc b/linux/Makefile.inc
new file mode 100644
index 0000000..3078959
--- /dev/null
+++ b/linux/Makefile.inc
@@ -0,0 +1,604 @@
+#
+# 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: Makefile.inc,v 1.9 2008/11/10 03:37:38 sam Exp $
+#
+HAL= ..
+PUBLIC= ${HAL}/public
+DEBUG= ${HAL}/debug
+#
+# Makefile for building the Atheros/MADWIFI HAL from source code on Linux.
+#
+# This file is intended to be called by the Makefile in the hal
+# directory with TARGET set to the desired target platform.
+#
+# There is support for multiple "generations" of Atheros hardware devices:
+#
+# AH_SUPPORT_AR5210 802.11a only MAC
+# AH_SUPPORT_AR5211 802.11a+802.11b MAC (also pure g, but not yet supported)
+# AH_SUPPORT_AR5212 802.11a+802.11b+802.11g MAC
+# AH_SUPPORT_AR5312 5212 MAC WiSoC (requires AH_SUPPORT_AR5212)
+# AH_SUPPORT_AR5416 802.11a+802.11g+802.11n MAC (requires AH_SUPPORT_5212)
+# AH_SUPPORT_AR9160 802.11a+802.11g+802.11n MAC (requires AH_SUPPORT_5416)
+#
+# AH_SUPPORT_2133 2133 RF support for 5416
+# AH_SUPPORT_2316 2316 RF (Cobra) support for 5212 et. al.
+# AH_SUPPORT_2317 2317 RF (Spyder) support for 5212 et. al.
+# AH_SUPPORT_2413 2413 RF support for 5212 et. al.
+# AH_SUPPORT_2417 2425 RF (Nala) support for 5212 et. al.
+# AH_SUPPORT_2425 2425 RF (Swan) support for 5212 et. al.
+# AH_SUPPORT_5111 5111 RF support for 5212 et. al.
+# AH_SUPPORT_5112 5112 RF support for 5212 et. al.
+# AH_SUPPORT_5413 5413 RF support for 5212 et. al.
+#
+# and numerous optional debugging facilities (typically named AH_DEBUG_*):
+#
+# AH_DEBUG enables debugging stuff that's controlled by the sysctl:
+# hw.ath.hal.debug
+# AH_ASSERT enables assertions that panic or trap into the debugger.
+# AH_DEBUG_ALQ enables support for tracing register reads+writes
+# via alq
+# AH_DEBUG_COUNTRY accept the CTR_DEBUG country code (for debugging
+# the regulatory domain support)
+# AH_REGOPS_FUNC arrange for OS_REG_READ and OS_REG_WRITE to be function
+# calls and not inline expanded to memory references
+# AH_ENABLE_AP_SUPPORT enables AP-specific support not publicly available
+# (e.g. don't cap turbo power limits)
+# AH_DISABLE_WME disable HAL_TXQ_USE_LOCKOUT_BKOFF_DIS support
+#
+# AH_PRIVATE_DIAG enable private diagnostic support
+# AH_WRITE_EEPROM permit EEPROM writes (use with AH_PRIVATE_DIAG)
+# AH_WRITE_REGDOMAIN permit EEPROM writes of the regulatory domain through
+# ah_setRegulatoryDomain (implies AH_WRITE_EEPROM)
+#
+
+#
+# Default settings...
+#
+AH_SUPPORT_AR5210?=1 # 5210 support
+AH_SUPPORT_AR5211?=1 # 5211 support
+AH_SUPPORT_AR5212?=1 # 5212 support
+AH_SUPPORT_AR5312?=0 # 5312 support
+AH_SUPPORT_AR5416?=1 # 5416 support
+AH_SUPPORT_AR9160?=0 # 9160 support
+AH_SUPPORT_2316?=0 # 2316 RF support
+AH_SUPPORT_2317?=0 # 2317 RF support
+AH_SUPPORT_2133?=0 # 2133 RF support
+AH_SUPPORT_2413?=1 # 2413 RF support
+AH_SUPPORT_2417?=1 # 2417 RF support
+AH_SUPPORT_2425?=1 # 2425 RF support
+AH_SUPPORT_5111?=1 # 5111 RF support
+AH_SUPPORT_5112?=1 # 5112 RF support
+AH_SUPPORT_5413?=1 # 5413 RF support
+
+AH_EEPROM_V3?=0 # v3+ EEPROM support
+AH_EEPROM_V14?=0 # v14+ EEPROM support
+
+AH_DEBUG?=0 # debugging (e.g. hw.ath.hal.debug)
+AH_ASSERT?=0 # assertions (pretty lame)
+AH_DEBUG_ALQ?=0 # ALQ register tracing support
+AH_REGOPS_FUNC?=0 # use inline memory references
+AH_WRITE_REGDOMAIN?=0 # support EEPROM writes of the regulatory domain
+AH_DEBUG_COUNTRY?=0 # accept CTR_DEBUG country code
+AH_DISABLE_WME?=0 # disable HAL_TXQ_USE_LOCKOUT_BKOFF_DIS
+AH_ENABLE_AP_SUPPORT?=0 # enable AP-specific support
+AH_WRITE_EEPROM?=0 # support EEPROM writes
+AH_PRIVATE_DIAG?=0 # non-public diagnostic support
+AH_NEED_DESC_SWAP?=0 # Need to swap TX descriptor
+AH_ENABLE_FORCEBIAS?=0 # 2133 orientation sensitivity
+
+#
+# If 5312 support is enabled it's certain we're not going
+# to use the 5210, 5211, or 5416 support so disable them.
+#
+ifeq ($(strip ${AH_SUPPORT_AR5312}),1)
+AH_SUPPORT_AR5210=0
+AH_SUPPORT_AR5211=0
+AH_SUPPORT_AR5416=0
+AH_SUPPORT_2133=0
+AH_SUPPORT_2413=0
+AH_SUPPORT_2417=0
+AH_SUPPORT_2425=0
+AH_SUPPORT_5413=0
+AH_SUPPORT_AR5212=1 # force 5212 support
+endif
+
+#
+# 5211 and 5212 require v3 EEPROM support; do it here
+# before we enable 5212 to support 5416 (this way we don't
+# pull in v3 support as a side effect).
+#
+ifeq ($(strip ${AH_SUPPORT_AR5212}),1)
+AH_EEPROM_V3=1
+endif
+ifeq ($(strip ${AH_SUPPORT_AR5211}),1)
+AH_EEPROM_V3=1
+endif
+
+#
+# If 9160 support is enabled force 5416 on also.
+#
+ifeq ($(strip ${AH_SUPPORT_AR9160}),1)
+AH_SUPPORT_AR5416=1
+endif
+
+#
+# If 5416 support is enabled force 5212 on also.
+#
+ifeq ($(strip ${AH_SUPPORT_AR5416}),1)
+AH_SUPPORT_AR5212=1
+endif
+
+#
+# 5416 support presently =>'s 2133 and force bias support;
+# do those automatically (but separately from 5212 for now).
+#
+ifeq ($(strip ${AH_SUPPORT_AR5416}),1)
+AH_SUPPORT_2133=1
+AH_ENABLE_FORCEBIAS=1
+AH_EEPROM_V14=1
+endif
+
+#
+# 2417 support presently requires 2425 support
+#
+ifeq ($(strip ${AH_SUPPORT_2417}),1)
+AH_SUPPORT_2425=1
+endif
+
+#
+# Basic build components.
+#
+OBJDIR= obj/${TARGET}
+
+WARNFLAGS=-Wall -Wredundant-decls -Wnested-externs -Wstrict-prototypes \
+ -Wmissing-prototypes -Winline -Wcast-qual -std=c99
+# NB: can't do this until we fix register r/w macros
+WARNFLAGS_NOTYET=-Wpointer-arith
+COPTS= -Werror -g -O ${WARNFLAGS}
+INCS= -I${OBJDIR} -I. -I..
+CLEANFILES= ${OBJDIR}/.depend
+
+include ${PUBLIC}/${TARGET}.inc
+
+CFLAGS= ${INCS} ${COPTS}
+
+HAL_SRCS=${HAL}/ah.c ${HAL}/ah_regdomain.c
+HAL_OBJS=${OBJDIR}/ah.o ${OBJDIR}/ah_regdomain.o
+
+ifeq ($(strip ${AH_EEPROM_V3}),1)
+HAL_SRCS+=${HAL}/ah_eeprom_v3.c
+HAL_OBJS+=${OBJDIR}/ah_eeprom_v3.o
+endif
+
+ifeq ($(strip ${AH_EEPROM_V14}),1)
+HAL_SRCS+=${HAL}/ah_eeprom_v14.c
+HAL_OBJS+=${OBJDIR}/ah_eeprom_v14.o
+endif
+
+ifeq ($(strip ${AH_SUPPORT_AR5210}),1)
+AR5210= ${HAL}/ar5210
+HAL_SRCS+=${AR5210}/ar5210_attach.c ${AR5210}/ar5210_beacon.c \
+ ${AR5210}/ar5210_interrupts.c ${AR5210}/ar5210_keycache.c \
+ ${AR5210}/ar5210_misc.c ${AR5210}/ar5210_power.c \
+ ${AR5210}/ar5210_phy.c ${AR5210}/ar5210_recv.c \
+ ${AR5210}/ar5210_reset.c ${AR5210}/ar5210_xmit.c
+HAL_OBJS+=${OBJDIR}/ar5210_attach.o ${OBJDIR}/ar5210_beacon.o \
+ ${OBJDIR}/ar5210_interrupts.o ${OBJDIR}/ar5210_keycache.o \
+ ${OBJDIR}/ar5210_misc.o ${OBJDIR}/ar5210_power.o \
+ ${OBJDIR}/ar5210_phy.o ${OBJDIR}/ar5210_recv.o \
+ ${OBJDIR}/ar5210_reset.o ${OBJDIR}/ar5210_xmit.o
+endif
+
+ifeq ($(strip ${AH_SUPPORT_AR5211}),1)
+AR5211= ${HAL}/ar5211
+HAL_SRCS+=${AR5211}/ar5211_attach.c ${AR5211}/ar5211_beacon.c \
+ ${AR5211}/ar5211_interrupts.c ${AR5211}/ar5211_keycache.c \
+ ${AR5211}/ar5211_misc.c ${AR5211}/ar5211_power.c \
+ ${AR5211}/ar5211_phy.c ${AR5211}/ar5211_recv.c \
+ ${AR5211}/ar5211_reset.c ${AR5211}/ar5211_xmit.c
+HAL_OBJS+=${OBJDIR}/ar5211_attach.o ${OBJDIR}/ar5211_beacon.o \
+ ${OBJDIR}/ar5211_interrupts.o ${OBJDIR}/ar5211_keycache.o \
+ ${OBJDIR}/ar5211_misc.o ${OBJDIR}/ar5211_power.o \
+ ${OBJDIR}/ar5211_phy.o ${OBJDIR}/ar5211_recv.o \
+ ${OBJDIR}/ar5211_reset.o ${OBJDIR}/ar5211_xmit.o
+endif
+
+ifeq ($(strip ${AH_SUPPORT_AR5212}),1)
+AR5212= ${HAL}/ar5212
+HAL_SRCS+=${AR5212}/ar5212_attach.c ${AR5212}/ar5212_beacon.c \
+ ${AR5212}/ar5212_eeprom.c ${AR5212}/ar5212_gpio.c \
+ ${AR5212}/ar5212_interrupts.c ${AR5212}/ar5212_keycache.c \
+ ${AR5212}/ar5212_misc.c ${AR5212}/ar5212_power.c \
+ ${AR5212}/ar5212_phy.c ${AR5212}/ar5212_recv.c \
+ ${AR5212}/ar5212_reset.c ${AR5212}/ar5212_xmit.c \
+ ${AR5212}/ar5212_ani.c
+HAL_OBJS+=${OBJDIR}/ar5212_attach.o ${OBJDIR}/ar5212_beacon.o \
+ ${OBJDIR}/ar5212_eeprom.o ${OBJDIR}/ar5212_gpio.o \
+ ${OBJDIR}/ar5212_interrupts.o ${OBJDIR}/ar5212_keycache.o \
+ ${OBJDIR}/ar5212_misc.o ${OBJDIR}/ar5212_power.o \
+ ${OBJDIR}/ar5212_phy.o ${OBJDIR}/ar5212_recv.o \
+ ${OBJDIR}/ar5212_reset.o ${OBJDIR}/ar5212_xmit.o \
+ ${OBJDIR}/ar5212_ani.o
+endif
+
+ifeq ($(strip ${AH_SUPPORT_AR5312}),1)
+AR5312= ${HAL}/ar5312
+HAL_SRCS+=${AR5312}/ar5312_attach.c ${AR5312}/ar5312_interrupts.c \
+ ${AR5312}/ar5312_eeprom.c \
+ ${AR5312}/ar5312_gpio.c ${AR5312}/ar5315_gpio.c \
+ ${AR5312}/ar5312_misc.c ${AR5312}/ar5312_power.c \
+ ${AR5312}/ar5312_reset.c
+HAL_OBJS+=${OBJDIR}/ar5312_attach.o ${OBJDIR}/ar5312_interrupts.o \
+ ${OBJDIR}/ar5312_eeprom.o \
+ ${OBJDIR}/ar5312_gpio.o ${OBJDIR}/ar5315_gpio.o \
+ ${OBJDIR}/ar5312_misc.o ${OBJDIR}/ar5312_power.o \
+ ${OBJDIR}/ar5312_reset.o
+endif
+
+ifeq ($(strip ${AH_SUPPORT_AR5416}),1)
+AR5416= ${HAL}/ar5416
+HAL_SRCS+=${AR5416}/ar5416_attach.c ${AR5416}/ar5416_beacon.c \
+ ${AR5416}/ar5416_eeprom.c ${AR5416}/ar5416_gpio.c \
+ ${AR5416}/ar5416_interrupts.c ${AR5416}/ar5416_keycache.c \
+ ${AR5416}/ar5416_misc.c ${AR5416}/ar5416_power.c \
+ ${AR5416}/ar5416_phy.c ${AR5416}/ar5416_recv.c \
+ ${AR5416}/ar5416_reset.c ${AR5416}/ar5416_xmit.c
+HAL_OBJS+=${OBJDIR}/ar5416_attach.o ${OBJDIR}/ar5416_beacon.o \
+ ${OBJDIR}/ar5416_eeprom.o ${OBJDIR}/ar5416_gpio.o \
+ ${OBJDIR}/ar5416_interrupts.o ${OBJDIR}/ar5416_keycache.o \
+ ${OBJDIR}/ar5416_misc.o ${OBJDIR}/ar5416_power.o \
+ ${OBJDIR}/ar5416_phy.o ${OBJDIR}/ar5416_recv.o \
+ ${OBJDIR}/ar5416_reset.o ${OBJDIR}/ar5416_xmit.o
+endif
+
+ifeq ($(strip ${AH_SUPPORT_AR9160}),1)
+HAL_SRCS+=${AR5416}/ar9160_attach.c
+HAL_OBJS+=${OBJDIR}/ar9160_attach.o
+endif
+
+ifeq ($(strip ${AH_SUPPORT_2316}),1)
+HAL_SRCS+=${AR5212}/ar2316.c
+HAL_OBJS+=${OBJDIR}/ar2316.o
+endif
+
+ifeq ($(strip ${AH_SUPPORT_2317}),1)
+HAL_SRCS+=${AR5212}/ar2317.c
+HAL_OBJS+=${OBJDIR}/ar2317.o
+endif
+
+ifeq ($(strip ${AH_SUPPORT_2133}),1)
+HAL_SRCS+=${AR5416}/ar2133.c
+HAL_OBJS+=${OBJDIR}/ar2133.o
+endif
+
+ifeq ($(strip ${AH_SUPPORT_2413}),1)
+HAL_SRCS+=${AR5212}/ar2413.c
+HAL_OBJS+=${OBJDIR}/ar2413.o
+endif
+
+ifeq ($(strip ${AH_SUPPORT_2425}),1)
+HAL_SRCS+=${AR5212}/ar2425.c
+HAL_OBJS+=${OBJDIR}/ar2425.o
+endif
+
+ifeq ($(strip ${AH_SUPPORT_5111}),1)
+HAL_SRCS+=${AR5212}/ar5111.c
+HAL_OBJS+=${OBJDIR}/ar5111.o
+endif
+
+ifeq ($(strip ${AH_SUPPORT_5112}),1)
+HAL_SRCS+=${AR5212}/ar5112.c
+HAL_OBJS+=${OBJDIR}/ar5112.o
+endif
+
+ifeq ($(strip ${AH_SUPPORT_5413}),1)
+HAL_SRCS+=${AR5212}/ar5413.c
+HAL_OBJS+=${OBJDIR}/ar5413.o
+endif
+
+SRCS+= ${HAL_SRCS}
+CLEANFILES+= ${OBJDIR}/opt_ah.h ${HAL_OBJS}
+
+#
+# NB: These are typically overridden in the target-specific specification.
+#
+LD?= ld
+#
+# These are specific to the host doing the build.
+#
+SED?= sed
+UUENCODE?=uuencode
+
+ALL= ${OBJDIR}/hal.o
+
+all: ${ALL}
+
+#
+# ARM binaries need their ELF header patched so they are marked
+# as using "virtual floating point"; otherwise the resulting .o
+# files will generate linker errors because they are marked as
+# using hardware floating point.
+#
+ifneq (,$(findstring arm-elf,${TOOLPREFIX}))
+${OBJDIR}/hal.o: ${HAL_OBJS} Makefile wackelf
+ ${LD} -o $@ -r ${LDOPTS} ${HAL_OBJS}
+ ./wackelf $@
+
+# NB: use host tools; not cross-compilation tools
+wackelf: ${PUBLIC}/wackelf.c
+ cc -o wackelf ${PUBLIC}/wackelf.c
+
+CLEANFILES+= wackelf
+else
+${OBJDIR}/hal.o: ${HAL_OBJS} Makefile
+ ${LD} -o $@ -r ${LDOPTS} ${HAL_OBJS}
+endif
+
+release: ${OBJDIR}/hal.o
+ rm -f ${PUBLIC}/${TARGET}.hal.o.uu
+ (${SED} -e '1,/^$$/d' ${HAL}/COPYRIGHT; \
+ ${SED} -n -e '/ATH_HAL_VERSION/p' ${HAL}/version.h; \
+ ${UUENCODE} ${OBJDIR}/hal.o hal.o) > ${PUBLIC}/${TARGET}.hal.o.uu
+ cmp -s ${OBJDIR}/opt_ah.h ${PUBLIC}/${TARGET}.opt_ah.h || \
+ cp ${OBJDIR}/opt_ah.h ${PUBLIC}/${TARGET}.opt_ah.h
+
+debug: ${OBJDIR}/hal.o
+ rm -f ${DEBUG}/${TARGET}.hal.o.uu
+ (${SED} -e '1,/^$$/d' ${HAL}/COPYRIGHT; \
+ ${SED} -n -e '/ATH_HAL_VERSION/p' ${HAL}/version.h; \
+ ${UUENCODE} ${OBJDIR}/hal.o hal.o) > ${DEBUG}/${TARGET}.hal.o.uu
+ cmp -s ${OBJDIR}/opt_ah.h ${DEBUG}/${TARGET}.opt_ah.h || \
+ cp ${OBJDIR}/opt_ah.h ${DEBUG}/${TARGET}.opt_ah.h
+
+${OBJDIR}/ah.o: ${HAL}/ah.c
+ ${CC} -c -o $@ ${CFLAGS} $<
+${OBJDIR}/ah_eeprom_v3.o: ${HAL}/ah_eeprom_v3.c
+ ${CC} -c -o $@ ${CFLAGS} $<
+${OBJDIR}/ah_eeprom_v14.o: ${HAL}/ah_eeprom_v14.c
+ ${CC} -c -o $@ ${CFLAGS} $<
+${OBJDIR}/ah_regdomain.o: ${HAL}/ah_regdomain.c
+ ${CC} -c -o $@ ${CFLAGS} $<
+
+${OBJDIR}/ar5210_attach.o: ${AR5210}/ar5210_attach.c
+ ${CC} -c -o $@ ${CFLAGS} $<
+${OBJDIR}/ar5210_beacon.o: ${AR5210}/ar5210_beacon.c
+ ${CC} -c -o $@ ${CFLAGS} $<
+${OBJDIR}/ar5210_interrupts.o: ${AR5210}/ar5210_interrupts.c
+ ${CC} -c -o $@ ${CFLAGS} $<
+${OBJDIR}/ar5210_keycache.o: ${AR5210}/ar5210_keycache.c
+ ${CC} -c -o $@ ${CFLAGS} $<
+${OBJDIR}/ar5210_misc.o: ${AR5210}/ar5210_misc.c
+ ${CC} -c -o $@ ${CFLAGS} $<
+${OBJDIR}/ar5210_power.o: ${AR5210}/ar5210_power.c
+ ${CC} -c -o $@ ${CFLAGS} $<
+${OBJDIR}/ar5210_phy.o: ${AR5210}/ar5210_phy.c
+ ${CC} -c -o $@ ${CFLAGS} $<
+${OBJDIR}/ar5210_recv.o: ${AR5210}/ar5210_recv.c
+ ${CC} -c -o $@ ${CFLAGS} $<
+${OBJDIR}/ar5210_reset.o: ${AR5210}/ar5210_reset.c
+ ${CC} -c -o $@ ${CFLAGS} $<
+${OBJDIR}/ar5210_xmit.o: ${AR5210}/ar5210_xmit.c
+ ${CC} -c -o $@ ${CFLAGS} $<
+
+${OBJDIR}/ar5211_attach.o: ${AR5211}/ar5211_attach.c
+ ${CC} -c -o $@ ${CFLAGS} $<
+${OBJDIR}/ar5211_beacon.o: ${AR5211}/ar5211_beacon.c
+ ${CC} -c -o $@ ${CFLAGS} $<
+${OBJDIR}/ar5211_interrupts.o: ${AR5211}/ar5211_interrupts.c
+ ${CC} -c -o $@ ${CFLAGS} $<
+${OBJDIR}/ar5211_keycache.o: ${AR5211}/ar5211_keycache.c
+ ${CC} -c -o $@ ${CFLAGS} $<
+${OBJDIR}/ar5211_misc.o: ${AR5211}/ar5211_misc.c
+ ${CC} -c -o $@ ${CFLAGS} $<
+${OBJDIR}/ar5211_power.o: ${AR5211}/ar5211_power.c
+ ${CC} -c -o $@ ${CFLAGS} $<
+${OBJDIR}/ar5211_phy.o: ${AR5211}/ar5211_phy.c
+ ${CC} -c -o $@ ${CFLAGS} $<
+${OBJDIR}/ar5211_recv.o: ${AR5211}/ar5211_recv.c
+ ${CC} -c -o $@ ${CFLAGS} $<
+${OBJDIR}/ar5211_reset.o: ${AR5211}/ar5211_reset.c
+ ${CC} -c -o $@ ${CFLAGS} $<
+${OBJDIR}/ar5211_xmit.o: ${AR5211}/ar5211_xmit.c
+ ${CC} -c -o $@ ${CFLAGS} $<
+
+${OBJDIR}/ar5212_ani.o: ${AR5212}/ar5212_ani.c
+ ${CC} -c -o $@ ${CFLAGS} $<
+${OBJDIR}/ar5212_attach.o: ${AR5212}/ar5212_attach.c
+ ${CC} -c -o $@ ${CFLAGS} $<
+${OBJDIR}/ar5212_beacon.o: ${AR5212}/ar5212_beacon.c
+ ${CC} -c -o $@ ${CFLAGS} $<
+${OBJDIR}/ar5212_eeprom.o: ${AR5212}/ar5212_eeprom.c
+ ${CC} -c -o $@ ${CFLAGS} $<
+${OBJDIR}/ar5212_gpio.o: ${AR5212}/ar5212_gpio.c
+ ${CC} -c -o $@ ${CFLAGS} $<
+${OBJDIR}/ar5212_interrupts.o: ${AR5212}/ar5212_interrupts.c
+ ${CC} -c -o $@ ${CFLAGS} $<
+${OBJDIR}/ar5212_keycache.o: ${AR5212}/ar5212_keycache.c
+ ${CC} -c -o $@ ${CFLAGS} $<
+${OBJDIR}/ar5212_misc.o: ${AR5212}/ar5212_misc.c
+ ${CC} -c -o $@ ${CFLAGS} $<
+${OBJDIR}/ar5212_power.o: ${AR5212}/ar5212_power.c
+ ${CC} -c -o $@ ${CFLAGS} $<
+${OBJDIR}/ar5212_phy.o: ${AR5212}/ar5212_phy.c
+ ${CC} -c -o $@ ${CFLAGS} $<
+${OBJDIR}/ar5212_recv.o: ${AR5212}/ar5212_recv.c
+ ${CC} -c -o $@ ${CFLAGS} $<
+${OBJDIR}/ar5212_reset.o: ${AR5212}/ar5212_reset.c
+ ${CC} -c -o $@ ${CFLAGS} $<
+${OBJDIR}/ar5212_xmit.o: ${AR5212}/ar5212_xmit.c
+ ${CC} -c -o $@ ${CFLAGS} $<
+
+${OBJDIR}/ar5312_attach.o: ${AR5312}/ar5312_attach.c
+ ${CC} -c -o $@ ${CFLAGS} $<
+${OBJDIR}/ar5312_eeprom.o: ${AR5312}/ar5312_eeprom.c
+ ${CC} -c -o $@ ${CFLAGS} $<
+${OBJDIR}/ar5312_gpio.o: ${AR5312}/ar5312_gpio.c
+ ${CC} -c -o $@ ${CFLAGS} $<
+${OBJDIR}/ar5315_gpio.o: ${AR5312}/ar5315_gpio.c
+ ${CC} -c -o $@ ${CFLAGS} $<
+${OBJDIR}/ar5312_interrupts.o: ${AR5312}/ar5312_interrupts.c
+ ${CC} -c -o $@ ${CFLAGS} $<
+${OBJDIR}/ar5312_misc.o: ${AR5312}/ar5312_misc.c
+ ${CC} -c -o $@ ${CFLAGS} $<
+${OBJDIR}/ar5312_power.o: ${AR5312}/ar5312_power.c
+ ${CC} -c -o $@ ${CFLAGS} $<
+${OBJDIR}/ar5312_reset.o: ${AR5312}/ar5312_reset.c
+ ${CC} -c -o $@ ${CFLAGS} $<
+
+${OBJDIR}/ar2316.o: ${AR5212}/ar2316.c
+ ${CC} -c -o $@ ${CFLAGS} $<
+${OBJDIR}/ar2317.o: ${AR5212}/ar2317.c
+ ${CC} -c -o $@ ${CFLAGS} $<
+${OBJDIR}/ar2413.o: ${AR5212}/ar2413.c
+ ${CC} -c -o $@ ${CFLAGS} $<
+${OBJDIR}/ar2425.o: ${AR5212}/ar2425.c
+ ${CC} -c -o $@ ${CFLAGS} $<
+${OBJDIR}/ar5111.o: ${AR5212}/ar5111.c
+ ${CC} -c -o $@ ${CFLAGS} $<
+${OBJDIR}/ar5112.o: ${AR5212}/ar5112.c
+ ${CC} -c -o $@ ${CFLAGS} $<
+${OBJDIR}/ar5413.o: ${AR5212}/ar5413.c
+ ${CC} -c -o $@ ${CFLAGS} $<
+
+${OBJDIR}/ar5416_attach.o: ${AR5416}/ar5416_attach.c
+ ${CC} -c -o $@ ${CFLAGS} $<
+${OBJDIR}/ar5416_beacon.o: ${AR5416}/ar5416_beacon.c
+ ${CC} -c -o $@ ${CFLAGS} $<
+${OBJDIR}/ar5416_eeprom.o: ${AR5416}/ar5416_eeprom.c
+ ${CC} -c -o $@ ${CFLAGS} $<
+${OBJDIR}/ar5416_gpio.o: ${AR5416}/ar5416_gpio.c
+ ${CC} -c -o $@ ${CFLAGS} $<
+${OBJDIR}/ar5416_interrupts.o: ${AR5416}/ar5416_interrupts.c
+ ${CC} -c -o $@ ${CFLAGS} $<
+${OBJDIR}/ar5416_keycache.o: ${AR5416}/ar5416_keycache.c
+ ${CC} -c -o $@ ${CFLAGS} $<
+${OBJDIR}/ar5416_misc.o: ${AR5416}/ar5416_misc.c
+ ${CC} -c -o $@ ${CFLAGS} $<
+${OBJDIR}/ar5416_power.o: ${AR5416}/ar5416_power.c
+ ${CC} -c -o $@ ${CFLAGS} $<
+${OBJDIR}/ar5416_phy.o: ${AR5416}/ar5416_phy.c
+ ${CC} -c -o $@ ${CFLAGS} $<
+${OBJDIR}/ar5416_recv.o: ${AR5416}/ar5416_recv.c
+ ${CC} -c -o $@ ${CFLAGS} $<
+${OBJDIR}/ar5416_reset.o: ${AR5416}/ar5416_reset.c
+ ${CC} -c -o $@ ${CFLAGS} $<
+${OBJDIR}/ar5416_xmit.o: ${AR5416}/ar5416_xmit.c
+ ${CC} -c -o $@ ${CFLAGS} $<
+
+${OBJDIR}/ar9160_attach.o: ${AR5416}/ar9160_attach.c
+ ${CC} -c -o $@ ${CFLAGS} $<
+
+${OBJDIR}/ar2133.o: ${AR5416}/ar2133.c
+ ${CC} -c -o $@ ${CFLAGS} $<
+
+${OBJDIR}/opt_ah.h:
+ test -d ${OBJDIR} || mkdir -p ${OBJDIR}
+ifeq ($(strip ${AH_SUPPORT_AR5210}),1)
+ echo "#define AH_SUPPORT_AR5210 1" >> ${OBJDIR}/opt_ah.h
+endif
+ifeq ($(strip ${AH_SUPPORT_AR5211}),1)
+ echo "#define AH_SUPPORT_AR5211 1" >> ${OBJDIR}/opt_ah.h
+endif
+ifeq ($(strip ${AH_SUPPORT_AR5212}),1)
+ echo "#define AH_SUPPORT_AR5212 1" >> ${OBJDIR}/opt_ah.h
+endif
+ifeq ($(strip ${AH_SUPPORT_AR5312}),1)
+ echo "#define AH_SUPPORT_AR5312 1" >> ${OBJDIR}/opt_ah.h
+endif
+ifeq ($(strip ${AH_SUPPORT_AR5416}),1)
+ echo "#define AH_SUPPORT_AR5416 1" >> ${OBJDIR}/opt_ah.h
+endif
+ifeq ($(strip ${AH_SUPPORT_AR9160}),1)
+ echo "#define AH_SUPPORT_AR9160 1" >> ${OBJDIR}/opt_ah.h
+endif
+ifeq ($(strip ${AH_SUPPORT_2316}),1)
+ echo "#define AH_SUPPORT_2316 1" >> ${OBJDIR}/opt_ah.h
+endif
+ifeq ($(strip ${AH_SUPPORT_2317}),1)
+ echo "#define AH_SUPPORT_2317 1" >> ${OBJDIR}/opt_ah.h
+endif
+ifeq ($(strip ${AH_SUPPORT_2133}),1)
+ echo "#define AH_SUPPORT_2133 1" >> ${OBJDIR}/opt_ah.h
+endif
+ifeq ($(strip ${AH_SUPPORT_2413}),1)
+ echo "#define AH_SUPPORT_2413 1" >> ${OBJDIR}/opt_ah.h
+endif
+ifeq ($(strip ${AH_SUPPORT_2417}),1)
+ echo "#define AH_SUPPORT_2417 1" >> ${OBJDIR}/opt_ah.h
+endif
+ifeq ($(strip ${AH_SUPPORT_2425}),1)
+ echo "#define AH_SUPPORT_2425 1" >> ${OBJDIR}/opt_ah.h
+endif
+ifeq ($(strip ${AH_SUPPORT_5111}),1)
+ echo "#define AH_SUPPORT_5111 1" >> ${OBJDIR}/opt_ah.h
+endif
+ifeq ($(strip ${AH_SUPPORT_5112}),1)
+ echo "#define AH_SUPPORT_5112 1" >> ${OBJDIR}/opt_ah.h
+endif
+ifeq ($(strip ${AH_SUPPORT_5413}),1)
+ echo "#define AH_SUPPORT_5413 1" >> ${OBJDIR}/opt_ah.h
+endif
+ifeq ($(strip ${AH_ASSERT}),1)
+ echo "#define AH_ASSERT 1" >> ${OBJDIR}/opt_ah.h
+endif
+ifeq ($(strip ${AH_DEBUG_ALQ}),1)
+ echo "#define AH_DEBUG_ALQ 1" >> ${OBJDIR}/opt_ah.h
+endif
+ifeq ($(strip ${AH_DEBUG}),1)
+ echo "#define AH_DEBUG 1" >> ${OBJDIR}/opt_ah.h
+endif
+ifeq ($(strip ${AH_WRITE_REGDOMAIN}),1)
+ echo "#define AH_SUPPORT_WRITE_REGDOMAIN 1" >>${OBJDIR}/opt_ah.h
+ echo "#define AH_SUPPORT_WRITE_EEPROM 1">>${OBJDIR}/opt_ah.h
+else
+ifeq ($(strip ${AH_WRITE_EEPROM}),1)
+ echo "#define AH_SUPPORT_WRITE_EEPROM 1">>${OBJDIR}/opt_ah.h
+endif
+endif
+ifeq ($(strip ${AH_DEBUG_COUNTRY}),1)
+ echo "#define AH_DEBUG_COUNTRY 1" >>${OBJDIR}/opt_ah.h
+endif
+ifeq ($(strip ${AH_REGOPS_FUNC}),1)
+ echo "#define AH_REGOPS_FUNC 1" >>${OBJDIR}/opt_ah.h
+endif
+ifeq ($(strip ${AH_DISABLE_WME}),1)
+ echo "#define AH_DISABLE_WME 1" >>${OBJDIR}/opt_ah.h
+endif
+ifeq ($(strip ${AH_ENABLE_AP_SUPPORT}),1)
+ echo "#define AH_ENABLE_AP_SUPPORT 1" >>${OBJDIR}/opt_ah.h
+endif
+ifeq ($(strip ${AH_PRIVATE_DIAG}),1)
+ echo "#define AH_PRIVATE_DIAG 1" >>${OBJDIR}/opt_ah.h
+endif
+ifeq ($(strip ${AH_NEED_DESC_SWAP}),1)
+ echo "#define AH_NEED_DESC_SWAP 1" >>${OBJDIR}/opt_ah.h
+endif
+ifeq ($(strip ${AH_ENABLE_FORCEBIAS}),1)
+ echo "#define AH_ENABLE_FORCEBIAS 1" >>${OBJDIR}/opt_ah.h
+endif
+
+clean:
+ rm -f ${ALL} ${OBJS} ${CLEANFILES}
+ -rmdir -p ${OBJDIR}
+
+depend: beforedepend .depend afterdepend
+${OBJDIR}/.depend: ${SRCS} ${OBJDIR}/opt_ah.h
+ rm -f ${OBJDIR}/.depend
+ ${CC} -M ${CFLAGS} ${SRCS} | \
+ ${SED} 's,\(.*\)\.o:,${OBJDIR}/\1.o:,g' > ${OBJDIR}/.depend
+afterdepend:
+-include ${OBJDIR}/.depend
diff --git a/linux/ah_osdep.c b/linux/ah_osdep.c
new file mode 100644
index 0000000..121eb8a
--- /dev/null
+++ b/linux/ah_osdep.c
@@ -0,0 +1,566 @@
+/*
+ * 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_osdep.c,v 1.3 2008/11/10 04:08:05 sam Exp $
+ */
+#include "opt_ah.h"
+
+#ifndef EXPORT_SYMTAB
+#define EXPORT_SYMTAB
+#endif
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+
+#include <linux/sysctl.h>
+#include <linux/proc_fs.h>
+
+#include <asm/io.h>
+
+#include "ah.h"
+
+#ifndef __MOD_INC_USE_COUNT
+#define AH_MOD_INC_USE_COUNT(_m) \
+ if (!try_module_get(_m)) { \
+ printk(KERN_WARNING "try_module_get failed\n"); \
+ return NULL; \
+ }
+#define AH_MOD_DEC_USE_COUNT(_m) module_put(_m)
+#else
+#define AH_MOD_INC_USE_COUNT(_m) MOD_INC_USE_COUNT
+#define AH_MOD_DEC_USE_COUNT(_m) MOD_DEC_USE_COUNT
+#endif
+
+#ifdef AH_DEBUG
+static int ath_hal_debug = 0;
+#endif
+
+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 */
+
+struct ath_hal *
+_ath_hal_attach(uint16_t devid, HAL_SOFTC sc,
+ HAL_BUS_TAG t, HAL_BUS_HANDLE h, void* s)
+{
+ HAL_STATUS status;
+ struct ath_hal *ah = ath_hal_attach(devid, sc, t, h, &status);
+
+ *(HAL_STATUS *)s = status;
+ if (ah)
+ AH_MOD_INC_USE_COUNT(THIS_MODULE);
+ return ah;
+}
+
+void
+ath_hal_detach(struct ath_hal *ah)
+{
+ (*ah->ah_detach)(ah);
+ AH_MOD_DEC_USE_COUNT(THIS_MODULE);
+}
+
+/*
+ * Print/log message support.
+ */
+
+void __ahdecl
+ath_hal_vprintf(struct ath_hal *ah, const char* fmt, va_list ap)
+{
+ char buf[1024]; /* XXX */
+ vsnprintf(buf, sizeof(buf), fmt, ap);
+ printk("%s", buf);
+}
+
+void __ahdecl
+ath_hal_printf(struct ath_hal *ah, const char* fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ ath_hal_vprintf(ah, fmt, ap);
+ va_end(ap);
+}
+EXPORT_SYMBOL(ath_hal_printf);
+
+/*
+ * Format an Ethernet MAC for printing.
+ */
+const char* __ahdecl
+ath_hal_ether_sprintf(const uint8_t *mac)
+{
+ static char etherbuf[18];
+ snprintf(etherbuf, sizeof(etherbuf), "%02x:%02x:%02x:%02x:%02x:%02x",
+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+ return etherbuf;
+}
+
+#ifdef AH_ASSERT
+void __ahdecl
+ath_hal_assert_failed(const char* filename, int lineno, const char *msg)
+{
+ printk("Atheros HAL assertion failure: %s: line %u: %s\n",
+ filename, lineno, msg);
+ panic("ath_hal_assert");
+}
+#endif /* AH_ASSERT */
+
+#ifdef AH_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 ardecode 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 "alq/alq.h"
+#include "ah_decode.h"
+
+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 = 8*1024;
+
+static int
+ath_hal_setlogging(int enable)
+{
+ int error;
+
+ if (enable) {
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ error = alq_open(&ath_hal_alq, ath_hal_logfile,
+ sizeof (struct athregrec), ath_hal_alq_qsize);
+ ath_hal_alq_lost = 0;
+ ath_hal_alq_emitdev = 1;
+ printk("ath_hal: logging to %s %s\n", ath_hal_logfile,
+ error == 0 ? "enabled" : "could not be setup");
+ } else {
+ if (ath_hal_alq)
+ alq_close(ath_hal_alq);
+ ath_hal_alq = NULL;
+ printk("ath_hal: logging disabled\n");
+ error = 0;
+ }
+ return error;
+}
+
+/*
+ * Deal with the sysctl handler api changing.
+ */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,8)
+#define AH_SYSCTL_ARGS_DECL \
+ ctl_table *ctl, int write, struct file *filp, void *buffer, \
+ size_t *lenp
+#define AH_SYSCTL_ARGS ctl, write, filp, buffer, lenp
+#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,8) */
+#define AH_SYSCTL_ARGS_DECL \
+ ctl_table *ctl, int write, struct file *filp, void *buffer,\
+ size_t *lenp, loff_t *ppos
+#define AH_SYSCTL_ARGS ctl, write, filp, buffer, lenp, ppos
+#endif
+
+static int
+sysctl_hw_ath_hal_log(AH_SYSCTL_ARGS_DECL)
+{
+ int error, enable;
+
+ ctl->data = &enable;
+ ctl->maxlen = sizeof(enable);
+ enable = (ath_hal_alq != NULL);
+ error = proc_dointvec(AH_SYSCTL_ARGS);
+ if (error || !write)
+ return error;
+ else
+ return ath_hal_setlogging(enable);
+}
+
+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 __ahdecl
+ath_hal_reg_write(struct ath_hal *ah, uint32_t reg, uint32_t val)
+{
+ if (ath_hal_alq) {
+ unsigned long flags;
+ struct ale *ale;
+
+ local_irq_save(flags);
+ 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);
+ }
+ local_irq_restore(flags);
+ }
+ _OS_REG_WRITE(ah, reg, val);
+}
+EXPORT_SYMBOL(ath_hal_reg_write);
+
+uint32_t __ahdecl
+ath_hal_reg_read(struct ath_hal *ah, uint32_t reg)
+{
+ uint32_t val;
+
+ val = _OS_REG_READ(ah, reg);
+ if (ath_hal_alq) {
+ unsigned long flags;
+ struct ale *ale;
+
+ local_irq_save(flags);
+ 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);
+ }
+ local_irq_restore(flags);
+ }
+ return val;
+}
+EXPORT_SYMBOL(ath_hal_reg_read);
+
+void __ahdecl
+OS_MARK(struct ath_hal *ah, u_int id, uint32_t v)
+{
+ if (ath_hal_alq) {
+ unsigned long flags;
+ struct ale *ale;
+
+ local_irq_save(flags);
+ ale = ath_hal_alq_get(ah);
+ 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);
+ }
+ local_irq_restore(flags);
+ }
+}
+EXPORT_SYMBOL(OS_MARK);
+#elif defined(AH_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 __ahdecl
+ath_hal_reg_write(struct ath_hal *ah, u_int reg, uint32_t val)
+{
+#ifdef AH_DEBUG
+ if (ath_hal_debug > 1)
+ ath_hal_printf(ah, "WRITE 0x%x <= 0x%x\n", reg, val);
+#endif
+ _OS_REG_WRITE(ah, reg, val);
+}
+EXPORT_SYMBOL(ath_hal_reg_write);
+
+uint32_t __ahdecl
+ath_hal_reg_read(struct ath_hal *ah, u_int reg)
+{
+ uint32_t val;
+
+ val = _OS_REG_READ(ah, reg);
+#ifdef AH_DEBUG
+ if (ath_hal_debug > 1)
+ ath_hal_printf(ah, "READ 0x%x => 0x%x\n", reg, val);
+#endif
+ return val;
+}
+EXPORT_SYMBOL(ath_hal_reg_read);
+#endif /* AH_DEBUG || AH_REGOPS_FUNC */
+
+#ifdef AH_DEBUG
+void __ahdecl
+HALDEBUG(struct ath_hal *ah, const char* fmt, ...)
+{
+ if (ath_hal_debug) {
+ __va_list ap;
+ va_start(ap, fmt);
+ ath_hal_vprintf(ah, fmt, ap);
+ va_end(ap);
+ }
+}
+
+
+void __ahdecl
+HALDEBUGn(struct ath_hal *ah, u_int level, const char* fmt, ...)
+{
+ if (ath_hal_debug >= level) {
+ __va_list ap;
+ va_start(ap, fmt);
+ ath_hal_vprintf(ah, fmt, ap);
+ va_end(ap);
+ }
+}
+#endif /* AH_DEBUG */
+
+/*
+ * Delay n microseconds.
+ */
+void __ahdecl
+ath_hal_delay(int n)
+{
+ udelay(n);
+}
+
+uint32_t __ahdecl
+ath_hal_getuptime(struct ath_hal *ah)
+{
+ return ((jiffies / HZ) * 1000) + (jiffies % HZ) * (1000 / HZ);
+}
+EXPORT_SYMBOL(ath_hal_getuptime);
+
+/*
+ * Allocate/free memory.
+ */
+
+void * __ahdecl
+ath_hal_malloc(size_t size)
+{
+ void *p;
+ p = kmalloc(size, GFP_KERNEL);
+ if (p)
+ OS_MEMZERO(p, size);
+ return p;
+
+}
+
+void __ahdecl
+ath_hal_free(void* p)
+{
+ kfree(p);
+}
+
+void __ahdecl
+ath_hal_memzero(void *dst, size_t n)
+{
+ memset(dst, 0, n);
+}
+EXPORT_SYMBOL(ath_hal_memzero);
+
+void * __ahdecl
+ath_hal_memcpy(void *dst, const void *src, size_t n)
+{
+ return memcpy(dst, src, n);
+}
+EXPORT_SYMBOL(ath_hal_memcpy);
+
+int __ahdecl
+ath_hal_memcmp(const void *a, const void *b, size_t n)
+{
+ return memcmp(a, b, n);
+}
+EXPORT_SYMBOL(ath_hal_memcmp);
+
+#ifdef CONFIG_SYSCTL
+enum {
+ DEV_ATH = 9, /* XXX must match driver */
+};
+
+#define CTL_AUTO -2 /* cannot be CTL_ANY or CTL_NONE */
+
+static ctl_table ath_hal_sysctls[] = {
+#ifdef AH_DEBUG
+ { .ctl_name = CTL_AUTO,
+ .procname = "debug",
+ .mode = 0644,
+ .data = &ath_hal_debug,
+ .maxlen = sizeof(ath_hal_debug),
+ .proc_handler = proc_dointvec
+ },
+#endif
+ { .ctl_name = CTL_AUTO,
+ .procname = "dma_beacon_response_time",
+ .data = &ath_hal_dma_beacon_response_time,
+ .maxlen = sizeof(ath_hal_dma_beacon_response_time),
+ .mode = 0644,
+ .proc_handler = proc_dointvec
+ },
+ { .ctl_name = CTL_AUTO,
+ .procname = "sw_beacon_response_time",
+ .mode = 0644,
+ .data = &ath_hal_sw_beacon_response_time,
+ .maxlen = sizeof(ath_hal_sw_beacon_response_time),
+ .proc_handler = proc_dointvec
+ },
+ { .ctl_name = CTL_AUTO,
+ .procname = "swba_backoff",
+ .mode = 0644,
+ .data = &ath_hal_additional_swba_backoff,
+ .maxlen = sizeof(ath_hal_additional_swba_backoff),
+ .proc_handler = proc_dointvec
+ },
+#ifdef AH_DEBUG_ALQ
+ { .ctl_name = CTL_AUTO,
+ .procname = "alq",
+ .mode = 0644,
+ .proc_handler = sysctl_hw_ath_hal_log
+ },
+ { .ctl_name = CTL_AUTO,
+ .procname = "alq_size",
+ .mode = 0644,
+ .data = &ath_hal_alq_qsize,
+ .maxlen = sizeof(ath_hal_alq_qsize),
+ .proc_handler = proc_dointvec
+ },
+ { .ctl_name = CTL_AUTO,
+ .procname = "alq_lost",
+ .mode = 0644,
+ .data = &ath_hal_alq_lost,
+ .maxlen = sizeof(ath_hal_alq_lost),
+ .proc_handler = proc_dointvec
+ },
+#endif
+ { 0 }
+};
+static ctl_table ath_hal_table[] = {
+ { .ctl_name = CTL_AUTO,
+ .procname = "hal",
+ .mode = 0555,
+ .child = ath_hal_sysctls
+ }, { 0 }
+};
+static ctl_table ath_ath_table[] = {
+ { .ctl_name = DEV_ATH,
+ .procname = "ath",
+ .mode = 0555,
+ .child = ath_hal_table
+ }, { 0 }
+};
+static ctl_table ath_root_table[] = {
+ { .ctl_name = CTL_DEV,
+ .procname = "dev",
+ .mode = 0555,
+ .child = ath_ath_table
+ }, { 0 }
+};
+static struct ctl_table_header *ath_hal_sysctl_header;
+
+void
+ath_hal_sysctl_register(void)
+{
+ static int initialized = 0;
+
+ if (!initialized) {
+ ath_hal_sysctl_header =
+ register_sysctl_table(ath_root_table, 1);
+ initialized = 1;
+ }
+}
+
+void
+ath_hal_sysctl_unregister(void)
+{
+ if (ath_hal_sysctl_header)
+ unregister_sysctl_table(ath_hal_sysctl_header);
+}
+#endif /* CONFIG_SYSCTL */
+
+/*
+ * Module glue.
+ */
+static char *dev_info = "ath_hal";
+
+MODULE_AUTHOR("Errno Consulting, Sam Leffler");
+MODULE_DESCRIPTION("Atheros Hardware Access Layer (HAL)");
+MODULE_SUPPORTED_DEVICE("Atheros WLAN devices");
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("Proprietary");
+#endif
+
+EXPORT_SYMBOL(ath_hal_probe);
+EXPORT_SYMBOL(_ath_hal_attach);
+EXPORT_SYMBOL(ath_hal_detach);
+EXPORT_SYMBOL(ath_hal_init_channels);
+EXPORT_SYMBOL(ath_hal_getwirelessmodes);
+EXPORT_SYMBOL(ath_hal_computetxtime);
+EXPORT_SYMBOL(ath_hal_mhz2ieee);
+EXPORT_SYMBOL(ath_hal_process_noisefloor);
+
+static int __init
+init_ath_hal(void)
+{
+ const char *sep;
+ int i;
+
+ printk(KERN_INFO "%s: %s (", dev_info, ath_hal_version);
+ sep = "";
+ for (i = 0; ath_hal_buildopts[i] != NULL; i++) {
+ printk("%s%s", sep, ath_hal_buildopts[i]);
+ sep = ", ";
+ }
+ printk(")\n");
+#ifdef CONFIG_SYSCTL
+ ath_hal_sysctl_register();
+#endif
+ return (0);
+}
+module_init(init_ath_hal);
+
+static void __exit
+exit_ath_hal(void)
+{
+#ifdef CONFIG_SYSCTL
+ ath_hal_sysctl_unregister();
+#endif
+ printk(KERN_INFO "%s: driver unloaded\n", dev_info);
+}
+module_exit(exit_ath_hal);
diff --git a/linux/ah_osdep.h b/linux/ah_osdep.h
new file mode 100644
index 0000000..123c230
--- /dev/null
+++ b/linux/ah_osdep.h
@@ -0,0 +1,205 @@
+/*
+ * 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_osdep.h,v 1.3 2008/11/10 04:08:05 sam Exp $
+ */
+#ifndef _ATH_AH_OSDEP_H_
+#define _ATH_AH_OSDEP_H_
+/*
+ * Atheros Hardware Access Layer (HAL) OS Dependent Definitions.
+ */
+
+/*
+ * Starting with 2.6.4 the kernel supports a configuration option
+ * to pass parameters in registers. If this is enabled we must
+ * mark all function interfaces in+out of the HAL to pass parameters
+ * on the stack as this is the convention used internally (for
+ * maximum portability).
+ */
+#ifdef CONFIG_REGPARM
+#define __ahdecl __attribute__((regparm(0)))
+#else
+#define __ahdecl
+#endif
+#ifndef __packed
+#define __packed __attribute__((__packed__))
+#endif
+
+/*
+ * Beware of these being mismatched against the contents of <linux/types.h>
+ */
+#ifndef _LINUX_TYPES_H
+/* NB: arm defaults to unsigned so be explicit */
+typedef signed char int8_t;
+typedef short int16_t;
+typedef int int32_t;
+typedef long long int64_t;
+
+typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned int uint32_t;
+typedef unsigned long long uint64_t;
+
+typedef unsigned int size_t;
+typedef unsigned int u_int;
+typedef void *va_list;
+#endif
+
+/*
+ * Linux/BSD gcc compatibility shims.
+ */
+#define __printflike(_a,_b) \
+ __attribute__ ((__format__ (__printf__, _a, _b)))
+#define __va_list va_list
+#define OS_INLINE __inline
+
+/*
+ * Delay n microseconds.
+ */
+extern void __ahdecl ath_hal_delay(int);
+#define OS_DELAY(_n) ath_hal_delay(_n)
+
+#define OS_MEMZERO(_a, _n) ath_hal_memzero((_a), (_n))
+extern void __ahdecl ath_hal_memzero(void *, size_t);
+#define OS_MEMCPY(_d, _s, _n) ath_hal_memcpy(_d,_s,_n)
+extern void * __ahdecl ath_hal_memcpy(void *, const void *, size_t);
+
+#ifndef abs
+#define abs(_a) __builtin_abs(_a)
+#endif
+
+struct ath_hal;
+extern uint32_t __ahdecl ath_hal_getuptime(struct ath_hal *);
+#define OS_GETUPTIME(_ah) ath_hal_getuptime(_ah)
+
+/*
+ * Byte order/swapping support.
+ */
+#define AH_LITTLE_ENDIAN 1234
+#define AH_BIG_ENDIAN 4321
+
+#ifndef AH_BYTE_ORDER
+/*
+ * When the .inc file is not available (e.g. when building
+ * in a kernel source tree); look for some other way to
+ * setup the host byte order.
+ */
+#ifdef __LITTLE_ENDIAN
+#define AH_BYTE_ORDER AH_LITTLE_ENDIAN
+#endif
+#ifdef __BIG_ENDIAN
+#define AH_BYTE_ORDER AH_BIG_ENDIAN
+#endif
+#ifndef AH_BYTE_ORDER
+#error "Do not know host byte order"
+#endif
+#endif /* AH_BYTE_ORDER */
+
+#if AH_BYTE_ORDER == AH_BIG_ENDIAN
+/*
+ * This could be optimized but since we only use it for
+ * a few registers there's little reason to do so.
+ */
+static __inline__ uint32_t
+__bswap32(uint32_t _x)
+{
+ return ((uint32_t)(
+ (((const uint8_t *)(&_x))[0] ) |
+ (((const uint8_t *)(&_x))[1]<< 8) |
+ (((const uint8_t *)(&_x))[2]<<16) |
+ (((const uint8_t *)(&_x))[3]<<24))
+ );
+}
+#else
+#define __bswap32(_x) (_x)
+#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
+ * (AH_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.
+ *
+ * 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.
+ */
+#if AH_BYTE_ORDER == AH_BIG_ENDIAN
+#define OS_REG_UNSWAPPED(_reg) \
+ (((_reg) >= 0x4000 && (_reg) < 0x5000) || \
+ ((_reg) >= 0x7000 && (_reg) < 0x8000))
+#define _OS_REG_WRITE(_ah, _reg, _val) do { \
+ if (OS_REG_UNSWAPPED(_reg)) \
+ *((volatile uint32_t *)((_ah)->ah_sh + (_reg))) = \
+ __bswap32((_val)); \
+ else \
+ *((volatile uint32_t *)((_ah)->ah_sh + (_reg))) = (_val); \
+} while (0)
+#define _OS_REG_READ(_ah, _reg) \
+ (OS_REG_UNSWAPPED(_reg) ? \
+ __bswap32(*((volatile uint32_t *)((_ah)->ah_sh + (_reg)))) : \
+ *((volatile uint32_t *)((_ah)->ah_sh + (_reg))))
+#else /* AH_LITTLE_ENDIAN */
+#define OS_REG_UNSWAPPED(_reg) (0)
+#define _OS_REG_WRITE(_ah, _reg, _val) do { \
+ *((volatile uint32_t *)((_ah)->ah_sh + (_reg))) = (_val); \
+} while (0)
+#define _OS_REG_READ(_ah, _reg) \
+ *((volatile uint32_t *)((_ah)->ah_sh + (_reg)))
+#endif /* AH_BYTE_ORDER */
+
+#if defined(AH_DEBUG) || defined(AH_REGOPS_FUNC) || defined(AH_DEBUG_ALQ)
+/* use functions to do register operations */
+#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 __ahdecl ath_hal_reg_write(struct ath_hal *ah,
+ u_int reg, uint32_t val);
+extern uint32_t __ahdecl ath_hal_reg_read(struct ath_hal *ah, u_int reg);
+#else
+/* inline register operations */
+#define OS_REG_WRITE(_ah, _reg, _val) _OS_REG_WRITE(_ah, _reg, _val)
+#define OS_REG_READ(_ah, _reg) _OS_REG_READ(_ah, _reg)
+#endif /* AH_DEBUG || AH_REGFUNC || AH_DEBUG_ALQ */
+
+#ifdef AH_DEBUG_ALQ
+extern void __ahdecl OS_MARK(struct ath_hal *, u_int id, uint32_t value);
+#else
+#define OS_MARK(_ah, _id, _v)
+#endif
+
+/*
+ * Linux-specific attach/detach methods needed for module reference counting.
+ *
+ * XXX We can't use HAL_STATUS because the type isn't defined at this
+ * point (circular dependency); we wack the type and patch things
+ * up in the function.
+ *
+ * NB: These are intentionally not marked __ahdecl since they are
+ * compiled with the default calling convetion and are not called
+ * from within the HAL.
+ */
+extern struct ath_hal *_ath_hal_attach(uint16_t devid, HAL_SOFTC,
+ HAL_BUS_TAG, HAL_BUS_HANDLE, void* status);
+extern void ath_hal_detach(struct ath_hal *);
+
+#endif /* _ATH_AH_OSDEP_H_ */
diff --git a/public/alpha-elf.inc b/public/alpha-elf.inc
new file mode 100644
index 0000000..0205f6a
--- /dev/null
+++ b/public/alpha-elf.inc
@@ -0,0 +1,57 @@
+#
+# 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: alpha-elf.inc,v 1.2 2008/11/10 03:43:26 sam Exp $
+#
+
+#
+# Compilation configuration for building big-endian Alpha w/ elf.
+#
+# Built with GNU cross-devel tools:
+#
+# PREFIX=/pub/gnu
+# BINUTILS=binutils-2.14
+# GCC=gcc-3.3.2
+# target=alpha-elf-linux
+#
+# ${BINUTILS}/configure --target=$target --prefix=${PREFIX}
+# ${GCC}/configure --target=$target --prefix=${PREFIX} \
+# --enable-languages=c --with-gnu-as --with-gnu-ld \
+# --with-newlib --with-gxx-include-dir=${PREFIX}/$target/include
+#
+
+#
+ifndef TOOLPREFIX
+TOOLPREFIX= /pub/gnu/bin/alpha-elf-linux-
+endif
+#
+CC= ${TOOLPREFIX}gcc
+LD= ${TOOLPREFIX}ld
+STRIP= ${TOOLPREFIX}strip
+OBJCOPY=${TOOLPREFIX}objcopy
+NM= ${TOOLPREFIX}nm
+
+#
+# Force register read/write operations to go through a function.
+#
+AH_REGOPS_FUNC=1
+
+COPTS+= -DAH_BYTE_ORDER=AH_LITTLE_ENDIAN
+#
+# NB: this should come from inttypes.h but can't until we cleanp
+# the definition of va_list on linux
+#
+COPTS+= -DAH_WORDSIZE=64
diff --git a/public/ap30.inc b/public/ap30.inc
new file mode 100644
index 0000000..96e9653
--- /dev/null
+++ b/public/ap30.inc
@@ -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: ap30.inc,v 1.2 2008/11/10 03:43:27 sam Exp $
+#
+
+#
+# Configuration for building big-endian MIPS2 for the AP30 SoC
+# using the 5.01 linux-mips.org toolchain (manually moved to
+# /pub/gnu from /pub/gnu/local where rpm --prefix=/pub/gnu
+# bogusly installs them).
+#
+
+#
+# http://www.linux-mips.org/toolchain.html
+#
+# /pub/gnu/bin/mips-linux-gcc -v
+# Reading specs from /pub/gnu/bin/../lib/gcc-lib/mips-linux/2.96-mips3264-000710/specs
+# gcc version 2.96-mips3264-000710
+# /pub/gnu/bin/mips-linux-as -v
+# GNU assembler version 2.12.90.0.7 (mips-linux) using BFD version 2.12.90.0.7 20020423
+
+#
+ifndef TOOLPREFIX
+TOOLPREFIX= /pub/gnu/bin/mips-linux-
+endif
+#
+CC= ${TOOLPREFIX}gcc
+LD= ${TOOLPREFIX}ld
+STRIP= ${TOOLPREFIX}strip
+OBJCOPY=${TOOLPREFIX}objcopy
+NM= ${TOOLPREFIX}nm
+
+LDOPTS= -EB
+COPTS+= -DAH_BYTE_ORDER=AH_BIG_ENDIAN
+COPTS+= -G 0 -EB -mno-abicalls -fno-pic -mips32 -Wa,--trap \
+ -fno-strict-aliasing -fno-common -fomit-frame-pointer -mlong-calls
diff --git a/public/ap43.inc b/public/ap43.inc
new file mode 100644
index 0000000..3eb3067
--- /dev/null
+++ b/public/ap43.inc
@@ -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: ap43.inc,v 1.2 2008/11/10 03:43:29 sam Exp $
+#
+
+#
+# Configuration for building big-endian MIPS2 for the AP43/AP48 SoC
+# using the 5.01 linux-mips.org toolchain (manually moved to
+# /pub/gnu from /pub/gnu/local where rpm --prefix=/pub/gnu
+# bogusly installs them).
+#
+
+#
+# http://www.linux-mips.org/toolchain.html
+#
+# /pub/gnu/bin/mips-linux-gcc -v
+# Reading specs from /pub/gnu/bin/../lib/gcc-lib/mips-linux/2.96-mips3264-000710/specs
+# gcc version 2.96-mips3264-000710
+# /pub/gnu/bin/mips-linux-as -v
+# GNU assembler version 2.12.90.0.7 (mips-linux) using BFD version 2.12.90.0.7 20020423
+
+#
+ifndef TOOLPREFIX
+TOOLPREFIX= /pub/gnu/bin/mips-linux-
+endif
+#
+CC= ${TOOLPREFIX}gcc
+LD= ${TOOLPREFIX}ld
+STRIP= ${TOOLPREFIX}strip
+OBJCOPY=${TOOLPREFIX}objcopy
+NM= ${TOOLPREFIX}nm
+
+LDOPTS= -EB
+COPTS+= -DAH_BYTE_ORDER=AH_BIG_ENDIAN
+COPTS+= -G 0 -EB -mno-abicalls -fno-pic -mips32 -Wa,--trap \
+ -fno-strict-aliasing -fno-common -fomit-frame-pointer -mlong-calls
diff --git a/public/ap51.inc b/public/ap51.inc
new file mode 100644
index 0000000..9de6673
--- /dev/null
+++ b/public/ap51.inc
@@ -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: ap51.inc,v 1.2 2008/11/10 03:43:31 sam Exp $
+#
+
+#
+# Configuration for building big-endian MIPS2 for the AP51 SoC
+# using the 5.01 linux-mips.org toolchain (manually moved to
+# /pub/gnu from /pub/gnu/local where rpm --prefix=/pub/gnu
+# bogusly installs them).
+#
+
+#
+# http://www.linux-mips.org/toolchain.html
+#
+# /pub/gnu/bin/mips-linux-gcc -v
+# Reading specs from /pub/gnu/bin/../lib/gcc-lib/mips-linux/2.96-mips3264-000710/specs
+# gcc version 2.96-mips3264-000710
+# /pub/gnu/bin/mips-linux-as -v
+# GNU assembler version 2.12.90.0.7 (mips-linux) using BFD version 2.12.90.0.7 20020423
+
+#
+ifndef TOOLPREFIX
+TOOLPREFIX= /pub/gnu/bin/mips-linux-
+endif
+#
+CC= ${TOOLPREFIX}gcc
+LD= ${TOOLPREFIX}ld
+STRIP= ${TOOLPREFIX}strip
+OBJCOPY=${TOOLPREFIX}objcopy
+NM= ${TOOLPREFIX}nm
+
+LDOPTS= -EB
+COPTS+= -DAH_BYTE_ORDER=AH_BIG_ENDIAN
+COPTS+= -G 0 -EB -mno-abicalls -fno-pic -mips32 -Wa,--trap \
+ -fno-strict-aliasing -fno-common -fomit-frame-pointer -mlong-calls
diff --git a/public/ap61.inc b/public/ap61.inc
new file mode 100644
index 0000000..c1c193d
--- /dev/null
+++ b/public/ap61.inc
@@ -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: ap61.inc,v 1.2 2008/11/10 03:43:32 sam Exp $
+#
+
+#
+# Configuration for building big-endian MIPS2 for the AP61 SoC
+# using the 5.01 linux-mips.org toolchain (manually moved to
+# /pub/gnu from /pub/gnu/local where rpm --prefix=/pub/gnu
+# bogusly installs them).
+#
+
+#
+# http://www.linux-mips.org/toolchain.html
+#
+# /pub/gnu/bin/mips-linux-gcc -v
+# Reading specs from /pub/gnu/bin/../lib/gcc-lib/mips-linux/2.96-mips3264-000710/specs
+# gcc version 2.96-mips3264-000710
+# /pub/gnu/bin/mips-linux-as -v
+# GNU assembler version 2.12.90.0.7 (mips-linux) using BFD version 2.12.90.0.7 20020423
+
+#
+ifndef TOOLPREFIX
+TOOLPREFIX= /pub/gnu/bin/mips-linux-
+endif
+#
+CC= ${TOOLPREFIX}gcc
+LD= ${TOOLPREFIX}ld
+STRIP= ${TOOLPREFIX}strip
+OBJCOPY=${TOOLPREFIX}objcopy
+NM= ${TOOLPREFIX}nm
+
+LDOPTS= -EB
+COPTS+= -DAH_BYTE_ORDER=AH_BIG_ENDIAN
+COPTS+= -G 0 -EB -mno-abicalls -fno-pic -mips32 -Wa,--trap \
+ -fno-strict-aliasing -fno-common -fomit-frame-pointer -mlong-calls
diff --git a/public/arm9-le-thumb-elf.inc b/public/arm9-le-thumb-elf.inc
new file mode 100644
index 0000000..66cb0a3
--- /dev/null
+++ b/public/arm9-le-thumb-elf.inc
@@ -0,0 +1,59 @@
+#
+# 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: arm9-le-thumb-elf.inc,v 1.2 2008/11/10 03:43:36 sam Exp $
+#
+
+#
+# Compilation configuration for building little-endian ARM9/arm-elf.
+#
+# Known to work on:
+# Arm940T
+
+#
+# Force register read/write operations to go through a function so
+# ARM users can implement a windowing scheme to access registers in
+# the PCI address space.
+#
+AH_REGOPS_FUNC=1
+
+#
+# Built with GNU cross-devel tools:
+#
+# PREFIX=/pub/gnu
+# BINUTILS=binutils-2.14
+# GCC=gcc-3.3.2
+# target=arm-elf
+#
+# ${BINUTILS}/configure --target=$target --prefix=${PREFIX}
+# ${GCC}/configure --target=$target --prefix=${PREFIX} \
+# --enable-languages=c --with-gnu-as --with-gnu-ld \
+# --with-newlib --with-gxx-include-dir=${PREFIX}/$target/include
+#
+ifndef TOOLPREFIX
+TOOLPREFIX= /pub/gnu/bin/arm-elf-
+endif
+#
+CC= ${TOOLPREFIX}gcc
+LD= ${TOOLPREFIX}ld
+STRIP= ${TOOLPREFIX}strip
+OBJCOPY=${TOOLPREFIX}objcopy
+NM= ${TOOLPREFIX}nm
+
+LDOPTS= -EL
+COPTS+= -DAH_BYTE_ORDER=AH_LITTLE_ENDIAN
+COPTS+= -mthumb -mlittle-endian -mcpu=arm9 \
+ -ffunction-sections -fdata-sections
diff --git a/public/armv4-be-elf.inc b/public/armv4-be-elf.inc
new file mode 100644
index 0000000..a24f42b
--- /dev/null
+++ b/public/armv4-be-elf.inc
@@ -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: armv4-be-elf.inc,v 1.2 2008/11/10 03:43:40 sam Exp $
+#
+
+#
+# Compilation configuration for building big-endian ARMv4.
+#
+
+#
+# Built with GNU cross-devel tools:
+#
+# PREFIX=/pub/gnu
+# BINUTILS=binutils-2.14
+# GCC=gcc-3.3.2
+# target=arm-elf
+#
+# ${BINUTILS}/configure --target=$target --prefix=${PREFIX}
+# ${GCC}/configure --target=$target --prefix=${PREFIX} \
+# --enable-languages=c --with-gnu-as --with-gnu-ld \
+# --with-newlib --with-gxx-include-dir=${PREFIX}/$target/include
+#
+ifndef TOOLPREFIX
+TOOLPREFIX= /pub/gnu/bin/arm-elf-
+endif
+#
+CC= ${TOOLPREFIX}gcc
+LD= ${TOOLPREFIX}ld
+STRIP= ${TOOLPREFIX}strip
+OBJCOPY=${TOOLPREFIX}objcopy
+NM= ${TOOLPREFIX}nm
+
+#
+# Force register read/write operations to go through a function.
+#
+AH_REGOPS_FUNC=1
+
+LDOPTS= -EB
+COPTS+= -DAH_BYTE_ORDER=AH_BIG_ENDIAN
+COPTS+= -march=armv4 -mbig-endian \
+ -fno-strict-aliasing -fno-common
diff --git a/public/armv4-le-elf.inc b/public/armv4-le-elf.inc
new file mode 100644
index 0000000..0d059aa
--- /dev/null
+++ b/public/armv4-le-elf.inc
@@ -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: armv4-le-elf.inc,v 1.2 2008/11/10 03:43:48 sam Exp $
+#
+
+#
+# Compilation configuration for building little-endian ARMv4.
+#
+
+#
+# Built with GNU cross-devel tools:
+#
+# PREFIX=/pub/gnu
+# BINUTILS=binutils-2.14
+# GCC=gcc-3.3.2
+# target=arm-elf
+#
+# ${BINUTILS}/configure --target=$target --prefix=${PREFIX}
+# ${GCC}/configure --target=$target --prefix=${PREFIX} \
+# --enable-languages=c --with-gnu-as --with-gnu-ld \
+# --with-newlib --with-gxx-include-dir=${PREFIX}/$target/include
+#
+ifndef TOOLPREFIX
+TOOLPREFIX= /pub/gnu/bin/arm-elf-
+endif
+#
+CC= ${TOOLPREFIX}gcc
+LD= ${TOOLPREFIX}ld
+STRIP= ${TOOLPREFIX}strip
+OBJCOPY=${TOOLPREFIX}objcopy
+NM= ${TOOLPREFIX}nm
+
+#
+# Force register read/write operations to go through a function.
+#
+AH_REGOPS_FUNC=1
+
+LDOPTS= -EL
+COPTS+= -DAH_BYTE_ORDER=AH_LITTLE_ENDIAN
+COPTS+= -march=armv4 -mlittle-endian \
+ -fno-strict-aliasing -fno-common
diff --git a/public/i386-elf.inc b/public/i386-elf.inc
new file mode 100644
index 0000000..0c7c39d
--- /dev/null
+++ b/public/i386-elf.inc
@@ -0,0 +1,39 @@
+#
+# 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: i386-elf.inc,v 1.2 2008/11/10 03:43:53 sam Exp $
+#
+
+#
+# Compilation configuration for building i386-elf.
+# This assumes the build platform is also i386-elf.
+#
+
+#
+ifndef TOOLPREFIX
+TOOLPREFIX=
+endif
+#
+CC= ${TOOLPREFIX}gcc
+LD= ${TOOLPREFIX}ld
+STRIP= ${TOOLPREFIX}strip
+OBJCOPY=${TOOLPREFIX}objcopy
+NM= ${TOOLPREFIX}nm
+
+COPTS+= -DAH_BYTE_ORDER=AH_LITTLE_ENDIAN
+ifndef CONFIG_FRAME_POINTER
+COPTS+= -fomit-frame-pointer
+endif
diff --git a/public/mips-be-elf.inc b/public/mips-be-elf.inc
new file mode 100644
index 0000000..4a242bc
--- /dev/null
+++ b/public/mips-be-elf.inc
@@ -0,0 +1,56 @@
+#
+# 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: mips-be-elf.inc,v 1.2 2008/11/10 03:44:02 sam Exp $
+#
+
+#
+# Configuration for building big-endian MIPS2 using the 5.01
+# linux-mips.org toolchain (manually moved to /pub/gnu from
+# /pub/gnu/local where rpm --prefix=/pub/gnu bogusly installs them).
+#
+# Known to work on:
+# AMD Au1500
+
+#
+# http://www.linux-mips.org/toolchain.html
+#
+# /pub/gnu/bin/mips-linux-gcc -v
+# Reading specs from /pub/gnu/bin/../lib/gcc-lib/mips-linux/2.96-mips3264-000710/specs
+# gcc version 2.96-mips3264-000710
+# /pub/gnu/bin/mips-linux-as -v
+# GNU assembler version 2.12.90.0.7 (mips-linux) using BFD version 2.12.90.0.7 20020423
+
+#
+ifndef TOOLPREFIX
+TOOLPREFIX= /pub/gnu/bin/mips-linux-
+endif
+#
+CC= ${TOOLPREFIX}gcc
+LD= ${TOOLPREFIX}ld
+STRIP= ${TOOLPREFIX}strip
+OBJCOPY=${TOOLPREFIX}objcopy
+NM= ${TOOLPREFIX}nm
+
+#
+# Force register read/write operations to go through a function.
+#
+AH_REGOPS_FUNC=1
+
+LDOPTS= -EB
+COPTS+= -DAH_BYTE_ORDER=AH_BIG_ENDIAN
+COPTS+= -G 0 -EB -mno-abicalls -fno-pic -mips2 -Wa,--trap \
+ -fno-strict-aliasing -fno-common -fomit-frame-pointer -mlong-calls
diff --git a/public/mips-le-elf.inc b/public/mips-le-elf.inc
new file mode 100644
index 0000000..9f8dd38
--- /dev/null
+++ b/public/mips-le-elf.inc
@@ -0,0 +1,53 @@
+#
+# 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: mips-le-elf.inc,v 1.2 2008/11/10 03:44:05 sam Exp $
+#
+
+#
+# Configuration for building little-endian MIPS2 using the 5.01
+# linux-mips.org toolchain (manually moved to /pub/gnu from
+# /pub/gnu/local where rpm --prefix=/pub/gnu bogusly installs them).
+
+#
+# http://www.linux-mips.org/toolchain.html
+#
+# /pub/gnu/bin/mips-linux-gcc -v
+# Reading specs from /pub/gnu/bin/../lib/gcc-lib/mips-linux/2.96-mips3264-000710/specs
+# gcc version 2.96-mips3264-000710
+# /pub/gnu/bin/mips-linux-as -v
+# GNU assembler version 2.12.90.0.7 (mips-linux) using BFD version 2.12.90.0.7 20020423
+
+#
+ifndef TOOLPREFIX
+TOOLPREFIX= /pub/gnu/bin/mips-linux-
+endif
+#
+CC= ${TOOLPREFIX}gcc
+LD= ${TOOLPREFIX}ld
+STRIP= ${TOOLPREFIX}strip
+OBJCOPY=${TOOLPREFIX}objcopy
+NM= ${TOOLPREFIX}nm
+
+#
+# Force register read/write operations to go through a function.
+#
+AH_REGOPS_FUNC=1
+
+LDOPTS= -EL
+COPTS+= -DAH_BYTE_ORDER=AH_LITTLE_ENDIAN
+COPTS+= -G 0 -EL -mno-abicalls -fno-pic -mips2 -Wa,--trap \
+ -fno-strict-aliasing -fno-common -fomit-frame-pointer -mlong-calls
diff --git a/public/mips1-be-elf.inc b/public/mips1-be-elf.inc
new file mode 100644
index 0000000..a4c1c1b
--- /dev/null
+++ b/public/mips1-be-elf.inc
@@ -0,0 +1,53 @@
+#
+# 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: mips1-be-elf.inc,v 1.2 2008/11/10 03:44:09 sam Exp $
+#
+
+#
+# Configuration for building big-endian MIPS1 using the 5.01
+# linux-mips.org toolchain (manually moved to /pub/gnu from
+# /pub/gnu/local where rpm --prefix=/pub/gnu bogusly installs them).
+
+#
+# http://www.linux-mips.org/toolchain.html
+#
+# /pub/gnu/bin/mips-linux-gcc -v
+# Reading specs from /pub/gnu/bin/../lib/gcc-lib/mips-linux/2.96-mips3264-000710/specs
+# gcc version 2.96-mips3264-000710
+# /pub/gnu/bin/mips-linux-as -v
+# GNU assembler version 2.12.90.0.7 (mips-linux) using BFD version 2.12.90.0.7 20020423
+
+#
+ifndef TOOLPREFIX
+TOOLPREFIX= /pub/gnu/bin/mips-linux-
+endif
+#
+CC= ${TOOLPREFIX}gcc
+LD= ${TOOLPREFIX}ld
+STRIP= ${TOOLPREFIX}strip
+OBJCOPY=${TOOLPREFIX}objcopy
+NM= ${TOOLPREFIX}nm
+
+#
+# Force register read/write operations to go through a function.
+#
+AH_REGOPS_FUNC=1
+
+LDOPTS= -EB
+COPTS+= -DAH_BYTE_ORDER=AH_BIG_ENDIAN
+COPTS+= -G 0 -EB -mno-abicalls -fno-pic -mips1 -Wa,--trap \
+ -fno-strict-aliasing -fno-common -fomit-frame-pointer -mlong-calls
diff --git a/public/mips1-le-elf.inc b/public/mips1-le-elf.inc
new file mode 100644
index 0000000..5854589
--- /dev/null
+++ b/public/mips1-le-elf.inc
@@ -0,0 +1,53 @@
+#
+# 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: mips1-le-elf.inc,v 1.2 2008/11/10 03:44:14 sam Exp $
+#
+
+#
+# Configuration for building little-endian MIPS1 using the 5.01
+# linux-mips.org toolchain (manually moved to /pub/gnu from
+# /pub/gnu/local where rpm --prefix=/pub/gnu bogusly installs them).
+
+#
+# http://www.linux-mips.org/toolchain.html
+#
+# /pub/gnu/bin/mips-linux-gcc -v
+# Reading specs from /pub/gnu/bin/../lib/gcc-lib/mips-linux/2.96-mips3264-000710/specs
+# gcc version 2.96-mips3264-000710
+# /pub/gnu/bin/mips-linux-as -v
+# GNU assembler version 2.12.90.0.7 (mips-linux) using BFD version 2.12.90.0.7 20020423
+
+#
+ifndef TOOLPREFIX
+TOOLPREFIX= /pub/gnu/bin/mips-linux-
+endif
+#
+CC= ${TOOLPREFIX}gcc
+LD= ${TOOLPREFIX}ld
+STRIP= ${TOOLPREFIX}strip
+OBJCOPY=${TOOLPREFIX}objcopy
+NM= ${TOOLPREFIX}nm
+
+#
+# Force register read/write operations to go through a function.
+#
+AH_REGOPS_FUNC=1
+
+LDOPTS= -EL
+COPTS+= -DAH_BYTE_ORDER=AH_LITTLE_ENDIAN
+COPTS+= -G 0 -EL -mno-abicalls -fno-pic -mips1 -Wa,--trap \
+ -fno-strict-aliasing -fno-common -fomit-frame-pointer -mlong-calls
diff --git a/public/mipsisa32-be-elf.inc b/public/mipsisa32-be-elf.inc
new file mode 100644
index 0000000..9a0b4c5
--- /dev/null
+++ b/public/mipsisa32-be-elf.inc
@@ -0,0 +1,57 @@
+#
+# 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: mipsisa32-be-elf.inc,v 1.2 2008/11/10 03:44:18 sam Exp $
+#
+
+#
+# Compilation configuration for building big-endian mipsisa32-elf.
+#
+
+#
+# Built with GNU cross-devel tools:
+#
+# PREFIX=/pub/gnu
+# BINUTILS=binutils-2.14
+# GCC=gcc-3.3.2
+# target=mipsisa32-elf
+#
+# ${BINUTILS}/configure --target=$target --prefix=${PREFIX}
+# ${GCC}/configure --target=$target --prefix=${PREFIX} \
+# --enable-languages=c --with-gnu-as --with-gnu-ld \
+# --with-newlib --with-gxx-include-dir=${PREFIX}/$target/include
+#
+ifndef TOOLPREFIX
+TOOLPREFIX= /pub/gnu/bin/mipsisa32-elf-
+endif
+#
+CC= ${TOOLPREFIX}gcc
+LD= ${TOOLPREFIX}ld
+STRIP= ${TOOLPREFIX}strip
+OBJCOPY=${TOOLPREFIX}objcopy
+NM= ${TOOLPREFIX}nm
+
+#
+# Force register read/write operations to go through a function.
+#
+AH_REGOPS_FUNC=1
+
+LDOPTS+= -EB
+COPTS+= -DAH_BYTE_ORDER=AH_BIG_ENDIAN
+COPTS+= -G 0 -mno-abicalls -fno-pic -march=r4600 -Wa,--trap \
+ -fno-strict-aliasing -fno-common -fomit-frame-pointer -mlong-calls \
+ -isystem ${KERNELPATH}/include
+
diff --git a/public/mipsisa32-le-elf.inc b/public/mipsisa32-le-elf.inc
new file mode 100644
index 0000000..ef833fb9
--- /dev/null
+++ b/public/mipsisa32-le-elf.inc
@@ -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: mipsisa32-le-elf.inc,v 1.2 2008/11/10 03:44:22 sam Exp $
+#
+
+#
+# Compilation configuration for building little-endian mipsisa32-elf.
+#
+
+#
+# Built with GNU cross-devel tools:
+#
+# PREFIX=/pub/gnu
+# BINUTILS=binutils-2.14
+# GCC=gcc-3.3.2
+# target=mipsisa32-elf
+#
+# ${BINUTILS}/configure --target=$target --prefix=${PREFIX}
+# ${GCC}/configure --target=$target --prefix=${PREFIX} \
+# --enable-languages=c --with-gnu-as --with-gnu-ld \
+# --with-newlib --with-gxx-include-dir=${PREFIX}/$target/include
+#
+ifndef TOOLPREFIX
+TOOLPREFIX= /pub/gnu/bin/mipsisa32-elf-
+endif
+#
+CC= ${TOOLPREFIX}gcc
+LD= ${TOOLPREFIX}ld
+STRIP= ${TOOLPREFIX}strip
+OBJCOPY=${TOOLPREFIX}objcopy
+NM= ${TOOLPREFIX}nm
+
+#
+# Force register read/write operations to go through a function.
+#
+AH_REGOPS_FUNC=1
+
+LDOPTS= -EL
+COPTS+= -DAH_BYTE_ORDER=AH_LITTLE_ENDIAN
+COPTS+= -G 0 -EL -mno-abicalls -fno-pic -march=r4600 -Wa,--trap \
+ -fno-strict-aliasing -fno-common -fomit-frame-pointer -mlong-calls
diff --git a/public/powerpc-be-eabi.inc b/public/powerpc-be-eabi.inc
new file mode 100644
index 0000000..411883e
--- /dev/null
+++ b/public/powerpc-be-eabi.inc
@@ -0,0 +1,57 @@
+#
+# 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: powerpc-be-eabi.inc,v 1.2 2008/11/10 03:44:27 sam Exp $
+#
+
+#
+# Compilation configuration for building big-endian PowerPC/powerpc-eabi.
+#
+# Known to work on:
+# IBM 450EP
+
+#
+# Built with GNU cross-devel tools:
+#
+# PREFIX=/pub/gnu
+# BINUTILS=binutils-2.14
+# GCC=gcc-3.3.2
+# target=powerpc-eabi
+#
+# ${BINUTILS}/configure --target=$target --prefix=${PREFIX}
+# ${GCC}/configure --target=$target --prefix=${PREFIX} \
+# --enable-languages=c --with-gnu-as --with-gnu-ld \
+# --with-newlib --with-gxx-include-dir=${PREFIX}/$target/include
+#
+ifndef TOOLPREFIX
+TOOLPREFIX= /pub/gnu/bin/powerpc-eabi-
+endif
+#
+CC= ${TOOLPREFIX}gcc
+LD= ${TOOLPREFIX}ld
+STRIP= ${TOOLPREFIX}strip
+OBJCOPY=${TOOLPREFIX}objcopy
+NM= ${TOOLPREFIX}nm
+
+#
+# Force register read/write operations to go through a function.
+#
+AH_REGOPS_FUNC=1
+
+LDOPTS= -EB
+COPTS+= -DAH_BYTE_ORDER=AH_BIG_ENDIAN
+COPTS+= -mbig-endian
+COPTS+= -msoft-float -ffixed-r2
diff --git a/public/powerpc-be-elf.inc b/public/powerpc-be-elf.inc
new file mode 100644
index 0000000..13088a9
--- /dev/null
+++ b/public/powerpc-be-elf.inc
@@ -0,0 +1,53 @@
+#
+# 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: powerpc-be-elf.inc,v 1.2 2008/11/10 03:44:32 sam Exp $
+#
+
+#
+# Compilation configuration for building big-endian PowerPC/powerpc-elf.
+#
+# Built with GNU cross-devel tools:
+#
+# PREFIX=/pub/gnu
+# BINUTILS=binutils-2.14
+# GCC=gcc-3.3.2
+# target=powerpc-elf
+#
+# ${BINUTILS}/configure --target=$target --prefix=${PREFIX}
+# ${GCC}/configure --target=$target --prefix=${PREFIX} \
+# --enable-languages=c --with-gnu-as --with-gnu-ld \
+# --with-newlib --with-gxx-include-dir=${PREFIX}/$target/include
+#
+ifndef TOOLPREFIX
+TOOLPREFIX= /pub/gnu/bin/powerpc-elf-
+endif
+#
+CC= ${TOOLPREFIX}gcc
+LD= ${TOOLPREFIX}ld
+STRIP= ${TOOLPREFIX}strip
+OBJCOPY=${TOOLPREFIX}objcopy
+NM= ${TOOLPREFIX}nm
+
+#
+# Force register read/write operations to go through a function.
+#
+AH_REGOPS_FUNC=1
+
+LDOPTS= -EB
+COPTS+= -DAH_BYTE_ORDER=AH_BIG_ENDIAN
+COPTS+= -mbig-endian
+COPTS+= -msoft-float -ffixed-r2
diff --git a/public/powerpc-le-eabi.inc b/public/powerpc-le-eabi.inc
new file mode 100644
index 0000000..fb92c1f
--- /dev/null
+++ b/public/powerpc-le-eabi.inc
@@ -0,0 +1,56 @@
+#
+# 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: powerpc-le-eabi.inc,v 1.2 2008/11/10 03:44:36 sam Exp $
+#
+
+#
+# Compilation configuration for building little-endian PowerPC/powerpc-eabi.
+#
+
+#
+# Built with GNU cross-devel tools:
+#
+# PREFIX=/pub/gnu
+# BINUTILS=binutils-2.14
+# GCC=gcc-3.3.2
+# target=powerpc-eabi
+#
+# ${BINUTILS}/configure --target=$target --prefix=${PREFIX}
+# ${GCC}/configure --target=$target --prefix=${PREFIX} \
+# --enable-languages=c --with-gnu-as --with-gnu-ld \
+# --with-newlib --with-gxx-include-dir=${PREFIX}/$target/include
+#
+ifndef TOOLPREFIX
+TOOLPREFIX= /pub/gnu/bin/powerpc-eabi-
+endif
+#
+CC= ${TOOLPREFIX}gcc
+LD= ${TOOLPREFIX}ld
+STRIP= ${TOOLPREFIX}strip
+OBJCOPY=${TOOLPREFIX}objcopy
+NM= ${TOOLPREFIX}nm
+
+#
+# Force register read/write operations to go through a function.
+#
+AH_REGOPS_FUNC=1
+
+LDOPTS= -EL
+COPTS+= -DAH_BYTE_ORDER=AH_LITTLE_ENDIAN
+COPTS+= -mlittle-endian
+# NB: explicitly disable multiple and string instructions for little-endian
+COPTS+= -msoft-float -ffixed-r2 -mno-multiple -mno-string
diff --git a/public/sh4-le-elf.inc b/public/sh4-le-elf.inc
new file mode 100644
index 0000000..465b5e6
--- /dev/null
+++ b/public/sh4-le-elf.inc
@@ -0,0 +1,43 @@
+#
+# 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: sh4-le-elf.inc,v 1.2 2008/11/10 03:44:44 sam Exp $
+#
+
+#
+# Compilation configuration for building little-endian SuperH/ELF.
+#
+
+#
+# Built with pre-packaged tools for RedHat 7.3:
+#
+# http://mirror.sh-linux.org/rpm-index-2003/i386/ByName.html`
+# binutils-sh-linux-2.13.90.0.18-1
+# gcc-sh-linux-3.2.3-3
+#
+ifndef TOOLPREFIX
+TOOLPREFIX= /pub/gnu/bin/sh-linux-
+endif
+#
+CC= ${TOOLPREFIX}gcc
+LD= ${TOOLPREFIX}ld
+STRIP= ${TOOLPREFIX}strip
+OBJCOPY=${TOOLPREFIX}objcopy
+NM= ${TOOLPREFIX}nm
+
+LDOPTS= -EL
+COPTS+= -DAH_BYTE_ORDER=AH_LITTLE_ENDIAN
+COPTS+= -ml -m4 -mno-implicit-fp
diff --git a/public/sparc-be-elf.inc b/public/sparc-be-elf.inc
new file mode 100644
index 0000000..8c581a4
--- /dev/null
+++ b/public/sparc-be-elf.inc
@@ -0,0 +1,53 @@
+#
+# 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: sparc-be-elf.inc,v 1.2 2008/11/10 03:44:45 sam Exp $
+#
+
+#
+# Compilation configuration for building big-endian Sparc for 32-bit.
+#
+# Built with GNU cross-devel tools:
+#
+# PREFIX=/pub/gnu
+# BINUTILS=binutils-2.14
+# GCC=gcc-3.3.2
+# target=sparc-elf
+#
+# ${BINUTILS}/configure --target=$target --prefix=${PREFIX}
+# ${GCC}/configure --target=$target --prefix=${PREFIX} \
+# --enable-languages=c --with-gnu-as --with-gnu-ld \
+# --with-newlib --with-gxx-include-dir=${PREFIX}/$target/include
+#
+ifndef TOOLPREFIX
+TOOLPREFIX= /pub/gnu/bin/sparc-elf-
+endif
+#
+CC= ${TOOLPREFIX}gcc
+LD= ${TOOLPREFIX}ld
+STRIP= ${TOOLPREFIX}strip
+OBJCOPY=${TOOLPREFIX}objcopy
+NM= ${TOOLPREFIX}nm
+
+#
+# Force register read/write operations to go through a function.
+#
+AH_REGOPS_FUNC=1
+
+LDOPTS= -EB
+COPTS+= -DAH_BYTE_ORDER=AH_BIG_ENDIAN
+COPTS+= -m32
+COPTS+= -mno-fpu
diff --git a/public/sparc64-be-elf.inc b/public/sparc64-be-elf.inc
new file mode 100644
index 0000000..b00160f
--- /dev/null
+++ b/public/sparc64-be-elf.inc
@@ -0,0 +1,64 @@
+#
+# 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: sparc64-be-elf.inc,v 1.2 2008/11/10 03:44:51 sam Exp $
+#
+
+#
+# Compilation configuration for building big-endian Sparc64 w/ elf.
+#
+# Built with GNU cross-devel tools:
+#
+# PREFIX=/pub/gnu
+# BINUTILS=binutils-2.14
+# GCC=gcc-3.3.2
+# target=sparc64-elf
+#
+# ${BINUTILS}/configure --target=$target --prefix=${PREFIX}
+# ${GCC}/configure --target=$target --prefix=${PREFIX} \
+# --enable-languages=c --with-gnu-as --with-gnu-ld \
+# --with-newlib --with-gxx-include-dir=${PREFIX}/$target/include
+#
+ifndef TOOLPREFIX
+TOOLPREFIX= /pub/gnu/bin/sparc64-elf-
+endif
+#
+CC= ${TOOLPREFIX}gcc
+LD= ${TOOLPREFIX}ld
+STRIP= ${TOOLPREFIX}strip
+OBJCOPY=${TOOLPREFIX}objcopy
+NM= ${TOOLPREFIX}nm
+
+#
+# Force register read/write operations to go through a function.
+#
+AH_REGOPS_FUNC=1
+
+LDOPTS= -EB
+COPTS+= -DAH_BYTE_ORDER=AH_BIG_ENDIAN
+#
+# NB: this should come from inttypes.h but can't until we cleanp
+# the definition of va_list on linux
+#
+COPTS+= -DAH_WORDSIZE=64
+COPTS+= -mcmodel=medlow
+COPTS+= -mno-fpu
+#
+# Suppress TLS register usage; haven't figured out to do this
+# when we build the toolchain (so unfortunately we pollute the
+# build options).
+#
+COPTS+= -ffixed-g2 -ffixed-g3
diff --git a/public/wackelf.c b/public/wackelf.c
new file mode 100644
index 0000000..7200b69
--- /dev/null
+++ b/public/wackelf.c
@@ -0,0 +1,103 @@
+/*
+ * 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: wackelf.c,v 1.2 2008/11/10 03:44:51 sam Exp $
+ */
+
+/*
+ * Program to zap flags field in the ELF header of an object
+ * file so that it appears to use VFP soft floating point.
+ * This is done because there is no standard way to specify
+ * this on the command line to gcc/binutils.
+ *
+ * Derived from code by Olivier Houchard <cognet@freebsd.org>
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <elf.h>
+#include <fcntl.h>
+#include <err.h>
+
+#ifdef __linux__
+#include <endian.h>
+#include <byteswap.h>
+#define _LITTLE_ENDIAN __LITTLE_ENDIAN
+#define _BIG_ENDIAN __BIG_ENDIAN
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define htobe16(x) __bswap_16((x))
+#define htobe32(x) __bswap_32((x))
+#define htole16(x) ((uint16_t)(x))
+#define htole32(x) ((uint32_t)(x))
+#else /* _BYTE_ORDER != _LITTLE_ENDIAN */
+#define htobe16(x) ((uint16_t)(x))
+#define htobe32(x) ((uint32_t)(x))
+#define htole16(x) __bswap_16((x))
+#define htole32(x) __bswap_32((x))
+#endif /* _BYTE_ORDER == _LITTLE_ENDIAN */
+#else
+#include <sys/endian.h>
+#endif
+
+int
+main(int argc, char *argv[])
+{
+ int fd, endian, oflags;
+ int format = 0x400; /* default to VFP */
+ Elf32_Ehdr ehdr;
+
+ if (argc > 2) {
+ if (strcmp(argv[1], "-fpa") == 0) {
+ format = 0x200;
+ argc--, argv++;
+ } else if (strcmp(argv[1], "-vfp") == 0) {
+ format = 0x400;
+ argc--, argv++;
+ } else if (strcmp(argv[1], "-none") == 0) {
+ format = 0;
+ argc--, argv++;
+ }
+ }
+ if (argc != 2) {
+ fprintf(stderr, "usage: %s [-fpa|-vfp|-none] file\n", argv[0]);
+ exit(-1);
+ }
+ fd = open(argv[1], O_RDWR);
+ if (fd < 0)
+ err(1, "could not open %s", argv[1]);
+ if (read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr))
+ err(1, "could not read the ELF header");
+ if (ehdr.e_machine == htole16(EM_ARM))
+ endian = _LITTLE_ENDIAN;
+ else if (ehdr.e_machine == htobe16(EM_ARM))
+ endian = _BIG_ENDIAN;
+ else
+ errx(1, "not an ARM ELF object (machine 0x%x)", ehdr.e_machine);
+ oflags = ehdr.e_flags;
+ if (endian == _BIG_ENDIAN) {
+ ehdr.e_flags &= ~htobe32(0x600); /* Remove FPA Soft float */
+ ehdr.e_flags |= htobe32(format); /* VFP Soft Float */
+ } else {
+ ehdr.e_flags &= ~htole32(0x600); /* Remove FPA Soft float */
+ ehdr.e_flags |= htole32(format); /* VFP Soft Float */
+ }
+ printf("%s: e_flags 0x%x => 0x%x\n", argv[1], oflags, ehdr.e_flags);
+ if (lseek(fd, (off_t) 0, SEEK_SET) != 0)
+ err(1, "lseek");
+ if (write(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr))
+ err(1, "yow, elf header write failed");
+ close(fd);
+ return 0;
+}
diff --git a/public/wisoc.inc b/public/wisoc.inc
new file mode 100644
index 0000000..1ad8a00
--- /dev/null
+++ b/public/wisoc.inc
@@ -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: wisoc.inc,v 1.2 2008/11/10 03:44:53 sam Exp $
+#
+
+#
+# Configuration for building big-endian MIPS2 for the APxx SoC
+# using the 5.01 linux-mips.org toolchain (manually moved to
+# /pub/gnu from /pub/gnu/local where rpm --prefix=/pub/gnu
+# bogusly installs them).
+#
+
+#
+# http://www.linux-mips.org/toolchain.html
+#
+# /pub/gnu/bin/mips-linux-gcc -v
+# Reading specs from /pub/gnu/bin/../lib/gcc-lib/mips-linux/2.96-mips3264-000710/specs
+# gcc version 2.96-mips3264-000710
+# /pub/gnu/bin/mips-linux-as -v
+# GNU assembler version 2.12.90.0.7 (mips-linux) using BFD version 2.12.90.0.7 20020423
+
+#
+ifndef TOOLPREFIX
+TOOLPREFIX= /pub/gnu/bin/mips-linux-
+endif
+#
+CC= ${TOOLPREFIX}gcc
+LD= ${TOOLPREFIX}ld
+STRIP= ${TOOLPREFIX}strip
+OBJCOPY=${TOOLPREFIX}objcopy
+NM= ${TOOLPREFIX}nm
+
+LDOPTS= -EB
+COPTS+= -DAH_BYTE_ORDER=AH_BIG_ENDIAN
+COPTS+= -G 0 -EB -mno-abicalls -fno-pic -mips32 -Wa,--trap \
+ -fno-strict-aliasing -fno-common -fomit-frame-pointer -mlong-calls
diff --git a/public/x86_64-elf.inc b/public/x86_64-elf.inc
new file mode 100644
index 0000000..cea2389
--- /dev/null
+++ b/public/x86_64-elf.inc
@@ -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: x86_64-elf.inc,v 1.2 2008/11/10 03:44:59 sam Exp $
+#
+
+#
+# Compilation configuration for building x86-64-elf.
+#
+
+#
+ifndef TOOLPREFIX
+TOOLPREFIX= /pub/gnu/bin/x86_64-linux-
+endif
+#
+CC= ${TOOLPREFIX}gcc
+LD= ${TOOLPREFIX}ld
+STRIP= ${TOOLPREFIX}strip
+OBJCOPY=${TOOLPREFIX}objcopy
+NM= ${TOOLPREFIX}nm
+
+COPTS+= -DAH_BYTE_ORDER=AH_LITTLE_ENDIAN
+#
+# NB: this should come from inttypes.h but can't until we cleanp
+# the definition of va_list on linux
+#
+COPTS+= -DAH_WORDSIZE=64
+COPTS+= -mcmodel=kernel -mno-red-zone
+ifndef CONFIG_FRAME_POINTER
+COPTS+= -fomit-frame-pointer
+endif
diff --git a/public/xscale-be-elf.inc b/public/xscale-be-elf.inc
new file mode 100644
index 0000000..bb42dfb
--- /dev/null
+++ b/public/xscale-be-elf.inc
@@ -0,0 +1,62 @@
+#
+# 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: xscale-be-elf.inc,v 1.2 2008/11/10 03:45:03 sam Exp $
+#
+
+#
+# Compilation configuration for building big-endian XScale/arm-elf.
+#
+# NB: built with AH_REGOPS_FUNC to so that register accesses
+# can be done using the Linux readl/writel functions on
+# systems that need it.
+#
+# Reported to work on:
+# IXP425
+#
+
+#
+# Built with GNU cross-devel tools:
+#
+# PREFIX=/pub/gnu
+# BINUTILS=binutils-2.14
+# GCC=gcc-3.3.2
+# target=arm-elf
+#
+# ${BINUTILS}/configure --target=$target --prefix=${PREFIX}
+# ${GCC}/configure --target=$target --prefix=${PREFIX} \
+# --enable-languages=c --with-gnu-as --with-gnu-ld \
+# --with-newlib --with-gxx-include-dir=${PREFIX}/$target/include
+#
+ifndef TOOLPREFIX
+TOOLPREFIX= /pub/gnu/bin/arm-elf-
+endif
+#
+CC= ${TOOLPREFIX}gcc
+LD= ${TOOLPREFIX}ld
+STRIP= ${TOOLPREFIX}strip
+OBJCOPY=${TOOLPREFIX}objcopy
+NM= ${TOOLPREFIX}nm
+
+#
+# Force register read/write operations to go through a function.
+#
+AH_REGOPS_FUNC=1
+
+LDOPTS= -EB
+COPTS+= -DAH_BYTE_ORDER=AH_BIG_ENDIAN
+COPTS+= -march=armv4 -mbig-endian -fno-strict-aliasing -fno-common -mapcs-32 \
+ -mtune=xscale -mshort-load-bytes
diff --git a/public/xscale-le-elf.inc b/public/xscale-le-elf.inc
new file mode 100644
index 0000000..f34f9fa
--- /dev/null
+++ b/public/xscale-le-elf.inc
@@ -0,0 +1,63 @@
+#
+# 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: xscale-le-elf.inc,v 1.2 2008/11/10 03:45:07 sam Exp $
+#
+
+#
+# Compilation configuration for building little-endian XScale/arm-elf.
+#
+# NB: built with AH_REGOPS_FUNC to so that register accesses
+# can be done using the Linux readl/writel functions on
+# systems that need it.
+#
+# Reported to work on:
+# Compulab's ARMBASE using ARMCORE GX
+# (http://www.compulab.co.il/armbase.htm)
+#
+
+#
+# Built with GNU cross-devel tools:
+#
+# PREFIX=/pub/gnu
+# BINUTILS=binutils-2.14
+# GCC=gcc-3.3.2
+# target=arm-elf
+#
+# ${BINUTILS}/configure --target=$target --prefix=${PREFIX}
+# ${GCC}/configure --target=$target --prefix=${PREFIX} \
+# --enable-languages=c --with-gnu-as --with-gnu-ld \
+# --with-newlib --with-gxx-include-dir=${PREFIX}/$target/include
+#
+ifndef TOOLPREFIX
+TOOLPREFIX= /pub/gnu/bin/arm-elf-
+endif
+#
+CC= ${TOOLPREFIX}gcc
+LD= ${TOOLPREFIX}ld
+STRIP= ${TOOLPREFIX}strip
+OBJCOPY=${TOOLPREFIX}objcopy
+NM= ${TOOLPREFIX}nm
+
+#
+# Force register read/write operations to go through a function.
+#
+AH_REGOPS_FUNC=1
+
+LDOPTS= -EL
+COPTS+= -DAH_BYTE_ORDER=AH_LITTLE_ENDIAN
+COPTS+= -march=armv4 -mlittle-endian -fno-strict-aliasing -fno-common \
+ -mapcs-32 -mtune=xscale -mshort-load-bytes
diff --git a/version.h b/version.h
new file mode 100644
index 0000000..4c16163
--- /dev/null
+++ b/version.h
@@ -0,0 +1,19 @@
+/*
+ * 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: version.h,v 1.31 2008/11/10 01:05:31 sam Exp $
+ */
+#define ATH_HAL_VERSION "0.11.2.0"
OpenPOWER on IntegriCloud