aboutsummaryrefslogtreecommitdiff
path: root/ar5312
diff options
context:
space:
mode:
authorSam Leffler <sam@FreeBSD.org>2008-11-28 00:03:41 +0000
committerSam Leffler <sam@FreeBSD.org>2008-11-28 00:03:41 +0000
commitd972528d489f39e17e1c43f85d857b9b5414619c (patch)
tree5e6c67d27f7d4af49cc3aea5c9d7528a2243d63d /ar5312
downloadsrc-d972528d489f39e17e1c43f85d857b9b5414619c.tar.gz
src-d972528d489f39e17e1c43f85d857b9b5414619c.zip
virgin import of ath hal
Notes
Notes: svn path=/projects/ath_hal/; revision=185377
Diffstat (limited to 'ar5312')
-rw-r--r--ar5312/ar5312.h80
-rw-r--r--ar5312/ar5312_attach.c363
-rw-r--r--ar5312/ar5312_eeprom.c47
-rw-r--r--ar5312/ar5312_gpio.c131
-rw-r--r--ar5312/ar5312_interrupts.c47
-rw-r--r--ar5312/ar5312_misc.c165
-rw-r--r--ar5312/ar5312_power.c125
-rw-r--r--ar5312/ar5312_reset.c924
-rw-r--r--ar5312/ar5312phy.h31
-rw-r--r--ar5312/ar5312reg.h139
-rw-r--r--ar5312/ar5315_gpio.c130
11 files changed, 2182 insertions, 0 deletions
diff --git a/ar5312/ar5312.h b/ar5312/ar5312.h
new file mode 100644
index 000000000000..08edf2f490f7
--- /dev/null
+++ b/ar5312/ar5312.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
+ * Copyright (c) 2002-2008 Atheros Communications, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $Id: ar5312.h,v 1.4 2008/11/10 04:08:04 sam Exp $
+ */
+#ifndef _ATH_AR5312_H_
+#define _ATH_AR5312_H_
+
+#include "ah_soc.h"
+#include "ar5212/ar5212.h"
+
+#define AR5312_UNIT(_ah) \
+ (((const struct ar531x_config *)((_ah)->ah_st))->unit)
+#define AR5312_BOARDCONFIG(_ah) \
+ (((const struct ar531x_config *)((_ah)->ah_st))->board)
+#define AR5312_RADIOCONFIG(_ah) \
+ (((const struct ar531x_config *)((_ah)->ah_st))->radio)
+
+#define IS_5312_2_X(ah) \
+ (((AH_PRIVATE(ah)->ah_macVersion) == AR_SREV_VERSION_VENICE) && \
+ (((AH_PRIVATE(ah)->ah_macRev) == 2) || ((AH_PRIVATE(ah)->ah_macRev) == 7)))
+
+#define IS_5315(ah) \
+ ((AH_PRIVATE(ah)->ah_devid == AR5212_AR2315_REV6) || \
+ (AH_PRIVATE(ah)->ah_devid == AR5212_AR2315_REV7) || \
+ (AH_PRIVATE(ah)->ah_devid == AR5212_AR2317_REV1) || \
+ (AH_PRIVATE(ah)->ah_devid == AR5212_AR2317_REV2))
+
+
+extern struct ath_hal * ar5312Attach(uint16_t devid, HAL_SOFTC sc,
+ HAL_BUS_TAG st, HAL_BUS_HANDLE sh, HAL_STATUS *status);
+extern HAL_BOOL ar5312IsInterruptPending(struct ath_hal *ah);
+
+/* AR5312 */
+extern HAL_BOOL ar5312GpioCfgOutput(struct ath_hal *, uint32_t gpio);
+extern HAL_BOOL ar5312GpioCfgInput(struct ath_hal *, uint32_t gpio);
+extern HAL_BOOL ar5312GpioSet(struct ath_hal *, uint32_t gpio, uint32_t val);
+extern uint32_t ar5312GpioGet(struct ath_hal *ah, uint32_t gpio);
+extern void ar5312GpioSetIntr(struct ath_hal *ah, u_int, uint32_t ilevel);
+
+/* AR2315+ */
+extern HAL_BOOL ar5315GpioCfgOutput(struct ath_hal *, uint32_t gpio);
+extern HAL_BOOL ar5315GpioCfgInput(struct ath_hal *, uint32_t gpio);
+extern HAL_BOOL ar5315GpioSet(struct ath_hal *, uint32_t gpio, uint32_t val);
+extern uint32_t ar5315GpioGet(struct ath_hal *ah, uint32_t gpio);
+extern void ar5315GpioSetIntr(struct ath_hal *ah, u_int, uint32_t ilevel);
+
+extern void ar5312SetLedState(struct ath_hal *ah, HAL_LED_STATE state);
+extern HAL_BOOL ar5312DetectCardPresent(struct ath_hal *ah);
+extern void ar5312SetupClock(struct ath_hal *ah, HAL_OPMODE opmode);
+extern void ar5312RestoreClock(struct ath_hal *ah, HAL_OPMODE opmode);
+extern void ar5312DumpState(struct ath_hal *ah);
+extern HAL_BOOL ar5312Reset(struct ath_hal *ah, HAL_OPMODE opmode,
+ HAL_CHANNEL *chan, HAL_BOOL bChannelChange, HAL_STATUS *status);
+extern HAL_BOOL ar5312ChipReset(struct ath_hal *ah, HAL_CHANNEL *chan);
+extern HAL_BOOL ar5312SetPowerMode(struct ath_hal *ah, HAL_POWER_MODE mode,
+ int setChip);
+extern HAL_BOOL ar5312PhyDisable(struct ath_hal *ah);
+extern HAL_BOOL ar5312Disable(struct ath_hal *ah);
+extern HAL_BOOL ar5312MacReset(struct ath_hal *ah, unsigned int RCMask);
+extern uint32_t ar5312GetPowerMode(struct ath_hal *ah);
+extern HAL_BOOL ar5312GetPowerStatus(struct ath_hal *ah);
+
+/* BSP functions */
+extern HAL_BOOL ar5312EepromRead(struct ath_hal *, u_int off, uint16_t *data);
+
+#endif /* _ATH_AR3212_H_ */
diff --git a/ar5312/ar5312_attach.c b/ar5312/ar5312_attach.c
new file mode 100644
index 000000000000..52d2132655c9
--- /dev/null
+++ b/ar5312/ar5312_attach.c
@@ -0,0 +1,363 @@
+/*
+ * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
+ * Copyright (c) 2002-2008 Atheros Communications, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $Id: ar5312_attach.c,v 1.6 2008/11/10 04:08:04 sam Exp $
+ */
+#include "opt_ah.h"
+
+#ifdef AH_SUPPORT_AR5312
+
+#if !defined(AH_SUPPORT_5112) && \
+ !defined(AH_SUPPORT_5111) && \
+ !defined(AH_SUPPORT_2316) && \
+ !defined(AH_SUPPORT_2317)
+#error "No 5312 RF support defined"
+#endif
+
+#include "ah.h"
+#include "ah_internal.h"
+#include "ah_devid.h"
+
+#include "ar5312/ar5312.h"
+#include "ar5312/ar5312reg.h"
+#include "ar5312/ar5312phy.h"
+
+/* Add static register initialization vectors */
+#define AH_5212_COMMON
+#include "ar5212/ar5212.ini"
+
+/*
+ * These are not valid 2.4 channels, either we change these
+ * or we need to change the coding to accept these
+ */
+static const uint16_t channels11b[] = { 2412, 2447, 2484 };
+static const uint16_t channels11g[] = { 2312, 2412, 2484 };
+
+static HAL_BOOL ar5312GetMacAddr(struct ath_hal *ah);
+
+static void
+ar5312AniSetup(struct ath_hal *ah)
+{
+ static const struct ar5212AniParams aniparams = {
+ .maxNoiseImmunityLevel = 4, /* levels 0..4 */
+ .totalSizeDesired = { -41, -41, -48, -48, -48 },
+ .coarseHigh = { -18, -18, -16, -14, -12 },
+ .coarseLow = { -56, -56, -60, -60, -60 },
+ .firpwr = { -72, -72, -75, -78, -80 },
+ .maxSpurImmunityLevel = 2,
+ .cycPwrThr1 = { 2, 4, 6 },
+ .maxFirstepLevel = 2, /* levels 0..2 */
+ .firstep = { 0, 4, 8 },
+ .ofdmTrigHigh = 500,
+ .ofdmTrigLow = 200,
+ .cckTrigHigh = 200,
+ .cckTrigLow = 100,
+ .rssiThrHigh = 40,
+ .rssiThrLow = 7,
+ .period = 100,
+ };
+ ar5212AniAttach(ah, &aniparams, &aniparams, AH_TRUE);
+}
+
+/*
+ * Attach for an AR3212 part.
+ */
+struct ath_hal *
+ar5312Attach(uint16_t devid, HAL_SOFTC sc,
+ HAL_BUS_TAG st, HAL_BUS_HANDLE sh, HAL_STATUS *status)
+{
+ struct ath_hal_5212 *ahp = AH_NULL;
+ struct ath_hal *ah;
+ uint32_t val;
+ uint16_t eeval;
+ HAL_STATUS ecode;
+ HAL_BOOL rfStatus;
+
+ HALDEBUG(AH_NULL, HAL_DEBUG_ATTACH, "%s: sc %p st %p sh %p\n",
+ __func__, sc, st, (void*) sh);
+
+ /* NB: memory is returned zero'd */
+ ahp = ath_hal_malloc(sizeof (struct ath_hal_5212));
+ if (ahp == AH_NULL) {
+ HALDEBUG(AH_NULL, HAL_DEBUG_ANY,
+ "%s: cannot allocate memory for state block\n", __func__);
+ *status = HAL_ENOMEM;
+ return AH_NULL;
+ }
+ ar5212InitState(ahp, devid, sc, st, sh, status);
+ ah = &ahp->ah_priv.h;
+
+ /* override 5212 methods for our needs */
+ ah->ah_reset = ar5312Reset;
+ ah->ah_phyDisable = ar5312PhyDisable;
+ ah->ah_setLedState = ar5312SetLedState;
+ ah->ah_detectCardPresent = ar5312DetectCardPresent;
+ ah->ah_setPowerMode = ar5312SetPowerMode;
+ ah->ah_getPowerMode = ar5312GetPowerMode;
+ ah->ah_isInterruptPending = ar5312IsInterruptPending;
+
+ ahp->ah_priv.ah_eepromRead = ar5312EepromRead;
+#ifdef AH_SUPPORT_WRITE_EEPROM
+ ahp->ah_priv.ah_eepromWrite = ar5312EepromWrite;
+#endif
+#if ( AH_SUPPORT_2316 || AH_SUPPORT_2317)
+ if (IS_5315(ah)) {
+ ahp->ah_priv.ah_gpioCfgOutput = ar5315GpioCfgOutput;
+ ahp->ah_priv.ah_gpioCfgInput = ar5315GpioCfgInput;
+ ahp->ah_priv.ah_gpioGet = ar5315GpioGet;
+ ahp->ah_priv.ah_gpioSet = ar5315GpioSet;
+ ahp->ah_priv.ah_gpioSetIntr = ar5315GpioSetIntr;
+ } else
+#endif
+ {
+ ahp->ah_priv.ah_gpioCfgOutput = ar5312GpioCfgOutput;
+ ahp->ah_priv.ah_gpioCfgInput = ar5312GpioCfgInput;
+ ahp->ah_priv.ah_gpioGet = ar5312GpioGet;
+ ahp->ah_priv.ah_gpioSet = ar5312GpioSet;
+ ahp->ah_priv.ah_gpioSetIntr = ar5312GpioSetIntr;
+ }
+
+ ah->ah_gpioCfgInput = ahp->ah_priv.ah_gpioCfgInput;
+ ah->ah_gpioCfgOutput = ahp->ah_priv.ah_gpioCfgOutput;
+ ah->ah_gpioGet = ahp->ah_priv.ah_gpioGet;
+ ah->ah_gpioSet = ahp->ah_priv.ah_gpioSet;
+ ah->ah_gpioSetIntr = ahp->ah_priv.ah_gpioSetIntr;
+
+ /* setup common ini data; rf backends handle remainder */
+ HAL_INI_INIT(&ahp->ah_ini_modes, ar5212Modes, 6);
+ HAL_INI_INIT(&ahp->ah_ini_common, ar5212Common, 6);
+
+ if (!ar5312ChipReset(ah, AH_NULL)) { /* reset chip */
+ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: chip reset failed\n", __func__);
+ ecode = HAL_EIO;
+ goto bad;
+ }
+
+#if ( AH_SUPPORT_2316 || AH_SUPPORT_2317)
+ if ((devid == AR5212_AR2315_REV6) ||
+ (devid == AR5212_AR2315_REV7) ||
+ (devid == AR5212_AR2317_REV1) ||
+ (devid == AR5212_AR2317_REV2) ) {
+ val = ((OS_REG_READ(ah, (AR5315_RSTIMER_BASE -((uint32_t) sh)) + AR5315_WREV)) >> AR5315_WREV_S)
+ & AR5315_WREV_ID;
+ AH_PRIVATE(ah)->ah_macVersion = val >> AR5315_WREV_ID_S;
+ AH_PRIVATE(ah)->ah_macRev = val & AR5315_WREV_REVISION;
+ HALDEBUG(ah, HAL_DEBUG_ATTACH,
+ "%s: Mac Chip Rev 0x%02x.%x\n" , __func__,
+ AH_PRIVATE(ah)->ah_macVersion, AH_PRIVATE(ah)->ah_macRev);
+ } else
+#endif
+ {
+ val = OS_REG_READ(ah, (AR5312_RSTIMER_BASE - ((uint32_t) sh)) + 0x0020);
+ val = OS_REG_READ(ah, (AR5312_RSTIMER_BASE - ((uint32_t) sh)) + 0x0080);
+ /* Read Revisions from Chips */
+ val = ((OS_REG_READ(ah, (AR5312_RSTIMER_BASE - ((uint32_t) sh)) + AR5312_WREV)) >> AR5312_WREV_S) & AR5312_WREV_ID;
+ AH_PRIVATE(ah)->ah_macVersion = val >> AR5312_WREV_ID_S;
+ AH_PRIVATE(ah)->ah_macRev = val & AR5312_WREV_REVISION;
+ }
+ /* XXX - THIS IS WRONG. NEEDS TO BE FIXED */
+ if (((AH_PRIVATE(ah)->ah_macVersion != AR_SREV_VERSION_VENICE &&
+ AH_PRIVATE(ah)->ah_macVersion != AR_SREV_VERSION_VENICE) ||
+ AH_PRIVATE(ah)->ah_macRev < AR_SREV_D2PLUS) &&
+ AH_PRIVATE(ah)->ah_macVersion != AR_SREV_VERSION_COBRA) {
+#ifdef AH_DEBUG
+ ath_hal_printf(ah, "%s: Mac Chip Rev 0x%02x.%x is not supported by "
+ "this driver\n", __func__,
+ AH_PRIVATE(ah)->ah_macVersion,
+ AH_PRIVATE(ah)->ah_macRev);
+#endif
+ ecode = HAL_ENOTSUPP;
+ goto bad;
+ }
+
+ AH_PRIVATE(ah)->ah_phyRev = OS_REG_READ(ah, AR_PHY_CHIP_ID);
+
+ if (!ar5212ChipTest(ah)) {
+ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: hardware self-test failed\n",
+ __func__);
+ ecode = HAL_ESELFTEST;
+ goto bad;
+ }
+
+ /*
+ * Set correct Baseband to analog shift
+ * setting to access analog chips.
+ */
+ OS_REG_WRITE(ah, AR_PHY(0), 0x00000007);
+
+ /* Read Radio Chip Rev Extract */
+ AH_PRIVATE(ah)->ah_analog5GhzRev = ar5212GetRadioRev(ah);
+#ifdef AH_DEBUG
+ /* NB: silently accept anything in release code per Atheros */
+ if ((AH_PRIVATE(ah)->ah_analog5GhzRev & 0xF0) !=
+ AR_RAD5111_SREV_MAJOR &&
+ (AH_PRIVATE(ah)->ah_analog5GhzRev & 0xF0) !=
+ AR_RAD5112_SREV_MAJOR &&
+ (AH_PRIVATE(ah)->ah_analog5GhzRev & 0xF0) !=
+ AR_RAD2111_SREV_MAJOR &&
+ (AH_PRIVATE(ah)->ah_analog5GhzRev & 0xF0) !=
+ AR_RAD2112_SREV_MAJOR) {
+ ath_hal_printf(ah, "%s: 5G Radio Chip Rev 0x%02X is not supported by "
+ "this driver\n", __func__,
+ AH_PRIVATE(ah)->ah_analog5GhzRev);
+ ecode = HAL_ENOTSUPP;
+ goto bad;
+ }
+#endif
+ if (IS_5112(ah) && !IS_RADX112_REV2(ah)) {
+#ifdef AH_DEBUG
+ ath_hal_printf(ah, "%s: 5112 Rev 1 is not supported by this "
+ "driver (analog5GhzRev 0x%x)\n", __func__,
+ AH_PRIVATE(ah)->ah_analog5GhzRev);
+#endif
+ ecode = HAL_ENOTSUPP;
+ goto bad;
+ }
+
+ ecode = ath_hal_legacyEepromAttach(ah);
+ if (ecode != HAL_OK) {
+ goto bad;
+ }
+
+ /*
+ * If Bmode and AR5212, verify 2.4 analog exists
+ */
+ if (ath_hal_eepromGetFlag(ah, AR_EEP_BMODE) &&
+ (AH_PRIVATE(ah)->ah_analog5GhzRev & 0xF0) == AR_RAD5111_SREV_MAJOR) {
+ /*
+ * Set correct Baseband to analog shift
+ * setting to access analog chips.
+ */
+ OS_REG_WRITE(ah, AR_PHY(0), 0x00004007);
+ OS_DELAY(2000);
+ AH_PRIVATE(ah)->ah_analog2GhzRev = ar5212GetRadioRev(ah);
+
+ /* Set baseband for 5GHz chip */
+ OS_REG_WRITE(ah, AR_PHY(0), 0x00000007);
+ OS_DELAY(2000);
+ if ((AH_PRIVATE(ah)->ah_analog2GhzRev & 0xF0) != AR_RAD2111_SREV_MAJOR) {
+#ifdef AH_DEBUG
+ ath_hal_printf(ah, "%s: 2G Radio Chip Rev 0x%02X is not "
+ "supported by this driver\n", __func__,
+ AH_PRIVATE(ah)->ah_analog2GhzRev);
+#endif
+ ecode = HAL_ENOTSUPP;
+ goto bad;
+ }
+ }
+
+ ecode = ath_hal_eepromGet(ah, AR_EEP_REGDMN_0, &eeval);
+ if (ecode != HAL_OK) {
+ HALDEBUG(ah, HAL_DEBUG_ANY,
+ "%s: cannot read regulatory domain from EEPROM\n",
+ __func__);
+ goto bad;
+ }
+ AH_PRIVATE(ah)->ah_currentRD = eeval;
+ /* XXX record serial number */
+
+ /* XXX other capabilities */
+ /*
+ * Got everything we need now to setup the capabilities.
+ */
+ if (!ar5212FillCapabilityInfo(ah)) {
+ HALDEBUG(ah, HAL_DEBUG_ANY,
+ "%s: failed ar5212FillCapabilityInfo\n", __func__);
+ ecode = HAL_EEREAD;
+ goto bad;
+ }
+
+ rfStatus = AH_FALSE;
+ if (IS_2317(ah))
+#if defined AH_SUPPORT_2317
+ rfStatus = ar2317RfAttach(ah, &ecode);
+#else
+ ecode = HAL_ENOTSUPP;
+#endif
+ else if (IS_2316(ah))
+#if defined AH_SUPPORT_2316
+ rfStatus = ar2316RfAttach(ah, &ecode);
+#else
+ ecode = HAL_ENOTSUPP;
+#endif
+ else if (IS_5112(ah))
+#ifdef AH_SUPPORT_5112
+ rfStatus = ar5112RfAttach(ah, &ecode);
+#else
+ ecode = HAL_ENOTSUPP;
+#endif
+ else
+#ifdef AH_SUPPORT_5111
+ rfStatus = ar5111RfAttach(ah, &ecode);
+#else
+ ecode = HAL_ENOTSUPP;
+#endif
+ if (!rfStatus) {
+ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: RF setup failed, status %u\n",
+ __func__, ecode);
+ goto bad;
+ }
+ /* arrange a direct call instead of thunking */
+ AH_PRIVATE(ah)->ah_getNfAdjust = ahp->ah_rfHal->getNfAdjust;
+
+ /* Initialize gain ladder thermal calibration structure */
+ ar5212InitializeGainValues(ah);
+
+ /* BSP specific call for MAC address of this WMAC device */
+ if (!ar5312GetMacAddr(ah)) {
+ ecode = HAL_EEBADMAC;
+ goto bad;
+ }
+
+ ar5312AniSetup(ah);
+ ar5212InitNfCalHistBuffer(ah);
+
+ /* XXX EAR stuff goes here */
+ return ah;
+
+bad:
+ if (ahp)
+ ar5212Detach((struct ath_hal *) ahp);
+ if (status)
+ *status = ecode;
+ return AH_NULL;
+}
+
+static HAL_BOOL
+ar5312GetMacAddr(struct ath_hal *ah)
+{
+ const struct ar531x_boarddata *board = AR5312_BOARDCONFIG(ah);
+ int wlanNum = AR5312_UNIT(ah);
+ const uint8_t *macAddr;
+
+ switch (wlanNum) {
+ case 0:
+ macAddr = board->wlan0Mac;
+ break;
+ case 1:
+ macAddr = board->wlan1Mac;
+ break;
+ default:
+#ifdef AH_DEBUG
+ ath_hal_printf(ah, "Invalid WLAN wmac index (%d)\n",
+ wlanNum);
+#endif
+ return AH_FALSE;
+ }
+ OS_MEMCPY(AH5212(ah)->ah_macaddr, macAddr, 6);
+ return AH_TRUE;
+}
+#endif /* AH_SUPPORT_AR5312 */
diff --git a/ar5312/ar5312_eeprom.c b/ar5312/ar5312_eeprom.c
new file mode 100644
index 000000000000..c14b8b2cdba9
--- /dev/null
+++ b/ar5312/ar5312_eeprom.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
+ * Copyright (c) 2002-2008 Atheros Communications, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $Id: ar5312_eeprom.c,v 1.4 2008/11/10 04:08:04 sam Exp $
+ */
+#include "opt_ah.h"
+
+
+#ifdef AH_SUPPORT_AR5312
+
+#include "ah.h"
+#include "ah_internal.h"
+
+#include "ar5312/ar5312.h"
+#include "ar5312/ar5312reg.h"
+#include "ar5212/ar5212desc.h"
+
+/*
+ * Read 16 bits of data from offset into *data
+ */
+HAL_BOOL
+ar5312EepromRead(struct ath_hal *ah, u_int off, uint16_t *dataIn)
+{
+ int i,offset;
+ const char *eepromAddr = AR5312_RADIOCONFIG(ah);
+ uint8_t *data;
+
+ data = (uint8_t *) dataIn;
+ for (i=0,offset=2*off; i<2; i++,offset++) {
+ data[i] = eepromAddr[offset];
+ }
+ return AH_TRUE;
+}
+#endif /* AH_SUPPORT_AR5312 */
diff --git a/ar5312/ar5312_gpio.c b/ar5312/ar5312_gpio.c
new file mode 100644
index 000000000000..02ed5651ddac
--- /dev/null
+++ b/ar5312/ar5312_gpio.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
+ * Copyright (c) 2002-2008 Atheros Communications, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $Id: ar5312_gpio.c,v 1.3 2008/11/10 04:08:04 sam Exp $
+ */
+#include "opt_ah.h"
+
+#ifdef AH_SUPPORT_AR5312
+
+#include "ah.h"
+#include "ah_internal.h"
+#include "ah_devid.h"
+
+#include "ar5312/ar5312.h"
+#include "ar5312/ar5312reg.h"
+#include "ar5312/ar5312phy.h"
+
+#define AR_NUM_GPIO 6 /* 6 GPIO pins */
+#define AR5312_GPIOD_MASK 0x0000002F /* GPIO data reg r/w mask */
+
+/*
+ * Configure GPIO Output lines
+ */
+HAL_BOOL
+ar5312GpioCfgOutput(struct ath_hal *ah, uint32_t gpio)
+{
+ uint32_t gpioOffset = (AR5312_GPIO_BASE - ((uint32_t) ah->ah_sh));
+
+ HALASSERT(gpio < AR_NUM_GPIO);
+
+ OS_REG_WRITE(ah, gpioOffset+AR5312_GPIOCR,
+ (OS_REG_READ(ah, gpioOffset+AR5312_GPIOCR) &~ AR_GPIOCR_CR_A(gpio))
+ | AR_GPIOCR_CR_A(gpio));
+
+ return AH_TRUE;
+}
+
+/*
+ * Configure GPIO Input lines
+ */
+HAL_BOOL
+ar5312GpioCfgInput(struct ath_hal *ah, uint32_t gpio)
+{
+ uint32_t gpioOffset = (AR5312_GPIO_BASE - ((uint32_t) ah->ah_sh));
+
+ HALASSERT(gpio < AR_NUM_GPIO);
+
+ OS_REG_WRITE(ah, gpioOffset+AR5312_GPIOCR,
+ (OS_REG_READ(ah, gpioOffset+AR5312_GPIOCR) &~ AR_GPIOCR_CR_A(gpio))
+ | AR_GPIOCR_CR_N(gpio));
+
+ return AH_TRUE;
+}
+
+/*
+ * Once configured for I/O - set output lines
+ */
+HAL_BOOL
+ar5312GpioSet(struct ath_hal *ah, uint32_t gpio, uint32_t val)
+{
+ uint32_t reg;
+ uint32_t gpioOffset = (AR5312_GPIO_BASE - ((uint32_t) ah->ah_sh));
+
+ HALASSERT(gpio < AR_NUM_GPIO);
+
+ reg = OS_REG_READ(ah, gpioOffset+AR5312_GPIODO);
+ reg &= ~(1 << gpio);
+ reg |= (val&1) << gpio;
+
+ OS_REG_WRITE(ah, gpioOffset+AR5312_GPIODO, reg);
+ return AH_TRUE;
+}
+
+/*
+ * Once configured for I/O - get input lines
+ */
+uint32_t
+ar5312GpioGet(struct ath_hal *ah, uint32_t gpio)
+{
+ uint32_t gpioOffset = (AR5312_GPIO_BASE - ((uint32_t) ah->ah_sh));
+
+ if (gpio < AR_NUM_GPIO) {
+ uint32_t val = OS_REG_READ(ah, gpioOffset+AR5312_GPIODI);
+ val = ((val & AR5312_GPIOD_MASK) >> gpio) & 0x1;
+ return val;
+ } else {
+ return 0xffffffff;
+ }
+}
+
+/*
+ * Set the GPIO Interrupt
+ */
+void
+ar5312GpioSetIntr(struct ath_hal *ah, u_int gpio, uint32_t ilevel)
+{
+ uint32_t val;
+ uint32_t gpioOffset = (AR5312_GPIO_BASE - ((uint32_t) ah->ah_sh));
+
+ /* XXX bounds check gpio */
+ val = OS_REG_READ(ah, gpioOffset+AR5312_GPIOCR);
+ val &= ~(AR_GPIOCR_CR_A(gpio) |
+ AR_GPIOCR_INT_MASK | AR_GPIOCR_INT_ENA | AR_GPIOCR_INT_SEL);
+ val |= AR_GPIOCR_CR_N(gpio) | AR_GPIOCR_INT(gpio) | AR_GPIOCR_INT_ENA;
+ if (ilevel)
+ val |= AR_GPIOCR_INT_SELH; /* interrupt on pin high */
+ else
+ val |= AR_GPIOCR_INT_SELL; /* interrupt on pin low */
+
+ /* Don't need to change anything for low level interrupt. */
+ OS_REG_WRITE(ah, gpioOffset+AR5312_GPIOCR, val);
+
+ /* Change the interrupt mask. */
+ (void) ar5212SetInterrupts(ah, AH5212(ah)->ah_maskReg | HAL_INT_GPIO);
+}
+
+
+#endif /* AH_SUPPORT_AR5312 */
diff --git a/ar5312/ar5312_interrupts.c b/ar5312/ar5312_interrupts.c
new file mode 100644
index 000000000000..c40191ed55be
--- /dev/null
+++ b/ar5312/ar5312_interrupts.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
+ * Copyright (c) 2002-2008 Atheros Communications, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $Id: ar5312_interrupts.c,v 1.2 2008/11/10 01:19:39 sam Exp $
+ */
+#include "opt_ah.h"
+
+#ifdef AH_SUPPORT_AR5312
+
+#include "ah.h"
+#include "ah_internal.h"
+
+#include "ar5312/ar5312.h"
+#include "ar5312/ar5312reg.h"
+#include "ar5312/ar5312phy.h"
+
+
+/*
+ * Checks to see if an interrupt is pending on our NIC
+ *
+ * Returns: TRUE if an interrupt is pending
+ * FALSE if not
+ */
+HAL_BOOL
+ar5312IsInterruptPending(struct ath_hal *ah)
+{
+ /*
+ * Some platforms trigger our ISR before applying power to
+ * the card. For the 5312, this is always true.
+ */
+
+ return(AH_TRUE);
+}
+#endif /* AH_SUPPORT_AR5312 */
diff --git a/ar5312/ar5312_misc.c b/ar5312/ar5312_misc.c
new file mode 100644
index 000000000000..12e173b84dc2
--- /dev/null
+++ b/ar5312/ar5312_misc.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
+ * Copyright (c) 2002-2008 Atheros Communications, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $Id: ar5312_misc.c,v 1.3 2008/11/10 04:08:04 sam Exp $
+ */
+#include "opt_ah.h"
+
+#ifdef AH_SUPPORT_AR5312
+
+#include "ah.h"
+#include "ah_internal.h"
+#include "ah_devid.h"
+
+#include "ar5312/ar5312.h"
+#include "ar5312/ar5312reg.h"
+#include "ar5312/ar5312phy.h"
+
+#define AR_NUM_GPIO 6 /* 6 GPIO pins */
+#define AR_GPIOD_MASK 0x0000002F /* GPIO data reg r/w mask */
+
+/*
+ * Change the LED blinking pattern to correspond to the connectivity
+ */
+void
+ar5312SetLedState(struct ath_hal *ah, HAL_LED_STATE state)
+{
+ uint32_t val;
+ uint32_t resOffset = (AR5312_RSTIMER_BASE - ((uint32_t) ah->ah_sh));
+ if(IS_2316(ah)) return; /* not yet */
+ val = SM(AR5312_PCICFG_LEDSEL0, AR5312_PCICFG_LEDSEL) |
+ SM(AR5312_PCICFG_LEDMOD0, AR5312_PCICFG_LEDMODE) |
+ 2;
+ OS_REG_WRITE(ah, resOffset+AR5312_PCICFG,
+ (OS_REG_READ(ah, AR5312_PCICFG) &~
+ (AR5312_PCICFG_LEDSEL | AR5312_PCICFG_LEDMODE |
+ AR5312_PCICFG_LEDSBR))
+ | val);
+}
+
+/*
+ * Detect if our wireless mac is present.
+ */
+HAL_BOOL
+ar5312DetectCardPresent(struct ath_hal *ah)
+{
+ uint16_t macVersion, macRev;
+ uint32_t v;
+
+ /*
+ * Read the Silicon Revision register and compare that
+ * to what we read at attach time. If the same, we say
+ * a card/device is present.
+ */
+#if (AH_SUPPORT_2316 || AH_SUPPORT_2317)
+ if(IS_5315(ah))
+ {
+ v = (OS_REG_READ(ah,
+ (AR5315_RSTIMER_BASE-((uint32_t) ah->ah_sh)) + AR5315_WREV))
+ & AR_SREV_ID;
+ macVersion = v >> AR_SREV_ID_S;
+ macRev = v & AR_SREV_REVISION;
+ return (AH_PRIVATE(ah)->ah_macVersion == macVersion &&
+ AH_PRIVATE(ah)->ah_macRev == macRev);
+ }
+ else
+#endif
+ {
+ v = (OS_REG_READ(ah,
+ (AR5312_RSTIMER_BASE-((uint32_t) ah->ah_sh)) + AR5312_WREV))
+ & AR_SREV_ID;
+ macVersion = v >> AR_SREV_ID_S;
+ macRev = v & AR_SREV_REVISION;
+ return (AH_PRIVATE(ah)->ah_macVersion == macVersion &&
+ AH_PRIVATE(ah)->ah_macRev == macRev);
+ }
+}
+
+/*
+ * If 32KHz clock exists, use it to lower power consumption during sleep
+ *
+ * Note: If clock is set to 32 KHz, delays on accessing certain
+ * baseband registers (27-31, 124-127) are required.
+ */
+void
+ar5312SetupClock(struct ath_hal *ah, HAL_OPMODE opmode)
+{
+ if (ar5212Use32KHzclock(ah, opmode)) {
+ /*
+ * Enable clocks to be turned OFF in BB during sleep
+ * and also enable turning OFF 32MHz/40MHz Refclk
+ * from A2.
+ */
+ OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_CONTROL, 0x1f);
+ OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_LIMIT, 0x0d);
+ OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0c);
+ OS_REG_WRITE(ah, AR_PHY_M_SLEEP, 0x03);
+ OS_REG_WRITE(ah, AR_PHY_REFCLKDLY, 0x05);
+ OS_REG_WRITE(ah, AR_PHY_REFCLKPD, (IS_5112(ah) || IS_2413(ah)) ? 0x14 : 0x18);
+
+ OS_REG_RMW_FIELD(ah, AR_USEC, AR_USEC_USEC32, 1);
+ OS_REG_WRITE(ah, AR_TSF_PARM, 61); /* 32 KHz TSF incr */
+
+ } else {
+ OS_REG_WRITE(ah, AR_TSF_PARM, 1); /* 32 MHz TSF incr */
+ OS_REG_RMW_FIELD(ah, AR_USEC, AR_USEC_USEC32,
+ (IS_5112(ah) || IS_2413(ah)) ? 39 : 31);
+
+ OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_CONTROL, 0x1f);
+ OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_LIMIT, 0x7f);
+
+ if (IS_5312_2_X(ah)) {
+ /* Set ADC/DAC select values */
+ OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x04);
+ } else {
+ OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0e);
+ OS_REG_WRITE(ah, AR_PHY_M_SLEEP, 0x0c);
+ OS_REG_WRITE(ah, AR_PHY_REFCLKDLY, 0xff);
+ OS_REG_WRITE(ah, AR_PHY_REFCLKPD, (IS_5112(ah) || IS_2413(ah)) ? 0x14 : 0x18);
+ }
+ }
+}
+
+/*
+ * If 32KHz clock exists, turn it off and turn back on the 32Mhz
+ */
+void
+ar5312RestoreClock(struct ath_hal *ah, HAL_OPMODE opmode)
+{
+ if (ar5212Use32KHzclock(ah, opmode)) {
+ /* # Set sleep clock rate back to 32 MHz. */
+ OS_REG_WRITE(ah, AR_TSF_PARM, 1); /* 32 MHz TSF incr */
+ OS_REG_RMW_FIELD(ah, AR_USEC, AR_USEC_USEC32,
+ (IS_5112(ah) || IS_2413(ah)) ? 39 : 31);
+
+ /*
+ * Restore BB registers to power-on defaults
+ */
+ OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_CONTROL, 0x1f);
+ OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_LIMIT, 0x7f);
+ if (IS_5312_2_X(ah)) {
+ /* Set ADC/DAC select values */
+ OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x04);
+ } else {
+ OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0e);
+ OS_REG_WRITE(ah, AR_PHY_M_SLEEP, 0x0c);
+ OS_REG_WRITE(ah, AR_PHY_REFCLKDLY, 0xff);
+ OS_REG_WRITE(ah, AR_PHY_REFCLKPD, (IS_5112(ah) || IS_2413(ah)) ? 0x14 : 0x18);
+ }
+ }
+}
+
+#endif /* AH_SUPPORT_AR5312 */
diff --git a/ar5312/ar5312_power.c b/ar5312/ar5312_power.c
new file mode 100644
index 000000000000..1cc4ed64a0c1
--- /dev/null
+++ b/ar5312/ar5312_power.c
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
+ * Copyright (c) 2002-2008 Atheros Communications, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $Id: ar5312_power.c,v 1.4 2008/11/10 04:08:04 sam Exp $
+ */
+#include "opt_ah.h"
+
+#ifdef AH_SUPPORT_AR5312
+
+#include "ah.h"
+#include "ah_internal.h"
+
+#include "ar5312/ar5312.h"
+#include "ar5312/ar5312reg.h"
+#include "ar5212/ar5212desc.h"
+
+/*
+ * Notify Power Mgt is enabled in self-generated frames.
+ * If requested, force chip awake.
+ *
+ * Returns A_OK if chip is awake or successfully forced awake.
+ *
+ * WARNING WARNING WARNING
+ * There is a problem with the chip where sometimes it will not wake up.
+ */
+static HAL_BOOL
+ar5312SetPowerModeAwake(struct ath_hal *ah, int setChip)
+{
+ /* No need for this at the moment for APs */
+ return AH_TRUE;
+}
+
+/*
+ * Notify Power Mgt is disabled in self-generated frames.
+ * If requested, force chip to sleep.
+ */
+static void
+ar5312SetPowerModeSleep(struct ath_hal *ah, int setChip)
+{
+ /* No need for this at the moment for APs */
+}
+
+/*
+ * Notify Power Management is enabled in self-generating
+ * fames. If request, set power mode of chip to
+ * auto/normal. Duration in units of 128us (1/8 TU).
+ */
+static void
+ar5312SetPowerModeNetworkSleep(struct ath_hal *ah, int setChip)
+{
+ /* No need for this at the moment for APs */
+}
+
+/*
+ * Set power mgt to the requested mode, and conditionally set
+ * the chip as well
+ */
+HAL_BOOL
+ar5312SetPowerMode(struct ath_hal *ah, HAL_POWER_MODE mode, int setChip)
+{
+ struct ath_hal_5212 *ahp = AH5212(ah);
+#ifdef AH_DEBUG
+ static const char* modes[] = {
+ "AWAKE",
+ "FULL-SLEEP",
+ "NETWORK SLEEP",
+ "UNDEFINED"
+ };
+#endif
+ int status = AH_TRUE;
+
+ HALDEBUG(ah, HAL_DEBUG_POWER, "%s: %s -> %s (%s)\n", __func__,
+ modes[ahp->ah_powerMode], modes[mode],
+ setChip ? "set chip " : "");
+ switch (mode) {
+ case HAL_PM_AWAKE:
+ status = ar5312SetPowerModeAwake(ah, setChip);
+ break;
+ case HAL_PM_FULL_SLEEP:
+ ar5312SetPowerModeSleep(ah, setChip);
+ break;
+ case HAL_PM_NETWORK_SLEEP:
+ ar5312SetPowerModeNetworkSleep(ah, setChip);
+ break;
+ default:
+ HALDEBUG(ah, HAL_DEBUG_POWER, "%s: unknown power mode %u\n",
+ __func__, mode);
+ return AH_FALSE;
+ }
+ ahp->ah_powerMode = mode;
+ return status;
+}
+
+/*
+ * Return the current sleep mode of the chip
+ */
+uint32_t
+ar5312GetPowerMode(struct ath_hal *ah)
+{
+ return HAL_PM_AWAKE;
+}
+
+/*
+ * Return the current sleep state of the chip
+ * TRUE = sleeping
+ */
+HAL_BOOL
+ar5312GetPowerStatus(struct ath_hal *ah)
+{
+ return 0; /* Currently, 5312 is never in sleep mode. */
+}
+#endif /* AH_SUPPORT_AR5312 */
diff --git a/ar5312/ar5312_reset.c b/ar5312/ar5312_reset.c
new file mode 100644
index 000000000000..84904318e095
--- /dev/null
+++ b/ar5312/ar5312_reset.c
@@ -0,0 +1,924 @@
+/*
+ * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
+ * Copyright (c) 2002-2008 Atheros Communications, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $Id: ar5312_reset.c,v 1.9 2008/11/10 04:08:04 sam Exp $
+ */
+#include "opt_ah.h"
+
+#ifdef AH_SUPPORT_AR5312
+
+#include "ah.h"
+#include "ah_internal.h"
+#include "ah_devid.h"
+
+#include "ar5312/ar5312.h"
+#include "ar5312/ar5312reg.h"
+#include "ar5312/ar5312phy.h"
+
+#include "ah_eeprom_v3.h"
+
+/* Additional Time delay to wait after activiting the Base band */
+#define BASE_ACTIVATE_DELAY 100 /* 100 usec */
+#define PLL_SETTLE_DELAY 300 /* 300 usec */
+
+extern int16_t ar5212GetNf(struct ath_hal *, HAL_CHANNEL_INTERNAL *);
+extern void ar5212SetRateDurationTable(struct ath_hal *, HAL_CHANNEL *);
+extern HAL_BOOL ar5212SetTransmitPower(struct ath_hal *ah,
+ HAL_CHANNEL_INTERNAL *chan, uint16_t *rfXpdGain);
+extern void ar5212SetDeltaSlope(struct ath_hal *, HAL_CHANNEL *);
+extern HAL_BOOL ar5212SetBoardValues(struct ath_hal *, HAL_CHANNEL_INTERNAL *);
+extern void ar5212SetIFSTiming(struct ath_hal *, HAL_CHANNEL *);
+extern HAL_BOOL ar5212IsSpurChannel(struct ath_hal *, HAL_CHANNEL *);
+extern HAL_BOOL ar5212ChannelChange(struct ath_hal *, HAL_CHANNEL *);
+
+static HAL_BOOL ar5312SetResetReg(struct ath_hal *, uint32_t resetMask);
+
+static int
+write_common(struct ath_hal *ah, const HAL_INI_ARRAY *ia,
+ HAL_BOOL bChannelChange, int writes)
+{
+#define IS_NO_RESET_TIMER_ADDR(x) \
+ ( (((x) >= AR_BEACON) && ((x) <= AR_CFP_DUR)) || \
+ (((x) >= AR_SLEEP1) && ((x) <= AR_SLEEP3)))
+#define V(r, c) (ia)->data[((r)*(ia)->cols) + (c)]
+ int i;
+
+ /* Write Common Array Parameters */
+ for (i = 0; i < ia->rows; i++) {
+ uint32_t reg = V(i, 0);
+ /* XXX timer/beacon setup registers? */
+ /* On channel change, don't reset the PCU registers */
+ if (!(bChannelChange && IS_NO_RESET_TIMER_ADDR(reg))) {
+ OS_REG_WRITE(ah, reg, V(i, 1));
+ DMA_YIELD(writes);
+ }
+ }
+ return writes;
+#undef IS_NO_RESET_TIMER_ADDR
+#undef V
+}
+
+/*
+ * Places the device in and out of reset and then places sane
+ * values in the registers based on EEPROM config, initialization
+ * vectors (as determined by the mode), and station configuration
+ *
+ * bChannelChange is used to preserve DMA/PCU registers across
+ * a HW Reset during channel change.
+ */
+HAL_BOOL
+ar5312Reset(struct ath_hal *ah, HAL_OPMODE opmode,
+ HAL_CHANNEL *chan, HAL_BOOL bChannelChange, HAL_STATUS *status)
+{
+#define N(a) (sizeof (a) / sizeof (a[0]))
+#define FAIL(_code) do { ecode = _code; goto bad; } while (0)
+ struct ath_hal_5212 *ahp = AH5212(ah);
+ HAL_CHANNEL_INTERNAL *ichan;
+ const HAL_EEPROM *ee;
+ uint32_t saveFrameSeqCount, saveDefAntenna;
+ uint32_t macStaId1, synthDelay, txFrm2TxDStart;
+ uint16_t rfXpdGain[MAX_NUM_PDGAINS_PER_CHANNEL];
+ int16_t cckOfdmPwrDelta = 0;
+ u_int modesIndex, freqIndex;
+ HAL_STATUS ecode;
+ int i, regWrites = 0;
+ uint32_t testReg;
+ uint32_t saveLedState = 0;
+
+ HALASSERT(ah->ah_magic == AR5212_MAGIC);
+ ee = AH_PRIVATE(ah)->ah_eeprom;
+
+ OS_MARK(ah, AH_MARK_RESET, bChannelChange);
+#define IS(_c,_f) (((_c)->channelFlags & _f) || 0)
+ if ((IS(chan, CHANNEL_2GHZ) ^ IS(chan, CHANNEL_5GHZ)) == 0) {
+ HALDEBUG(ah, HAL_DEBUG_ANY,
+ "%s: invalid channel %u/0x%x; not marked as 2GHz or 5GHz\n",
+ __func__, chan->channel, chan->channelFlags);
+ FAIL(HAL_EINVAL);
+ }
+ if ((IS(chan, CHANNEL_OFDM) ^ IS(chan, CHANNEL_CCK)) == 0) {
+ HALDEBUG(ah, HAL_DEBUG_ANY,
+ "%s: invalid channel %u/0x%x; not marked as OFDM or CCK\n",
+ __func__, chan->channel, chan->channelFlags);
+ FAIL(HAL_EINVAL);
+ }
+#undef IS
+ /*
+ * Map public channel to private.
+ */
+ ichan = ath_hal_checkchannel(ah, chan);
+ if (ichan == AH_NULL) {
+ HALDEBUG(ah, HAL_DEBUG_ANY,
+ "%s: invalid channel %u/0x%x; no mapping\n",
+ __func__, chan->channel, chan->channelFlags);
+ FAIL(HAL_EINVAL);
+ }
+ switch (opmode) {
+ case HAL_M_STA:
+ case HAL_M_IBSS:
+ case HAL_M_HOSTAP:
+ case HAL_M_MONITOR:
+ break;
+ default:
+ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid operating mode %u\n",
+ __func__, opmode);
+ FAIL(HAL_EINVAL);
+ break;
+ }
+ HALASSERT(ahp->ah_eeversion >= AR_EEPROM_VER3);
+
+ /* Preserve certain DMA hardware registers on a channel change */
+ if (bChannelChange) {
+ /*
+ * On Venice, the TSF is almost preserved across a reset;
+ * it requires the doubling writes to the RESET_TSF
+ * bit in the AR_BEACON register; it also has the quirk
+ * of the TSF going back in time on the station (station
+ * latches onto the last beacon's tsf during a reset 50%
+ * of the times); the latter is not a problem for adhoc
+ * stations since as long as the TSF is behind, it will
+ * get resynchronized on receiving the next beacon; the
+ * TSF going backwards in time could be a problem for the
+ * sleep operation (supported on infrastructure stations
+ * only) - the best and most general fix for this situation
+ * is to resynchronize the various sleep/beacon timers on
+ * the receipt of the next beacon i.e. when the TSF itself
+ * gets resynchronized to the AP's TSF - power save is
+ * needed to be temporarily disabled until that time
+ *
+ * Need to save the sequence number to restore it after
+ * the reset!
+ */
+ saveFrameSeqCount = OS_REG_READ(ah, AR_D_SEQNUM);
+ } else
+ saveFrameSeqCount = 0; /* NB: silence compiler */
+
+ /* If the channel change is across the same mode - perform a fast channel change */
+ if ((IS_2413(ah) || IS_5413(ah))) {
+ /*
+ * Channel change can only be used when:
+ * -channel change requested - so it's not the initial reset.
+ * -it's not a change to the current channel - often called when switching modes
+ * on a channel
+ * -the modes of the previous and requested channel are the same
+ */
+ if (bChannelChange &&
+ (AH_PRIVATE(ah)->ah_curchan != AH_NULL) &&
+ (chan->channel != AH_PRIVATE(ah)->ah_curchan->channel) &&
+ ((chan->channelFlags & CHANNEL_ALL) ==
+ (AH_PRIVATE(ah)->ah_curchan->channelFlags & CHANNEL_ALL))) {
+ if (ar5212ChannelChange(ah, chan))
+ /* If ChannelChange completed - skip the rest of reset */
+ return AH_TRUE;
+ }
+ }
+
+ /*
+ * Preserve the antenna on a channel change
+ */
+ saveDefAntenna = OS_REG_READ(ah, AR_DEF_ANTENNA);
+ if (saveDefAntenna == 0) /* XXX magic constants */
+ saveDefAntenna = 1;
+
+ /* Save hardware flag before chip reset clears the register */
+ macStaId1 = OS_REG_READ(ah, AR_STA_ID1) &
+ (AR_STA_ID1_BASE_RATE_11B | AR_STA_ID1_USE_DEFANT);
+
+ /* Save led state from pci config register */
+ if (!IS_5315(ah))
+ saveLedState = OS_REG_READ(ah, AR5312_PCICFG) &
+ (AR_PCICFG_LEDCTL | AR_PCICFG_LEDMODE | AR_PCICFG_LEDBLINK |
+ AR_PCICFG_LEDSLOW);
+
+ ar5312RestoreClock(ah, opmode); /* move to refclk operation */
+
+ /*
+ * Adjust gain parameters before reset if
+ * there's an outstanding gain updated.
+ */
+ (void) ar5212GetRfgain(ah);
+
+ if (!ar5312ChipReset(ah, chan)) {
+ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: chip reset failed\n", __func__);
+ FAIL(HAL_EIO);
+ }
+
+ /* Setup the indices for the next set of register array writes */
+ switch (chan->channelFlags & CHANNEL_ALL) {
+ case CHANNEL_A:
+ modesIndex = 1;
+ freqIndex = 1;
+ break;
+ case CHANNEL_T:
+ modesIndex = 2;
+ freqIndex = 1;
+ break;
+ case CHANNEL_B:
+ modesIndex = 3;
+ freqIndex = 2;
+ break;
+ case CHANNEL_PUREG:
+ modesIndex = 4;
+ freqIndex = 2;
+ break;
+ case CHANNEL_108G:
+ modesIndex = 5;
+ freqIndex = 2;
+ break;
+ default:
+ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel flags 0x%x\n",
+ __func__, chan->channelFlags);
+ FAIL(HAL_EINVAL);
+ }
+
+ OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__);
+
+ /* Set correct Baseband to analog shift setting to access analog chips. */
+ OS_REG_WRITE(ah, AR_PHY(0), 0x00000007);
+
+ regWrites = ath_hal_ini_write(ah, &ahp->ah_ini_modes, modesIndex, 0);
+ regWrites = write_common(ah, &ahp->ah_ini_common, bChannelChange,
+ regWrites);
+ ahp->ah_rfHal->writeRegs(ah, modesIndex, freqIndex, regWrites);
+
+ OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__);
+
+ if (IS_CHAN_HALF_RATE(chan) || IS_CHAN_QUARTER_RATE(chan)) {
+ ar5212SetIFSTiming(ah, chan);
+ }
+
+ /* Overwrite INI values for revised chipsets */
+ if (AH_PRIVATE(ah)->ah_phyRev >= AR_PHY_CHIP_ID_REV_2) {
+ /* ADC_CTL */
+ OS_REG_WRITE(ah, AR_PHY_ADC_CTL,
+ SM(2, AR_PHY_ADC_CTL_OFF_INBUFGAIN) |
+ SM(2, AR_PHY_ADC_CTL_ON_INBUFGAIN) |
+ AR_PHY_ADC_CTL_OFF_PWDDAC |
+ AR_PHY_ADC_CTL_OFF_PWDADC);
+
+ /* TX_PWR_ADJ */
+ if (chan->channel == 2484) {
+ cckOfdmPwrDelta = SCALE_OC_DELTA(ee->ee_cckOfdmPwrDelta - ee->ee_scaledCh14FilterCckDelta);
+ } else {
+ cckOfdmPwrDelta = SCALE_OC_DELTA(ee->ee_cckOfdmPwrDelta);
+ }
+
+ if (IS_CHAN_G(chan)) {
+ OS_REG_WRITE(ah, AR_PHY_TXPWRADJ,
+ SM((ee->ee_cckOfdmPwrDelta*-1), AR_PHY_TXPWRADJ_CCK_GAIN_DELTA) |
+ SM((cckOfdmPwrDelta*-1), AR_PHY_TXPWRADJ_CCK_PCDAC_INDEX));
+ } else {
+ OS_REG_WRITE(ah, AR_PHY_TXPWRADJ, 0);
+ }
+
+ /* Add barker RSSI thresh enable as disabled */
+ OS_REG_CLR_BIT(ah, AR_PHY_DAG_CTRLCCK,
+ AR_PHY_DAG_CTRLCCK_EN_RSSI_THR);
+ OS_REG_RMW_FIELD(ah, AR_PHY_DAG_CTRLCCK,
+ AR_PHY_DAG_CTRLCCK_RSSI_THR, 2);
+
+ /* Set the mute mask to the correct default */
+ OS_REG_WRITE(ah, AR_SEQ_MASK, 0x0000000F);
+ }
+
+ if (AH_PRIVATE(ah)->ah_phyRev >= AR_PHY_CHIP_ID_REV_3) {
+ /* Clear reg to alllow RX_CLEAR line debug */
+ OS_REG_WRITE(ah, AR_PHY_BLUETOOTH, 0);
+ }
+ if (AH_PRIVATE(ah)->ah_phyRev >= AR_PHY_CHIP_ID_REV_4) {
+#ifdef notyet
+ /* Enable burst prefetch for the data queues */
+ OS_REG_RMW_FIELD(ah, AR_D_FPCTL, ... );
+ /* Enable double-buffering */
+ OS_REG_CLR_BIT(ah, AR_TXCFG, AR_TXCFG_DBL_BUF_DIS);
+#endif
+ }
+
+ if (IS_5312_2_X(ah)) {
+ /* ADC_CTRL */
+ OS_REG_WRITE(ah, AR_PHY_SIGMA_DELTA,
+ SM(2, AR_PHY_SIGMA_DELTA_ADC_SEL) |
+ SM(4, AR_PHY_SIGMA_DELTA_FILT2) |
+ SM(0x16, AR_PHY_SIGMA_DELTA_FILT1) |
+ SM(0, AR_PHY_SIGMA_DELTA_ADC_CLIP));
+
+ if (IS_CHAN_2GHZ(chan))
+ OS_REG_RMW_FIELD(ah, AR_PHY_RXGAIN, AR_PHY_RXGAIN_TXRX_RF_MAX, 0x0F);
+
+ /* CCK Short parameter adjustment in 11B mode */
+ if (IS_CHAN_B(chan))
+ OS_REG_RMW_FIELD(ah, AR_PHY_CCK_RXCTRL4, AR_PHY_CCK_RXCTRL4_FREQ_EST_SHORT, 12);
+
+ /* Set ADC/DAC select values */
+ OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x04);
+
+ /* Increase 11A AGC Settling */
+ if ((chan->channelFlags & CHANNEL_ALL) == CHANNEL_A)
+ OS_REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_AGC, 32);
+ } else {
+ /* Set ADC/DAC select values */
+ OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0e);
+ }
+
+ /* Setup the transmit power values. */
+ if (!ar5212SetTransmitPower(ah, ichan, rfXpdGain)) {
+ HALDEBUG(ah, HAL_DEBUG_ANY,
+ "%s: error init'ing transmit power\n", __func__);
+ FAIL(HAL_EIO);
+ }
+
+ /* Write the analog registers */
+ if (!ahp->ah_rfHal->setRfRegs(ah, ichan, modesIndex, rfXpdGain)) {
+ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: ar5212SetRfRegs failed\n",
+ __func__);
+ FAIL(HAL_EIO);
+ }
+
+ /* Write delta slope for OFDM enabled modes (A, G, Turbo) */
+ if (IS_CHAN_OFDM(chan)) {
+ if ((IS_5413(ah) || (AH_PRIVATE(ah)->ah_eeversion >= AR_EEPROM_VER5_3)) &&
+ (!IS_CHAN_B(chan)))
+ ar5212SetSpurMitigation(ah, ichan);
+ ar5212SetDeltaSlope(ah, chan);
+ }
+
+ /* Setup board specific options for EEPROM version 3 */
+ if (!ar5212SetBoardValues(ah, ichan)) {
+ HALDEBUG(ah, HAL_DEBUG_ANY,
+ "%s: error setting board options\n", __func__);
+ FAIL(HAL_EIO);
+ }
+
+ /* Restore certain DMA hardware registers on a channel change */
+ if (bChannelChange)
+ OS_REG_WRITE(ah, AR_D_SEQNUM, saveFrameSeqCount);
+
+ OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__);
+
+ OS_REG_WRITE(ah, AR_STA_ID0, LE_READ_4(ahp->ah_macaddr));
+ OS_REG_WRITE(ah, AR_STA_ID1, LE_READ_2(ahp->ah_macaddr + 4)
+ | macStaId1
+ | AR_STA_ID1_RTS_USE_DEF
+ | ahp->ah_staId1Defaults
+ );
+ ar5212SetOperatingMode(ah, opmode);
+
+ /* Set Venice BSSID mask according to current state */
+ OS_REG_WRITE(ah, AR_BSSMSKL, LE_READ_4(ahp->ah_bssidmask));
+ OS_REG_WRITE(ah, AR_BSSMSKU, LE_READ_2(ahp->ah_bssidmask + 4));
+
+ /* Restore previous led state */
+ if (!IS_5315(ah))
+ OS_REG_WRITE(ah, AR5312_PCICFG, OS_REG_READ(ah, AR_PCICFG) | saveLedState);
+
+ /* Restore previous antenna */
+ OS_REG_WRITE(ah, AR_DEF_ANTENNA, saveDefAntenna);
+
+ /* then our BSSID */
+ OS_REG_WRITE(ah, AR_BSS_ID0, LE_READ_4(ahp->ah_bssid));
+ OS_REG_WRITE(ah, AR_BSS_ID1, LE_READ_2(ahp->ah_bssid + 4));
+
+ /* Restore bmiss rssi & count thresholds */
+ OS_REG_WRITE(ah, AR_RSSI_THR, ahp->ah_rssiThr);
+
+ OS_REG_WRITE(ah, AR_ISR, ~0); /* cleared on write */
+
+ if (!ar5212SetChannel(ah, ichan))
+ FAIL(HAL_EIO);
+
+ OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__);
+
+ ar5212SetCoverageClass(ah, AH_PRIVATE(ah)->ah_coverageClass, 1);
+
+ ar5212SetRateDurationTable(ah, chan);
+
+ /* Set Tx frame start to tx data start delay */
+ if (IS_5112(ah) && (IS_CHAN_HALF_RATE(AH_PRIVATE(ah)->ah_curchan) ||
+ IS_CHAN_QUARTER_RATE(AH_PRIVATE(ah)->ah_curchan))) {
+ txFrm2TxDStart =
+ (IS_CHAN_HALF_RATE(AH_PRIVATE(ah)->ah_curchan)) ?
+ TX_FRAME_D_START_HALF_RATE:
+ TX_FRAME_D_START_QUARTER_RATE;
+ OS_REG_RMW_FIELD(ah, AR_PHY_TX_CTL,
+ AR_PHY_TX_FRAME_TO_TX_DATA_START, txFrm2TxDStart);
+ }
+
+ /*
+ * Setup fast diversity.
+ * Fast diversity can be enabled or disabled via regadd.txt.
+ * Default is enabled.
+ * For reference,
+ * Disable: reg val
+ * 0x00009860 0x00009d18 (if 11a / 11g, else no change)
+ * 0x00009970 0x192bb514
+ * 0x0000a208 0xd03e4648
+ *
+ * Enable: 0x00009860 0x00009d10 (if 11a / 11g, else no change)
+ * 0x00009970 0x192fb514
+ * 0x0000a208 0xd03e6788
+ */
+
+ /* XXX Setup pre PHY ENABLE EAR additions */
+
+ /* flush SCAL reg */
+ if (IS_5312_2_X(ah)) {
+ (void) OS_REG_READ(ah, AR_PHY_SLEEP_SCAL);
+ }
+
+ /*
+ * Wait for the frequency synth to settle (synth goes on
+ * via AR_PHY_ACTIVE_EN). Read the phy active delay register.
+ * Value is in 100ns increments.
+ */
+ synthDelay = OS_REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY;
+ if (IS_CHAN_CCK(chan)) {
+ synthDelay = (4 * synthDelay) / 22;
+ } else {
+ synthDelay /= 10;
+ }
+
+ /* Activate the PHY (includes baseband activate and synthesizer on) */
+ OS_REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
+
+ /*
+ * There is an issue if the AP starts the calibration before
+ * the base band timeout completes. This could result in the
+ * rx_clear false triggering. As a workaround we add delay an
+ * extra BASE_ACTIVATE_DELAY usecs to ensure this condition
+ * does not happen.
+ */
+ if (IS_CHAN_HALF_RATE(AH_PRIVATE(ah)->ah_curchan)) {
+ OS_DELAY((synthDelay << 1) + BASE_ACTIVATE_DELAY);
+ } else if (IS_CHAN_QUARTER_RATE(AH_PRIVATE(ah)->ah_curchan)) {
+ OS_DELAY((synthDelay << 2) + BASE_ACTIVATE_DELAY);
+ } else {
+ OS_DELAY(synthDelay + BASE_ACTIVATE_DELAY);
+ }
+
+ /*
+ * The udelay method is not reliable with notebooks.
+ * Need to check to see if the baseband is ready
+ */
+ testReg = OS_REG_READ(ah, AR_PHY_TESTCTRL);
+ /* Selects the Tx hold */
+ OS_REG_WRITE(ah, AR_PHY_TESTCTRL, AR_PHY_TESTCTRL_TXHOLD);
+ i = 0;
+ while ((i++ < 20) &&
+ (OS_REG_READ(ah, 0x9c24) & 0x10)) /* test if baseband not ready */ OS_DELAY(200);
+ OS_REG_WRITE(ah, AR_PHY_TESTCTRL, testReg);
+
+ /* Calibrate the AGC and start a NF calculation */
+ OS_REG_WRITE(ah, AR_PHY_AGC_CONTROL,
+ OS_REG_READ(ah, AR_PHY_AGC_CONTROL)
+ | AR_PHY_AGC_CONTROL_CAL
+ | AR_PHY_AGC_CONTROL_NF);
+
+ if (!IS_CHAN_B(chan) && ahp->ah_bIQCalibration != IQ_CAL_DONE) {
+ /* Start IQ calibration w/ 2^(INIT_IQCAL_LOG_COUNT_MAX+1) samples */
+ OS_REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4,
+ AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX,
+ INIT_IQCAL_LOG_COUNT_MAX);
+ OS_REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4,
+ AR_PHY_TIMING_CTRL4_DO_IQCAL);
+ ahp->ah_bIQCalibration = IQ_CAL_RUNNING;
+ } else
+ ahp->ah_bIQCalibration = IQ_CAL_INACTIVE;
+
+ /* Setup compression registers */
+ ar5212SetCompRegs(ah);
+
+ /* Set 1:1 QCU to DCU mapping for all queues */
+ for (i = 0; i < AR_NUM_DCU; i++)
+ OS_REG_WRITE(ah, AR_DQCUMASK(i), 1 << i);
+
+ ahp->ah_intrTxqs = 0;
+ for (i = 0; i < AH_PRIVATE(ah)->ah_caps.halTotalQueues; i++)
+ ar5212ResetTxQueue(ah, i);
+
+ /*
+ * Setup interrupt handling. Note that ar5212ResetTxQueue
+ * manipulates the secondary IMR's as queues are enabled
+ * and disabled. This is done with RMW ops to insure the
+ * settings we make here are preserved.
+ */
+ ahp->ah_maskReg = AR_IMR_TXOK | AR_IMR_TXERR | AR_IMR_TXURN
+ | AR_IMR_RXOK | AR_IMR_RXERR | AR_IMR_RXORN
+ | AR_IMR_HIUERR
+ ;
+ if (opmode == HAL_M_HOSTAP)
+ ahp->ah_maskReg |= AR_IMR_MIB;
+ OS_REG_WRITE(ah, AR_IMR, ahp->ah_maskReg);
+ /* Enable bus errors that are OR'd to set the HIUERR bit */
+ OS_REG_WRITE(ah, AR_IMR_S2,
+ OS_REG_READ(ah, AR_IMR_S2)
+ | AR_IMR_S2_MCABT | AR_IMR_S2_SSERR | AR_IMR_S2_DPERR);
+
+ if (AH_PRIVATE(ah)->ah_rfkillEnabled)
+ ar5212EnableRfKill(ah);
+
+ if (!ath_hal_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0)) {
+ HALDEBUG(ah, HAL_DEBUG_ANY,
+ "%s: offset calibration failed to complete in 1ms;"
+ " noisy environment?\n", __func__);
+ }
+
+ /*
+ * Set clocks back to 32kHz if they had been using refClk, then
+ * use an external 32kHz crystal when sleeping, if one exists.
+ */
+ ar5312SetupClock(ah, opmode);
+
+ /*
+ * Writing to AR_BEACON will start timers. Hence it should
+ * be the last register to be written. Do not reset tsf, do
+ * not enable beacons at this point, but preserve other values
+ * like beaconInterval.
+ */
+ OS_REG_WRITE(ah, AR_BEACON,
+ (OS_REG_READ(ah, AR_BEACON) &~ (AR_BEACON_EN | AR_BEACON_RESET_TSF)));
+
+ /* XXX Setup post reset EAR additions */
+
+ /* QoS support */
+ if (AH_PRIVATE(ah)->ah_macVersion > AR_SREV_VERSION_VENICE ||
+ (AH_PRIVATE(ah)->ah_macVersion == AR_SREV_VERSION_VENICE &&
+ AH_PRIVATE(ah)->ah_macRev >= AR_SREV_GRIFFIN_LITE)) {
+ OS_REG_WRITE(ah, AR_QOS_CONTROL, 0x100aa); /* XXX magic */
+ OS_REG_WRITE(ah, AR_QOS_SELECT, 0x3210); /* XXX magic */
+ }
+
+ /* Turn on NOACK Support for QoS packets */
+ OS_REG_WRITE(ah, AR_NOACK,
+ SM(2, AR_NOACK_2BIT_VALUE) |
+ SM(5, AR_NOACK_BIT_OFFSET) |
+ SM(0, AR_NOACK_BYTE_OFFSET));
+
+ /* Restore user-specified settings */
+ if (ahp->ah_miscMode != 0)
+ OS_REG_WRITE(ah, AR_MISC_MODE, ahp->ah_miscMode);
+ if (ahp->ah_slottime != (u_int) -1)
+ ar5212SetSlotTime(ah, ahp->ah_slottime);
+ if (ahp->ah_acktimeout != (u_int) -1)
+ ar5212SetAckTimeout(ah, ahp->ah_acktimeout);
+ if (ahp->ah_ctstimeout != (u_int) -1)
+ ar5212SetCTSTimeout(ah, ahp->ah_ctstimeout);
+ if (ahp->ah_sifstime != (u_int) -1)
+ ar5212SetSifsTime(ah, ahp->ah_sifstime);
+ if (AH_PRIVATE(ah)->ah_diagreg != 0)
+ OS_REG_WRITE(ah, AR_DIAG_SW, AH_PRIVATE(ah)->ah_diagreg);
+
+ AH_PRIVATE(ah)->ah_opmode = opmode; /* record operating mode */
+
+ if (bChannelChange) {
+ if (!(ichan->privFlags & CHANNEL_DFS))
+ ichan->privFlags &= ~CHANNEL_INTERFERENCE;
+ chan->channelFlags = ichan->channelFlags;
+ chan->privFlags = ichan->privFlags;
+ }
+
+ HALDEBUG(ah, HAL_DEBUG_RESET, "%s: done\n", __func__);
+
+ OS_MARK(ah, AH_MARK_RESET_DONE, 0);
+
+ return AH_TRUE;
+bad:
+ OS_MARK(ah, AH_MARK_RESET_DONE, ecode);
+ if (*status)
+ *status = ecode;
+ return AH_FALSE;
+#undef FAIL
+#undef N
+}
+
+/*
+ * Places the PHY and Radio chips into reset. A full reset
+ * must be called to leave this state. The PCI/MAC/PCU are
+ * not placed into reset as we must receive interrupt to
+ * re-enable the hardware.
+ */
+HAL_BOOL
+ar5312PhyDisable(struct ath_hal *ah)
+{
+ return ar5312SetResetReg(ah, AR_RC_BB);
+}
+
+/*
+ * Places all of hardware into reset
+ */
+HAL_BOOL
+ar5312Disable(struct ath_hal *ah)
+{
+ if (!ar5312SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE))
+ return AH_FALSE;
+ /*
+ * Reset the HW - PCI must be reset after the rest of the
+ * device has been reset.
+ */
+ return ar5312SetResetReg(ah, AR_RC_MAC | AR_RC_BB);
+}
+
+/*
+ * Places the hardware into reset and then pulls it out of reset
+ *
+ * TODO: Only write the PLL if we're changing to or from CCK mode
+ *
+ * WARNING: The order of the PLL and mode registers must be correct.
+ */
+HAL_BOOL
+ar5312ChipReset(struct ath_hal *ah, HAL_CHANNEL *chan)
+{
+
+ OS_MARK(ah, AH_MARK_CHIPRESET, chan ? chan->channel : 0);
+
+ /*
+ * Reset the HW
+ */
+ if (!ar5312SetResetReg(ah, AR_RC_MAC | AR_RC_BB)) {
+ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: ar5312SetResetReg failed\n",
+ __func__);
+ return AH_FALSE;
+ }
+
+ /* Bring out of sleep mode (AGAIN) */
+ if (!ar5312SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE)) {
+ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: ar5312SetPowerMode failed\n",
+ __func__);
+ return AH_FALSE;
+ }
+
+ /* Clear warm reset register */
+ if (!ar5312SetResetReg(ah, 0)) {
+ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: ar5312SetResetReg failed\n",
+ __func__);
+ return AH_FALSE;
+ }
+
+ /*
+ * Perform warm reset before the mode/PLL/turbo registers
+ * are changed in order to deactivate the radio. Mode changes
+ * with an active radio can result in corrupted shifts to the
+ * radio device.
+ */
+
+ /*
+ * Set CCK and Turbo modes correctly.
+ */
+ if (chan != AH_NULL) { /* NB: can be null during attach */
+ uint32_t rfMode, phyPLL = 0, curPhyPLL, turbo;
+
+ if (IS_5112(ah) || IS_2413(ah)) {
+ rfMode = AR_PHY_MODE_AR5112;
+ if (!IS_5315(ah)) {
+ if (IS_CHAN_CCK(chan) || IS_CHAN_G(chan)) {
+ phyPLL = AR_PHY_PLL_CTL_44_5312;
+ } else {
+ if (IS_CHAN_HALF_RATE(chan)) {
+ phyPLL = AR_PHY_PLL_CTL_40_5312_HALF;
+ } else if (IS_CHAN_QUARTER_RATE(chan)) {
+ phyPLL = AR_PHY_PLL_CTL_40_5312_QUARTER;
+ } else {
+ phyPLL = AR_PHY_PLL_CTL_40_5312;
+ }
+ }
+ } else {
+ if (IS_CHAN_CCK(chan) || IS_CHAN_G(chan)) {
+ phyPLL = AR_PHY_PLL_CTL_44_5112;
+ } else {
+ if (IS_CHAN_HALF_RATE(chan)) {
+ phyPLL = AR_PHY_PLL_CTL_40_5112_HALF;
+ } else if (IS_CHAN_QUARTER_RATE(chan)) {
+ phyPLL = AR_PHY_PLL_CTL_40_5112_QUARTER;
+ } else {
+ phyPLL = AR_PHY_PLL_CTL_40_5112;
+ }
+ }
+ }
+ } else {
+ rfMode = AR_PHY_MODE_AR5111;
+ if (IS_CHAN_CCK(chan) || IS_CHAN_G(chan)) {
+ phyPLL = AR_PHY_PLL_CTL_44;
+ } else {
+ if (IS_CHAN_HALF_RATE(chan)) {
+ phyPLL = AR_PHY_PLL_CTL_40_HALF;
+ } else if (IS_CHAN_QUARTER_RATE(chan)) {
+ phyPLL = AR_PHY_PLL_CTL_40_QUARTER;
+ } else {
+ phyPLL = AR_PHY_PLL_CTL_40;
+ }
+ }
+ }
+ if (IS_CHAN_OFDM(chan) && (IS_CHAN_CCK(chan) ||
+ IS_CHAN_G(chan)))
+ rfMode |= AR_PHY_MODE_DYNAMIC;
+ else if (IS_CHAN_OFDM(chan))
+ rfMode |= AR_PHY_MODE_OFDM;
+ else
+ rfMode |= AR_PHY_MODE_CCK;
+ if (IS_CHAN_5GHZ(chan))
+ rfMode |= AR_PHY_MODE_RF5GHZ;
+ else
+ rfMode |= AR_PHY_MODE_RF2GHZ;
+ turbo = IS_CHAN_TURBO(chan) ?
+ (AR_PHY_FC_TURBO_MODE | AR_PHY_FC_TURBO_SHORT) : 0;
+ curPhyPLL = OS_REG_READ(ah, AR_PHY_PLL_CTL);
+ /*
+ * PLL, Mode, and Turbo values must be written in the correct
+ * order to ensure:
+ * - The PLL cannot be set to 44 unless the CCK or DYNAMIC
+ * mode bit is set
+ * - Turbo cannot be set at the same time as CCK or DYNAMIC
+ */
+ if (IS_CHAN_CCK(chan) || IS_CHAN_G(chan)) {
+ OS_REG_WRITE(ah, AR_PHY_TURBO, turbo);
+ OS_REG_WRITE(ah, AR_PHY_MODE, rfMode);
+ if (curPhyPLL != phyPLL) {
+ OS_REG_WRITE(ah, AR_PHY_PLL_CTL, phyPLL);
+ /* Wait for the PLL to settle */
+ OS_DELAY(PLL_SETTLE_DELAY);
+ }
+ } else {
+ if (curPhyPLL != phyPLL) {
+ OS_REG_WRITE(ah, AR_PHY_PLL_CTL, phyPLL);
+ /* Wait for the PLL to settle */
+ OS_DELAY(PLL_SETTLE_DELAY);
+ }
+ OS_REG_WRITE(ah, AR_PHY_TURBO, turbo);
+ OS_REG_WRITE(ah, AR_PHY_MODE, rfMode);
+ }
+ }
+ return AH_TRUE;
+}
+
+/*
+ * Write the given reset bit mask into the reset register
+ */
+static HAL_BOOL
+ar5312SetResetReg(struct ath_hal *ah, uint32_t resetMask)
+{
+ uint32_t mask = resetMask ? resetMask : ~0;
+ HAL_BOOL rt;
+
+ if ((rt = ar5312MacReset(ah, mask)) == AH_FALSE) {
+ return rt;
+ }
+ if ((resetMask & AR_RC_MAC) == 0) {
+ if (isBigEndian()) {
+ /*
+ * Set CFG, little-endian for register
+ * and descriptor accesses.
+ */
+#ifdef AH_NEED_DESC_SWAP
+ mask = INIT_CONFIG_STATUS | AR_CFG_SWRD;
+#else
+ mask = INIT_CONFIG_STATUS |
+ AR_CFG_SWTD | AR_CFG_SWRD;
+#endif
+ OS_REG_WRITE(ah, AR_CFG, mask);
+ } else
+ OS_REG_WRITE(ah, AR_CFG, INIT_CONFIG_STATUS);
+ }
+ return rt;
+}
+
+/*
+ * ar5312MacReset resets (and then un-resets) the specified
+ * wireless components.
+ * Note: The RCMask cannot be zero on entering from ar5312SetResetReg.
+ */
+
+HAL_BOOL
+ar5312MacReset(struct ath_hal *ah, unsigned int RCMask)
+{
+ int wlanNum = AR5312_UNIT(ah);
+ uint32_t resetBB, resetBits, regMask;
+ uint32_t reg;
+
+ if (RCMask == 0)
+ return(AH_FALSE);
+#if ( AH_SUPPORT_2316 || AH_SUPPORT_2317 )
+ if (IS_5315(ah)) {
+ switch(wlanNum) {
+ case 0:
+ resetBB = AR5315_RC_BB0_CRES | AR5315_RC_WBB0_RES;
+ /* Warm and cold reset bits for wbb */
+ resetBits = AR5315_RC_WMAC0_RES;
+ break;
+ case 1:
+ resetBB = AR5315_RC_BB1_CRES | AR5315_RC_WBB1_RES;
+ /* Warm and cold reset bits for wbb */
+ resetBits = AR5315_RC_WMAC1_RES;
+ break;
+ default:
+ return(AH_FALSE);
+ }
+ regMask = ~(resetBB | resetBits);
+
+ /* read before */
+ reg = OS_REG_READ(ah,
+ (AR5315_RSTIMER_BASE - ((uint32_t) ah->ah_sh) + AR5315_RESET));
+
+ if (RCMask == AR_RC_BB) {
+ /* Put baseband in reset */
+ reg |= resetBB; /* Cold and warm reset the baseband bits */
+ } else {
+ /*
+ * Reset the MAC and baseband. This is a bit different than
+ * the PCI version, but holding in reset causes problems.
+ */
+ reg &= regMask;
+ reg |= (resetBits | resetBB) ;
+ }
+ OS_REG_WRITE(ah,
+ (AR5315_RSTIMER_BASE - ((uint32_t) ah->ah_sh)+AR5315_RESET),
+ reg);
+ /* read after */
+ OS_REG_READ(ah,
+ (AR5315_RSTIMER_BASE - ((uint32_t) ah->ah_sh) +AR5315_RESET));
+ OS_DELAY(100);
+
+ /* Bring MAC and baseband out of reset */
+ reg &= regMask;
+ /* read before */
+ OS_REG_READ(ah,
+ (AR5315_RSTIMER_BASE- ((uint32_t) ah->ah_sh) +AR5315_RESET));
+ OS_REG_WRITE(ah,
+ (AR5315_RSTIMER_BASE - ((uint32_t) ah->ah_sh)+AR5315_RESET),
+ reg);
+ /* read after */
+ OS_REG_READ(ah,
+ (AR5315_RSTIMER_BASE- ((uint32_t) ah->ah_sh) +AR5315_RESET));
+
+
+ }
+ else
+#endif
+ {
+
+ switch(wlanNum) {
+ case 0:
+ resetBB = AR5312_RC_BB0_CRES | AR5312_RC_WBB0_RES;
+ /* Warm and cold reset bits for wbb */
+ resetBits = AR5312_RC_WMAC0_RES;
+ break;
+ case 1:
+ resetBB = AR5312_RC_BB1_CRES | AR5312_RC_WBB1_RES;
+ /* Warm and cold reset bits for wbb */
+ resetBits = AR5312_RC_WMAC1_RES;
+ break;
+ default:
+ return(AH_FALSE);
+ }
+ regMask = ~(resetBB | resetBits);
+
+ /* read before */
+ reg = OS_REG_READ(ah,
+ (AR5312_RSTIMER_BASE - ((uint32_t) ah->ah_sh) + AR5312_RESET));
+
+ if (RCMask == AR_RC_BB) {
+ /* Put baseband in reset */
+ reg |= resetBB; /* Cold and warm reset the baseband bits */
+ } else {
+ /*
+ * Reset the MAC and baseband. This is a bit different than
+ * the PCI version, but holding in reset causes problems.
+ */
+ reg &= regMask;
+ reg |= (resetBits | resetBB) ;
+ }
+ OS_REG_WRITE(ah,
+ (AR5312_RSTIMER_BASE - ((uint32_t) ah->ah_sh)+AR5312_RESET),
+ reg);
+ /* read after */
+ OS_REG_READ(ah,
+ (AR5312_RSTIMER_BASE - ((uint32_t) ah->ah_sh) +AR5312_RESET));
+ OS_DELAY(100);
+
+ /* Bring MAC and baseband out of reset */
+ reg &= regMask;
+ /* read before */
+ OS_REG_READ(ah,
+ (AR5312_RSTIMER_BASE- ((uint32_t) ah->ah_sh) +AR5312_RESET));
+ OS_REG_WRITE(ah,
+ (AR5312_RSTIMER_BASE - ((uint32_t) ah->ah_sh)+AR5312_RESET),
+ reg);
+ /* read after */
+ OS_REG_READ(ah,
+ (AR5312_RSTIMER_BASE- ((uint32_t) ah->ah_sh) +AR5312_RESET));
+ }
+ return(AH_TRUE);
+}
+
+#endif /* AH_SUPPORT_AR5312 */
diff --git a/ar5312/ar5312phy.h b/ar5312/ar5312phy.h
new file mode 100644
index 000000000000..9f867c7526b1
--- /dev/null
+++ b/ar5312/ar5312phy.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
+ * Copyright (c) 2002-2008 Atheros Communications, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $Id: ar5312phy.h,v 1.3 2008/10/06 18:32:50 sam Exp $
+ */
+#ifndef _DEV_ATH_AR5312PHY_H_
+#define _DEV_ATH_AR5312PHY_H_
+
+#include "ar5212/ar5212phy.h"
+
+/* PHY registers */
+
+#define AR_PHY_PLL_CTL_44_5312 0x14d6 /* 44 MHz for 11b, 11g */
+#define AR_PHY_PLL_CTL_40_5312 0x14d4 /* 40 MHz for 11a, turbos */
+#define AR_PHY_PLL_CTL_40_5312_HALF 0x15d4 /* 40 MHz for 11a, turbos (Half)*/
+#define AR_PHY_PLL_CTL_40_5312_QUARTER 0x16d4 /* 40 MHz for 11a, turbos (Quarter)*/
+
+#endif /* _DEV_ATH_AR5312PHY_H_ */
diff --git a/ar5312/ar5312reg.h b/ar5312/ar5312reg.h
new file mode 100644
index 000000000000..ff79cd3f08fe
--- /dev/null
+++ b/ar5312/ar5312reg.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
+ * Copyright (c) 2002-2008 Atheros Communications, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $Id: ar5312reg.h,v 1.4 2008/11/10 04:08:04 sam Exp $
+ */
+#ifndef _DEV_ATH_AR5312REG_H_
+#define _DEV_ATH_AR5312REG_H_
+
+#include "ar5212/ar5212reg.h"
+/*
+ * Definitions for the Atheros 5312 chipset.
+ */
+
+/* Register base addresses for modules which are not wmac modules */
+/* 531X has a fixed memory map */
+
+
+#define REG_WRITE(_reg,_val) *((volatile uint32_t *)(_reg)) = (_val);
+#define REG_READ(_reg) *((volatile uint32_t *)(_reg))
+/*
+ * PCI-MAC Configuration registers (AR2315+)
+ */
+#define AR5315_RSTIMER_BASE 0xb1000000 /* Address for reset/timer registers */
+#define AR5315_GPIO_BASE 0xb1000000 /* Address for GPIO registers */
+#define AR5315_WLAN0 0xb0000000
+
+#define AR5315_RESET 0x0004 /* Offset of reset control register */
+#define AR5315_SREV 0x0014 /* Offset of reset control register */
+#define AR5315_ENDIAN_CTL 0x000c /* offset of the endian control register */
+#define AR5315_CONFIG_WLAN 0x00000002 /* WLAN byteswap */
+
+#define AR5315_REV_MAJ 0x00f0
+#define AR5315_REV_MIN 0x000f
+
+#define AR5315_GPIODIR 0x0098 /* GPIO direction register */
+#define AR5315_GPIODO 0x0090 /* GPIO data output access reg */
+#define AR5315_GPIODI 0x0088 /* GPIO data input access reg*/
+#define AR5315_GPIOINT 0x00a0 /* GPIO interrupt control */
+
+#define AR5315_GPIODIR_M(x) (1 << (x)) /* mask for i/o */
+#define AR5315_GPIODIR_O(x) (1 << (x)) /* output */
+#define AR5315_GPIODIR_I(x) 0 /* input */
+
+#define AR5315_GPIOINT_S 0
+#define AR5315_GPIOINT_M 0x3F
+#define AR5315_GPIOINTLVL_S 6
+#define AR5315_GPIOINTLVL_M (3 << AR5315_GPIOINTLVL_S)
+
+#define AR5315_WREV (-0xefbfe0) /* Revision ID register offset */
+#define AR5315_WREV_S 0 /* Shift for WMAC revision info */
+#define AR5315_WREV_ID 0x000000FF /* Mask for WMAC revision info */
+#define AR5315_WREV_ID_S 4 /* Shift for WMAC Rev ID */
+#define AR5315_WREV_REVISION 0x0000000F /* Mask for WMAN Revsion version */
+
+#define AR5315_RC_BB0_CRES 0x00000002 /* Cold reset to WMAC0 & WBB0 */
+#define AR5315_RC_BB1_CRES 0x00000200 /* Cold reset to WMAC1 & WBB1n */
+#define AR5315_RC_WMAC0_RES 0x00000001 /* Warm reset to WMAC 0 */
+#define AR5315_RC_WBB0_RES 0x00000002 /* Warm reset to WBB0 */
+#define AR5315_RC_WMAC1_RES 0x00020000 /* Warm reset to WMAC1 */
+#define AR5315_RC_WBB1_RES 0x00040000 /* Warm reset to WBB */
+
+/*
+ * PCI-MAC Configuration registers (AR5312)
+ */
+#define AR5312_RSTIMER_BASE 0xbc003000 /* Address for reset/timer registers */
+#define AR5312_GPIO_BASE 0xbc002000 /* Address for GPIO registers */
+#define AR5312_WLAN0 0xb8000000
+#define AR5312_WLAN1 0xb8500000
+
+#define AR5312_RESET 0x0020 /* Offset of reset control register */
+#define AR5312_PCICFG 0x00B0 /* MAC/PCI configuration reg (LEDs) */
+
+#define AR5312_PCICFG_LEDMODE 0x0000001c /* LED Mode mask */
+#define AR5312_PCICFG_LEDMODE_S 2 /* LED Mode shift */
+#define AR5312_PCICFG_LEDMOD0 0 /* Blnk prop to Tx and filtered Rx */
+#define AR5312_PCICFG_LEDMOD1 1 /* Blnk prop to all Tx and Rx */
+#define AR5312_PCICFG_LEDMOD2 2 /* DEBG flash */
+#define AR5312_PCICFG_LEDMOD3 3 /* BLNK Randomly */
+
+#define AR5312_PCICFG_LEDSEL 0x000000e0 /* LED Throughput select */
+#define AR5312_PCICFG_LEDSEL_S 5
+#define AR5312_PCICFG_LEDSEL0 0 /* See blink rate table on p. 143 */
+#define AR5312_PCICFG_LEDSEL1 1 /* of AR5212 data sheet */
+#define AR5312_PCICFG_LEDSEL2 2
+#define AR5312_PCICFG_LEDSEL3 3
+#define AR5312_PCICFG_LEDSEL4 4
+#define AR5312_PCICFG_LEDSEL5 5
+#define AR5312_PCICFG_LEDSEL6 6
+#define AR5312_PCICFG_LEDSEL7 7
+
+#define AR5312_PCICFG_LEDSBR 0x00000100 /* Slow blink rate if no
+ activity. 0 = blink @ lowest
+ rate */
+
+#undef AR_GPIOCR
+#undef AR_GPIODO /* Undefine the 5212 defs */
+#undef AR_GPIODI
+
+#define AR5312_GPIOCR 0x0008 /* GPIO Control register */
+#define AR5312_GPIODO 0x0000 /* GPIO data output access reg */
+#define AR5312_GPIODI 0x0004 /* GPIO data input access reg*/
+/* NB: AR5312 uses AR5212 defines for GPIOCR definitions */
+
+#define AR5312_WREV 0x0090 /* Revision ID register offset */
+#define AR5312_WREV_S 8 /* Shift for WMAC revision info */
+#define AR5312_WREV_ID 0x000000FF /* Mask for WMAC revision info */
+#define AR5312_WREV_ID_S 4 /* Shift for WMAC Rev ID */
+#define AR5312_WREV_REVISION 0x0000000F /* Mask for WMAN Revsion version */
+
+#define AR5312_RC_BB0_CRES 0x00000004 /* Cold reset to WMAC0 & WBB0 */
+#define AR5312_RC_BB1_CRES 0x00000200 /* Cold reset to WMAC1 & WBB1n */
+#define AR5312_RC_WMAC0_RES 0x00002000 /* Warm reset to WMAC 0 */
+#define AR5312_RC_WBB0_RES 0x00004000 /* Warm reset to WBB0 */
+#define AR5312_RC_WMAC1_RES 0x00020000 /* Warm reset to WMAC1 */
+#define AR5312_RC_WBB1_RES 0x00040000 /* Warm reset to WBB */
+
+
+#define AR_RAD2112_SREV_MAJOR 0x40 /* 2112 Major Rev */
+
+enum AR5312PowerMode {
+ AR5312_POWER_MODE_FORCE_SLEEP = 0,
+ AR5312_POWER_MODE_FORCE_WAKE = 1,
+ AR5312_POWER_MODE_NORMAL = 2,
+};
+
+#endif /* _DEV_AR5312REG_H_ */
diff --git a/ar5312/ar5315_gpio.c b/ar5312/ar5315_gpio.c
new file mode 100644
index 000000000000..2aca97a2e2a6
--- /dev/null
+++ b/ar5312/ar5315_gpio.c
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
+ * Copyright (c) 2002-2008 Atheros Communications, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $Id: ar5315_gpio.c,v 1.3 2008/11/10 04:08:04 sam Exp $
+ */
+#include "opt_ah.h"
+
+#if (AH_SUPPORT_2316 || AH_SUPPORT_2317)
+
+#include "ah.h"
+#include "ah_internal.h"
+#include "ah_devid.h"
+
+#include "ar5312/ar5312.h"
+#include "ar5312/ar5312reg.h"
+#include "ar5312/ar5312phy.h"
+
+#define AR_NUM_GPIO 7 /* 6 GPIO pins */
+#define AR5315_GPIOD_MASK 0x0000007F /* GPIO data reg r/w mask */
+
+/*
+ * Configure GPIO Output lines
+ */
+HAL_BOOL
+ar5315GpioCfgOutput(struct ath_hal *ah, uint32_t gpio)
+{
+ uint32_t gpioOffset = (AR5315_GPIO_BASE - ((uint32_t) ah->ah_sh));
+
+ HALASSERT(gpio < AR_NUM_GPIO);
+
+ OS_REG_WRITE(ah, gpioOffset+AR5315_GPIODIR,
+ (OS_REG_READ(ah, gpioOffset+AR5315_GPIODIR) &~ AR5315_GPIODIR_M(gpio))
+ | AR5315_GPIODIR_O(gpio));
+
+ return AH_TRUE;
+}
+
+/*
+ * Configure GPIO Input lines
+ */
+HAL_BOOL
+ar5315GpioCfgInput(struct ath_hal *ah, uint32_t gpio)
+{
+ uint32_t gpioOffset = (AR5315_GPIO_BASE - ((uint32_t) ah->ah_sh));
+
+ HALASSERT(gpio < AR_NUM_GPIO);
+
+ OS_REG_WRITE(ah, gpioOffset+AR5315_GPIODIR,
+ (OS_REG_READ(ah, gpioOffset+AR5315_GPIODIR) &~ AR5315_GPIODIR_M(gpio))
+ | AR5315_GPIODIR_I(gpio));
+
+ return AH_TRUE;
+}
+
+/*
+ * Once configured for I/O - set output lines
+ */
+HAL_BOOL
+ar5315GpioSet(struct ath_hal *ah, uint32_t gpio, uint32_t val)
+{
+ uint32_t reg;
+ uint32_t gpioOffset = (AR5315_GPIO_BASE - ((uint32_t) ah->ah_sh));
+
+ HALASSERT(gpio < AR_NUM_GPIO);
+
+ reg = OS_REG_READ(ah, gpioOffset+AR5315_GPIODO);
+ reg &= ~(1 << gpio);
+ reg |= (val&1) << gpio;
+
+ OS_REG_WRITE(ah, gpioOffset+AR5315_GPIODO, reg);
+ return AH_TRUE;
+}
+
+/*
+ * Once configured for I/O - get input lines
+ */
+uint32_t
+ar5315GpioGet(struct ath_hal *ah, uint32_t gpio)
+{
+ uint32_t gpioOffset = (AR5315_GPIO_BASE - ((uint32_t) ah->ah_sh));
+
+ if (gpio < AR_NUM_GPIO) {
+ uint32_t val = OS_REG_READ(ah, gpioOffset+AR5315_GPIODI);
+ val = ((val & AR5315_GPIOD_MASK) >> gpio) & 0x1;
+ return val;
+ } else {
+ return 0xffffffff;
+ }
+}
+
+/*
+ * Set the GPIO Interrupt
+ */
+void
+ar5315GpioSetIntr(struct ath_hal *ah, u_int gpio, uint32_t ilevel)
+{
+ uint32_t val;
+ uint32_t gpioOffset = (AR5315_GPIO_BASE - ((uint32_t) ah->ah_sh));
+
+ /* XXX bounds check gpio */
+ val = OS_REG_READ(ah, gpioOffset+AR5315_GPIOINT);
+ val &= ~(AR5315_GPIOINT_M | AR5315_GPIOINTLVL_M);
+ val |= gpio << AR5315_GPIOINT_S;
+ if (ilevel)
+ val |= 2 << AR5315_GPIOINTLVL_S; /* interrupt on pin high */
+ else
+ val |= 1 << AR5315_GPIOINTLVL_S; /* interrupt on pin low */
+
+ /* Don't need to change anything for low level interrupt. */
+ OS_REG_WRITE(ah, gpioOffset+AR5315_GPIOINT, val);
+
+ /* Change the interrupt mask. */
+ (void) ar5212SetInterrupts(ah, AH5212(ah)->ah_maskReg | HAL_INT_GPIO);
+}
+
+
+#endif /* AH_SUPPORT_2316 || AH_SUPPORT_2317 */