1222301Sadrian/* 2222301Sadrian * Copyright (c) 2011 Adrian Chadd, Xenion Pty Ltd. 3222301Sadrian * 4222301Sadrian * Redistribution and use in source and binary forms, with or without 5222301Sadrian * modification, are permitted provided that the following conditions 6222301Sadrian * are met: 7222301Sadrian * 1. Redistributions of source code must retain the above copyright 8222301Sadrian * notice, this list of conditions and the following disclaimer. 9222301Sadrian * 2. Redistributions in binary form must reproduce the above copyright 10222301Sadrian * notice, this list of conditions and the following disclaimer in the 11222301Sadrian * documentation and/or other materials provided with the distribution. 12222301Sadrian * 13222301Sadrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14222301Sadrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15222301Sadrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16222301Sadrian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17222301Sadrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18222301Sadrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19222301Sadrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20222301Sadrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21222301Sadrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22222301Sadrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23222301Sadrian * SUCH DAMAGE. 24222301Sadrian * 25222301Sadrian * $FreeBSD$ 26222301Sadrian */ 27222301Sadrian#include "opt_ah.h" 28222301Sadrian 29222301Sadrian#include "ah.h" 30222301Sadrian#include "ah_internal.h" 31222301Sadrian 32222301Sadrian#include "ah_eeprom_v14.h" 33222308Sadrian#include "ah_eeprom_9287.h" 34222301Sadrian 35222301Sadrian#include "ar9002/ar9280.h" 36222301Sadrian#include "ar5416/ar5416reg.h" 37222301Sadrian#include "ar5416/ar5416phy.h" 38222301Sadrian#include "ar9002/ar9002phy.h" 39222301Sadrian 40222301Sadrian#include "ar9002/ar9287phy.h" 41222301Sadrian#include "ar9002/ar9287an.h" 42222301Sadrian#include "ar9002/ar9287_olc.h" 43222301Sadrian 44222301Sadrianvoid 45222301Sadrianar9287olcInit(struct ath_hal *ah) 46222301Sadrian{ 47222301Sadrian OS_REG_SET_BIT(ah, AR_PHY_TX_PWRCTRL9, 48222301Sadrian AR_PHY_TX_PWRCTRL9_RES_DC_REMOVAL); 49222301Sadrian OS_A_REG_RMW_FIELD(ah, AR9287_AN_TXPC0, 50222301Sadrian AR9287_AN_TXPC0_TXPCMODE, 51222301Sadrian AR9287_AN_TXPC0_TXPCMODE_TEMPSENSE); 52222301Sadrian OS_DELAY(100); 53222301Sadrian} 54222301Sadrian 55222301Sadrian/* 56222301Sadrian * Run temperature compensation calibration. 57222301Sadrian * 58222301Sadrian * The TX gain table is adjusted depending upon the difference 59222301Sadrian * between the initial PDADC value and the currently read 60222301Sadrian * average TX power sample value. This value is only valid if 61222301Sadrian * frames have been transmitted, so currPDADC will be 0 if 62222301Sadrian * no frames have yet been transmitted. 63222301Sadrian */ 64222301Sadrianvoid 65222301Sadrianar9287olcTemperatureCompensation(struct ath_hal *ah) 66222301Sadrian{ 67222301Sadrian uint32_t rddata; 68222301Sadrian int32_t delta, currPDADC, slope; 69222301Sadrian 70222301Sadrian rddata = OS_REG_READ(ah, AR_PHY_TX_PWRCTRL4); 71222301Sadrian currPDADC = MS(rddata, AR_PHY_TX_PWRCTRL_PD_AVG_OUT); 72222301Sadrian 73222314Sadrian HALDEBUG(ah, HAL_DEBUG_PERCAL, "%s: initPDADC=%d, currPDADC=%d\n", 74222314Sadrian __func__, AH5416(ah)->initPDADC, currPDADC); 75222314Sadrian 76222301Sadrian if (AH5416(ah)->initPDADC == 0 || currPDADC == 0) { 77222301Sadrian /* 78222301Sadrian * Zero value indicates that no frames have been transmitted 79222301Sadrian * yet, can't do temperature compensation until frames are 80222301Sadrian * transmitted. 81222301Sadrian */ 82222301Sadrian return; 83222301Sadrian } else { 84222301Sadrian int8_t val; 85222301Sadrian (void) (ath_hal_eepromGet(ah, AR_EEP_TEMPSENSE_SLOPE, &val)); 86222301Sadrian slope = val; 87222301Sadrian 88222301Sadrian if (slope == 0) { /* to avoid divide by zero case */ 89222301Sadrian delta = 0; 90222301Sadrian } else { 91222301Sadrian delta = ((currPDADC - AH5416(ah)->initPDADC)*4) / slope; 92222301Sadrian } 93222301Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_CH0_TX_PWRCTRL11, 94222301Sadrian AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, delta); 95222301Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_CH1_TX_PWRCTRL11, 96222301Sadrian AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, delta); 97222314Sadrian 98222314Sadrian HALDEBUG(ah, HAL_DEBUG_PERCAL, "%s: delta=%d\n", __func__, delta); 99222301Sadrian } 100222301Sadrian} 101222308Sadrian 102222308Sadrianvoid 103222308Sadrianar9287olcGetTxGainIndex(struct ath_hal *ah, 104222308Sadrian const struct ieee80211_channel *chan, 105222308Sadrian struct cal_data_op_loop_ar9287 *pRawDatasetOpLoop, 106222308Sadrian uint8_t *pCalChans, uint16_t availPiers, int8_t *pPwr) 107222308Sadrian{ 108222308Sadrian uint16_t idxL = 0, idxR = 0, numPiers; 109222308Sadrian HAL_BOOL match; 110222308Sadrian CHAN_CENTERS centers; 111222308Sadrian 112222308Sadrian ar5416GetChannelCenters(ah, chan, ¢ers); 113222308Sadrian 114222308Sadrian for (numPiers = 0; numPiers < availPiers; numPiers++) { 115222308Sadrian if (pCalChans[numPiers] == AR5416_BCHAN_UNUSED) 116222308Sadrian break; 117222308Sadrian } 118222308Sadrian 119222308Sadrian match = ath_ee_getLowerUpperIndex( 120222308Sadrian (uint8_t)FREQ2FBIN(centers.synth_center, IEEE80211_IS_CHAN_2GHZ(chan)), 121222308Sadrian pCalChans, numPiers, &idxL, &idxR); 122222308Sadrian 123222308Sadrian if (match) { 124222308Sadrian *pPwr = (int8_t) pRawDatasetOpLoop[idxL].pwrPdg[0][0]; 125222308Sadrian } else { 126222308Sadrian *pPwr = ((int8_t) pRawDatasetOpLoop[idxL].pwrPdg[0][0] + 127222308Sadrian (int8_t) pRawDatasetOpLoop[idxR].pwrPdg[0][0])/2; 128222308Sadrian } 129222308Sadrian} 130222308Sadrian 131222308Sadrianvoid 132222308Sadrianar9287olcSetPDADCs(struct ath_hal *ah, int32_t txPower, 133222308Sadrian uint16_t chain) 134222308Sadrian{ 135222308Sadrian uint32_t tmpVal; 136222308Sadrian uint32_t a; 137222308Sadrian 138222308Sadrian /* Enable OLPC for chain 0 */ 139222308Sadrian 140222308Sadrian tmpVal = OS_REG_READ(ah, 0xa270); 141222308Sadrian tmpVal = tmpVal & 0xFCFFFFFF; 142222308Sadrian tmpVal = tmpVal | (0x3 << 24); 143222308Sadrian OS_REG_WRITE(ah, 0xa270, tmpVal); 144222308Sadrian 145222308Sadrian /* Enable OLPC for chain 1 */ 146222308Sadrian 147222308Sadrian tmpVal = OS_REG_READ(ah, 0xb270); 148222308Sadrian tmpVal = tmpVal & 0xFCFFFFFF; 149222308Sadrian tmpVal = tmpVal | (0x3 << 24); 150222308Sadrian OS_REG_WRITE(ah, 0xb270, tmpVal); 151222308Sadrian 152222308Sadrian /* Write the OLPC ref power for chain 0 */ 153222308Sadrian 154222308Sadrian if (chain == 0) { 155222308Sadrian tmpVal = OS_REG_READ(ah, 0xa398); 156222308Sadrian tmpVal = tmpVal & 0xff00ffff; 157222308Sadrian a = (txPower)&0xff; 158222308Sadrian tmpVal = tmpVal | (a << 16); 159222308Sadrian OS_REG_WRITE(ah, 0xa398, tmpVal); 160222308Sadrian } 161222308Sadrian 162222308Sadrian /* Write the OLPC ref power for chain 1 */ 163222308Sadrian 164222308Sadrian if (chain == 1) { 165222308Sadrian tmpVal = OS_REG_READ(ah, 0xb398); 166222308Sadrian tmpVal = tmpVal & 0xff00ffff; 167222308Sadrian a = (txPower)&0xff; 168222308Sadrian tmpVal = tmpVal | (a << 16); 169222308Sadrian OS_REG_WRITE(ah, 0xb398, tmpVal); 170222308Sadrian } 171222308Sadrian} 172