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; 24331c5ea2SMohammed Shafi Shajakhan struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep; 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 39331c5ea2SMohammed Shafi Shajakhan if (IS_CHAN_5GHZ(chan)) { 40331c5ea2SMohammed Shafi Shajakhan if (chan->channel >= UPPER_5G_SUB_BAND_START) { 41331c5ea2SMohammed Shafi Shajakhan if (le32_to_cpu(eep->modalHeader5G.papdRateMaskHt20) 42331c5ea2SMohammed Shafi Shajakhan & BIT(30)) 43331c5ea2SMohammed Shafi Shajakhan val = false; 44331c5ea2SMohammed Shafi Shajakhan } else if (chan->channel >= MID_5G_SUB_BAND_START) { 45331c5ea2SMohammed Shafi Shajakhan if (le32_to_cpu(eep->modalHeader5G.papdRateMaskHt20) 46331c5ea2SMohammed Shafi Shajakhan & BIT(29)) 47331c5ea2SMohammed Shafi Shajakhan val = false; 48331c5ea2SMohammed Shafi Shajakhan } else { 49331c5ea2SMohammed Shafi Shajakhan if (le32_to_cpu(eep->modalHeader5G.papdRateMaskHt20) 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); 771bf38661SFelix Fietkau power = REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE5, 781bf38661SFelix Fietkau AR_PHY_POWERTX_RATE5_POWERTXHT20_0); 791bf38661SFelix Fietkau 801bf38661SFelix Fietkau delta = abs((int) ah->paprd_target_power - (int) power); 811bf38661SFelix Fietkau if (delta > scale) 821bf38661SFelix Fietkau return -1; 831bf38661SFelix Fietkau 841bf38661SFelix Fietkau if (delta < 4) 851bf38661SFelix Fietkau power -= 4 - delta; 861bf38661SFelix Fietkau 871bf38661SFelix Fietkau return power; 881bf38661SFelix Fietkau } 891bf38661SFelix Fietkau 901bf38661SFelix Fietkau static int ar9003_get_training_power_5g(struct ath_hw *ah) 911bf38661SFelix Fietkau { 921bf38661SFelix Fietkau struct ath_common *common = ath9k_hw_common(ah); 931bf38661SFelix Fietkau struct ath9k_channel *chan = ah->curchan; 941bf38661SFelix Fietkau unsigned int power, scale, delta; 951bf38661SFelix Fietkau 96931749bfSMohammed Shafi Shajakhan scale = ar9003_get_paprd_scale_factor(ah, chan); 971bf38661SFelix Fietkau 981bf38661SFelix Fietkau if (IS_CHAN_HT40(chan)) 991bf38661SFelix Fietkau power = REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE8, 1001bf38661SFelix Fietkau AR_PHY_POWERTX_RATE8_POWERTXHT40_5); 1011bf38661SFelix Fietkau else 1021bf38661SFelix Fietkau power = REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE6, 1031bf38661SFelix Fietkau AR_PHY_POWERTX_RATE6_POWERTXHT20_5); 1041bf38661SFelix Fietkau 1051bf38661SFelix Fietkau power += scale; 1061bf38661SFelix Fietkau delta = abs((int) ah->paprd_target_power - (int) power); 1071bf38661SFelix Fietkau if (delta > scale) 1081bf38661SFelix Fietkau return -1; 1091bf38661SFelix Fietkau 11082b2d334SFelix Fietkau switch (get_streams(ah->txchainmask)) { 1117952ca5bSMohammed Shafi Shajakhan case 1: 1127952ca5bSMohammed Shafi Shajakhan delta = 6; 1137952ca5bSMohammed Shafi Shajakhan break; 1147952ca5bSMohammed Shafi Shajakhan case 2: 1157952ca5bSMohammed Shafi Shajakhan delta = 4; 1167952ca5bSMohammed Shafi Shajakhan break; 1177952ca5bSMohammed Shafi Shajakhan case 3: 1187952ca5bSMohammed Shafi Shajakhan delta = 2; 1197952ca5bSMohammed Shafi Shajakhan break; 1207952ca5bSMohammed Shafi Shajakhan default: 1217952ca5bSMohammed Shafi Shajakhan delta = 0; 122d2182b69SJoe Perches ath_dbg(common, CALIBRATE, "Invalid tx-chainmask: %u\n", 123d2182b69SJoe Perches ah->txchainmask); 1247952ca5bSMohammed Shafi Shajakhan } 1257952ca5bSMohammed Shafi Shajakhan 1267952ca5bSMohammed Shafi Shajakhan power += delta; 1271bf38661SFelix Fietkau return power; 1281bf38661SFelix Fietkau } 1291bf38661SFelix Fietkau 1301bf38661SFelix Fietkau static int ar9003_paprd_setup_single_table(struct ath_hw *ah) 1311bf38661SFelix Fietkau { 1321bf38661SFelix Fietkau struct ath_common *common = ath9k_hw_common(ah); 13307b2fa5aSJoe Perches static const u32 ctrl0[3] = { 134717f6bedSFelix Fietkau AR_PHY_PAPRD_CTRL0_B0, 135717f6bedSFelix Fietkau AR_PHY_PAPRD_CTRL0_B1, 136717f6bedSFelix Fietkau AR_PHY_PAPRD_CTRL0_B2 137717f6bedSFelix Fietkau }; 13807b2fa5aSJoe Perches static const u32 ctrl1[3] = { 139717f6bedSFelix Fietkau AR_PHY_PAPRD_CTRL1_B0, 140717f6bedSFelix Fietkau AR_PHY_PAPRD_CTRL1_B1, 141717f6bedSFelix Fietkau AR_PHY_PAPRD_CTRL1_B2 142717f6bedSFelix Fietkau }; 1431bf38661SFelix Fietkau int training_power; 1442577c6e8SSenthil Balasubramanian int i, val; 14526228959SFelix Fietkau u32 am2pm_mask = ah->paprd_ratemask; 146717f6bedSFelix Fietkau 1471bf38661SFelix Fietkau if (IS_CHAN_2GHZ(ah->curchan)) 1481bf38661SFelix Fietkau training_power = ar9003_get_training_power_2g(ah); 1491bf38661SFelix Fietkau else 1501bf38661SFelix Fietkau training_power = ar9003_get_training_power_5g(ah); 1511bf38661SFelix Fietkau 152d2182b69SJoe Perches ath_dbg(common, CALIBRATE, "Training power: %d, Target power: %d\n", 15384288044SMohammed Shafi Shajakhan training_power, ah->paprd_target_power); 15484288044SMohammed Shafi Shajakhan 1551bf38661SFelix Fietkau if (training_power < 0) { 156d2182b69SJoe Perches ath_dbg(common, CALIBRATE, 157d2182b69SJoe Perches "PAPRD target power delta out of range\n"); 1581bf38661SFelix Fietkau return -ERANGE; 1591bf38661SFelix Fietkau } 1601bf38661SFelix Fietkau ah->paprd_training_power = training_power; 1611bf38661SFelix Fietkau 16226228959SFelix Fietkau if (AR_SREV_9330(ah)) 16326228959SFelix Fietkau am2pm_mask = 0; 16426228959SFelix Fietkau 1657072bf62SVasanthakumar Thiagarajan REG_RMW_FIELD(ah, AR_PHY_PAPRD_AM2AM, AR_PHY_PAPRD_AM2AM_MASK, 1667072bf62SVasanthakumar Thiagarajan ah->paprd_ratemask); 1677072bf62SVasanthakumar Thiagarajan REG_RMW_FIELD(ah, AR_PHY_PAPRD_AM2PM, AR_PHY_PAPRD_AM2PM_MASK, 16826228959SFelix Fietkau am2pm_mask); 1697072bf62SVasanthakumar Thiagarajan REG_RMW_FIELD(ah, AR_PHY_PAPRD_HT40, AR_PHY_PAPRD_HT40_MASK, 170f1a8abb0SFelix Fietkau ah->paprd_ratemask_ht40); 171717f6bedSFelix Fietkau 172914d0f4dSSujith Manoharan ath_dbg(common, CALIBRATE, "PAPRD HT20 mask: 0x%x, HT40 mask: 0x%x\n", 173914d0f4dSSujith Manoharan ah->paprd_ratemask, ah->paprd_ratemask_ht40); 174914d0f4dSSujith Manoharan 17511441fb8SVasanthakumar Thiagarajan for (i = 0; i < ah->caps.max_txchains; i++) { 176717f6bedSFelix Fietkau REG_RMW_FIELD(ah, ctrl0[i], 177717f6bedSFelix Fietkau AR_PHY_PAPRD_CTRL0_USE_SINGLE_TABLE_MASK, 1); 178717f6bedSFelix Fietkau REG_RMW_FIELD(ah, ctrl1[i], 179717f6bedSFelix Fietkau AR_PHY_PAPRD_CTRL1_ADAPTIVE_AM2PM_ENABLE, 1); 180717f6bedSFelix Fietkau REG_RMW_FIELD(ah, ctrl1[i], 181717f6bedSFelix Fietkau AR_PHY_PAPRD_CTRL1_ADAPTIVE_AM2AM_ENABLE, 1); 182717f6bedSFelix Fietkau REG_RMW_FIELD(ah, ctrl1[i], 183717f6bedSFelix Fietkau AR_PHY_PAPRD_CTRL1_ADAPTIVE_SCALING_ENA, 0); 184717f6bedSFelix Fietkau REG_RMW_FIELD(ah, ctrl1[i], 185717f6bedSFelix Fietkau AR_PHY_PAPRD_CTRL1_PA_GAIN_SCALE_FACT_MASK, 181); 186717f6bedSFelix Fietkau REG_RMW_FIELD(ah, ctrl1[i], 187717f6bedSFelix Fietkau AR_PHY_PAPRD_CTRL1_PAPRD_MAG_SCALE_FACT, 361); 188717f6bedSFelix Fietkau REG_RMW_FIELD(ah, ctrl1[i], 189717f6bedSFelix Fietkau AR_PHY_PAPRD_CTRL1_ADAPTIVE_SCALING_ENA, 0); 190717f6bedSFelix Fietkau REG_RMW_FIELD(ah, ctrl0[i], 191717f6bedSFelix Fietkau AR_PHY_PAPRD_CTRL0_PAPRD_MAG_THRSH, 3); 192717f6bedSFelix Fietkau } 193717f6bedSFelix Fietkau 194717f6bedSFelix Fietkau ar9003_paprd_enable(ah, false); 195717f6bedSFelix Fietkau 196717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1, 197717f6bedSFelix Fietkau AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_LB_SKIP, 0x30); 198717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1, 199717f6bedSFelix Fietkau AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_LB_ENABLE, 1); 200717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1, 201717f6bedSFelix Fietkau AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_TX_GAIN_FORCE, 1); 202717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1, 203717f6bedSFelix Fietkau AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_RX_BB_GAIN_FORCE, 0); 204717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1, 205717f6bedSFelix Fietkau AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_IQCORR_ENABLE, 0); 206717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1, 207717f6bedSFelix Fietkau AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_AGC2_SETTLING, 28); 208717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1, 209717f6bedSFelix Fietkau AR_PHY_PAPRD_TRAINER_CNTL1_CF_CF_PAPRD_TRAIN_ENABLE, 1); 2108c723e2dSSujith Manoharan 2118c723e2dSSujith Manoharan if (AR_SREV_9485(ah)) { 2128c723e2dSSujith Manoharan val = 148; 2138c723e2dSSujith Manoharan } else { 2148c723e2dSSujith Manoharan if (IS_CHAN_2GHZ(ah->curchan)) { 2158c723e2dSSujith Manoharan if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) 2168c723e2dSSujith Manoharan val = 145; 2178c723e2dSSujith Manoharan else 2188c723e2dSSujith Manoharan val = 147; 2198c723e2dSSujith Manoharan } else { 2208c723e2dSSujith Manoharan val = 137; 2218c723e2dSSujith Manoharan } 2228c723e2dSSujith Manoharan } 2238c723e2dSSujith Manoharan 224717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL2, 2252577c6e8SSenthil Balasubramanian AR_PHY_PAPRD_TRAINER_CNTL2_CF_PAPRD_INIT_RX_BB_GAIN, val); 226717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3, 227717f6bedSFelix Fietkau AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_FINE_CORR_LEN, 4); 228717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3, 229717f6bedSFelix Fietkau AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_COARSE_CORR_LEN, 4); 230717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3, 231717f6bedSFelix Fietkau AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_NUM_CORR_STAGES, 7); 232717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3, 233717f6bedSFelix Fietkau AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_MIN_LOOPBACK_DEL, 1); 2348c723e2dSSujith Manoharan 2358c723e2dSSujith Manoharan if (AR_SREV_9485(ah) || 2368c723e2dSSujith Manoharan AR_SREV_9462(ah) || 2378c723e2dSSujith Manoharan AR_SREV_9565(ah) || 2388c723e2dSSujith Manoharan AR_SREV_9550(ah) || 2398c723e2dSSujith Manoharan AR_SREV_9330(ah) || 2408c723e2dSSujith Manoharan AR_SREV_9340(ah)) 241717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3, 2428c723e2dSSujith Manoharan AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP, -3); 24311441fb8SVasanthakumar Thiagarajan else 24411441fb8SVasanthakumar Thiagarajan REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3, 2458c723e2dSSujith Manoharan AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP, -6); 2468c723e2dSSujith Manoharan 2478c723e2dSSujith Manoharan val = -10; 2488c723e2dSSujith Manoharan 2498c723e2dSSujith Manoharan if (IS_CHAN_2GHZ(ah->curchan) && !AR_SREV_9462(ah) && !AR_SREV_9565(ah)) 2508c723e2dSSujith Manoharan val = -15; 2518c723e2dSSujith Manoharan 252717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3, 253717f6bedSFelix Fietkau AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_ADC_DESIRED_SIZE, 2542577c6e8SSenthil Balasubramanian val); 255717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3, 256717f6bedSFelix Fietkau AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_BBTXMIX_DISABLE, 1); 257717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL4, 258717f6bedSFelix Fietkau AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_SAFETY_DELTA, 0); 259717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL4, 260717f6bedSFelix Fietkau AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_MIN_CORR, 400); 261717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL4, 262717f6bedSFelix Fietkau AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_NUM_TRAIN_SAMPLES, 263717f6bedSFelix Fietkau 100); 264717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_0_B0, 265717f6bedSFelix Fietkau AR_PHY_PAPRD_PRE_POST_SCALING, 261376); 266717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_1_B0, 267717f6bedSFelix Fietkau AR_PHY_PAPRD_PRE_POST_SCALING, 248079); 268717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_2_B0, 269717f6bedSFelix Fietkau AR_PHY_PAPRD_PRE_POST_SCALING, 233759); 270717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_3_B0, 271717f6bedSFelix Fietkau AR_PHY_PAPRD_PRE_POST_SCALING, 220464); 272717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_4_B0, 273717f6bedSFelix Fietkau AR_PHY_PAPRD_PRE_POST_SCALING, 208194); 274717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_5_B0, 275717f6bedSFelix Fietkau AR_PHY_PAPRD_PRE_POST_SCALING, 196949); 276717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_6_B0, 277717f6bedSFelix Fietkau AR_PHY_PAPRD_PRE_POST_SCALING, 185706); 278717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_7_B0, 279717f6bedSFelix Fietkau AR_PHY_PAPRD_PRE_POST_SCALING, 175487); 2801bf38661SFelix Fietkau return 0; 281717f6bedSFelix Fietkau } 282717f6bedSFelix Fietkau 283717f6bedSFelix Fietkau static void ar9003_paprd_get_gain_table(struct ath_hw *ah) 284717f6bedSFelix Fietkau { 285717f6bedSFelix Fietkau u32 *entry = ah->paprd_gain_table_entries; 286717f6bedSFelix Fietkau u8 *index = ah->paprd_gain_table_index; 287717f6bedSFelix Fietkau u32 reg = AR_PHY_TXGAIN_TABLE; 288717f6bedSFelix Fietkau int i; 289717f6bedSFelix Fietkau 29005b60d4eSMohammed Shafi Shajakhan for (i = 0; i < PAPRD_GAIN_TABLE_ENTRIES; i++) { 291717f6bedSFelix Fietkau entry[i] = REG_READ(ah, reg); 292717f6bedSFelix Fietkau index[i] = (entry[i] >> 24) & 0xff; 293717f6bedSFelix Fietkau reg += 4; 294717f6bedSFelix Fietkau } 295717f6bedSFelix Fietkau } 296717f6bedSFelix Fietkau 297717f6bedSFelix Fietkau static unsigned int ar9003_get_desired_gain(struct ath_hw *ah, int chain, 298717f6bedSFelix Fietkau int target_power) 299717f6bedSFelix Fietkau { 300f68e20f0SMohammed Shafi Shajakhan int olpc_gain_delta = 0, cl_gain_mod; 301717f6bedSFelix Fietkau int alpha_therm, alpha_volt; 302717f6bedSFelix Fietkau int therm_cal_value, volt_cal_value; 303717f6bedSFelix Fietkau int therm_value, volt_value; 304717f6bedSFelix Fietkau int thermal_gain_corr, voltage_gain_corr; 305717f6bedSFelix Fietkau int desired_scale, desired_gain = 0; 306f68e20f0SMohammed Shafi Shajakhan u32 reg_olpc = 0, reg_cl_gain = 0; 307717f6bedSFelix Fietkau 308717f6bedSFelix Fietkau REG_CLR_BIT(ah, AR_PHY_PAPRD_TRAINER_STAT1, 309717f6bedSFelix Fietkau AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE); 310717f6bedSFelix Fietkau desired_scale = REG_READ_FIELD(ah, AR_PHY_TPC_12, 311717f6bedSFelix Fietkau AR_PHY_TPC_12_DESIRED_SCALE_HT40_5); 312717f6bedSFelix Fietkau alpha_therm = REG_READ_FIELD(ah, AR_PHY_TPC_19, 313717f6bedSFelix Fietkau AR_PHY_TPC_19_ALPHA_THERM); 314717f6bedSFelix Fietkau alpha_volt = REG_READ_FIELD(ah, AR_PHY_TPC_19, 315717f6bedSFelix Fietkau AR_PHY_TPC_19_ALPHA_VOLT); 316717f6bedSFelix Fietkau therm_cal_value = REG_READ_FIELD(ah, AR_PHY_TPC_18, 317717f6bedSFelix Fietkau AR_PHY_TPC_18_THERM_CAL_VALUE); 318717f6bedSFelix Fietkau volt_cal_value = REG_READ_FIELD(ah, AR_PHY_TPC_18, 319717f6bedSFelix Fietkau AR_PHY_TPC_18_VOLT_CAL_VALUE); 320717f6bedSFelix Fietkau therm_value = REG_READ_FIELD(ah, AR_PHY_BB_THERM_ADC_4, 321717f6bedSFelix Fietkau AR_PHY_BB_THERM_ADC_4_LATEST_THERM_VALUE); 322717f6bedSFelix Fietkau volt_value = REG_READ_FIELD(ah, AR_PHY_BB_THERM_ADC_4, 323717f6bedSFelix Fietkau AR_PHY_BB_THERM_ADC_4_LATEST_VOLT_VALUE); 324717f6bedSFelix Fietkau 325f68e20f0SMohammed Shafi Shajakhan switch (chain) { 326f68e20f0SMohammed Shafi Shajakhan case 0: 327f68e20f0SMohammed Shafi Shajakhan reg_olpc = AR_PHY_TPC_11_B0; 328f68e20f0SMohammed Shafi Shajakhan reg_cl_gain = AR_PHY_CL_TAB_0; 329f68e20f0SMohammed Shafi Shajakhan break; 330f68e20f0SMohammed Shafi Shajakhan case 1: 331f68e20f0SMohammed Shafi Shajakhan reg_olpc = AR_PHY_TPC_11_B1; 332f68e20f0SMohammed Shafi Shajakhan reg_cl_gain = AR_PHY_CL_TAB_1; 333f68e20f0SMohammed Shafi Shajakhan break; 334f68e20f0SMohammed Shafi Shajakhan case 2: 335f68e20f0SMohammed Shafi Shajakhan reg_olpc = AR_PHY_TPC_11_B2; 336f68e20f0SMohammed Shafi Shajakhan reg_cl_gain = AR_PHY_CL_TAB_2; 337f68e20f0SMohammed Shafi Shajakhan break; 338f68e20f0SMohammed Shafi Shajakhan default: 339d2182b69SJoe Perches ath_dbg(ath9k_hw_common(ah), CALIBRATE, 340f68e20f0SMohammed Shafi Shajakhan "Invalid chainmask: %d\n", chain); 341f68e20f0SMohammed Shafi Shajakhan break; 342f68e20f0SMohammed Shafi Shajakhan } 343717f6bedSFelix Fietkau 344f68e20f0SMohammed Shafi Shajakhan olpc_gain_delta = REG_READ_FIELD(ah, reg_olpc, 345717f6bedSFelix Fietkau AR_PHY_TPC_11_OLPC_GAIN_DELTA); 346f68e20f0SMohammed Shafi Shajakhan cl_gain_mod = REG_READ_FIELD(ah, reg_cl_gain, 347f68e20f0SMohammed Shafi Shajakhan AR_PHY_CL_TAB_CL_GAIN_MOD); 348717f6bedSFelix Fietkau 349717f6bedSFelix Fietkau if (olpc_gain_delta >= 128) 350717f6bedSFelix Fietkau olpc_gain_delta = olpc_gain_delta - 256; 351717f6bedSFelix Fietkau 352717f6bedSFelix Fietkau thermal_gain_corr = (alpha_therm * (therm_value - therm_cal_value) + 353717f6bedSFelix Fietkau (256 / 2)) / 256; 354717f6bedSFelix Fietkau voltage_gain_corr = (alpha_volt * (volt_value - volt_cal_value) + 355717f6bedSFelix Fietkau (128 / 2)) / 128; 356717f6bedSFelix Fietkau desired_gain = target_power - olpc_gain_delta - thermal_gain_corr - 357f68e20f0SMohammed Shafi Shajakhan voltage_gain_corr + desired_scale + cl_gain_mod; 358717f6bedSFelix Fietkau 359717f6bedSFelix Fietkau return desired_gain; 360717f6bedSFelix Fietkau } 361717f6bedSFelix Fietkau 362717f6bedSFelix Fietkau static void ar9003_tx_force_gain(struct ath_hw *ah, unsigned int gain_index) 363717f6bedSFelix Fietkau { 364717f6bedSFelix Fietkau int selected_gain_entry, txbb1dbgain, txbb6dbgain, txmxrgain; 365717f6bedSFelix Fietkau int padrvgnA, padrvgnB, padrvgnC, padrvgnD; 366717f6bedSFelix Fietkau u32 *gain_table_entries = ah->paprd_gain_table_entries; 367717f6bedSFelix Fietkau 368717f6bedSFelix Fietkau selected_gain_entry = gain_table_entries[gain_index]; 369717f6bedSFelix Fietkau txbb1dbgain = selected_gain_entry & 0x7; 370717f6bedSFelix Fietkau txbb6dbgain = (selected_gain_entry >> 3) & 0x3; 371717f6bedSFelix Fietkau txmxrgain = (selected_gain_entry >> 5) & 0xf; 372717f6bedSFelix Fietkau padrvgnA = (selected_gain_entry >> 9) & 0xf; 373717f6bedSFelix Fietkau padrvgnB = (selected_gain_entry >> 13) & 0xf; 374717f6bedSFelix Fietkau padrvgnC = (selected_gain_entry >> 17) & 0xf; 375717f6bedSFelix Fietkau padrvgnD = (selected_gain_entry >> 21) & 0x3; 376717f6bedSFelix Fietkau 377717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN, 378717f6bedSFelix Fietkau AR_PHY_TX_FORCED_GAIN_FORCED_TXBB1DBGAIN, txbb1dbgain); 379717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN, 380717f6bedSFelix Fietkau AR_PHY_TX_FORCED_GAIN_FORCED_TXBB6DBGAIN, txbb6dbgain); 381717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN, 382717f6bedSFelix Fietkau AR_PHY_TX_FORCED_GAIN_FORCED_TXMXRGAIN, txmxrgain); 383717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN, 384717f6bedSFelix Fietkau AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGNA, padrvgnA); 385717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN, 386717f6bedSFelix Fietkau AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGNB, padrvgnB); 387717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN, 388717f6bedSFelix Fietkau AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGNC, padrvgnC); 389717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN, 390717f6bedSFelix Fietkau AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGND, padrvgnD); 391717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN, 392717f6bedSFelix Fietkau AR_PHY_TX_FORCED_GAIN_FORCED_ENABLE_PAL, 0); 393717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN, 394717f6bedSFelix Fietkau AR_PHY_TX_FORCED_GAIN_FORCE_TX_GAIN, 0); 395717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_TPC_1, AR_PHY_TPC_1_FORCED_DAC_GAIN, 0); 396717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_TPC_1, AR_PHY_TPC_1_FORCE_DAC_GAIN, 0); 397717f6bedSFelix Fietkau } 398717f6bedSFelix Fietkau 399717f6bedSFelix Fietkau static inline int find_expn(int num) 400717f6bedSFelix Fietkau { 401717f6bedSFelix Fietkau return fls(num) - 1; 402717f6bedSFelix Fietkau } 403717f6bedSFelix Fietkau 404717f6bedSFelix Fietkau static inline int find_proper_scale(int expn, int N) 405717f6bedSFelix Fietkau { 406717f6bedSFelix Fietkau return (expn > N) ? expn - 10 : 0; 407717f6bedSFelix Fietkau } 408717f6bedSFelix Fietkau 409717f6bedSFelix Fietkau #define NUM_BIN 23 410717f6bedSFelix Fietkau 411717f6bedSFelix Fietkau static bool create_pa_curve(u32 *data_L, u32 *data_U, u32 *pa_table, u16 *gain) 412717f6bedSFelix Fietkau { 413717f6bedSFelix Fietkau unsigned int thresh_accum_cnt; 414717f6bedSFelix Fietkau int x_est[NUM_BIN + 1], Y[NUM_BIN + 1], theta[NUM_BIN + 1]; 415717f6bedSFelix Fietkau int PA_in[NUM_BIN + 1]; 416717f6bedSFelix Fietkau int B1_tmp[NUM_BIN + 1], B2_tmp[NUM_BIN + 1]; 417717f6bedSFelix Fietkau unsigned int B1_abs_max, B2_abs_max; 418717f6bedSFelix Fietkau int max_index, scale_factor; 419717f6bedSFelix Fietkau int y_est[NUM_BIN + 1]; 420717f6bedSFelix Fietkau int x_est_fxp1_nonlin, x_tilde[NUM_BIN + 1]; 421717f6bedSFelix Fietkau unsigned int x_tilde_abs; 422717f6bedSFelix Fietkau int G_fxp, Y_intercept, order_x_by_y, M, I, L, sum_y_sqr, sum_y_quad; 423717f6bedSFelix Fietkau int Q_x, Q_B1, Q_B2, beta_raw, alpha_raw, scale_B; 424717f6bedSFelix Fietkau int Q_scale_B, Q_beta, Q_alpha, alpha, beta, order_1, order_2; 425717f6bedSFelix Fietkau int order1_5x, order2_3x, order1_5x_rem, order2_3x_rem; 426717f6bedSFelix Fietkau int y5, y3, tmp; 427717f6bedSFelix Fietkau int theta_low_bin = 0; 428717f6bedSFelix Fietkau int i; 429717f6bedSFelix Fietkau 430717f6bedSFelix Fietkau /* disregard any bin that contains <= 16 samples */ 431717f6bedSFelix Fietkau thresh_accum_cnt = 16; 432717f6bedSFelix Fietkau scale_factor = 5; 433717f6bedSFelix Fietkau max_index = 0; 434717f6bedSFelix Fietkau memset(theta, 0, sizeof(theta)); 435717f6bedSFelix Fietkau memset(x_est, 0, sizeof(x_est)); 436717f6bedSFelix Fietkau memset(Y, 0, sizeof(Y)); 437717f6bedSFelix Fietkau memset(y_est, 0, sizeof(y_est)); 438717f6bedSFelix Fietkau memset(x_tilde, 0, sizeof(x_tilde)); 439717f6bedSFelix Fietkau 440717f6bedSFelix Fietkau for (i = 0; i < NUM_BIN; i++) { 441717f6bedSFelix Fietkau s32 accum_cnt, accum_tx, accum_rx, accum_ang; 442717f6bedSFelix Fietkau 443717f6bedSFelix Fietkau /* number of samples */ 444717f6bedSFelix Fietkau accum_cnt = data_L[i] & 0xffff; 445717f6bedSFelix Fietkau 446717f6bedSFelix Fietkau if (accum_cnt <= thresh_accum_cnt) 447717f6bedSFelix Fietkau continue; 448717f6bedSFelix Fietkau 449717f6bedSFelix Fietkau /* sum(tx amplitude) */ 450717f6bedSFelix Fietkau accum_tx = ((data_L[i] >> 16) & 0xffff) | 451717f6bedSFelix Fietkau ((data_U[i] & 0x7ff) << 16); 452717f6bedSFelix Fietkau 453717f6bedSFelix Fietkau /* sum(rx amplitude distance to lower bin edge) */ 454717f6bedSFelix Fietkau accum_rx = ((data_U[i] >> 11) & 0x1f) | 455717f6bedSFelix Fietkau ((data_L[i + 23] & 0xffff) << 5); 456717f6bedSFelix Fietkau 457717f6bedSFelix Fietkau /* sum(angles) */ 458717f6bedSFelix Fietkau accum_ang = ((data_L[i + 23] >> 16) & 0xffff) | 459717f6bedSFelix Fietkau ((data_U[i + 23] & 0x7ff) << 16); 460717f6bedSFelix Fietkau 461717f6bedSFelix Fietkau accum_tx <<= scale_factor; 462717f6bedSFelix Fietkau accum_rx <<= scale_factor; 463717f6bedSFelix Fietkau x_est[i + 1] = (((accum_tx + accum_cnt) / accum_cnt) + 32) >> 464717f6bedSFelix Fietkau scale_factor; 465717f6bedSFelix Fietkau 466717f6bedSFelix Fietkau Y[i + 1] = ((((accum_rx + accum_cnt) / accum_cnt) + 32) >> 467717f6bedSFelix Fietkau scale_factor) + 468717f6bedSFelix Fietkau (1 << scale_factor) * max_index + 16; 469717f6bedSFelix Fietkau 470717f6bedSFelix Fietkau if (accum_ang >= (1 << 26)) 471717f6bedSFelix Fietkau accum_ang -= 1 << 27; 472717f6bedSFelix Fietkau 473717f6bedSFelix Fietkau theta[i + 1] = ((accum_ang * (1 << scale_factor)) + accum_cnt) / 474717f6bedSFelix Fietkau accum_cnt; 475717f6bedSFelix Fietkau 476717f6bedSFelix Fietkau max_index++; 477717f6bedSFelix Fietkau } 478717f6bedSFelix Fietkau 479717f6bedSFelix Fietkau /* 480717f6bedSFelix Fietkau * Find average theta of first 5 bin and all of those to same value. 481717f6bedSFelix Fietkau * Curve is linear at that range. 482717f6bedSFelix Fietkau */ 483717f6bedSFelix Fietkau for (i = 1; i < 6; i++) 484717f6bedSFelix Fietkau theta_low_bin += theta[i]; 485717f6bedSFelix Fietkau 486717f6bedSFelix Fietkau theta_low_bin = theta_low_bin / 5; 487717f6bedSFelix Fietkau for (i = 1; i < 6; i++) 488717f6bedSFelix Fietkau theta[i] = theta_low_bin; 489717f6bedSFelix Fietkau 490717f6bedSFelix Fietkau /* Set values at origin */ 491717f6bedSFelix Fietkau theta[0] = theta_low_bin; 492717f6bedSFelix Fietkau for (i = 0; i <= max_index; i++) 493717f6bedSFelix Fietkau theta[i] -= theta_low_bin; 494717f6bedSFelix Fietkau 495717f6bedSFelix Fietkau x_est[0] = 0; 496717f6bedSFelix Fietkau Y[0] = 0; 497717f6bedSFelix Fietkau scale_factor = 8; 498717f6bedSFelix Fietkau 499717f6bedSFelix Fietkau /* low signal gain */ 500717f6bedSFelix Fietkau if (x_est[6] == x_est[3]) 501717f6bedSFelix Fietkau return false; 502717f6bedSFelix Fietkau 503717f6bedSFelix Fietkau G_fxp = 504717f6bedSFelix Fietkau (((Y[6] - Y[3]) * 1 << scale_factor) + 505717f6bedSFelix Fietkau (x_est[6] - x_est[3])) / (x_est[6] - x_est[3]); 506717f6bedSFelix Fietkau 5072d3fca18SSenthil Balasubramanian /* prevent division by zero */ 5082d3fca18SSenthil Balasubramanian if (G_fxp == 0) 5092d3fca18SSenthil Balasubramanian return false; 5102d3fca18SSenthil Balasubramanian 511717f6bedSFelix Fietkau Y_intercept = 512717f6bedSFelix Fietkau (G_fxp * (x_est[0] - x_est[3]) + 513717f6bedSFelix Fietkau (1 << scale_factor)) / (1 << scale_factor) + Y[3]; 514717f6bedSFelix Fietkau 515717f6bedSFelix Fietkau for (i = 0; i <= max_index; i++) 516717f6bedSFelix Fietkau y_est[i] = Y[i] - Y_intercept; 517717f6bedSFelix Fietkau 518717f6bedSFelix Fietkau for (i = 0; i <= 3; i++) { 519717f6bedSFelix Fietkau y_est[i] = i * 32; 520717f6bedSFelix Fietkau x_est[i] = ((y_est[i] * 1 << scale_factor) + G_fxp) / G_fxp; 521717f6bedSFelix Fietkau } 522717f6bedSFelix Fietkau 5232d3fca18SSenthil Balasubramanian if (y_est[max_index] == 0) 5242d3fca18SSenthil Balasubramanian return false; 5252d3fca18SSenthil Balasubramanian 526717f6bedSFelix Fietkau x_est_fxp1_nonlin = 527717f6bedSFelix Fietkau x_est[max_index] - ((1 << scale_factor) * y_est[max_index] + 528717f6bedSFelix Fietkau G_fxp) / G_fxp; 529717f6bedSFelix Fietkau 530717f6bedSFelix Fietkau order_x_by_y = 531717f6bedSFelix Fietkau (x_est_fxp1_nonlin + y_est[max_index]) / y_est[max_index]; 532717f6bedSFelix Fietkau 533717f6bedSFelix Fietkau if (order_x_by_y == 0) 534717f6bedSFelix Fietkau M = 10; 535717f6bedSFelix Fietkau else if (order_x_by_y == 1) 536717f6bedSFelix Fietkau M = 9; 537717f6bedSFelix Fietkau else 538717f6bedSFelix Fietkau M = 8; 539717f6bedSFelix Fietkau 540717f6bedSFelix Fietkau I = (max_index > 15) ? 7 : max_index >> 1; 541717f6bedSFelix Fietkau L = max_index - I; 542717f6bedSFelix Fietkau scale_factor = 8; 543717f6bedSFelix Fietkau sum_y_sqr = 0; 544717f6bedSFelix Fietkau sum_y_quad = 0; 545717f6bedSFelix Fietkau x_tilde_abs = 0; 546717f6bedSFelix Fietkau 547717f6bedSFelix Fietkau for (i = 0; i <= L; i++) { 548717f6bedSFelix Fietkau unsigned int y_sqr; 549717f6bedSFelix Fietkau unsigned int y_quad; 550717f6bedSFelix Fietkau unsigned int tmp_abs; 551717f6bedSFelix Fietkau 552717f6bedSFelix Fietkau /* prevent division by zero */ 553717f6bedSFelix Fietkau if (y_est[i + I] == 0) 554717f6bedSFelix Fietkau return false; 555717f6bedSFelix Fietkau 556717f6bedSFelix Fietkau x_est_fxp1_nonlin = 557717f6bedSFelix Fietkau x_est[i + I] - ((1 << scale_factor) * y_est[i + I] + 558717f6bedSFelix Fietkau G_fxp) / G_fxp; 559717f6bedSFelix Fietkau 560717f6bedSFelix Fietkau x_tilde[i] = 561717f6bedSFelix Fietkau (x_est_fxp1_nonlin * (1 << M) + y_est[i + I]) / y_est[i + 562717f6bedSFelix Fietkau I]; 563717f6bedSFelix Fietkau x_tilde[i] = 564717f6bedSFelix Fietkau (x_tilde[i] * (1 << M) + y_est[i + I]) / y_est[i + I]; 565717f6bedSFelix Fietkau x_tilde[i] = 566717f6bedSFelix Fietkau (x_tilde[i] * (1 << M) + y_est[i + I]) / y_est[i + I]; 567717f6bedSFelix Fietkau y_sqr = 568717f6bedSFelix Fietkau (y_est[i + I] * y_est[i + I] + 569717f6bedSFelix Fietkau (scale_factor * scale_factor)) / (scale_factor * 570717f6bedSFelix Fietkau scale_factor); 571717f6bedSFelix Fietkau tmp_abs = abs(x_tilde[i]); 572717f6bedSFelix Fietkau if (tmp_abs > x_tilde_abs) 573717f6bedSFelix Fietkau x_tilde_abs = tmp_abs; 574717f6bedSFelix Fietkau 575717f6bedSFelix Fietkau y_quad = y_sqr * y_sqr; 576717f6bedSFelix Fietkau sum_y_sqr = sum_y_sqr + y_sqr; 577717f6bedSFelix Fietkau sum_y_quad = sum_y_quad + y_quad; 578717f6bedSFelix Fietkau B1_tmp[i] = y_sqr * (L + 1); 579717f6bedSFelix Fietkau B2_tmp[i] = y_sqr; 580717f6bedSFelix Fietkau } 581717f6bedSFelix Fietkau 582717f6bedSFelix Fietkau B1_abs_max = 0; 583717f6bedSFelix Fietkau B2_abs_max = 0; 584717f6bedSFelix Fietkau for (i = 0; i <= L; i++) { 585717f6bedSFelix Fietkau int abs_val; 586717f6bedSFelix Fietkau 587717f6bedSFelix Fietkau B1_tmp[i] -= sum_y_sqr; 588717f6bedSFelix Fietkau B2_tmp[i] = sum_y_quad - sum_y_sqr * B2_tmp[i]; 589717f6bedSFelix Fietkau 590717f6bedSFelix Fietkau abs_val = abs(B1_tmp[i]); 591717f6bedSFelix Fietkau if (abs_val > B1_abs_max) 592717f6bedSFelix Fietkau B1_abs_max = abs_val; 593717f6bedSFelix Fietkau 594717f6bedSFelix Fietkau abs_val = abs(B2_tmp[i]); 595717f6bedSFelix Fietkau if (abs_val > B2_abs_max) 596717f6bedSFelix Fietkau B2_abs_max = abs_val; 597717f6bedSFelix Fietkau } 598717f6bedSFelix Fietkau 599717f6bedSFelix Fietkau Q_x = find_proper_scale(find_expn(x_tilde_abs), 10); 600717f6bedSFelix Fietkau Q_B1 = find_proper_scale(find_expn(B1_abs_max), 10); 601717f6bedSFelix Fietkau Q_B2 = find_proper_scale(find_expn(B2_abs_max), 10); 602717f6bedSFelix Fietkau 603717f6bedSFelix Fietkau beta_raw = 0; 604717f6bedSFelix Fietkau alpha_raw = 0; 605717f6bedSFelix Fietkau for (i = 0; i <= L; i++) { 606717f6bedSFelix Fietkau x_tilde[i] = x_tilde[i] / (1 << Q_x); 607717f6bedSFelix Fietkau B1_tmp[i] = B1_tmp[i] / (1 << Q_B1); 608717f6bedSFelix Fietkau B2_tmp[i] = B2_tmp[i] / (1 << Q_B2); 609717f6bedSFelix Fietkau beta_raw = beta_raw + B1_tmp[i] * x_tilde[i]; 610717f6bedSFelix Fietkau alpha_raw = alpha_raw + B2_tmp[i] * x_tilde[i]; 611717f6bedSFelix Fietkau } 612717f6bedSFelix Fietkau 613717f6bedSFelix Fietkau scale_B = 614717f6bedSFelix Fietkau ((sum_y_quad / scale_factor) * (L + 1) - 615717f6bedSFelix Fietkau (sum_y_sqr / scale_factor) * sum_y_sqr) * scale_factor; 616717f6bedSFelix Fietkau 617717f6bedSFelix Fietkau Q_scale_B = find_proper_scale(find_expn(abs(scale_B)), 10); 618717f6bedSFelix Fietkau scale_B = scale_B / (1 << Q_scale_B); 6192d3fca18SSenthil Balasubramanian if (scale_B == 0) 6202d3fca18SSenthil Balasubramanian return false; 621717f6bedSFelix Fietkau Q_beta = find_proper_scale(find_expn(abs(beta_raw)), 10); 622717f6bedSFelix Fietkau Q_alpha = find_proper_scale(find_expn(abs(alpha_raw)), 10); 623717f6bedSFelix Fietkau beta_raw = beta_raw / (1 << Q_beta); 624717f6bedSFelix Fietkau alpha_raw = alpha_raw / (1 << Q_alpha); 625717f6bedSFelix Fietkau alpha = (alpha_raw << 10) / scale_B; 626717f6bedSFelix Fietkau beta = (beta_raw << 10) / scale_B; 627717f6bedSFelix Fietkau order_1 = 3 * M - Q_x - Q_B1 - Q_beta + 10 + Q_scale_B; 628717f6bedSFelix Fietkau order_2 = 3 * M - Q_x - Q_B2 - Q_alpha + 10 + Q_scale_B; 629717f6bedSFelix Fietkau order1_5x = order_1 / 5; 630717f6bedSFelix Fietkau order2_3x = order_2 / 3; 631717f6bedSFelix Fietkau order1_5x_rem = order_1 - 5 * order1_5x; 632717f6bedSFelix Fietkau order2_3x_rem = order_2 - 3 * order2_3x; 633717f6bedSFelix Fietkau 634717f6bedSFelix Fietkau for (i = 0; i < PAPRD_TABLE_SZ; i++) { 635717f6bedSFelix Fietkau tmp = i * 32; 636717f6bedSFelix Fietkau y5 = ((beta * tmp) >> 6) >> order1_5x; 637717f6bedSFelix Fietkau y5 = (y5 * tmp) >> order1_5x; 638717f6bedSFelix Fietkau y5 = (y5 * tmp) >> order1_5x; 639717f6bedSFelix Fietkau y5 = (y5 * tmp) >> order1_5x; 640717f6bedSFelix Fietkau y5 = (y5 * tmp) >> order1_5x; 641717f6bedSFelix Fietkau y5 = y5 >> order1_5x_rem; 642717f6bedSFelix Fietkau y3 = (alpha * tmp) >> order2_3x; 643717f6bedSFelix Fietkau y3 = (y3 * tmp) >> order2_3x; 644717f6bedSFelix Fietkau y3 = (y3 * tmp) >> order2_3x; 645717f6bedSFelix Fietkau y3 = y3 >> order2_3x_rem; 646717f6bedSFelix Fietkau PA_in[i] = y5 + y3 + (256 * tmp) / G_fxp; 647717f6bedSFelix Fietkau 648717f6bedSFelix Fietkau if (i >= 2) { 649717f6bedSFelix Fietkau tmp = PA_in[i] - PA_in[i - 1]; 650717f6bedSFelix Fietkau if (tmp < 0) 651717f6bedSFelix Fietkau PA_in[i] = 652717f6bedSFelix Fietkau PA_in[i - 1] + (PA_in[i - 1] - 653717f6bedSFelix Fietkau PA_in[i - 2]); 654717f6bedSFelix Fietkau } 655717f6bedSFelix Fietkau 656717f6bedSFelix Fietkau PA_in[i] = (PA_in[i] < 1400) ? PA_in[i] : 1400; 657717f6bedSFelix Fietkau } 658717f6bedSFelix Fietkau 659717f6bedSFelix Fietkau beta_raw = 0; 660717f6bedSFelix Fietkau alpha_raw = 0; 661717f6bedSFelix Fietkau 662717f6bedSFelix Fietkau for (i = 0; i <= L; i++) { 663717f6bedSFelix Fietkau int theta_tilde = 664717f6bedSFelix Fietkau ((theta[i + I] << M) + y_est[i + I]) / y_est[i + I]; 665717f6bedSFelix Fietkau theta_tilde = 666717f6bedSFelix Fietkau ((theta_tilde << M) + y_est[i + I]) / y_est[i + I]; 667717f6bedSFelix Fietkau theta_tilde = 668717f6bedSFelix Fietkau ((theta_tilde << M) + y_est[i + I]) / y_est[i + I]; 669717f6bedSFelix Fietkau beta_raw = beta_raw + B1_tmp[i] * theta_tilde; 670717f6bedSFelix Fietkau alpha_raw = alpha_raw + B2_tmp[i] * theta_tilde; 671717f6bedSFelix Fietkau } 672717f6bedSFelix Fietkau 673717f6bedSFelix Fietkau Q_beta = find_proper_scale(find_expn(abs(beta_raw)), 10); 674717f6bedSFelix Fietkau Q_alpha = find_proper_scale(find_expn(abs(alpha_raw)), 10); 675717f6bedSFelix Fietkau beta_raw = beta_raw / (1 << Q_beta); 676717f6bedSFelix Fietkau alpha_raw = alpha_raw / (1 << Q_alpha); 677717f6bedSFelix Fietkau 678717f6bedSFelix Fietkau alpha = (alpha_raw << 10) / scale_B; 679717f6bedSFelix Fietkau beta = (beta_raw << 10) / scale_B; 680717f6bedSFelix Fietkau order_1 = 3 * M - Q_x - Q_B1 - Q_beta + 10 + Q_scale_B + 5; 681717f6bedSFelix Fietkau order_2 = 3 * M - Q_x - Q_B2 - Q_alpha + 10 + Q_scale_B + 5; 682717f6bedSFelix Fietkau order1_5x = order_1 / 5; 683717f6bedSFelix Fietkau order2_3x = order_2 / 3; 684717f6bedSFelix Fietkau order1_5x_rem = order_1 - 5 * order1_5x; 685717f6bedSFelix Fietkau order2_3x_rem = order_2 - 3 * order2_3x; 686717f6bedSFelix Fietkau 687717f6bedSFelix Fietkau for (i = 0; i < PAPRD_TABLE_SZ; i++) { 688717f6bedSFelix Fietkau int PA_angle; 689717f6bedSFelix Fietkau 690717f6bedSFelix Fietkau /* pa_table[4] is calculated from PA_angle for i=5 */ 691717f6bedSFelix Fietkau if (i == 4) 692717f6bedSFelix Fietkau continue; 693717f6bedSFelix Fietkau 694717f6bedSFelix Fietkau tmp = i * 32; 695717f6bedSFelix Fietkau if (beta > 0) 696717f6bedSFelix Fietkau y5 = (((beta * tmp - 64) >> 6) - 697717f6bedSFelix Fietkau (1 << order1_5x)) / (1 << order1_5x); 698717f6bedSFelix Fietkau else 699717f6bedSFelix Fietkau y5 = ((((beta * tmp - 64) >> 6) + 700717f6bedSFelix Fietkau (1 << order1_5x)) / (1 << order1_5x)); 701717f6bedSFelix Fietkau 702717f6bedSFelix Fietkau y5 = (y5 * tmp) / (1 << order1_5x); 703717f6bedSFelix Fietkau y5 = (y5 * tmp) / (1 << order1_5x); 704717f6bedSFelix Fietkau y5 = (y5 * tmp) / (1 << order1_5x); 705717f6bedSFelix Fietkau y5 = (y5 * tmp) / (1 << order1_5x); 706717f6bedSFelix Fietkau y5 = y5 / (1 << order1_5x_rem); 707717f6bedSFelix Fietkau 708717f6bedSFelix Fietkau if (beta > 0) 709717f6bedSFelix Fietkau y3 = (alpha * tmp - 710717f6bedSFelix Fietkau (1 << order2_3x)) / (1 << order2_3x); 711717f6bedSFelix Fietkau else 712717f6bedSFelix Fietkau y3 = (alpha * tmp + 713717f6bedSFelix Fietkau (1 << order2_3x)) / (1 << order2_3x); 714717f6bedSFelix Fietkau y3 = (y3 * tmp) / (1 << order2_3x); 715717f6bedSFelix Fietkau y3 = (y3 * tmp) / (1 << order2_3x); 716717f6bedSFelix Fietkau y3 = y3 / (1 << order2_3x_rem); 717717f6bedSFelix Fietkau 718717f6bedSFelix Fietkau if (i < 4) { 719717f6bedSFelix Fietkau PA_angle = 0; 720717f6bedSFelix Fietkau } else { 721717f6bedSFelix Fietkau PA_angle = y5 + y3; 722717f6bedSFelix Fietkau if (PA_angle < -150) 723717f6bedSFelix Fietkau PA_angle = -150; 724717f6bedSFelix Fietkau else if (PA_angle > 150) 725717f6bedSFelix Fietkau PA_angle = 150; 726717f6bedSFelix Fietkau } 727717f6bedSFelix Fietkau 728717f6bedSFelix Fietkau pa_table[i] = ((PA_in[i] & 0x7ff) << 11) + (PA_angle & 0x7ff); 729717f6bedSFelix Fietkau if (i == 5) { 730717f6bedSFelix Fietkau PA_angle = (PA_angle + 2) >> 1; 731717f6bedSFelix Fietkau pa_table[i - 1] = ((PA_in[i - 1] & 0x7ff) << 11) + 732717f6bedSFelix Fietkau (PA_angle & 0x7ff); 733717f6bedSFelix Fietkau } 734717f6bedSFelix Fietkau } 735717f6bedSFelix Fietkau 736717f6bedSFelix Fietkau *gain = G_fxp; 737717f6bedSFelix Fietkau return true; 738717f6bedSFelix Fietkau } 739717f6bedSFelix Fietkau 740717f6bedSFelix Fietkau void ar9003_paprd_populate_single_table(struct ath_hw *ah, 74120bd2a09SFelix Fietkau struct ath9k_hw_cal_data *caldata, 74220bd2a09SFelix Fietkau int chain) 743717f6bedSFelix Fietkau { 74420bd2a09SFelix Fietkau u32 *paprd_table_val = caldata->pa_table[chain]; 74520bd2a09SFelix Fietkau u32 small_signal_gain = caldata->small_signal_gain[chain]; 7461bf38661SFelix Fietkau u32 training_power = ah->paprd_training_power; 747717f6bedSFelix Fietkau u32 reg = 0; 748717f6bedSFelix Fietkau int i; 749717f6bedSFelix Fietkau 750717f6bedSFelix Fietkau if (chain == 0) 751717f6bedSFelix Fietkau reg = AR_PHY_PAPRD_MEM_TAB_B0; 752717f6bedSFelix Fietkau else if (chain == 1) 753717f6bedSFelix Fietkau reg = AR_PHY_PAPRD_MEM_TAB_B1; 754717f6bedSFelix Fietkau else if (chain == 2) 755717f6bedSFelix Fietkau reg = AR_PHY_PAPRD_MEM_TAB_B2; 756717f6bedSFelix Fietkau 757717f6bedSFelix Fietkau for (i = 0; i < PAPRD_TABLE_SZ; i++) { 758717f6bedSFelix Fietkau REG_WRITE(ah, reg, paprd_table_val[i]); 759717f6bedSFelix Fietkau reg = reg + 4; 760717f6bedSFelix Fietkau } 761717f6bedSFelix Fietkau 762717f6bedSFelix Fietkau if (chain == 0) 763717f6bedSFelix Fietkau reg = AR_PHY_PA_GAIN123_B0; 764717f6bedSFelix Fietkau else if (chain == 1) 765717f6bedSFelix Fietkau reg = AR_PHY_PA_GAIN123_B1; 766717f6bedSFelix Fietkau else 767717f6bedSFelix Fietkau reg = AR_PHY_PA_GAIN123_B2; 768717f6bedSFelix Fietkau 769717f6bedSFelix Fietkau REG_RMW_FIELD(ah, reg, AR_PHY_PA_GAIN123_PA_GAIN1, small_signal_gain); 770717f6bedSFelix Fietkau 771717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL1_B0, 772717f6bedSFelix Fietkau AR_PHY_PAPRD_CTRL1_PAPRD_POWER_AT_AM2AM_CAL, 773717f6bedSFelix Fietkau training_power); 774717f6bedSFelix Fietkau 77511441fb8SVasanthakumar Thiagarajan if (ah->caps.tx_chainmask & BIT(1)) 776717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL1_B1, 777717f6bedSFelix Fietkau AR_PHY_PAPRD_CTRL1_PAPRD_POWER_AT_AM2AM_CAL, 778717f6bedSFelix Fietkau training_power); 779717f6bedSFelix Fietkau 78011441fb8SVasanthakumar Thiagarajan if (ah->caps.tx_chainmask & BIT(2)) 7812577c6e8SSenthil Balasubramanian /* val AR_PHY_PAPRD_CTRL1_PAPRD_POWER_AT_AM2AM_CAL correct? */ 782717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL1_B2, 783717f6bedSFelix Fietkau AR_PHY_PAPRD_CTRL1_PAPRD_POWER_AT_AM2AM_CAL, 784717f6bedSFelix Fietkau training_power); 785717f6bedSFelix Fietkau } 786717f6bedSFelix Fietkau EXPORT_SYMBOL(ar9003_paprd_populate_single_table); 787717f6bedSFelix Fietkau 78836d2943bSSujith Manoharan void ar9003_paprd_setup_gain_table(struct ath_hw *ah, int chain) 789717f6bedSFelix Fietkau { 790717f6bedSFelix Fietkau unsigned int i, desired_gain, gain_index; 7911bf38661SFelix Fietkau unsigned int train_power = ah->paprd_training_power; 792717f6bedSFelix Fietkau 793717f6bedSFelix Fietkau desired_gain = ar9003_get_desired_gain(ah, chain, train_power); 794717f6bedSFelix Fietkau 795717f6bedSFelix Fietkau gain_index = 0; 79605b60d4eSMohammed Shafi Shajakhan for (i = 0; i < PAPRD_GAIN_TABLE_ENTRIES; i++) { 797717f6bedSFelix Fietkau if (ah->paprd_gain_table_index[i] >= desired_gain) 798717f6bedSFelix Fietkau break; 799717f6bedSFelix Fietkau gain_index++; 800717f6bedSFelix Fietkau } 801717f6bedSFelix Fietkau 802717f6bedSFelix Fietkau ar9003_tx_force_gain(ah, gain_index); 803717f6bedSFelix Fietkau 804717f6bedSFelix Fietkau REG_CLR_BIT(ah, AR_PHY_PAPRD_TRAINER_STAT1, 805717f6bedSFelix Fietkau AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE); 806717f6bedSFelix Fietkau } 807717f6bedSFelix Fietkau EXPORT_SYMBOL(ar9003_paprd_setup_gain_table); 808717f6bedSFelix Fietkau 809381c726cSFelix Fietkau static bool ar9003_paprd_retrain_pa_in(struct ath_hw *ah, 810381c726cSFelix Fietkau struct ath9k_hw_cal_data *caldata, 811381c726cSFelix Fietkau int chain) 812381c726cSFelix Fietkau { 813381c726cSFelix Fietkau u32 *pa_in = caldata->pa_table[chain]; 814381c726cSFelix Fietkau int capdiv_offset, quick_drop_offset; 815381c726cSFelix Fietkau int capdiv2g, quick_drop; 816381c726cSFelix Fietkau int count = 0; 817381c726cSFelix Fietkau int i; 818381c726cSFelix Fietkau 819381c726cSFelix Fietkau if (!AR_SREV_9485(ah) && !AR_SREV_9330(ah)) 820381c726cSFelix Fietkau return false; 821381c726cSFelix Fietkau 822381c726cSFelix Fietkau capdiv2g = REG_READ_FIELD(ah, AR_PHY_65NM_CH0_TXRF3, 823381c726cSFelix Fietkau AR_PHY_65NM_CH0_TXRF3_CAPDIV2G); 824381c726cSFelix Fietkau 825381c726cSFelix Fietkau quick_drop = REG_READ_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3, 826381c726cSFelix Fietkau AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP); 827381c726cSFelix Fietkau 828381c726cSFelix Fietkau if (quick_drop) 829381c726cSFelix Fietkau quick_drop -= 0x40; 830381c726cSFelix Fietkau 831381c726cSFelix Fietkau for (i = 0; i < NUM_BIN + 1; i++) { 832381c726cSFelix Fietkau if (pa_in[i] == 1400) 833381c726cSFelix Fietkau count++; 834381c726cSFelix Fietkau } 835381c726cSFelix Fietkau 836381c726cSFelix Fietkau if (AR_SREV_9485(ah)) { 837381c726cSFelix Fietkau if (pa_in[23] < 800) { 838381c726cSFelix Fietkau capdiv_offset = (int)((1000 - pa_in[23] + 75) / 150); 839381c726cSFelix Fietkau capdiv2g += capdiv_offset; 840381c726cSFelix Fietkau if (capdiv2g > 7) { 841381c726cSFelix Fietkau capdiv2g = 7; 842381c726cSFelix Fietkau if (pa_in[23] < 600) { 843381c726cSFelix Fietkau quick_drop++; 844381c726cSFelix Fietkau if (quick_drop > 0) 845381c726cSFelix Fietkau quick_drop = 0; 846381c726cSFelix Fietkau } 847381c726cSFelix Fietkau } 848381c726cSFelix Fietkau } else if (pa_in[23] == 1400) { 849381c726cSFelix Fietkau quick_drop_offset = min_t(int, count / 3, 2); 850381c726cSFelix Fietkau quick_drop += quick_drop_offset; 851381c726cSFelix Fietkau capdiv2g += quick_drop_offset / 2; 852381c726cSFelix Fietkau 853381c726cSFelix Fietkau if (capdiv2g > 7) 854381c726cSFelix Fietkau capdiv2g = 7; 855381c726cSFelix Fietkau 856381c726cSFelix Fietkau if (quick_drop > 0) { 857381c726cSFelix Fietkau quick_drop = 0; 858381c726cSFelix Fietkau capdiv2g -= quick_drop_offset; 859381c726cSFelix Fietkau if (capdiv2g < 0) 860381c726cSFelix Fietkau capdiv2g = 0; 861381c726cSFelix Fietkau } 862381c726cSFelix Fietkau } else { 863381c726cSFelix Fietkau return false; 864381c726cSFelix Fietkau } 865381c726cSFelix Fietkau } else if (AR_SREV_9330(ah)) { 866381c726cSFelix Fietkau if (pa_in[23] < 1000) { 867381c726cSFelix Fietkau capdiv_offset = (1000 - pa_in[23]) / 100; 868381c726cSFelix Fietkau capdiv2g += capdiv_offset; 869381c726cSFelix Fietkau if (capdiv_offset > 3) { 870381c726cSFelix Fietkau capdiv_offset = 1; 871381c726cSFelix Fietkau quick_drop--; 872381c726cSFelix Fietkau } 873381c726cSFelix Fietkau 874381c726cSFelix Fietkau capdiv2g += capdiv_offset; 875381c726cSFelix Fietkau if (capdiv2g > 6) 876381c726cSFelix Fietkau capdiv2g = 6; 877381c726cSFelix Fietkau if (quick_drop < -4) 878381c726cSFelix Fietkau quick_drop = -4; 879381c726cSFelix Fietkau } else if (pa_in[23] == 1400) { 880381c726cSFelix Fietkau if (count > 3) { 881381c726cSFelix Fietkau quick_drop++; 882381c726cSFelix Fietkau capdiv2g -= count / 4; 883381c726cSFelix Fietkau if (quick_drop > -2) 884381c726cSFelix Fietkau quick_drop = -2; 885381c726cSFelix Fietkau } else { 886381c726cSFelix Fietkau capdiv2g--; 887381c726cSFelix Fietkau } 888381c726cSFelix Fietkau 889381c726cSFelix Fietkau if (capdiv2g < 0) 890381c726cSFelix Fietkau capdiv2g = 0; 891381c726cSFelix Fietkau } else { 892381c726cSFelix Fietkau return false; 893381c726cSFelix Fietkau } 894381c726cSFelix Fietkau } 895381c726cSFelix Fietkau 896381c726cSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_TXRF3, 897381c726cSFelix Fietkau AR_PHY_65NM_CH0_TXRF3_CAPDIV2G, capdiv2g); 898381c726cSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3, 899381c726cSFelix Fietkau AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP, 900381c726cSFelix Fietkau quick_drop); 901381c726cSFelix Fietkau 902381c726cSFelix Fietkau return true; 903381c726cSFelix Fietkau } 904381c726cSFelix Fietkau 90520bd2a09SFelix Fietkau int ar9003_paprd_create_curve(struct ath_hw *ah, 90620bd2a09SFelix Fietkau struct ath9k_hw_cal_data *caldata, int chain) 907717f6bedSFelix Fietkau { 90820bd2a09SFelix Fietkau u16 *small_signal_gain = &caldata->small_signal_gain[chain]; 90920bd2a09SFelix Fietkau u32 *pa_table = caldata->pa_table[chain]; 910717f6bedSFelix Fietkau u32 *data_L, *data_U; 911717f6bedSFelix Fietkau int i, status = 0; 912717f6bedSFelix Fietkau u32 *buf; 913717f6bedSFelix Fietkau u32 reg; 914717f6bedSFelix Fietkau 91520bd2a09SFelix Fietkau memset(caldata->pa_table[chain], 0, sizeof(caldata->pa_table[chain])); 916717f6bedSFelix Fietkau 91736d2943bSSujith Manoharan buf = kmalloc(2 * 48 * sizeof(u32), GFP_KERNEL); 918717f6bedSFelix Fietkau if (!buf) 919717f6bedSFelix Fietkau return -ENOMEM; 920717f6bedSFelix Fietkau 921717f6bedSFelix Fietkau data_L = &buf[0]; 922717f6bedSFelix Fietkau data_U = &buf[48]; 923717f6bedSFelix Fietkau 924717f6bedSFelix Fietkau REG_CLR_BIT(ah, AR_PHY_CHAN_INFO_MEMORY, 925717f6bedSFelix Fietkau AR_PHY_CHAN_INFO_MEMORY_CHANINFOMEM_S2_READ); 926717f6bedSFelix Fietkau 927717f6bedSFelix Fietkau reg = AR_PHY_CHAN_INFO_TAB_0; 928717f6bedSFelix Fietkau for (i = 0; i < 48; i++) 929717f6bedSFelix Fietkau data_L[i] = REG_READ(ah, reg + (i << 2)); 930717f6bedSFelix Fietkau 931717f6bedSFelix Fietkau REG_SET_BIT(ah, AR_PHY_CHAN_INFO_MEMORY, 932717f6bedSFelix Fietkau AR_PHY_CHAN_INFO_MEMORY_CHANINFOMEM_S2_READ); 933717f6bedSFelix Fietkau 934717f6bedSFelix Fietkau for (i = 0; i < 48; i++) 935717f6bedSFelix Fietkau data_U[i] = REG_READ(ah, reg + (i << 2)); 936717f6bedSFelix Fietkau 937717f6bedSFelix Fietkau if (!create_pa_curve(data_L, data_U, pa_table, small_signal_gain)) 938717f6bedSFelix Fietkau status = -2; 939717f6bedSFelix Fietkau 940381c726cSFelix Fietkau if (ar9003_paprd_retrain_pa_in(ah, caldata, chain)) 941381c726cSFelix Fietkau status = -EINPROGRESS; 942381c726cSFelix Fietkau 943717f6bedSFelix Fietkau REG_CLR_BIT(ah, AR_PHY_PAPRD_TRAINER_STAT1, 944717f6bedSFelix Fietkau AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE); 945717f6bedSFelix Fietkau 946717f6bedSFelix Fietkau kfree(buf); 947717f6bedSFelix Fietkau 948717f6bedSFelix Fietkau return status; 949717f6bedSFelix Fietkau } 950717f6bedSFelix Fietkau EXPORT_SYMBOL(ar9003_paprd_create_curve); 951717f6bedSFelix Fietkau 952717f6bedSFelix Fietkau int ar9003_paprd_init_table(struct ath_hw *ah) 953717f6bedSFelix Fietkau { 9541bf38661SFelix Fietkau int ret; 9551bf38661SFelix Fietkau 9561bf38661SFelix Fietkau ret = ar9003_paprd_setup_single_table(ah); 9571bf38661SFelix Fietkau if (ret < 0) 9581bf38661SFelix Fietkau return ret; 9591bf38661SFelix Fietkau 960717f6bedSFelix Fietkau ar9003_paprd_get_gain_table(ah); 961717f6bedSFelix Fietkau return 0; 962717f6bedSFelix Fietkau } 963717f6bedSFelix Fietkau EXPORT_SYMBOL(ar9003_paprd_init_table); 964717f6bedSFelix Fietkau 965717f6bedSFelix Fietkau bool ar9003_paprd_is_done(struct ath_hw *ah) 966717f6bedSFelix Fietkau { 9670e44d48cSMohammed Shafi Shajakhan int paprd_done, agc2_pwr; 968*d882d242SSujith Manoharan 9690e44d48cSMohammed Shafi Shajakhan paprd_done = REG_READ_FIELD(ah, AR_PHY_PAPRD_TRAINER_STAT1, 970717f6bedSFelix Fietkau AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE); 9710e44d48cSMohammed Shafi Shajakhan 972*d882d242SSujith Manoharan if (AR_SREV_9485(ah)) 973*d882d242SSujith Manoharan goto exit; 974*d882d242SSujith Manoharan 9750e44d48cSMohammed Shafi Shajakhan if (paprd_done == 0x1) { 9760e44d48cSMohammed Shafi Shajakhan agc2_pwr = REG_READ_FIELD(ah, AR_PHY_PAPRD_TRAINER_STAT1, 9770e44d48cSMohammed Shafi Shajakhan AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_AGC2_PWR); 9780e44d48cSMohammed Shafi Shajakhan 979d2182b69SJoe Perches ath_dbg(ath9k_hw_common(ah), CALIBRATE, 9800e44d48cSMohammed Shafi Shajakhan "AGC2_PWR = 0x%x training done = 0x%x\n", 9810e44d48cSMohammed Shafi Shajakhan agc2_pwr, paprd_done); 9820e44d48cSMohammed Shafi Shajakhan /* 9830e44d48cSMohammed Shafi Shajakhan * agc2_pwr range should not be less than 'IDEAL_AGC2_PWR_CHANGE' 9840e44d48cSMohammed Shafi Shajakhan * when the training is completely done, otherwise retraining is 9850e44d48cSMohammed Shafi Shajakhan * done to make sure the value is in ideal range 9860e44d48cSMohammed Shafi Shajakhan */ 9870e44d48cSMohammed Shafi Shajakhan if (agc2_pwr <= PAPRD_IDEAL_AGC2_PWR_RANGE) 9880e44d48cSMohammed Shafi Shajakhan paprd_done = 0; 9890e44d48cSMohammed Shafi Shajakhan } 990*d882d242SSujith Manoharan exit: 9910e44d48cSMohammed Shafi Shajakhan return !!paprd_done; 992717f6bedSFelix Fietkau } 993717f6bedSFelix Fietkau EXPORT_SYMBOL(ar9003_paprd_is_done); 994