1718cf2ccSPedro F. Giffuni /*-
2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
3718cf2ccSPedro F. Giffuni *
4d8daa2e3SAdrian Chadd * Copyright (c) 2011 Adrian Chadd, Xenion Pty Ltd.
5d8daa2e3SAdrian Chadd *
6d8daa2e3SAdrian Chadd * Redistribution and use in source and binary forms, with or without
7d8daa2e3SAdrian Chadd * modification, are permitted provided that the following conditions
8d8daa2e3SAdrian Chadd * are met:
9d8daa2e3SAdrian Chadd * 1. Redistributions of source code must retain the above copyright
10d8daa2e3SAdrian Chadd * notice, this list of conditions and the following disclaimer.
11d8daa2e3SAdrian Chadd * 2. Redistributions in binary form must reproduce the above copyright
12d8daa2e3SAdrian Chadd * notice, this list of conditions and the following disclaimer in the
13d8daa2e3SAdrian Chadd * documentation and/or other materials provided with the distribution.
14d8daa2e3SAdrian Chadd *
15d8daa2e3SAdrian Chadd * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16d8daa2e3SAdrian Chadd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17d8daa2e3SAdrian Chadd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18d8daa2e3SAdrian Chadd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19d8daa2e3SAdrian Chadd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20d8daa2e3SAdrian Chadd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21d8daa2e3SAdrian Chadd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22d8daa2e3SAdrian Chadd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23d8daa2e3SAdrian Chadd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24d8daa2e3SAdrian Chadd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25d8daa2e3SAdrian Chadd * SUCH DAMAGE.
26d8daa2e3SAdrian Chadd */
27d8daa2e3SAdrian Chadd #include "opt_ah.h"
28d8daa2e3SAdrian Chadd
29d8daa2e3SAdrian Chadd #include "ah.h"
30d8daa2e3SAdrian Chadd #include "ah_internal.h"
31d8daa2e3SAdrian Chadd
32d8daa2e3SAdrian Chadd #include "ah_eeprom_v14.h"
334551052dSAdrian Chadd #include "ah_eeprom_9287.h"
34d8daa2e3SAdrian Chadd
35d8daa2e3SAdrian Chadd #include "ar9002/ar9280.h"
36d8daa2e3SAdrian Chadd #include "ar5416/ar5416reg.h"
37d8daa2e3SAdrian Chadd #include "ar5416/ar5416phy.h"
38d8daa2e3SAdrian Chadd #include "ar9002/ar9002phy.h"
39d8daa2e3SAdrian Chadd
40d8daa2e3SAdrian Chadd #include "ar9002/ar9287phy.h"
41d8daa2e3SAdrian Chadd #include "ar9002/ar9287an.h"
42d8daa2e3SAdrian Chadd #include "ar9002/ar9287_olc.h"
43d8daa2e3SAdrian Chadd
44d8daa2e3SAdrian Chadd void
ar9287olcInit(struct ath_hal * ah)45d8daa2e3SAdrian Chadd ar9287olcInit(struct ath_hal *ah)
46d8daa2e3SAdrian Chadd {
47d8daa2e3SAdrian Chadd OS_REG_SET_BIT(ah, AR_PHY_TX_PWRCTRL9,
48d8daa2e3SAdrian Chadd AR_PHY_TX_PWRCTRL9_RES_DC_REMOVAL);
49d8daa2e3SAdrian Chadd OS_A_REG_RMW_FIELD(ah, AR9287_AN_TXPC0,
50d8daa2e3SAdrian Chadd AR9287_AN_TXPC0_TXPCMODE,
51d8daa2e3SAdrian Chadd AR9287_AN_TXPC0_TXPCMODE_TEMPSENSE);
52d8daa2e3SAdrian Chadd OS_DELAY(100);
53d8daa2e3SAdrian Chadd }
54d8daa2e3SAdrian Chadd
55d8daa2e3SAdrian Chadd /*
56d8daa2e3SAdrian Chadd * Run temperature compensation calibration.
57d8daa2e3SAdrian Chadd *
58d8daa2e3SAdrian Chadd * The TX gain table is adjusted depending upon the difference
59d8daa2e3SAdrian Chadd * between the initial PDADC value and the currently read
60d8daa2e3SAdrian Chadd * average TX power sample value. This value is only valid if
61d8daa2e3SAdrian Chadd * frames have been transmitted, so currPDADC will be 0 if
62d8daa2e3SAdrian Chadd * no frames have yet been transmitted.
63d8daa2e3SAdrian Chadd */
64d8daa2e3SAdrian Chadd void
ar9287olcTemperatureCompensation(struct ath_hal * ah)65d8daa2e3SAdrian Chadd ar9287olcTemperatureCompensation(struct ath_hal *ah)
66d8daa2e3SAdrian Chadd {
67d8daa2e3SAdrian Chadd uint32_t rddata;
68d8daa2e3SAdrian Chadd int32_t delta, currPDADC, slope;
69d8daa2e3SAdrian Chadd
70d8daa2e3SAdrian Chadd rddata = OS_REG_READ(ah, AR_PHY_TX_PWRCTRL4);
71d8daa2e3SAdrian Chadd currPDADC = MS(rddata, AR_PHY_TX_PWRCTRL_PD_AVG_OUT);
72d8daa2e3SAdrian Chadd
73fe5237edSAdrian Chadd HALDEBUG(ah, HAL_DEBUG_PERCAL, "%s: initPDADC=%d, currPDADC=%d\n",
74fe5237edSAdrian Chadd __func__, AH5416(ah)->initPDADC, currPDADC);
75fe5237edSAdrian Chadd
76d8daa2e3SAdrian Chadd if (AH5416(ah)->initPDADC == 0 || currPDADC == 0) {
77d8daa2e3SAdrian Chadd /*
78d8daa2e3SAdrian Chadd * Zero value indicates that no frames have been transmitted
79d8daa2e3SAdrian Chadd * yet, can't do temperature compensation until frames are
80d8daa2e3SAdrian Chadd * transmitted.
81d8daa2e3SAdrian Chadd */
82d8daa2e3SAdrian Chadd return;
83d8daa2e3SAdrian Chadd } else {
84d8daa2e3SAdrian Chadd int8_t val;
85d8daa2e3SAdrian Chadd (void) (ath_hal_eepromGet(ah, AR_EEP_TEMPSENSE_SLOPE, &val));
86d8daa2e3SAdrian Chadd slope = val;
87d8daa2e3SAdrian Chadd
88d8daa2e3SAdrian Chadd if (slope == 0) { /* to avoid divide by zero case */
89d8daa2e3SAdrian Chadd delta = 0;
90d8daa2e3SAdrian Chadd } else {
91d8daa2e3SAdrian Chadd delta = ((currPDADC - AH5416(ah)->initPDADC)*4) / slope;
92d8daa2e3SAdrian Chadd }
93d8daa2e3SAdrian Chadd OS_REG_RMW_FIELD(ah, AR_PHY_CH0_TX_PWRCTRL11,
94d8daa2e3SAdrian Chadd AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, delta);
95d8daa2e3SAdrian Chadd OS_REG_RMW_FIELD(ah, AR_PHY_CH1_TX_PWRCTRL11,
96d8daa2e3SAdrian Chadd AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, delta);
97fe5237edSAdrian Chadd
98fe5237edSAdrian Chadd HALDEBUG(ah, HAL_DEBUG_PERCAL, "%s: delta=%d\n", __func__, delta);
99d8daa2e3SAdrian Chadd }
100d8daa2e3SAdrian Chadd }
1014551052dSAdrian Chadd
1024551052dSAdrian Chadd void
ar9287olcGetTxGainIndex(struct ath_hal * ah,const struct ieee80211_channel * chan,struct cal_data_op_loop_ar9287 * pRawDatasetOpLoop,uint8_t * pCalChans,uint16_t availPiers,int8_t * pPwr)1034551052dSAdrian Chadd ar9287olcGetTxGainIndex(struct ath_hal *ah,
1044551052dSAdrian Chadd const struct ieee80211_channel *chan,
1054551052dSAdrian Chadd struct cal_data_op_loop_ar9287 *pRawDatasetOpLoop,
1064551052dSAdrian Chadd uint8_t *pCalChans, uint16_t availPiers, int8_t *pPwr)
1074551052dSAdrian Chadd {
1084551052dSAdrian Chadd uint16_t idxL = 0, idxR = 0, numPiers;
1094551052dSAdrian Chadd HAL_BOOL match;
1104551052dSAdrian Chadd CHAN_CENTERS centers;
1114551052dSAdrian Chadd
1124551052dSAdrian Chadd ar5416GetChannelCenters(ah, chan, ¢ers);
1134551052dSAdrian Chadd
1144551052dSAdrian Chadd for (numPiers = 0; numPiers < availPiers; numPiers++) {
1154551052dSAdrian Chadd if (pCalChans[numPiers] == AR5416_BCHAN_UNUSED)
1164551052dSAdrian Chadd break;
1174551052dSAdrian Chadd }
1184551052dSAdrian Chadd
1194551052dSAdrian Chadd match = ath_ee_getLowerUpperIndex(
1204551052dSAdrian Chadd (uint8_t)FREQ2FBIN(centers.synth_center, IEEE80211_IS_CHAN_2GHZ(chan)),
1214551052dSAdrian Chadd pCalChans, numPiers, &idxL, &idxR);
1224551052dSAdrian Chadd
1234551052dSAdrian Chadd if (match) {
1244551052dSAdrian Chadd *pPwr = (int8_t) pRawDatasetOpLoop[idxL].pwrPdg[0][0];
1254551052dSAdrian Chadd } else {
1264551052dSAdrian Chadd *pPwr = ((int8_t) pRawDatasetOpLoop[idxL].pwrPdg[0][0] +
1274551052dSAdrian Chadd (int8_t) pRawDatasetOpLoop[idxR].pwrPdg[0][0])/2;
1284551052dSAdrian Chadd }
1294551052dSAdrian Chadd }
1304551052dSAdrian Chadd
1314551052dSAdrian Chadd void
ar9287olcSetPDADCs(struct ath_hal * ah,int32_t txPower,uint16_t chain)1324551052dSAdrian Chadd ar9287olcSetPDADCs(struct ath_hal *ah, int32_t txPower,
1334551052dSAdrian Chadd uint16_t chain)
1344551052dSAdrian Chadd {
1354551052dSAdrian Chadd uint32_t tmpVal;
1364551052dSAdrian Chadd uint32_t a;
1374551052dSAdrian Chadd
1384551052dSAdrian Chadd /* Enable OLPC for chain 0 */
1394551052dSAdrian Chadd
1404551052dSAdrian Chadd tmpVal = OS_REG_READ(ah, 0xa270);
1414551052dSAdrian Chadd tmpVal = tmpVal & 0xFCFFFFFF;
1424551052dSAdrian Chadd tmpVal = tmpVal | (0x3 << 24);
1434551052dSAdrian Chadd OS_REG_WRITE(ah, 0xa270, tmpVal);
1444551052dSAdrian Chadd
1454551052dSAdrian Chadd /* Enable OLPC for chain 1 */
1464551052dSAdrian Chadd
1474551052dSAdrian Chadd tmpVal = OS_REG_READ(ah, 0xb270);
1484551052dSAdrian Chadd tmpVal = tmpVal & 0xFCFFFFFF;
1494551052dSAdrian Chadd tmpVal = tmpVal | (0x3 << 24);
1504551052dSAdrian Chadd OS_REG_WRITE(ah, 0xb270, tmpVal);
1514551052dSAdrian Chadd
1524551052dSAdrian Chadd /* Write the OLPC ref power for chain 0 */
1534551052dSAdrian Chadd
1544551052dSAdrian Chadd if (chain == 0) {
1554551052dSAdrian Chadd tmpVal = OS_REG_READ(ah, 0xa398);
1564551052dSAdrian Chadd tmpVal = tmpVal & 0xff00ffff;
1574551052dSAdrian Chadd a = (txPower)&0xff;
1584551052dSAdrian Chadd tmpVal = tmpVal | (a << 16);
1594551052dSAdrian Chadd OS_REG_WRITE(ah, 0xa398, tmpVal);
1604551052dSAdrian Chadd }
1614551052dSAdrian Chadd
1624551052dSAdrian Chadd /* Write the OLPC ref power for chain 1 */
1634551052dSAdrian Chadd
1644551052dSAdrian Chadd if (chain == 1) {
1654551052dSAdrian Chadd tmpVal = OS_REG_READ(ah, 0xb398);
1664551052dSAdrian Chadd tmpVal = tmpVal & 0xff00ffff;
1674551052dSAdrian Chadd a = (txPower)&0xff;
1684551052dSAdrian Chadd tmpVal = tmpVal | (a << 16);
1694551052dSAdrian Chadd OS_REG_WRITE(ah, 0xb398, tmpVal);
1704551052dSAdrian Chadd }
1714551052dSAdrian Chadd }
172