Deleted Added
sdiff udiff text old ( 219218 ) new ( 219393 )
full compact
1/*
2 * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
3 * Copyright (c) 2002-2008 Atheros Communications, Inc.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 *
17 * $FreeBSD: head/sys/dev/ath/ath_hal/ar5416/ar5416_reset.c 219393 2011-03-08 06:59:59Z adrian $
18 */
19#include "opt_ah.h"
20
21#include "ah.h"
22#include "ah_internal.h"
23#include "ah_devid.h"
24
25#include "ah_eeprom_v14.h"

--- 30 unchanged lines hidden (view full) ---

56static HAL_BOOL ar5416SetReset(struct ath_hal *ah, int type);
57static void ar5416InitPLL(struct ath_hal *ah, const struct ieee80211_channel *chan);
58static HAL_BOOL ar5416SetPowerPerRateTable(struct ath_hal *ah,
59 struct ar5416eeprom *pEepData,
60 const struct ieee80211_channel *chan, int16_t *ratesArray,
61 uint16_t cfgCtl, uint16_t AntennaReduction,
62 uint16_t twiceMaxRegulatoryPower,
63 uint16_t powerLimit);
64static uint16_t ar5416GetMaxEdgePower(uint16_t freq,
65 CAL_CTL_EDGES *pRdEdgesPower, HAL_BOOL is2GHz);
66
67static int16_t interpolate(uint16_t target, uint16_t srcLeft,
68 uint16_t srcRight, int16_t targetLeft, int16_t targetRight);
69static void ar5416Set11nRegs(struct ath_hal *ah, const struct ieee80211_channel *chan);
70static HAL_BOOL ar5416FillVpdTable(uint8_t pwrMin, uint8_t pwrMax,
71 uint8_t *pPwrList, uint8_t *pVpdList,
72 uint16_t numIntercepts, uint8_t *pRetVpdList);
73
74/*
75 * Places the device in and out of reset and then places sane
76 * values in the registers based on EEPROM config, initialization
77 * vectors (as determined by the mode), and station configuration

--- 129 unchanged lines hidden (view full) ---

207 * with enabling the TX/RX radio chains.
208 */
209 ar5416UpdateChainMasks(ah, IEEE80211_IS_CHAN_HT(chan));
210 /*
211 * This routine swaps the analog chains - it should be done
212 * before any radio register twiddling is done.
213 */
214 ar5416InitChainMasks(ah);
215 AH5416(ah)->ah_olcInit(ah);
216
217 /* Setup the transmit power values. */
218 if (!ah->ah_setTxPower(ah, chan, rfXpdGain)) {
219 HALDEBUG(ah, HAL_DEBUG_ANY,
220 "%s: error init'ing transmit power\n", __func__);
221 FAIL(HAL_EIO);
222 }
223

--- 608 unchanged lines hidden (view full) ---

