diff options
author | Vasanthakumar Thiagarajan <vasanth@atheros.com> | 2010-12-15 10:30:50 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-12-16 15:22:30 -0500 |
commit | 0b2084bc578128be866d6fc9926ed887c3432bb1 (patch) | |
tree | 8c1c7d20e720078dd160e6f70492606423203cfb /drivers/net/wireless/ath/ath9k | |
parent | 895ad7eb21ed228444169dbbff44f3dccfc7e006 (diff) |
ath9k_hw: Tx IQ cal changes for AR9003
Add multiple Tx IQ cal support to improve EVM accross
different power levels.
Signed-off-by: Vasanthakumar Thiagarajan <vasanth@atheros.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/ath/ath9k')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/ar9003_calib.c | 212 |
1 files changed, 108 insertions, 104 deletions
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c index 75a1c6e5195c..4a4cd88429c0 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c | |||
@@ -608,107 +608,6 @@ static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah, | |||
608 | return true; | 608 | return true; |
609 | } | 609 | } |
610 | 610 | ||
611 | static void ar9003_hw_tx_iq_cal(struct ath_hw *ah) | ||
612 | { | ||
613 | struct ath_common *common = ath9k_hw_common(ah); | ||
614 | static const u32 txiqcal_status[AR9300_MAX_CHAINS] = { | ||
615 | AR_PHY_TX_IQCAL_STATUS_B0, | ||
616 | AR_PHY_TX_IQCAL_STATUS_B1, | ||
617 | AR_PHY_TX_IQCAL_STATUS_B2, | ||
618 | }; | ||
619 | static const u_int32_t chan_info_tab[] = { | ||
620 | AR_PHY_CHAN_INFO_TAB_0, | ||
621 | AR_PHY_CHAN_INFO_TAB_1, | ||
622 | AR_PHY_CHAN_INFO_TAB_2, | ||
623 | }; | ||
624 | u32 tx_corr_coeff[AR9300_MAX_CHAINS]; | ||
625 | s32 iq_res[6]; | ||
626 | s32 iqc_coeff[2]; | ||
627 | s32 i, j; | ||
628 | u32 num_chains = 0; | ||
629 | |||
630 | tx_corr_coeff[0] = AR_PHY_TX_IQCAL_CORR_COEFF_B0(0); | ||
631 | tx_corr_coeff[1] = AR_PHY_TX_IQCAL_CORR_COEFF_B1(0); | ||
632 | tx_corr_coeff[2] = AR_PHY_TX_IQCAL_CORR_COEFF_B2(0); | ||
633 | |||
634 | for (i = 0; i < AR9300_MAX_CHAINS; i++) { | ||
635 | if (ah->txchainmask & (1 << i)) | ||
636 | num_chains++; | ||
637 | } | ||
638 | |||
639 | REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_1, | ||
640 | AR_PHY_TX_IQCAQL_CONTROL_1_IQCORR_I_Q_COFF_DELPT, | ||
641 | DELPT); | ||
642 | REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_START, | ||
643 | AR_PHY_TX_IQCAL_START_DO_CAL, | ||
644 | AR_PHY_TX_IQCAL_START_DO_CAL); | ||
645 | |||
646 | if (!ath9k_hw_wait(ah, AR_PHY_TX_IQCAL_START, | ||
647 | AR_PHY_TX_IQCAL_START_DO_CAL, | ||
648 | 0, AH_WAIT_TIMEOUT)) { | ||
649 | ath_dbg(common, ATH_DBG_CALIBRATE, | ||
650 | "Tx IQ Cal not complete.\n"); | ||
651 | goto TX_IQ_CAL_FAILED; | ||
652 | } | ||
653 | |||
654 | for (i = 0; i < num_chains; i++) { | ||
655 | ath_dbg(common, ATH_DBG_CALIBRATE, | ||
656 | "Doing Tx IQ Cal for chain %d.\n", i); | ||
657 | |||
658 | if (REG_READ(ah, txiqcal_status[i]) & | ||
659 | AR_PHY_TX_IQCAL_STATUS_FAILED) { | ||
660 | ath_dbg(common, ATH_DBG_CALIBRATE, | ||
661 | "Tx IQ Cal failed for chain %d.\n", i); | ||
662 | goto TX_IQ_CAL_FAILED; | ||
663 | } | ||
664 | |||
665 | for (j = 0; j < 3; j++) { | ||
666 | u_int8_t idx = 2 * j, | ||
667 | offset = 4 * j; | ||
668 | |||
669 | REG_RMW_FIELD(ah, AR_PHY_CHAN_INFO_MEMORY, | ||
670 | AR_PHY_CHAN_INFO_TAB_S2_READ, 0); | ||
671 | |||
672 | /* 32 bits */ | ||
673 | iq_res[idx] = REG_READ(ah, chan_info_tab[i] + offset); | ||
674 | |||
675 | REG_RMW_FIELD(ah, AR_PHY_CHAN_INFO_MEMORY, | ||
676 | AR_PHY_CHAN_INFO_TAB_S2_READ, 1); | ||
677 | |||
678 | /* 16 bits */ | ||
679 | iq_res[idx+1] = 0xffff & REG_READ(ah, | ||
680 | chan_info_tab[i] + | ||
681 | offset); | ||
682 | |||
683 | ath_dbg(common, ATH_DBG_CALIBRATE, | ||
684 | "IQ RES[%d]=0x%x IQ_RES[%d]=0x%x\n", | ||
685 | idx, iq_res[idx], idx+1, iq_res[idx+1]); | ||
686 | } | ||
687 | |||
688 | if (!ar9003_hw_calc_iq_corr(ah, i, iq_res, iqc_coeff)) { | ||
689 | ath_dbg(common, ATH_DBG_CALIBRATE, | ||
690 | "Failed in calculation of IQ correction.\n"); | ||
691 | goto TX_IQ_CAL_FAILED; | ||
692 | } | ||
693 | |||
694 | ath_dbg(common, ATH_DBG_CALIBRATE, | ||
695 | "IQ_COEFF[0] = 0x%x IQ_COEFF[1] = 0x%x\n", | ||
696 | iqc_coeff[0], iqc_coeff[1]); | ||
697 | |||
698 | REG_RMW_FIELD(ah, tx_corr_coeff[i], | ||
699 | AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE, | ||
700 | iqc_coeff[0]); | ||
701 | } | ||
702 | |||
703 | REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_3, | ||
704 | AR_PHY_TX_IQCAL_CONTROL_3_IQCORR_EN, 0x1); | ||
705 | |||
706 | return; | ||
707 | |||
708 | TX_IQ_CAL_FAILED: | ||
709 | ath_dbg(common, ATH_DBG_CALIBRATE, "Tx IQ Cal failed\n"); | ||
710 | } | ||
711 | |||
712 | static bool ar9003_hw_compute_closest_pass_and_avg(int *mp_coeff, int *mp_avg) | 611 | static bool ar9003_hw_compute_closest_pass_and_avg(int *mp_coeff, int *mp_avg) |
713 | { | 612 | { |
714 | int diff[MPASS]; | 613 | int diff[MPASS]; |
@@ -717,9 +616,9 @@ static bool ar9003_hw_compute_closest_pass_and_avg(int *mp_coeff, int *mp_avg) | |||
717 | diff[1] = abs(mp_coeff[1] - mp_coeff[2]); | 616 | diff[1] = abs(mp_coeff[1] - mp_coeff[2]); |
718 | diff[2] = abs(mp_coeff[2] - mp_coeff[0]); | 617 | diff[2] = abs(mp_coeff[2] - mp_coeff[0]); |
719 | 618 | ||
720 | if (diff[0] > MAX_MEASUREMENT && | 619 | if (diff[0] > MAX_DIFFERENCE && |
721 | diff[1] > MAX_MEASUREMENT && | 620 | diff[1] > MAX_DIFFERENCE && |
722 | diff[2] > MAX_MEASUREMENT) | 621 | diff[2] > MAX_DIFFERENCE) |
723 | return false; | 622 | return false; |
724 | 623 | ||
725 | if (diff[0] <= diff[1] && diff[0] <= diff[2]) | 624 | if (diff[0] <= diff[1] && diff[0] <= diff[2]) |
@@ -817,6 +716,111 @@ disable_txiqcal: | |||
817 | ath_dbg(common, ATH_DBG_CALIBRATE, "TX IQ Cal disabled\n"); | 716 | ath_dbg(common, ATH_DBG_CALIBRATE, "TX IQ Cal disabled\n"); |
818 | } | 717 | } |
819 | 718 | ||
719 | static void ar9003_hw_tx_iq_cal(struct ath_hw *ah) | ||
720 | { | ||
721 | 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 | |||
820 | static void ar9003_hw_tx_iq_cal_run(struct ath_hw *ah) | 824 | static void ar9003_hw_tx_iq_cal_run(struct ath_hw *ah) |
821 | { | 825 | { |
822 | u8 tx_gain_forced; | 826 | u8 tx_gain_forced; |