diff options
author | Nick Kossifidis <mick@madwifi.org> | 2008-12-20 21:47:39 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-01-29 15:58:42 -0500 |
commit | 0ea9c00c9d4e6309637a2defe18d26b6cda0fdc0 (patch) | |
tree | eb8477b48b95d95f47288bcdc1debf6e382059b9 | |
parent | 754be3098b22d1bea9620b40fe2f9f2286c55101 (diff) |
ath5k: Update EEPROM code
*Read misc2...6 values from eeprom since we want to use them (fixes
wrong power calibration info offset on RF2413+ chips)
*Initialize num_piers to 0 for RF2413 chips (note that we read 2GHz
frequency piers while reading mode sections, we have to ignore them
-usualy they are 0xff anyway but during my tests i got a 1 on b mode
with no data- and use the newer eemap.
*Add some more comments (please forgive my poor English ;-( ) and
some minor code cleanup
*Tested on 2425 and 2112 and has the same data with ath_info (i
wrote some debug code on debug.c to print everything like ath_info
but i haven't tested it yet on 5111 and it's full of > 80 col lines,
if anyone wants to play with it let me know).
Signed-Off-by: Nick Kossifidis <mickflemm@gmail.com>
Acked-by: Felix Fietkau <nbd@openwrt.org>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r-- | drivers/net/wireless/ath5k/eeprom.c | 143 |
1 files changed, 116 insertions, 27 deletions
diff --git a/drivers/net/wireless/ath5k/eeprom.c b/drivers/net/wireless/ath5k/eeprom.c index 1cb7edfae625..079e9ca168d5 100644 --- a/drivers/net/wireless/ath5k/eeprom.c +++ b/drivers/net/wireless/ath5k/eeprom.c | |||
@@ -137,6 +137,18 @@ ath5k_eeprom_init_header(struct ath5k_hw *ah) | |||
137 | if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) { | 137 | if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) { |
138 | AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC0, ee_misc0); | 138 | AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC0, ee_misc0); |
139 | AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC1, ee_misc1); | 139 | AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC1, ee_misc1); |
140 | |||
141 | /* XXX: Don't know which versions include these two */ | ||
142 | AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC2, ee_misc2); | ||
143 | |||
144 | if (ee->ee_version >= AR5K_EEPROM_VERSION_4_3) | ||
145 | AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC3, ee_misc3); | ||
146 | |||
147 | if (ee->ee_version >= AR5K_EEPROM_VERSION_5_0) { | ||
148 | AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC4, ee_misc4); | ||
149 | AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC5, ee_misc5); | ||
150 | AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC6, ee_misc6); | ||
151 | } | ||
140 | } | 152 | } |
141 | 153 | ||
142 | if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_3) { | 154 | if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_3) { |
@@ -213,7 +225,8 @@ static int ath5k_eeprom_read_ants(struct ath5k_hw *ah, u32 *offset, | |||
213 | } | 225 | } |
214 | 226 | ||
215 | /* | 227 | /* |
216 | * Read supported modes from eeprom | 228 | * Read supported modes and some mode-specific calibration data |
229 | * from eeprom | ||
217 | */ | 230 | */ |
218 | static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset, | 231 | static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset, |
219 | unsigned int mode) | 232 | unsigned int mode) |
@@ -315,6 +328,9 @@ static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset, | |||
315 | if (ah->ah_ee_version < AR5K_EEPROM_VERSION_4_0) | 328 | if (ah->ah_ee_version < AR5K_EEPROM_VERSION_4_0) |
316 | goto done; | 329 | goto done; |
317 | 330 | ||
331 | /* Note: >= v5 have bg freq piers on another location | ||
332 | * so these freq piers are ignored for >= v5 (should be 0xff | ||
333 | * anyway) */ | ||
318 | switch(mode) { | 334 | switch(mode) { |
319 | case AR5K_EEPROM_MODE_11A: | 335 | case AR5K_EEPROM_MODE_11A: |
320 | if (ah->ah_ee_version < AR5K_EEPROM_VERSION_4_1) | 336 | if (ah->ah_ee_version < AR5K_EEPROM_VERSION_4_1) |
@@ -442,7 +458,7 @@ ath5k_eeprom_read_turbo_modes(struct ath5k_hw *ah, | |||
442 | return 0; | 458 | return 0; |
443 | } | 459 | } |
444 | 460 | ||
445 | 461 | /* Read mode-specific data (except power calibration data) */ | |
446 | static int | 462 | static int |
447 | ath5k_eeprom_init_modes(struct ath5k_hw *ah) | 463 | ath5k_eeprom_init_modes(struct ath5k_hw *ah) |
448 | { | 464 | { |
@@ -488,6 +504,16 @@ ath5k_eeprom_init_modes(struct ath5k_hw *ah) | |||
488 | return 0; | 504 | return 0; |
489 | } | 505 | } |
490 | 506 | ||
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 | */ | ||
491 | static inline void | 517 | static inline void |
492 | ath5k_get_pcdac_intercepts(struct ath5k_hw *ah, u8 min, u8 max, u8 *vp) | 518 | ath5k_get_pcdac_intercepts(struct ath5k_hw *ah, u8 min, u8 max, u8 *vp) |
493 | { | 519 | { |
@@ -507,37 +533,48 @@ ath5k_get_pcdac_intercepts(struct ath5k_hw *ah, u8 min, u8 max, u8 *vp) | |||
507 | *vp++ = (ip[i] * max + (100 - ip[i]) * min) / 100; | 533 | *vp++ = (ip[i] * max + (100 - ip[i]) * min) / 100; |
508 | } | 534 | } |
509 | 535 | ||
536 | /* Read the frequency piers for each mode (mostly used on newer eeproms with 0xff | ||
537 | * frequency mask) */ | ||
510 | static inline int | 538 | static inline int |
511 | ath5k_eeprom_read_freq_list(struct ath5k_hw *ah, int *offset, int max, | 539 | ath5k_eeprom_read_freq_list(struct ath5k_hw *ah, int *offset, int max, |
512 | struct ath5k_chan_pcal_info *pc, u8 *count) | 540 | struct ath5k_chan_pcal_info *pc, unsigned int mode) |
513 | { | 541 | { |
542 | struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; | ||
514 | int o = *offset; | 543 | int o = *offset; |
515 | int i = 0; | 544 | int i = 0; |
516 | u8 f1, f2; | 545 | u8 freq1, freq2; |
517 | int ret; | 546 | int ret; |
518 | u16 val; | 547 | u16 val; |
519 | 548 | ||
520 | while(i < max) { | 549 | while(i < max) { |
521 | AR5K_EEPROM_READ(o++, val); | 550 | AR5K_EEPROM_READ(o++, val); |
522 | 551 | ||
523 | f1 = (val >> 8) & 0xff; | 552 | freq1 = (val >> 8) & 0xff; |
524 | f2 = val & 0xff; | 553 | freq2 = val & 0xff; |
525 | 554 | ||
526 | if (f1) | 555 | if (freq1) { |
527 | pc[i++].freq = f1; | 556 | pc[i++].freq = ath5k_eeprom_bin2freq(ee, |
557 | freq1, mode); | ||
558 | ee->ee_n_piers[mode]++; | ||
559 | } | ||
528 | 560 | ||
529 | if (f2) | 561 | if (freq2) { |
530 | pc[i++].freq = f2; | 562 | pc[i++].freq = ath5k_eeprom_bin2freq(ee, |
563 | freq2, mode); | ||
564 | ee->ee_n_piers[mode]++; | ||
565 | } | ||
531 | 566 | ||
532 | if (!f1 || !f2) | 567 | if (!freq1 || !freq2) |
533 | break; | 568 | break; |
534 | } | 569 | } |
570 | |||
571 | /* return new offset */ | ||
535 | *offset = o; | 572 | *offset = o; |
536 | *count = i; | ||
537 | 573 | ||
538 | return 0; | 574 | return 0; |
539 | } | 575 | } |
540 | 576 | ||
577 | /* Read frequency piers for 802.11a */ | ||
541 | static int | 578 | static int |
542 | ath5k_eeprom_init_11a_pcal_freq(struct ath5k_hw *ah, int offset) | 579 | ath5k_eeprom_init_11a_pcal_freq(struct ath5k_hw *ah, int offset) |
543 | { | 580 | { |
@@ -550,7 +587,7 @@ ath5k_eeprom_init_11a_pcal_freq(struct ath5k_hw *ah, int offset) | |||
550 | if (ee->ee_version >= AR5K_EEPROM_VERSION_3_3) { | 587 | if (ee->ee_version >= AR5K_EEPROM_VERSION_3_3) { |
551 | ath5k_eeprom_read_freq_list(ah, &offset, | 588 | ath5k_eeprom_read_freq_list(ah, &offset, |
552 | AR5K_EEPROM_N_5GHZ_CHAN, pcal, | 589 | AR5K_EEPROM_N_5GHZ_CHAN, pcal, |
553 | &ee->ee_n_piers[AR5K_EEPROM_MODE_11A]); | 590 | AR5K_EEPROM_MODE_11A); |
554 | } else { | 591 | } else { |
555 | mask = AR5K_EEPROM_FREQ_M(ah->ah_ee_version); | 592 | mask = AR5K_EEPROM_FREQ_M(ah->ah_ee_version); |
556 | 593 | ||
@@ -577,23 +614,25 @@ ath5k_eeprom_init_11a_pcal_freq(struct ath5k_hw *ah, int offset) | |||
577 | 614 | ||
578 | AR5K_EEPROM_READ(offset++, val); | 615 | AR5K_EEPROM_READ(offset++, val); |
579 | pcal[9].freq |= (val >> 10) & 0x3f; | 616 | pcal[9].freq |= (val >> 10) & 0x3f; |
617 | |||
618 | /* Fixed number of piers */ | ||
580 | ee->ee_n_piers[AR5K_EEPROM_MODE_11A] = 10; | 619 | ee->ee_n_piers[AR5K_EEPROM_MODE_11A] = 10; |
581 | } | ||
582 | 620 | ||
583 | for(i = 0; i < AR5K_EEPROM_N_5GHZ_CHAN; i += 1) { | 621 | for (i = 0; i < AR5K_EEPROM_N_5GHZ_CHAN; i++) { |
584 | pcal[i].freq = ath5k_eeprom_bin2freq(ee, | 622 | pcal[i].freq = ath5k_eeprom_bin2freq(ee, |
585 | pcal[i].freq, AR5K_EEPROM_MODE_11A); | 623 | pcal[i].freq, AR5K_EEPROM_MODE_11A); |
624 | } | ||
586 | } | 625 | } |
587 | 626 | ||
588 | return 0; | 627 | return 0; |
589 | } | 628 | } |
590 | 629 | ||
630 | /* Read frequency piers for 802.11bg on eeprom versions >= 5 and eemap >= 2 */ | ||
591 | static inline int | 631 | static inline int |
592 | ath5k_eeprom_init_11bg_2413(struct ath5k_hw *ah, unsigned int mode, int offset) | 632 | ath5k_eeprom_init_11bg_2413(struct ath5k_hw *ah, unsigned int mode, int offset) |
593 | { | 633 | { |
594 | struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; | 634 | struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; |
595 | struct ath5k_chan_pcal_info *pcal; | 635 | struct ath5k_chan_pcal_info *pcal; |
596 | int i; | ||
597 | 636 | ||
598 | switch(mode) { | 637 | switch(mode) { |
599 | case AR5K_EEPROM_MODE_11B: | 638 | case AR5K_EEPROM_MODE_11B: |
@@ -608,16 +647,18 @@ ath5k_eeprom_init_11bg_2413(struct ath5k_hw *ah, unsigned int mode, int offset) | |||
608 | 647 | ||
609 | ath5k_eeprom_read_freq_list(ah, &offset, | 648 | ath5k_eeprom_read_freq_list(ah, &offset, |
610 | AR5K_EEPROM_N_2GHZ_CHAN_2413, pcal, | 649 | AR5K_EEPROM_N_2GHZ_CHAN_2413, pcal, |
611 | &ee->ee_n_piers[mode]); | 650 | mode); |
612 | for(i = 0; i < AR5K_EEPROM_N_2GHZ_CHAN_2413; i += 1) { | ||
613 | pcal[i].freq = ath5k_eeprom_bin2freq(ee, | ||
614 | pcal[i].freq, mode); | ||
615 | } | ||
616 | 651 | ||
617 | return 0; | 652 | return 0; |
618 | } | 653 | } |
619 | 654 | ||
620 | 655 | /* Read power calibration for RF5111 chips | |
656 | * For RF5111 we have an XPD -eXternal Power Detector- curve | ||
657 | * for each calibrated channel. Each curve has PCDAC steps on | ||
658 | * x axis and power on y axis and looks like a logarithmic | ||
659 | * function. To recreate the curve and pass the power values | ||
660 | * on the pcdac table, we read 10 points here and interpolate later. | ||
661 | */ | ||
621 | static int | 662 | static int |
622 | ath5k_eeprom_read_pcal_info_5111(struct ath5k_hw *ah, int mode) | 663 | ath5k_eeprom_read_pcal_info_5111(struct ath5k_hw *ah, int mode) |
623 | { | 664 | { |
@@ -714,6 +755,17 @@ ath5k_eeprom_read_pcal_info_5111(struct ath5k_hw *ah, int mode) | |||
714 | return 0; | 755 | return 0; |
715 | } | 756 | } |
716 | 757 | ||
758 | /* Read power calibration for RF5112 chips | ||
759 | * For RF5112 we have 4 XPD -eXternal Power Detector- curves | ||
760 | * for each calibrated channel on 0, -6, -12 and -18dbm but we only | ||
761 | * use the higher (3) and the lower (0) curves. Each curve has PCDAC | ||
762 | * steps on x axis and power on y axis and looks like a linear | ||
763 | * function. To recreate the curve and pass the power values | ||
764 | * on the pcdac table, we read 4 points for xpd 0 and 3 points | ||
765 | * for xpd 3 here and interpolate later. | ||
766 | * | ||
767 | * Note: Many vendors just use xpd 0 so xpd 3 is zeroed. | ||
768 | */ | ||
717 | static int | 769 | static int |
718 | ath5k_eeprom_read_pcal_info_5112(struct ath5k_hw *ah, int mode) | 770 | ath5k_eeprom_read_pcal_info_5112(struct ath5k_hw *ah, int mode) |
719 | { | 771 | { |
@@ -790,7 +842,7 @@ ath5k_eeprom_read_pcal_info_5112(struct ath5k_hw *ah, int mode) | |||
790 | 842 | ||
791 | /* PCDAC steps | 843 | /* PCDAC steps |
792 | * corresponding to the above power | 844 | * corresponding to the above power |
793 | * measurements (static) */ | 845 | * measurements (fixed) */ |
794 | chan_pcal_info->pcdac_x3[0] = 20; | 846 | chan_pcal_info->pcdac_x3[0] = 20; |
795 | chan_pcal_info->pcdac_x3[1] = 35; | 847 | chan_pcal_info->pcdac_x3[1] = 35; |
796 | chan_pcal_info->pcdac_x3[2] = 63; | 848 | chan_pcal_info->pcdac_x3[2] = 63; |
@@ -814,6 +866,13 @@ ath5k_eeprom_read_pcal_info_5112(struct ath5k_hw *ah, int mode) | |||
814 | return 0; | 866 | return 0; |
815 | } | 867 | } |
816 | 868 | ||
869 | /* For RF2413 power calibration data doesn't start on a fixed location and | ||
870 | * if a mode is not supported, it's section is missing -not zeroed-. | ||
871 | * So we need to calculate the starting offset for each section by using | ||
872 | * these two functions */ | ||
873 | |||
874 | /* Return the size of each section based on the mode and the number of pd | ||
875 | * gains available (maximum 4). */ | ||
817 | static inline unsigned int | 876 | static inline unsigned int |
818 | ath5k_pdgains_size_2413(struct ath5k_eeprom_info *ee, unsigned int mode) | 877 | ath5k_pdgains_size_2413(struct ath5k_eeprom_info *ee, unsigned int mode) |
819 | { | 878 | { |
@@ -826,6 +885,8 @@ ath5k_pdgains_size_2413(struct ath5k_eeprom_info *ee, unsigned int mode) | |||
826 | return sz; | 885 | return sz; |
827 | } | 886 | } |
828 | 887 | ||
888 | /* Return the starting offset for a section based on the modes supported | ||
889 | * and each section's size. */ | ||
829 | static unsigned int | 890 | static unsigned int |
830 | ath5k_cal_data_offset_2413(struct ath5k_eeprom_info *ee, int mode) | 891 | ath5k_cal_data_offset_2413(struct ath5k_eeprom_info *ee, int mode) |
831 | { | 892 | { |
@@ -834,11 +895,13 @@ ath5k_cal_data_offset_2413(struct ath5k_eeprom_info *ee, int mode) | |||
834 | switch(mode) { | 895 | switch(mode) { |
835 | case AR5K_EEPROM_MODE_11G: | 896 | case AR5K_EEPROM_MODE_11G: |
836 | if (AR5K_EEPROM_HDR_11B(ee->ee_header)) | 897 | if (AR5K_EEPROM_HDR_11B(ee->ee_header)) |
837 | offset += ath5k_pdgains_size_2413(ee, AR5K_EEPROM_MODE_11B) + 2; | 898 | offset += ath5k_pdgains_size_2413(ee, AR5K_EEPROM_MODE_11B) + |
899 | AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2; | ||
838 | /* fall through */ | 900 | /* fall through */ |
839 | case AR5K_EEPROM_MODE_11B: | 901 | case AR5K_EEPROM_MODE_11B: |
840 | if (AR5K_EEPROM_HDR_11A(ee->ee_header)) | 902 | if (AR5K_EEPROM_HDR_11A(ee->ee_header)) |
841 | offset += ath5k_pdgains_size_2413(ee, AR5K_EEPROM_MODE_11A) + 5; | 903 | offset += ath5k_pdgains_size_2413(ee, AR5K_EEPROM_MODE_11A) + |
904 | AR5K_EEPROM_N_5GHZ_CHAN / 2; | ||
842 | /* fall through */ | 905 | /* fall through */ |
843 | case AR5K_EEPROM_MODE_11A: | 906 | case AR5K_EEPROM_MODE_11A: |
844 | break; | 907 | break; |
@@ -849,6 +912,17 @@ ath5k_cal_data_offset_2413(struct ath5k_eeprom_info *ee, int mode) | |||
849 | return offset; | 912 | return offset; |
850 | } | 913 | } |
851 | 914 | ||
915 | /* Read power calibration for RF2413 chips | ||
916 | * For RF2413 we have a PDDAC table (Power Detector) instead | ||
917 | * of a PCDAC and 4 pd gain curves for each calibrated channel. | ||
918 | * Each curve has PDDAC steps on x axis and power on y axis and | ||
919 | * looks like an exponential function. To recreate the curves | ||
920 | * we read here the points and interpolate later. Note that | ||
921 | * in most cases only higher and lower curves are used (like | ||
922 | * RF5112) but vendors have the oportunity to include all 4 | ||
923 | * curves on eeprom. The final curve (higher power) has an extra | ||
924 | * point for better accuracy like RF5112. | ||
925 | */ | ||
852 | static int | 926 | static int |
853 | ath5k_eeprom_read_pcal_info_2413(struct ath5k_hw *ah, int mode) | 927 | ath5k_eeprom_read_pcal_info_2413(struct ath5k_hw *ah, int mode) |
854 | { | 928 | { |
@@ -868,6 +942,7 @@ ath5k_eeprom_read_pcal_info_2413(struct ath5k_hw *ah, int mode) | |||
868 | ee->ee_pd_gains[mode] = pd_gains; | 942 | ee->ee_pd_gains[mode] = pd_gains; |
869 | 943 | ||
870 | offset = ath5k_cal_data_offset_2413(ee, mode); | 944 | offset = ath5k_cal_data_offset_2413(ee, mode); |
945 | ee->ee_n_piers[mode] = 0; | ||
871 | switch (mode) { | 946 | switch (mode) { |
872 | case AR5K_EEPROM_MODE_11A: | 947 | case AR5K_EEPROM_MODE_11A: |
873 | if (!AR5K_EEPROM_HDR_11A(ee->ee_header)) | 948 | if (!AR5K_EEPROM_HDR_11A(ee->ee_header)) |
@@ -1163,6 +1238,20 @@ static int ath5k_eeprom_read_target_rate_pwr_info(struct ath5k_hw *ah, unsigned | |||
1163 | return 0; | 1238 | return 0; |
1164 | } | 1239 | } |
1165 | 1240 | ||
1241 | /* | ||
1242 | * Read per channel calibration info from EEPROM | ||
1243 | * | ||
1244 | * This info is used to calibrate the baseband power table. Imagine | ||
1245 | * that for each channel there is a power curve that's hw specific | ||
1246 | * (depends on amplifier etc) and we try to "correct" this curve using | ||
1247 | * offests we pass on to phy chip (baseband -> before amplifier) so that | ||
1248 | * it can use accurate power values when setting tx power (takes amplifier's | ||
1249 | * performance on each channel into account). | ||
1250 | * | ||
1251 | * EEPROM provides us with the offsets for some pre-calibrated channels | ||
1252 | * and we have to interpolate to create the full table for these channels and | ||
1253 | * also the table for any channel. | ||
1254 | */ | ||
1166 | static int | 1255 | static int |
1167 | ath5k_eeprom_read_pcal_info(struct ath5k_hw *ah) | 1256 | ath5k_eeprom_read_pcal_info(struct ath5k_hw *ah) |
1168 | { | 1257 | { |
@@ -1193,7 +1282,7 @@ ath5k_eeprom_read_pcal_info(struct ath5k_hw *ah) | |||
1193 | return 0; | 1282 | return 0; |
1194 | } | 1283 | } |
1195 | 1284 | ||
1196 | /* Read conformance test limits */ | 1285 | /* Read conformance test limits used for regulatory control */ |
1197 | static int | 1286 | static int |
1198 | ath5k_eeprom_read_ctl_info(struct ath5k_hw *ah) | 1287 | ath5k_eeprom_read_ctl_info(struct ath5k_hw *ah) |
1199 | { | 1288 | { |