832 &ratesArray[0],cfgCtl,
833 twiceAntennaReduction,
834 twiceMaxRegulatoryPower, powerLimit)) {
835 HALDEBUG(ah, HAL_DEBUG_ANY,
836 "%s: unable to set tx power per rate table\n", __func__);
837 return AH_FALSE;
838 }
839
840 if (!AH5416(ah)->ah_setPowerCalTable(ah, pEepData, chan, &txPowerIndexOffset)) {
841 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unable to set power table\n",
842 __func__);
843 return AH_FALSE;
844 }
845
846 maxPower = AH_MAX(ratesArray[rate6mb], ratesArray[rateHt20_0]);
847
848 if (IEEE80211_IS_CHAN_2GHZ(chan)) {

--- 14 unchanged lines hidden (view full) ---

863 */
864 for (i = 0; i < N(ratesArray); i++) {
865 ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]);
866 if (ratesArray[i] > AR5416_MAX_RATE_POWER)
867 ratesArray[i] = AR5416_MAX_RATE_POWER;
868 }
869
870#ifdef AH_EEPROM_DUMP
871 /*
872 * Dump the rate array whilst it represents the intended dBm*2
873 * values versus what's being adjusted before being programmed
874 * in. Keep this in mind if you code up this function and enable
875 * this debugging; the values won't necessarily be what's being
876 * programmed into the hardware.
877 */
878 ar5416PrintPowerPerRate(ah, ratesArray);
879#endif
880
881 /*
882 * Merlin and later have a power offset, so subtract
883 * pwr_table_offset * 2 from each value. The default
884 * power offset is -5 dBm - ie, a register value of 0
885 * equates to a TX power of -5 dBm.
886 */
887 if (AR_SREV_MERLIN_20_OR_LATER(ah)) {
888 int8_t pwr_table_offset;
889
890 (void) ath_hal_eepromGet(ah, AR_EEP_PWR_TABLE_OFFSET,
891 &pwr_table_offset);
892 /* Underflow power gets clamped at raw value 0 */
893 /* Overflow power gets camped at AR5416_MAX_RATE_POWER */
894 for (i = 0; i < N(ratesArray); i++) {
895 /*
896 * + pwr_table_offset is in dBm
897 * + ratesArray is in 1/2 dBm
898 */
899 ratesArray[i] -= (pwr_table_offset * 2);
900 if (ratesArray[i] < 0)
901 ratesArray[i] = 0;
902 else if (ratesArray[i] > AR5416_MAX_RATE_POWER)
903 ratesArray[i] = AR5416_MAX_RATE_POWER;
904 }
905 }
906
907 /*
908 * Adjust rates for OLC where needed
909 *
910 * The following CCK rates need adjusting when doing 2.4ghz
911 * CCK transmission.
912 *
913 * + rate2s, rate2l, rate1l, rate11s, rate11l, rate5_5s, rate5_5l
914 * + rateExtCck, rateDupCck
915 *
916 * They're adjusted here regardless. The hardware then gets
917 * programmed as needed. 5GHz operation doesn't program in CCK
918 * rates for legacy mode but they seem to be initialised for
919 * HT40 regardless of channel type.
920 */
921 if (AR_SREV_MERLIN_20_OR_LATER(ah) &&
922 ath_hal_eepromGetFlag(ah, AR_EEP_OL_PWRCTRL)) {
923 int adj[] = {
924 rate2s, rate2l, rate1l, rate11s, rate11l,
925 rate5_5s, rate5_5l, rateExtCck, rateDupCck
926 };
927 int cck_ofdm_delta = 2;
928 int i;
929 for (i = 0; i < N(adj); i++) {
930 ratesArray[i] -= cck_ofdm_delta;
931 if (ratesArray[i] < 0)
932 ratesArray[i] = 0;
933 }
934 }
935
936 /* Write the OFDM power per rate set */
937 OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE1,
938 POW_SM(ratesArray[rate18mb], 24)
939 | POW_SM(ratesArray[rate12mb], 16)
940 | POW_SM(ratesArray[rate9mb], 8)
941 | POW_SM(ratesArray[rate6mb], 0)
942 );
943 OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE2,

--- 399 unchanged lines hidden (view full) ---

