diff options
Diffstat (limited to 'drivers/net/wireless/ath5k/eeprom.c')
-rw-r--r-- | drivers/net/wireless/ath5k/eeprom.c | 774 |
1 files changed, 542 insertions, 232 deletions
diff --git a/drivers/net/wireless/ath5k/eeprom.c b/drivers/net/wireless/ath5k/eeprom.c index ac45ca47ca87..c0fb3b09ba45 100644 --- a/drivers/net/wireless/ath5k/eeprom.c +++ b/drivers/net/wireless/ath5k/eeprom.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org> | 2 | * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org> |
3 | * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com> | 3 | * Copyright (c) 2006-2009 Nick Kossifidis <mickflemm@gmail.com> |
4 | * Copyright (c) 2008 Felix Fietkau <nbd@openwrt.org> | 4 | * Copyright (c) 2008-2009 Felix Fietkau <nbd@openwrt.org> |
5 | * | 5 | * |
6 | * Permission to use, copy, modify, and distribute this software for any | 6 | * Permission to use, copy, modify, and distribute this software for any |
7 | * purpose with or without fee is hereby granted, provided that the above | 7 | * purpose with or without fee is hereby granted, provided that the above |
@@ -98,11 +98,6 @@ ath5k_eeprom_init_header(struct ath5k_hw *ah) | |||
98 | int ret; | 98 | int ret; |
99 | u16 val; | 99 | u16 val; |
100 | 100 | ||
101 | /* Initial TX thermal adjustment values */ | ||
102 | ee->ee_tx_clip = 4; | ||
103 | ee->ee_pwd_84 = ee->ee_pwd_90 = 1; | ||
104 | ee->ee_gain_select = 1; | ||
105 | |||
106 | /* | 101 | /* |
107 | * Read values from EEPROM and store them in the capability structure | 102 | * Read values from EEPROM and store them in the capability structure |
108 | */ | 103 | */ |
@@ -241,22 +236,22 @@ static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset, | |||
241 | ee->ee_adc_desired_size[mode] = (s8)((val >> 8) & 0xff); | 236 | ee->ee_adc_desired_size[mode] = (s8)((val >> 8) & 0xff); |
242 | switch(mode) { | 237 | switch(mode) { |
243 | case AR5K_EEPROM_MODE_11A: | 238 | case AR5K_EEPROM_MODE_11A: |
244 | ee->ee_ob[mode][3] = (val >> 5) & 0x7; | 239 | ee->ee_ob[mode][3] = (val >> 5) & 0x7; |
245 | ee->ee_db[mode][3] = (val >> 2) & 0x7; | 240 | ee->ee_db[mode][3] = (val >> 2) & 0x7; |
246 | ee->ee_ob[mode][2] = (val << 1) & 0x7; | 241 | ee->ee_ob[mode][2] = (val << 1) & 0x7; |
247 | 242 | ||
248 | AR5K_EEPROM_READ(o++, val); | 243 | AR5K_EEPROM_READ(o++, val); |
249 | ee->ee_ob[mode][2] |= (val >> 15) & 0x1; | 244 | ee->ee_ob[mode][2] |= (val >> 15) & 0x1; |
250 | ee->ee_db[mode][2] = (val >> 12) & 0x7; | 245 | ee->ee_db[mode][2] = (val >> 12) & 0x7; |
251 | ee->ee_ob[mode][1] = (val >> 9) & 0x7; | 246 | ee->ee_ob[mode][1] = (val >> 9) & 0x7; |
252 | ee->ee_db[mode][1] = (val >> 6) & 0x7; | 247 | ee->ee_db[mode][1] = (val >> 6) & 0x7; |
253 | ee->ee_ob[mode][0] = (val >> 3) & 0x7; | 248 | ee->ee_ob[mode][0] = (val >> 3) & 0x7; |
254 | ee->ee_db[mode][0] = val & 0x7; | 249 | ee->ee_db[mode][0] = val & 0x7; |
255 | break; | 250 | break; |
256 | case AR5K_EEPROM_MODE_11G: | 251 | case AR5K_EEPROM_MODE_11G: |
257 | case AR5K_EEPROM_MODE_11B: | 252 | case AR5K_EEPROM_MODE_11B: |
258 | ee->ee_ob[mode][1] = (val >> 4) & 0x7; | 253 | ee->ee_ob[mode][1] = (val >> 4) & 0x7; |
259 | ee->ee_db[mode][1] = val & 0x7; | 254 | ee->ee_db[mode][1] = val & 0x7; |
260 | break; | 255 | break; |
261 | } | 256 | } |
262 | 257 | ||
@@ -504,35 +499,6 @@ ath5k_eeprom_init_modes(struct ath5k_hw *ah) | |||
504 | return 0; | 499 | return 0; |
505 | } | 500 | } |
506 | 501 | ||
507 | /* Used to match PCDAC steps with power values on RF5111 chips | ||
508 | * (eeprom versions < 4). For RF5111 we have 10 pre-defined PCDAC | ||
509 | * steps that match with the power values we read from eeprom. On | ||
510 | * older eeprom versions (< 3.2) these steps are equaly spaced at | ||
511 | * 10% of the pcdac curve -until the curve reaches it's maximum- | ||
512 | * (10 steps from 0 to 100%) but on newer eeprom versions (>= 3.2) | ||
513 | * these 10 steps are spaced in a different way. This function returns | ||
514 | * the pcdac steps based on eeprom version and curve min/max so that we | ||
515 | * can have pcdac/pwr points. | ||
516 | */ | ||
517 | static inline void | ||
518 | ath5k_get_pcdac_intercepts(struct ath5k_hw *ah, u8 min, u8 max, u8 *vp) | ||
519 | { | ||
520 | static const u16 intercepts3[] = | ||
521 | { 0, 5, 10, 20, 30, 50, 70, 85, 90, 95, 100 }; | ||
522 | static const u16 intercepts3_2[] = | ||
523 | { 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 }; | ||
524 | const u16 *ip; | ||
525 | int i; | ||
526 | |||
527 | if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_3_2) | ||
528 | ip = intercepts3_2; | ||
529 | else | ||
530 | ip = intercepts3; | ||
531 | |||
532 | for (i = 0; i < ARRAY_SIZE(intercepts3); i++) | ||
533 | *vp++ = (ip[i] * max + (100 - ip[i]) * min) / 100; | ||
534 | } | ||
535 | |||
536 | /* Read the frequency piers for each mode (mostly used on newer eeproms with 0xff | 502 | /* Read the frequency piers for each mode (mostly used on newer eeproms with 0xff |
537 | * frequency mask) */ | 503 | * frequency mask) */ |
538 | static inline int | 504 | static inline int |
@@ -546,26 +512,25 @@ ath5k_eeprom_read_freq_list(struct ath5k_hw *ah, int *offset, int max, | |||
546 | int ret; | 512 | int ret; |
547 | u16 val; | 513 | u16 val; |
548 | 514 | ||
515 | ee->ee_n_piers[mode] = 0; | ||
549 | while(i < max) { | 516 | while(i < max) { |
550 | AR5K_EEPROM_READ(o++, val); | 517 | AR5K_EEPROM_READ(o++, val); |
551 | 518 | ||
552 | freq1 = (val >> 8) & 0xff; | 519 | freq1 = val & 0xff; |
553 | freq2 = val & 0xff; | 520 | if (!freq1) |
554 | 521 | break; | |
555 | if (freq1) { | ||
556 | pc[i++].freq = ath5k_eeprom_bin2freq(ee, | ||
557 | freq1, mode); | ||
558 | ee->ee_n_piers[mode]++; | ||
559 | } | ||
560 | 522 | ||
561 | if (freq2) { | 523 | pc[i++].freq = ath5k_eeprom_bin2freq(ee, |
562 | pc[i++].freq = ath5k_eeprom_bin2freq(ee, | 524 | freq1, mode); |
563 | freq2, mode); | 525 | ee->ee_n_piers[mode]++; |
564 | ee->ee_n_piers[mode]++; | ||
565 | } | ||
566 | 526 | ||
567 | if (!freq1 || !freq2) | 527 | freq2 = (val >> 8) & 0xff; |
528 | if (!freq2) | ||
568 | break; | 529 | break; |
530 | |||
531 | pc[i++].freq = ath5k_eeprom_bin2freq(ee, | ||
532 | freq2, mode); | ||
533 | ee->ee_n_piers[mode]++; | ||
569 | } | 534 | } |
570 | 535 | ||
571 | /* return new offset */ | 536 | /* return new offset */ |
@@ -652,13 +617,122 @@ ath5k_eeprom_init_11bg_2413(struct ath5k_hw *ah, unsigned int mode, int offset) | |||
652 | return 0; | 617 | return 0; |
653 | } | 618 | } |
654 | 619 | ||
655 | /* Read power calibration for RF5111 chips | 620 | /* |
621 | * Read power calibration for RF5111 chips | ||
622 | * | ||
656 | * For RF5111 we have an XPD -eXternal Power Detector- curve | 623 | * For RF5111 we have an XPD -eXternal Power Detector- curve |
657 | * for each calibrated channel. Each curve has PCDAC steps on | 624 | * for each calibrated channel. Each curve has 0,5dB Power steps |
658 | * x axis and power on y axis and looks like a logarithmic | 625 | * on x axis and PCDAC steps (offsets) on y axis and looks like an |
659 | * function. To recreate the curve and pass the power values | 626 | * exponential function. To recreate the curve we read 11 points |
660 | * on the pcdac table, we read 10 points here and interpolate later. | 627 | * here and interpolate later. |
661 | */ | 628 | */ |
629 | |||
630 | /* Used to match PCDAC steps with power values on RF5111 chips | ||
631 | * (eeprom versions < 4). For RF5111 we have 11 pre-defined PCDAC | ||
632 | * steps that match with the power values we read from eeprom. On | ||
633 | * older eeprom versions (< 3.2) these steps are equaly spaced at | ||
634 | * 10% of the pcdac curve -until the curve reaches it's maximum- | ||
635 | * (11 steps from 0 to 100%) but on newer eeprom versions (>= 3.2) | ||
636 | * these 11 steps are spaced in a different way. This function returns | ||
637 | * the pcdac steps based on eeprom version and curve min/max so that we | ||
638 | * can have pcdac/pwr points. | ||
639 | */ | ||
640 | static inline void | ||
641 | ath5k_get_pcdac_intercepts(struct ath5k_hw *ah, u8 min, u8 max, u8 *vp) | ||
642 | { | ||
643 | const static u16 intercepts3[] = | ||
644 | { 0, 5, 10, 20, 30, 50, 70, 85, 90, 95, 100 }; | ||
645 | const static u16 intercepts3_2[] = | ||
646 | { 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 }; | ||
647 | const u16 *ip; | ||
648 | int i; | ||
649 | |||
650 | if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_3_2) | ||
651 | ip = intercepts3_2; | ||
652 | else | ||
653 | ip = intercepts3; | ||
654 | |||
655 | for (i = 0; i < ARRAY_SIZE(intercepts3); i++) | ||
656 | vp[i] = (ip[i] * max + (100 - ip[i]) * min) / 100; | ||
657 | } | ||
658 | |||
659 | /* Convert RF5111 specific data to generic raw data | ||
660 | * used by interpolation code */ | ||
661 | static int | ||
662 | ath5k_eeprom_convert_pcal_info_5111(struct ath5k_hw *ah, int mode, | ||
663 | struct ath5k_chan_pcal_info *chinfo) | ||
664 | { | ||
665 | struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; | ||
666 | struct ath5k_chan_pcal_info_rf5111 *pcinfo; | ||
667 | struct ath5k_pdgain_info *pd; | ||
668 | u8 pier, point, idx; | ||
669 | u8 *pdgain_idx = ee->ee_pdc_to_idx[mode]; | ||
670 | |||
671 | /* Fill raw data for each calibration pier */ | ||
672 | for (pier = 0; pier < ee->ee_n_piers[mode]; pier++) { | ||
673 | |||
674 | pcinfo = &chinfo[pier].rf5111_info; | ||
675 | |||
676 | /* Allocate pd_curves for this cal pier */ | ||
677 | chinfo[pier].pd_curves = | ||
678 | kcalloc(AR5K_EEPROM_N_PD_CURVES, | ||
679 | sizeof(struct ath5k_pdgain_info), | ||
680 | GFP_KERNEL); | ||
681 | |||
682 | if (!chinfo[pier].pd_curves) | ||
683 | return -ENOMEM; | ||
684 | |||
685 | /* Only one curve for RF5111 | ||
686 | * find out which one and place | ||
687 | * in in pd_curves. | ||
688 | * Note: ee_x_gain is reversed here */ | ||
689 | for (idx = 0; idx < AR5K_EEPROM_N_PD_CURVES; idx++) { | ||
690 | |||
691 | if (!((ee->ee_x_gain[mode] >> idx) & 0x1)) { | ||
692 | pdgain_idx[0] = idx; | ||
693 | break; | ||
694 | } | ||
695 | } | ||
696 | |||
697 | ee->ee_pd_gains[mode] = 1; | ||
698 | |||
699 | pd = &chinfo[pier].pd_curves[idx]; | ||
700 | |||
701 | pd->pd_points = AR5K_EEPROM_N_PWR_POINTS_5111; | ||
702 | |||
703 | /* Allocate pd points for this curve */ | ||
704 | pd->pd_step = kcalloc(AR5K_EEPROM_N_PWR_POINTS_5111, | ||
705 | sizeof(u8), GFP_KERNEL); | ||
706 | if (!pd->pd_step) | ||
707 | return -ENOMEM; | ||
708 | |||
709 | pd->pd_pwr = kcalloc(AR5K_EEPROM_N_PWR_POINTS_5111, | ||
710 | sizeof(s16), GFP_KERNEL); | ||
711 | if (!pd->pd_pwr) | ||
712 | return -ENOMEM; | ||
713 | |||
714 | /* Fill raw dataset | ||
715 | * (convert power to 0.25dB units | ||
716 | * for RF5112 combatibility) */ | ||
717 | for (point = 0; point < pd->pd_points; point++) { | ||
718 | |||
719 | /* Absolute values */ | ||
720 | pd->pd_pwr[point] = 2 * pcinfo->pwr[point]; | ||
721 | |||
722 | /* Already sorted */ | ||
723 | pd->pd_step[point] = pcinfo->pcdac[point]; | ||
724 | } | ||
725 | |||
726 | /* Set min/max pwr */ | ||
727 | chinfo[pier].min_pwr = pd->pd_pwr[0]; | ||
728 | chinfo[pier].max_pwr = pd->pd_pwr[10]; | ||
729 | |||
730 | } | ||
731 | |||
732 | return 0; | ||
733 | } | ||
734 | |||
735 | /* Parse EEPROM data */ | ||
662 | static int | 736 | static int |
663 | ath5k_eeprom_read_pcal_info_5111(struct ath5k_hw *ah, int mode) | 737 | ath5k_eeprom_read_pcal_info_5111(struct ath5k_hw *ah, int mode) |
664 | { | 738 | { |
@@ -747,30 +821,165 @@ ath5k_eeprom_read_pcal_info_5111(struct ath5k_hw *ah, int mode) | |||
747 | cdata->pcdac_max, cdata->pcdac); | 821 | cdata->pcdac_max, cdata->pcdac); |
748 | } | 822 | } |
749 | 823 | ||
750 | return 0; | 824 | return ath5k_eeprom_convert_pcal_info_5111(ah, mode, pcal); |
751 | } | 825 | } |
752 | 826 | ||
753 | /* Read power calibration for RF5112 chips | 827 | |
828 | /* | ||
829 | * Read power calibration for RF5112 chips | ||
830 | * | ||
754 | * For RF5112 we have 4 XPD -eXternal Power Detector- curves | 831 | * For RF5112 we have 4 XPD -eXternal Power Detector- curves |
755 | * for each calibrated channel on 0, -6, -12 and -18dbm but we only | 832 | * for each calibrated channel on 0, -6, -12 and -18dbm but we only |
756 | * use the higher (3) and the lower (0) curves. Each curve has PCDAC | 833 | * use the higher (3) and the lower (0) curves. Each curve has 0.5dB |
757 | * steps on x axis and power on y axis and looks like a linear | 834 | * power steps on x axis and PCDAC steps on y axis and looks like a |
758 | * function. To recreate the curve and pass the power values | 835 | * linear function. To recreate the curve and pass the power values |
759 | * on the pcdac table, we read 4 points for xpd 0 and 3 points | 836 | * on hw, we read 4 points for xpd 0 (lower gain -> max power) |
760 | * for xpd 3 here and interpolate later. | 837 | * and 3 points for xpd 3 (higher gain -> lower power) here and |
838 | * interpolate later. | ||
761 | * | 839 | * |
762 | * Note: Many vendors just use xpd 0 so xpd 3 is zeroed. | 840 | * Note: Many vendors just use xpd 0 so xpd 3 is zeroed. |
763 | */ | 841 | */ |
842 | |||
843 | /* Convert RF5112 specific data to generic raw data | ||
844 | * used by interpolation code */ | ||
845 | static int | ||
846 | ath5k_eeprom_convert_pcal_info_5112(struct ath5k_hw *ah, int mode, | ||
847 | struct ath5k_chan_pcal_info *chinfo) | ||
848 | { | ||
849 | struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; | ||
850 | struct ath5k_chan_pcal_info_rf5112 *pcinfo; | ||
851 | u8 *pdgain_idx = ee->ee_pdc_to_idx[mode]; | ||
852 | unsigned int pier, pdg, point; | ||
853 | |||
854 | /* Fill raw data for each calibration pier */ | ||
855 | for (pier = 0; pier < ee->ee_n_piers[mode]; pier++) { | ||
856 | |||
857 | pcinfo = &chinfo[pier].rf5112_info; | ||
858 | |||
859 | /* Allocate pd_curves for this cal pier */ | ||
860 | chinfo[pier].pd_curves = | ||
861 | kcalloc(AR5K_EEPROM_N_PD_CURVES, | ||
862 | sizeof(struct ath5k_pdgain_info), | ||
863 | GFP_KERNEL); | ||
864 | |||
865 | if (!chinfo[pier].pd_curves) | ||
866 | return -ENOMEM; | ||
867 | |||
868 | /* Fill pd_curves */ | ||
869 | for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) { | ||
870 | |||
871 | u8 idx = pdgain_idx[pdg]; | ||
872 | struct ath5k_pdgain_info *pd = | ||
873 | &chinfo[pier].pd_curves[idx]; | ||
874 | |||
875 | /* Lowest gain curve (max power) */ | ||
876 | if (pdg == 0) { | ||
877 | /* One more point for better accuracy */ | ||
878 | pd->pd_points = AR5K_EEPROM_N_XPD0_POINTS; | ||
879 | |||
880 | /* Allocate pd points for this curve */ | ||
881 | pd->pd_step = kcalloc(pd->pd_points, | ||
882 | sizeof(u8), GFP_KERNEL); | ||
883 | |||
884 | if (!pd->pd_step) | ||
885 | return -ENOMEM; | ||
886 | |||
887 | pd->pd_pwr = kcalloc(pd->pd_points, | ||
888 | sizeof(s16), GFP_KERNEL); | ||
889 | |||
890 | if (!pd->pd_pwr) | ||
891 | return -ENOMEM; | ||
892 | |||
893 | |||
894 | /* Fill raw dataset | ||
895 | * (all power levels are in 0.25dB units) */ | ||
896 | pd->pd_step[0] = pcinfo->pcdac_x0[0]; | ||
897 | pd->pd_pwr[0] = pcinfo->pwr_x0[0]; | ||
898 | |||
899 | for (point = 1; point < pd->pd_points; | ||
900 | point++) { | ||
901 | /* Absolute values */ | ||
902 | pd->pd_pwr[point] = | ||
903 | pcinfo->pwr_x0[point]; | ||
904 | |||
905 | /* Deltas */ | ||
906 | pd->pd_step[point] = | ||
907 | pd->pd_step[point - 1] + | ||
908 | pcinfo->pcdac_x0[point]; | ||
909 | } | ||
910 | |||
911 | /* Set min power for this frequency */ | ||
912 | chinfo[pier].min_pwr = pd->pd_pwr[0]; | ||
913 | |||
914 | /* Highest gain curve (min power) */ | ||
915 | } else if (pdg == 1) { | ||
916 | |||
917 | pd->pd_points = AR5K_EEPROM_N_XPD3_POINTS; | ||
918 | |||
919 | /* Allocate pd points for this curve */ | ||
920 | pd->pd_step = kcalloc(pd->pd_points, | ||
921 | sizeof(u8), GFP_KERNEL); | ||
922 | |||
923 | if (!pd->pd_step) | ||
924 | return -ENOMEM; | ||
925 | |||
926 | pd->pd_pwr = kcalloc(pd->pd_points, | ||
927 | sizeof(s16), GFP_KERNEL); | ||
928 | |||
929 | if (!pd->pd_pwr) | ||
930 | return -ENOMEM; | ||
931 | |||
932 | /* Fill raw dataset | ||
933 | * (all power levels are in 0.25dB units) */ | ||
934 | for (point = 0; point < pd->pd_points; | ||
935 | point++) { | ||
936 | /* Absolute values */ | ||
937 | pd->pd_pwr[point] = | ||
938 | pcinfo->pwr_x3[point]; | ||
939 | |||
940 | /* Fixed points */ | ||
941 | pd->pd_step[point] = | ||
942 | pcinfo->pcdac_x3[point]; | ||
943 | } | ||
944 | |||
945 | /* Since we have a higher gain curve | ||
946 | * override min power */ | ||
947 | chinfo[pier].min_pwr = pd->pd_pwr[0]; | ||
948 | } | ||
949 | } | ||
950 | } | ||
951 | |||
952 | return 0; | ||
953 | } | ||
954 | |||
955 | /* Parse EEPROM data */ | ||
764 | static int | 956 | static int |
765 | ath5k_eeprom_read_pcal_info_5112(struct ath5k_hw *ah, int mode) | 957 | ath5k_eeprom_read_pcal_info_5112(struct ath5k_hw *ah, int mode) |
766 | { | 958 | { |
767 | struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; | 959 | struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; |
768 | struct ath5k_chan_pcal_info_rf5112 *chan_pcal_info; | 960 | struct ath5k_chan_pcal_info_rf5112 *chan_pcal_info; |
769 | struct ath5k_chan_pcal_info *gen_chan_info; | 961 | struct ath5k_chan_pcal_info *gen_chan_info; |
962 | u8 *pdgain_idx = ee->ee_pdc_to_idx[mode]; | ||
770 | u32 offset; | 963 | u32 offset; |
771 | unsigned int i, c; | 964 | u8 i, c; |
772 | u16 val; | 965 | u16 val; |
773 | int ret; | 966 | int ret; |
967 | u8 pd_gains = 0; | ||
968 | |||
969 | /* Count how many curves we have and | ||
970 | * identify them (which one of the 4 | ||
971 | * available curves we have on each count). | ||
972 | * Curves are stored from lower (x0) to | ||
973 | * higher (x3) gain */ | ||
974 | for (i = 0; i < AR5K_EEPROM_N_PD_CURVES; i++) { | ||
975 | /* ee_x_gain[mode] is x gain mask */ | ||
976 | if ((ee->ee_x_gain[mode] >> i) & 0x1) | ||
977 | pdgain_idx[pd_gains++] = i; | ||
978 | } | ||
979 | ee->ee_pd_gains[mode] = pd_gains; | ||
980 | |||
981 | if (pd_gains == 0 || pd_gains > 2) | ||
982 | return -EINVAL; | ||
774 | 983 | ||
775 | switch (mode) { | 984 | switch (mode) { |
776 | case AR5K_EEPROM_MODE_11A: | 985 | case AR5K_EEPROM_MODE_11A: |
@@ -808,13 +1017,13 @@ ath5k_eeprom_read_pcal_info_5112(struct ath5k_hw *ah, int mode) | |||
808 | for (i = 0; i < ee->ee_n_piers[mode]; i++) { | 1017 | for (i = 0; i < ee->ee_n_piers[mode]; i++) { |
809 | chan_pcal_info = &gen_chan_info[i].rf5112_info; | 1018 | chan_pcal_info = &gen_chan_info[i].rf5112_info; |
810 | 1019 | ||
811 | /* Power values in dBm * 4 | 1020 | /* Power values in quarter dB |
812 | * for the lower xpd gain curve | 1021 | * for the lower xpd gain curve |
813 | * (0 dBm -> higher output power) */ | 1022 | * (0 dBm -> higher output power) */ |
814 | for (c = 0; c < AR5K_EEPROM_N_XPD0_POINTS; c++) { | 1023 | for (c = 0; c < AR5K_EEPROM_N_XPD0_POINTS; c++) { |
815 | AR5K_EEPROM_READ(offset++, val); | 1024 | AR5K_EEPROM_READ(offset++, val); |
816 | chan_pcal_info->pwr_x0[c] = (val & 0xff); | 1025 | chan_pcal_info->pwr_x0[c] = (s8) (val & 0xff); |
817 | chan_pcal_info->pwr_x0[++c] = ((val >> 8) & 0xff); | 1026 | chan_pcal_info->pwr_x0[++c] = (s8) ((val >> 8) & 0xff); |
818 | } | 1027 | } |
819 | 1028 | ||
820 | /* PCDAC steps | 1029 | /* PCDAC steps |
@@ -825,12 +1034,12 @@ ath5k_eeprom_read_pcal_info_5112(struct ath5k_hw *ah, int mode) | |||
825 | chan_pcal_info->pcdac_x0[2] = ((val >> 5) & 0x1f); | 1034 | chan_pcal_info->pcdac_x0[2] = ((val >> 5) & 0x1f); |
826 | chan_pcal_info->pcdac_x0[3] = ((val >> 10) & 0x1f); | 1035 | chan_pcal_info->pcdac_x0[3] = ((val >> 10) & 0x1f); |
827 | 1036 | ||
828 | /* Power values in dBm * 4 | 1037 | /* Power values in quarter dB |
829 | * for the higher xpd gain curve | 1038 | * for the higher xpd gain curve |
830 | * (18 dBm -> lower output power) */ | 1039 | * (18 dBm -> lower output power) */ |
831 | AR5K_EEPROM_READ(offset++, val); | 1040 | AR5K_EEPROM_READ(offset++, val); |
832 | chan_pcal_info->pwr_x3[0] = (val & 0xff); | 1041 | chan_pcal_info->pwr_x3[0] = (s8) (val & 0xff); |
833 | chan_pcal_info->pwr_x3[1] = ((val >> 8) & 0xff); | 1042 | chan_pcal_info->pwr_x3[1] = (s8) ((val >> 8) & 0xff); |
834 | 1043 | ||
835 | AR5K_EEPROM_READ(offset++, val); | 1044 | AR5K_EEPROM_READ(offset++, val); |
836 | chan_pcal_info->pwr_x3[2] = (val & 0xff); | 1045 | chan_pcal_info->pwr_x3[2] = (val & 0xff); |
@@ -843,24 +1052,36 @@ ath5k_eeprom_read_pcal_info_5112(struct ath5k_hw *ah, int mode) | |||
843 | chan_pcal_info->pcdac_x3[2] = 63; | 1052 | chan_pcal_info->pcdac_x3[2] = 63; |
844 | 1053 | ||
845 | if (ee->ee_version >= AR5K_EEPROM_VERSION_4_3) { | 1054 | if (ee->ee_version >= AR5K_EEPROM_VERSION_4_3) { |
846 | chan_pcal_info->pcdac_x0[0] = ((val >> 8) & 0xff); | 1055 | chan_pcal_info->pcdac_x0[0] = ((val >> 8) & 0x3f); |
847 | 1056 | ||
848 | /* Last xpd0 power level is also channel maximum */ | 1057 | /* Last xpd0 power level is also channel maximum */ |
849 | gen_chan_info[i].max_pwr = chan_pcal_info->pwr_x0[3]; | 1058 | gen_chan_info[i].max_pwr = chan_pcal_info->pwr_x0[3]; |
850 | } else { | 1059 | } else { |
851 | chan_pcal_info->pcdac_x0[0] = 1; | 1060 | chan_pcal_info->pcdac_x0[0] = 1; |
852 | gen_chan_info[i].max_pwr = ((val >> 8) & 0xff); | 1061 | gen_chan_info[i].max_pwr = (s8) ((val >> 8) & 0xff); |
853 | } | 1062 | } |
854 | 1063 | ||
855 | /* Recreate pcdac_x0 table for this channel using pcdac steps */ | ||
856 | chan_pcal_info->pcdac_x0[1] += chan_pcal_info->pcdac_x0[0]; | ||
857 | chan_pcal_info->pcdac_x0[2] += chan_pcal_info->pcdac_x0[1]; | ||
858 | chan_pcal_info->pcdac_x0[3] += chan_pcal_info->pcdac_x0[2]; | ||
859 | } | 1064 | } |
860 | 1065 | ||
861 | return 0; | 1066 | return ath5k_eeprom_convert_pcal_info_5112(ah, mode, gen_chan_info); |
862 | } | 1067 | } |
863 | 1068 | ||
1069 | |||
1070 | /* | ||
1071 | * Read power calibration for RF2413 chips | ||
1072 | * | ||
1073 | * For RF2413 we have a Power to PDDAC table (Power Detector) | ||
1074 | * instead of a PCDAC and 4 pd gain curves for each calibrated channel. | ||
1075 | * Each curve has power on x axis in 0.5 db steps and PDDADC steps on y | ||
1076 | * axis and looks like an exponential function like the RF5111 curve. | ||
1077 | * | ||
1078 | * To recreate the curves we read here the points and interpolate | ||
1079 | * later. Note that in most cases only 2 (higher and lower) curves are | ||
1080 | * used (like RF5112) but vendors have the oportunity to include all | ||
1081 | * 4 curves on eeprom. The final curve (higher power) has an extra | ||
1082 | * point for better accuracy like RF5112. | ||
1083 | */ | ||
1084 | |||
864 | /* For RF2413 power calibration data doesn't start on a fixed location and | 1085 | /* For RF2413 power calibration data doesn't start on a fixed location and |
865 | * if a mode is not supported, it's section is missing -not zeroed-. | 1086 | * if a mode is not supported, it's section is missing -not zeroed-. |
866 | * So we need to calculate the starting offset for each section by using | 1087 | * So we need to calculate the starting offset for each section by using |
@@ -890,13 +1111,15 @@ ath5k_cal_data_offset_2413(struct ath5k_eeprom_info *ee, int mode) | |||
890 | switch(mode) { | 1111 | switch(mode) { |
891 | case AR5K_EEPROM_MODE_11G: | 1112 | case AR5K_EEPROM_MODE_11G: |
892 | if (AR5K_EEPROM_HDR_11B(ee->ee_header)) | 1113 | if (AR5K_EEPROM_HDR_11B(ee->ee_header)) |
893 | offset += ath5k_pdgains_size_2413(ee, AR5K_EEPROM_MODE_11B) + | 1114 | offset += ath5k_pdgains_size_2413(ee, |
894 | AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2; | 1115 | AR5K_EEPROM_MODE_11B) + |
1116 | AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2; | ||
895 | /* fall through */ | 1117 | /* fall through */ |
896 | case AR5K_EEPROM_MODE_11B: | 1118 | case AR5K_EEPROM_MODE_11B: |
897 | if (AR5K_EEPROM_HDR_11A(ee->ee_header)) | 1119 | if (AR5K_EEPROM_HDR_11A(ee->ee_header)) |
898 | offset += ath5k_pdgains_size_2413(ee, AR5K_EEPROM_MODE_11A) + | 1120 | offset += ath5k_pdgains_size_2413(ee, |
899 | AR5K_EEPROM_N_5GHZ_CHAN / 2; | 1121 | AR5K_EEPROM_MODE_11A) + |
1122 | AR5K_EEPROM_N_5GHZ_CHAN / 2; | ||
900 | /* fall through */ | 1123 | /* fall through */ |
901 | case AR5K_EEPROM_MODE_11A: | 1124 | case AR5K_EEPROM_MODE_11A: |
902 | break; | 1125 | break; |
@@ -907,37 +1130,118 @@ ath5k_cal_data_offset_2413(struct ath5k_eeprom_info *ee, int mode) | |||
907 | return offset; | 1130 | return offset; |
908 | } | 1131 | } |
909 | 1132 | ||
910 | /* Read power calibration for RF2413 chips | 1133 | /* Convert RF2413 specific data to generic raw data |
911 | * For RF2413 we have a PDDAC table (Power Detector) instead | 1134 | * used by interpolation code */ |
912 | * of a PCDAC and 4 pd gain curves for each calibrated channel. | 1135 | static int |
913 | * Each curve has PDDAC steps on x axis and power on y axis and | 1136 | ath5k_eeprom_convert_pcal_info_2413(struct ath5k_hw *ah, int mode, |
914 | * looks like an exponential function. To recreate the curves | 1137 | struct ath5k_chan_pcal_info *chinfo) |
915 | * we read here the points and interpolate later. Note that | 1138 | { |
916 | * in most cases only higher and lower curves are used (like | 1139 | struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; |
917 | * RF5112) but vendors have the oportunity to include all 4 | 1140 | struct ath5k_chan_pcal_info_rf2413 *pcinfo; |
918 | * curves on eeprom. The final curve (higher power) has an extra | 1141 | u8 *pdgain_idx = ee->ee_pdc_to_idx[mode]; |
919 | * point for better accuracy like RF5112. | 1142 | unsigned int pier, pdg, point; |
920 | */ | 1143 | |
1144 | /* Fill raw data for each calibration pier */ | ||
1145 | for (pier = 0; pier < ee->ee_n_piers[mode]; pier++) { | ||
1146 | |||
1147 | pcinfo = &chinfo[pier].rf2413_info; | ||
1148 | |||
1149 | /* Allocate pd_curves for this cal pier */ | ||
1150 | chinfo[pier].pd_curves = | ||
1151 | kcalloc(AR5K_EEPROM_N_PD_CURVES, | ||
1152 | sizeof(struct ath5k_pdgain_info), | ||
1153 | GFP_KERNEL); | ||
1154 | |||
1155 | if (!chinfo[pier].pd_curves) | ||
1156 | return -ENOMEM; | ||
1157 | |||
1158 | /* Fill pd_curves */ | ||
1159 | for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) { | ||
1160 | |||
1161 | u8 idx = pdgain_idx[pdg]; | ||
1162 | struct ath5k_pdgain_info *pd = | ||
1163 | &chinfo[pier].pd_curves[idx]; | ||
1164 | |||
1165 | /* One more point for the highest power | ||
1166 | * curve (lowest gain) */ | ||
1167 | if (pdg == ee->ee_pd_gains[mode] - 1) | ||
1168 | pd->pd_points = AR5K_EEPROM_N_PD_POINTS; | ||
1169 | else | ||
1170 | pd->pd_points = AR5K_EEPROM_N_PD_POINTS - 1; | ||
1171 | |||
1172 | /* Allocate pd points for this curve */ | ||
1173 | pd->pd_step = kcalloc(pd->pd_points, | ||
1174 | sizeof(u8), GFP_KERNEL); | ||
1175 | |||
1176 | if (!pd->pd_step) | ||
1177 | return -ENOMEM; | ||
1178 | |||
1179 | pd->pd_pwr = kcalloc(pd->pd_points, | ||
1180 | sizeof(s16), GFP_KERNEL); | ||
1181 | |||
1182 | if (!pd->pd_pwr) | ||
1183 | return -ENOMEM; | ||
1184 | |||
1185 | /* Fill raw dataset | ||
1186 | * convert all pwr levels to | ||
1187 | * quarter dB for RF5112 combatibility */ | ||
1188 | pd->pd_step[0] = pcinfo->pddac_i[pdg]; | ||
1189 | pd->pd_pwr[0] = 4 * pcinfo->pwr_i[pdg]; | ||
1190 | |||
1191 | for (point = 1; point < pd->pd_points; point++) { | ||
1192 | |||
1193 | pd->pd_pwr[point] = pd->pd_pwr[point - 1] + | ||
1194 | 2 * pcinfo->pwr[pdg][point - 1]; | ||
1195 | |||
1196 | pd->pd_step[point] = pd->pd_step[point - 1] + | ||
1197 | pcinfo->pddac[pdg][point - 1]; | ||
1198 | |||
1199 | } | ||
1200 | |||
1201 | /* Highest gain curve -> min power */ | ||
1202 | if (pdg == 0) | ||
1203 | chinfo[pier].min_pwr = pd->pd_pwr[0]; | ||
1204 | |||
1205 | /* Lowest gain curve -> max power */ | ||
1206 | if (pdg == ee->ee_pd_gains[mode] - 1) | ||
1207 | chinfo[pier].max_pwr = | ||
1208 | pd->pd_pwr[pd->pd_points - 1]; | ||
1209 | } | ||
1210 | } | ||
1211 | |||
1212 | return 0; | ||
1213 | } | ||
1214 | |||
1215 | /* Parse EEPROM data */ | ||
921 | static int | 1216 | static int |
922 | ath5k_eeprom_read_pcal_info_2413(struct ath5k_hw *ah, int mode) | 1217 | ath5k_eeprom_read_pcal_info_2413(struct ath5k_hw *ah, int mode) |
923 | { | 1218 | { |
924 | struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; | 1219 | struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; |
925 | struct ath5k_chan_pcal_info_rf2413 *chan_pcal_info; | 1220 | struct ath5k_chan_pcal_info_rf2413 *pcinfo; |
926 | struct ath5k_chan_pcal_info *gen_chan_info; | 1221 | struct ath5k_chan_pcal_info *chinfo; |
927 | unsigned int i, c; | 1222 | u8 *pdgain_idx = ee->ee_pdc_to_idx[mode]; |
928 | u32 offset; | 1223 | u32 offset; |
929 | int ret; | 1224 | int idx, i, ret; |
930 | u16 val; | 1225 | u16 val; |
931 | u8 pd_gains = 0; | 1226 | u8 pd_gains = 0; |
932 | 1227 | ||
933 | if (ee->ee_x_gain[mode] & 0x1) pd_gains++; | 1228 | /* Count how many curves we have and |
934 | if ((ee->ee_x_gain[mode] >> 1) & 0x1) pd_gains++; | 1229 | * identify them (which one of the 4 |
935 | if ((ee->ee_x_gain[mode] >> 2) & 0x1) pd_gains++; | 1230 | * available curves we have on each count). |
936 | if ((ee->ee_x_gain[mode] >> 3) & 0x1) pd_gains++; | 1231 | * Curves are stored from higher to |
1232 | * lower gain so we go backwards */ | ||
1233 | for (idx = AR5K_EEPROM_N_PD_CURVES - 1; idx >= 0; idx--) { | ||
1234 | /* ee_x_gain[mode] is x gain mask */ | ||
1235 | if ((ee->ee_x_gain[mode] >> idx) & 0x1) | ||
1236 | pdgain_idx[pd_gains++] = idx; | ||
1237 | |||
1238 | } | ||
937 | ee->ee_pd_gains[mode] = pd_gains; | 1239 | ee->ee_pd_gains[mode] = pd_gains; |
938 | 1240 | ||
1241 | if (pd_gains == 0) | ||
1242 | return -EINVAL; | ||
1243 | |||
939 | offset = ath5k_cal_data_offset_2413(ee, mode); | 1244 | offset = ath5k_cal_data_offset_2413(ee, mode); |
940 | ee->ee_n_piers[mode] = 0; | ||
941 | switch (mode) { | 1245 | switch (mode) { |
942 | case AR5K_EEPROM_MODE_11A: | 1246 | case AR5K_EEPROM_MODE_11A: |
943 | if (!AR5K_EEPROM_HDR_11A(ee->ee_header)) | 1247 | if (!AR5K_EEPROM_HDR_11A(ee->ee_header)) |
@@ -945,7 +1249,7 @@ ath5k_eeprom_read_pcal_info_2413(struct ath5k_hw *ah, int mode) | |||
945 | 1249 | ||
946 | ath5k_eeprom_init_11a_pcal_freq(ah, offset); | 1250 | ath5k_eeprom_init_11a_pcal_freq(ah, offset); |
947 | offset += AR5K_EEPROM_N_5GHZ_CHAN / 2; | 1251 | offset += AR5K_EEPROM_N_5GHZ_CHAN / 2; |
948 | gen_chan_info = ee->ee_pwr_cal_a; | 1252 | chinfo = ee->ee_pwr_cal_a; |
949 | break; | 1253 | break; |
950 | case AR5K_EEPROM_MODE_11B: | 1254 | case AR5K_EEPROM_MODE_11B: |
951 | if (!AR5K_EEPROM_HDR_11B(ee->ee_header)) | 1255 | if (!AR5K_EEPROM_HDR_11B(ee->ee_header)) |
@@ -953,7 +1257,7 @@ ath5k_eeprom_read_pcal_info_2413(struct ath5k_hw *ah, int mode) | |||
953 | 1257 | ||
954 | ath5k_eeprom_init_11bg_2413(ah, mode, offset); | 1258 | ath5k_eeprom_init_11bg_2413(ah, mode, offset); |
955 | offset += AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2; | 1259 | offset += AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2; |
956 | gen_chan_info = ee->ee_pwr_cal_b; | 1260 | chinfo = ee->ee_pwr_cal_b; |
957 | break; | 1261 | break; |
958 | case AR5K_EEPROM_MODE_11G: | 1262 | case AR5K_EEPROM_MODE_11G: |
959 | if (!AR5K_EEPROM_HDR_11G(ee->ee_header)) | 1263 | if (!AR5K_EEPROM_HDR_11G(ee->ee_header)) |
@@ -961,41 +1265,35 @@ ath5k_eeprom_read_pcal_info_2413(struct ath5k_hw *ah, int mode) | |||
961 | 1265 | ||
962 | ath5k_eeprom_init_11bg_2413(ah, mode, offset); | 1266 | ath5k_eeprom_init_11bg_2413(ah, mode, offset); |
963 | offset += AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2; | 1267 | offset += AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2; |
964 | gen_chan_info = ee->ee_pwr_cal_g; | 1268 | chinfo = ee->ee_pwr_cal_g; |
965 | break; | 1269 | break; |
966 | default: | 1270 | default: |
967 | return -EINVAL; | 1271 | return -EINVAL; |
968 | } | 1272 | } |
969 | 1273 | ||
970 | if (pd_gains == 0) | ||
971 | return 0; | ||
972 | |||
973 | for (i = 0; i < ee->ee_n_piers[mode]; i++) { | 1274 | for (i = 0; i < ee->ee_n_piers[mode]; i++) { |
974 | chan_pcal_info = &gen_chan_info[i].rf2413_info; | 1275 | pcinfo = &chinfo[i].rf2413_info; |
975 | 1276 | ||
976 | /* | 1277 | /* |
977 | * Read pwr_i, pddac_i and the first | 1278 | * Read pwr_i, pddac_i and the first |
978 | * 2 pd points (pwr, pddac) | 1279 | * 2 pd points (pwr, pddac) |
979 | */ | 1280 | */ |
980 | AR5K_EEPROM_READ(offset++, val); | 1281 | AR5K_EEPROM_READ(offset++, val); |
981 | chan_pcal_info->pwr_i[0] = val & 0x1f; | 1282 | pcinfo->pwr_i[0] = val & 0x1f; |
982 | chan_pcal_info->pddac_i[0] = (val >> 5) & 0x7f; | 1283 | pcinfo->pddac_i[0] = (val >> 5) & 0x7f; |
983 | chan_pcal_info->pwr[0][0] = | 1284 | pcinfo->pwr[0][0] = (val >> 12) & 0xf; |
984 | (val >> 12) & 0xf; | ||
985 | 1285 | ||
986 | AR5K_EEPROM_READ(offset++, val); | 1286 | AR5K_EEPROM_READ(offset++, val); |
987 | chan_pcal_info->pddac[0][0] = val & 0x3f; | 1287 | pcinfo->pddac[0][0] = val & 0x3f; |
988 | chan_pcal_info->pwr[0][1] = (val >> 6) & 0xf; | 1288 | pcinfo->pwr[0][1] = (val >> 6) & 0xf; |
989 | chan_pcal_info->pddac[0][1] = | 1289 | pcinfo->pddac[0][1] = (val >> 10) & 0x3f; |
990 | (val >> 10) & 0x3f; | ||
991 | 1290 | ||
992 | AR5K_EEPROM_READ(offset++, val); | 1291 | AR5K_EEPROM_READ(offset++, val); |
993 | chan_pcal_info->pwr[0][2] = val & 0xf; | 1292 | pcinfo->pwr[0][2] = val & 0xf; |
994 | chan_pcal_info->pddac[0][2] = | 1293 | pcinfo->pddac[0][2] = (val >> 4) & 0x3f; |
995 | (val >> 4) & 0x3f; | ||
996 | 1294 | ||
997 | chan_pcal_info->pwr[0][3] = 0; | 1295 | pcinfo->pwr[0][3] = 0; |
998 | chan_pcal_info->pddac[0][3] = 0; | 1296 | pcinfo->pddac[0][3] = 0; |
999 | 1297 | ||
1000 | if (pd_gains > 1) { | 1298 | if (pd_gains > 1) { |
1001 | /* | 1299 | /* |
@@ -1003,44 +1301,36 @@ ath5k_eeprom_read_pcal_info_2413(struct ath5k_hw *ah, int mode) | |||
1003 | * so it only has 2 pd points. | 1301 | * so it only has 2 pd points. |
1004 | * Continue wih pd gain 1. | 1302 | * Continue wih pd gain 1. |
1005 | */ | 1303 | */ |
1006 | chan_pcal_info->pwr_i[1] = (val >> 10) & 0x1f; | 1304 | pcinfo->pwr_i[1] = (val >> 10) & 0x1f; |
1007 | 1305 | ||
1008 | chan_pcal_info->pddac_i[1] = (val >> 15) & 0x1; | 1306 | pcinfo->pddac_i[1] = (val >> 15) & 0x1; |
1009 | AR5K_EEPROM_READ(offset++, val); | 1307 | AR5K_EEPROM_READ(offset++, val); |
1010 | chan_pcal_info->pddac_i[1] |= (val & 0x3F) << 1; | 1308 | pcinfo->pddac_i[1] |= (val & 0x3F) << 1; |
1011 | 1309 | ||
1012 | chan_pcal_info->pwr[1][0] = (val >> 6) & 0xf; | 1310 | pcinfo->pwr[1][0] = (val >> 6) & 0xf; |
1013 | chan_pcal_info->pddac[1][0] = | 1311 | pcinfo->pddac[1][0] = (val >> 10) & 0x3f; |
1014 | (val >> 10) & 0x3f; | ||
1015 | 1312 | ||
1016 | AR5K_EEPROM_READ(offset++, val); | 1313 | AR5K_EEPROM_READ(offset++, val); |
1017 | chan_pcal_info->pwr[1][1] = val & 0xf; | 1314 | pcinfo->pwr[1][1] = val & 0xf; |
1018 | chan_pcal_info->pddac[1][1] = | 1315 | pcinfo->pddac[1][1] = (val >> 4) & 0x3f; |
1019 | (val >> 4) & 0x3f; | 1316 | pcinfo->pwr[1][2] = (val >> 10) & 0xf; |
1020 | chan_pcal_info->pwr[1][2] = | 1317 | |
1021 | (val >> 10) & 0xf; | 1318 | pcinfo->pddac[1][2] = (val >> 14) & 0x3; |
1022 | |||
1023 | chan_pcal_info->pddac[1][2] = | ||
1024 | (val >> 14) & 0x3; | ||
1025 | AR5K_EEPROM_READ(offset++, val); | 1319 | AR5K_EEPROM_READ(offset++, val); |
1026 | chan_pcal_info->pddac[1][2] |= | 1320 | pcinfo->pddac[1][2] |= (val & 0xF) << 2; |
1027 | (val & 0xF) << 2; | ||
1028 | 1321 | ||
1029 | chan_pcal_info->pwr[1][3] = 0; | 1322 | pcinfo->pwr[1][3] = 0; |
1030 | chan_pcal_info->pddac[1][3] = 0; | 1323 | pcinfo->pddac[1][3] = 0; |
1031 | } else if (pd_gains == 1) { | 1324 | } else if (pd_gains == 1) { |
1032 | /* | 1325 | /* |
1033 | * Pd gain 0 is the last one so | 1326 | * Pd gain 0 is the last one so |
1034 | * read the extra point. | 1327 | * read the extra point. |
1035 | */ | 1328 | */ |
1036 | chan_pcal_info->pwr[0][3] = | 1329 | pcinfo->pwr[0][3] = (val >> 10) & 0xf; |
1037 | (val >> 10) & 0xf; | ||
1038 | 1330 | ||
1039 | chan_pcal_info->pddac[0][3] = | 1331 | pcinfo->pddac[0][3] = (val >> 14) & 0x3; |
1040 | (val >> 14) & 0x3; | ||
1041 | AR5K_EEPROM_READ(offset++, val); | 1332 | AR5K_EEPROM_READ(offset++, val); |
1042 | chan_pcal_info->pddac[0][3] |= | 1333 | pcinfo->pddac[0][3] |= (val & 0xF) << 2; |
1043 | (val & 0xF) << 2; | ||
1044 | } | 1334 | } |
1045 | 1335 | ||
1046 | /* | 1336 | /* |
@@ -1048,105 +1338,65 @@ ath5k_eeprom_read_pcal_info_2413(struct ath5k_hw *ah, int mode) | |||
1048 | * as above. | 1338 | * as above. |
1049 | */ | 1339 | */ |
1050 | if (pd_gains > 2) { | 1340 | if (pd_gains > 2) { |
1051 | chan_pcal_info->pwr_i[2] = (val >> 4) & 0x1f; | 1341 | pcinfo->pwr_i[2] = (val >> 4) & 0x1f; |
1052 | chan_pcal_info->pddac_i[2] = (val >> 9) & 0x7f; | 1342 | pcinfo->pddac_i[2] = (val >> 9) & 0x7f; |
1053 | 1343 | ||
1054 | AR5K_EEPROM_READ(offset++, val); | 1344 | AR5K_EEPROM_READ(offset++, val); |
1055 | chan_pcal_info->pwr[2][0] = | 1345 | pcinfo->pwr[2][0] = (val >> 0) & 0xf; |
1056 | (val >> 0) & 0xf; | 1346 | pcinfo->pddac[2][0] = (val >> 4) & 0x3f; |
1057 | chan_pcal_info->pddac[2][0] = | 1347 | pcinfo->pwr[2][1] = (val >> 10) & 0xf; |
1058 | (val >> 4) & 0x3f; | 1348 | |
1059 | chan_pcal_info->pwr[2][1] = | 1349 | pcinfo->pddac[2][1] = (val >> 14) & 0x3; |
1060 | (val >> 10) & 0xf; | ||
1061 | |||
1062 | chan_pcal_info->pddac[2][1] = | ||
1063 | (val >> 14) & 0x3; | ||
1064 | AR5K_EEPROM_READ(offset++, val); | 1350 | AR5K_EEPROM_READ(offset++, val); |
1065 | chan_pcal_info->pddac[2][1] |= | 1351 | pcinfo->pddac[2][1] |= (val & 0xF) << 2; |
1066 | (val & 0xF) << 2; | ||
1067 | 1352 | ||
1068 | chan_pcal_info->pwr[2][2] = | 1353 | pcinfo->pwr[2][2] = (val >> 4) & 0xf; |
1069 | (val >> 4) & 0xf; | 1354 | pcinfo->pddac[2][2] = (val >> 8) & 0x3f; |
1070 | chan_pcal_info->pddac[2][2] = | ||
1071 | (val >> 8) & 0x3f; | ||
1072 | 1355 | ||
1073 | chan_pcal_info->pwr[2][3] = 0; | 1356 | pcinfo->pwr[2][3] = 0; |
1074 | chan_pcal_info->pddac[2][3] = 0; | 1357 | pcinfo->pddac[2][3] = 0; |
1075 | } else if (pd_gains == 2) { | 1358 | } else if (pd_gains == 2) { |
1076 | chan_pcal_info->pwr[1][3] = | 1359 | pcinfo->pwr[1][3] = (val >> 4) & 0xf; |
1077 | (val >> 4) & 0xf; | 1360 | pcinfo->pddac[1][3] = (val >> 8) & 0x3f; |
1078 | chan_pcal_info->pddac[1][3] = | ||
1079 | (val >> 8) & 0x3f; | ||
1080 | } | 1361 | } |
1081 | 1362 | ||
1082 | if (pd_gains > 3) { | 1363 | if (pd_gains > 3) { |
1083 | chan_pcal_info->pwr_i[3] = (val >> 14) & 0x3; | 1364 | pcinfo->pwr_i[3] = (val >> 14) & 0x3; |
1084 | AR5K_EEPROM_READ(offset++, val); | 1365 | AR5K_EEPROM_READ(offset++, val); |
1085 | chan_pcal_info->pwr_i[3] |= ((val >> 0) & 0x7) << 2; | 1366 | pcinfo->pwr_i[3] |= ((val >> 0) & 0x7) << 2; |
1086 | 1367 | ||
1087 | chan_pcal_info->pddac_i[3] = (val >> 3) & 0x7f; | 1368 | pcinfo->pddac_i[3] = (val >> 3) & 0x7f; |
1088 | chan_pcal_info->pwr[3][0] = | 1369 | pcinfo->pwr[3][0] = (val >> 10) & 0xf; |
1089 | (val >> 10) & 0xf; | 1370 | pcinfo->pddac[3][0] = (val >> 14) & 0x3; |
1090 | chan_pcal_info->pddac[3][0] = | ||
1091 | (val >> 14) & 0x3; | ||
1092 | 1371 | ||
1093 | AR5K_EEPROM_READ(offset++, val); | 1372 | AR5K_EEPROM_READ(offset++, val); |
1094 | chan_pcal_info->pddac[3][0] |= | 1373 | pcinfo->pddac[3][0] |= (val & 0xF) << 2; |
1095 | (val & 0xF) << 2; | 1374 | pcinfo->pwr[3][1] = (val >> 4) & 0xf; |
1096 | chan_pcal_info->pwr[3][1] = | 1375 | pcinfo->pddac[3][1] = (val >> 8) & 0x3f; |
1097 | (val >> 4) & 0xf; | 1376 | |
1098 | chan_pcal_info->pddac[3][1] = | 1377 | pcinfo->pwr[3][2] = (val >> 14) & 0x3; |
1099 | (val >> 8) & 0x3f; | ||
1100 | |||
1101 | chan_pcal_info->pwr[3][2] = | ||
1102 | (val >> 14) & 0x3; | ||
1103 | AR5K_EEPROM_READ(offset++, val); | 1378 | AR5K_EEPROM_READ(offset++, val); |
1104 | chan_pcal_info->pwr[3][2] |= | 1379 | pcinfo->pwr[3][2] |= ((val >> 0) & 0x3) << 2; |
1105 | ((val >> 0) & 0x3) << 2; | ||
1106 | 1380 | ||
1107 | chan_pcal_info->pddac[3][2] = | 1381 | pcinfo->pddac[3][2] = (val >> 2) & 0x3f; |
1108 | (val >> 2) & 0x3f; | 1382 | pcinfo->pwr[3][3] = (val >> 8) & 0xf; |
1109 | chan_pcal_info->pwr[3][3] = | ||
1110 | (val >> 8) & 0xf; | ||
1111 | 1383 | ||
1112 | chan_pcal_info->pddac[3][3] = | 1384 | pcinfo->pddac[3][3] = (val >> 12) & 0xF; |
1113 | (val >> 12) & 0xF; | ||
1114 | AR5K_EEPROM_READ(offset++, val); | 1385 | AR5K_EEPROM_READ(offset++, val); |
1115 | chan_pcal_info->pddac[3][3] |= | 1386 | pcinfo->pddac[3][3] |= ((val >> 0) & 0x3) << 4; |
1116 | ((val >> 0) & 0x3) << 4; | ||
1117 | } else if (pd_gains == 3) { | 1387 | } else if (pd_gains == 3) { |
1118 | chan_pcal_info->pwr[2][3] = | 1388 | pcinfo->pwr[2][3] = (val >> 14) & 0x3; |
1119 | (val >> 14) & 0x3; | ||
1120 | AR5K_EEPROM_READ(offset++, val); | 1389 | AR5K_EEPROM_READ(offset++, val); |
1121 | chan_pcal_info->pwr[2][3] |= | 1390 | pcinfo->pwr[2][3] |= ((val >> 0) & 0x3) << 2; |
1122 | ((val >> 0) & 0x3) << 2; | ||
1123 | |||
1124 | chan_pcal_info->pddac[2][3] = | ||
1125 | (val >> 2) & 0x3f; | ||
1126 | } | ||
1127 | 1391 | ||
1128 | for (c = 0; c < pd_gains; c++) { | 1392 | pcinfo->pddac[2][3] = (val >> 2) & 0x3f; |
1129 | /* Recreate pwr table for this channel using pwr steps */ | ||
1130 | chan_pcal_info->pwr[c][0] += chan_pcal_info->pwr_i[c] * 2; | ||
1131 | chan_pcal_info->pwr[c][1] += chan_pcal_info->pwr[c][0]; | ||
1132 | chan_pcal_info->pwr[c][2] += chan_pcal_info->pwr[c][1]; | ||
1133 | chan_pcal_info->pwr[c][3] += chan_pcal_info->pwr[c][2]; | ||
1134 | if (chan_pcal_info->pwr[c][3] == chan_pcal_info->pwr[c][2]) | ||
1135 | chan_pcal_info->pwr[c][3] = 0; | ||
1136 | |||
1137 | /* Recreate pddac table for this channel using pddac steps */ | ||
1138 | chan_pcal_info->pddac[c][0] += chan_pcal_info->pddac_i[c]; | ||
1139 | chan_pcal_info->pddac[c][1] += chan_pcal_info->pddac[c][0]; | ||
1140 | chan_pcal_info->pddac[c][2] += chan_pcal_info->pddac[c][1]; | ||
1141 | chan_pcal_info->pddac[c][3] += chan_pcal_info->pddac[c][2]; | ||
1142 | if (chan_pcal_info->pddac[c][3] == chan_pcal_info->pddac[c][2]) | ||
1143 | chan_pcal_info->pddac[c][3] = 0; | ||
1144 | } | 1393 | } |
1145 | } | 1394 | } |
1146 | 1395 | ||
1147 | return 0; | 1396 | return ath5k_eeprom_convert_pcal_info_2413(ah, mode, chinfo); |
1148 | } | 1397 | } |
1149 | 1398 | ||
1399 | |||
1150 | /* | 1400 | /* |
1151 | * Read per rate target power (this is the maximum tx power | 1401 | * Read per rate target power (this is the maximum tx power |
1152 | * supported by the card). This info is used when setting | 1402 | * supported by the card). This info is used when setting |
@@ -1154,11 +1404,12 @@ ath5k_eeprom_read_pcal_info_2413(struct ath5k_hw *ah, int mode) | |||
1154 | * | 1404 | * |
1155 | * This also works for v5 EEPROMs. | 1405 | * This also works for v5 EEPROMs. |
1156 | */ | 1406 | */ |
1157 | static int ath5k_eeprom_read_target_rate_pwr_info(struct ath5k_hw *ah, unsigned int mode) | 1407 | static int |
1408 | ath5k_eeprom_read_target_rate_pwr_info(struct ath5k_hw *ah, unsigned int mode) | ||
1158 | { | 1409 | { |
1159 | struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; | 1410 | struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; |
1160 | struct ath5k_rate_pcal_info *rate_pcal_info; | 1411 | struct ath5k_rate_pcal_info *rate_pcal_info; |
1161 | u16 *rate_target_pwr_num; | 1412 | u8 *rate_target_pwr_num; |
1162 | u32 offset; | 1413 | u32 offset; |
1163 | u16 val; | 1414 | u16 val; |
1164 | int ret, i; | 1415 | int ret, i; |
@@ -1264,7 +1515,9 @@ ath5k_eeprom_read_pcal_info(struct ath5k_hw *ah) | |||
1264 | else | 1515 | else |
1265 | read_pcal = ath5k_eeprom_read_pcal_info_5111; | 1516 | read_pcal = ath5k_eeprom_read_pcal_info_5111; |
1266 | 1517 | ||
1267 | for (mode = AR5K_EEPROM_MODE_11A; mode <= AR5K_EEPROM_MODE_11G; mode++) { | 1518 | |
1519 | for (mode = AR5K_EEPROM_MODE_11A; mode <= AR5K_EEPROM_MODE_11G; | ||
1520 | mode++) { | ||
1268 | err = read_pcal(ah, mode); | 1521 | err = read_pcal(ah, mode); |
1269 | if (err) | 1522 | if (err) |
1270 | return err; | 1523 | return err; |
@@ -1277,6 +1530,62 @@ ath5k_eeprom_read_pcal_info(struct ath5k_hw *ah) | |||
1277 | return 0; | 1530 | return 0; |
1278 | } | 1531 | } |
1279 | 1532 | ||
1533 | static int | ||
1534 | ath5k_eeprom_free_pcal_info(struct ath5k_hw *ah, int mode) | ||
1535 | { | ||
1536 | struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; | ||
1537 | struct ath5k_chan_pcal_info *chinfo; | ||
1538 | u8 pier, pdg; | ||
1539 | |||
1540 | switch (mode) { | ||
1541 | case AR5K_EEPROM_MODE_11A: | ||
1542 | if (!AR5K_EEPROM_HDR_11A(ee->ee_header)) | ||
1543 | return 0; | ||
1544 | chinfo = ee->ee_pwr_cal_a; | ||
1545 | break; | ||
1546 | case AR5K_EEPROM_MODE_11B: | ||
1547 | if (!AR5K_EEPROM_HDR_11B(ee->ee_header)) | ||
1548 | return 0; | ||
1549 | chinfo = ee->ee_pwr_cal_b; | ||
1550 | break; | ||
1551 | case AR5K_EEPROM_MODE_11G: | ||
1552 | if (!AR5K_EEPROM_HDR_11G(ee->ee_header)) | ||
1553 | return 0; | ||
1554 | chinfo = ee->ee_pwr_cal_g; | ||
1555 | break; | ||
1556 | default: | ||
1557 | return -EINVAL; | ||
1558 | } | ||
1559 | |||
1560 | for (pier = 0; pier < ee->ee_n_piers[mode]; pier++) { | ||
1561 | if (!chinfo[pier].pd_curves) | ||
1562 | continue; | ||
1563 | |||
1564 | for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) { | ||
1565 | struct ath5k_pdgain_info *pd = | ||
1566 | &chinfo[pier].pd_curves[pdg]; | ||
1567 | |||
1568 | if (pd != NULL) { | ||
1569 | kfree(pd->pd_step); | ||
1570 | kfree(pd->pd_pwr); | ||
1571 | } | ||
1572 | } | ||
1573 | |||
1574 | kfree(chinfo[pier].pd_curves); | ||
1575 | } | ||
1576 | |||
1577 | return 0; | ||
1578 | } | ||
1579 | |||
1580 | void | ||
1581 | ath5k_eeprom_detach(struct ath5k_hw *ah) | ||
1582 | { | ||
1583 | u8 mode; | ||
1584 | |||
1585 | for (mode = AR5K_EEPROM_MODE_11A; mode <= AR5K_EEPROM_MODE_11G; mode++) | ||
1586 | ath5k_eeprom_free_pcal_info(ah, mode); | ||
1587 | } | ||
1588 | |||
1280 | /* Read conformance test limits used for regulatory control */ | 1589 | /* Read conformance test limits used for regulatory control */ |
1281 | static int | 1590 | static int |
1282 | ath5k_eeprom_read_ctl_info(struct ath5k_hw *ah) | 1591 | ath5k_eeprom_read_ctl_info(struct ath5k_hw *ah) |
@@ -1457,3 +1766,4 @@ bool ath5k_eeprom_is_hb63(struct ath5k_hw *ah) | |||
1457 | else | 1766 | else |
1458 | return false; | 1767 | return false; |
1459 | } | 1768 | } |
1769 | |||