1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2011 Adrian Chadd, Xenion Pty Ltd. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 * $FreeBSD$ 28 */ 29 #include "opt_ah.h" 30 31 #include "ah.h" 32 #include "ah_internal.h" 33 34 #include "ah_eeprom_v14.h" 35 #include "ah_eeprom_9287.h" 36 37 #include "ar9002/ar9280.h" 38 #include "ar5416/ar5416reg.h" 39 #include "ar5416/ar5416phy.h" 40 #include "ar9002/ar9002phy.h" 41 42 #include "ar9002/ar9287phy.h" 43 #include "ar9002/ar9287an.h" 44 #include "ar9002/ar9287_olc.h" 45 46 void 47 ar9287olcInit(struct ath_hal *ah) 48 { 49 OS_REG_SET_BIT(ah, AR_PHY_TX_PWRCTRL9, 50 AR_PHY_TX_PWRCTRL9_RES_DC_REMOVAL); 51 OS_A_REG_RMW_FIELD(ah, AR9287_AN_TXPC0, 52 AR9287_AN_TXPC0_TXPCMODE, 53 AR9287_AN_TXPC0_TXPCMODE_TEMPSENSE); 54 OS_DELAY(100); 55 } 56 57 /* 58 * Run temperature compensation calibration. 59 * 60 * The TX gain table is adjusted depending upon the difference 61 * between the initial PDADC value and the currently read 62 * average TX power sample value. This value is only valid if 63 * frames have been transmitted, so currPDADC will be 0 if 64 * no frames have yet been transmitted. 65 */ 66 void 67 ar9287olcTemperatureCompensation(struct ath_hal *ah) 68 { 69 uint32_t rddata; 70 int32_t delta, currPDADC, slope; 71 72 rddata = OS_REG_READ(ah, AR_PHY_TX_PWRCTRL4); 73 currPDADC = MS(rddata, AR_PHY_TX_PWRCTRL_PD_AVG_OUT); 74 75 HALDEBUG(ah, HAL_DEBUG_PERCAL, "%s: initPDADC=%d, currPDADC=%d\n", 76 __func__, AH5416(ah)->initPDADC, currPDADC); 77 78 if (AH5416(ah)->initPDADC == 0 || currPDADC == 0) { 79 /* 80 * Zero value indicates that no frames have been transmitted 81 * yet, can't do temperature compensation until frames are 82 * transmitted. 83 */ 84 return; 85 } else { 86 int8_t val; 87 (void) (ath_hal_eepromGet(ah, AR_EEP_TEMPSENSE_SLOPE, &val)); 88 slope = val; 89 90 if (slope == 0) { /* to avoid divide by zero case */ 91 delta = 0; 92 } else { 93 delta = ((currPDADC - AH5416(ah)->initPDADC)*4) / slope; 94 } 95 OS_REG_RMW_FIELD(ah, AR_PHY_CH0_TX_PWRCTRL11, 96 AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, delta); 97 OS_REG_RMW_FIELD(ah, AR_PHY_CH1_TX_PWRCTRL11, 98 AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, delta); 99 100 HALDEBUG(ah, HAL_DEBUG_PERCAL, "%s: delta=%d\n", __func__, delta); 101 } 102 } 103 104 void 105 ar9287olcGetTxGainIndex(struct ath_hal *ah, 106 const struct ieee80211_channel *chan, 107 struct cal_data_op_loop_ar9287 *pRawDatasetOpLoop, 108 uint8_t *pCalChans, uint16_t availPiers, int8_t *pPwr) 109 { 110 uint16_t idxL = 0, idxR = 0, numPiers; 111 HAL_BOOL match; 112 CHAN_CENTERS centers; 113 114 ar5416GetChannelCenters(ah, chan, ¢ers); 115 116 for (numPiers = 0; numPiers < availPiers; numPiers++) { 117 if (pCalChans[numPiers] == AR5416_BCHAN_UNUSED) 118 break; 119 } 120 121 match = ath_ee_getLowerUpperIndex( 122 (uint8_t)FREQ2FBIN(centers.synth_center, IEEE80211_IS_CHAN_2GHZ(chan)), 123 pCalChans, numPiers, &idxL, &idxR); 124 125 if (match) { 126 *pPwr = (int8_t) pRawDatasetOpLoop[idxL].pwrPdg[0][0]; 127 } else { 128 *pPwr = ((int8_t) pRawDatasetOpLoop[idxL].pwrPdg[0][0] + 129 (int8_t) pRawDatasetOpLoop[idxR].pwrPdg[0][0])/2; 130 } 131 } 132 133 void 134 ar9287olcSetPDADCs(struct ath_hal *ah, int32_t txPower, 135 uint16_t chain) 136 { 137 uint32_t tmpVal; 138 uint32_t a; 139 140 /* Enable OLPC for chain 0 */ 141 142 tmpVal = OS_REG_READ(ah, 0xa270); 143 tmpVal = tmpVal & 0xFCFFFFFF; 144 tmpVal = tmpVal | (0x3 << 24); 145 OS_REG_WRITE(ah, 0xa270, tmpVal); 146 147 /* Enable OLPC for chain 1 */ 148 149 tmpVal = OS_REG_READ(ah, 0xb270); 150 tmpVal = tmpVal & 0xFCFFFFFF; 151 tmpVal = tmpVal | (0x3 << 24); 152 OS_REG_WRITE(ah, 0xb270, tmpVal); 153 154 /* Write the OLPC ref power for chain 0 */ 155 156 if (chain == 0) { 157 tmpVal = OS_REG_READ(ah, 0xa398); 158 tmpVal = tmpVal & 0xff00ffff; 159 a = (txPower)&0xff; 160 tmpVal = tmpVal | (a << 16); 161 OS_REG_WRITE(ah, 0xa398, tmpVal); 162 } 163 164 /* Write the OLPC ref power for chain 1 */ 165 166 if (chain == 1) { 167 tmpVal = OS_REG_READ(ah, 0xb398); 168 tmpVal = tmpVal & 0xff00ffff; 169 a = (txPower)&0xff; 170 tmpVal = tmpVal | (a << 16); 171 OS_REG_WRITE(ah, 0xb398, tmpVal); 172 } 173 } 174