diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath9k/ar9003_calib.c')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/ar9003_calib.c | 387 |
1 files changed, 146 insertions, 241 deletions
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c index 4a4cd88429c0..f276cb922b4d 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c | |||
@@ -18,13 +18,13 @@ | |||
18 | #include "hw-ops.h" | 18 | #include "hw-ops.h" |
19 | #include "ar9003_phy.h" | 19 | #include "ar9003_phy.h" |
20 | 20 | ||
21 | #define MPASS 3 | ||
22 | #define MAX_MEASUREMENT 8 | 21 | #define MAX_MEASUREMENT 8 |
23 | #define MAX_DIFFERENCE 10 | 22 | #define MAX_MAG_DELTA 11 |
23 | #define MAX_PHS_DELTA 10 | ||
24 | 24 | ||
25 | struct coeff { | 25 | struct coeff { |
26 | int mag_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT][MPASS]; | 26 | int mag_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT]; |
27 | int phs_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT][MPASS]; | 27 | int phs_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT]; |
28 | int iqc_coeff[2]; | 28 | int iqc_coeff[2]; |
29 | }; | 29 | }; |
30 | 30 | ||
@@ -185,17 +185,19 @@ static void ar9003_hw_iqcal_collect(struct ath_hw *ah) | |||
185 | 185 | ||
186 | /* Accumulate IQ cal measures for active chains */ | 186 | /* Accumulate IQ cal measures for active chains */ |
187 | for (i = 0; i < AR5416_MAX_CHAINS; i++) { | 187 | for (i = 0; i < AR5416_MAX_CHAINS; i++) { |
188 | ah->totalPowerMeasI[i] += | 188 | if (ah->txchainmask & BIT(i)) { |
189 | REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); | 189 | ah->totalPowerMeasI[i] += |
190 | ah->totalPowerMeasQ[i] += | 190 | REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); |
191 | REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); | 191 | ah->totalPowerMeasQ[i] += |
192 | ah->totalIqCorrMeas[i] += | 192 | REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); |
193 | (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); | 193 | ah->totalIqCorrMeas[i] += |
194 | ath_dbg(ath9k_hw_common(ah), ATH_DBG_CALIBRATE, | 194 | (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); |
195 | "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n", | 195 | ath_dbg(ath9k_hw_common(ah), ATH_DBG_CALIBRATE, |
196 | ah->cal_samples, i, ah->totalPowerMeasI[i], | 196 | "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n", |
197 | ah->totalPowerMeasQ[i], | 197 | ah->cal_samples, i, ah->totalPowerMeasI[i], |
198 | ah->totalIqCorrMeas[i]); | 198 | ah->totalPowerMeasQ[i], |
199 | ah->totalIqCorrMeas[i]); | ||
200 | } | ||
199 | } | 201 | } |
200 | } | 202 | } |
201 | 203 | ||
@@ -608,36 +610,48 @@ static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah, | |||
608 | return true; | 610 | return true; |
609 | } | 611 | } |
610 | 612 | ||
611 | static bool ar9003_hw_compute_closest_pass_and_avg(int *mp_coeff, int *mp_avg) | 613 | static void ar9003_hw_detect_outlier(int *mp_coeff, int nmeasurement, |
614 | int max_delta) | ||
612 | { | 615 | { |
613 | int diff[MPASS]; | 616 | int mp_max = -64, max_idx = 0; |
614 | 617 | int mp_min = 63, min_idx = 0; | |
615 | diff[0] = abs(mp_coeff[0] - mp_coeff[1]); | 618 | int mp_avg = 0, i, outlier_idx = 0; |
616 | diff[1] = abs(mp_coeff[1] - mp_coeff[2]); | 619 | |
617 | diff[2] = abs(mp_coeff[2] - mp_coeff[0]); | 620 | /* find min/max mismatch across all calibrated gains */ |
618 | 621 | for (i = 0; i < nmeasurement; i++) { | |
619 | if (diff[0] > MAX_DIFFERENCE && | 622 | mp_avg += mp_coeff[i]; |
620 | diff[1] > MAX_DIFFERENCE && | 623 | if (mp_coeff[i] > mp_max) { |
621 | diff[2] > MAX_DIFFERENCE) | 624 | mp_max = mp_coeff[i]; |
622 | return false; | 625 | max_idx = i; |
626 | } else if (mp_coeff[i] < mp_min) { | ||
627 | mp_min = mp_coeff[i]; | ||
628 | min_idx = i; | ||
629 | } | ||
630 | } | ||
623 | 631 | ||
624 | if (diff[0] <= diff[1] && diff[0] <= diff[2]) | 632 | /* find average (exclude max abs value) */ |
625 | *mp_avg = (mp_coeff[0] + mp_coeff[1]) / 2; | 633 | for (i = 0; i < nmeasurement; i++) { |
626 | else if (diff[1] <= diff[2]) | 634 | if ((abs(mp_coeff[i]) < abs(mp_max)) || |
627 | *mp_avg = (mp_coeff[1] + mp_coeff[2]) / 2; | 635 | (abs(mp_coeff[i]) < abs(mp_min))) |
628 | else | 636 | mp_avg += mp_coeff[i]; |
629 | *mp_avg = (mp_coeff[2] + mp_coeff[0]) / 2; | 637 | } |
638 | mp_avg /= (nmeasurement - 1); | ||
630 | 639 | ||
631 | return true; | 640 | /* detect outlier */ |
641 | if (abs(mp_max - mp_min) > max_delta) { | ||
642 | if (abs(mp_max - mp_avg) > abs(mp_min - mp_avg)) | ||
643 | outlier_idx = max_idx; | ||
644 | else | ||
645 | outlier_idx = min_idx; | ||
646 | } | ||
647 | mp_coeff[outlier_idx] = mp_avg; | ||
632 | } | 648 | } |
633 | 649 | ||
634 | static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah, | 650 | static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah, |
635 | u8 num_chains, | 651 | u8 num_chains, |
636 | struct coeff *coeff) | 652 | struct coeff *coeff) |
637 | { | 653 | { |
638 | struct ath_common *common = ath9k_hw_common(ah); | ||
639 | int i, im, nmeasurement; | 654 | int i, im, nmeasurement; |
640 | int magnitude, phase; | ||
641 | u32 tx_corr_coeff[MAX_MEASUREMENT][AR9300_MAX_CHAINS]; | 655 | u32 tx_corr_coeff[MAX_MEASUREMENT][AR9300_MAX_CHAINS]; |
642 | 656 | ||
643 | memset(tx_corr_coeff, 0, sizeof(tx_corr_coeff)); | 657 | memset(tx_corr_coeff, 0, sizeof(tx_corr_coeff)); |
@@ -657,37 +671,28 @@ static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah, | |||
657 | 671 | ||
658 | /* Load the average of 2 passes */ | 672 | /* Load the average of 2 passes */ |
659 | for (i = 0; i < num_chains; i++) { | 673 | for (i = 0; i < num_chains; i++) { |
660 | if (AR_SREV_9485(ah)) | 674 | nmeasurement = REG_READ_FIELD(ah, |
661 | nmeasurement = REG_READ_FIELD(ah, | 675 | AR_PHY_TX_IQCAL_STATUS_B0, |
662 | AR_PHY_TX_IQCAL_STATUS_B0_9485, | 676 | AR_PHY_CALIBRATED_GAINS_0); |
663 | AR_PHY_CALIBRATED_GAINS_0); | ||
664 | else | ||
665 | nmeasurement = REG_READ_FIELD(ah, | ||
666 | AR_PHY_TX_IQCAL_STATUS_B0, | ||
667 | AR_PHY_CALIBRATED_GAINS_0); | ||
668 | 677 | ||
669 | if (nmeasurement > MAX_MEASUREMENT) | 678 | if (nmeasurement > MAX_MEASUREMENT) |
670 | nmeasurement = MAX_MEASUREMENT; | 679 | nmeasurement = MAX_MEASUREMENT; |
671 | 680 | ||
672 | for (im = 0; im < nmeasurement; im++) { | 681 | /* detect outlier only if nmeasurement > 1 */ |
673 | /* | 682 | if (nmeasurement > 1) { |
674 | * Determine which 2 passes are closest and compute avg | 683 | /* Detect magnitude outlier */ |
675 | * magnitude | 684 | ar9003_hw_detect_outlier(coeff->mag_coeff[i], |
676 | */ | 685 | nmeasurement, MAX_MAG_DELTA); |
677 | if (!ar9003_hw_compute_closest_pass_and_avg(coeff->mag_coeff[i][im], | ||
678 | &magnitude)) | ||
679 | goto disable_txiqcal; | ||
680 | 686 | ||
681 | /* | 687 | /* Detect phase outlier */ |
682 | * Determine which 2 passes are closest and compute avg | 688 | ar9003_hw_detect_outlier(coeff->phs_coeff[i], |
683 | * phase | 689 | nmeasurement, MAX_PHS_DELTA); |
684 | */ | 690 | } |
685 | if (!ar9003_hw_compute_closest_pass_and_avg(coeff->phs_coeff[i][im], | 691 | |
686 | &phase)) | 692 | for (im = 0; im < nmeasurement; im++) { |
687 | goto disable_txiqcal; | ||
688 | 693 | ||
689 | coeff->iqc_coeff[0] = (magnitude & 0x7f) | | 694 | coeff->iqc_coeff[0] = (coeff->mag_coeff[i][im] & 0x7f) | |
690 | ((phase & 0x7f) << 7); | 695 | ((coeff->phs_coeff[i][im] & 0x7f) << 7); |
691 | 696 | ||
692 | if ((im % 2) == 0) | 697 | if ((im % 2) == 0) |
693 | REG_RMW_FIELD(ah, tx_corr_coeff[im][i], | 698 | REG_RMW_FIELD(ah, tx_corr_coeff[im][i], |
@@ -707,141 +712,37 @@ static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah, | |||
707 | 712 | ||
708 | return; | 713 | return; |
709 | 714 | ||
710 | disable_txiqcal: | ||
711 | REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_3, | ||
712 | AR_PHY_TX_IQCAL_CONTROL_3_IQCORR_EN, 0x0); | ||
713 | REG_RMW_FIELD(ah, AR_PHY_RX_IQCAL_CORR_B0, | ||
714 | AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN, 0x0); | ||
715 | |||
716 | ath_dbg(common, ATH_DBG_CALIBRATE, "TX IQ Cal disabled\n"); | ||
717 | } | 715 | } |
718 | 716 | ||
719 | static void ar9003_hw_tx_iq_cal(struct ath_hw *ah) | 717 | static bool ar9003_hw_tx_iq_cal_run(struct ath_hw *ah) |
720 | { | 718 | { |
721 | struct ath_common *common = ath9k_hw_common(ah); | 719 | struct ath_common *common = ath9k_hw_common(ah); |
722 | static const u32 txiqcal_status[AR9300_MAX_CHAINS] = { | ||
723 | AR_PHY_TX_IQCAL_STATUS_B0, | ||
724 | AR_PHY_TX_IQCAL_STATUS_B1, | ||
725 | AR_PHY_TX_IQCAL_STATUS_B2, | ||
726 | }; | ||
727 | static const u32 chan_info_tab[] = { | ||
728 | AR_PHY_CHAN_INFO_TAB_0, | ||
729 | AR_PHY_CHAN_INFO_TAB_1, | ||
730 | AR_PHY_CHAN_INFO_TAB_2, | ||
731 | }; | ||
732 | struct coeff coeff; | ||
733 | s32 iq_res[6]; | ||
734 | s32 i, j, ip, im, nmeasurement; | ||
735 | u8 nchains = get_streams(common->tx_chainmask); | ||
736 | |||
737 | for (ip = 0; ip < MPASS; ip++) { | ||
738 | REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_1, | ||
739 | AR_PHY_TX_IQCAQL_CONTROL_1_IQCORR_I_Q_COFF_DELPT, | ||
740 | DELPT); | ||
741 | REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_START, | ||
742 | AR_PHY_TX_IQCAL_START_DO_CAL, | ||
743 | AR_PHY_TX_IQCAL_START_DO_CAL); | ||
744 | |||
745 | if (!ath9k_hw_wait(ah, AR_PHY_TX_IQCAL_START, | ||
746 | AR_PHY_TX_IQCAL_START_DO_CAL, | ||
747 | 0, AH_WAIT_TIMEOUT)) { | ||
748 | ath_dbg(common, ATH_DBG_CALIBRATE, | ||
749 | "Tx IQ Cal not complete.\n"); | ||
750 | goto TX_IQ_CAL_FAILED; | ||
751 | } | ||
752 | |||
753 | nmeasurement = REG_READ_FIELD(ah, AR_PHY_TX_IQCAL_STATUS_B0, | ||
754 | AR_PHY_CALIBRATED_GAINS_0); | ||
755 | if (nmeasurement > MAX_MEASUREMENT) | ||
756 | nmeasurement = MAX_MEASUREMENT; | ||
757 | |||
758 | for (i = 0; i < nchains; i++) { | ||
759 | ath_dbg(common, ATH_DBG_CALIBRATE, | ||
760 | "Doing Tx IQ Cal for chain %d.\n", i); | ||
761 | for (im = 0; im < nmeasurement; im++) { | ||
762 | if (REG_READ(ah, txiqcal_status[i]) & | ||
763 | AR_PHY_TX_IQCAL_STATUS_FAILED) { | ||
764 | ath_dbg(common, ATH_DBG_CALIBRATE, | ||
765 | "Tx IQ Cal failed for chain %d.\n", i); | ||
766 | goto TX_IQ_CAL_FAILED; | ||
767 | } | ||
768 | |||
769 | for (j = 0; j < 3; j++) { | ||
770 | u8 idx = 2 * j, | ||
771 | offset = 4 * (3 * im + j); | ||
772 | |||
773 | REG_RMW_FIELD(ah, AR_PHY_CHAN_INFO_MEMORY, | ||
774 | AR_PHY_CHAN_INFO_TAB_S2_READ, | ||
775 | 0); | ||
776 | |||
777 | /* 32 bits */ | ||
778 | iq_res[idx] = REG_READ(ah, | ||
779 | chan_info_tab[i] + | ||
780 | offset); | ||
781 | |||
782 | REG_RMW_FIELD(ah, AR_PHY_CHAN_INFO_MEMORY, | ||
783 | AR_PHY_CHAN_INFO_TAB_S2_READ, | ||
784 | 1); | ||
785 | |||
786 | /* 16 bits */ | ||
787 | iq_res[idx+1] = 0xffff & REG_READ(ah, | ||
788 | chan_info_tab[i] + | ||
789 | offset); | ||
790 | |||
791 | ath_dbg(common, ATH_DBG_CALIBRATE, | ||
792 | "IQ RES[%d]=0x%x IQ_RES[%d]=0x%x\n", | ||
793 | idx, iq_res[idx], idx+1, iq_res[idx+1]); | ||
794 | } | ||
795 | |||
796 | if (!ar9003_hw_calc_iq_corr(ah, i, iq_res, | ||
797 | coeff.iqc_coeff)) { | ||
798 | ath_dbg(common, ATH_DBG_CALIBRATE, | ||
799 | "Failed in calculation of IQ correction.\n"); | ||
800 | goto TX_IQ_CAL_FAILED; | ||
801 | } | ||
802 | coeff.mag_coeff[i][im][ip] = | ||
803 | coeff.iqc_coeff[0] & 0x7f; | ||
804 | coeff.phs_coeff[i][im][ip] = | ||
805 | (coeff.iqc_coeff[0] >> 7) & 0x7f; | ||
806 | |||
807 | if (coeff.mag_coeff[i][im][ip] > 63) | ||
808 | coeff.mag_coeff[i][im][ip] -= 128; | ||
809 | if (coeff.phs_coeff[i][im][ip] > 63) | ||
810 | coeff.phs_coeff[i][im][ip] -= 128; | ||
811 | |||
812 | } | ||
813 | } | ||
814 | } | ||
815 | |||
816 | ar9003_hw_tx_iqcal_load_avg_2_passes(ah, nchains, &coeff); | ||
817 | |||
818 | return; | ||
819 | |||
820 | TX_IQ_CAL_FAILED: | ||
821 | ath_dbg(common, ATH_DBG_CALIBRATE, "Tx IQ Cal failed\n"); | ||
822 | } | ||
823 | |||
824 | static void ar9003_hw_tx_iq_cal_run(struct ath_hw *ah) | ||
825 | { | ||
826 | u8 tx_gain_forced; | 720 | u8 tx_gain_forced; |
827 | 721 | ||
828 | REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_1_9485, | ||
829 | AR_PHY_TX_IQCAQL_CONTROL_1_IQCORR_I_Q_COFF_DELPT, DELPT); | ||
830 | tx_gain_forced = REG_READ_FIELD(ah, AR_PHY_TX_FORCED_GAIN, | 722 | tx_gain_forced = REG_READ_FIELD(ah, AR_PHY_TX_FORCED_GAIN, |
831 | AR_PHY_TXGAIN_FORCE); | 723 | AR_PHY_TXGAIN_FORCE); |
832 | if (tx_gain_forced) | 724 | if (tx_gain_forced) |
833 | REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN, | 725 | REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN, |
834 | AR_PHY_TXGAIN_FORCE, 0); | 726 | AR_PHY_TXGAIN_FORCE, 0); |
835 | 727 | ||
836 | REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_START_9485, | 728 | REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_START, |
837 | AR_PHY_TX_IQCAL_START_DO_CAL_9485, 1); | 729 | AR_PHY_TX_IQCAL_START_DO_CAL, 1); |
730 | |||
731 | if (!ath9k_hw_wait(ah, AR_PHY_TX_IQCAL_START, | ||
732 | AR_PHY_TX_IQCAL_START_DO_CAL, 0, | ||
733 | AH_WAIT_TIMEOUT)) { | ||
734 | ath_dbg(common, ATH_DBG_CALIBRATE, | ||
735 | "Tx IQ Cal is not completed.\n"); | ||
736 | return false; | ||
737 | } | ||
738 | return true; | ||
838 | } | 739 | } |
839 | 740 | ||
840 | static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah) | 741 | static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah) |
841 | { | 742 | { |
842 | struct ath_common *common = ath9k_hw_common(ah); | 743 | struct ath_common *common = ath9k_hw_common(ah); |
843 | const u32 txiqcal_status[AR9300_MAX_CHAINS] = { | 744 | const u32 txiqcal_status[AR9300_MAX_CHAINS] = { |
844 | AR_PHY_TX_IQCAL_STATUS_B0_9485, | 745 | AR_PHY_TX_IQCAL_STATUS_B0, |
845 | AR_PHY_TX_IQCAL_STATUS_B1, | 746 | AR_PHY_TX_IQCAL_STATUS_B1, |
846 | AR_PHY_TX_IQCAL_STATUS_B2, | 747 | AR_PHY_TX_IQCAL_STATUS_B2, |
847 | }; | 748 | }; |
@@ -853,7 +754,7 @@ static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah) | |||
853 | struct coeff coeff; | 754 | struct coeff coeff; |
854 | s32 iq_res[6]; | 755 | s32 iq_res[6]; |
855 | u8 num_chains = 0; | 756 | u8 num_chains = 0; |
856 | int i, ip, im, j; | 757 | int i, im, j; |
857 | int nmeasurement; | 758 | int nmeasurement; |
858 | 759 | ||
859 | for (i = 0; i < AR9300_MAX_CHAINS; i++) { | 760 | for (i = 0; i < AR9300_MAX_CHAINS; i++) { |
@@ -861,71 +762,69 @@ static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah) | |||
861 | num_chains++; | 762 | num_chains++; |
862 | } | 763 | } |
863 | 764 | ||
864 | for (ip = 0; ip < MPASS; ip++) { | 765 | for (i = 0; i < num_chains; i++) { |
865 | for (i = 0; i < num_chains; i++) { | 766 | nmeasurement = REG_READ_FIELD(ah, |
866 | nmeasurement = REG_READ_FIELD(ah, | 767 | AR_PHY_TX_IQCAL_STATUS_B0, |
867 | AR_PHY_TX_IQCAL_STATUS_B0_9485, | 768 | AR_PHY_CALIBRATED_GAINS_0); |
868 | AR_PHY_CALIBRATED_GAINS_0); | 769 | if (nmeasurement > MAX_MEASUREMENT) |
869 | if (nmeasurement > MAX_MEASUREMENT) | 770 | nmeasurement = MAX_MEASUREMENT; |
870 | nmeasurement = MAX_MEASUREMENT; | ||
871 | 771 | ||
872 | for (im = 0; im < nmeasurement; im++) { | 772 | for (im = 0; im < nmeasurement; im++) { |
873 | ath_dbg(common, ATH_DBG_CALIBRATE, | 773 | ath_dbg(common, ATH_DBG_CALIBRATE, |
874 | "Doing Tx IQ Cal for chain %d.\n", i); | 774 | "Doing Tx IQ Cal for chain %d.\n", i); |
875 | 775 | ||
876 | if (REG_READ(ah, txiqcal_status[i]) & | 776 | if (REG_READ(ah, txiqcal_status[i]) & |
877 | AR_PHY_TX_IQCAL_STATUS_FAILED) { | 777 | AR_PHY_TX_IQCAL_STATUS_FAILED) { |
878 | ath_dbg(common, ATH_DBG_CALIBRATE, | 778 | ath_dbg(common, ATH_DBG_CALIBRATE, |
879 | "Tx IQ Cal failed for chain %d.\n", i); | 779 | "Tx IQ Cal failed for chain %d.\n", i); |
880 | goto tx_iqcal_fail; | 780 | goto tx_iqcal_fail; |
881 | } | 781 | } |
882 | 782 | ||
883 | for (j = 0; j < 3; j++) { | 783 | for (j = 0; j < 3; j++) { |
884 | u32 idx = 2 * j, offset = 4 * (3 * im + j); | 784 | u32 idx = 2 * j, offset = 4 * (3 * im + j); |
885 | 785 | ||
886 | REG_RMW_FIELD(ah, | 786 | REG_RMW_FIELD(ah, |
887 | AR_PHY_CHAN_INFO_MEMORY, | 787 | AR_PHY_CHAN_INFO_MEMORY, |
888 | AR_PHY_CHAN_INFO_TAB_S2_READ, | 788 | AR_PHY_CHAN_INFO_TAB_S2_READ, |
889 | 0); | 789 | 0); |
890 | 790 | ||
891 | /* 32 bits */ | 791 | /* 32 bits */ |
892 | iq_res[idx] = REG_READ(ah, | 792 | iq_res[idx] = REG_READ(ah, |
893 | chan_info_tab[i] + | 793 | chan_info_tab[i] + |
894 | offset); | 794 | offset); |
895 | 795 | ||
896 | REG_RMW_FIELD(ah, | 796 | REG_RMW_FIELD(ah, |
897 | AR_PHY_CHAN_INFO_MEMORY, | 797 | AR_PHY_CHAN_INFO_MEMORY, |
898 | AR_PHY_CHAN_INFO_TAB_S2_READ, | 798 | AR_PHY_CHAN_INFO_TAB_S2_READ, |
899 | 1); | 799 | 1); |
900 | 800 | ||
901 | /* 16 bits */ | 801 | /* 16 bits */ |
902 | iq_res[idx + 1] = 0xffff & REG_READ(ah, | 802 | iq_res[idx + 1] = 0xffff & REG_READ(ah, |
903 | chan_info_tab[i] + offset); | 803 | chan_info_tab[i] + offset); |
904 | 804 | ||
905 | ath_dbg(common, ATH_DBG_CALIBRATE, | 805 | ath_dbg(common, ATH_DBG_CALIBRATE, |
906 | "IQ RES[%d]=0x%x" | 806 | "IQ RES[%d]=0x%x" |
907 | "IQ_RES[%d]=0x%x\n", | 807 | "IQ_RES[%d]=0x%x\n", |
908 | idx, iq_res[idx], idx + 1, | 808 | idx, iq_res[idx], idx + 1, |
909 | iq_res[idx + 1]); | 809 | iq_res[idx + 1]); |
910 | } | 810 | } |
911 | 811 | ||
912 | if (!ar9003_hw_calc_iq_corr(ah, i, iq_res, | 812 | if (!ar9003_hw_calc_iq_corr(ah, i, iq_res, |
913 | coeff.iqc_coeff)) { | 813 | coeff.iqc_coeff)) { |
914 | ath_dbg(common, ATH_DBG_CALIBRATE, | 814 | ath_dbg(common, ATH_DBG_CALIBRATE, |
915 | "Failed in calculation of IQ correction.\n"); | 815 | "Failed in calculation of \ |
916 | goto tx_iqcal_fail; | 816 | IQ correction.\n"); |
917 | } | 817 | goto tx_iqcal_fail; |
818 | } | ||
918 | 819 | ||
919 | coeff.mag_coeff[i][im][ip] = | 820 | coeff.mag_coeff[i][im] = coeff.iqc_coeff[0] & 0x7f; |
920 | coeff.iqc_coeff[0] & 0x7f; | 821 | coeff.phs_coeff[i][im] = |
921 | coeff.phs_coeff[i][im][ip] = | 822 | (coeff.iqc_coeff[0] >> 7) & 0x7f; |
922 | (coeff.iqc_coeff[0] >> 7) & 0x7f; | ||
923 | 823 | ||
924 | if (coeff.mag_coeff[i][im][ip] > 63) | 824 | if (coeff.mag_coeff[i][im] > 63) |
925 | coeff.mag_coeff[i][im][ip] -= 128; | 825 | coeff.mag_coeff[i][im] -= 128; |
926 | if (coeff.phs_coeff[i][im][ip] > 63) | 826 | if (coeff.phs_coeff[i][im] > 63) |
927 | coeff.phs_coeff[i][im][ip] -= 128; | 827 | coeff.phs_coeff[i][im] -= 128; |
928 | } | ||
929 | } | 828 | } |
930 | } | 829 | } |
931 | ar9003_hw_tx_iqcal_load_avg_2_passes(ah, num_chains, &coeff); | 830 | ar9003_hw_tx_iqcal_load_avg_2_passes(ah, num_chains, &coeff); |
@@ -940,31 +839,37 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah, | |||
940 | struct ath9k_channel *chan) | 839 | struct ath9k_channel *chan) |
941 | { | 840 | { |
942 | struct ath_common *common = ath9k_hw_common(ah); | 841 | struct ath_common *common = ath9k_hw_common(ah); |
842 | struct ath9k_hw_capabilities *pCap = &ah->caps; | ||
943 | int val; | 843 | int val; |
844 | bool txiqcal_done = false; | ||
944 | 845 | ||
945 | val = REG_READ(ah, AR_ENT_OTP); | 846 | val = REG_READ(ah, AR_ENT_OTP); |
946 | ath_dbg(common, ATH_DBG_CALIBRATE, "ath9k: AR_ENT_OTP 0x%x\n", val); | 847 | ath_dbg(common, ATH_DBG_CALIBRATE, "ath9k: AR_ENT_OTP 0x%x\n", val); |
947 | 848 | ||
948 | if (AR_SREV_9485(ah)) | 849 | /* Configure rx/tx chains before running AGC/TxiQ cals */ |
949 | ar9003_hw_set_chain_masks(ah, 0x1, 0x1); | 850 | if (val & AR_ENT_OTP_CHAIN2_DISABLE) |
950 | else if (val & AR_ENT_OTP_CHAIN2_DISABLE) | ||
951 | ar9003_hw_set_chain_masks(ah, 0x3, 0x3); | 851 | ar9003_hw_set_chain_masks(ah, 0x3, 0x3); |
952 | else | 852 | else |
953 | /* | 853 | ar9003_hw_set_chain_masks(ah, pCap->rx_chainmask, |
954 | * 0x7 = 0b111 , AR9003 needs to be configured for 3-chain | 854 | pCap->tx_chainmask); |
955 | * mode before running AGC/TxIQ cals | ||
956 | */ | ||
957 | ar9003_hw_set_chain_masks(ah, 0x7, 0x7); | ||
958 | 855 | ||
959 | /* Do Tx IQ Calibration */ | 856 | /* Do Tx IQ Calibration */ |
960 | if (AR_SREV_9485(ah)) | 857 | REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_1, |
961 | ar9003_hw_tx_iq_cal_run(ah); | 858 | AR_PHY_TX_IQCAL_CONTROL_1_IQCORR_I_Q_COFF_DELPT, |
962 | else | 859 | DELPT); |
963 | ar9003_hw_tx_iq_cal(ah); | ||
964 | 860 | ||
965 | REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS); | 861 | /* |
966 | udelay(5); | 862 | * For AR9485 or later chips, TxIQ cal runs as part of |
967 | REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); | 863 | * AGC calibration |
864 | */ | ||
865 | if (AR_SREV_9485_OR_LATER(ah)) | ||
866 | txiqcal_done = true; | ||
867 | else { | ||
868 | txiqcal_done = ar9003_hw_tx_iq_cal_run(ah); | ||
869 | REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS); | ||
870 | udelay(5); | ||
871 | REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); | ||
872 | } | ||
968 | 873 | ||
969 | /* Calibrate the AGC */ | 874 | /* Calibrate the AGC */ |
970 | REG_WRITE(ah, AR_PHY_AGC_CONTROL, | 875 | REG_WRITE(ah, AR_PHY_AGC_CONTROL, |
@@ -979,7 +884,7 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah, | |||
979 | return false; | 884 | return false; |
980 | } | 885 | } |
981 | 886 | ||
982 | if (AR_SREV_9485(ah)) | 887 | if (txiqcal_done) |
983 | ar9003_hw_tx_iq_cal_post_proc(ah); | 888 | ar9003_hw_tx_iq_cal_post_proc(ah); |
984 | 889 | ||
985 | /* Revert chainmasks to their original values before NF cal */ | 890 | /* Revert chainmasks to their original values before NF cal */ |