Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / net / wireless / ath / ath9k / ar9003_paprd.c
1 /*
2 * Copyright (c) 2010-2011 Atheros Communications Inc.
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 #include "hw.h"
18 #include "ar9003_phy.h"
19
20 void ar9003_paprd_enable(struct ath_hw *ah, bool val)
21 {
22 struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
23 struct ath9k_channel *chan = ah->curchan;
24
25 if (val) {
26 ah->paprd_table_write_done = true;
27
28 ah->eep_ops->set_txpower(ah, chan,
29 ath9k_regd_get_ctl(regulatory, chan),
30 chan->chan->max_antenna_gain * 2,
31 chan->chan->max_power * 2,
32 min((u32) MAX_RATE_POWER,
33 (u32) regulatory->power_limit), false);
34 }
35
36 REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL0_B0,
37 AR_PHY_PAPRD_CTRL0_PAPRD_ENABLE, !!val);
38 if (ah->caps.tx_chainmask & BIT(1))
39 REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL0_B1,
40 AR_PHY_PAPRD_CTRL0_PAPRD_ENABLE, !!val);
41 if (ah->caps.tx_chainmask & BIT(2))
42 REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL0_B2,
43 AR_PHY_PAPRD_CTRL0_PAPRD_ENABLE, !!val);
44 }
45 EXPORT_SYMBOL(ar9003_paprd_enable);
46
47 static int ar9003_get_training_power_2g(struct ath_hw *ah)
48 {
49 struct ath9k_channel *chan = ah->curchan;
50 unsigned int power, scale, delta;
51
52 scale = ar9003_get_paprd_scale_factor(ah, chan);
53 power = REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE5,
54 AR_PHY_POWERTX_RATE5_POWERTXHT20_0);
55
56 delta = abs((int) ah->paprd_target_power - (int) power);
57 if (delta > scale)
58 return -1;
59
60 if (delta < 4)
61 power -= 4 - delta;
62
63 return power;
64 }
65
66 static int ar9003_get_training_power_5g(struct ath_hw *ah)
67 {
68 struct ath_common *common = ath9k_hw_common(ah);
69 struct ath9k_channel *chan = ah->curchan;
70 unsigned int power, scale, delta;
71
72 scale = ar9003_get_paprd_scale_factor(ah, chan);
73
74 if (IS_CHAN_HT40(chan))
75 power = REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE8,
76 AR_PHY_POWERTX_RATE8_POWERTXHT40_5);
77 else
78 power = REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE6,
79 AR_PHY_POWERTX_RATE6_POWERTXHT20_5);
80
81 power += scale;
82 delta = abs((int) ah->paprd_target_power - (int) power);
83 if (delta > scale)
84 return -1;
85
86 power += 2 * get_streams(common->tx_chainmask);
87 return power;
88 }
89
90 static int ar9003_paprd_setup_single_table(struct ath_hw *ah)
91 {
92 struct ath_common *common = ath9k_hw_common(ah);
93 static const u32 ctrl0[3] = {
94 AR_PHY_PAPRD_CTRL0_B0,
95 AR_PHY_PAPRD_CTRL0_B1,
96 AR_PHY_PAPRD_CTRL0_B2
97 };
98 static const u32 ctrl1[3] = {
99 AR_PHY_PAPRD_CTRL1_B0,
100 AR_PHY_PAPRD_CTRL1_B1,
101 AR_PHY_PAPRD_CTRL1_B2
102 };
103 int training_power;
104 int i;
105
106 if (IS_CHAN_2GHZ(ah->curchan))
107 training_power = ar9003_get_training_power_2g(ah);
108 else
109 training_power = ar9003_get_training_power_5g(ah);
110
111 ath_dbg(common, ATH_DBG_CALIBRATE,
112 "Training power: %d, Target power: %d\n",
113 training_power, ah->paprd_target_power);
114
115 if (training_power < 0) {
116 ath_dbg(common, ATH_DBG_CALIBRATE,
117 "PAPRD target power delta out of range");
118 return -ERANGE;
119 }
120 ah->paprd_training_power = training_power;
121
122 REG_RMW_FIELD(ah, AR_PHY_PAPRD_AM2AM, AR_PHY_PAPRD_AM2AM_MASK,
123 ah->paprd_ratemask);
124 REG_RMW_FIELD(ah, AR_PHY_PAPRD_AM2PM, AR_PHY_PAPRD_AM2PM_MASK,
125 ah->paprd_ratemask);
126 REG_RMW_FIELD(ah, AR_PHY_PAPRD_HT40, AR_PHY_PAPRD_HT40_MASK,
127 ah->paprd_ratemask_ht40);
128
129 for (i = 0; i < ah->caps.max_txchains; i++) {
130 REG_RMW_FIELD(ah, ctrl0[i],
131 AR_PHY_PAPRD_CTRL0_USE_SINGLE_TABLE_MASK, 1);
132 REG_RMW_FIELD(ah, ctrl1[i],
133 AR_PHY_PAPRD_CTRL1_ADAPTIVE_AM2PM_ENABLE, 1);
134 REG_RMW_FIELD(ah, ctrl1[i],
135 AR_PHY_PAPRD_CTRL1_ADAPTIVE_AM2AM_ENABLE, 1);
136 REG_RMW_FIELD(ah, ctrl1[i],
137 AR_PHY_PAPRD_CTRL1_ADAPTIVE_SCALING_ENA, 0);
138 REG_RMW_FIELD(ah, ctrl1[i],
139 AR_PHY_PAPRD_CTRL1_PA_GAIN_SCALE_FACT_MASK, 181);
140 REG_RMW_FIELD(ah, ctrl1[i],
141 AR_PHY_PAPRD_CTRL1_PAPRD_MAG_SCALE_FACT, 361);
142 REG_RMW_FIELD(ah, ctrl1[i],
143 AR_PHY_PAPRD_CTRL1_ADAPTIVE_SCALING_ENA, 0);
144 REG_RMW_FIELD(ah, ctrl0[i],
145 AR_PHY_PAPRD_CTRL0_PAPRD_MAG_THRSH, 3);
146 }
147
148 ar9003_paprd_enable(ah, false);
149
150 REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1,
151 AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_LB_SKIP, 0x30);
152 REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1,
153 AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_LB_ENABLE, 1);
154 REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1,
155 AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_TX_GAIN_FORCE, 1);
156 REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1,
157 AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_RX_BB_GAIN_FORCE, 0);
158 REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1,
159 AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_IQCORR_ENABLE, 0);
160 REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1,
161 AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_AGC2_SETTLING, 28);
162 REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1,
163 AR_PHY_PAPRD_TRAINER_CNTL1_CF_CF_PAPRD_TRAIN_ENABLE, 1);
164 REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL2,
165 AR_PHY_PAPRD_TRAINER_CNTL2_CF_PAPRD_INIT_RX_BB_GAIN, 147);
166 REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
167 AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_FINE_CORR_LEN, 4);
168 REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
169 AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_COARSE_CORR_LEN, 4);
170 REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
171 AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_NUM_CORR_STAGES, 7);
172 REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
173 AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_MIN_LOOPBACK_DEL, 1);
174 if (AR_SREV_9485(ah))
175 REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
176 AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP,
177 -3);
178 else
179 REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
180 AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP,
181 -6);
182 REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
183 AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_ADC_DESIRED_SIZE,
184 -15);
185 REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
186 AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_BBTXMIX_DISABLE, 1);
187 REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL4,
188 AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_SAFETY_DELTA, 0);
189 REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL4,
190 AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_MIN_CORR, 400);
191 REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL4,
192 AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_NUM_TRAIN_SAMPLES,
193 100);
194 REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_0_B0,
195 AR_PHY_PAPRD_PRE_POST_SCALING, 261376);
196 REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_1_B0,
197 AR_PHY_PAPRD_PRE_POST_SCALING, 248079);
198 REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_2_B0,
199 AR_PHY_PAPRD_PRE_POST_SCALING, 233759);
200 REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_3_B0,
201 AR_PHY_PAPRD_PRE_POST_SCALING, 220464);
202 REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_4_B0,
203 AR_PHY_PAPRD_PRE_POST_SCALING, 208194);
204 REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_5_B0,
205 AR_PHY_PAPRD_PRE_POST_SCALING, 196949);
206 REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_6_B0,
207 AR_PHY_PAPRD_PRE_POST_SCALING, 185706);
208 REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_7_B0,
209 AR_PHY_PAPRD_PRE_POST_SCALING, 175487);
210 return 0;
211 }
212
213 static void ar9003_paprd_get_gain_table(struct ath_hw *ah)
214 {
215 u32 *entry = ah->paprd_gain_table_entries;
216 u8 *index = ah->paprd_gain_table_index;
217 u32 reg = AR_PHY_TXGAIN_TABLE;
218 int i;
219
220 memset(entry, 0, sizeof(ah->paprd_gain_table_entries));
221 memset(index, 0, sizeof(ah->paprd_gain_table_index));
222
223 for (i = 0; i < 32; i++) {
224 entry[i] = REG_READ(ah, reg);
225 index[i] = (entry[i] >> 24) & 0xff;
226 reg += 4;
227 }
228 }
229
230 static unsigned int ar9003_get_desired_gain(struct ath_hw *ah, int chain,
231 int target_power)
232 {
233 int olpc_gain_delta = 0;
234 int alpha_therm, alpha_volt;
235 int therm_cal_value, volt_cal_value;
236 int therm_value, volt_value;
237 int thermal_gain_corr, voltage_gain_corr;
238 int desired_scale, desired_gain = 0;
239 u32 reg;
240
241 REG_CLR_BIT(ah, AR_PHY_PAPRD_TRAINER_STAT1,
242 AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE);
243 desired_scale = REG_READ_FIELD(ah, AR_PHY_TPC_12,
244 AR_PHY_TPC_12_DESIRED_SCALE_HT40_5);
245 alpha_therm = REG_READ_FIELD(ah, AR_PHY_TPC_19,
246 AR_PHY_TPC_19_ALPHA_THERM);
247 alpha_volt = REG_READ_FIELD(ah, AR_PHY_TPC_19,
248 AR_PHY_TPC_19_ALPHA_VOLT);
249 therm_cal_value = REG_READ_FIELD(ah, AR_PHY_TPC_18,
250 AR_PHY_TPC_18_THERM_CAL_VALUE);
251 volt_cal_value = REG_READ_FIELD(ah, AR_PHY_TPC_18,
252 AR_PHY_TPC_18_VOLT_CAL_VALUE);
253 therm_value = REG_READ_FIELD(ah, AR_PHY_BB_THERM_ADC_4,
254 AR_PHY_BB_THERM_ADC_4_LATEST_THERM_VALUE);
255 volt_value = REG_READ_FIELD(ah, AR_PHY_BB_THERM_ADC_4,
256 AR_PHY_BB_THERM_ADC_4_LATEST_VOLT_VALUE);
257
258 if (chain == 0)
259 reg = AR_PHY_TPC_11_B0;
260 else if (chain == 1)
261 reg = AR_PHY_TPC_11_B1;
262 else
263 reg = AR_PHY_TPC_11_B2;
264
265 olpc_gain_delta = REG_READ_FIELD(ah, reg,
266 AR_PHY_TPC_11_OLPC_GAIN_DELTA);
267
268 if (olpc_gain_delta >= 128)
269 olpc_gain_delta = olpc_gain_delta - 256;
270
271 thermal_gain_corr = (alpha_therm * (therm_value - therm_cal_value) +
272 (256 / 2)) / 256;
273 voltage_gain_corr = (alpha_volt * (volt_value - volt_cal_value) +
274 (128 / 2)) / 128;
275 desired_gain = target_power - olpc_gain_delta - thermal_gain_corr -
276 voltage_gain_corr + desired_scale;
277
278 return desired_gain;
279 }
280
281 static void ar9003_tx_force_gain(struct ath_hw *ah, unsigned int gain_index)
282 {
283 int selected_gain_entry, txbb1dbgain, txbb6dbgain, txmxrgain;
284 int padrvgnA, padrvgnB, padrvgnC, padrvgnD;
285 u32 *gain_table_entries = ah->paprd_gain_table_entries;
286
287 selected_gain_entry = gain_table_entries[gain_index];
288 txbb1dbgain = selected_gain_entry & 0x7;
289 txbb6dbgain = (selected_gain_entry >> 3) & 0x3;
290 txmxrgain = (selected_gain_entry >> 5) & 0xf;
291 padrvgnA = (selected_gain_entry >> 9) & 0xf;
292 padrvgnB = (selected_gain_entry >> 13) & 0xf;
293 padrvgnC = (selected_gain_entry >> 17) & 0xf;
294 padrvgnD = (selected_gain_entry >> 21) & 0x3;
295
296 REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN,
297 AR_PHY_TX_FORCED_GAIN_FORCED_TXBB1DBGAIN, txbb1dbgain);
298 REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN,
299 AR_PHY_TX_FORCED_GAIN_FORCED_TXBB6DBGAIN, txbb6dbgain);
300 REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN,
301 AR_PHY_TX_FORCED_GAIN_FORCED_TXMXRGAIN, txmxrgain);
302 REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN,
303 AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGNA, padrvgnA);
304 REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN,
305 AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGNB, padrvgnB);
306 REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN,
307 AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGNC, padrvgnC);
308 REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN,
309 AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGND, padrvgnD);
310 REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN,
311 AR_PHY_TX_FORCED_GAIN_FORCED_ENABLE_PAL, 0);
312 REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN,
313 AR_PHY_TX_FORCED_GAIN_FORCE_TX_GAIN, 0);
314 REG_RMW_FIELD(ah, AR_PHY_TPC_1, AR_PHY_TPC_1_FORCED_DAC_GAIN, 0);
315 REG_RMW_FIELD(ah, AR_PHY_TPC_1, AR_PHY_TPC_1_FORCE_DAC_GAIN, 0);
316 }
317
318 static inline int find_expn(int num)
319 {
320 return fls(num) - 1;
321 }
322
323 static inline int find_proper_scale(int expn, int N)
324 {
325 return (expn > N) ? expn - 10 : 0;
326 }
327
328 #define NUM_BIN 23
329
330 static bool create_pa_curve(u32 *data_L, u32 *data_U, u32 *pa_table, u16 *gain)
331 {
332 unsigned int thresh_accum_cnt;
333 int x_est[NUM_BIN + 1], Y[NUM_BIN + 1], theta[NUM_BIN + 1];
334 int PA_in[NUM_BIN + 1];
335 int B1_tmp[NUM_BIN + 1], B2_tmp[NUM_BIN + 1];
336 unsigned int B1_abs_max, B2_abs_max;
337 int max_index, scale_factor;
338 int y_est[NUM_BIN + 1];
339 int x_est_fxp1_nonlin, x_tilde[NUM_BIN + 1];
340 unsigned int x_tilde_abs;
341 int G_fxp, Y_intercept, order_x_by_y, M, I, L, sum_y_sqr, sum_y_quad;
342 int Q_x, Q_B1, Q_B2, beta_raw, alpha_raw, scale_B;
343 int Q_scale_B, Q_beta, Q_alpha, alpha, beta, order_1, order_2;
344 int order1_5x, order2_3x, order1_5x_rem, order2_3x_rem;
345 int y5, y3, tmp;
346 int theta_low_bin = 0;
347 int i;
348
349 /* disregard any bin that contains <= 16 samples */
350 thresh_accum_cnt = 16;
351 scale_factor = 5;
352 max_index = 0;
353 memset(theta, 0, sizeof(theta));
354 memset(x_est, 0, sizeof(x_est));
355 memset(Y, 0, sizeof(Y));
356 memset(y_est, 0, sizeof(y_est));
357 memset(x_tilde, 0, sizeof(x_tilde));
358
359 for (i = 0; i < NUM_BIN; i++) {
360 s32 accum_cnt, accum_tx, accum_rx, accum_ang;
361
362 /* number of samples */
363 accum_cnt = data_L[i] & 0xffff;
364
365 if (accum_cnt <= thresh_accum_cnt)
366 continue;
367
368 /* sum(tx amplitude) */
369 accum_tx = ((data_L[i] >> 16) & 0xffff) |
370 ((data_U[i] & 0x7ff) << 16);
371
372 /* sum(rx amplitude distance to lower bin edge) */
373 accum_rx = ((data_U[i] >> 11) & 0x1f) |
374 ((data_L[i + 23] & 0xffff) << 5);
375
376 /* sum(angles) */
377 accum_ang = ((data_L[i + 23] >> 16) & 0xffff) |
378 ((data_U[i + 23] & 0x7ff) << 16);
379
380 accum_tx <<= scale_factor;
381 accum_rx <<= scale_factor;
382 x_est[i + 1] = (((accum_tx + accum_cnt) / accum_cnt) + 32) >>
383 scale_factor;
384
385 Y[i + 1] = ((((accum_rx + accum_cnt) / accum_cnt) + 32) >>
386 scale_factor) +
387 (1 << scale_factor) * max_index + 16;
388
389 if (accum_ang >= (1 << 26))
390 accum_ang -= 1 << 27;
391
392 theta[i + 1] = ((accum_ang * (1 << scale_factor)) + accum_cnt) /
393 accum_cnt;
394
395 max_index++;
396 }
397
398 /*
399 * Find average theta of first 5 bin and all of those to same value.
400 * Curve is linear at that range.
401 */
402 for (i = 1; i < 6; i++)
403 theta_low_bin += theta[i];
404
405 theta_low_bin = theta_low_bin / 5;
406 for (i = 1; i < 6; i++)
407 theta[i] = theta_low_bin;
408
409 /* Set values at origin */
410 theta[0] = theta_low_bin;
411 for (i = 0; i <= max_index; i++)
412 theta[i] -= theta_low_bin;
413
414 x_est[0] = 0;
415 Y[0] = 0;
416 scale_factor = 8;
417
418 /* low signal gain */
419 if (x_est[6] == x_est[3])
420 return false;
421
422 G_fxp =
423 (((Y[6] - Y[3]) * 1 << scale_factor) +
424 (x_est[6] - x_est[3])) / (x_est[6] - x_est[3]);
425
426 /* prevent division by zero */
427 if (G_fxp == 0)
428 return false;
429
430 Y_intercept =
431 (G_fxp * (x_est[0] - x_est[3]) +
432 (1 << scale_factor)) / (1 << scale_factor) + Y[3];
433
434 for (i = 0; i <= max_index; i++)
435 y_est[i] = Y[i] - Y_intercept;
436
437 for (i = 0; i <= 3; i++) {
438 y_est[i] = i * 32;
439 x_est[i] = ((y_est[i] * 1 << scale_factor) + G_fxp) / G_fxp;
440 }
441
442 if (y_est[max_index] == 0)
443 return false;
444
445 x_est_fxp1_nonlin =
446 x_est[max_index] - ((1 << scale_factor) * y_est[max_index] +
447 G_fxp) / G_fxp;
448
449 order_x_by_y =
450 (x_est_fxp1_nonlin + y_est[max_index]) / y_est[max_index];
451
452 if (order_x_by_y == 0)
453 M = 10;
454 else if (order_x_by_y == 1)
455 M = 9;
456 else
457 M = 8;
458
459 I = (max_index > 15) ? 7 : max_index >> 1;
460 L = max_index - I;
461 scale_factor = 8;
462 sum_y_sqr = 0;
463 sum_y_quad = 0;
464 x_tilde_abs = 0;
465
466 for (i = 0; i <= L; i++) {
467 unsigned int y_sqr;
468 unsigned int y_quad;
469 unsigned int tmp_abs;
470
471 /* prevent division by zero */
472 if (y_est[i + I] == 0)
473 return false;
474
475 x_est_fxp1_nonlin =
476 x_est[i + I] - ((1 << scale_factor) * y_est[i + I] +
477 G_fxp) / G_fxp;
478
479 x_tilde[i] =
480 (x_est_fxp1_nonlin * (1 << M) + y_est[i + I]) / y_est[i +
481 I];
482 x_tilde[i] =
483 (x_tilde[i] * (1 << M) + y_est[i + I]) / y_est[i + I];
484 x_tilde[i] =
485 (x_tilde[i] * (1 << M) + y_est[i + I]) / y_est[i + I];
486 y_sqr =
487 (y_est[i + I] * y_est[i + I] +
488 (scale_factor * scale_factor)) / (scale_factor *
489 scale_factor);
490 tmp_abs = abs(x_tilde[i]);
491 if (tmp_abs > x_tilde_abs)
492 x_tilde_abs = tmp_abs;
493
494 y_quad = y_sqr * y_sqr;
495 sum_y_sqr = sum_y_sqr + y_sqr;
496 sum_y_quad = sum_y_quad + y_quad;
497 B1_tmp[i] = y_sqr * (L + 1);
498 B2_tmp[i] = y_sqr;
499 }
500
501 B1_abs_max = 0;
502 B2_abs_max = 0;
503 for (i = 0; i <= L; i++) {
504 int abs_val;
505
506 B1_tmp[i] -= sum_y_sqr;
507 B2_tmp[i] = sum_y_quad - sum_y_sqr * B2_tmp[i];
508
509 abs_val = abs(B1_tmp[i]);
510 if (abs_val > B1_abs_max)
511 B1_abs_max = abs_val;
512
513 abs_val = abs(B2_tmp[i]);
514 if (abs_val > B2_abs_max)
515 B2_abs_max = abs_val;
516 }
517
518 Q_x = find_proper_scale(find_expn(x_tilde_abs), 10);
519 Q_B1 = find_proper_scale(find_expn(B1_abs_max), 10);
520 Q_B2 = find_proper_scale(find_expn(B2_abs_max), 10);
521
522 beta_raw = 0;
523 alpha_raw = 0;
524 for (i = 0; i <= L; i++) {
525 x_tilde[i] = x_tilde[i] / (1 << Q_x);
526 B1_tmp[i] = B1_tmp[i] / (1 << Q_B1);
527 B2_tmp[i] = B2_tmp[i] / (1 << Q_B2);
528 beta_raw = beta_raw + B1_tmp[i] * x_tilde[i];
529 alpha_raw = alpha_raw + B2_tmp[i] * x_tilde[i];
530 }
531
532 scale_B =
533 ((sum_y_quad / scale_factor) * (L + 1) -
534 (sum_y_sqr / scale_factor) * sum_y_sqr) * scale_factor;
535
536 Q_scale_B = find_proper_scale(find_expn(abs(scale_B)), 10);
537 scale_B = scale_B / (1 << Q_scale_B);
538 if (scale_B == 0)
539 return false;
540 Q_beta = find_proper_scale(find_expn(abs(beta_raw)), 10);
541 Q_alpha = find_proper_scale(find_expn(abs(alpha_raw)), 10);
542 beta_raw = beta_raw / (1 << Q_beta);
543 alpha_raw = alpha_raw / (1 << Q_alpha);
544 alpha = (alpha_raw << 10) / scale_B;
545 beta = (beta_raw << 10) / scale_B;
546 order_1 = 3 * M - Q_x - Q_B1 - Q_beta + 10 + Q_scale_B;
547 order_2 = 3 * M - Q_x - Q_B2 - Q_alpha + 10 + Q_scale_B;
548 order1_5x = order_1 / 5;
549 order2_3x = order_2 / 3;
550 order1_5x_rem = order_1 - 5 * order1_5x;
551 order2_3x_rem = order_2 - 3 * order2_3x;
552
553 for (i = 0; i < PAPRD_TABLE_SZ; i++) {
554 tmp = i * 32;
555 y5 = ((beta * tmp) >> 6) >> order1_5x;
556 y5 = (y5 * tmp) >> order1_5x;
557 y5 = (y5 * tmp) >> order1_5x;
558 y5 = (y5 * tmp) >> order1_5x;
559 y5 = (y5 * tmp) >> order1_5x;
560 y5 = y5 >> order1_5x_rem;
561 y3 = (alpha * tmp) >> order2_3x;
562 y3 = (y3 * tmp) >> order2_3x;
563 y3 = (y3 * tmp) >> order2_3x;
564 y3 = y3 >> order2_3x_rem;
565 PA_in[i] = y5 + y3 + (256 * tmp) / G_fxp;
566
567 if (i >= 2) {
568 tmp = PA_in[i] - PA_in[i - 1];
569 if (tmp < 0)
570 PA_in[i] =
571 PA_in[i - 1] + (PA_in[i - 1] -
572 PA_in[i - 2]);
573 }
574
575 PA_in[i] = (PA_in[i] < 1400) ? PA_in[i] : 1400;
576 }
577
578 beta_raw = 0;
579 alpha_raw = 0;
580
581 for (i = 0; i <= L; i++) {
582 int theta_tilde =
583 ((theta[i + I] << M) + y_est[i + I]) / y_est[i + I];
584 theta_tilde =
585 ((theta_tilde << M) + y_est[i + I]) / y_est[i + I];
586 theta_tilde =
587 ((theta_tilde << M) + y_est[i + I]) / y_est[i + I];
588 beta_raw = beta_raw + B1_tmp[i] * theta_tilde;
589 alpha_raw = alpha_raw + B2_tmp[i] * theta_tilde;
590 }
591
592 Q_beta = find_proper_scale(find_expn(abs(beta_raw)), 10);
593 Q_alpha = find_proper_scale(find_expn(abs(alpha_raw)), 10);
594 beta_raw = beta_raw / (1 << Q_beta);
595 alpha_raw = alpha_raw / (1 << Q_alpha);
596
597 alpha = (alpha_raw << 10) / scale_B;
598 beta = (beta_raw << 10) / scale_B;
599 order_1 = 3 * M - Q_x - Q_B1 - Q_beta + 10 + Q_scale_B + 5;
600 order_2 = 3 * M - Q_x - Q_B2 - Q_alpha + 10 + Q_scale_B + 5;
601 order1_5x = order_1 / 5;
602 order2_3x = order_2 / 3;
603 order1_5x_rem = order_1 - 5 * order1_5x;
604 order2_3x_rem = order_2 - 3 * order2_3x;
605
606 for (i = 0; i < PAPRD_TABLE_SZ; i++) {
607 int PA_angle;
608
609 /* pa_table[4] is calculated from PA_angle for i=5 */
610 if (i == 4)
611 continue;
612
613 tmp = i * 32;
614 if (beta > 0)
615 y5 = (((beta * tmp - 64) >> 6) -
616 (1 << order1_5x)) / (1 << order1_5x);
617 else
618 y5 = ((((beta * tmp - 64) >> 6) +
619 (1 << order1_5x)) / (1 << order1_5x));
620
621 y5 = (y5 * tmp) / (1 << order1_5x);
622 y5 = (y5 * tmp) / (1 << order1_5x);
623 y5 = (y5 * tmp) / (1 << order1_5x);
624 y5 = (y5 * tmp) / (1 << order1_5x);
625 y5 = y5 / (1 << order1_5x_rem);
626
627 if (beta > 0)
628 y3 = (alpha * tmp -
629 (1 << order2_3x)) / (1 << order2_3x);
630 else
631 y3 = (alpha * tmp +
632 (1 << order2_3x)) / (1 << order2_3x);
633 y3 = (y3 * tmp) / (1 << order2_3x);
634 y3 = (y3 * tmp) / (1 << order2_3x);
635 y3 = y3 / (1 << order2_3x_rem);
636
637 if (i < 4) {
638 PA_angle = 0;
639 } else {
640 PA_angle = y5 + y3;
641 if (PA_angle < -150)
642 PA_angle = -150;
643 else if (PA_angle > 150)
644 PA_angle = 150;
645 }
646
647 pa_table[i] = ((PA_in[i] & 0x7ff) << 11) + (PA_angle & 0x7ff);
648 if (i == 5) {
649 PA_angle = (PA_angle + 2) >> 1;
650 pa_table[i - 1] = ((PA_in[i - 1] & 0x7ff) << 11) +
651 (PA_angle & 0x7ff);
652 }
653 }
654
655 *gain = G_fxp;
656 return true;
657 }
658
659 void ar9003_paprd_populate_single_table(struct ath_hw *ah,
660 struct ath9k_hw_cal_data *caldata,
661 int chain)
662 {
663 u32 *paprd_table_val = caldata->pa_table[chain];
664 u32 small_signal_gain = caldata->small_signal_gain[chain];
665 u32 training_power = ah->paprd_training_power;
666 u32 reg = 0;
667 int i;
668
669 if (chain == 0)
670 reg = AR_PHY_PAPRD_MEM_TAB_B0;
671 else if (chain == 1)
672 reg = AR_PHY_PAPRD_MEM_TAB_B1;
673 else if (chain == 2)
674 reg = AR_PHY_PAPRD_MEM_TAB_B2;
675
676 for (i = 0; i < PAPRD_TABLE_SZ; i++) {
677 REG_WRITE(ah, reg, paprd_table_val[i]);
678 reg = reg + 4;
679 }
680
681 if (chain == 0)
682 reg = AR_PHY_PA_GAIN123_B0;
683 else if (chain == 1)
684 reg = AR_PHY_PA_GAIN123_B1;
685 else
686 reg = AR_PHY_PA_GAIN123_B2;
687
688 REG_RMW_FIELD(ah, reg, AR_PHY_PA_GAIN123_PA_GAIN1, small_signal_gain);
689
690 REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL1_B0,
691 AR_PHY_PAPRD_CTRL1_PAPRD_POWER_AT_AM2AM_CAL,
692 training_power);
693
694 if (ah->caps.tx_chainmask & BIT(1))
695 REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL1_B1,
696 AR_PHY_PAPRD_CTRL1_PAPRD_POWER_AT_AM2AM_CAL,
697 training_power);
698
699 if (ah->caps.tx_chainmask & BIT(2))
700 REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL1_B2,
701 AR_PHY_PAPRD_CTRL1_PAPRD_POWER_AT_AM2AM_CAL,
702 training_power);
703 }
704 EXPORT_SYMBOL(ar9003_paprd_populate_single_table);
705
706 int ar9003_paprd_setup_gain_table(struct ath_hw *ah, int chain)
707 {
708 unsigned int i, desired_gain, gain_index;
709 unsigned int train_power = ah->paprd_training_power;
710
711 desired_gain = ar9003_get_desired_gain(ah, chain, train_power);
712
713 gain_index = 0;
714 for (i = 0; i < 32; i++) {
715 if (ah->paprd_gain_table_index[i] >= desired_gain)
716 break;
717 gain_index++;
718 }
719
720 ar9003_tx_force_gain(ah, gain_index);
721
722 REG_CLR_BIT(ah, AR_PHY_PAPRD_TRAINER_STAT1,
723 AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE);
724
725 return 0;
726 }
727 EXPORT_SYMBOL(ar9003_paprd_setup_gain_table);
728
729 int ar9003_paprd_create_curve(struct ath_hw *ah,
730 struct ath9k_hw_cal_data *caldata, int chain)
731 {
732 u16 *small_signal_gain = &caldata->small_signal_gain[chain];
733 u32 *pa_table = caldata->pa_table[chain];
734 u32 *data_L, *data_U;
735 int i, status = 0;
736 u32 *buf;
737 u32 reg;
738
739 memset(caldata->pa_table[chain], 0, sizeof(caldata->pa_table[chain]));
740
741 buf = kmalloc(2 * 48 * sizeof(u32), GFP_ATOMIC);
742 if (!buf)
743 return -ENOMEM;
744
745 data_L = &buf[0];
746 data_U = &buf[48];
747
748 REG_CLR_BIT(ah, AR_PHY_CHAN_INFO_MEMORY,
749 AR_PHY_CHAN_INFO_MEMORY_CHANINFOMEM_S2_READ);
750
751 reg = AR_PHY_CHAN_INFO_TAB_0;
752 for (i = 0; i < 48; i++)
753 data_L[i] = REG_READ(ah, reg + (i << 2));
754
755 REG_SET_BIT(ah, AR_PHY_CHAN_INFO_MEMORY,
756 AR_PHY_CHAN_INFO_MEMORY_CHANINFOMEM_S2_READ);
757
758 for (i = 0; i < 48; i++)
759 data_U[i] = REG_READ(ah, reg + (i << 2));
760
761 if (!create_pa_curve(data_L, data_U, pa_table, small_signal_gain))
762 status = -2;
763
764 REG_CLR_BIT(ah, AR_PHY_PAPRD_TRAINER_STAT1,
765 AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE);
766
767 kfree(buf);
768
769 return status;
770 }
771 EXPORT_SYMBOL(ar9003_paprd_create_curve);
772
773 int ar9003_paprd_init_table(struct ath_hw *ah)
774 {
775 int ret;
776
777 ret = ar9003_paprd_setup_single_table(ah);
778 if (ret < 0)
779 return ret;
780
781 ar9003_paprd_get_gain_table(ah);
782 return 0;
783 }
784 EXPORT_SYMBOL(ar9003_paprd_init_table);
785
786 bool ar9003_paprd_is_done(struct ath_hw *ah)
787 {
788 return !!REG_READ_FIELD(ah, AR_PHY_PAPRD_TRAINER_STAT1,
789 AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE);
790 }
791 EXPORT_SYMBOL(ar9003_paprd_is_done);