1343 OS_REG_WRITE(ah,
1344 AR_PHY_GAIN_2GHZ + regChainOffset,
1345 (OS_REG_READ(ah, AR_PHY_GAIN_2GHZ + regChainOffset) &
1346 ~AR_PHY_GAIN_2GHZ_RXTX_MARGIN) |
1347 SM(pModal->rxTxMarginCh[i], AR_PHY_GAIN_2GHZ_RXTX_MARGIN));
1348 }
1349}
1350
1351/*
1352 * Get the register chain offset for the given chain.
1353 *
1354 * Take into account the register chain swapping with AR5416 v2.0.
1355 *
1356 * XXX make sure that the reg chain swapping is only done for
1357 * XXX AR5416 v2.0 or greater, and not later chips?
1358 */
1359int
1360ar5416GetRegChainOffset(struct ath_hal *ah, int i)
1361{
1362 int regChainOffset;
1363
1364 if (AR_SREV_OWL_20_OR_LATER(ah) &&
1365 (AH5416(ah)->ah_rx_chainmask == 0x5 ||
1366 AH5416(ah)->ah_tx_chainmask == 0x5) && (i != 0)) {
1367 /* Regs are swapped from chain 2 to 1 for 5416 2_0 with
1368 * only chains 0 and 2 populated
1369 */
1370 regChainOffset = (i == 1) ? 0x2000 : 0x1000;
1371 } else {
1372 regChainOffset = i * 0x1000;
1373 }
1374
1375 return regChainOffset;
1376}
1377
1378/*
1379 * Read EEPROM header info and program the device for correct operation
1380 * given the channel value.
1381 */
1382HAL_BOOL
1383ar5416SetBoardValues(struct ath_hal *ah, const struct ieee80211_channel *chan)
1384{
1385 const HAL_EEPROM_v14 *ee = AH_PRIVATE(ah)->ah_eeprom;

--- 8 unchanged lines hidden (view full) ---

1394 /* NB: workaround for eeprom versions <= 14.2 */
1395 txRxAttenLocal = IEEE80211_IS_CHAN_2GHZ(chan) ? 23 : 44;
1396
1397 OS_REG_WRITE(ah, AR_PHY_SWITCH_COM, pModal->antCtrlCommon);
1398 for (i = 0; i < AR5416_MAX_CHAINS; i++) {
1399 if (AR_SREV_MERLIN(ah)) {
1400 if (i >= 2) break;
1401 }
1402 regChainOffset = ar5416GetRegChainOffset(ah, i);
1403
1404 OS_REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset, pModal->antCtrlChain[i]);
1405
1406 OS_REG_WRITE(ah, AR_PHY_TIMING_CTRL4 + regChainOffset,
1407 (OS_REG_READ(ah, AR_PHY_TIMING_CTRL4 + regChainOffset) &
1408 ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) |
1409 SM(pModal->iqCalICh[i], AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) |
1410 SM(pModal->iqCalQCh[i], AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF));

--- 508 unchanged lines hidden (view full) ---

1919
1920 for (i = 0; i < numRates; i++) {
1921 pNewPower->tPow2x[i] = (uint8_t)interpolate(freq, clo, chi,
1922 powInfo[lowIndex].tPow2x[i], powInfo[lowIndex + 1].tPow2x[i]);
1923 }
1924 }
1925}
1926
1927/*
1928 * Set the gain boundaries for the given radio chain.
1929 *
1930 * The gain boundaries tell the hardware at what point in the
1931 * PDADC array to "switch over" from one PD gain setting
1932 * to another. There's also a gain overlap between two
1933 * PDADC array gain curves where there's valid PD values
1934 * for 2 gain settings.
1935 *
1936 * The hardware uses the gain overlap and gain boundaries
1937 * to determine which gain curve to use for the given
1938 * target TX power.
1939 */
1940void
1941ar5416SetGainBoundariesClosedLoop(struct ath_hal *ah, int regChainOffset,
1942 uint16_t pdGainOverlap_t2, uint16_t gainBoundaries[])
1943{
1944 OS_REG_WRITE(ah, AR_PHY_TPCRG5 + regChainOffset,
1945 SM(pdGainOverlap_t2, AR_PHY_TPCRG5_PD_GAIN_OVERLAP) |
1946 SM(gainBoundaries[0], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1) |
1947 SM(gainBoundaries[1], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2) |
1948 SM(gainBoundaries[2], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3) |
1949 SM(gainBoundaries[3], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4));
1950}
1951
1952/*
1953 * Get the gain values and the number of gain levels given
1954 * in xpdMask.
1955 *
1956 * The EEPROM xpdMask determines which power detector gain
1957 * levels were used during calibration. Each of these mask
1958 * bits maps to a fixed gain level in hardware.
1959 */
1960uint16_t
1961ar5416GetXpdGainValues(struct ath_hal *ah, uint16_t xpdMask,
1962 uint16_t xpdGainValues[])
1963{
1964 int i;
1965 uint16_t numXpdGain = 0;
1966
1967 for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) {
1968 if ((xpdMask >> (AR5416_PD_GAINS_IN_MASK - i)) & 1) {
1969 if (numXpdGain >= AR5416_NUM_PD_GAINS) {
1970 HALASSERT(0);
1971 break;
1972 }
1973 xpdGainValues[numXpdGain] = (uint16_t)(AR5416_PD_GAINS_IN_MASK - i);
1974 numXpdGain++;
1975 }
1976 }
1977 return numXpdGain;
1978}
1979
1980/*
1981 * Write the detector gain and biases.
1982 *
1983 * There are four power detector gain levels. The xpdMask in the EEPROM
1984 * determines which power detector gain levels have TX power calibration
1985 * data associated with them. This function writes the number of
1986 * PD gain levels and their values into the hardware.
1987 *
1988 * This is valid for all TX chains - the calibration data itself however
1989 * will likely differ per-chain.
1990 */
1991void
1992ar5416WriteDetectorGainBiases(struct ath_hal *ah, uint16_t numXpdGain,
1993 uint16_t xpdGainValues[])
1994{
1995 OS_REG_WRITE(ah, AR_PHY_TPCRG1, (OS_REG_READ(ah, AR_PHY_TPCRG1) &
1996 ~(AR_PHY_TPCRG1_NUM_PD_GAIN | AR_PHY_TPCRG1_PD_GAIN_1 |
1997 AR_PHY_TPCRG1_PD_GAIN_2 | AR_PHY_TPCRG1_PD_GAIN_3)) |
1998 SM(numXpdGain - 1, AR_PHY_TPCRG1_NUM_PD_GAIN) |
1999 SM(xpdGainValues[0], AR_PHY_TPCRG1_PD_GAIN_1 ) |
2000 SM(xpdGainValues[1], AR_PHY_TPCRG1_PD_GAIN_2) |
2001 SM(xpdGainValues[2], AR_PHY_TPCRG1_PD_GAIN_3));
2002}
2003
2004/*
2005 * Write the PDADC array to the given chain offset.
2006 *
2007 * The 32 PDADC registers are written without any care about
2008 * their contents - so if various chips treat values as "special",
2009 * this routine will not care.
2010 */
2011void
2012ar5416WritePdadcValues(struct ath_hal *ah, int regChainOffset,
2013 uint8_t pdadcValues[])
2014{
2015 int regOffset;
2016 int j;
2017 int reg32;
2018
2019 regOffset = AR_PHY_BASE + (672 << 2) + regChainOffset;
2020
2021 for (j = 0; j < 32; j++) {
2022 reg32 = ((pdadcValues[4*j + 0] & 0xFF) << 0) |
2023 ((pdadcValues[4*j + 1] & 0xFF) << 8) |
2024 ((pdadcValues[4*j + 2] & 0xFF) << 16) |
2025 ((pdadcValues[4*j + 3] & 0xFF) << 24) ;
2026 OS_REG_WRITE(ah, regOffset, reg32);
2027#ifdef PDADC_DUMP
2028 ath_hal_printf(ah, "PDADC: Chain %d | PDADC %3d Value %3d |"
2029 " PDADC %3d Value %3d | PDADC %3d Value %3d | PDADC %3d"
2030 " Value %3d |\n",
2031 i,
2032 4*j, pdadcValues[4*j],
2033 4*j+1, pdadcValues[4*j + 1],
2034 4*j+2, pdadcValues[4*j + 2],
2035 4*j+3, pdadcValues[4*j + 3]);
2036#endif
2037 regOffset += 4;
2038 }
2039}
2040
2041/**************************************************************
2042 * ar5416SetPowerCalTable
2043 *
2044 * Pull the PDADC piers from cal data and interpolate them across the given
2045 * points as well as from the nearest pier(s) to get a power detector
2046 * linear voltage to power level table.
2047 */
2048HAL_BOOL
2049ar5416SetPowerCalTable(struct ath_hal *ah, struct ar5416eeprom *pEepData,
2050 const struct ieee80211_channel *chan, int16_t *pTxPowerIndexOffset)
2051{
2052 CAL_DATA_PER_FREQ *pRawDataset;
2053 uint8_t *pCalBChans = AH_NULL;
2054 uint16_t pdGainOverlap_t2;
2055 static uint8_t pdadcValues[AR5416_NUM_PDADC_VALUES];
2056 uint16_t gainBoundaries[AR5416_PD_GAINS_IN_MASK];
2057 uint16_t numPiers, i;
2058 int16_t tMinCalPower;
2059 uint16_t numXpdGain, xpdMask;
2060 uint16_t xpdGainValues[AR5416_NUM_PD_GAINS];
2061 uint32_t regChainOffset;
2062
2063 OS_MEMZERO(xpdGainValues, sizeof(xpdGainValues));
2064
2065 xpdMask = pEepData->modalHeader[IEEE80211_IS_CHAN_2GHZ(chan)].xpdGain;
2066
2067 if (IS_EEP_MINOR_V2(ah)) {
2068 pdGainOverlap_t2 = pEepData->modalHeader[IEEE80211_IS_CHAN_2GHZ(chan)].pdGainOverlap;
2069 } else {
2070 pdGainOverlap_t2 = (uint16_t)(MS(OS_REG_READ(ah, AR_PHY_TPCRG5), AR_PHY_TPCRG5_PD_GAIN_OVERLAP));
2071 }
2072
2073 if (IEEE80211_IS_CHAN_2GHZ(chan)) {
2074 pCalBChans = pEepData->calFreqPier2G;
2075 numPiers = AR5416_NUM_2G_CAL_PIERS;
2076 } else {
2077 pCalBChans = pEepData->calFreqPier5G;
2078 numPiers = AR5416_NUM_5G_CAL_PIERS;
2079 }
2080
2081 /* Calculate the value of xpdgains from the xpdGain Mask */
2082 numXpdGain = ar5416GetXpdGainValues(ah, xpdMask, xpdGainValues);
2083
2084 /* Write the detector gain biases and their number */
2085 ar5416WriteDetectorGainBiases(ah, numXpdGain, xpdGainValues);
2086
2087 for (i = 0; i < AR5416_MAX_CHAINS; i++) {
2088 regChainOffset = ar5416GetRegChainOffset(ah, i);
2089
2090 if (pEepData->baseEepHeader.txMask & (1 << i)) {
2091 if (IEEE80211_IS_CHAN_2GHZ(chan)) {
2092 pRawDataset = pEepData->calPierData2G[i];
2093 } else {
2094 pRawDataset = pEepData->calPierData5G[i];
2095 }
2096
2097 /* Fetch the gain boundaries and the PDADC values */
2098 ar5416GetGainBoundariesAndPdadcs(ah, chan, pRawDataset,
2099 pCalBChans, numPiers,
2100 pdGainOverlap_t2,
2101 &tMinCalPower, gainBoundaries,
2102 pdadcValues, numXpdGain);
2103
2104 if ((i == 0) || AR_SREV_OWL_20_OR_LATER(ah)) {
2105 ar5416SetGainBoundariesClosedLoop(ah, regChainOffset,
2106 pdGainOverlap_t2, gainBoundaries);
2107 }
2108
2109 /* Write the power values into the baseband power table */
2110 ar5416WritePdadcValues(ah, regChainOffset, pdadcValues);
2111 }
2112 }
2113 *pTxPowerIndexOffset = 0;
2114
2115 return AH_TRUE;
2116}
2117
2118/**************************************************************
2119 * ar5416GetGainBoundariesAndPdadcs
2120 *
2121 * Uses the data points read from EEPROM to reconstruct the pdadc power table
2122 * Called by ar5416SetPowerCalTable only.
2123 */
2124void
2125ar5416GetGainBoundariesAndPdadcs(struct ath_hal *ah,
2126 const struct ieee80211_channel *chan,
2127 CAL_DATA_PER_FREQ *pRawDataSet,
2128 uint8_t * bChans, uint16_t availPiers,
2129 uint16_t tPdGainOverlap, int16_t *pMinCalPower, uint16_t * pPdGainBoundaries,
2130 uint8_t * pPDADCValues, uint16_t numXpdGains)
2131{
2132

--- 383 unchanged lines hidden ---