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 #include "opt_ah.h" 28 29 #include "ah.h" 30 #include "ah_internal.h" 31 32 #include "ah_eeprom_v14.h" 33 #include "ah_eeprom_9287.h" 34 35 #include "ar9002/ar9280.h" 36 #include "ar5416/ar5416reg.h" 37 #include "ar5416/ar5416phy.h" 38 #include "ar9002/ar9002phy.h" 39 40 #include "ar9002/ar9287phy.h" 41 #include "ar9002/ar9287an.h" 42 #include "ar9002/ar9287_olc.h" 43 44 void 45 ar9287olcInit(struct ath_hal *ah) 46 { 47 OS_REG_SET_BIT(ah, AR_PHY_TX_PWRCTRL9, 48 AR_PHY_TX_PWRCTRL9_RES_DC_REMOVAL); 49 OS_A_REG_RMW_FIELD(ah, AR9287_AN_TXPC0, 50 AR9287_AN_TXPC0_TXPCMODE, 51 AR9287_AN_TXPC0_TXPCMODE_TEMPSENSE); 52 OS_DELAY(100); 53 } 54 55 /* 56 * Run temperature compensation calibration. 57 * 58 * The TX gain table is adjusted depending upon the difference 59 * between the initial PDADC value and the currently read 60 * average TX power sample value. This value is only valid if 61 * frames have been transmitted, so currPDADC will be 0 if 62 * no frames have yet been transmitted. 63 */ 64 void 65 ar9287olcTemperatureCompensation(struct ath_hal *ah) 66 { 67 uint32_t rddata; 68 int32_t delta, currPDADC, slope; 69 70 rddata = OS_REG_READ(ah, AR_PHY_TX_PWRCTRL4); 71 currPDADC = MS(rddata, AR_PHY_TX_PWRCTRL_PD_AVG_OUT); 72 73 HALDEBUG(ah, HAL_DEBUG_PERCAL, "%s: initPDADC=%d, currPDADC=%d\n", 74 __func__, AH5416(ah)->initPDADC, currPDADC); 75 76 if (AH5416(ah)->initPDADC == 0 || currPDADC == 0) { 77 /* 78 * Zero value indicates that no frames have been transmitted 79 * yet, can't do temperature compensation until frames are 80 * transmitted. 81 */ 82 return; 83 } else { 84 int8_t val; 85 (void) (ath_hal_eepromGet(ah, AR_EEP_TEMPSENSE_SLOPE, &val)); 86 slope = val; 87 88 if (slope == 0) { /* to avoid divide by zero case */ 89 delta = 0; 90 } else { 91 delta = ((currPDADC - AH5416(ah)->initPDADC)*4) / slope; 92 } 93 OS_REG_RMW_FIELD(ah, AR_PHY_CH0_TX_PWRCTRL11, 94 AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, delta); 95 OS_REG_RMW_FIELD(ah, AR_PHY_CH1_TX_PWRCTRL11, 96 AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, delta); 97 98 HALDEBUG(ah, HAL_DEBUG_PERCAL, "%s: delta=%d\n", __func__, delta); 99 } 100 } 101 102 void 103 ar9287olcGetTxGainIndex(struct ath_hal *ah, 104 const struct ieee80211_channel *chan, 105 struct cal_data_op_loop_ar9287 *pRawDatasetOpLoop, 106 uint8_t *pCalChans, uint16_t availPiers, int8_t *pPwr) 107 { 108 uint16_t idxL = 0, idxR = 0, numPiers; 109 HAL_BOOL match; 110 CHAN_CENTERS centers; 111 112 ar5416GetChannelCenters(ah, chan, ¢ers); 113 114 for (numPiers = 0; numPiers < availPiers; numPiers++) { 115 if (pCalChans[numPiers] == AR5416_BCHAN_UNUSED) 116 break; 117 } 118 119 match = ath_ee_getLowerUpperIndex( 120 (uint8_t)FREQ2FBIN(centers.synth_center, IEEE80211_IS_CHAN_2GHZ(chan)), 121 pCalChans, numPiers, &idxL, &idxR); 122 123 if (match) { 124 *pPwr = (int8_t) pRawDatasetOpLoop[idxL].pwrPdg[0][0]; 125 } else { 126 *pPwr = ((int8_t) pRawDatasetOpLoop[idxL].pwrPdg[0][0] + 127 (int8_t) pRawDatasetOpLoop[idxR].pwrPdg[0][0])/2; 128 } 129 } 130 131 void 132 ar9287olcSetPDADCs(struct ath_hal *ah, int32_t txPower, 133 uint16_t chain) 134 { 135 uint32_t tmpVal; 136 uint32_t a; 137 138 /* Enable OLPC for chain 0 */ 139 140 tmpVal = OS_REG_READ(ah, 0xa270); 141 tmpVal = tmpVal & 0xFCFFFFFF; 142 tmpVal = tmpVal | (0x3 << 24); 143 OS_REG_WRITE(ah, 0xa270, tmpVal); 144 145 /* Enable OLPC for chain 1 */ 146 147 tmpVal = OS_REG_READ(ah, 0xb270); 148 tmpVal = tmpVal & 0xFCFFFFFF; 149 tmpVal = tmpVal | (0x3 << 24); 150 OS_REG_WRITE(ah, 0xb270, tmpVal); 151 152 /* Write the OLPC ref power for chain 0 */ 153 154 if (chain == 0) { 155 tmpVal = OS_REG_READ(ah, 0xa398); 156 tmpVal = tmpVal & 0xff00ffff; 157 a = (txPower)&0xff; 158 tmpVal = tmpVal | (a << 16); 159 OS_REG_WRITE(ah, 0xa398, tmpVal); 160 } 161 162 /* Write the OLPC ref power for chain 1 */ 163 164 if (chain == 1) { 165 tmpVal = OS_REG_READ(ah, 0xb398); 166 tmpVal = tmpVal & 0xff00ffff; 167 a = (txPower)&0xff; 168 tmpVal = tmpVal | (a << 16); 169 OS_REG_WRITE(ah, 0xb398, tmpVal); 170 } 171 } 172