diff options
author | Sam Leffler <sam@FreeBSD.org> | 2008-11-28 00:03:41 +0000 |
---|---|---|
committer | Sam Leffler <sam@FreeBSD.org> | 2008-11-28 00:03:41 +0000 |
commit | d972528d489f39e17e1c43f85d857b9b5414619c (patch) | |
tree | 5e6c67d27f7d4af49cc3aea5c9d7528a2243d63d /ar5312 | |
download | src-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.h | 80 | ||||
-rw-r--r-- | ar5312/ar5312_attach.c | 363 | ||||
-rw-r--r-- | ar5312/ar5312_eeprom.c | 47 | ||||
-rw-r--r-- | ar5312/ar5312_gpio.c | 131 | ||||
-rw-r--r-- | ar5312/ar5312_interrupts.c | 47 | ||||
-rw-r--r-- | ar5312/ar5312_misc.c | 165 | ||||
-rw-r--r-- | ar5312/ar5312_power.c | 125 | ||||
-rw-r--r-- | ar5312/ar5312_reset.c | 924 | ||||
-rw-r--r-- | ar5312/ar5312phy.h | 31 | ||||
-rw-r--r-- | ar5312/ar5312reg.h | 139 | ||||
-rw-r--r-- | ar5312/ar5315_gpio.c | 130 |
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 */ |