diff options
author | Sujith Manoharan <c_manoha@qca.qualcomm.com> | 2014-01-01 23:36:21 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2014-01-03 15:37:01 -0500 |
commit | 42dd98b028912c1a27cb6bd26fe5014eeab97202 (patch) | |
tree | 704e6a3101b05dd3b7af054a1dcb746b0387c1a9 | |
parent | 47acf6f544314a383e2208bf0ba29528bb6302d2 (diff) |
ath9k: Fix AR955x RX sensitivity
AR955x has problems with RX sensitivity in 2G. This patch
adds a routine to select range_osdac dynamically on a
per-chain basis to address this issue.
Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r-- | drivers/net/wireless/ath/ath9k/ar9003_calib.c | 223 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/ar9003_phy.h | 10 |
2 files changed, 233 insertions, 0 deletions
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c index 97e09d5f3a42..8c145cd98c1c 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c | |||
@@ -326,6 +326,224 @@ static void ar9003_hw_init_cal_settings(struct ath_hw *ah) | |||
326 | ah->supp_cals = IQ_MISMATCH_CAL; | 326 | ah->supp_cals = IQ_MISMATCH_CAL; |
327 | } | 327 | } |
328 | 328 | ||
329 | #define OFF_UPPER_LT 24 | ||
330 | #define OFF_LOWER_LT 7 | ||
331 | |||
332 | static bool ar9003_hw_dynamic_osdac_selection(struct ath_hw *ah, | ||
333 | bool txiqcal_done) | ||
334 | { | ||
335 | struct ath_common *common = ath9k_hw_common(ah); | ||
336 | int ch0_done, osdac_ch0, dc_off_ch0_i1, dc_off_ch0_q1, dc_off_ch0_i2, | ||
337 | dc_off_ch0_q2, dc_off_ch0_i3, dc_off_ch0_q3; | ||
338 | int ch1_done, osdac_ch1, dc_off_ch1_i1, dc_off_ch1_q1, dc_off_ch1_i2, | ||
339 | dc_off_ch1_q2, dc_off_ch1_i3, dc_off_ch1_q3; | ||
340 | int ch2_done, osdac_ch2, dc_off_ch2_i1, dc_off_ch2_q1, dc_off_ch2_i2, | ||
341 | dc_off_ch2_q2, dc_off_ch2_i3, dc_off_ch2_q3; | ||
342 | bool status; | ||
343 | u32 temp, val; | ||
344 | |||
345 | /* | ||
346 | * Clear offset and IQ calibration, run AGC cal. | ||
347 | */ | ||
348 | REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, | ||
349 | AR_PHY_AGC_CONTROL_OFFSET_CAL); | ||
350 | REG_CLR_BIT(ah, AR_PHY_TX_IQCAL_CONTROL_0, | ||
351 | AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL); | ||
352 | REG_WRITE(ah, AR_PHY_AGC_CONTROL, | ||
353 | REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_CAL); | ||
354 | |||
355 | status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, | ||
356 | AR_PHY_AGC_CONTROL_CAL, | ||
357 | 0, AH_WAIT_TIMEOUT); | ||
358 | if (!status) { | ||
359 | ath_dbg(common, CALIBRATE, | ||
360 | "AGC cal without offset cal failed to complete in 1ms"); | ||
361 | return false; | ||
362 | } | ||
363 | |||
364 | /* | ||
365 | * Allow only offset calibration and disable the others | ||
366 | * (Carrier Leak calibration, TX Filter calibration and | ||
367 | * Peak Detector offset calibration). | ||
368 | */ | ||
369 | REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, | ||
370 | AR_PHY_AGC_CONTROL_OFFSET_CAL); | ||
371 | REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, | ||
372 | AR_PHY_CL_CAL_ENABLE); | ||
373 | REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, | ||
374 | AR_PHY_AGC_CONTROL_FLTR_CAL); | ||
375 | REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, | ||
376 | AR_PHY_AGC_CONTROL_PKDET_CAL); | ||
377 | |||
378 | ch0_done = 0; | ||
379 | ch1_done = 0; | ||
380 | ch2_done = 0; | ||
381 | |||
382 | while ((ch0_done == 0) || (ch1_done == 0) || (ch2_done == 0)) { | ||
383 | osdac_ch0 = (REG_READ(ah, AR_PHY_65NM_CH0_BB1) >> 30) & 0x3; | ||
384 | osdac_ch1 = (REG_READ(ah, AR_PHY_65NM_CH1_BB1) >> 30) & 0x3; | ||
385 | osdac_ch2 = (REG_READ(ah, AR_PHY_65NM_CH2_BB1) >> 30) & 0x3; | ||
386 | |||
387 | REG_SET_BIT(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); | ||
388 | |||
389 | REG_WRITE(ah, AR_PHY_AGC_CONTROL, | ||
390 | REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_CAL); | ||
391 | |||
392 | status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, | ||
393 | AR_PHY_AGC_CONTROL_CAL, | ||
394 | 0, AH_WAIT_TIMEOUT); | ||
395 | if (!status) { | ||
396 | ath_dbg(common, CALIBRATE, | ||
397 | "DC offset cal failed to complete in 1ms"); | ||
398 | return false; | ||
399 | } | ||
400 | |||
401 | REG_CLR_BIT(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); | ||
402 | |||
403 | /* | ||
404 | * High gain. | ||
405 | */ | ||
406 | REG_WRITE(ah, AR_PHY_65NM_CH0_BB3, | ||
407 | ((REG_READ(ah, AR_PHY_65NM_CH0_BB3) & 0xfffffcff) | (1 << 8))); | ||
408 | REG_WRITE(ah, AR_PHY_65NM_CH1_BB3, | ||
409 | ((REG_READ(ah, AR_PHY_65NM_CH1_BB3) & 0xfffffcff) | (1 << 8))); | ||
410 | REG_WRITE(ah, AR_PHY_65NM_CH2_BB3, | ||
411 | ((REG_READ(ah, AR_PHY_65NM_CH2_BB3) & 0xfffffcff) | (1 << 8))); | ||
412 | |||
413 | temp = REG_READ(ah, AR_PHY_65NM_CH0_BB3); | ||
414 | dc_off_ch0_i1 = (temp >> 26) & 0x1f; | ||
415 | dc_off_ch0_q1 = (temp >> 21) & 0x1f; | ||
416 | |||
417 | temp = REG_READ(ah, AR_PHY_65NM_CH1_BB3); | ||
418 | dc_off_ch1_i1 = (temp >> 26) & 0x1f; | ||
419 | dc_off_ch1_q1 = (temp >> 21) & 0x1f; | ||
420 | |||
421 | temp = REG_READ(ah, AR_PHY_65NM_CH2_BB3); | ||
422 | dc_off_ch2_i1 = (temp >> 26) & 0x1f; | ||
423 | dc_off_ch2_q1 = (temp >> 21) & 0x1f; | ||
424 | |||
425 | /* | ||
426 | * Low gain. | ||
427 | */ | ||
428 | REG_WRITE(ah, AR_PHY_65NM_CH0_BB3, | ||
429 | ((REG_READ(ah, AR_PHY_65NM_CH0_BB3) & 0xfffffcff) | (2 << 8))); | ||
430 | REG_WRITE(ah, AR_PHY_65NM_CH1_BB3, | ||
431 | ((REG_READ(ah, AR_PHY_65NM_CH1_BB3) & 0xfffffcff) | (2 << 8))); | ||
432 | REG_WRITE(ah, AR_PHY_65NM_CH2_BB3, | ||
433 | ((REG_READ(ah, AR_PHY_65NM_CH2_BB3) & 0xfffffcff) | (2 << 8))); | ||
434 | |||
435 | temp = REG_READ(ah, AR_PHY_65NM_CH0_BB3); | ||
436 | dc_off_ch0_i2 = (temp >> 26) & 0x1f; | ||
437 | dc_off_ch0_q2 = (temp >> 21) & 0x1f; | ||
438 | |||
439 | temp = REG_READ(ah, AR_PHY_65NM_CH1_BB3); | ||
440 | dc_off_ch1_i2 = (temp >> 26) & 0x1f; | ||
441 | dc_off_ch1_q2 = (temp >> 21) & 0x1f; | ||
442 | |||
443 | temp = REG_READ(ah, AR_PHY_65NM_CH2_BB3); | ||
444 | dc_off_ch2_i2 = (temp >> 26) & 0x1f; | ||
445 | dc_off_ch2_q2 = (temp >> 21) & 0x1f; | ||
446 | |||
447 | /* | ||
448 | * Loopback. | ||
449 | */ | ||
450 | REG_WRITE(ah, AR_PHY_65NM_CH0_BB3, | ||
451 | ((REG_READ(ah, AR_PHY_65NM_CH0_BB3) & 0xfffffcff) | (3 << 8))); | ||
452 | REG_WRITE(ah, AR_PHY_65NM_CH1_BB3, | ||
453 | ((REG_READ(ah, AR_PHY_65NM_CH1_BB3) & 0xfffffcff) | (3 << 8))); | ||
454 | REG_WRITE(ah, AR_PHY_65NM_CH2_BB3, | ||
455 | ((REG_READ(ah, AR_PHY_65NM_CH2_BB3) & 0xfffffcff) | (3 << 8))); | ||
456 | |||
457 | temp = REG_READ(ah, AR_PHY_65NM_CH0_BB3); | ||
458 | dc_off_ch0_i3 = (temp >> 26) & 0x1f; | ||
459 | dc_off_ch0_q3 = (temp >> 21) & 0x1f; | ||
460 | |||
461 | temp = REG_READ(ah, AR_PHY_65NM_CH1_BB3); | ||
462 | dc_off_ch1_i3 = (temp >> 26) & 0x1f; | ||
463 | dc_off_ch1_q3 = (temp >> 21) & 0x1f; | ||
464 | |||
465 | temp = REG_READ(ah, AR_PHY_65NM_CH2_BB3); | ||
466 | dc_off_ch2_i3 = (temp >> 26) & 0x1f; | ||
467 | dc_off_ch2_q3 = (temp >> 21) & 0x1f; | ||
468 | |||
469 | if ((dc_off_ch0_i1 > OFF_UPPER_LT) || (dc_off_ch0_i1 < OFF_LOWER_LT) || | ||
470 | (dc_off_ch0_i2 > OFF_UPPER_LT) || (dc_off_ch0_i2 < OFF_LOWER_LT) || | ||
471 | (dc_off_ch0_i3 > OFF_UPPER_LT) || (dc_off_ch0_i3 < OFF_LOWER_LT) || | ||
472 | (dc_off_ch0_q1 > OFF_UPPER_LT) || (dc_off_ch0_q1 < OFF_LOWER_LT) || | ||
473 | (dc_off_ch0_q2 > OFF_UPPER_LT) || (dc_off_ch0_q2 < OFF_LOWER_LT) || | ||
474 | (dc_off_ch0_q3 > OFF_UPPER_LT) || (dc_off_ch0_q3 < OFF_LOWER_LT)) { | ||
475 | if (osdac_ch0 == 3) { | ||
476 | ch0_done = 1; | ||
477 | } else { | ||
478 | osdac_ch0++; | ||
479 | |||
480 | val = REG_READ(ah, AR_PHY_65NM_CH0_BB1) & 0x3fffffff; | ||
481 | val |= (osdac_ch0 << 30); | ||
482 | REG_WRITE(ah, AR_PHY_65NM_CH0_BB1, val); | ||
483 | |||
484 | ch0_done = 0; | ||
485 | } | ||
486 | } else { | ||
487 | ch0_done = 1; | ||
488 | } | ||
489 | |||
490 | if ((dc_off_ch1_i1 > OFF_UPPER_LT) || (dc_off_ch1_i1 < OFF_LOWER_LT) || | ||
491 | (dc_off_ch1_i2 > OFF_UPPER_LT) || (dc_off_ch1_i2 < OFF_LOWER_LT) || | ||
492 | (dc_off_ch1_i3 > OFF_UPPER_LT) || (dc_off_ch1_i3 < OFF_LOWER_LT) || | ||
493 | (dc_off_ch1_q1 > OFF_UPPER_LT) || (dc_off_ch1_q1 < OFF_LOWER_LT) || | ||
494 | (dc_off_ch1_q2 > OFF_UPPER_LT) || (dc_off_ch1_q2 < OFF_LOWER_LT) || | ||
495 | (dc_off_ch1_q3 > OFF_UPPER_LT) || (dc_off_ch1_q3 < OFF_LOWER_LT)) { | ||
496 | if (osdac_ch1 == 3) { | ||
497 | ch1_done = 1; | ||
498 | } else { | ||
499 | osdac_ch1++; | ||
500 | |||
501 | val = REG_READ(ah, AR_PHY_65NM_CH1_BB1) & 0x3fffffff; | ||
502 | val |= (osdac_ch1 << 30); | ||
503 | REG_WRITE(ah, AR_PHY_65NM_CH1_BB1, val); | ||
504 | |||
505 | ch1_done = 0; | ||
506 | } | ||
507 | } else { | ||
508 | ch1_done = 1; | ||
509 | } | ||
510 | |||
511 | if ((dc_off_ch2_i1 > OFF_UPPER_LT) || (dc_off_ch2_i1 < OFF_LOWER_LT) || | ||
512 | (dc_off_ch2_i2 > OFF_UPPER_LT) || (dc_off_ch2_i2 < OFF_LOWER_LT) || | ||
513 | (dc_off_ch2_i3 > OFF_UPPER_LT) || (dc_off_ch2_i3 < OFF_LOWER_LT) || | ||
514 | (dc_off_ch2_q1 > OFF_UPPER_LT) || (dc_off_ch2_q1 < OFF_LOWER_LT) || | ||
515 | (dc_off_ch2_q2 > OFF_UPPER_LT) || (dc_off_ch2_q2 < OFF_LOWER_LT) || | ||
516 | (dc_off_ch2_q3 > OFF_UPPER_LT) || (dc_off_ch2_q3 < OFF_LOWER_LT)) { | ||
517 | if (osdac_ch2 == 3) { | ||
518 | ch2_done = 1; | ||
519 | } else { | ||
520 | osdac_ch2++; | ||
521 | |||
522 | val = REG_READ(ah, AR_PHY_65NM_CH2_BB1) & 0x3fffffff; | ||
523 | val |= (osdac_ch2 << 30); | ||
524 | REG_WRITE(ah, AR_PHY_65NM_CH2_BB1, val); | ||
525 | |||
526 | ch2_done = 0; | ||
527 | } | ||
528 | } else { | ||
529 | ch2_done = 1; | ||
530 | } | ||
531 | } | ||
532 | |||
533 | REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, | ||
534 | AR_PHY_AGC_CONTROL_OFFSET_CAL); | ||
535 | REG_SET_BIT(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); | ||
536 | |||
537 | /* | ||
538 | * We don't need to check txiqcal_done here since it is always | ||
539 | * set for AR9550. | ||
540 | */ | ||
541 | REG_SET_BIT(ah, AR_PHY_TX_IQCAL_CONTROL_0, | ||
542 | AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL); | ||
543 | |||
544 | return true; | ||
545 | } | ||
546 | |||
329 | /* | 547 | /* |
330 | * solve 4x4 linear equation used in loopback iq cal. | 548 | * solve 4x4 linear equation used in loopback iq cal. |
331 | */ | 549 | */ |
@@ -1271,6 +1489,11 @@ static bool ar9003_hw_init_cal_soc(struct ath_hw *ah, | |||
1271 | REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); | 1489 | REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); |
1272 | } | 1490 | } |
1273 | 1491 | ||
1492 | if (AR_SREV_9550(ah) && IS_CHAN_2GHZ(chan)) { | ||
1493 | if (!ar9003_hw_dynamic_osdac_selection(ah, txiqcal_done)) | ||
1494 | return false; | ||
1495 | } | ||
1496 | |||
1274 | skip_tx_iqcal: | 1497 | skip_tx_iqcal: |
1275 | if (run_agc_cal || !(ah->ah_flags & AH_FASTCC)) { | 1498 | if (run_agc_cal || !(ah->ah_flags & AH_FASTCC)) { |
1276 | if (AR_SREV_9330_11(ah)) | 1499 | if (AR_SREV_9330_11(ah)) |
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h index 94a8598d0e95..50767155c05b 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h | |||
@@ -670,6 +670,16 @@ | |||
670 | #define AR_PHY_65NM_CH1_RXTX4 0x1650c | 670 | #define AR_PHY_65NM_CH1_RXTX4 0x1650c |
671 | #define AR_PHY_65NM_CH2_RXTX4 0x1690c | 671 | #define AR_PHY_65NM_CH2_RXTX4 0x1690c |
672 | 672 | ||
673 | #define AR_PHY_65NM_CH0_BB1 0x16140 | ||
674 | #define AR_PHY_65NM_CH0_BB2 0x16144 | ||
675 | #define AR_PHY_65NM_CH0_BB3 0x16148 | ||
676 | #define AR_PHY_65NM_CH1_BB1 0x16540 | ||
677 | #define AR_PHY_65NM_CH1_BB2 0x16544 | ||
678 | #define AR_PHY_65NM_CH1_BB3 0x16548 | ||
679 | #define AR_PHY_65NM_CH2_BB1 0x16940 | ||
680 | #define AR_PHY_65NM_CH2_BB2 0x16944 | ||
681 | #define AR_PHY_65NM_CH2_BB3 0x16948 | ||
682 | |||
673 | #define AR_PHY_65NM_CH0_SYNTH12_VREFMUL3 0x00780000 | 683 | #define AR_PHY_65NM_CH0_SYNTH12_VREFMUL3 0x00780000 |
674 | #define AR_PHY_65NM_CH0_SYNTH12_VREFMUL3_S 19 | 684 | #define AR_PHY_65NM_CH0_SYNTH12_VREFMUL3_S 19 |
675 | #define AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK 0x00000004 | 685 | #define AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK 0x00000004 |