diff options
Diffstat (limited to 'package/mac80211/patches/330-ath5k_eeprom.patch')
-rw-r--r-- | package/mac80211/patches/330-ath5k_eeprom.patch | 494 |
1 files changed, 494 insertions, 0 deletions
diff --git a/package/mac80211/patches/330-ath5k_eeprom.patch b/package/mac80211/patches/330-ath5k_eeprom.patch new file mode 100644 index 0000000..a3a0285 --- /dev/null +++ b/package/mac80211/patches/330-ath5k_eeprom.patch @@ -0,0 +1,494 @@ +Clean up the eeprom parsing code and prepare the pdgain +data for 2413, which will be required for power calibration code. +Also clean up some ugly line wrapping to make the code easier on +the eyes. + +Signed-off-by: Felix Fietkau <nbd@openwrt.org> + +--- a/drivers/net/wireless/ath5k/eeprom.c ++++ b/drivers/net/wireless/ath5k/eeprom.c +@@ -541,31 +541,30 @@ ath5k_eeprom_read_freq_list(struct ath5k + { + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + int o = *offset; +- int i = 0; ++ int i; + u8 freq1, freq2; + int ret; + u16 val; + ++ ee->ee_n_piers[mode] = 0; + while(i < max) { + AR5K_EEPROM_READ(o++, val); + +- freq1 = (val >> 8) & 0xff; +- freq2 = val & 0xff; +- +- if (freq1) { +- pc[i++].freq = ath5k_eeprom_bin2freq(ee, +- freq1, mode); +- ee->ee_n_piers[mode]++; +- } ++ freq1 = val & 0xff; ++ if (!freq1) ++ break; + +- if (freq2) { +- pc[i++].freq = ath5k_eeprom_bin2freq(ee, +- freq2, mode); +- ee->ee_n_piers[mode]++; +- } ++ pc[i++].freq = ath5k_eeprom_bin2freq(ee, ++ freq1, mode); ++ ee->ee_n_piers[mode]++; + +- if (!freq1 || !freq2) ++ freq2 = (val >> 8) & 0xff; ++ if (!freq2) + break; ++ ++ pc[i++].freq = ath5k_eeprom_bin2freq(ee, ++ freq2, mode); ++ ee->ee_n_piers[mode]++; + } + + /* return new offset */ +@@ -918,84 +917,46 @@ ath5k_cal_data_offset_2413(struct ath5k_ + * curves on eeprom. The final curve (higher power) has an extra + * point for better accuracy like RF5112. + */ ++ + static int +-ath5k_eeprom_read_pcal_info_2413(struct ath5k_hw *ah, int mode) ++ath5k_eeprom_parse_pcal_info_2413(struct ath5k_hw *ah, int mode, u32 offset, ++ struct ath5k_chan_pcal_info *chinfo) + { + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; +- struct ath5k_chan_pcal_info_rf2413 *chan_pcal_info; +- struct ath5k_chan_pcal_info *gen_chan_info; +- unsigned int i, c; +- u32 offset; ++ struct ath5k_chan_pcal_info_rf2413 *pcinfo; ++ unsigned int i; + int ret; + u16 val; +- u8 pd_gains = 0; +- +- if (ee->ee_x_gain[mode] & 0x1) pd_gains++; +- if ((ee->ee_x_gain[mode] >> 1) & 0x1) pd_gains++; +- if ((ee->ee_x_gain[mode] >> 2) & 0x1) pd_gains++; +- if ((ee->ee_x_gain[mode] >> 3) & 0x1) pd_gains++; +- ee->ee_pd_gains[mode] = pd_gains; ++ u8 pd_gains; + +- offset = ath5k_cal_data_offset_2413(ee, mode); +- ee->ee_n_piers[mode] = 0; +- switch (mode) { +- case AR5K_EEPROM_MODE_11A: +- if (!AR5K_EEPROM_HDR_11A(ee->ee_header)) +- return 0; +- +- ath5k_eeprom_init_11a_pcal_freq(ah, offset); +- offset += AR5K_EEPROM_N_5GHZ_CHAN / 2; +- gen_chan_info = ee->ee_pwr_cal_a; +- break; +- case AR5K_EEPROM_MODE_11B: +- if (!AR5K_EEPROM_HDR_11B(ee->ee_header)) +- return 0; +- +- ath5k_eeprom_init_11bg_2413(ah, mode, offset); +- offset += AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2; +- gen_chan_info = ee->ee_pwr_cal_b; +- break; +- case AR5K_EEPROM_MODE_11G: +- if (!AR5K_EEPROM_HDR_11G(ee->ee_header)) +- return 0; +- +- ath5k_eeprom_init_11bg_2413(ah, mode, offset); +- offset += AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2; +- gen_chan_info = ee->ee_pwr_cal_g; +- break; +- default: +- return -EINVAL; +- } ++ pd_gains = ee->ee_pd_gains[mode]; + + if (pd_gains == 0) + return 0; + + for (i = 0; i < ee->ee_n_piers[mode]; i++) { +- chan_pcal_info = &gen_chan_info[i].rf2413_info; ++ pcinfo = &chinfo[i].rf2413_info; + + /* + * Read pwr_i, pddac_i and the first + * 2 pd points (pwr, pddac) + */ + AR5K_EEPROM_READ(offset++, val); +- chan_pcal_info->pwr_i[0] = val & 0x1f; +- chan_pcal_info->pddac_i[0] = (val >> 5) & 0x7f; +- chan_pcal_info->pwr[0][0] = +- (val >> 12) & 0xf; ++ pcinfo->pwr_i[0] = val & 0x1f; ++ pcinfo->pddac_i[0] = (val >> 5) & 0x7f; ++ pcinfo->pwr[0][0] = (val >> 12) & 0xf; + + AR5K_EEPROM_READ(offset++, val); +- chan_pcal_info->pddac[0][0] = val & 0x3f; +- chan_pcal_info->pwr[0][1] = (val >> 6) & 0xf; +- chan_pcal_info->pddac[0][1] = +- (val >> 10) & 0x3f; ++ pcinfo->pddac[0][0] = val & 0x3f; ++ pcinfo->pwr[0][1] = (val >> 6) & 0xf; ++ pcinfo->pddac[0][1] = (val >> 10) & 0x3f; + + AR5K_EEPROM_READ(offset++, val); +- chan_pcal_info->pwr[0][2] = val & 0xf; +- chan_pcal_info->pddac[0][2] = +- (val >> 4) & 0x3f; ++ pcinfo->pwr[0][2] = val & 0xf; ++ pcinfo->pddac[0][2] = (val >> 4) & 0x3f; + +- chan_pcal_info->pwr[0][3] = 0; +- chan_pcal_info->pddac[0][3] = 0; ++ pcinfo->pwr[0][3] = 0; ++ pcinfo->pddac[0][3] = 0; + + if (pd_gains > 1) { + /* +@@ -1003,44 +964,36 @@ ath5k_eeprom_read_pcal_info_2413(struct + * so it only has 2 pd points. + * Continue wih pd gain 1. + */ +- chan_pcal_info->pwr_i[1] = (val >> 10) & 0x1f; ++ pcinfo->pwr_i[1] = (val >> 10) & 0x1f; + +- chan_pcal_info->pddac_i[1] = (val >> 15) & 0x1; ++ pcinfo->pddac_i[1] = (val >> 15) & 0x1; + AR5K_EEPROM_READ(offset++, val); +- chan_pcal_info->pddac_i[1] |= (val & 0x3F) << 1; ++ pcinfo->pddac_i[1] |= (val & 0x3F) << 1; + +- chan_pcal_info->pwr[1][0] = (val >> 6) & 0xf; +- chan_pcal_info->pddac[1][0] = +- (val >> 10) & 0x3f; ++ pcinfo->pwr[1][0] = (val >> 6) & 0xf; ++ pcinfo->pddac[1][0] = (val >> 10) & 0x3f; + + AR5K_EEPROM_READ(offset++, val); +- chan_pcal_info->pwr[1][1] = val & 0xf; +- chan_pcal_info->pddac[1][1] = +- (val >> 4) & 0x3f; +- chan_pcal_info->pwr[1][2] = +- (val >> 10) & 0xf; ++ pcinfo->pwr[1][1] = val & 0xf; ++ pcinfo->pddac[1][1] = (val >> 4) & 0x3f; ++ pcinfo->pwr[1][2] = (val >> 10) & 0xf; + +- chan_pcal_info->pddac[1][2] = +- (val >> 14) & 0x3; ++ pcinfo->pddac[1][2] = (val >> 14) & 0x3; + AR5K_EEPROM_READ(offset++, val); +- chan_pcal_info->pddac[1][2] |= +- (val & 0xF) << 2; ++ pcinfo->pddac[1][2] |= (val & 0xF) << 2; + +- chan_pcal_info->pwr[1][3] = 0; +- chan_pcal_info->pddac[1][3] = 0; ++ pcinfo->pwr[1][3] = 0; ++ pcinfo->pddac[1][3] = 0; + } else if (pd_gains == 1) { + /* + * Pd gain 0 is the last one so + * read the extra point. + */ +- chan_pcal_info->pwr[0][3] = +- (val >> 10) & 0xf; ++ pcinfo->pwr[0][3] = (val >> 10) & 0xf; + +- chan_pcal_info->pddac[0][3] = +- (val >> 14) & 0x3; ++ pcinfo->pddac[0][3] = (val >> 14) & 0x3; + AR5K_EEPROM_READ(offset++, val); +- chan_pcal_info->pddac[0][3] |= +- (val & 0xF) << 2; ++ pcinfo->pddac[0][3] |= (val & 0xF) << 2; + } + + /* +@@ -1048,105 +1001,159 @@ ath5k_eeprom_read_pcal_info_2413(struct + * as above. + */ + if (pd_gains > 2) { +- chan_pcal_info->pwr_i[2] = (val >> 4) & 0x1f; +- chan_pcal_info->pddac_i[2] = (val >> 9) & 0x7f; ++ pcinfo->pwr_i[2] = (val >> 4) & 0x1f; ++ pcinfo->pddac_i[2] = (val >> 9) & 0x7f; + + AR5K_EEPROM_READ(offset++, val); +- chan_pcal_info->pwr[2][0] = +- (val >> 0) & 0xf; +- chan_pcal_info->pddac[2][0] = +- (val >> 4) & 0x3f; +- chan_pcal_info->pwr[2][1] = +- (val >> 10) & 0xf; +- +- chan_pcal_info->pddac[2][1] = +- (val >> 14) & 0x3; +- AR5K_EEPROM_READ(offset++, val); +- chan_pcal_info->pddac[2][1] |= +- (val & 0xF) << 2; +- +- chan_pcal_info->pwr[2][2] = +- (val >> 4) & 0xf; +- chan_pcal_info->pddac[2][2] = +- (val >> 8) & 0x3f; ++ pcinfo->pwr[2][0] = (val >> 0) & 0xf; ++ pcinfo->pddac[2][0] = (val >> 4) & 0x3f; ++ pcinfo->pwr[2][1] = (val >> 10) & 0xf; + +- chan_pcal_info->pwr[2][3] = 0; +- chan_pcal_info->pddac[2][3] = 0; ++ pcinfo->pddac[2][1] = (val >> 14) & 0x3; ++ AR5K_EEPROM_READ(offset++, val); ++ pcinfo->pddac[2][1] |= (val & 0xF) << 2; ++ ++ pcinfo->pwr[2][2] = (val >> 4) & 0xf; ++ pcinfo->pddac[2][2] = (val >> 8) & 0x3f; ++ ++ pcinfo->pwr[2][3] = 0; ++ pcinfo->pddac[2][3] = 0; + } else if (pd_gains == 2) { +- chan_pcal_info->pwr[1][3] = +- (val >> 4) & 0xf; +- chan_pcal_info->pddac[1][3] = +- (val >> 8) & 0x3f; ++ pcinfo->pwr[1][3] = (val >> 4) & 0xf; ++ pcinfo->pddac[1][3] = (val >> 8) & 0x3f; + } + + if (pd_gains > 3) { +- chan_pcal_info->pwr_i[3] = (val >> 14) & 0x3; ++ pcinfo->pwr_i[3] = (val >> 14) & 0x3; + AR5K_EEPROM_READ(offset++, val); +- chan_pcal_info->pwr_i[3] |= ((val >> 0) & 0x7) << 2; ++ pcinfo->pwr_i[3] |= ((val >> 0) & 0x7) << 2; + +- chan_pcal_info->pddac_i[3] = (val >> 3) & 0x7f; +- chan_pcal_info->pwr[3][0] = +- (val >> 10) & 0xf; +- chan_pcal_info->pddac[3][0] = +- (val >> 14) & 0x3; ++ pcinfo->pddac_i[3] = (val >> 3) & 0x7f; ++ pcinfo->pwr[3][0] = (val >> 10) & 0xf; ++ pcinfo->pddac[3][0] = (val >> 14) & 0x3; + + AR5K_EEPROM_READ(offset++, val); +- chan_pcal_info->pddac[3][0] |= +- (val & 0xF) << 2; +- chan_pcal_info->pwr[3][1] = +- (val >> 4) & 0xf; +- chan_pcal_info->pddac[3][1] = +- (val >> 8) & 0x3f; ++ pcinfo->pddac[3][0] |= (val & 0xF) << 2; ++ pcinfo->pwr[3][1] = (val >> 4) & 0xf; ++ pcinfo->pddac[3][1] = (val >> 8) & 0x3f; + +- chan_pcal_info->pwr[3][2] = +- (val >> 14) & 0x3; ++ pcinfo->pwr[3][2] = (val >> 14) & 0x3; + AR5K_EEPROM_READ(offset++, val); +- chan_pcal_info->pwr[3][2] |= +- ((val >> 0) & 0x3) << 2; ++ pcinfo->pwr[3][2] |= ((val >> 0) & 0x3) << 2; + +- chan_pcal_info->pddac[3][2] = +- (val >> 2) & 0x3f; +- chan_pcal_info->pwr[3][3] = +- (val >> 8) & 0xf; ++ pcinfo->pddac[3][2] = (val >> 2) & 0x3f; ++ pcinfo->pwr[3][3] = (val >> 8) & 0xf; + +- chan_pcal_info->pddac[3][3] = +- (val >> 12) & 0xF; ++ pcinfo->pddac[3][3] = (val >> 12) & 0xF; + AR5K_EEPROM_READ(offset++, val); +- chan_pcal_info->pddac[3][3] |= +- ((val >> 0) & 0x3) << 4; ++ pcinfo->pddac[3][3] |= ((val >> 0) & 0x3) << 4; + } else if (pd_gains == 3) { +- chan_pcal_info->pwr[2][3] = +- (val >> 14) & 0x3; ++ pcinfo->pwr[2][3] = (val >> 14) & 0x3; + AR5K_EEPROM_READ(offset++, val); +- chan_pcal_info->pwr[2][3] |= +- ((val >> 0) & 0x3) << 2; ++ pcinfo->pwr[2][3] |= ((val >> 0) & 0x3) << 2; + +- chan_pcal_info->pddac[2][3] = +- (val >> 2) & 0x3f; ++ pcinfo->pddac[2][3] = (val >> 2) & 0x3f; + } ++ } ++ return 0; ++} ++ ++static int ++ath5k_eeprom_convert_pcal_info_2413(struct ath5k_hw *ah, int mode, ++ struct ath5k_chan_pcal_info *chinfo, ++ unsigned int *xgains) ++{ ++ struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; ++ struct ath5k_chan_pcal_info_rf2413 *pcinfo; ++ unsigned int i, j, k; + +- for (c = 0; c < pd_gains; c++) { +- /* Recreate pwr table for this channel using pwr steps */ +- chan_pcal_info->pwr[c][0] += chan_pcal_info->pwr_i[c] * 2; +- chan_pcal_info->pwr[c][1] += chan_pcal_info->pwr[c][0]; +- chan_pcal_info->pwr[c][2] += chan_pcal_info->pwr[c][1]; +- chan_pcal_info->pwr[c][3] += chan_pcal_info->pwr[c][2]; +- if (chan_pcal_info->pwr[c][3] == chan_pcal_info->pwr[c][2]) +- chan_pcal_info->pwr[c][3] = 0; +- +- /* Recreate pddac table for this channel using pddac steps */ +- chan_pcal_info->pddac[c][0] += chan_pcal_info->pddac_i[c]; +- chan_pcal_info->pddac[c][1] += chan_pcal_info->pddac[c][0]; +- chan_pcal_info->pddac[c][2] += chan_pcal_info->pddac[c][1]; +- chan_pcal_info->pddac[c][3] += chan_pcal_info->pddac[c][2]; +- if (chan_pcal_info->pddac[c][3] == chan_pcal_info->pddac[c][2]) +- chan_pcal_info->pddac[c][3] = 0; ++ /* prepare the raw values */ ++ for (i = 0; i < ee->ee_n_piers[mode]; i++) { ++ pcinfo = &chinfo[i].rf2413_info; ++ for (j = 0; j < ee->ee_pd_gains[mode]; j++) { ++ unsigned int idx = xgains[j]; ++ struct ath5k_pdgain_info *pd = &pcinfo->pdgains[idx]; ++ ++ /* one more point for the highest power (lowest gain) */ ++ if (j == ee->ee_pd_gains[mode] - 1) { ++ pd->n_vpd = AR5K_EEPROM_N_PD_POINTS; ++ } else { ++ pd->n_vpd = AR5K_EEPROM_N_PD_POINTS - 1; ++ } ++ ++ pd->vpd[0] = pcinfo->pddac_i[j]; ++ pd->pwr_t4[0] = 4 * pcinfo->pwr_i[j]; ++ for (k = 1; k < pd->n_vpd; k++) { ++ pd->pwr_t4[k] = pd->pwr_t4[k - 1] + 2 * pcinfo->pwr[j][k - 1]; ++ pd->vpd[k] = pd->vpd[k - 1] + pcinfo->pddac[j][k - 1]; ++ } + } + } + + return 0; + } + ++static int ++ath5k_eeprom_read_pcal_info_2413(struct ath5k_hw *ah, int mode) ++{ ++ struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; ++ struct ath5k_chan_pcal_info *chinfo; ++ unsigned int xgains[AR5K_EEPROM_N_PD_GAINS]; ++ u32 offset; ++ u8 pd_gains = 0; ++ int i, ret; ++ ++ memset(xgains, 0, sizeof(xgains)); ++ for (i = 0; i < AR5K_EEPROM_N_PD_GAINS; i++) { ++ int idx = AR5K_EEPROM_N_PD_GAINS - i - 1; ++ ++ if ((ee->ee_x_gain[mode] >> idx) & 0x1) ++ xgains[pd_gains++] = idx; ++ } ++ ee->ee_pd_gains[mode] = pd_gains; ++ ++ offset = ath5k_cal_data_offset_2413(ee, mode); ++ switch (mode) { ++ case AR5K_EEPROM_MODE_11A: ++ if (!AR5K_EEPROM_HDR_11A(ee->ee_header)) ++ return 0; ++ ++ ath5k_eeprom_init_11a_pcal_freq(ah, offset); ++ offset += AR5K_EEPROM_N_5GHZ_CHAN / 2; ++ chinfo = ee->ee_pwr_cal_a; ++ break; ++ case AR5K_EEPROM_MODE_11B: ++ if (!AR5K_EEPROM_HDR_11B(ee->ee_header)) ++ return 0; ++ ++ ath5k_eeprom_init_11bg_2413(ah, mode, offset); ++ offset += AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2; ++ chinfo = ee->ee_pwr_cal_b; ++ break; ++ case AR5K_EEPROM_MODE_11G: ++ if (!AR5K_EEPROM_HDR_11G(ee->ee_header)) ++ return 0; ++ ++ ath5k_eeprom_init_11bg_2413(ah, mode, offset); ++ offset += AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2; ++ chinfo = ee->ee_pwr_cal_g; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ ++ ret = ath5k_eeprom_parse_pcal_info_2413(ah, mode, offset, chinfo); ++ if (ret) ++ return ret; ++ ++ ret = ath5k_eeprom_convert_pcal_info_2413(ah, mode, chinfo, xgains); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ + /* + * Read per rate target power (this is the maximum tx power + * supported by the card). This info is used when setting +@@ -1264,6 +1271,7 @@ ath5k_eeprom_read_pcal_info(struct ath5k + else + read_pcal = ath5k_eeprom_read_pcal_info_5111; + ++ + for (mode = AR5K_EEPROM_MODE_11A; mode <= AR5K_EEPROM_MODE_11G; mode++) { + err = read_pcal(ah, mode); + if (err) +--- a/drivers/net/wireless/ath5k/eeprom.h ++++ b/drivers/net/wireless/ath5k/eeprom.h +@@ -265,15 +265,27 @@ struct ath5k_chan_pcal_info_rf5112 { + u8 pcdac_x3[AR5K_EEPROM_N_XPD3_POINTS]; + }; + ++ ++struct ath5k_pdgain_info { ++ u16 n_vpd; ++ u16 vpd[AR5K_EEPROM_N_PD_POINTS]; ++ s16 pwr_t4[AR5K_EEPROM_N_PD_POINTS]; ++}; ++ + struct ath5k_chan_pcal_info_rf2413 { ++ /* --- EEPROM VALUES --- */ + /* Starting pwr/pddac values */ +- s8 pwr_i[AR5K_EEPROM_N_PD_GAINS]; +- u8 pddac_i[AR5K_EEPROM_N_PD_GAINS]; ++ s8 pwr_i[AR5K_EEPROM_N_PD_GAINS]; ++ u8 pddac_i[AR5K_EEPROM_N_PD_GAINS]; + /* (pwr,pddac) points */ +- s8 pwr[AR5K_EEPROM_N_PD_GAINS] +- [AR5K_EEPROM_N_PD_POINTS]; +- u8 pddac[AR5K_EEPROM_N_PD_GAINS] +- [AR5K_EEPROM_N_PD_POINTS]; ++ s8 pwr[AR5K_EEPROM_N_PD_GAINS] ++ [AR5K_EEPROM_N_PD_POINTS]; ++ u8 pddac[AR5K_EEPROM_N_PD_GAINS] ++ [AR5K_EEPROM_N_PD_POINTS]; ++ ++ /* --- RAW VALUES --- */ ++ struct ath5k_pdgain_info pdgains ++ [AR5K_EEPROM_N_PD_GAINS]; + }; + + struct ath5k_chan_pcal_info { |