1717f6bedSFelix Fietkau /* 25b68138eSSujith Manoharan * Copyright (c) 2010-2011 Atheros Communications Inc. 3717f6bedSFelix Fietkau * 4717f6bedSFelix Fietkau * Permission to use, copy, modify, and/or distribute this software for any 5717f6bedSFelix Fietkau * purpose with or without fee is hereby granted, provided that the above 6717f6bedSFelix Fietkau * copyright notice and this permission notice appear in all copies. 7717f6bedSFelix Fietkau * 8717f6bedSFelix Fietkau * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9717f6bedSFelix Fietkau * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10717f6bedSFelix Fietkau * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11717f6bedSFelix Fietkau * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12717f6bedSFelix Fietkau * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13717f6bedSFelix Fietkau * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14717f6bedSFelix Fietkau * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15717f6bedSFelix Fietkau */ 16717f6bedSFelix Fietkau 17ee40fa06SPaul Gortmaker #include <linux/export.h> 18717f6bedSFelix Fietkau #include "hw.h" 19717f6bedSFelix Fietkau #include "ar9003_phy.h" 20717f6bedSFelix Fietkau 21717f6bedSFelix Fietkau void ar9003_paprd_enable(struct ath_hw *ah, bool val) 22717f6bedSFelix Fietkau { 2345ef6a0bSVasanthakumar Thiagarajan struct ath9k_channel *chan = ah->curchan; 24673424ceSWenli Looi bool is2ghz = IS_CHAN_2GHZ(chan); 25331c5ea2SMohammed Shafi Shajakhan 26331c5ea2SMohammed Shafi Shajakhan /* 27331c5ea2SMohammed Shafi Shajakhan * 3 bits for modalHeader5G.papdRateMaskHt20 28331c5ea2SMohammed Shafi Shajakhan * is used for sub-band disabling of PAPRD. 29331c5ea2SMohammed Shafi Shajakhan * 5G band is divided into 3 sub-bands -- upper, 30331c5ea2SMohammed Shafi Shajakhan * middle, lower. 31331c5ea2SMohammed Shafi Shajakhan * if bit 30 of modalHeader5G.papdRateMaskHt20 is set 32331c5ea2SMohammed Shafi Shajakhan * -- disable PAPRD for upper band 5GHz 33331c5ea2SMohammed Shafi Shajakhan * if bit 29 of modalHeader5G.papdRateMaskHt20 is set 34331c5ea2SMohammed Shafi Shajakhan * -- disable PAPRD for middle band 5GHz 35331c5ea2SMohammed Shafi Shajakhan * if bit 28 of modalHeader5G.papdRateMaskHt20 is set 36331c5ea2SMohammed Shafi Shajakhan * -- disable PAPRD for lower band 5GHz 37331c5ea2SMohammed Shafi Shajakhan */ 38331c5ea2SMohammed Shafi Shajakhan 39673424ceSWenli Looi if (!is2ghz) { 40331c5ea2SMohammed Shafi Shajakhan if (chan->channel >= UPPER_5G_SUB_BAND_START) { 41673424ceSWenli Looi if (ar9003_get_paprd_rate_mask_ht20(ah, is2ghz) 42331c5ea2SMohammed Shafi Shajakhan & BIT(30)) 43331c5ea2SMohammed Shafi Shajakhan val = false; 44331c5ea2SMohammed Shafi Shajakhan } else if (chan->channel >= MID_5G_SUB_BAND_START) { 45673424ceSWenli Looi if (ar9003_get_paprd_rate_mask_ht20(ah, is2ghz) 46331c5ea2SMohammed Shafi Shajakhan & BIT(29)) 47331c5ea2SMohammed Shafi Shajakhan val = false; 48331c5ea2SMohammed Shafi Shajakhan } else { 49673424ceSWenli Looi if (ar9003_get_paprd_rate_mask_ht20(ah, is2ghz) 50331c5ea2SMohammed Shafi Shajakhan & BIT(28)) 51331c5ea2SMohammed Shafi Shajakhan val = false; 52331c5ea2SMohammed Shafi Shajakhan } 53331c5ea2SMohammed Shafi Shajakhan } 5445ef6a0bSVasanthakumar Thiagarajan 5545ef6a0bSVasanthakumar Thiagarajan if (val) { 5645ef6a0bSVasanthakumar Thiagarajan ah->paprd_table_write_done = true; 5764ea57d0SGabor Juhos ath9k_hw_apply_txpower(ah, chan, false); 5845ef6a0bSVasanthakumar Thiagarajan } 5945ef6a0bSVasanthakumar Thiagarajan 60717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL0_B0, 61717f6bedSFelix Fietkau AR_PHY_PAPRD_CTRL0_PAPRD_ENABLE, !!val); 6211441fb8SVasanthakumar Thiagarajan if (ah->caps.tx_chainmask & BIT(1)) 63717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL0_B1, 64717f6bedSFelix Fietkau AR_PHY_PAPRD_CTRL0_PAPRD_ENABLE, !!val); 6511441fb8SVasanthakumar Thiagarajan if (ah->caps.tx_chainmask & BIT(2)) 66717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL0_B2, 67717f6bedSFelix Fietkau AR_PHY_PAPRD_CTRL0_PAPRD_ENABLE, !!val); 68717f6bedSFelix Fietkau } 69717f6bedSFelix Fietkau EXPORT_SYMBOL(ar9003_paprd_enable); 70717f6bedSFelix Fietkau 711bf38661SFelix Fietkau static int ar9003_get_training_power_2g(struct ath_hw *ah) 72717f6bedSFelix Fietkau { 73931749bfSMohammed Shafi Shajakhan struct ath9k_channel *chan = ah->curchan; 741bf38661SFelix Fietkau unsigned int power, scale, delta; 751bf38661SFelix Fietkau 76931749bfSMohammed Shafi Shajakhan scale = ar9003_get_paprd_scale_factor(ah, chan); 771562580eSSujith Manoharan 781562580eSSujith Manoharan if (AR_SREV_9330(ah) || AR_SREV_9340(ah) || 791562580eSSujith Manoharan AR_SREV_9462(ah) || AR_SREV_9565(ah)) { 801562580eSSujith Manoharan power = ah->paprd_target_power + 2; 811562580eSSujith Manoharan } else if (AR_SREV_9485(ah)) { 821562580eSSujith Manoharan power = 25; 831562580eSSujith Manoharan } else { 841bf38661SFelix Fietkau power = REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE5, 851bf38661SFelix Fietkau AR_PHY_POWERTX_RATE5_POWERTXHT20_0); 861bf38661SFelix Fietkau 871bf38661SFelix Fietkau delta = abs((int) ah->paprd_target_power - (int) power); 881bf38661SFelix Fietkau if (delta > scale) 891bf38661SFelix Fietkau return -1; 901bf38661SFelix Fietkau 911bf38661SFelix Fietkau if (delta < 4) 921bf38661SFelix Fietkau power -= 4 - delta; 931562580eSSujith Manoharan } 941bf38661SFelix Fietkau 951bf38661SFelix Fietkau return power; 961bf38661SFelix Fietkau } 971bf38661SFelix Fietkau 981bf38661SFelix Fietkau static int ar9003_get_training_power_5g(struct ath_hw *ah) 991bf38661SFelix Fietkau { 1001bf38661SFelix Fietkau struct ath_common *common = ath9k_hw_common(ah); 1011bf38661SFelix Fietkau struct ath9k_channel *chan = ah->curchan; 1021bf38661SFelix Fietkau unsigned int power, scale, delta; 1031bf38661SFelix Fietkau 104931749bfSMohammed Shafi Shajakhan scale = ar9003_get_paprd_scale_factor(ah, chan); 1051bf38661SFelix Fietkau 1061bf38661SFelix Fietkau if (IS_CHAN_HT40(chan)) 1071bf38661SFelix Fietkau power = REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE8, 1081bf38661SFelix Fietkau AR_PHY_POWERTX_RATE8_POWERTXHT40_5); 1091bf38661SFelix Fietkau else 1101bf38661SFelix Fietkau power = REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE6, 1111bf38661SFelix Fietkau AR_PHY_POWERTX_RATE6_POWERTXHT20_5); 1121bf38661SFelix Fietkau 1131bf38661SFelix Fietkau power += scale; 1141bf38661SFelix Fietkau delta = abs((int) ah->paprd_target_power - (int) power); 1151bf38661SFelix Fietkau if (delta > scale) 1161bf38661SFelix Fietkau return -1; 1171bf38661SFelix Fietkau 11882b2d334SFelix Fietkau switch (get_streams(ah->txchainmask)) { 1197952ca5bSMohammed Shafi Shajakhan case 1: 1207952ca5bSMohammed Shafi Shajakhan delta = 6; 1217952ca5bSMohammed Shafi Shajakhan break; 1227952ca5bSMohammed Shafi Shajakhan case 2: 1237952ca5bSMohammed Shafi Shajakhan delta = 4; 1247952ca5bSMohammed Shafi Shajakhan break; 1257952ca5bSMohammed Shafi Shajakhan case 3: 1267952ca5bSMohammed Shafi Shajakhan delta = 2; 1277952ca5bSMohammed Shafi Shajakhan break; 1287952ca5bSMohammed Shafi Shajakhan default: 1297952ca5bSMohammed Shafi Shajakhan delta = 0; 130d2182b69SJoe Perches ath_dbg(common, CALIBRATE, "Invalid tx-chainmask: %u\n", 131d2182b69SJoe Perches ah->txchainmask); 1327952ca5bSMohammed Shafi Shajakhan } 1337952ca5bSMohammed Shafi Shajakhan 1347952ca5bSMohammed Shafi Shajakhan power += delta; 1351bf38661SFelix Fietkau return power; 1361bf38661SFelix Fietkau } 1371bf38661SFelix Fietkau 1381bf38661SFelix Fietkau static int ar9003_paprd_setup_single_table(struct ath_hw *ah) 1391bf38661SFelix Fietkau { 1401bf38661SFelix Fietkau struct ath_common *common = ath9k_hw_common(ah); 14107b2fa5aSJoe Perches static const u32 ctrl0[3] = { 142717f6bedSFelix Fietkau AR_PHY_PAPRD_CTRL0_B0, 143717f6bedSFelix Fietkau AR_PHY_PAPRD_CTRL0_B1, 144717f6bedSFelix Fietkau AR_PHY_PAPRD_CTRL0_B2 145717f6bedSFelix Fietkau }; 14607b2fa5aSJoe Perches static const u32 ctrl1[3] = { 147717f6bedSFelix Fietkau AR_PHY_PAPRD_CTRL1_B0, 148717f6bedSFelix Fietkau AR_PHY_PAPRD_CTRL1_B1, 149717f6bedSFelix Fietkau AR_PHY_PAPRD_CTRL1_B2 150717f6bedSFelix Fietkau }; 1511bf38661SFelix Fietkau int training_power; 1522577c6e8SSenthil Balasubramanian int i, val; 15326228959SFelix Fietkau u32 am2pm_mask = ah->paprd_ratemask; 154717f6bedSFelix Fietkau 1551bf38661SFelix Fietkau if (IS_CHAN_2GHZ(ah->curchan)) 1561bf38661SFelix Fietkau training_power = ar9003_get_training_power_2g(ah); 1571bf38661SFelix Fietkau else 1581bf38661SFelix Fietkau training_power = ar9003_get_training_power_5g(ah); 1591bf38661SFelix Fietkau 160d2182b69SJoe Perches ath_dbg(common, CALIBRATE, "Training power: %d, Target power: %d\n", 16184288044SMohammed Shafi Shajakhan training_power, ah->paprd_target_power); 16284288044SMohammed Shafi Shajakhan 1631bf38661SFelix Fietkau if (training_power < 0) { 164d2182b69SJoe Perches ath_dbg(common, CALIBRATE, 165d2182b69SJoe Perches "PAPRD target power delta out of range\n"); 1661bf38661SFelix Fietkau return -ERANGE; 1671bf38661SFelix Fietkau } 1681bf38661SFelix Fietkau ah->paprd_training_power = training_power; 1691bf38661SFelix Fietkau 17026228959SFelix Fietkau if (AR_SREV_9330(ah)) 17126228959SFelix Fietkau am2pm_mask = 0; 17226228959SFelix Fietkau 1737072bf62SVasanthakumar Thiagarajan REG_RMW_FIELD(ah, AR_PHY_PAPRD_AM2AM, AR_PHY_PAPRD_AM2AM_MASK, 1747072bf62SVasanthakumar Thiagarajan ah->paprd_ratemask); 1757072bf62SVasanthakumar Thiagarajan REG_RMW_FIELD(ah, AR_PHY_PAPRD_AM2PM, AR_PHY_PAPRD_AM2PM_MASK, 17626228959SFelix Fietkau am2pm_mask); 1777072bf62SVasanthakumar Thiagarajan REG_RMW_FIELD(ah, AR_PHY_PAPRD_HT40, AR_PHY_PAPRD_HT40_MASK, 178f1a8abb0SFelix Fietkau ah->paprd_ratemask_ht40); 179717f6bedSFelix Fietkau 180914d0f4dSSujith Manoharan ath_dbg(common, CALIBRATE, "PAPRD HT20 mask: 0x%x, HT40 mask: 0x%x\n", 181914d0f4dSSujith Manoharan ah->paprd_ratemask, ah->paprd_ratemask_ht40); 182914d0f4dSSujith Manoharan 18311441fb8SVasanthakumar Thiagarajan for (i = 0; i < ah->caps.max_txchains; i++) { 184717f6bedSFelix Fietkau REG_RMW_FIELD(ah, ctrl0[i], 185717f6bedSFelix Fietkau AR_PHY_PAPRD_CTRL0_USE_SINGLE_TABLE_MASK, 1); 186717f6bedSFelix Fietkau REG_RMW_FIELD(ah, ctrl1[i], 187717f6bedSFelix Fietkau AR_PHY_PAPRD_CTRL1_ADAPTIVE_AM2PM_ENABLE, 1); 188717f6bedSFelix Fietkau REG_RMW_FIELD(ah, ctrl1[i], 189717f6bedSFelix Fietkau AR_PHY_PAPRD_CTRL1_ADAPTIVE_AM2AM_ENABLE, 1); 190717f6bedSFelix Fietkau REG_RMW_FIELD(ah, ctrl1[i], 191717f6bedSFelix Fietkau AR_PHY_PAPRD_CTRL1_ADAPTIVE_SCALING_ENA, 0); 192717f6bedSFelix Fietkau REG_RMW_FIELD(ah, ctrl1[i], 193717f6bedSFelix Fietkau AR_PHY_PAPRD_CTRL1_PA_GAIN_SCALE_FACT_MASK, 181); 194717f6bedSFelix Fietkau REG_RMW_FIELD(ah, ctrl1[i], 195717f6bedSFelix Fietkau AR_PHY_PAPRD_CTRL1_PAPRD_MAG_SCALE_FACT, 361); 196717f6bedSFelix Fietkau REG_RMW_FIELD(ah, ctrl1[i], 197717f6bedSFelix Fietkau AR_PHY_PAPRD_CTRL1_ADAPTIVE_SCALING_ENA, 0); 198717f6bedSFelix Fietkau REG_RMW_FIELD(ah, ctrl0[i], 199717f6bedSFelix Fietkau AR_PHY_PAPRD_CTRL0_PAPRD_MAG_THRSH, 3); 200717f6bedSFelix Fietkau } 201717f6bedSFelix Fietkau 202717f6bedSFelix Fietkau ar9003_paprd_enable(ah, false); 203717f6bedSFelix Fietkau 204*b3a663f0SWenli Looi REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1(ah), 205717f6bedSFelix Fietkau AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_LB_SKIP, 0x30); 206*b3a663f0SWenli Looi REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1(ah), 207717f6bedSFelix Fietkau AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_LB_ENABLE, 1); 208*b3a663f0SWenli Looi REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1(ah), 209717f6bedSFelix Fietkau AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_TX_GAIN_FORCE, 1); 210*b3a663f0SWenli Looi REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1(ah), 211717f6bedSFelix Fietkau AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_RX_BB_GAIN_FORCE, 0); 212*b3a663f0SWenli Looi REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1(ah), 213717f6bedSFelix Fietkau AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_IQCORR_ENABLE, 0); 214*b3a663f0SWenli Looi REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1(ah), 215717f6bedSFelix Fietkau AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_AGC2_SETTLING, 28); 216*b3a663f0SWenli Looi REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1(ah), 217717f6bedSFelix Fietkau AR_PHY_PAPRD_TRAINER_CNTL1_CF_CF_PAPRD_TRAIN_ENABLE, 1); 2188c723e2dSSujith Manoharan 2198c723e2dSSujith Manoharan if (AR_SREV_9485(ah)) { 2208c723e2dSSujith Manoharan val = 148; 2218c723e2dSSujith Manoharan } else { 2228c723e2dSSujith Manoharan if (IS_CHAN_2GHZ(ah->curchan)) { 2238c723e2dSSujith Manoharan if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) 2248c723e2dSSujith Manoharan val = 145; 2258c723e2dSSujith Manoharan else 2268c723e2dSSujith Manoharan val = 147; 2278c723e2dSSujith Manoharan } else { 2288c723e2dSSujith Manoharan val = 137; 2298c723e2dSSujith Manoharan } 2308c723e2dSSujith Manoharan } 2318c723e2dSSujith Manoharan 232*b3a663f0SWenli Looi REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL2(ah), 2332577c6e8SSenthil Balasubramanian AR_PHY_PAPRD_TRAINER_CNTL2_CF_PAPRD_INIT_RX_BB_GAIN, val); 234*b3a663f0SWenli Looi REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3(ah), 235717f6bedSFelix Fietkau AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_FINE_CORR_LEN, 4); 236*b3a663f0SWenli Looi REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3(ah), 237717f6bedSFelix Fietkau AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_COARSE_CORR_LEN, 4); 238*b3a663f0SWenli Looi REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3(ah), 239717f6bedSFelix Fietkau AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_NUM_CORR_STAGES, 7); 240*b3a663f0SWenli Looi REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3(ah), 241717f6bedSFelix Fietkau AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_MIN_LOOPBACK_DEL, 1); 2428c723e2dSSujith Manoharan 2438c723e2dSSujith Manoharan if (AR_SREV_9485(ah) || 2448c723e2dSSujith Manoharan AR_SREV_9462(ah) || 2458c723e2dSSujith Manoharan AR_SREV_9565(ah) || 2468c723e2dSSujith Manoharan AR_SREV_9550(ah) || 2478c723e2dSSujith Manoharan AR_SREV_9330(ah) || 2488c723e2dSSujith Manoharan AR_SREV_9340(ah)) 249*b3a663f0SWenli Looi REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3(ah), 2508c723e2dSSujith Manoharan AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP, -3); 25111441fb8SVasanthakumar Thiagarajan else 252*b3a663f0SWenli Looi REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3(ah), 2538c723e2dSSujith Manoharan AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP, -6); 2548c723e2dSSujith Manoharan 2558c723e2dSSujith Manoharan val = -10; 2568c723e2dSSujith Manoharan 2578c723e2dSSujith Manoharan if (IS_CHAN_2GHZ(ah->curchan) && !AR_SREV_9462(ah) && !AR_SREV_9565(ah)) 2588c723e2dSSujith Manoharan val = -15; 2598c723e2dSSujith Manoharan 260*b3a663f0SWenli Looi REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3(ah), 261717f6bedSFelix Fietkau AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_ADC_DESIRED_SIZE, 2622577c6e8SSenthil Balasubramanian val); 263*b3a663f0SWenli Looi REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3(ah), 264717f6bedSFelix Fietkau AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_BBTXMIX_DISABLE, 1); 265*b3a663f0SWenli Looi REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL4(ah), 266717f6bedSFelix Fietkau AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_SAFETY_DELTA, 0); 267*b3a663f0SWenli Looi REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL4(ah), 268717f6bedSFelix Fietkau AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_MIN_CORR, 400); 269*b3a663f0SWenli Looi REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL4(ah), 270717f6bedSFelix Fietkau AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_NUM_TRAIN_SAMPLES, 271717f6bedSFelix Fietkau 100); 272717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_0_B0, 273717f6bedSFelix Fietkau AR_PHY_PAPRD_PRE_POST_SCALING, 261376); 274717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_1_B0, 275717f6bedSFelix Fietkau AR_PHY_PAPRD_PRE_POST_SCALING, 248079); 276717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_2_B0, 277717f6bedSFelix Fietkau AR_PHY_PAPRD_PRE_POST_SCALING, 233759); 278717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_3_B0, 279717f6bedSFelix Fietkau AR_PHY_PAPRD_PRE_POST_SCALING, 220464); 280717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_4_B0, 281717f6bedSFelix Fietkau AR_PHY_PAPRD_PRE_POST_SCALING, 208194); 282717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_5_B0, 283717f6bedSFelix Fietkau AR_PHY_PAPRD_PRE_POST_SCALING, 196949); 284717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_6_B0, 285717f6bedSFelix Fietkau AR_PHY_PAPRD_PRE_POST_SCALING, 185706); 286717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_7_B0, 287717f6bedSFelix Fietkau AR_PHY_PAPRD_PRE_POST_SCALING, 175487); 2881bf38661SFelix Fietkau return 0; 289717f6bedSFelix Fietkau } 290717f6bedSFelix Fietkau 291717f6bedSFelix Fietkau static void ar9003_paprd_get_gain_table(struct ath_hw *ah) 292717f6bedSFelix Fietkau { 293717f6bedSFelix Fietkau u32 *entry = ah->paprd_gain_table_entries; 294717f6bedSFelix Fietkau u8 *index = ah->paprd_gain_table_index; 295717f6bedSFelix Fietkau u32 reg = AR_PHY_TXGAIN_TABLE; 296717f6bedSFelix Fietkau int i; 297717f6bedSFelix Fietkau 29805b60d4eSMohammed Shafi Shajakhan for (i = 0; i < PAPRD_GAIN_TABLE_ENTRIES; i++) { 299717f6bedSFelix Fietkau entry[i] = REG_READ(ah, reg); 300717f6bedSFelix Fietkau index[i] = (entry[i] >> 24) & 0xff; 301717f6bedSFelix Fietkau reg += 4; 302717f6bedSFelix Fietkau } 303717f6bedSFelix Fietkau } 304717f6bedSFelix Fietkau 305717f6bedSFelix Fietkau static unsigned int ar9003_get_desired_gain(struct ath_hw *ah, int chain, 306717f6bedSFelix Fietkau int target_power) 307717f6bedSFelix Fietkau { 308f68e20f0SMohammed Shafi Shajakhan int olpc_gain_delta = 0, cl_gain_mod; 309717f6bedSFelix Fietkau int alpha_therm, alpha_volt; 310717f6bedSFelix Fietkau int therm_cal_value, volt_cal_value; 311717f6bedSFelix Fietkau int therm_value, volt_value; 312717f6bedSFelix Fietkau int thermal_gain_corr, voltage_gain_corr; 313717f6bedSFelix Fietkau int desired_scale, desired_gain = 0; 314f68e20f0SMohammed Shafi Shajakhan u32 reg_olpc = 0, reg_cl_gain = 0; 315717f6bedSFelix Fietkau 316*b3a663f0SWenli Looi REG_CLR_BIT(ah, AR_PHY_PAPRD_TRAINER_STAT1(ah), 317717f6bedSFelix Fietkau AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE); 318717f6bedSFelix Fietkau desired_scale = REG_READ_FIELD(ah, AR_PHY_TPC_12, 319717f6bedSFelix Fietkau AR_PHY_TPC_12_DESIRED_SCALE_HT40_5); 320717f6bedSFelix Fietkau alpha_therm = REG_READ_FIELD(ah, AR_PHY_TPC_19, 321717f6bedSFelix Fietkau AR_PHY_TPC_19_ALPHA_THERM); 322717f6bedSFelix Fietkau alpha_volt = REG_READ_FIELD(ah, AR_PHY_TPC_19, 323717f6bedSFelix Fietkau AR_PHY_TPC_19_ALPHA_VOLT); 324717f6bedSFelix Fietkau therm_cal_value = REG_READ_FIELD(ah, AR_PHY_TPC_18, 325717f6bedSFelix Fietkau AR_PHY_TPC_18_THERM_CAL_VALUE); 326717f6bedSFelix Fietkau volt_cal_value = REG_READ_FIELD(ah, AR_PHY_TPC_18, 327717f6bedSFelix Fietkau AR_PHY_TPC_18_VOLT_CAL_VALUE); 328717f6bedSFelix Fietkau therm_value = REG_READ_FIELD(ah, AR_PHY_BB_THERM_ADC_4, 329717f6bedSFelix Fietkau AR_PHY_BB_THERM_ADC_4_LATEST_THERM_VALUE); 330717f6bedSFelix Fietkau volt_value = REG_READ_FIELD(ah, AR_PHY_BB_THERM_ADC_4, 331717f6bedSFelix Fietkau AR_PHY_BB_THERM_ADC_4_LATEST_VOLT_VALUE); 332717f6bedSFelix Fietkau 333f68e20f0SMohammed Shafi Shajakhan switch (chain) { 334f68e20f0SMohammed Shafi Shajakhan case 0: 335f68e20f0SMohammed Shafi Shajakhan reg_olpc = AR_PHY_TPC_11_B0; 336f68e20f0SMohammed Shafi Shajakhan reg_cl_gain = AR_PHY_CL_TAB_0; 337f68e20f0SMohammed Shafi Shajakhan break; 338f68e20f0SMohammed Shafi Shajakhan case 1: 339f68e20f0SMohammed Shafi Shajakhan reg_olpc = AR_PHY_TPC_11_B1; 340f68e20f0SMohammed Shafi Shajakhan reg_cl_gain = AR_PHY_CL_TAB_1; 341f68e20f0SMohammed Shafi Shajakhan break; 342f68e20f0SMohammed Shafi Shajakhan case 2: 343f68e20f0SMohammed Shafi Shajakhan reg_olpc = AR_PHY_TPC_11_B2; 344f68e20f0SMohammed Shafi Shajakhan reg_cl_gain = AR_PHY_CL_TAB_2; 345f68e20f0SMohammed Shafi Shajakhan break; 346f68e20f0SMohammed Shafi Shajakhan default: 347d2182b69SJoe Perches ath_dbg(ath9k_hw_common(ah), CALIBRATE, 348f68e20f0SMohammed Shafi Shajakhan "Invalid chainmask: %d\n", chain); 349f68e20f0SMohammed Shafi Shajakhan break; 350f68e20f0SMohammed Shafi Shajakhan } 351717f6bedSFelix Fietkau 352f68e20f0SMohammed Shafi Shajakhan olpc_gain_delta = REG_READ_FIELD(ah, reg_olpc, 353717f6bedSFelix Fietkau AR_PHY_TPC_11_OLPC_GAIN_DELTA); 354f68e20f0SMohammed Shafi Shajakhan cl_gain_mod = REG_READ_FIELD(ah, reg_cl_gain, 355f68e20f0SMohammed Shafi Shajakhan AR_PHY_CL_TAB_CL_GAIN_MOD); 356717f6bedSFelix Fietkau 357717f6bedSFelix Fietkau if (olpc_gain_delta >= 128) 358717f6bedSFelix Fietkau olpc_gain_delta = olpc_gain_delta - 256; 359717f6bedSFelix Fietkau 360717f6bedSFelix Fietkau thermal_gain_corr = (alpha_therm * (therm_value - therm_cal_value) + 361717f6bedSFelix Fietkau (256 / 2)) / 256; 362717f6bedSFelix Fietkau voltage_gain_corr = (alpha_volt * (volt_value - volt_cal_value) + 363717f6bedSFelix Fietkau (128 / 2)) / 128; 364717f6bedSFelix Fietkau desired_gain = target_power - olpc_gain_delta - thermal_gain_corr - 365f68e20f0SMohammed Shafi Shajakhan voltage_gain_corr + desired_scale + cl_gain_mod; 366717f6bedSFelix Fietkau 367717f6bedSFelix Fietkau return desired_gain; 368717f6bedSFelix Fietkau } 369717f6bedSFelix Fietkau 370717f6bedSFelix Fietkau static void ar9003_tx_force_gain(struct ath_hw *ah, unsigned int gain_index) 371717f6bedSFelix Fietkau { 372717f6bedSFelix Fietkau int selected_gain_entry, txbb1dbgain, txbb6dbgain, txmxrgain; 373717f6bedSFelix Fietkau int padrvgnA, padrvgnB, padrvgnC, padrvgnD; 374717f6bedSFelix Fietkau u32 *gain_table_entries = ah->paprd_gain_table_entries; 375717f6bedSFelix Fietkau 376717f6bedSFelix Fietkau selected_gain_entry = gain_table_entries[gain_index]; 377717f6bedSFelix Fietkau txbb1dbgain = selected_gain_entry & 0x7; 378717f6bedSFelix Fietkau txbb6dbgain = (selected_gain_entry >> 3) & 0x3; 379717f6bedSFelix Fietkau txmxrgain = (selected_gain_entry >> 5) & 0xf; 380717f6bedSFelix Fietkau padrvgnA = (selected_gain_entry >> 9) & 0xf; 381717f6bedSFelix Fietkau padrvgnB = (selected_gain_entry >> 13) & 0xf; 382717f6bedSFelix Fietkau padrvgnC = (selected_gain_entry >> 17) & 0xf; 383717f6bedSFelix Fietkau padrvgnD = (selected_gain_entry >> 21) & 0x3; 384717f6bedSFelix Fietkau 385717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN, 386717f6bedSFelix Fietkau AR_PHY_TX_FORCED_GAIN_FORCED_TXBB1DBGAIN, txbb1dbgain); 387717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN, 388717f6bedSFelix Fietkau AR_PHY_TX_FORCED_GAIN_FORCED_TXBB6DBGAIN, txbb6dbgain); 389717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN, 390717f6bedSFelix Fietkau AR_PHY_TX_FORCED_GAIN_FORCED_TXMXRGAIN, txmxrgain); 391717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN, 392717f6bedSFelix Fietkau AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGNA, padrvgnA); 393717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN, 394717f6bedSFelix Fietkau AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGNB, padrvgnB); 395717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN, 396717f6bedSFelix Fietkau AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGNC, padrvgnC); 397717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN, 398717f6bedSFelix Fietkau AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGND, padrvgnD); 399717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN, 400717f6bedSFelix Fietkau AR_PHY_TX_FORCED_GAIN_FORCED_ENABLE_PAL, 0); 401717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN, 402717f6bedSFelix Fietkau AR_PHY_TX_FORCED_GAIN_FORCE_TX_GAIN, 0); 403717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_TPC_1, AR_PHY_TPC_1_FORCED_DAC_GAIN, 0); 404717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_TPC_1, AR_PHY_TPC_1_FORCE_DAC_GAIN, 0); 405717f6bedSFelix Fietkau } 406717f6bedSFelix Fietkau 407717f6bedSFelix Fietkau static inline int find_expn(int num) 408717f6bedSFelix Fietkau { 409717f6bedSFelix Fietkau return fls(num) - 1; 410717f6bedSFelix Fietkau } 411717f6bedSFelix Fietkau 412717f6bedSFelix Fietkau static inline int find_proper_scale(int expn, int N) 413717f6bedSFelix Fietkau { 414717f6bedSFelix Fietkau return (expn > N) ? expn - 10 : 0; 415717f6bedSFelix Fietkau } 416717f6bedSFelix Fietkau 417717f6bedSFelix Fietkau #define NUM_BIN 23 418717f6bedSFelix Fietkau 419717f6bedSFelix Fietkau static bool create_pa_curve(u32 *data_L, u32 *data_U, u32 *pa_table, u16 *gain) 420717f6bedSFelix Fietkau { 421717f6bedSFelix Fietkau unsigned int thresh_accum_cnt; 422717f6bedSFelix Fietkau int x_est[NUM_BIN + 1], Y[NUM_BIN + 1], theta[NUM_BIN + 1]; 423717f6bedSFelix Fietkau int PA_in[NUM_BIN + 1]; 424717f6bedSFelix Fietkau int B1_tmp[NUM_BIN + 1], B2_tmp[NUM_BIN + 1]; 425717f6bedSFelix Fietkau unsigned int B1_abs_max, B2_abs_max; 426717f6bedSFelix Fietkau int max_index, scale_factor; 427717f6bedSFelix Fietkau int y_est[NUM_BIN + 1]; 428717f6bedSFelix Fietkau int x_est_fxp1_nonlin, x_tilde[NUM_BIN + 1]; 429717f6bedSFelix Fietkau unsigned int x_tilde_abs; 430717f6bedSFelix Fietkau int G_fxp, Y_intercept, order_x_by_y, M, I, L, sum_y_sqr, sum_y_quad; 431717f6bedSFelix Fietkau int Q_x, Q_B1, Q_B2, beta_raw, alpha_raw, scale_B; 432717f6bedSFelix Fietkau int Q_scale_B, Q_beta, Q_alpha, alpha, beta, order_1, order_2; 433717f6bedSFelix Fietkau int order1_5x, order2_3x, order1_5x_rem, order2_3x_rem; 434717f6bedSFelix Fietkau int y5, y3, tmp; 435717f6bedSFelix Fietkau int theta_low_bin = 0; 436717f6bedSFelix Fietkau int i; 437717f6bedSFelix Fietkau 438717f6bedSFelix Fietkau /* disregard any bin that contains <= 16 samples */ 439717f6bedSFelix Fietkau thresh_accum_cnt = 16; 440717f6bedSFelix Fietkau scale_factor = 5; 441717f6bedSFelix Fietkau max_index = 0; 442717f6bedSFelix Fietkau memset(theta, 0, sizeof(theta)); 443717f6bedSFelix Fietkau memset(x_est, 0, sizeof(x_est)); 444717f6bedSFelix Fietkau memset(Y, 0, sizeof(Y)); 445717f6bedSFelix Fietkau memset(y_est, 0, sizeof(y_est)); 446717f6bedSFelix Fietkau memset(x_tilde, 0, sizeof(x_tilde)); 447717f6bedSFelix Fietkau 448717f6bedSFelix Fietkau for (i = 0; i < NUM_BIN; i++) { 449717f6bedSFelix Fietkau s32 accum_cnt, accum_tx, accum_rx, accum_ang; 450717f6bedSFelix Fietkau 451717f6bedSFelix Fietkau /* number of samples */ 452717f6bedSFelix Fietkau accum_cnt = data_L[i] & 0xffff; 453717f6bedSFelix Fietkau 454717f6bedSFelix Fietkau if (accum_cnt <= thresh_accum_cnt) 455717f6bedSFelix Fietkau continue; 456717f6bedSFelix Fietkau 4579c8426fcSFelix Fietkau max_index++; 4589c8426fcSFelix Fietkau 459717f6bedSFelix Fietkau /* sum(tx amplitude) */ 460717f6bedSFelix Fietkau accum_tx = ((data_L[i] >> 16) & 0xffff) | 461717f6bedSFelix Fietkau ((data_U[i] & 0x7ff) << 16); 462717f6bedSFelix Fietkau 463717f6bedSFelix Fietkau /* sum(rx amplitude distance to lower bin edge) */ 464717f6bedSFelix Fietkau accum_rx = ((data_U[i] >> 11) & 0x1f) | 465717f6bedSFelix Fietkau ((data_L[i + 23] & 0xffff) << 5); 466717f6bedSFelix Fietkau 467717f6bedSFelix Fietkau /* sum(angles) */ 468717f6bedSFelix Fietkau accum_ang = ((data_L[i + 23] >> 16) & 0xffff) | 469717f6bedSFelix Fietkau ((data_U[i + 23] & 0x7ff) << 16); 470717f6bedSFelix Fietkau 471717f6bedSFelix Fietkau accum_tx <<= scale_factor; 472717f6bedSFelix Fietkau accum_rx <<= scale_factor; 4739c8426fcSFelix Fietkau x_est[max_index] = 4749c8426fcSFelix Fietkau (((accum_tx + accum_cnt) / accum_cnt) + 32) >> 475717f6bedSFelix Fietkau scale_factor; 476717f6bedSFelix Fietkau 4779c8426fcSFelix Fietkau Y[max_index] = 4789c8426fcSFelix Fietkau ((((accum_rx + accum_cnt) / accum_cnt) + 32) >> 479717f6bedSFelix Fietkau scale_factor) + 4809c8426fcSFelix Fietkau (1 << scale_factor) * i + 16; 481717f6bedSFelix Fietkau 482717f6bedSFelix Fietkau if (accum_ang >= (1 << 26)) 483717f6bedSFelix Fietkau accum_ang -= 1 << 27; 484717f6bedSFelix Fietkau 4859c8426fcSFelix Fietkau theta[max_index] = 4869c8426fcSFelix Fietkau ((accum_ang * (1 << scale_factor)) + accum_cnt) / 487717f6bedSFelix Fietkau accum_cnt; 488717f6bedSFelix Fietkau } 489717f6bedSFelix Fietkau 490717f6bedSFelix Fietkau /* 491717f6bedSFelix Fietkau * Find average theta of first 5 bin and all of those to same value. 492717f6bedSFelix Fietkau * Curve is linear at that range. 493717f6bedSFelix Fietkau */ 494717f6bedSFelix Fietkau for (i = 1; i < 6; i++) 495717f6bedSFelix Fietkau theta_low_bin += theta[i]; 496717f6bedSFelix Fietkau 497717f6bedSFelix Fietkau theta_low_bin = theta_low_bin / 5; 498717f6bedSFelix Fietkau for (i = 1; i < 6; i++) 499717f6bedSFelix Fietkau theta[i] = theta_low_bin; 500717f6bedSFelix Fietkau 501717f6bedSFelix Fietkau /* Set values at origin */ 502717f6bedSFelix Fietkau theta[0] = theta_low_bin; 503717f6bedSFelix Fietkau for (i = 0; i <= max_index; i++) 504717f6bedSFelix Fietkau theta[i] -= theta_low_bin; 505717f6bedSFelix Fietkau 506717f6bedSFelix Fietkau x_est[0] = 0; 507717f6bedSFelix Fietkau Y[0] = 0; 508717f6bedSFelix Fietkau scale_factor = 8; 509717f6bedSFelix Fietkau 510717f6bedSFelix Fietkau /* low signal gain */ 511717f6bedSFelix Fietkau if (x_est[6] == x_est[3]) 512717f6bedSFelix Fietkau return false; 513717f6bedSFelix Fietkau 514717f6bedSFelix Fietkau G_fxp = 515717f6bedSFelix Fietkau (((Y[6] - Y[3]) * 1 << scale_factor) + 516717f6bedSFelix Fietkau (x_est[6] - x_est[3])) / (x_est[6] - x_est[3]); 517717f6bedSFelix Fietkau 5182d3fca18SSenthil Balasubramanian /* prevent division by zero */ 5192d3fca18SSenthil Balasubramanian if (G_fxp == 0) 5202d3fca18SSenthil Balasubramanian return false; 5212d3fca18SSenthil Balasubramanian 522717f6bedSFelix Fietkau Y_intercept = 523717f6bedSFelix Fietkau (G_fxp * (x_est[0] - x_est[3]) + 524717f6bedSFelix Fietkau (1 << scale_factor)) / (1 << scale_factor) + Y[3]; 525717f6bedSFelix Fietkau 526717f6bedSFelix Fietkau for (i = 0; i <= max_index; i++) 527717f6bedSFelix Fietkau y_est[i] = Y[i] - Y_intercept; 528717f6bedSFelix Fietkau 529717f6bedSFelix Fietkau for (i = 0; i <= 3; i++) { 530717f6bedSFelix Fietkau y_est[i] = i * 32; 531717f6bedSFelix Fietkau x_est[i] = ((y_est[i] * 1 << scale_factor) + G_fxp) / G_fxp; 532717f6bedSFelix Fietkau } 533717f6bedSFelix Fietkau 5342d3fca18SSenthil Balasubramanian if (y_est[max_index] == 0) 5352d3fca18SSenthil Balasubramanian return false; 5362d3fca18SSenthil Balasubramanian 537717f6bedSFelix Fietkau x_est_fxp1_nonlin = 538717f6bedSFelix Fietkau x_est[max_index] - ((1 << scale_factor) * y_est[max_index] + 539717f6bedSFelix Fietkau G_fxp) / G_fxp; 540717f6bedSFelix Fietkau 541717f6bedSFelix Fietkau order_x_by_y = 542717f6bedSFelix Fietkau (x_est_fxp1_nonlin + y_est[max_index]) / y_est[max_index]; 543717f6bedSFelix Fietkau 544717f6bedSFelix Fietkau if (order_x_by_y == 0) 545717f6bedSFelix Fietkau M = 10; 546717f6bedSFelix Fietkau else if (order_x_by_y == 1) 547717f6bedSFelix Fietkau M = 9; 548717f6bedSFelix Fietkau else 549717f6bedSFelix Fietkau M = 8; 550717f6bedSFelix Fietkau 551717f6bedSFelix Fietkau I = (max_index > 15) ? 7 : max_index >> 1; 552717f6bedSFelix Fietkau L = max_index - I; 553717f6bedSFelix Fietkau scale_factor = 8; 554717f6bedSFelix Fietkau sum_y_sqr = 0; 555717f6bedSFelix Fietkau sum_y_quad = 0; 556717f6bedSFelix Fietkau x_tilde_abs = 0; 557717f6bedSFelix Fietkau 558717f6bedSFelix Fietkau for (i = 0; i <= L; i++) { 559717f6bedSFelix Fietkau unsigned int y_sqr; 560717f6bedSFelix Fietkau unsigned int y_quad; 561717f6bedSFelix Fietkau unsigned int tmp_abs; 562717f6bedSFelix Fietkau 563717f6bedSFelix Fietkau /* prevent division by zero */ 564717f6bedSFelix Fietkau if (y_est[i + I] == 0) 565717f6bedSFelix Fietkau return false; 566717f6bedSFelix Fietkau 567717f6bedSFelix Fietkau x_est_fxp1_nonlin = 568717f6bedSFelix Fietkau x_est[i + I] - ((1 << scale_factor) * y_est[i + I] + 569717f6bedSFelix Fietkau G_fxp) / G_fxp; 570717f6bedSFelix Fietkau 571717f6bedSFelix Fietkau x_tilde[i] = 572717f6bedSFelix Fietkau (x_est_fxp1_nonlin * (1 << M) + y_est[i + I]) / y_est[i + 573717f6bedSFelix Fietkau I]; 574717f6bedSFelix Fietkau x_tilde[i] = 575717f6bedSFelix Fietkau (x_tilde[i] * (1 << M) + y_est[i + I]) / y_est[i + I]; 576717f6bedSFelix Fietkau x_tilde[i] = 577717f6bedSFelix Fietkau (x_tilde[i] * (1 << M) + y_est[i + I]) / y_est[i + I]; 578717f6bedSFelix Fietkau y_sqr = 579717f6bedSFelix Fietkau (y_est[i + I] * y_est[i + I] + 580717f6bedSFelix Fietkau (scale_factor * scale_factor)) / (scale_factor * 581717f6bedSFelix Fietkau scale_factor); 582717f6bedSFelix Fietkau tmp_abs = abs(x_tilde[i]); 583717f6bedSFelix Fietkau if (tmp_abs > x_tilde_abs) 584717f6bedSFelix Fietkau x_tilde_abs = tmp_abs; 585717f6bedSFelix Fietkau 586717f6bedSFelix Fietkau y_quad = y_sqr * y_sqr; 587717f6bedSFelix Fietkau sum_y_sqr = sum_y_sqr + y_sqr; 588717f6bedSFelix Fietkau sum_y_quad = sum_y_quad + y_quad; 589717f6bedSFelix Fietkau B1_tmp[i] = y_sqr * (L + 1); 590717f6bedSFelix Fietkau B2_tmp[i] = y_sqr; 591717f6bedSFelix Fietkau } 592717f6bedSFelix Fietkau 593717f6bedSFelix Fietkau B1_abs_max = 0; 594717f6bedSFelix Fietkau B2_abs_max = 0; 595717f6bedSFelix Fietkau for (i = 0; i <= L; i++) { 596717f6bedSFelix Fietkau int abs_val; 597717f6bedSFelix Fietkau 598717f6bedSFelix Fietkau B1_tmp[i] -= sum_y_sqr; 599717f6bedSFelix Fietkau B2_tmp[i] = sum_y_quad - sum_y_sqr * B2_tmp[i]; 600717f6bedSFelix Fietkau 601717f6bedSFelix Fietkau abs_val = abs(B1_tmp[i]); 602717f6bedSFelix Fietkau if (abs_val > B1_abs_max) 603717f6bedSFelix Fietkau B1_abs_max = abs_val; 604717f6bedSFelix Fietkau 605717f6bedSFelix Fietkau abs_val = abs(B2_tmp[i]); 606717f6bedSFelix Fietkau if (abs_val > B2_abs_max) 607717f6bedSFelix Fietkau B2_abs_max = abs_val; 608717f6bedSFelix Fietkau } 609717f6bedSFelix Fietkau 610717f6bedSFelix Fietkau Q_x = find_proper_scale(find_expn(x_tilde_abs), 10); 611717f6bedSFelix Fietkau Q_B1 = find_proper_scale(find_expn(B1_abs_max), 10); 612717f6bedSFelix Fietkau Q_B2 = find_proper_scale(find_expn(B2_abs_max), 10); 613717f6bedSFelix Fietkau 614717f6bedSFelix Fietkau beta_raw = 0; 615717f6bedSFelix Fietkau alpha_raw = 0; 616717f6bedSFelix Fietkau for (i = 0; i <= L; i++) { 617717f6bedSFelix Fietkau x_tilde[i] = x_tilde[i] / (1 << Q_x); 618717f6bedSFelix Fietkau B1_tmp[i] = B1_tmp[i] / (1 << Q_B1); 619717f6bedSFelix Fietkau B2_tmp[i] = B2_tmp[i] / (1 << Q_B2); 620717f6bedSFelix Fietkau beta_raw = beta_raw + B1_tmp[i] * x_tilde[i]; 621717f6bedSFelix Fietkau alpha_raw = alpha_raw + B2_tmp[i] * x_tilde[i]; 622717f6bedSFelix Fietkau } 623717f6bedSFelix Fietkau 624717f6bedSFelix Fietkau scale_B = 625717f6bedSFelix Fietkau ((sum_y_quad / scale_factor) * (L + 1) - 626717f6bedSFelix Fietkau (sum_y_sqr / scale_factor) * sum_y_sqr) * scale_factor; 627717f6bedSFelix Fietkau 628717f6bedSFelix Fietkau Q_scale_B = find_proper_scale(find_expn(abs(scale_B)), 10); 629717f6bedSFelix Fietkau scale_B = scale_B / (1 << Q_scale_B); 6302d3fca18SSenthil Balasubramanian if (scale_B == 0) 6312d3fca18SSenthil Balasubramanian return false; 632717f6bedSFelix Fietkau Q_beta = find_proper_scale(find_expn(abs(beta_raw)), 10); 633717f6bedSFelix Fietkau Q_alpha = find_proper_scale(find_expn(abs(alpha_raw)), 10); 634717f6bedSFelix Fietkau beta_raw = beta_raw / (1 << Q_beta); 635717f6bedSFelix Fietkau alpha_raw = alpha_raw / (1 << Q_alpha); 636717f6bedSFelix Fietkau alpha = (alpha_raw << 10) / scale_B; 637717f6bedSFelix Fietkau beta = (beta_raw << 10) / scale_B; 638717f6bedSFelix Fietkau order_1 = 3 * M - Q_x - Q_B1 - Q_beta + 10 + Q_scale_B; 639717f6bedSFelix Fietkau order_2 = 3 * M - Q_x - Q_B2 - Q_alpha + 10 + Q_scale_B; 640717f6bedSFelix Fietkau order1_5x = order_1 / 5; 641717f6bedSFelix Fietkau order2_3x = order_2 / 3; 642717f6bedSFelix Fietkau order1_5x_rem = order_1 - 5 * order1_5x; 643717f6bedSFelix Fietkau order2_3x_rem = order_2 - 3 * order2_3x; 644717f6bedSFelix Fietkau 645717f6bedSFelix Fietkau for (i = 0; i < PAPRD_TABLE_SZ; i++) { 646717f6bedSFelix Fietkau tmp = i * 32; 647717f6bedSFelix Fietkau y5 = ((beta * tmp) >> 6) >> order1_5x; 648717f6bedSFelix Fietkau y5 = (y5 * tmp) >> order1_5x; 649717f6bedSFelix Fietkau y5 = (y5 * tmp) >> order1_5x; 650717f6bedSFelix Fietkau y5 = (y5 * tmp) >> order1_5x; 651717f6bedSFelix Fietkau y5 = (y5 * tmp) >> order1_5x; 652717f6bedSFelix Fietkau y5 = y5 >> order1_5x_rem; 653717f6bedSFelix Fietkau y3 = (alpha * tmp) >> order2_3x; 654717f6bedSFelix Fietkau y3 = (y3 * tmp) >> order2_3x; 655717f6bedSFelix Fietkau y3 = (y3 * tmp) >> order2_3x; 656717f6bedSFelix Fietkau y3 = y3 >> order2_3x_rem; 657717f6bedSFelix Fietkau PA_in[i] = y5 + y3 + (256 * tmp) / G_fxp; 658717f6bedSFelix Fietkau 659717f6bedSFelix Fietkau if (i >= 2) { 660717f6bedSFelix Fietkau tmp = PA_in[i] - PA_in[i - 1]; 661717f6bedSFelix Fietkau if (tmp < 0) 662717f6bedSFelix Fietkau PA_in[i] = 663717f6bedSFelix Fietkau PA_in[i - 1] + (PA_in[i - 1] - 664717f6bedSFelix Fietkau PA_in[i - 2]); 665717f6bedSFelix Fietkau } 666717f6bedSFelix Fietkau 667717f6bedSFelix Fietkau PA_in[i] = (PA_in[i] < 1400) ? PA_in[i] : 1400; 668717f6bedSFelix Fietkau } 669717f6bedSFelix Fietkau 670717f6bedSFelix Fietkau beta_raw = 0; 671717f6bedSFelix Fietkau alpha_raw = 0; 672717f6bedSFelix Fietkau 673717f6bedSFelix Fietkau for (i = 0; i <= L; i++) { 674717f6bedSFelix Fietkau int theta_tilde = 675717f6bedSFelix Fietkau ((theta[i + I] << M) + y_est[i + I]) / y_est[i + I]; 676717f6bedSFelix Fietkau theta_tilde = 677717f6bedSFelix Fietkau ((theta_tilde << M) + y_est[i + I]) / y_est[i + I]; 678717f6bedSFelix Fietkau theta_tilde = 679717f6bedSFelix Fietkau ((theta_tilde << M) + y_est[i + I]) / y_est[i + I]; 680717f6bedSFelix Fietkau beta_raw = beta_raw + B1_tmp[i] * theta_tilde; 681717f6bedSFelix Fietkau alpha_raw = alpha_raw + B2_tmp[i] * theta_tilde; 682717f6bedSFelix Fietkau } 683717f6bedSFelix Fietkau 684717f6bedSFelix Fietkau Q_beta = find_proper_scale(find_expn(abs(beta_raw)), 10); 685717f6bedSFelix Fietkau Q_alpha = find_proper_scale(find_expn(abs(alpha_raw)), 10); 686717f6bedSFelix Fietkau beta_raw = beta_raw / (1 << Q_beta); 687717f6bedSFelix Fietkau alpha_raw = alpha_raw / (1 << Q_alpha); 688717f6bedSFelix Fietkau 689717f6bedSFelix Fietkau alpha = (alpha_raw << 10) / scale_B; 690717f6bedSFelix Fietkau beta = (beta_raw << 10) / scale_B; 691717f6bedSFelix Fietkau order_1 = 3 * M - Q_x - Q_B1 - Q_beta + 10 + Q_scale_B + 5; 692717f6bedSFelix Fietkau order_2 = 3 * M - Q_x - Q_B2 - Q_alpha + 10 + Q_scale_B + 5; 693717f6bedSFelix Fietkau order1_5x = order_1 / 5; 694717f6bedSFelix Fietkau order2_3x = order_2 / 3; 695717f6bedSFelix Fietkau order1_5x_rem = order_1 - 5 * order1_5x; 696717f6bedSFelix Fietkau order2_3x_rem = order_2 - 3 * order2_3x; 697717f6bedSFelix Fietkau 698717f6bedSFelix Fietkau for (i = 0; i < PAPRD_TABLE_SZ; i++) { 699717f6bedSFelix Fietkau int PA_angle; 700717f6bedSFelix Fietkau 701717f6bedSFelix Fietkau /* pa_table[4] is calculated from PA_angle for i=5 */ 702717f6bedSFelix Fietkau if (i == 4) 703717f6bedSFelix Fietkau continue; 704717f6bedSFelix Fietkau 705717f6bedSFelix Fietkau tmp = i * 32; 706717f6bedSFelix Fietkau if (beta > 0) 707717f6bedSFelix Fietkau y5 = (((beta * tmp - 64) >> 6) - 708717f6bedSFelix Fietkau (1 << order1_5x)) / (1 << order1_5x); 709717f6bedSFelix Fietkau else 710717f6bedSFelix Fietkau y5 = ((((beta * tmp - 64) >> 6) + 711717f6bedSFelix Fietkau (1 << order1_5x)) / (1 << order1_5x)); 712717f6bedSFelix Fietkau 713717f6bedSFelix Fietkau y5 = (y5 * tmp) / (1 << order1_5x); 714717f6bedSFelix Fietkau y5 = (y5 * tmp) / (1 << order1_5x); 715717f6bedSFelix Fietkau y5 = (y5 * tmp) / (1 << order1_5x); 716717f6bedSFelix Fietkau y5 = (y5 * tmp) / (1 << order1_5x); 717717f6bedSFelix Fietkau y5 = y5 / (1 << order1_5x_rem); 718717f6bedSFelix Fietkau 719717f6bedSFelix Fietkau if (beta > 0) 720717f6bedSFelix Fietkau y3 = (alpha * tmp - 721717f6bedSFelix Fietkau (1 << order2_3x)) / (1 << order2_3x); 722717f6bedSFelix Fietkau else 723717f6bedSFelix Fietkau y3 = (alpha * tmp + 724717f6bedSFelix Fietkau (1 << order2_3x)) / (1 << order2_3x); 725717f6bedSFelix Fietkau y3 = (y3 * tmp) / (1 << order2_3x); 726717f6bedSFelix Fietkau y3 = (y3 * tmp) / (1 << order2_3x); 727717f6bedSFelix Fietkau y3 = y3 / (1 << order2_3x_rem); 728717f6bedSFelix Fietkau 729717f6bedSFelix Fietkau if (i < 4) { 730717f6bedSFelix Fietkau PA_angle = 0; 731717f6bedSFelix Fietkau } else { 732717f6bedSFelix Fietkau PA_angle = y5 + y3; 733717f6bedSFelix Fietkau if (PA_angle < -150) 734717f6bedSFelix Fietkau PA_angle = -150; 735717f6bedSFelix Fietkau else if (PA_angle > 150) 736717f6bedSFelix Fietkau PA_angle = 150; 737717f6bedSFelix Fietkau } 738717f6bedSFelix Fietkau 739717f6bedSFelix Fietkau pa_table[i] = ((PA_in[i] & 0x7ff) << 11) + (PA_angle & 0x7ff); 740717f6bedSFelix Fietkau if (i == 5) { 741717f6bedSFelix Fietkau PA_angle = (PA_angle + 2) >> 1; 742717f6bedSFelix Fietkau pa_table[i - 1] = ((PA_in[i - 1] & 0x7ff) << 11) + 743717f6bedSFelix Fietkau (PA_angle & 0x7ff); 744717f6bedSFelix Fietkau } 745717f6bedSFelix Fietkau } 746717f6bedSFelix Fietkau 747717f6bedSFelix Fietkau *gain = G_fxp; 748717f6bedSFelix Fietkau return true; 749717f6bedSFelix Fietkau } 750717f6bedSFelix Fietkau 751717f6bedSFelix Fietkau void ar9003_paprd_populate_single_table(struct ath_hw *ah, 75220bd2a09SFelix Fietkau struct ath9k_hw_cal_data *caldata, 75320bd2a09SFelix Fietkau int chain) 754717f6bedSFelix Fietkau { 75520bd2a09SFelix Fietkau u32 *paprd_table_val = caldata->pa_table[chain]; 75620bd2a09SFelix Fietkau u32 small_signal_gain = caldata->small_signal_gain[chain]; 7571bf38661SFelix Fietkau u32 training_power = ah->paprd_training_power; 758717f6bedSFelix Fietkau u32 reg = 0; 759717f6bedSFelix Fietkau int i; 760717f6bedSFelix Fietkau 761717f6bedSFelix Fietkau if (chain == 0) 762717f6bedSFelix Fietkau reg = AR_PHY_PAPRD_MEM_TAB_B0; 763717f6bedSFelix Fietkau else if (chain == 1) 764717f6bedSFelix Fietkau reg = AR_PHY_PAPRD_MEM_TAB_B1; 765717f6bedSFelix Fietkau else if (chain == 2) 766717f6bedSFelix Fietkau reg = AR_PHY_PAPRD_MEM_TAB_B2; 767717f6bedSFelix Fietkau 768717f6bedSFelix Fietkau for (i = 0; i < PAPRD_TABLE_SZ; i++) { 769717f6bedSFelix Fietkau REG_WRITE(ah, reg, paprd_table_val[i]); 770717f6bedSFelix Fietkau reg = reg + 4; 771717f6bedSFelix Fietkau } 772717f6bedSFelix Fietkau 773717f6bedSFelix Fietkau if (chain == 0) 774717f6bedSFelix Fietkau reg = AR_PHY_PA_GAIN123_B0; 775717f6bedSFelix Fietkau else if (chain == 1) 776717f6bedSFelix Fietkau reg = AR_PHY_PA_GAIN123_B1; 777717f6bedSFelix Fietkau else 778717f6bedSFelix Fietkau reg = AR_PHY_PA_GAIN123_B2; 779717f6bedSFelix Fietkau 780717f6bedSFelix Fietkau REG_RMW_FIELD(ah, reg, AR_PHY_PA_GAIN123_PA_GAIN1, small_signal_gain); 781717f6bedSFelix Fietkau 782717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL1_B0, 783717f6bedSFelix Fietkau AR_PHY_PAPRD_CTRL1_PAPRD_POWER_AT_AM2AM_CAL, 784717f6bedSFelix Fietkau training_power); 785717f6bedSFelix Fietkau 78611441fb8SVasanthakumar Thiagarajan if (ah->caps.tx_chainmask & BIT(1)) 787717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL1_B1, 788717f6bedSFelix Fietkau AR_PHY_PAPRD_CTRL1_PAPRD_POWER_AT_AM2AM_CAL, 789717f6bedSFelix Fietkau training_power); 790717f6bedSFelix Fietkau 79111441fb8SVasanthakumar Thiagarajan if (ah->caps.tx_chainmask & BIT(2)) 7922577c6e8SSenthil Balasubramanian /* val AR_PHY_PAPRD_CTRL1_PAPRD_POWER_AT_AM2AM_CAL correct? */ 793717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL1_B2, 794717f6bedSFelix Fietkau AR_PHY_PAPRD_CTRL1_PAPRD_POWER_AT_AM2AM_CAL, 795717f6bedSFelix Fietkau training_power); 796717f6bedSFelix Fietkau } 797717f6bedSFelix Fietkau EXPORT_SYMBOL(ar9003_paprd_populate_single_table); 798717f6bedSFelix Fietkau 79936d2943bSSujith Manoharan void ar9003_paprd_setup_gain_table(struct ath_hw *ah, int chain) 800717f6bedSFelix Fietkau { 801717f6bedSFelix Fietkau unsigned int i, desired_gain, gain_index; 8021bf38661SFelix Fietkau unsigned int train_power = ah->paprd_training_power; 803717f6bedSFelix Fietkau 804717f6bedSFelix Fietkau desired_gain = ar9003_get_desired_gain(ah, chain, train_power); 805717f6bedSFelix Fietkau 806717f6bedSFelix Fietkau gain_index = 0; 80705b60d4eSMohammed Shafi Shajakhan for (i = 0; i < PAPRD_GAIN_TABLE_ENTRIES; i++) { 808717f6bedSFelix Fietkau if (ah->paprd_gain_table_index[i] >= desired_gain) 809717f6bedSFelix Fietkau break; 810717f6bedSFelix Fietkau gain_index++; 811717f6bedSFelix Fietkau } 812717f6bedSFelix Fietkau 813717f6bedSFelix Fietkau ar9003_tx_force_gain(ah, gain_index); 814717f6bedSFelix Fietkau 815*b3a663f0SWenli Looi REG_CLR_BIT(ah, AR_PHY_PAPRD_TRAINER_STAT1(ah), 816717f6bedSFelix Fietkau AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE); 817717f6bedSFelix Fietkau } 818717f6bedSFelix Fietkau EXPORT_SYMBOL(ar9003_paprd_setup_gain_table); 819717f6bedSFelix Fietkau 820381c726cSFelix Fietkau static bool ar9003_paprd_retrain_pa_in(struct ath_hw *ah, 821381c726cSFelix Fietkau struct ath9k_hw_cal_data *caldata, 822381c726cSFelix Fietkau int chain) 823381c726cSFelix Fietkau { 824381c726cSFelix Fietkau u32 *pa_in = caldata->pa_table[chain]; 825381c726cSFelix Fietkau int capdiv_offset, quick_drop_offset; 826381c726cSFelix Fietkau int capdiv2g, quick_drop; 827381c726cSFelix Fietkau int count = 0; 828381c726cSFelix Fietkau int i; 829381c726cSFelix Fietkau 830381c726cSFelix Fietkau if (!AR_SREV_9485(ah) && !AR_SREV_9330(ah)) 831381c726cSFelix Fietkau return false; 832381c726cSFelix Fietkau 833381c726cSFelix Fietkau capdiv2g = REG_READ_FIELD(ah, AR_PHY_65NM_CH0_TXRF3, 834381c726cSFelix Fietkau AR_PHY_65NM_CH0_TXRF3_CAPDIV2G); 835381c726cSFelix Fietkau 836*b3a663f0SWenli Looi quick_drop = REG_READ_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3(ah), 837381c726cSFelix Fietkau AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP); 838381c726cSFelix Fietkau 839381c726cSFelix Fietkau if (quick_drop) 840381c726cSFelix Fietkau quick_drop -= 0x40; 841381c726cSFelix Fietkau 842381c726cSFelix Fietkau for (i = 0; i < NUM_BIN + 1; i++) { 843381c726cSFelix Fietkau if (pa_in[i] == 1400) 844381c726cSFelix Fietkau count++; 845381c726cSFelix Fietkau } 846381c726cSFelix Fietkau 847381c726cSFelix Fietkau if (AR_SREV_9485(ah)) { 848381c726cSFelix Fietkau if (pa_in[23] < 800) { 849381c726cSFelix Fietkau capdiv_offset = (int)((1000 - pa_in[23] + 75) / 150); 850381c726cSFelix Fietkau capdiv2g += capdiv_offset; 851381c726cSFelix Fietkau if (capdiv2g > 7) { 852381c726cSFelix Fietkau capdiv2g = 7; 853381c726cSFelix Fietkau if (pa_in[23] < 600) { 854381c726cSFelix Fietkau quick_drop++; 855381c726cSFelix Fietkau if (quick_drop > 0) 856381c726cSFelix Fietkau quick_drop = 0; 857381c726cSFelix Fietkau } 858381c726cSFelix Fietkau } 859381c726cSFelix Fietkau } else if (pa_in[23] == 1400) { 860381c726cSFelix Fietkau quick_drop_offset = min_t(int, count / 3, 2); 861381c726cSFelix Fietkau quick_drop += quick_drop_offset; 862381c726cSFelix Fietkau capdiv2g += quick_drop_offset / 2; 863381c726cSFelix Fietkau 864381c726cSFelix Fietkau if (capdiv2g > 7) 865381c726cSFelix Fietkau capdiv2g = 7; 866381c726cSFelix Fietkau 867381c726cSFelix Fietkau if (quick_drop > 0) { 868381c726cSFelix Fietkau quick_drop = 0; 869381c726cSFelix Fietkau capdiv2g -= quick_drop_offset; 870381c726cSFelix Fietkau if (capdiv2g < 0) 871381c726cSFelix Fietkau capdiv2g = 0; 872381c726cSFelix Fietkau } 873381c726cSFelix Fietkau } else { 874381c726cSFelix Fietkau return false; 875381c726cSFelix Fietkau } 876381c726cSFelix Fietkau } else if (AR_SREV_9330(ah)) { 877381c726cSFelix Fietkau if (pa_in[23] < 1000) { 878381c726cSFelix Fietkau capdiv_offset = (1000 - pa_in[23]) / 100; 879381c726cSFelix Fietkau capdiv2g += capdiv_offset; 880381c726cSFelix Fietkau if (capdiv_offset > 3) { 881381c726cSFelix Fietkau capdiv_offset = 1; 882381c726cSFelix Fietkau quick_drop--; 883381c726cSFelix Fietkau } 884381c726cSFelix Fietkau 885381c726cSFelix Fietkau capdiv2g += capdiv_offset; 886381c726cSFelix Fietkau if (capdiv2g > 6) 887381c726cSFelix Fietkau capdiv2g = 6; 888381c726cSFelix Fietkau if (quick_drop < -4) 889381c726cSFelix Fietkau quick_drop = -4; 890381c726cSFelix Fietkau } else if (pa_in[23] == 1400) { 891381c726cSFelix Fietkau if (count > 3) { 892381c726cSFelix Fietkau quick_drop++; 893381c726cSFelix Fietkau capdiv2g -= count / 4; 894381c726cSFelix Fietkau if (quick_drop > -2) 895381c726cSFelix Fietkau quick_drop = -2; 896381c726cSFelix Fietkau } else { 897381c726cSFelix Fietkau capdiv2g--; 898381c726cSFelix Fietkau } 899381c726cSFelix Fietkau 900381c726cSFelix Fietkau if (capdiv2g < 0) 901381c726cSFelix Fietkau capdiv2g = 0; 902381c726cSFelix Fietkau } else { 903381c726cSFelix Fietkau return false; 904381c726cSFelix Fietkau } 905381c726cSFelix Fietkau } 906381c726cSFelix Fietkau 907381c726cSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_TXRF3, 908381c726cSFelix Fietkau AR_PHY_65NM_CH0_TXRF3_CAPDIV2G, capdiv2g); 909*b3a663f0SWenli Looi REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3(ah), 910381c726cSFelix Fietkau AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP, 911381c726cSFelix Fietkau quick_drop); 912381c726cSFelix Fietkau 913381c726cSFelix Fietkau return true; 914381c726cSFelix Fietkau } 915381c726cSFelix Fietkau 91620bd2a09SFelix Fietkau int ar9003_paprd_create_curve(struct ath_hw *ah, 91720bd2a09SFelix Fietkau struct ath9k_hw_cal_data *caldata, int chain) 918717f6bedSFelix Fietkau { 91920bd2a09SFelix Fietkau u16 *small_signal_gain = &caldata->small_signal_gain[chain]; 92020bd2a09SFelix Fietkau u32 *pa_table = caldata->pa_table[chain]; 921717f6bedSFelix Fietkau u32 *data_L, *data_U; 922717f6bedSFelix Fietkau int i, status = 0; 923717f6bedSFelix Fietkau u32 *buf; 924717f6bedSFelix Fietkau u32 reg; 925717f6bedSFelix Fietkau 92620bd2a09SFelix Fietkau memset(caldata->pa_table[chain], 0, sizeof(caldata->pa_table[chain])); 927717f6bedSFelix Fietkau 9286da2ec56SKees Cook buf = kmalloc_array(2 * 48, sizeof(u32), GFP_KERNEL); 929717f6bedSFelix Fietkau if (!buf) 930717f6bedSFelix Fietkau return -ENOMEM; 931717f6bedSFelix Fietkau 932717f6bedSFelix Fietkau data_L = &buf[0]; 933717f6bedSFelix Fietkau data_U = &buf[48]; 934717f6bedSFelix Fietkau 935*b3a663f0SWenli Looi REG_CLR_BIT(ah, AR_PHY_CHAN_INFO_MEMORY(ah), 936717f6bedSFelix Fietkau AR_PHY_CHAN_INFO_MEMORY_CHANINFOMEM_S2_READ); 937717f6bedSFelix Fietkau 938717f6bedSFelix Fietkau reg = AR_PHY_CHAN_INFO_TAB_0; 939717f6bedSFelix Fietkau for (i = 0; i < 48; i++) 940717f6bedSFelix Fietkau data_L[i] = REG_READ(ah, reg + (i << 2)); 941717f6bedSFelix Fietkau 942*b3a663f0SWenli Looi REG_SET_BIT(ah, AR_PHY_CHAN_INFO_MEMORY(ah), 943717f6bedSFelix Fietkau AR_PHY_CHAN_INFO_MEMORY_CHANINFOMEM_S2_READ); 944717f6bedSFelix Fietkau 945717f6bedSFelix Fietkau for (i = 0; i < 48; i++) 946717f6bedSFelix Fietkau data_U[i] = REG_READ(ah, reg + (i << 2)); 947717f6bedSFelix Fietkau 948717f6bedSFelix Fietkau if (!create_pa_curve(data_L, data_U, pa_table, small_signal_gain)) 949717f6bedSFelix Fietkau status = -2; 950717f6bedSFelix Fietkau 951381c726cSFelix Fietkau if (ar9003_paprd_retrain_pa_in(ah, caldata, chain)) 952381c726cSFelix Fietkau status = -EINPROGRESS; 953381c726cSFelix Fietkau 954*b3a663f0SWenli Looi REG_CLR_BIT(ah, AR_PHY_PAPRD_TRAINER_STAT1(ah), 955717f6bedSFelix Fietkau AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE); 956717f6bedSFelix Fietkau 957717f6bedSFelix Fietkau kfree(buf); 958717f6bedSFelix Fietkau 959717f6bedSFelix Fietkau return status; 960717f6bedSFelix Fietkau } 961717f6bedSFelix Fietkau EXPORT_SYMBOL(ar9003_paprd_create_curve); 962717f6bedSFelix Fietkau 963717f6bedSFelix Fietkau int ar9003_paprd_init_table(struct ath_hw *ah) 964717f6bedSFelix Fietkau { 9651bf38661SFelix Fietkau int ret; 9661bf38661SFelix Fietkau 9671bf38661SFelix Fietkau ret = ar9003_paprd_setup_single_table(ah); 9681bf38661SFelix Fietkau if (ret < 0) 9691bf38661SFelix Fietkau return ret; 9701bf38661SFelix Fietkau 971717f6bedSFelix Fietkau ar9003_paprd_get_gain_table(ah); 972717f6bedSFelix Fietkau return 0; 973717f6bedSFelix Fietkau } 974717f6bedSFelix Fietkau EXPORT_SYMBOL(ar9003_paprd_init_table); 975717f6bedSFelix Fietkau 976717f6bedSFelix Fietkau bool ar9003_paprd_is_done(struct ath_hw *ah) 977717f6bedSFelix Fietkau { 9780e44d48cSMohammed Shafi Shajakhan int paprd_done, agc2_pwr; 979d882d242SSujith Manoharan 980*b3a663f0SWenli Looi paprd_done = REG_READ_FIELD(ah, AR_PHY_PAPRD_TRAINER_STAT1(ah), 981717f6bedSFelix Fietkau AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE); 9820e44d48cSMohammed Shafi Shajakhan 983d882d242SSujith Manoharan if (AR_SREV_9485(ah)) 984d882d242SSujith Manoharan goto exit; 985d882d242SSujith Manoharan 9860e44d48cSMohammed Shafi Shajakhan if (paprd_done == 0x1) { 987*b3a663f0SWenli Looi agc2_pwr = REG_READ_FIELD(ah, AR_PHY_PAPRD_TRAINER_STAT1(ah), 9880e44d48cSMohammed Shafi Shajakhan AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_AGC2_PWR); 9890e44d48cSMohammed Shafi Shajakhan 990d2182b69SJoe Perches ath_dbg(ath9k_hw_common(ah), CALIBRATE, 9910e44d48cSMohammed Shafi Shajakhan "AGC2_PWR = 0x%x training done = 0x%x\n", 9920e44d48cSMohammed Shafi Shajakhan agc2_pwr, paprd_done); 9930e44d48cSMohammed Shafi Shajakhan /* 9940e44d48cSMohammed Shafi Shajakhan * agc2_pwr range should not be less than 'IDEAL_AGC2_PWR_CHANGE' 9950e44d48cSMohammed Shafi Shajakhan * when the training is completely done, otherwise retraining is 9960e44d48cSMohammed Shafi Shajakhan * done to make sure the value is in ideal range 9970e44d48cSMohammed Shafi Shajakhan */ 9980e44d48cSMohammed Shafi Shajakhan if (agc2_pwr <= PAPRD_IDEAL_AGC2_PWR_RANGE) 9990e44d48cSMohammed Shafi Shajakhan paprd_done = 0; 10000e44d48cSMohammed Shafi Shajakhan } 1001d882d242SSujith Manoharan exit: 10020e44d48cSMohammed Shafi Shajakhan return !!paprd_done; 1003717f6bedSFelix Fietkau } 1004717f6bedSFelix Fietkau EXPORT_SYMBOL(ar9003_paprd_is_done); 10050f21ee8dSSujith Manoharan 10060f21ee8dSSujith Manoharan bool ar9003_is_paprd_enabled(struct ath_hw *ah) 10070f21ee8dSSujith Manoharan { 10080f21ee8dSSujith Manoharan if ((ah->caps.hw_caps & ATH9K_HW_CAP_PAPRD) && ah->config.enable_paprd) 10090f21ee8dSSujith Manoharan return true; 10100f21ee8dSSujith Manoharan 10110f21ee8dSSujith Manoharan return false; 10120f21ee8dSSujith Manoharan } 10130f21ee8dSSujith Manoharan EXPORT_SYMBOL(ar9003_is_paprd_enabled); 1014