xref: /freebsd/sys/dev/ath/ath_hal/ar9002/ar9287_olc.c (revision 95ee2897e98f5d444f26ed2334cc7c439f9c16c6)
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, &centers);
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