Home | History | Annotate | Line # | Download | only in ar5416
      1 /*
      2  * Copyright (c) 2002-2008 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  * $Id: ar2133.c,v 1.1.1.1 2008/12/11 04:46:46 alc Exp $
     18  */
     19 #include "opt_ah.h"
     20 
     21 #include "ah.h"
     22 #include "ah_internal.h"
     23 
     24 #include "ah_eeprom_v14.h"
     25 
     26 #include "ar5416/ar5416.h"
     27 #include "ar5416/ar5416reg.h"
     28 #include "ar5416/ar5416phy.h"
     29 
     30 #define N(a)    (sizeof(a)/sizeof(a[0]))
     31 
     32 struct ar2133State {
     33 	RF_HAL_FUNCS	base;		/* public state, must be first */
     34 	uint16_t	pcdacTable[1];
     35 
     36 	uint32_t	*Bank0Data;
     37 	uint32_t	*Bank1Data;
     38 	uint32_t	*Bank2Data;
     39 	uint32_t	*Bank3Data;
     40 	uint32_t	*Bank6Data;
     41 	uint32_t	*Bank7Data;
     42 
     43 	/* NB: Bank*Data storage follows */
     44 };
     45 #define	AR2133(ah)	((struct ar2133State *) AH5212(ah)->ah_rfHal)
     46 
     47 #define	ar5416ModifyRfBuffer	ar5212ModifyRfBuffer	/*XXX*/
     48 
     49 extern  void ar5416ModifyRfBuffer(uint32_t *rfBuf, uint32_t reg32,
     50 	uint32_t numBits, uint32_t firstBit, uint32_t column);
     51 HAL_BOOL ar2133GetChipPowerLimits(struct ath_hal *ah, HAL_CHANNEL
     52 	*chans, uint32_t nchans);
     53 
     54 static HAL_BOOL ar2133GetChannelMaxMinPower(struct ath_hal *, HAL_CHANNEL *,
     55 		int16_t *maxPow,int16_t *minPow);
     56 int16_t ar2133GetNfAdjust(struct ath_hal *ah, const HAL_CHANNEL_INTERNAL *c);
     57 
     58 static void
     59 ar2133WriteRegs(struct ath_hal *ah, u_int modesIndex, u_int freqIndex,
     60 	int writes)
     61 {
     62 	(void) ath_hal_ini_write(ah, &AH5416(ah)->ah_ini_bb_rfgain,
     63 		freqIndex, writes);
     64 }
     65 
     66 /*
     67  * Take the MHz channel value and set the Channel value
     68  *
     69  * ASSUMES: Writes enabled to analog bus
     70  */
     71 static HAL_BOOL
     72 ar2133SetChannel(struct ath_hal *ah,  HAL_CHANNEL_INTERNAL *chan)
     73 {
     74 	uint32_t channelSel  = 0;
     75 	uint32_t bModeSynth  = 0;
     76 	uint32_t aModeRefSel = 0;
     77 	uint32_t reg32       = 0;
     78 	uint16_t freq;
     79 	CHAN_CENTERS centers;
     80 
     81 	OS_MARK(ah, AH_MARK_SETCHANNEL, chan->channel);
     82 
     83 	ar5416GetChannelCenters(ah,  chan, &centers);
     84 	freq = centers.synth_center;
     85 
     86 	if (freq < 4800) {
     87 		uint32_t txctl;
     88 
     89 		if (((freq - 2192) % 5) == 0) {
     90 			channelSel = ((freq - 672) * 2 - 3040)/10;
     91 			bModeSynth = 0;
     92 		} else if (((freq - 2224) % 5) == 0) {
     93 			channelSel = ((freq - 704) * 2 - 3040) / 10;
     94 			bModeSynth = 1;
     95 		} else {
     96 			HALDEBUG(ah, HAL_DEBUG_ANY,
     97 			    "%s: invalid channel %u MHz\n", __func__, freq);
     98 			return AH_FALSE;
     99 		}
    100 
    101 		channelSel = (channelSel << 2) & 0xff;
    102 		channelSel = ath_hal_reverseBits(channelSel, 8);
    103 
    104 		txctl = OS_REG_READ(ah, AR_PHY_CCK_TX_CTRL);
    105 		if (freq == 2484) {
    106 			/* Enable channel spreading for channel 14 */
    107 			OS_REG_WRITE(ah, AR_PHY_CCK_TX_CTRL,
    108 				txctl | AR_PHY_CCK_TX_CTRL_JAPAN);
    109 		} else {
    110 			OS_REG_WRITE(ah, AR_PHY_CCK_TX_CTRL,
    111  			txctl &~ AR_PHY_CCK_TX_CTRL_JAPAN);
    112 		}
    113 	} else if ((freq % 20) == 0 && freq >= 5120) {
    114 		channelSel = ath_hal_reverseBits(((freq - 4800) / 20 << 2), 8);
    115 		if (AR_SREV_SOWL_10_OR_LATER(ah))
    116 			aModeRefSel = ath_hal_reverseBits(3, 2);
    117 		else
    118 			aModeRefSel = ath_hal_reverseBits(1, 2);
    119 	} else if ((freq % 10) == 0) {
    120 		channelSel = ath_hal_reverseBits(((freq - 4800) / 10 << 1), 8);
    121 		if (AR_SREV_SOWL_10_OR_LATER(ah))
    122 			aModeRefSel = ath_hal_reverseBits(2, 2);
    123 		else
    124 			aModeRefSel = ath_hal_reverseBits(1, 2);
    125 	} else if ((freq % 5) == 0) {
    126 		channelSel = ath_hal_reverseBits((freq - 4800) / 5, 8);
    127 		aModeRefSel = ath_hal_reverseBits(1, 2);
    128 	} else {
    129 		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel %u MHz\n",
    130 		    __func__, freq);
    131 		return AH_FALSE;
    132 	}
    133 
    134 	reg32 = (channelSel << 8) | (aModeRefSel << 2) | (bModeSynth << 1) |
    135 		(1 << 5) | 0x1;
    136 
    137 	OS_REG_WRITE(ah, AR_PHY(0x37), reg32);
    138 
    139 	AH_PRIVATE(ah)->ah_curchan = chan;
    140 	return AH_TRUE;
    141 
    142 }
    143 
    144 /*
    145  * Return a reference to the requested RF Bank.
    146  */
    147 static uint32_t *
    148 ar2133GetRfBank(struct ath_hal *ah, int bank)
    149 {
    150 	struct ar2133State *priv = AR2133(ah);
    151 
    152 	HALASSERT(priv != AH_NULL);
    153 	switch (bank) {
    154 	case 1: return priv->Bank1Data;
    155 	case 2: return priv->Bank2Data;
    156 	case 3: return priv->Bank3Data;
    157 	case 6: return priv->Bank6Data;
    158 	case 7: return priv->Bank7Data;
    159 	}
    160 	HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unknown RF Bank %d requested\n",
    161 	    __func__, bank);
    162 	return AH_NULL;
    163 }
    164 
    165 /*
    166  * Reads EEPROM header info from device structure and programs
    167  * all rf registers
    168  *
    169  * REQUIRES: Access to the analog rf device
    170  */
    171 static HAL_BOOL
    172 ar2133SetRfRegs(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan,
    173                 uint16_t modesIndex, uint16_t *rfXpdGain)
    174 {
    175 	struct ar2133State *priv = AR2133(ah);
    176 	int writes;
    177 
    178 	HALASSERT(priv);
    179 
    180 	/* Setup Bank 0 Write */
    181 	ath_hal_ini_bank_setup(priv->Bank0Data, &AH5416(ah)->ah_ini_bank0, 1);
    182 
    183 	/* Setup Bank 1 Write */
    184 	ath_hal_ini_bank_setup(priv->Bank1Data, &AH5416(ah)->ah_ini_bank1, 1);
    185 
    186 	/* Setup Bank 2 Write */
    187 	ath_hal_ini_bank_setup(priv->Bank2Data, &AH5416(ah)->ah_ini_bank2, 1);
    188 
    189 	/* Setup Bank 3 Write */
    190 	ath_hal_ini_bank_setup(priv->Bank3Data, &AH5416(ah)->ah_ini_bank3, modesIndex);
    191 
    192 	/* Setup Bank 6 Write */
    193 	ath_hal_ini_bank_setup(priv->Bank6Data, &AH5416(ah)->ah_ini_bank6, modesIndex);
    194 
    195 	/* Only the 5 or 2 GHz OB/DB need to be set for a mode */
    196 	if (IS_CHAN_2GHZ(chan)) {
    197 		ar5416ModifyRfBuffer(priv->Bank6Data,
    198 		    ath_hal_eepromGet(ah, AR_EEP_OB_2, AH_NULL), 3, 197, 0);
    199 		ar5416ModifyRfBuffer(priv->Bank6Data,
    200 		    ath_hal_eepromGet(ah, AR_EEP_DB_2, AH_NULL), 3, 194, 0);
    201 	} else {
    202 		ar5416ModifyRfBuffer(priv->Bank6Data,
    203 		    ath_hal_eepromGet(ah, AR_EEP_OB_5, AH_NULL), 3, 203, 0);
    204 		ar5416ModifyRfBuffer(priv->Bank6Data,
    205 		    ath_hal_eepromGet(ah, AR_EEP_DB_5, AH_NULL), 3, 200, 0);
    206 	}
    207 	/* Setup Bank 7 Setup */
    208 	ath_hal_ini_bank_setup(priv->Bank7Data, &AH5416(ah)->ah_ini_bank7, 1);
    209 
    210 	/* Write Analog registers */
    211 	writes = ath_hal_ini_bank_write(ah, &AH5416(ah)->ah_ini_bank0,
    212 	    priv->Bank0Data, 0);
    213 	writes = ath_hal_ini_bank_write(ah, &AH5416(ah)->ah_ini_bank1,
    214 	    priv->Bank1Data, writes);
    215 	writes = ath_hal_ini_bank_write(ah, &AH5416(ah)->ah_ini_bank2,
    216 	    priv->Bank2Data, writes);
    217 	writes = ath_hal_ini_bank_write(ah, &AH5416(ah)->ah_ini_bank3,
    218 	    priv->Bank3Data, writes);
    219 	writes = ath_hal_ini_bank_write(ah, &AH5416(ah)->ah_ini_bank6,
    220 	    priv->Bank6Data, writes);
    221 	(void) ath_hal_ini_bank_write(ah, &AH5416(ah)->ah_ini_bank7,
    222 	    priv->Bank7Data, writes);
    223 
    224 	return AH_TRUE;
    225 #undef  RF_BANK_SETUP
    226 }
    227 
    228 /*
    229  * Read the transmit power levels from the structures taken from EEPROM
    230  * Interpolate read transmit power values for this channel
    231  * Organize the transmit power values into a table for writing into the hardware
    232  */
    233 
    234 static HAL_BOOL
    235 ar2133SetPowerTable(struct ath_hal *ah, int16_t *pPowerMin, int16_t *pPowerMax,
    236 	HAL_CHANNEL_INTERNAL *chan, uint16_t *rfXpdGain)
    237 {
    238 	return AH_TRUE;
    239 }
    240 
    241 #if 0
    242 static int16_t
    243 ar2133GetMinPower(struct ath_hal *ah, EXPN_DATA_PER_CHANNEL_5112 *data)
    244 {
    245     int i, minIndex;
    246     int16_t minGain,minPwr,minPcdac,retVal;
    247 
    248     /* Assume NUM_POINTS_XPD0 > 0 */
    249     minGain = data->pDataPerXPD[0].xpd_gain;
    250     for (minIndex=0,i=1; i<NUM_XPD_PER_CHANNEL; i++) {
    251         if (data->pDataPerXPD[i].xpd_gain < minGain) {
    252             minIndex = i;
    253             minGain = data->pDataPerXPD[i].xpd_gain;
    254         }
    255     }
    256     minPwr = data->pDataPerXPD[minIndex].pwr_t4[0];
    257     minPcdac = data->pDataPerXPD[minIndex].pcdac[0];
    258     for (i=1; i<NUM_POINTS_XPD0; i++) {
    259         if (data->pDataPerXPD[minIndex].pwr_t4[i] < minPwr) {
    260             minPwr = data->pDataPerXPD[minIndex].pwr_t4[i];
    261             minPcdac = data->pDataPerXPD[minIndex].pcdac[i];
    262         }
    263     }
    264     retVal = minPwr - (minPcdac*2);
    265     return(retVal);
    266 }
    267 #endif
    268 
    269 static HAL_BOOL
    270 ar2133GetChannelMaxMinPower(struct ath_hal *ah, HAL_CHANNEL *chan, int16_t *maxPow,
    271                 int16_t *minPow)
    272 {
    273 #if 0
    274     struct ath_hal_5212 *ahp = AH5212(ah);
    275     int numChannels=0,i,last;
    276     int totalD, totalF,totalMin;
    277     EXPN_DATA_PER_CHANNEL_5112 *data=AH_NULL;
    278     EEPROM_POWER_EXPN_5112 *powerArray=AH_NULL;
    279 
    280     *maxPow = 0;
    281     if (IS_CHAN_A(chan)) {
    282         powerArray = ahp->ah_modePowerArray5112;
    283         data = powerArray[headerInfo11A].pDataPerChannel;
    284         numChannels = powerArray[headerInfo11A].numChannels;
    285     } else if (IS_CHAN_G(chan) || IS_CHAN_108G(chan)) {
    286         /* XXX - is this correct? Should we also use the same power for turbo G? */
    287         powerArray = ahp->ah_modePowerArray5112;
    288         data = powerArray[headerInfo11G].pDataPerChannel;
    289         numChannels = powerArray[headerInfo11G].numChannels;
    290     } else if (IS_CHAN_B(chan)) {
    291         powerArray = ahp->ah_modePowerArray5112;
    292         data = powerArray[headerInfo11B].pDataPerChannel;
    293         numChannels = powerArray[headerInfo11B].numChannels;
    294     } else {
    295         return (AH_TRUE);
    296     }
    297     /* Make sure the channel is in the range of the TP values
    298      *  (freq piers)
    299      */
    300     if ((numChannels < 1) ||
    301         (chan->channel < data[0].channelValue) ||
    302         (chan->channel > data[numChannels-1].channelValue))
    303         return(AH_FALSE);
    304 
    305     /* Linearly interpolate the power value now */
    306     for (last=0,i=0;
    307          (i<numChannels) && (chan->channel > data[i].channelValue);
    308          last=i++);
    309     totalD = data[i].channelValue - data[last].channelValue;
    310     if (totalD > 0) {
    311         totalF = data[i].maxPower_t4 - data[last].maxPower_t4;
    312         *maxPow = (int8_t) ((totalF*(chan->channel-data[last].channelValue) + data[last].maxPower_t4*totalD)/totalD);
    313 
    314         totalMin = ar2133GetMinPower(ah,&data[i]) - ar2133GetMinPower(ah, &data[last]);
    315         *minPow = (int8_t) ((totalMin*(chan->channel-data[last].channelValue) + ar2133GetMinPower(ah, &data[last])*totalD)/totalD);
    316         return (AH_TRUE);
    317     } else {
    318         if (chan->channel == data[i].channelValue) {
    319             *maxPow = data[i].maxPower_t4;
    320             *minPow = ar2133GetMinPower(ah, &data[i]);
    321             return(AH_TRUE);
    322         } else
    323             return(AH_FALSE);
    324     }
    325 #else
    326     *maxPow = *minPow = 0;
    327 	return AH_FALSE;
    328 #endif
    329 }
    330 
    331 static void
    332 ar2133GetNoiseFloor(struct ath_hal *ah, int16_t nfarray[])
    333 {
    334 	struct ath_hal_5416 *ahp = AH5416(ah);
    335 	int16_t nf;
    336 
    337 	switch (ahp->ah_rx_chainmask) {
    338         case 0x7:
    339 		nf = MS(OS_REG_READ(ah, AR_PHY_CH2_CCA), AR_PHY_CH2_MINCCA_PWR);
    340 		if (nf & 0x100)
    341 			nf = 0 - ((nf ^ 0x1ff) + 1);
    342 		HALDEBUG(ah, HAL_DEBUG_NFCAL,
    343 		    "NF calibrated [ctl] [chain 2] is %d\n", nf);
    344 		nfarray[4] = nf;
    345 
    346 		nf = MS(OS_REG_READ(ah, AR_PHY_CH2_EXT_CCA), AR_PHY_CH2_EXT_MINCCA_PWR);
    347 		if (nf & 0x100)
    348 			nf = 0 - ((nf ^ 0x1ff) + 1);
    349 		HALDEBUG(ah, HAL_DEBUG_NFCAL,
    350 		    "NF calibrated [ext] [chain 2] is %d\n", nf);
    351 		nfarray[5] = nf;
    352 		/* fall thru... */
    353         case 0x3:
    354         case 0x5:
    355 		nf = MS(OS_REG_READ(ah, AR_PHY_CH1_CCA), AR_PHY_CH1_MINCCA_PWR);
    356 		if (nf & 0x100)
    357 			nf = 0 - ((nf ^ 0x1ff) + 1);
    358 		HALDEBUG(ah, HAL_DEBUG_NFCAL,
    359 		    "NF calibrated [ctl] [chain 1] is %d\n", nf);
    360 		nfarray[2] = nf;
    361 
    362 
    363 		nf = MS(OS_REG_READ(ah, AR_PHY_CH1_EXT_CCA), AR_PHY_CH1_EXT_MINCCA_PWR);
    364 		if (nf & 0x100)
    365 			nf = 0 - ((nf ^ 0x1ff) + 1);
    366 		HALDEBUG(ah, HAL_DEBUG_NFCAL,
    367 		    "NF calibrated [ext] [chain 1] is %d\n", nf);
    368 		nfarray[3] = nf;
    369 		/* fall thru... */
    370         case 0x1:
    371 		nf = MS(OS_REG_READ(ah, AR_PHY_CCA), AR_PHY_MINCCA_PWR);
    372 		if (nf & 0x100)
    373 			nf = 0 - ((nf ^ 0x1ff) + 1);
    374 		HALDEBUG(ah, HAL_DEBUG_NFCAL,
    375 		    "NF calibrated [ctl] [chain 0] is %d\n", nf);
    376 		nfarray[0] = nf;
    377 
    378 		nf = MS(OS_REG_READ(ah, AR_PHY_EXT_CCA), AR_PHY_EXT_MINCCA_PWR);
    379 		if (nf & 0x100)
    380 			nf = 0 - ((nf ^ 0x1ff) + 1);
    381 		HALDEBUG(ah, HAL_DEBUG_NFCAL,
    382 		    "NF calibrated [ext] [chain 0] is %d\n", nf);
    383 		nfarray[1] = nf;
    384 
    385 		break;
    386 	}
    387 }
    388 
    389 /*
    390  * Adjust NF based on statistical values for 5GHz frequencies.
    391  * Stubbed:Not used by Fowl
    392  */
    393 int16_t
    394 ar2133GetNfAdjust(struct ath_hal *ah, const HAL_CHANNEL_INTERNAL *c)
    395 {
    396 	return 0;
    397 }
    398 
    399 /*
    400  * Free memory for analog bank scratch buffers
    401  */
    402 static void
    403 ar2133RfDetach(struct ath_hal *ah)
    404 {
    405 	struct ath_hal_5212 *ahp = AH5212(ah);
    406 
    407 	HALASSERT(ahp->ah_rfHal != AH_NULL);
    408 	ath_hal_free(ahp->ah_rfHal);
    409 	ahp->ah_rfHal = AH_NULL;
    410 }
    411 
    412 /*
    413  * Allocate memory for analog bank scratch buffers
    414  * Scratch Buffer will be reinitialized every reset so no need to zero now
    415  */
    416 HAL_BOOL
    417 ar2133RfAttach(struct ath_hal *ah, HAL_STATUS *status)
    418 {
    419 	struct ath_hal_5212 *ahp = AH5212(ah);
    420 	struct ar2133State *priv;
    421 	uint32_t *bankData;
    422 
    423 	HALASSERT(ahp->ah_rfHal == AH_NULL);
    424 	priv = ath_hal_malloc(sizeof(struct ar2133State)
    425 	    + AH5416(ah)->ah_ini_bank0.rows * sizeof(uint32_t)
    426 	    + AH5416(ah)->ah_ini_bank1.rows * sizeof(uint32_t)
    427 	    + AH5416(ah)->ah_ini_bank2.rows * sizeof(uint32_t)
    428 	    + AH5416(ah)->ah_ini_bank3.rows * sizeof(uint32_t)
    429 	    + AH5416(ah)->ah_ini_bank6.rows * sizeof(uint32_t)
    430 	    + AH5416(ah)->ah_ini_bank7.rows * sizeof(uint32_t)
    431 	);
    432 	if (priv == AH_NULL) {
    433 		HALDEBUG(ah, HAL_DEBUG_ANY,
    434 		    "%s: cannot allocate private state\n", __func__);
    435 		*status = HAL_ENOMEM;		/* XXX */
    436 		return AH_FALSE;
    437 	}
    438 	priv->base.rfDetach		= ar2133RfDetach;
    439 	priv->base.writeRegs		= ar2133WriteRegs;
    440 	priv->base.getRfBank		= ar2133GetRfBank;
    441 	priv->base.setChannel		= ar2133SetChannel;
    442 	priv->base.setRfRegs		= ar2133SetRfRegs;
    443 	priv->base.setPowerTable	= ar2133SetPowerTable;
    444 	priv->base.getChannelMaxMinPower = ar2133GetChannelMaxMinPower;
    445 	priv->base.getNfAdjust		= ar2133GetNfAdjust;
    446 
    447 	bankData = (uint32_t *) &priv[1];
    448 	priv->Bank0Data = bankData, bankData += AH5416(ah)->ah_ini_bank0.rows;
    449 	priv->Bank1Data = bankData, bankData += AH5416(ah)->ah_ini_bank1.rows;
    450 	priv->Bank2Data = bankData, bankData += AH5416(ah)->ah_ini_bank2.rows;
    451 	priv->Bank3Data = bankData, bankData += AH5416(ah)->ah_ini_bank3.rows;
    452 	priv->Bank6Data = bankData, bankData += AH5416(ah)->ah_ini_bank6.rows;
    453 	priv->Bank7Data = bankData, bankData += AH5416(ah)->ah_ini_bank7.rows;
    454 
    455 	ahp->ah_pcdacTable = priv->pcdacTable;
    456 	ahp->ah_pcdacTableSize = sizeof(priv->pcdacTable);
    457 	ahp->ah_rfHal = &priv->base;
    458 	/*
    459 	 * Set noise floor adjust method; we arrange a
    460 	 * direct call instead of thunking.
    461 	 */
    462 	AH_PRIVATE(ah)->ah_getNfAdjust = priv->base.getNfAdjust;
    463 	AH_PRIVATE(ah)->ah_getNoiseFloor = ar2133GetNoiseFloor;
    464 
    465 	return AH_TRUE;
    466 }
    467