18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright (c) 2010-2011 Atheros Communications Inc.
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Permission to use, copy, modify, and/or distribute this software for any
58c2ecf20Sopenharmony_ci * purpose with or without fee is hereby granted, provided that the above
68c2ecf20Sopenharmony_ci * copyright notice and this permission notice appear in all copies.
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
98c2ecf20Sopenharmony_ci * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
108c2ecf20Sopenharmony_ci * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
118c2ecf20Sopenharmony_ci * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
128c2ecf20Sopenharmony_ci * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
138c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
148c2ecf20Sopenharmony_ci * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
158c2ecf20Sopenharmony_ci */
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#include "hw.h"
188c2ecf20Sopenharmony_ci#include "hw-ops.h"
198c2ecf20Sopenharmony_ci#include "ar9003_phy.h"
208c2ecf20Sopenharmony_ci#include "ar9003_rtt.h"
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#define RTT_RESTORE_TIMEOUT          1000
238c2ecf20Sopenharmony_ci#define RTT_ACCESS_TIMEOUT           100
248c2ecf20Sopenharmony_ci#define RTT_BAD_VALUE                0x0bad0bad
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci/*
278c2ecf20Sopenharmony_ci * RTT (Radio Retention Table) hardware implementation information
288c2ecf20Sopenharmony_ci *
298c2ecf20Sopenharmony_ci * There is an internal table (i.e. the rtt) for each chain (or bank).
308c2ecf20Sopenharmony_ci * Each table contains 6 entries and each entry is corresponding to
318c2ecf20Sopenharmony_ci * a specific calibration parameter as depicted below.
328c2ecf20Sopenharmony_ci *  0~2 - DC offset DAC calibration: loop, low, high (offsetI/Q_...)
338c2ecf20Sopenharmony_ci *  3   - Filter cal (filterfc)
348c2ecf20Sopenharmony_ci *  4   - RX gain settings
358c2ecf20Sopenharmony_ci *  5   - Peak detector offset calibration (agc_caldac)
368c2ecf20Sopenharmony_ci */
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_civoid ar9003_hw_rtt_enable(struct ath_hw *ah)
398c2ecf20Sopenharmony_ci{
408c2ecf20Sopenharmony_ci	REG_WRITE(ah, AR_PHY_RTT_CTRL, 1);
418c2ecf20Sopenharmony_ci}
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_civoid ar9003_hw_rtt_disable(struct ath_hw *ah)
448c2ecf20Sopenharmony_ci{
458c2ecf20Sopenharmony_ci	REG_WRITE(ah, AR_PHY_RTT_CTRL, 0);
468c2ecf20Sopenharmony_ci}
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_civoid ar9003_hw_rtt_set_mask(struct ath_hw *ah, u32 rtt_mask)
498c2ecf20Sopenharmony_ci{
508c2ecf20Sopenharmony_ci	REG_RMW_FIELD(ah, AR_PHY_RTT_CTRL,
518c2ecf20Sopenharmony_ci		      AR_PHY_RTT_CTRL_RESTORE_MASK, rtt_mask);
528c2ecf20Sopenharmony_ci}
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_cibool ar9003_hw_rtt_force_restore(struct ath_hw *ah)
558c2ecf20Sopenharmony_ci{
568c2ecf20Sopenharmony_ci	if (!ath9k_hw_wait(ah, AR_PHY_RTT_CTRL,
578c2ecf20Sopenharmony_ci			   AR_PHY_RTT_CTRL_FORCE_RADIO_RESTORE,
588c2ecf20Sopenharmony_ci			   0, RTT_RESTORE_TIMEOUT))
598c2ecf20Sopenharmony_ci		return false;
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	REG_RMW_FIELD(ah, AR_PHY_RTT_CTRL,
628c2ecf20Sopenharmony_ci		      AR_PHY_RTT_CTRL_FORCE_RADIO_RESTORE, 1);
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	if (!ath9k_hw_wait(ah, AR_PHY_RTT_CTRL,
658c2ecf20Sopenharmony_ci			   AR_PHY_RTT_CTRL_FORCE_RADIO_RESTORE,
668c2ecf20Sopenharmony_ci			   0, RTT_RESTORE_TIMEOUT))
678c2ecf20Sopenharmony_ci		return false;
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	return true;
708c2ecf20Sopenharmony_ci}
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_cistatic void ar9003_hw_rtt_load_hist_entry(struct ath_hw *ah, u8 chain,
738c2ecf20Sopenharmony_ci					  u32 index, u32 data28)
748c2ecf20Sopenharmony_ci{
758c2ecf20Sopenharmony_ci	u32 val;
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	val = SM(data28, AR_PHY_RTT_SW_RTT_TABLE_DATA);
788c2ecf20Sopenharmony_ci	REG_WRITE(ah, AR_PHY_RTT_TABLE_SW_INTF_1_B(chain), val);
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	val = SM(0, AR_PHY_RTT_SW_RTT_TABLE_ACCESS) |
818c2ecf20Sopenharmony_ci	      SM(1, AR_PHY_RTT_SW_RTT_TABLE_WRITE) |
828c2ecf20Sopenharmony_ci	      SM(index, AR_PHY_RTT_SW_RTT_TABLE_ADDR);
838c2ecf20Sopenharmony_ci	REG_WRITE(ah, AR_PHY_RTT_TABLE_SW_INTF_B(chain), val);
848c2ecf20Sopenharmony_ci	udelay(1);
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	val |= SM(1, AR_PHY_RTT_SW_RTT_TABLE_ACCESS);
878c2ecf20Sopenharmony_ci	REG_WRITE(ah, AR_PHY_RTT_TABLE_SW_INTF_B(chain), val);
888c2ecf20Sopenharmony_ci	udelay(1);
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	if (!ath9k_hw_wait(ah, AR_PHY_RTT_TABLE_SW_INTF_B(chain),
918c2ecf20Sopenharmony_ci			   AR_PHY_RTT_SW_RTT_TABLE_ACCESS, 0,
928c2ecf20Sopenharmony_ci			   RTT_ACCESS_TIMEOUT))
938c2ecf20Sopenharmony_ci		return;
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	val &= ~SM(1, AR_PHY_RTT_SW_RTT_TABLE_WRITE);
968c2ecf20Sopenharmony_ci	REG_WRITE(ah, AR_PHY_RTT_TABLE_SW_INTF_B(chain), val);
978c2ecf20Sopenharmony_ci	udelay(1);
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	ath9k_hw_wait(ah, AR_PHY_RTT_TABLE_SW_INTF_B(chain),
1008c2ecf20Sopenharmony_ci		      AR_PHY_RTT_SW_RTT_TABLE_ACCESS, 0,
1018c2ecf20Sopenharmony_ci		      RTT_ACCESS_TIMEOUT);
1028c2ecf20Sopenharmony_ci}
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_civoid ar9003_hw_rtt_load_hist(struct ath_hw *ah)
1058c2ecf20Sopenharmony_ci{
1068c2ecf20Sopenharmony_ci	int chain, i;
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) {
1098c2ecf20Sopenharmony_ci		if (!(ah->caps.rx_chainmask & (1 << chain)))
1108c2ecf20Sopenharmony_ci			continue;
1118c2ecf20Sopenharmony_ci		for (i = 0; i < MAX_RTT_TABLE_ENTRY; i++) {
1128c2ecf20Sopenharmony_ci			ar9003_hw_rtt_load_hist_entry(ah, chain, i,
1138c2ecf20Sopenharmony_ci					      ah->caldata->rtt_table[chain][i]);
1148c2ecf20Sopenharmony_ci			ath_dbg(ath9k_hw_common(ah), CALIBRATE,
1158c2ecf20Sopenharmony_ci				"Load RTT value at idx %d, chain %d: 0x%x\n",
1168c2ecf20Sopenharmony_ci				i, chain, ah->caldata->rtt_table[chain][i]);
1178c2ecf20Sopenharmony_ci		}
1188c2ecf20Sopenharmony_ci	}
1198c2ecf20Sopenharmony_ci}
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_cistatic void ar9003_hw_patch_rtt(struct ath_hw *ah, int index, int chain)
1228c2ecf20Sopenharmony_ci{
1238c2ecf20Sopenharmony_ci	int agc, caldac;
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	if (!test_bit(SW_PKDET_DONE, &ah->caldata->cal_flags))
1268c2ecf20Sopenharmony_ci		return;
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	if ((index != 5) || (chain >= 2))
1298c2ecf20Sopenharmony_ci		return;
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	agc = REG_READ_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
1328c2ecf20Sopenharmony_ci			     AR_PHY_65NM_RXRF_AGC_AGC_OVERRIDE);
1338c2ecf20Sopenharmony_ci	if (!agc)
1348c2ecf20Sopenharmony_ci		return;
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	caldac = ah->caldata->caldac[chain];
1378c2ecf20Sopenharmony_ci	ah->caldata->rtt_table[chain][index] &= 0xFFFF05FF;
1388c2ecf20Sopenharmony_ci	caldac = (caldac & 0x20) | ((caldac & 0x1F) << 7);
1398c2ecf20Sopenharmony_ci	ah->caldata->rtt_table[chain][index] |= (caldac << 4);
1408c2ecf20Sopenharmony_ci}
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_cistatic int ar9003_hw_rtt_fill_hist_entry(struct ath_hw *ah, u8 chain, u32 index)
1438c2ecf20Sopenharmony_ci{
1448c2ecf20Sopenharmony_ci	u32 val;
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	val = SM(0, AR_PHY_RTT_SW_RTT_TABLE_ACCESS) |
1478c2ecf20Sopenharmony_ci	      SM(0, AR_PHY_RTT_SW_RTT_TABLE_WRITE) |
1488c2ecf20Sopenharmony_ci	      SM(index, AR_PHY_RTT_SW_RTT_TABLE_ADDR);
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	REG_WRITE(ah, AR_PHY_RTT_TABLE_SW_INTF_B(chain), val);
1518c2ecf20Sopenharmony_ci	udelay(1);
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	val |= SM(1, AR_PHY_RTT_SW_RTT_TABLE_ACCESS);
1548c2ecf20Sopenharmony_ci	REG_WRITE(ah, AR_PHY_RTT_TABLE_SW_INTF_B(chain), val);
1558c2ecf20Sopenharmony_ci	udelay(1);
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	if (!ath9k_hw_wait(ah, AR_PHY_RTT_TABLE_SW_INTF_B(chain),
1588c2ecf20Sopenharmony_ci			   AR_PHY_RTT_SW_RTT_TABLE_ACCESS, 0,
1598c2ecf20Sopenharmony_ci			   RTT_ACCESS_TIMEOUT))
1608c2ecf20Sopenharmony_ci		return RTT_BAD_VALUE;
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	val = MS(REG_READ(ah, AR_PHY_RTT_TABLE_SW_INTF_1_B(chain)),
1638c2ecf20Sopenharmony_ci		 AR_PHY_RTT_SW_RTT_TABLE_DATA);
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	return val;
1678c2ecf20Sopenharmony_ci}
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_civoid ar9003_hw_rtt_fill_hist(struct ath_hw *ah)
1708c2ecf20Sopenharmony_ci{
1718c2ecf20Sopenharmony_ci	int chain, i;
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) {
1748c2ecf20Sopenharmony_ci		if (!(ah->caps.rx_chainmask & (1 << chain)))
1758c2ecf20Sopenharmony_ci			continue;
1768c2ecf20Sopenharmony_ci		for (i = 0; i < MAX_RTT_TABLE_ENTRY; i++) {
1778c2ecf20Sopenharmony_ci			ah->caldata->rtt_table[chain][i] =
1788c2ecf20Sopenharmony_ci				ar9003_hw_rtt_fill_hist_entry(ah, chain, i);
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci			ar9003_hw_patch_rtt(ah, i, chain);
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci			ath_dbg(ath9k_hw_common(ah), CALIBRATE,
1838c2ecf20Sopenharmony_ci				"RTT value at idx %d, chain %d is: 0x%x\n",
1848c2ecf20Sopenharmony_ci				i, chain, ah->caldata->rtt_table[chain][i]);
1858c2ecf20Sopenharmony_ci		}
1868c2ecf20Sopenharmony_ci	}
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	set_bit(RTT_DONE, &ah->caldata->cal_flags);
1898c2ecf20Sopenharmony_ci}
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_civoid ar9003_hw_rtt_clear_hist(struct ath_hw *ah)
1928c2ecf20Sopenharmony_ci{
1938c2ecf20Sopenharmony_ci	int chain, i;
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) {
1968c2ecf20Sopenharmony_ci		if (!(ah->caps.rx_chainmask & (1 << chain)))
1978c2ecf20Sopenharmony_ci			continue;
1988c2ecf20Sopenharmony_ci		for (i = 0; i < MAX_RTT_TABLE_ENTRY; i++)
1998c2ecf20Sopenharmony_ci			ar9003_hw_rtt_load_hist_entry(ah, chain, i, 0);
2008c2ecf20Sopenharmony_ci	}
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	if (ah->caldata)
2038c2ecf20Sopenharmony_ci		clear_bit(RTT_DONE, &ah->caldata->cal_flags);
2048c2ecf20Sopenharmony_ci}
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_cibool ar9003_hw_rtt_restore(struct ath_hw *ah, struct ath9k_channel *chan)
2078c2ecf20Sopenharmony_ci{
2088c2ecf20Sopenharmony_ci	bool restore;
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	if (!ah->caldata)
2118c2ecf20Sopenharmony_ci		return false;
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	if (test_bit(SW_PKDET_DONE, &ah->caldata->cal_flags)) {
2148c2ecf20Sopenharmony_ci		if (IS_CHAN_2GHZ(chan)){
2158c2ecf20Sopenharmony_ci			REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(0),
2168c2ecf20Sopenharmony_ci				      AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR,
2178c2ecf20Sopenharmony_ci				      ah->caldata->caldac[0]);
2188c2ecf20Sopenharmony_ci			REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(1),
2198c2ecf20Sopenharmony_ci				      AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR,
2208c2ecf20Sopenharmony_ci				      ah->caldata->caldac[1]);
2218c2ecf20Sopenharmony_ci		} else {
2228c2ecf20Sopenharmony_ci			REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(0),
2238c2ecf20Sopenharmony_ci				      AR_PHY_65NM_RXRF_AGC_AGC5G_CALDAC_OVR,
2248c2ecf20Sopenharmony_ci				      ah->caldata->caldac[0]);
2258c2ecf20Sopenharmony_ci			REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(1),
2268c2ecf20Sopenharmony_ci				      AR_PHY_65NM_RXRF_AGC_AGC5G_CALDAC_OVR,
2278c2ecf20Sopenharmony_ci				      ah->caldata->caldac[1]);
2288c2ecf20Sopenharmony_ci		}
2298c2ecf20Sopenharmony_ci		REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(1),
2308c2ecf20Sopenharmony_ci			      AR_PHY_65NM_RXRF_AGC_AGC_OVERRIDE, 0x1);
2318c2ecf20Sopenharmony_ci		REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(0),
2328c2ecf20Sopenharmony_ci			      AR_PHY_65NM_RXRF_AGC_AGC_OVERRIDE, 0x1);
2338c2ecf20Sopenharmony_ci	}
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	if (!test_bit(RTT_DONE, &ah->caldata->cal_flags))
2368c2ecf20Sopenharmony_ci		return false;
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	ar9003_hw_rtt_enable(ah);
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	if (test_bit(SW_PKDET_DONE, &ah->caldata->cal_flags))
2418c2ecf20Sopenharmony_ci		ar9003_hw_rtt_set_mask(ah, 0x30);
2428c2ecf20Sopenharmony_ci	else
2438c2ecf20Sopenharmony_ci		ar9003_hw_rtt_set_mask(ah, 0x10);
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	if (!ath9k_hw_rfbus_req(ah)) {
2468c2ecf20Sopenharmony_ci		ath_err(ath9k_hw_common(ah), "Could not stop baseband\n");
2478c2ecf20Sopenharmony_ci		restore = false;
2488c2ecf20Sopenharmony_ci		goto fail;
2498c2ecf20Sopenharmony_ci	}
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	ar9003_hw_rtt_load_hist(ah);
2528c2ecf20Sopenharmony_ci	restore = ar9003_hw_rtt_force_restore(ah);
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_cifail:
2558c2ecf20Sopenharmony_ci	ath9k_hw_rfbus_done(ah);
2568c2ecf20Sopenharmony_ci	ar9003_hw_rtt_disable(ah);
2578c2ecf20Sopenharmony_ci	return restore;
2588c2ecf20Sopenharmony_ci}
259