summaryrefslogtreecommitdiff
path: root/package/mac80211/patches/330-ath5k_eeprom.patch
diff options
context:
space:
mode:
Diffstat (limited to 'package/mac80211/patches/330-ath5k_eeprom.patch')
-rw-r--r--package/mac80211/patches/330-ath5k_eeprom.patch494
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 {