1717f6bedSFelix Fietkau /* 2717f6bedSFelix Fietkau * Copyright (c) 2010 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 17717f6bedSFelix Fietkau #include "hw.h" 18717f6bedSFelix Fietkau #include "ar9003_phy.h" 19717f6bedSFelix Fietkau 20717f6bedSFelix Fietkau void ar9003_paprd_enable(struct ath_hw *ah, bool val) 21717f6bedSFelix Fietkau { 22717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL0_B0, 23717f6bedSFelix Fietkau AR_PHY_PAPRD_CTRL0_PAPRD_ENABLE, !!val); 24717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL0_B1, 25717f6bedSFelix Fietkau AR_PHY_PAPRD_CTRL0_PAPRD_ENABLE, !!val); 26717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL0_B2, 27717f6bedSFelix Fietkau AR_PHY_PAPRD_CTRL0_PAPRD_ENABLE, !!val); 28717f6bedSFelix Fietkau } 29717f6bedSFelix Fietkau EXPORT_SYMBOL(ar9003_paprd_enable); 30717f6bedSFelix Fietkau 31717f6bedSFelix Fietkau static void ar9003_paprd_setup_single_table(struct ath_hw *ah) 32717f6bedSFelix Fietkau { 33717f6bedSFelix Fietkau struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep; 34717f6bedSFelix Fietkau struct ar9300_modal_eep_header *hdr; 35*07b2fa5aSJoe Perches static const u32 ctrl0[3] = { 36717f6bedSFelix Fietkau AR_PHY_PAPRD_CTRL0_B0, 37717f6bedSFelix Fietkau AR_PHY_PAPRD_CTRL0_B1, 38717f6bedSFelix Fietkau AR_PHY_PAPRD_CTRL0_B2 39717f6bedSFelix Fietkau }; 40*07b2fa5aSJoe Perches static const u32 ctrl1[3] = { 41717f6bedSFelix Fietkau AR_PHY_PAPRD_CTRL1_B0, 42717f6bedSFelix Fietkau AR_PHY_PAPRD_CTRL1_B1, 43717f6bedSFelix Fietkau AR_PHY_PAPRD_CTRL1_B2 44717f6bedSFelix Fietkau }; 45717f6bedSFelix Fietkau u32 am_mask, ht40_mask; 46717f6bedSFelix Fietkau int i; 47717f6bedSFelix Fietkau 48717f6bedSFelix Fietkau if (ah->curchan && IS_CHAN_5GHZ(ah->curchan)) 49717f6bedSFelix Fietkau hdr = &eep->modalHeader5G; 50717f6bedSFelix Fietkau else 51717f6bedSFelix Fietkau hdr = &eep->modalHeader2G; 52717f6bedSFelix Fietkau 53717f6bedSFelix Fietkau am_mask = le32_to_cpu(hdr->papdRateMaskHt20); 54717f6bedSFelix Fietkau ht40_mask = le32_to_cpu(hdr->papdRateMaskHt40); 55717f6bedSFelix Fietkau 56717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_AM2AM, AR_PHY_PAPRD_AM2AM_MASK, am_mask); 57717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_AM2PM, AR_PHY_PAPRD_AM2PM_MASK, am_mask); 58717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_HT40, AR_PHY_PAPRD_HT40_MASK, ht40_mask); 59717f6bedSFelix Fietkau 60717f6bedSFelix Fietkau for (i = 0; i < 3; i++) { 61717f6bedSFelix Fietkau REG_RMW_FIELD(ah, ctrl0[i], 62717f6bedSFelix Fietkau AR_PHY_PAPRD_CTRL0_USE_SINGLE_TABLE_MASK, 1); 63717f6bedSFelix Fietkau REG_RMW_FIELD(ah, ctrl1[i], 64717f6bedSFelix Fietkau AR_PHY_PAPRD_CTRL1_ADAPTIVE_AM2PM_ENABLE, 1); 65717f6bedSFelix Fietkau REG_RMW_FIELD(ah, ctrl1[i], 66717f6bedSFelix Fietkau AR_PHY_PAPRD_CTRL1_ADAPTIVE_AM2AM_ENABLE, 1); 67717f6bedSFelix Fietkau REG_RMW_FIELD(ah, ctrl1[i], 68717f6bedSFelix Fietkau AR_PHY_PAPRD_CTRL1_ADAPTIVE_SCALING_ENA, 0); 69717f6bedSFelix Fietkau REG_RMW_FIELD(ah, ctrl1[i], 70717f6bedSFelix Fietkau AR_PHY_PAPRD_CTRL1_PA_GAIN_SCALE_FACT_MASK, 181); 71717f6bedSFelix Fietkau REG_RMW_FIELD(ah, ctrl1[i], 72717f6bedSFelix Fietkau AR_PHY_PAPRD_CTRL1_PAPRD_MAG_SCALE_FACT, 361); 73717f6bedSFelix Fietkau REG_RMW_FIELD(ah, ctrl1[i], 74717f6bedSFelix Fietkau AR_PHY_PAPRD_CTRL1_ADAPTIVE_SCALING_ENA, 0); 75717f6bedSFelix Fietkau REG_RMW_FIELD(ah, ctrl0[i], 76717f6bedSFelix Fietkau AR_PHY_PAPRD_CTRL0_PAPRD_MAG_THRSH, 3); 77717f6bedSFelix Fietkau } 78717f6bedSFelix Fietkau 79717f6bedSFelix Fietkau ar9003_paprd_enable(ah, false); 80717f6bedSFelix Fietkau 81717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1, 82717f6bedSFelix Fietkau AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_LB_SKIP, 0x30); 83717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1, 84717f6bedSFelix Fietkau AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_LB_ENABLE, 1); 85717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1, 86717f6bedSFelix Fietkau AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_TX_GAIN_FORCE, 1); 87717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1, 88717f6bedSFelix Fietkau AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_RX_BB_GAIN_FORCE, 0); 89717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1, 90717f6bedSFelix Fietkau AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_IQCORR_ENABLE, 0); 91717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1, 92717f6bedSFelix Fietkau AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_AGC2_SETTLING, 28); 93717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1, 94717f6bedSFelix Fietkau AR_PHY_PAPRD_TRAINER_CNTL1_CF_CF_PAPRD_TRAIN_ENABLE, 1); 95717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL2, 96717f6bedSFelix Fietkau AR_PHY_PAPRD_TRAINER_CNTL2_CF_PAPRD_INIT_RX_BB_GAIN, 147); 97717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3, 98717f6bedSFelix Fietkau AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_FINE_CORR_LEN, 4); 99717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3, 100717f6bedSFelix Fietkau AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_COARSE_CORR_LEN, 4); 101717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3, 102717f6bedSFelix Fietkau AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_NUM_CORR_STAGES, 7); 103717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3, 104717f6bedSFelix Fietkau AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_MIN_LOOPBACK_DEL, 1); 105717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3, 106717f6bedSFelix Fietkau AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP, -6); 107717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3, 108717f6bedSFelix Fietkau AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_ADC_DESIRED_SIZE, 109717f6bedSFelix Fietkau -15); 110717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3, 111717f6bedSFelix Fietkau AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_BBTXMIX_DISABLE, 1); 112717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL4, 113717f6bedSFelix Fietkau AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_SAFETY_DELTA, 0); 114717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL4, 115717f6bedSFelix Fietkau AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_MIN_CORR, 400); 116717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL4, 117717f6bedSFelix Fietkau AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_NUM_TRAIN_SAMPLES, 118717f6bedSFelix Fietkau 100); 119717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_0_B0, 120717f6bedSFelix Fietkau AR_PHY_PAPRD_PRE_POST_SCALING, 261376); 121717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_1_B0, 122717f6bedSFelix Fietkau AR_PHY_PAPRD_PRE_POST_SCALING, 248079); 123717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_2_B0, 124717f6bedSFelix Fietkau AR_PHY_PAPRD_PRE_POST_SCALING, 233759); 125717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_3_B0, 126717f6bedSFelix Fietkau AR_PHY_PAPRD_PRE_POST_SCALING, 220464); 127717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_4_B0, 128717f6bedSFelix Fietkau AR_PHY_PAPRD_PRE_POST_SCALING, 208194); 129717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_5_B0, 130717f6bedSFelix Fietkau AR_PHY_PAPRD_PRE_POST_SCALING, 196949); 131717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_6_B0, 132717f6bedSFelix Fietkau AR_PHY_PAPRD_PRE_POST_SCALING, 185706); 133717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_7_B0, 134717f6bedSFelix Fietkau AR_PHY_PAPRD_PRE_POST_SCALING, 175487); 135717f6bedSFelix Fietkau } 136717f6bedSFelix Fietkau 137717f6bedSFelix Fietkau static void ar9003_paprd_get_gain_table(struct ath_hw *ah) 138717f6bedSFelix Fietkau { 139717f6bedSFelix Fietkau u32 *entry = ah->paprd_gain_table_entries; 140717f6bedSFelix Fietkau u8 *index = ah->paprd_gain_table_index; 141717f6bedSFelix Fietkau u32 reg = AR_PHY_TXGAIN_TABLE; 142717f6bedSFelix Fietkau int i; 143717f6bedSFelix Fietkau 144717f6bedSFelix Fietkau memset(entry, 0, sizeof(ah->paprd_gain_table_entries)); 145717f6bedSFelix Fietkau memset(index, 0, sizeof(ah->paprd_gain_table_index)); 146717f6bedSFelix Fietkau 147717f6bedSFelix Fietkau for (i = 0; i < 32; i++) { 148717f6bedSFelix Fietkau entry[i] = REG_READ(ah, reg); 149717f6bedSFelix Fietkau index[i] = (entry[i] >> 24) & 0xff; 150717f6bedSFelix Fietkau reg += 4; 151717f6bedSFelix Fietkau } 152717f6bedSFelix Fietkau } 153717f6bedSFelix Fietkau 154717f6bedSFelix Fietkau static unsigned int ar9003_get_desired_gain(struct ath_hw *ah, int chain, 155717f6bedSFelix Fietkau int target_power) 156717f6bedSFelix Fietkau { 157717f6bedSFelix Fietkau int olpc_gain_delta = 0; 158717f6bedSFelix Fietkau int alpha_therm, alpha_volt; 159717f6bedSFelix Fietkau int therm_cal_value, volt_cal_value; 160717f6bedSFelix Fietkau int therm_value, volt_value; 161717f6bedSFelix Fietkau int thermal_gain_corr, voltage_gain_corr; 162717f6bedSFelix Fietkau int desired_scale, desired_gain = 0; 163717f6bedSFelix Fietkau u32 reg; 164717f6bedSFelix Fietkau 165717f6bedSFelix Fietkau REG_CLR_BIT(ah, AR_PHY_PAPRD_TRAINER_STAT1, 166717f6bedSFelix Fietkau AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE); 167717f6bedSFelix Fietkau desired_scale = REG_READ_FIELD(ah, AR_PHY_TPC_12, 168717f6bedSFelix Fietkau AR_PHY_TPC_12_DESIRED_SCALE_HT40_5); 169717f6bedSFelix Fietkau alpha_therm = REG_READ_FIELD(ah, AR_PHY_TPC_19, 170717f6bedSFelix Fietkau AR_PHY_TPC_19_ALPHA_THERM); 171717f6bedSFelix Fietkau alpha_volt = REG_READ_FIELD(ah, AR_PHY_TPC_19, 172717f6bedSFelix Fietkau AR_PHY_TPC_19_ALPHA_VOLT); 173717f6bedSFelix Fietkau therm_cal_value = REG_READ_FIELD(ah, AR_PHY_TPC_18, 174717f6bedSFelix Fietkau AR_PHY_TPC_18_THERM_CAL_VALUE); 175717f6bedSFelix Fietkau volt_cal_value = REG_READ_FIELD(ah, AR_PHY_TPC_18, 176717f6bedSFelix Fietkau AR_PHY_TPC_18_VOLT_CAL_VALUE); 177717f6bedSFelix Fietkau therm_value = REG_READ_FIELD(ah, AR_PHY_BB_THERM_ADC_4, 178717f6bedSFelix Fietkau AR_PHY_BB_THERM_ADC_4_LATEST_THERM_VALUE); 179717f6bedSFelix Fietkau volt_value = REG_READ_FIELD(ah, AR_PHY_BB_THERM_ADC_4, 180717f6bedSFelix Fietkau AR_PHY_BB_THERM_ADC_4_LATEST_VOLT_VALUE); 181717f6bedSFelix Fietkau 182717f6bedSFelix Fietkau if (chain == 0) 183717f6bedSFelix Fietkau reg = AR_PHY_TPC_11_B0; 184717f6bedSFelix Fietkau else if (chain == 1) 185717f6bedSFelix Fietkau reg = AR_PHY_TPC_11_B1; 186717f6bedSFelix Fietkau else 187717f6bedSFelix Fietkau reg = AR_PHY_TPC_11_B2; 188717f6bedSFelix Fietkau 189717f6bedSFelix Fietkau olpc_gain_delta = REG_READ_FIELD(ah, reg, 190717f6bedSFelix Fietkau AR_PHY_TPC_11_OLPC_GAIN_DELTA); 191717f6bedSFelix Fietkau 192717f6bedSFelix Fietkau if (olpc_gain_delta >= 128) 193717f6bedSFelix Fietkau olpc_gain_delta = olpc_gain_delta - 256; 194717f6bedSFelix Fietkau 195717f6bedSFelix Fietkau thermal_gain_corr = (alpha_therm * (therm_value - therm_cal_value) + 196717f6bedSFelix Fietkau (256 / 2)) / 256; 197717f6bedSFelix Fietkau voltage_gain_corr = (alpha_volt * (volt_value - volt_cal_value) + 198717f6bedSFelix Fietkau (128 / 2)) / 128; 199717f6bedSFelix Fietkau desired_gain = target_power - olpc_gain_delta - thermal_gain_corr - 200717f6bedSFelix Fietkau voltage_gain_corr + desired_scale; 201717f6bedSFelix Fietkau 202717f6bedSFelix Fietkau return desired_gain; 203717f6bedSFelix Fietkau } 204717f6bedSFelix Fietkau 205717f6bedSFelix Fietkau static void ar9003_tx_force_gain(struct ath_hw *ah, unsigned int gain_index) 206717f6bedSFelix Fietkau { 207717f6bedSFelix Fietkau int selected_gain_entry, txbb1dbgain, txbb6dbgain, txmxrgain; 208717f6bedSFelix Fietkau int padrvgnA, padrvgnB, padrvgnC, padrvgnD; 209717f6bedSFelix Fietkau u32 *gain_table_entries = ah->paprd_gain_table_entries; 210717f6bedSFelix Fietkau 211717f6bedSFelix Fietkau selected_gain_entry = gain_table_entries[gain_index]; 212717f6bedSFelix Fietkau txbb1dbgain = selected_gain_entry & 0x7; 213717f6bedSFelix Fietkau txbb6dbgain = (selected_gain_entry >> 3) & 0x3; 214717f6bedSFelix Fietkau txmxrgain = (selected_gain_entry >> 5) & 0xf; 215717f6bedSFelix Fietkau padrvgnA = (selected_gain_entry >> 9) & 0xf; 216717f6bedSFelix Fietkau padrvgnB = (selected_gain_entry >> 13) & 0xf; 217717f6bedSFelix Fietkau padrvgnC = (selected_gain_entry >> 17) & 0xf; 218717f6bedSFelix Fietkau padrvgnD = (selected_gain_entry >> 21) & 0x3; 219717f6bedSFelix Fietkau 220717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN, 221717f6bedSFelix Fietkau AR_PHY_TX_FORCED_GAIN_FORCED_TXBB1DBGAIN, txbb1dbgain); 222717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN, 223717f6bedSFelix Fietkau AR_PHY_TX_FORCED_GAIN_FORCED_TXBB6DBGAIN, txbb6dbgain); 224717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN, 225717f6bedSFelix Fietkau AR_PHY_TX_FORCED_GAIN_FORCED_TXMXRGAIN, txmxrgain); 226717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN, 227717f6bedSFelix Fietkau AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGNA, padrvgnA); 228717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN, 229717f6bedSFelix Fietkau AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGNB, padrvgnB); 230717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN, 231717f6bedSFelix Fietkau AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGNC, padrvgnC); 232717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN, 233717f6bedSFelix Fietkau AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGND, padrvgnD); 234717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN, 235717f6bedSFelix Fietkau AR_PHY_TX_FORCED_GAIN_FORCED_ENABLE_PAL, 0); 236717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN, 237717f6bedSFelix Fietkau AR_PHY_TX_FORCED_GAIN_FORCE_TX_GAIN, 0); 238717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_TPC_1, AR_PHY_TPC_1_FORCED_DAC_GAIN, 0); 239717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_TPC_1, AR_PHY_TPC_1_FORCE_DAC_GAIN, 0); 240717f6bedSFelix Fietkau } 241717f6bedSFelix Fietkau 242717f6bedSFelix Fietkau static inline int find_expn(int num) 243717f6bedSFelix Fietkau { 244717f6bedSFelix Fietkau return fls(num) - 1; 245717f6bedSFelix Fietkau } 246717f6bedSFelix Fietkau 247717f6bedSFelix Fietkau static inline int find_proper_scale(int expn, int N) 248717f6bedSFelix Fietkau { 249717f6bedSFelix Fietkau return (expn > N) ? expn - 10 : 0; 250717f6bedSFelix Fietkau } 251717f6bedSFelix Fietkau 252717f6bedSFelix Fietkau #define NUM_BIN 23 253717f6bedSFelix Fietkau 254717f6bedSFelix Fietkau static bool create_pa_curve(u32 *data_L, u32 *data_U, u32 *pa_table, u16 *gain) 255717f6bedSFelix Fietkau { 256717f6bedSFelix Fietkau unsigned int thresh_accum_cnt; 257717f6bedSFelix Fietkau int x_est[NUM_BIN + 1], Y[NUM_BIN + 1], theta[NUM_BIN + 1]; 258717f6bedSFelix Fietkau int PA_in[NUM_BIN + 1]; 259717f6bedSFelix Fietkau int B1_tmp[NUM_BIN + 1], B2_tmp[NUM_BIN + 1]; 260717f6bedSFelix Fietkau unsigned int B1_abs_max, B2_abs_max; 261717f6bedSFelix Fietkau int max_index, scale_factor; 262717f6bedSFelix Fietkau int y_est[NUM_BIN + 1]; 263717f6bedSFelix Fietkau int x_est_fxp1_nonlin, x_tilde[NUM_BIN + 1]; 264717f6bedSFelix Fietkau unsigned int x_tilde_abs; 265717f6bedSFelix Fietkau int G_fxp, Y_intercept, order_x_by_y, M, I, L, sum_y_sqr, sum_y_quad; 266717f6bedSFelix Fietkau int Q_x, Q_B1, Q_B2, beta_raw, alpha_raw, scale_B; 267717f6bedSFelix Fietkau int Q_scale_B, Q_beta, Q_alpha, alpha, beta, order_1, order_2; 268717f6bedSFelix Fietkau int order1_5x, order2_3x, order1_5x_rem, order2_3x_rem; 269717f6bedSFelix Fietkau int y5, y3, tmp; 270717f6bedSFelix Fietkau int theta_low_bin = 0; 271717f6bedSFelix Fietkau int i; 272717f6bedSFelix Fietkau 273717f6bedSFelix Fietkau /* disregard any bin that contains <= 16 samples */ 274717f6bedSFelix Fietkau thresh_accum_cnt = 16; 275717f6bedSFelix Fietkau scale_factor = 5; 276717f6bedSFelix Fietkau max_index = 0; 277717f6bedSFelix Fietkau memset(theta, 0, sizeof(theta)); 278717f6bedSFelix Fietkau memset(x_est, 0, sizeof(x_est)); 279717f6bedSFelix Fietkau memset(Y, 0, sizeof(Y)); 280717f6bedSFelix Fietkau memset(y_est, 0, sizeof(y_est)); 281717f6bedSFelix Fietkau memset(x_tilde, 0, sizeof(x_tilde)); 282717f6bedSFelix Fietkau 283717f6bedSFelix Fietkau for (i = 0; i < NUM_BIN; i++) { 284717f6bedSFelix Fietkau s32 accum_cnt, accum_tx, accum_rx, accum_ang; 285717f6bedSFelix Fietkau 286717f6bedSFelix Fietkau /* number of samples */ 287717f6bedSFelix Fietkau accum_cnt = data_L[i] & 0xffff; 288717f6bedSFelix Fietkau 289717f6bedSFelix Fietkau if (accum_cnt <= thresh_accum_cnt) 290717f6bedSFelix Fietkau continue; 291717f6bedSFelix Fietkau 292717f6bedSFelix Fietkau /* sum(tx amplitude) */ 293717f6bedSFelix Fietkau accum_tx = ((data_L[i] >> 16) & 0xffff) | 294717f6bedSFelix Fietkau ((data_U[i] & 0x7ff) << 16); 295717f6bedSFelix Fietkau 296717f6bedSFelix Fietkau /* sum(rx amplitude distance to lower bin edge) */ 297717f6bedSFelix Fietkau accum_rx = ((data_U[i] >> 11) & 0x1f) | 298717f6bedSFelix Fietkau ((data_L[i + 23] & 0xffff) << 5); 299717f6bedSFelix Fietkau 300717f6bedSFelix Fietkau /* sum(angles) */ 301717f6bedSFelix Fietkau accum_ang = ((data_L[i + 23] >> 16) & 0xffff) | 302717f6bedSFelix Fietkau ((data_U[i + 23] & 0x7ff) << 16); 303717f6bedSFelix Fietkau 304717f6bedSFelix Fietkau accum_tx <<= scale_factor; 305717f6bedSFelix Fietkau accum_rx <<= scale_factor; 306717f6bedSFelix Fietkau x_est[i + 1] = (((accum_tx + accum_cnt) / accum_cnt) + 32) >> 307717f6bedSFelix Fietkau scale_factor; 308717f6bedSFelix Fietkau 309717f6bedSFelix Fietkau Y[i + 1] = ((((accum_rx + accum_cnt) / accum_cnt) + 32) >> 310717f6bedSFelix Fietkau scale_factor) + 311717f6bedSFelix Fietkau (1 << scale_factor) * max_index + 16; 312717f6bedSFelix Fietkau 313717f6bedSFelix Fietkau if (accum_ang >= (1 << 26)) 314717f6bedSFelix Fietkau accum_ang -= 1 << 27; 315717f6bedSFelix Fietkau 316717f6bedSFelix Fietkau theta[i + 1] = ((accum_ang * (1 << scale_factor)) + accum_cnt) / 317717f6bedSFelix Fietkau accum_cnt; 318717f6bedSFelix Fietkau 319717f6bedSFelix Fietkau max_index++; 320717f6bedSFelix Fietkau } 321717f6bedSFelix Fietkau 322717f6bedSFelix Fietkau /* 323717f6bedSFelix Fietkau * Find average theta of first 5 bin and all of those to same value. 324717f6bedSFelix Fietkau * Curve is linear at that range. 325717f6bedSFelix Fietkau */ 326717f6bedSFelix Fietkau for (i = 1; i < 6; i++) 327717f6bedSFelix Fietkau theta_low_bin += theta[i]; 328717f6bedSFelix Fietkau 329717f6bedSFelix Fietkau theta_low_bin = theta_low_bin / 5; 330717f6bedSFelix Fietkau for (i = 1; i < 6; i++) 331717f6bedSFelix Fietkau theta[i] = theta_low_bin; 332717f6bedSFelix Fietkau 333717f6bedSFelix Fietkau /* Set values at origin */ 334717f6bedSFelix Fietkau theta[0] = theta_low_bin; 335717f6bedSFelix Fietkau for (i = 0; i <= max_index; i++) 336717f6bedSFelix Fietkau theta[i] -= theta_low_bin; 337717f6bedSFelix Fietkau 338717f6bedSFelix Fietkau x_est[0] = 0; 339717f6bedSFelix Fietkau Y[0] = 0; 340717f6bedSFelix Fietkau scale_factor = 8; 341717f6bedSFelix Fietkau 342717f6bedSFelix Fietkau /* low signal gain */ 343717f6bedSFelix Fietkau if (x_est[6] == x_est[3]) 344717f6bedSFelix Fietkau return false; 345717f6bedSFelix Fietkau 346717f6bedSFelix Fietkau G_fxp = 347717f6bedSFelix Fietkau (((Y[6] - Y[3]) * 1 << scale_factor) + 348717f6bedSFelix Fietkau (x_est[6] - x_est[3])) / (x_est[6] - x_est[3]); 349717f6bedSFelix Fietkau 3502d3fca18SSenthil Balasubramanian /* prevent division by zero */ 3512d3fca18SSenthil Balasubramanian if (G_fxp == 0) 3522d3fca18SSenthil Balasubramanian return false; 3532d3fca18SSenthil Balasubramanian 354717f6bedSFelix Fietkau Y_intercept = 355717f6bedSFelix Fietkau (G_fxp * (x_est[0] - x_est[3]) + 356717f6bedSFelix Fietkau (1 << scale_factor)) / (1 << scale_factor) + Y[3]; 357717f6bedSFelix Fietkau 358717f6bedSFelix Fietkau for (i = 0; i <= max_index; i++) 359717f6bedSFelix Fietkau y_est[i] = Y[i] - Y_intercept; 360717f6bedSFelix Fietkau 361717f6bedSFelix Fietkau for (i = 0; i <= 3; i++) { 362717f6bedSFelix Fietkau y_est[i] = i * 32; 363717f6bedSFelix Fietkau x_est[i] = ((y_est[i] * 1 << scale_factor) + G_fxp) / G_fxp; 364717f6bedSFelix Fietkau } 365717f6bedSFelix Fietkau 3662d3fca18SSenthil Balasubramanian if (y_est[max_index] == 0) 3672d3fca18SSenthil Balasubramanian return false; 3682d3fca18SSenthil Balasubramanian 369717f6bedSFelix Fietkau x_est_fxp1_nonlin = 370717f6bedSFelix Fietkau x_est[max_index] - ((1 << scale_factor) * y_est[max_index] + 371717f6bedSFelix Fietkau G_fxp) / G_fxp; 372717f6bedSFelix Fietkau 373717f6bedSFelix Fietkau order_x_by_y = 374717f6bedSFelix Fietkau (x_est_fxp1_nonlin + y_est[max_index]) / y_est[max_index]; 375717f6bedSFelix Fietkau 376717f6bedSFelix Fietkau if (order_x_by_y == 0) 377717f6bedSFelix Fietkau M = 10; 378717f6bedSFelix Fietkau else if (order_x_by_y == 1) 379717f6bedSFelix Fietkau M = 9; 380717f6bedSFelix Fietkau else 381717f6bedSFelix Fietkau M = 8; 382717f6bedSFelix Fietkau 383717f6bedSFelix Fietkau I = (max_index > 15) ? 7 : max_index >> 1; 384717f6bedSFelix Fietkau L = max_index - I; 385717f6bedSFelix Fietkau scale_factor = 8; 386717f6bedSFelix Fietkau sum_y_sqr = 0; 387717f6bedSFelix Fietkau sum_y_quad = 0; 388717f6bedSFelix Fietkau x_tilde_abs = 0; 389717f6bedSFelix Fietkau 390717f6bedSFelix Fietkau for (i = 0; i <= L; i++) { 391717f6bedSFelix Fietkau unsigned int y_sqr; 392717f6bedSFelix Fietkau unsigned int y_quad; 393717f6bedSFelix Fietkau unsigned int tmp_abs; 394717f6bedSFelix Fietkau 395717f6bedSFelix Fietkau /* prevent division by zero */ 396717f6bedSFelix Fietkau if (y_est[i + I] == 0) 397717f6bedSFelix Fietkau return false; 398717f6bedSFelix Fietkau 399717f6bedSFelix Fietkau x_est_fxp1_nonlin = 400717f6bedSFelix Fietkau x_est[i + I] - ((1 << scale_factor) * y_est[i + I] + 401717f6bedSFelix Fietkau G_fxp) / G_fxp; 402717f6bedSFelix Fietkau 403717f6bedSFelix Fietkau x_tilde[i] = 404717f6bedSFelix Fietkau (x_est_fxp1_nonlin * (1 << M) + y_est[i + I]) / y_est[i + 405717f6bedSFelix Fietkau I]; 406717f6bedSFelix Fietkau x_tilde[i] = 407717f6bedSFelix Fietkau (x_tilde[i] * (1 << M) + y_est[i + I]) / y_est[i + I]; 408717f6bedSFelix Fietkau x_tilde[i] = 409717f6bedSFelix Fietkau (x_tilde[i] * (1 << M) + y_est[i + I]) / y_est[i + I]; 410717f6bedSFelix Fietkau y_sqr = 411717f6bedSFelix Fietkau (y_est[i + I] * y_est[i + I] + 412717f6bedSFelix Fietkau (scale_factor * scale_factor)) / (scale_factor * 413717f6bedSFelix Fietkau scale_factor); 414717f6bedSFelix Fietkau tmp_abs = abs(x_tilde[i]); 415717f6bedSFelix Fietkau if (tmp_abs > x_tilde_abs) 416717f6bedSFelix Fietkau x_tilde_abs = tmp_abs; 417717f6bedSFelix Fietkau 418717f6bedSFelix Fietkau y_quad = y_sqr * y_sqr; 419717f6bedSFelix Fietkau sum_y_sqr = sum_y_sqr + y_sqr; 420717f6bedSFelix Fietkau sum_y_quad = sum_y_quad + y_quad; 421717f6bedSFelix Fietkau B1_tmp[i] = y_sqr * (L + 1); 422717f6bedSFelix Fietkau B2_tmp[i] = y_sqr; 423717f6bedSFelix Fietkau } 424717f6bedSFelix Fietkau 425717f6bedSFelix Fietkau B1_abs_max = 0; 426717f6bedSFelix Fietkau B2_abs_max = 0; 427717f6bedSFelix Fietkau for (i = 0; i <= L; i++) { 428717f6bedSFelix Fietkau int abs_val; 429717f6bedSFelix Fietkau 430717f6bedSFelix Fietkau B1_tmp[i] -= sum_y_sqr; 431717f6bedSFelix Fietkau B2_tmp[i] = sum_y_quad - sum_y_sqr * B2_tmp[i]; 432717f6bedSFelix Fietkau 433717f6bedSFelix Fietkau abs_val = abs(B1_tmp[i]); 434717f6bedSFelix Fietkau if (abs_val > B1_abs_max) 435717f6bedSFelix Fietkau B1_abs_max = abs_val; 436717f6bedSFelix Fietkau 437717f6bedSFelix Fietkau abs_val = abs(B2_tmp[i]); 438717f6bedSFelix Fietkau if (abs_val > B2_abs_max) 439717f6bedSFelix Fietkau B2_abs_max = abs_val; 440717f6bedSFelix Fietkau } 441717f6bedSFelix Fietkau 442717f6bedSFelix Fietkau Q_x = find_proper_scale(find_expn(x_tilde_abs), 10); 443717f6bedSFelix Fietkau Q_B1 = find_proper_scale(find_expn(B1_abs_max), 10); 444717f6bedSFelix Fietkau Q_B2 = find_proper_scale(find_expn(B2_abs_max), 10); 445717f6bedSFelix Fietkau 446717f6bedSFelix Fietkau beta_raw = 0; 447717f6bedSFelix Fietkau alpha_raw = 0; 448717f6bedSFelix Fietkau for (i = 0; i <= L; i++) { 449717f6bedSFelix Fietkau x_tilde[i] = x_tilde[i] / (1 << Q_x); 450717f6bedSFelix Fietkau B1_tmp[i] = B1_tmp[i] / (1 << Q_B1); 451717f6bedSFelix Fietkau B2_tmp[i] = B2_tmp[i] / (1 << Q_B2); 452717f6bedSFelix Fietkau beta_raw = beta_raw + B1_tmp[i] * x_tilde[i]; 453717f6bedSFelix Fietkau alpha_raw = alpha_raw + B2_tmp[i] * x_tilde[i]; 454717f6bedSFelix Fietkau } 455717f6bedSFelix Fietkau 456717f6bedSFelix Fietkau scale_B = 457717f6bedSFelix Fietkau ((sum_y_quad / scale_factor) * (L + 1) - 458717f6bedSFelix Fietkau (sum_y_sqr / scale_factor) * sum_y_sqr) * scale_factor; 459717f6bedSFelix Fietkau 460717f6bedSFelix Fietkau Q_scale_B = find_proper_scale(find_expn(abs(scale_B)), 10); 461717f6bedSFelix Fietkau scale_B = scale_B / (1 << Q_scale_B); 4622d3fca18SSenthil Balasubramanian if (scale_B == 0) 4632d3fca18SSenthil Balasubramanian return false; 464717f6bedSFelix Fietkau Q_beta = find_proper_scale(find_expn(abs(beta_raw)), 10); 465717f6bedSFelix Fietkau Q_alpha = find_proper_scale(find_expn(abs(alpha_raw)), 10); 466717f6bedSFelix Fietkau beta_raw = beta_raw / (1 << Q_beta); 467717f6bedSFelix Fietkau alpha_raw = alpha_raw / (1 << Q_alpha); 468717f6bedSFelix Fietkau alpha = (alpha_raw << 10) / scale_B; 469717f6bedSFelix Fietkau beta = (beta_raw << 10) / scale_B; 470717f6bedSFelix Fietkau order_1 = 3 * M - Q_x - Q_B1 - Q_beta + 10 + Q_scale_B; 471717f6bedSFelix Fietkau order_2 = 3 * M - Q_x - Q_B2 - Q_alpha + 10 + Q_scale_B; 472717f6bedSFelix Fietkau order1_5x = order_1 / 5; 473717f6bedSFelix Fietkau order2_3x = order_2 / 3; 474717f6bedSFelix Fietkau order1_5x_rem = order_1 - 5 * order1_5x; 475717f6bedSFelix Fietkau order2_3x_rem = order_2 - 3 * order2_3x; 476717f6bedSFelix Fietkau 477717f6bedSFelix Fietkau for (i = 0; i < PAPRD_TABLE_SZ; i++) { 478717f6bedSFelix Fietkau tmp = i * 32; 479717f6bedSFelix Fietkau y5 = ((beta * tmp) >> 6) >> order1_5x; 480717f6bedSFelix Fietkau y5 = (y5 * tmp) >> order1_5x; 481717f6bedSFelix Fietkau y5 = (y5 * tmp) >> order1_5x; 482717f6bedSFelix Fietkau y5 = (y5 * tmp) >> order1_5x; 483717f6bedSFelix Fietkau y5 = (y5 * tmp) >> order1_5x; 484717f6bedSFelix Fietkau y5 = y5 >> order1_5x_rem; 485717f6bedSFelix Fietkau y3 = (alpha * tmp) >> order2_3x; 486717f6bedSFelix Fietkau y3 = (y3 * tmp) >> order2_3x; 487717f6bedSFelix Fietkau y3 = (y3 * tmp) >> order2_3x; 488717f6bedSFelix Fietkau y3 = y3 >> order2_3x_rem; 489717f6bedSFelix Fietkau PA_in[i] = y5 + y3 + (256 * tmp) / G_fxp; 490717f6bedSFelix Fietkau 491717f6bedSFelix Fietkau if (i >= 2) { 492717f6bedSFelix Fietkau tmp = PA_in[i] - PA_in[i - 1]; 493717f6bedSFelix Fietkau if (tmp < 0) 494717f6bedSFelix Fietkau PA_in[i] = 495717f6bedSFelix Fietkau PA_in[i - 1] + (PA_in[i - 1] - 496717f6bedSFelix Fietkau PA_in[i - 2]); 497717f6bedSFelix Fietkau } 498717f6bedSFelix Fietkau 499717f6bedSFelix Fietkau PA_in[i] = (PA_in[i] < 1400) ? PA_in[i] : 1400; 500717f6bedSFelix Fietkau } 501717f6bedSFelix Fietkau 502717f6bedSFelix Fietkau beta_raw = 0; 503717f6bedSFelix Fietkau alpha_raw = 0; 504717f6bedSFelix Fietkau 505717f6bedSFelix Fietkau for (i = 0; i <= L; i++) { 506717f6bedSFelix Fietkau int theta_tilde = 507717f6bedSFelix Fietkau ((theta[i + I] << M) + y_est[i + I]) / y_est[i + I]; 508717f6bedSFelix Fietkau theta_tilde = 509717f6bedSFelix Fietkau ((theta_tilde << M) + y_est[i + I]) / y_est[i + I]; 510717f6bedSFelix Fietkau theta_tilde = 511717f6bedSFelix Fietkau ((theta_tilde << M) + y_est[i + I]) / y_est[i + I]; 512717f6bedSFelix Fietkau beta_raw = beta_raw + B1_tmp[i] * theta_tilde; 513717f6bedSFelix Fietkau alpha_raw = alpha_raw + B2_tmp[i] * theta_tilde; 514717f6bedSFelix Fietkau } 515717f6bedSFelix Fietkau 516717f6bedSFelix Fietkau Q_beta = find_proper_scale(find_expn(abs(beta_raw)), 10); 517717f6bedSFelix Fietkau Q_alpha = find_proper_scale(find_expn(abs(alpha_raw)), 10); 518717f6bedSFelix Fietkau beta_raw = beta_raw / (1 << Q_beta); 519717f6bedSFelix Fietkau alpha_raw = alpha_raw / (1 << Q_alpha); 520717f6bedSFelix Fietkau 521717f6bedSFelix Fietkau alpha = (alpha_raw << 10) / scale_B; 522717f6bedSFelix Fietkau beta = (beta_raw << 10) / scale_B; 523717f6bedSFelix Fietkau order_1 = 3 * M - Q_x - Q_B1 - Q_beta + 10 + Q_scale_B + 5; 524717f6bedSFelix Fietkau order_2 = 3 * M - Q_x - Q_B2 - Q_alpha + 10 + Q_scale_B + 5; 525717f6bedSFelix Fietkau order1_5x = order_1 / 5; 526717f6bedSFelix Fietkau order2_3x = order_2 / 3; 527717f6bedSFelix Fietkau order1_5x_rem = order_1 - 5 * order1_5x; 528717f6bedSFelix Fietkau order2_3x_rem = order_2 - 3 * order2_3x; 529717f6bedSFelix Fietkau 530717f6bedSFelix Fietkau for (i = 0; i < PAPRD_TABLE_SZ; i++) { 531717f6bedSFelix Fietkau int PA_angle; 532717f6bedSFelix Fietkau 533717f6bedSFelix Fietkau /* pa_table[4] is calculated from PA_angle for i=5 */ 534717f6bedSFelix Fietkau if (i == 4) 535717f6bedSFelix Fietkau continue; 536717f6bedSFelix Fietkau 537717f6bedSFelix Fietkau tmp = i * 32; 538717f6bedSFelix Fietkau if (beta > 0) 539717f6bedSFelix Fietkau y5 = (((beta * tmp - 64) >> 6) - 540717f6bedSFelix Fietkau (1 << order1_5x)) / (1 << order1_5x); 541717f6bedSFelix Fietkau else 542717f6bedSFelix Fietkau y5 = ((((beta * tmp - 64) >> 6) + 543717f6bedSFelix Fietkau (1 << order1_5x)) / (1 << order1_5x)); 544717f6bedSFelix Fietkau 545717f6bedSFelix Fietkau y5 = (y5 * tmp) / (1 << order1_5x); 546717f6bedSFelix Fietkau y5 = (y5 * tmp) / (1 << order1_5x); 547717f6bedSFelix Fietkau y5 = (y5 * tmp) / (1 << order1_5x); 548717f6bedSFelix Fietkau y5 = (y5 * tmp) / (1 << order1_5x); 549717f6bedSFelix Fietkau y5 = y5 / (1 << order1_5x_rem); 550717f6bedSFelix Fietkau 551717f6bedSFelix Fietkau if (beta > 0) 552717f6bedSFelix Fietkau y3 = (alpha * tmp - 553717f6bedSFelix Fietkau (1 << order2_3x)) / (1 << order2_3x); 554717f6bedSFelix Fietkau else 555717f6bedSFelix Fietkau y3 = (alpha * tmp + 556717f6bedSFelix Fietkau (1 << order2_3x)) / (1 << order2_3x); 557717f6bedSFelix Fietkau y3 = (y3 * tmp) / (1 << order2_3x); 558717f6bedSFelix Fietkau y3 = (y3 * tmp) / (1 << order2_3x); 559717f6bedSFelix Fietkau y3 = y3 / (1 << order2_3x_rem); 560717f6bedSFelix Fietkau 561717f6bedSFelix Fietkau if (i < 4) { 562717f6bedSFelix Fietkau PA_angle = 0; 563717f6bedSFelix Fietkau } else { 564717f6bedSFelix Fietkau PA_angle = y5 + y3; 565717f6bedSFelix Fietkau if (PA_angle < -150) 566717f6bedSFelix Fietkau PA_angle = -150; 567717f6bedSFelix Fietkau else if (PA_angle > 150) 568717f6bedSFelix Fietkau PA_angle = 150; 569717f6bedSFelix Fietkau } 570717f6bedSFelix Fietkau 571717f6bedSFelix Fietkau pa_table[i] = ((PA_in[i] & 0x7ff) << 11) + (PA_angle & 0x7ff); 572717f6bedSFelix Fietkau if (i == 5) { 573717f6bedSFelix Fietkau PA_angle = (PA_angle + 2) >> 1; 574717f6bedSFelix Fietkau pa_table[i - 1] = ((PA_in[i - 1] & 0x7ff) << 11) + 575717f6bedSFelix Fietkau (PA_angle & 0x7ff); 576717f6bedSFelix Fietkau } 577717f6bedSFelix Fietkau } 578717f6bedSFelix Fietkau 579717f6bedSFelix Fietkau *gain = G_fxp; 580717f6bedSFelix Fietkau return true; 581717f6bedSFelix Fietkau } 582717f6bedSFelix Fietkau 583717f6bedSFelix Fietkau void ar9003_paprd_populate_single_table(struct ath_hw *ah, 58420bd2a09SFelix Fietkau struct ath9k_hw_cal_data *caldata, 58520bd2a09SFelix Fietkau int chain) 586717f6bedSFelix Fietkau { 58720bd2a09SFelix Fietkau u32 *paprd_table_val = caldata->pa_table[chain]; 58820bd2a09SFelix Fietkau u32 small_signal_gain = caldata->small_signal_gain[chain]; 589717f6bedSFelix Fietkau u32 training_power; 590717f6bedSFelix Fietkau u32 reg = 0; 591717f6bedSFelix Fietkau int i; 592717f6bedSFelix Fietkau 593717f6bedSFelix Fietkau training_power = 594717f6bedSFelix Fietkau REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE5, 595717f6bedSFelix Fietkau AR_PHY_POWERTX_RATE5_POWERTXHT20_0); 596717f6bedSFelix Fietkau training_power -= 4; 597717f6bedSFelix Fietkau 598717f6bedSFelix Fietkau if (chain == 0) 599717f6bedSFelix Fietkau reg = AR_PHY_PAPRD_MEM_TAB_B0; 600717f6bedSFelix Fietkau else if (chain == 1) 601717f6bedSFelix Fietkau reg = AR_PHY_PAPRD_MEM_TAB_B1; 602717f6bedSFelix Fietkau else if (chain == 2) 603717f6bedSFelix Fietkau reg = AR_PHY_PAPRD_MEM_TAB_B2; 604717f6bedSFelix Fietkau 605717f6bedSFelix Fietkau for (i = 0; i < PAPRD_TABLE_SZ; i++) { 606717f6bedSFelix Fietkau REG_WRITE(ah, reg, paprd_table_val[i]); 607717f6bedSFelix Fietkau reg = reg + 4; 608717f6bedSFelix Fietkau } 609717f6bedSFelix Fietkau 610717f6bedSFelix Fietkau if (chain == 0) 611717f6bedSFelix Fietkau reg = AR_PHY_PA_GAIN123_B0; 612717f6bedSFelix Fietkau else if (chain == 1) 613717f6bedSFelix Fietkau reg = AR_PHY_PA_GAIN123_B1; 614717f6bedSFelix Fietkau else 615717f6bedSFelix Fietkau reg = AR_PHY_PA_GAIN123_B2; 616717f6bedSFelix Fietkau 617717f6bedSFelix Fietkau REG_RMW_FIELD(ah, reg, AR_PHY_PA_GAIN123_PA_GAIN1, small_signal_gain); 618717f6bedSFelix Fietkau 619717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL1_B0, 620717f6bedSFelix Fietkau AR_PHY_PAPRD_CTRL1_PAPRD_POWER_AT_AM2AM_CAL, 621717f6bedSFelix Fietkau training_power); 622717f6bedSFelix Fietkau 623717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL1_B1, 624717f6bedSFelix Fietkau AR_PHY_PAPRD_CTRL1_PAPRD_POWER_AT_AM2AM_CAL, 625717f6bedSFelix Fietkau training_power); 626717f6bedSFelix Fietkau 627717f6bedSFelix Fietkau REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL1_B2, 628717f6bedSFelix Fietkau AR_PHY_PAPRD_CTRL1_PAPRD_POWER_AT_AM2AM_CAL, 629717f6bedSFelix Fietkau training_power); 630717f6bedSFelix Fietkau } 631717f6bedSFelix Fietkau EXPORT_SYMBOL(ar9003_paprd_populate_single_table); 632717f6bedSFelix Fietkau 633717f6bedSFelix Fietkau int ar9003_paprd_setup_gain_table(struct ath_hw *ah, int chain) 634717f6bedSFelix Fietkau { 635717f6bedSFelix Fietkau 636717f6bedSFelix Fietkau unsigned int i, desired_gain, gain_index; 637717f6bedSFelix Fietkau unsigned int train_power; 638717f6bedSFelix Fietkau 639717f6bedSFelix Fietkau train_power = REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE5, 640717f6bedSFelix Fietkau AR_PHY_POWERTX_RATE5_POWERTXHT20_0); 641717f6bedSFelix Fietkau 642717f6bedSFelix Fietkau train_power = train_power - 4; 643717f6bedSFelix Fietkau 644717f6bedSFelix Fietkau desired_gain = ar9003_get_desired_gain(ah, chain, train_power); 645717f6bedSFelix Fietkau 646717f6bedSFelix Fietkau gain_index = 0; 647717f6bedSFelix Fietkau for (i = 0; i < 32; i++) { 648717f6bedSFelix Fietkau if (ah->paprd_gain_table_index[i] >= desired_gain) 649717f6bedSFelix Fietkau break; 650717f6bedSFelix Fietkau gain_index++; 651717f6bedSFelix Fietkau } 652717f6bedSFelix Fietkau 653717f6bedSFelix Fietkau ar9003_tx_force_gain(ah, gain_index); 654717f6bedSFelix Fietkau 655717f6bedSFelix Fietkau REG_CLR_BIT(ah, AR_PHY_PAPRD_TRAINER_STAT1, 656717f6bedSFelix Fietkau AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE); 657717f6bedSFelix Fietkau 658717f6bedSFelix Fietkau return 0; 659717f6bedSFelix Fietkau } 660717f6bedSFelix Fietkau EXPORT_SYMBOL(ar9003_paprd_setup_gain_table); 661717f6bedSFelix Fietkau 66220bd2a09SFelix Fietkau int ar9003_paprd_create_curve(struct ath_hw *ah, 66320bd2a09SFelix Fietkau struct ath9k_hw_cal_data *caldata, int chain) 664717f6bedSFelix Fietkau { 66520bd2a09SFelix Fietkau u16 *small_signal_gain = &caldata->small_signal_gain[chain]; 66620bd2a09SFelix Fietkau u32 *pa_table = caldata->pa_table[chain]; 667717f6bedSFelix Fietkau u32 *data_L, *data_U; 668717f6bedSFelix Fietkau int i, status = 0; 669717f6bedSFelix Fietkau u32 *buf; 670717f6bedSFelix Fietkau u32 reg; 671717f6bedSFelix Fietkau 67220bd2a09SFelix Fietkau memset(caldata->pa_table[chain], 0, sizeof(caldata->pa_table[chain])); 673717f6bedSFelix Fietkau 674717f6bedSFelix Fietkau buf = kmalloc(2 * 48 * sizeof(u32), GFP_ATOMIC); 675717f6bedSFelix Fietkau if (!buf) 676717f6bedSFelix Fietkau return -ENOMEM; 677717f6bedSFelix Fietkau 678717f6bedSFelix Fietkau data_L = &buf[0]; 679717f6bedSFelix Fietkau data_U = &buf[48]; 680717f6bedSFelix Fietkau 681717f6bedSFelix Fietkau REG_CLR_BIT(ah, AR_PHY_CHAN_INFO_MEMORY, 682717f6bedSFelix Fietkau AR_PHY_CHAN_INFO_MEMORY_CHANINFOMEM_S2_READ); 683717f6bedSFelix Fietkau 684717f6bedSFelix Fietkau reg = AR_PHY_CHAN_INFO_TAB_0; 685717f6bedSFelix Fietkau for (i = 0; i < 48; i++) 686717f6bedSFelix Fietkau data_L[i] = REG_READ(ah, reg + (i << 2)); 687717f6bedSFelix Fietkau 688717f6bedSFelix Fietkau REG_SET_BIT(ah, AR_PHY_CHAN_INFO_MEMORY, 689717f6bedSFelix Fietkau AR_PHY_CHAN_INFO_MEMORY_CHANINFOMEM_S2_READ); 690717f6bedSFelix Fietkau 691717f6bedSFelix Fietkau for (i = 0; i < 48; i++) 692717f6bedSFelix Fietkau data_U[i] = REG_READ(ah, reg + (i << 2)); 693717f6bedSFelix Fietkau 694717f6bedSFelix Fietkau if (!create_pa_curve(data_L, data_U, pa_table, small_signal_gain)) 695717f6bedSFelix Fietkau status = -2; 696717f6bedSFelix Fietkau 697717f6bedSFelix Fietkau REG_CLR_BIT(ah, AR_PHY_PAPRD_TRAINER_STAT1, 698717f6bedSFelix Fietkau AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE); 699717f6bedSFelix Fietkau 700717f6bedSFelix Fietkau kfree(buf); 701717f6bedSFelix Fietkau 702717f6bedSFelix Fietkau return status; 703717f6bedSFelix Fietkau } 704717f6bedSFelix Fietkau EXPORT_SYMBOL(ar9003_paprd_create_curve); 705717f6bedSFelix Fietkau 706717f6bedSFelix Fietkau int ar9003_paprd_init_table(struct ath_hw *ah) 707717f6bedSFelix Fietkau { 708717f6bedSFelix Fietkau ar9003_paprd_setup_single_table(ah); 709717f6bedSFelix Fietkau ar9003_paprd_get_gain_table(ah); 710717f6bedSFelix Fietkau return 0; 711717f6bedSFelix Fietkau } 712717f6bedSFelix Fietkau EXPORT_SYMBOL(ar9003_paprd_init_table); 713717f6bedSFelix Fietkau 714717f6bedSFelix Fietkau bool ar9003_paprd_is_done(struct ath_hw *ah) 715717f6bedSFelix Fietkau { 716717f6bedSFelix Fietkau return !!REG_READ_FIELD(ah, AR_PHY_PAPRD_TRAINER_STAT1, 717717f6bedSFelix Fietkau AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE); 718717f6bedSFelix Fietkau } 719717f6bedSFelix Fietkau EXPORT_SYMBOL(ar9003_paprd_is_done); 720