summaryrefslogtreecommitdiffstats
path: root/ar5416
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 /ar5416
downloadFreeBSD-src-e0752b627b8facba40d9f4daae09c6833bb1daec.zip
FreeBSD-src-e0752b627b8facba40d9f4daae09c6833bb1daec.tar.gz
virgin import of ath hal
Diffstat (limited to 'ar5416')
-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
20 files changed, 10328 insertions, 0 deletions
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 */
OpenPOWER on IntegriCloud