ath5k: Clean up eeprom parsing and add missing calibration data
PATCH 1/1 ath5k: Clean up eeprom parsing and add missing calibration data
This patch brings the ath5k eeprom parsing code in sync with the work done on ath_info by Nick Kossifidis and integrates the missing parts based on the code of the Atheros Legacy HAL release.
drivers/net/wireless/ath5k/eeprom.c +1046 -146
@@ -1,6 +1,7 @@/* * Copyright (c) 2004-2008 Reyk Floeter <[email protected]> * Copyright (c) 2006-2008 Nick Kossifidis <[email protected]> +* Copyright (c) 2008 Felix Fietkau <[email protected]> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above
@@ -63,8 +64,8 @@ static int ath5k_hw_eeprom_read(struct a/* * Translate binary channel representation in EEPROM to frequency */ -static u16 ath5k_eeprom_bin2freq (struct ath5k_hw *ah,u16 bin, -unsigned int mode) +static u16 ath5k_eeprom_bin2freq (struct ath5k_eeprom_info *ee,u16 bin, +unsigned int mode) {u16 val;
@@ -72,13 +73,13 @@ static u16 ath5k_eeprom_bin2freq(structreturn bin;if (mode ==AR5K_EEPROM_MODE_11A ) { -if (ah->ah_ee_version >AR5K_EEPROM_VERSION_3_2 ) +if (ee->ee_version >AR5K_EEPROM_VERSION_3_2 ) val = (5 * bin) +4800 ;else val = bin >62 ? (10 *62 ) + (5 * (bin -62 )) +5100 : (bin *10 ) +5100 ; }else { -if (ah->ah_ee_version >AR5K_EEPROM_VERSION_3_2 ) +if (ee->ee_version >AR5K_EEPROM_VERSION_3_2 ) val = bin +2300 ;else val = bin +2400 ;
@@ -88,6 +89,71 @@ static u16 ath5k_eeprom_bin2freq(struct }/* +* Initialize eeprom & capabilities structs +*/ +static int +ath5k_eeprom_init_header (struct ath5k_hw *ah) +{ +struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; +int ret; +u16 val; + +/* Initial TX thermal adjustment values */ + ee->ee_tx_clip =4 ; + ee->ee_pwd_84 = ee->ee_pwd_90 =1 ; + ee->ee_gain_select =1 ; + +/* +* Read values from EEPROM and store them in the capability structure +*/ +AR5K_EEPROM_READ_HDR (AR5K_EEPROM_MAGIC , ee_magic); +AR5K_EEPROM_READ_HDR (AR5K_EEPROM_PROTECT , ee_protect); +AR5K_EEPROM_READ_HDR (AR5K_EEPROM_REG_DOMAIN , ee_regdomain); +AR5K_EEPROM_READ_HDR (AR5K_EEPROM_VERSION , ee_version); +AR5K_EEPROM_READ_HDR (AR5K_EEPROM_HDR , ee_header); + +/* Return if we have an old EEPROM */ +if (ah->ah_ee_version <AR5K_EEPROM_VERSION_3_0 ) +return 0 ; + +#ifdef notyet +/* +* Validate the checksum of the EEPROM date. There are some +* devices with invalid EEPROMs. +*/ +for (cksum =0 , offset =0 ; offset <AR5K_EEPROM_INFO_MAX ; offset++) { +AR5K_EEPROM_READ (AR5K_EEPROM_INFO (offset), val); + cksum ^= val; + } +if (cksum !=AR5K_EEPROM_INFO_CKSUM ) { +ATH5K_ERR (ah->ah_sc,"Invalid EEPROM checksum 0x%04x\n" , cksum); +return -EIO ; + } +#endif + +AR5K_EEPROM_READ_HDR (AR5K_EEPROM_ANT_GAIN (ah->ah_ee_version), + ee_ant_gain); + +if (ah->ah_ee_version >=AR5K_EEPROM_VERSION_4_0 ) { +AR5K_EEPROM_READ_HDR (AR5K_EEPROM_MISC0 , ee_misc0); +AR5K_EEPROM_READ_HDR (AR5K_EEPROM_MISC1 , ee_misc1); + } + +if (ah->ah_ee_version <AR5K_EEPROM_VERSION_3_3 ) { +AR5K_EEPROM_READ (AR5K_EEPROM_OBDB0_2GHZ , val); + ee->ee_ob[AR5K_EEPROM_MODE_11B ][0 ] = val &0x7 ; + ee->ee_db[AR5K_EEPROM_MODE_11B ][0 ] = (val >>3 ) &0x7 ; + +AR5K_EEPROM_READ (AR5K_EEPROM_OBDB1_2GHZ , val); + ee->ee_ob[AR5K_EEPROM_MODE_11G ][0 ] = val &0x7 ; + ee->ee_db[AR5K_EEPROM_MODE_11G ][0 ] = (val >>3 ) &0x7 ; + } + +return 0 ; +} + + +/* * Read antenna infos from eeprom */ static int ath5k_eeprom_read_ants(struct ath5k_hw *ah, u32 *offset,
@@ -100,7 +166,7 @@ static int ath5k_eeprom_read_ants(structAR5K_EEPROM_READ (o++, val); ee->ee_switch_settling[mode] = (val >>8 ) &0x7f ; - ee->ee_ant_tx_rx[mode] = (val >>2 ) &0x3f ; + ee->ee_atn_tx_rx[mode] = (val >>2 ) &0x3f ; ee->ee_ant_control[mode][i] = (val <<4 ) &0x3f ;AR5K_EEPROM_READ (o++, val);
@@ -157,6 +223,30 @@ static int ath5k_eeprom_read_modes(strucu16 val;int ret; + ee->ee_n_piers[mode] =0 ; +AR5K_EEPROM_READ (o++, val); + ee->ee_adc_desired_size[mode] = (s8)((val >>8 ) &0xff ); +switch (mode) { +case AR5K_EEPROM_MODE_11A : + ee->ee_ob[mode][3 ] = (val >>5 ) &0x7 ; + ee->ee_db[mode][3 ] = (val >>2 ) &0x7 ; + ee->ee_ob[mode][2 ] = (val <<1 ) &0x7 ; + +AR5K_EEPROM_READ (o++, val); + ee->ee_ob[mode][2 ] |= (val >>15 ) &0x1 ; + ee->ee_db[mode][2 ] = (val >>12 ) &0x7 ; + ee->ee_ob[mode][1 ] = (val >>9 ) &0x7 ; + ee->ee_db[mode][1 ] = (val >>6 ) &0x7 ; + ee->ee_ob[mode][0 ] = (val >>3 ) &0x7 ; + ee->ee_db[mode][0 ] = val &0x7 ; +break ; +case AR5K_EEPROM_MODE_11G : +case AR5K_EEPROM_MODE_11B : + ee->ee_ob[mode][1 ] = (val >>4 ) &0x7 ; + ee->ee_db[mode][1 ] = val &0x7 ; +break ; + } +AR5K_EEPROM_READ (o++, val); ee->ee_tx_end2xlna_enable[mode] = (val >>8 ) &0xff ; ee->ee_thr_62[mode] = val &0xff ;
@@ -209,8 +299,11 @@ static int ath5k_eeprom_read_modes(strucAR5K_EEPROM_READ (o++, val); ee->ee_i_gain[mode] |= (val <<3 ) &0x38 ; -if (mode ==AR5K_EEPROM_MODE_11G ) +if (mode ==AR5K_EEPROM_MODE_11G ) { ee->ee_cck_ofdm_power_delta = (val >>3 ) &0xff ; +if (ah->ah_ee_version >=AR5K_EEPROM_VERSION_4_6 ) + ee->ee_scaled_cck_delta = (val >>11 ) &0x1f ; + } } if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0 &&
@@ -219,10 +312,77 @@ static int ath5k_eeprom_read_modes(struc ee->ee_q_cal[mode] = (val >>3 ) &0x1f ; } -if (ah->ah_ee_version >=AR5K_EEPROM_VERSION_4_6 && - mode ==AR5K_EEPROM_MODE_11G ) - ee->ee_scaled_cck_delta = (val >>11 ) &0x1f ; +if (ah->ah_ee_version <AR5K_EEPROM_VERSION_4_0 ) + goto done; + +switch (mode) { +case AR5K_EEPROM_MODE_11A : +if (ah->ah_ee_version <AR5K_EEPROM_VERSION_4_1 ) +break ; + +AR5K_EEPROM_READ (o++, val); + ee->ee_margin_tx_rx[mode] = val &0x3f ; +break ; +case AR5K_EEPROM_MODE_11B : +AR5K_EEPROM_READ (o++, val); + + ee->ee_pwr_cal_b[0 ].freq = +ath5k_eeprom_bin2freq (ee, val &0xff , mode); +if (ee->ee_pwr_cal_b[0 ].freq !=AR5K_EEPROM_CHANNEL_DIS ) + ee->ee_n_piers[mode]++; + + ee->ee_pwr_cal_b[1 ].freq = +ath5k_eeprom_bin2freq (ee, (val >>8 ) &0xff , mode); +if (ee->ee_pwr_cal_b[1 ].freq !=AR5K_EEPROM_CHANNEL_DIS ) + ee->ee_n_piers[mode]++; + +AR5K_EEPROM_READ (o++, val); + ee->ee_pwr_cal_b[2 ].freq = +ath5k_eeprom_bin2freq (ee, val &0xff , mode); +if (ee->ee_pwr_cal_b[2 ].freq !=AR5K_EEPROM_CHANNEL_DIS ) + ee->ee_n_piers[mode]++; + +if (ah->ah_ee_version >=AR5K_EEPROM_VERSION_4_1 ) + ee->ee_margin_tx_rx[mode] = (val >>8 ) &0x3f ; +break ; +case AR5K_EEPROM_MODE_11G : +AR5K_EEPROM_READ (o++, val); + + ee->ee_pwr_cal_g[0 ].freq = +ath5k_eeprom_bin2freq (ee, val &0xff , mode); +if (ee->ee_pwr_cal_g[0 ].freq !=AR5K_EEPROM_CHANNEL_DIS ) + ee->ee_n_piers[mode]++; + + ee->ee_pwr_cal_g[1 ].freq = +ath5k_eeprom_bin2freq (ee, (val >>8 ) &0xff , mode); +if (ee->ee_pwr_cal_g[1 ].freq !=AR5K_EEPROM_CHANNEL_DIS ) + ee->ee_n_piers[mode]++; +AR5K_EEPROM_READ (o++, val); + ee->ee_turbo_max_power[mode] = val &0x7f ; + ee->ee_xr_power[mode] = (val >>7 ) &0x3f ; + +AR5K_EEPROM_READ (o++, val); + ee->ee_pwr_cal_g[2 ].freq = +ath5k_eeprom_bin2freq (ee, val &0xff , mode); +if (ee->ee_pwr_cal_g[2 ].freq !=AR5K_EEPROM_CHANNEL_DIS ) + ee->ee_n_piers[mode]++; + +if (ah->ah_ee_version >=AR5K_EEPROM_VERSION_4_1 ) + ee->ee_margin_tx_rx[mode] = (val >>8 ) &0x3f ; + +AR5K_EEPROM_READ (o++, val); + ee->ee_i_cal[mode] = (val >>8 ) &0x3f ; + ee->ee_q_cal[mode] = (val >>3 ) &0x1f ; + +if (ah->ah_ee_version >=AR5K_EEPROM_VERSION_4_2 ) { +AR5K_EEPROM_READ (o++, val); + ee->ee_cck_ofdm_gain_delta = val &0xff ; + } +break ; + } + +done:/* return new offset */ *offset = o;
@@ -230,204 +390,944 @@ static int ath5k_eeprom_read_modes(struc }/* -* Initialize eeprom & capabilities structs +* Read turbo mode information on newer EEPROM versions */ -int ath5k_eeprom_init (struct ath5k_hw *ah) +static int +ath5k_eeprom_read_turbo_modes (struct ath5k_hw *ah, +u32 *offset,unsigned int mode) {struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; -unsigned int mode, i; -int ret; -u32 offset; +u32 o = *offset;u16 val; +int ret; -/* Initial TX thermal adjustment values */ - ee->ee_tx_clip =4 ; - ee->ee_pwd_84 = ee->ee_pwd_90 =1 ; - ee->ee_gain_select =1 ; +if (ee->ee_version <AR5K_EEPROM_VERSION_5_0 ) +return 0 ; -/* -* Read values from EEPROM and store them in the capability structure -*/ -AR5K_EEPROM_READ_HDR (AR5K_EEPROM_MAGIC , ee_magic); -AR5K_EEPROM_READ_HDR (AR5K_EEPROM_PROTECT , ee_protect); -AR5K_EEPROM_READ_HDR (AR5K_EEPROM_REG_DOMAIN , ee_regdomain); -AR5K_EEPROM_READ_HDR (AR5K_EEPROM_VERSION , ee_version); -AR5K_EEPROM_READ_HDR (AR5K_EEPROM_HDR , ee_header); +switch (mode){ +case AR5K_EEPROM_MODE_11A : + ee->ee_switch_settling_turbo[mode] = (val >>6 ) &0x7f ; -/* Return if we have an old EEPROM */ -if (ah->ah_ee_version <AR5K_EEPROM_VERSION_3_0 ) -return 0 ; + ee->ee_atn_tx_rx_turbo[mode] = (val >>13 ) &0x7 ; +AR5K_EEPROM_READ (o++, val); + ee->ee_atn_tx_rx_turbo[mode] |= (val &0x7 ) <<3 ; + ee->ee_margin_tx_rx_turbo[mode] = (val >>3 ) &0x3f ; + + ee->ee_adc_desired_size_turbo[mode] = (val >>9 ) &0x7f ; +AR5K_EEPROM_READ (o++, val); + ee->ee_adc_desired_size_turbo[mode] |= (val &0x1 ) <<7 ; + ee->ee_pga_desired_size_turbo[mode] = (val >>1 ) &0xff ; + +if (AR5K_EEPROM_EEMAP (ee->ee_misc0) >=2 ) + ee->ee_pd_gain_overlap = (val >>9 ) &0xf ; +break ; +case AR5K_EEPROM_MODE_11G : + ee->ee_switch_settling_turbo[mode] = (val >>8 ) &0x7f ; + + ee->ee_atn_tx_rx_turbo[mode] = (val >>15 ) &0x7 ; +AR5K_EEPROM_READ (o++, val); + ee->ee_atn_tx_rx_turbo[mode] |= (val &0x1f ) <<1 ; + ee->ee_margin_tx_rx_turbo[mode] = (val >>5 ) &0x3f ; + + ee->ee_adc_desired_size_turbo[mode] = (val >>11 ) &0x7f ; +AR5K_EEPROM_READ (o++, val); + ee->ee_adc_desired_size_turbo[mode] |= (val &0x7 ) <<5 ; + ee->ee_pga_desired_size_turbo[mode] = (val >>3 ) &0xff ; +break ; + } + +/* return new offset */ + *offset = o; + +return 0 ; +} + + +static int +ath5k_eeprom_init_modes (struct ath5k_hw *ah) +{ +struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; +u32 mode_offset[3 ]; +unsigned int mode; +u32 offset; +int ret; -#ifdef notyet/* -* Validate the checksum of the EEPROM date. There are some -* devices with invalid EEPROMs. +* Get values for all modes */ -for (cksum =0 , offset =0 ; offset <AR5K_EEPROM_INFO_MAX ; offset++) { -AR5K_EEPROM_READ (AR5K_EEPROM_INFO (offset), val); - cksum ^= val; + mode_offset[AR5K_EEPROM_MODE_11A ] =AR5K_EEPROM_MODES_11A (ah->ah_ee_version); + mode_offset[AR5K_EEPROM_MODE_11B ] =AR5K_EEPROM_MODES_11B (ah->ah_ee_version); + mode_offset[AR5K_EEPROM_MODE_11G ] =AR5K_EEPROM_MODES_11G (ah->ah_ee_version); + + ee->ee_turbo_max_power[AR5K_EEPROM_MODE_11A ] = +AR5K_EEPROM_HDR_T_5GHZ_DBM (ee->ee_header); + +for (mode =AR5K_EEPROM_MODE_11A ; mode <=AR5K_EEPROM_MODE_11G ; mode++) { + offset = mode_offset[mode]; + + ret =ath5k_eeprom_read_ants (ah, &offset, mode); +if (ret) +return ret; + + ret =ath5k_eeprom_read_modes (ah, &offset, mode); +if (ret) +return ret; + + ret =ath5k_eeprom_read_turbo_modes (ah, &offset, mode); +if (ret) +return ret; } -if (cksum !=AR5K_EEPROM_INFO_CKSUM ) { -ATH5K_ERR (ah->ah_sc,"Invalid EEPROM checksum 0x%04x\n" , cksum); -return -EIO ; + +/* override for older eeprom versions for better performance */ +if (ah->ah_ee_version <=AR5K_EEPROM_VERSION_3_2 ) { + ee->ee_thr_62[AR5K_EEPROM_MODE_11A ] =15 ; + ee->ee_thr_62[AR5K_EEPROM_MODE_11B ] =28 ; + ee->ee_thr_62[AR5K_EEPROM_MODE_11G ] =28 ; } -#endif -AR5K_EEPROM_READ_HDR (AR5K_EEPROM_ANT_GAIN (ah->ah_ee_version), - ee_ant_gain); +return 0 ; +} -if (ah->ah_ee_version >=AR5K_EEPROM_VERSION_4_0 ) { -AR5K_EEPROM_READ_HDR (AR5K_EEPROM_MISC0 , ee_misc0); -AR5K_EEPROM_READ_HDR (AR5K_EEPROM_MISC1 , ee_misc1); - } +static inline void +ath5k_get_pcdac_intercepts (struct ath5k_hw *ah,u8 min,u8 max,u8 *vp) +{ +const static u16 intercepts3[] = + {0 ,5 ,10 ,20 ,30 ,50 ,70 ,85 ,90 ,95 ,100 }; +const static u16 intercepts3_2[] = + {0 ,10 ,20 ,30 ,40 ,50 ,60 ,70 ,80 ,90 ,100 }; +const u16 *ip; +int i; -if (ah->ah_ee_version <AR5K_EEPROM_VERSION_3_3 ) { -AR5K_EEPROM_READ (AR5K_EEPROM_OBDB0_2GHZ , val); - ee->ee_ob[AR5K_EEPROM_MODE_11B ][0 ] = val &0x7 ; - ee->ee_db[AR5K_EEPROM_MODE_11B ][0 ] = (val >>3 ) &0x7 ; +if (ah->ah_ee_version >=AR5K_EEPROM_VERSION_3_2 ) + ip = intercepts3_2; +else + ip = intercepts3; -AR5K_EEPROM_READ (AR5K_EEPROM_OBDB1_2GHZ , val); - ee->ee_ob[AR5K_EEPROM_MODE_11G ][0 ] = val &0x7 ; - ee->ee_db[AR5K_EEPROM_MODE_11G ][0 ] = (val >>3 ) &0x7 ; +for (i =0 ; i <ARRAY_SIZE (intercepts3); i++) + *vp++ = (ip[i] * max + (100 - ip[i]) * min) /100 ; +} + +static inline int +ath5k_eeprom_read_freq_list (struct ath5k_hw *ah,int *offset,int max, +struct ath5k_chan_pcal_info *pc,u8 *count) +{ +int o = *offset; +int i =0 ; +u8 f1, f2; +int ret; +u16 val; + +while (i < max) { +AR5K_EEPROM_READ (o++, val); + + f1 = (val >>8 ) &0xff ; + f2 = val &0xff ; + +if (f1) + pc[i++].freq = f1; + +if (f2) + pc[i++].freq = f2; + +if (!f1 || !f2) +break ; } + *offset = o; + *count = i; -/* -* Get conformance test limit values -*/ - offset =AR5K_EEPROM_CTL (ah->ah_ee_version); - ee->ee_ctls =AR5K_EEPROM_N_CTLS (ah->ah_ee_version); +return 0 ; +} + +static int +ath5k_eeprom_init_11a_pcal_freq (struct ath5k_hw *ah,int offset) +{ +struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; +struct ath5k_chan_pcal_info *pcal = ee->ee_pwr_cal_a; +int i, ret; +u16 val; +u8 mask; + +if (ee->ee_version >=AR5K_EEPROM_VERSION_3_3 ) { +ath5k_eeprom_read_freq_list (ah, &offset, +AR5K_EEPROM_N_5GHZ_CHAN , pcal, + &ee->ee_n_piers[AR5K_EEPROM_MODE_11A ]); + }else { + mask =AR5K_EEPROM_FREQ_M (ah->ah_ee_version); -for (i =0 ; i < ee->ee_ctls; i++) {AR5K_EEPROM_READ (offset++, val); - ee->ee_ctl[i] = (val >>8 ) &0xff ; - ee->ee_ctl[i +1 ] = val &0xff ; + pcal[0 ].freq = (val >>9 ) & mask; + pcal[1 ].freq = (val >>2 ) & mask; + pcal[2 ].freq = (val <<5 ) & mask; + +AR5K_EEPROM_READ (offset++, val); + pcal[2 ].freq |= (val >>11 ) &0x1f ; + pcal[3 ].freq = (val >>4 ) & mask; + pcal[4 ].freq = (val <<3 ) & mask; + +AR5K_EEPROM_READ (offset++, val); + pcal[4 ].freq |= (val >>13 ) &0x7 ; + pcal[5 ].freq = (val >>6 ) & mask; + pcal[6 ].freq = (val <<1 ) & mask; + +AR5K_EEPROM_READ (offset++, val); + pcal[6 ].freq |= (val >>15 ) &0x1 ; + pcal[7 ].freq = (val >>8 ) & mask; + pcal[8 ].freq = (val >>1 ) & mask; + pcal[9 ].freq = (val <<6 ) & mask; + +AR5K_EEPROM_READ (offset++, val); + pcal[9 ].freq |= (val >>10 ) &0x3f ; + ee->ee_n_piers[AR5K_EEPROM_MODE_11A ] =10 ; } -/* -* Get values for 802.11a (5GHz) -*/ - mode =AR5K_EEPROM_MODE_11A ; +for (i =0 ; i <AR5K_EEPROM_N_5GHZ_CHAN ; i +=1 ) { + pcal[i].freq =ath5k_eeprom_bin2freq (ee, + pcal[i].freq,AR5K_EEPROM_MODE_11A ); + } + +return 0 ; +} - ee->ee_turbo_max_power[mode] = -AR5K_EEPROM_HDR_T_5GHZ_DBM (ee->ee_header); +static inline int +ath5k_eeprom_init_11bg_2413 (struct ath5k_hw *ah,unsigned int mode,int offset) +{ +struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; +struct ath5k_chan_pcal_info *pcal; +int i; - offset =AR5K_EEPROM_MODES_11A (ah->ah_ee_version); +switch (mode) { +case AR5K_EEPROM_MODE_11B : + pcal = ee->ee_pwr_cal_b; +break ; +case AR5K_EEPROM_MODE_11G : + pcal = ee->ee_pwr_cal_g; +break ; +default : +return -EINVAL ; + } - ret =ath5k_eeprom_read_ants (ah, &offset, mode); -if (ret) -return ret; +ath5k_eeprom_read_freq_list (ah, &offset, +AR5K_EEPROM_N_2GHZ_CHAN_2413 , pcal, + &ee->ee_n_piers[mode]); +for (i =0 ; i <AR5K_EEPROM_N_2GHZ_CHAN_2413 ; i +=1 ) { + pcal[i].freq =ath5k_eeprom_bin2freq (ee, + pcal[i].freq, mode); + } -AR5K_EEPROM_READ (offset++, val); - ee->ee_adc_desired_size[mode] = (s8)((val >>8 ) &0xff ); - ee->ee_ob[mode][3 ] = (val >>5 ) &0x7 ; - ee->ee_db[mode][3 ] = (val >>2 ) &0x7 ; - ee->ee_ob[mode][2 ] = (val <<1 ) &0x7 ; - -AR5K_EEPROM_READ (offset++, val); - ee->ee_ob[mode][2 ] |= (val >>15 ) &0x1 ; - ee->ee_db[mode][2 ] = (val >>12 ) &0x7 ; - ee->ee_ob[mode][1 ] = (val >>9 ) &0x7 ; - ee->ee_db[mode][1 ] = (val >>6 ) &0x7 ; - ee->ee_ob[mode][0 ] = (val >>3 ) &0x7 ; - ee->ee_db[mode][0 ] = val &0x7 ; +return 0 ; +} - ret =ath5k_eeprom_read_modes (ah, &offset, mode); -if (ret) -return ret; -if (ah->ah_ee_version >=AR5K_EEPROM_VERSION_4_1 ) { -AR5K_EEPROM_READ (offset++, val); - ee->ee_margin_tx_rx[mode] = val &0x3f ; +static int +ath5k_eeprom_read_pcal_info_5111 (struct ath5k_hw *ah,int mode) +{ +struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; +struct ath5k_chan_pcal_info *pcal; +int offset, ret; +int i, j; +u16 val; + + offset =AR5K_EEPROM_GROUPS_START (ee->ee_version); +switch (mode) { +case AR5K_EEPROM_MODE_11A : +if (!AR5K_EEPROM_HDR_11A (ee->ee_header)) +return 0 ; + + ret =ath5k_eeprom_init_11a_pcal_freq (ah, + offset +AR5K_EEPROM_GROUP1_OFFSET ); +if (ret <0 ) +return ret; + + offset +=AR5K_EEPROM_GROUP2_OFFSET ; + pcal = ee->ee_pwr_cal_a; +break ; +case AR5K_EEPROM_MODE_11B : +if (!AR5K_EEPROM_HDR_11B (ee->ee_header) && + !AR5K_EEPROM_HDR_11G (ee->ee_header)) +return 0 ; + + pcal = ee->ee_pwr_cal_b; + offset +=AR5K_EEPROM_GROUP3_OFFSET ; + +/* fixed piers */ + pcal[0 ].freq =2412 ; + pcal[1 ].freq =2447 ; + pcal[2 ].freq =2484 ; + ee->ee_n_piers[mode] =3 ; +break ; +case AR5K_EEPROM_MODE_11G : +if (!AR5K_EEPROM_HDR_11G (ee->ee_header)) +return 0 ; + + pcal = ee->ee_pwr_cal_g; + offset +=AR5K_EEPROM_GROUP4_OFFSET ; + +/* fixed piers */ + pcal[0 ].freq =2312 ; + pcal[1 ].freq =2412 ; + pcal[2 ].freq =2484 ; + ee->ee_n_piers[mode] =3 ; +break ; +default : +return -EINVAL ; } -/* -* Get values for 802.11b (2.4GHz) -*/ - mode =AR5K_EEPROM_MODE_11B ; - offset =AR5K_EEPROM_MODES_11B (ah->ah_ee_version); +for (i =0 ; i < ee->ee_n_piers[mode]; i++) { +struct ath5k_chan_pcal_info_rf5111 *cdata = + &pcal[i].rf5111_info; - ret =ath5k_eeprom_read_ants (ah, &offset, mode); -if (ret) -return ret; +AR5K_EEPROM_READ (offset++, val); + cdata->pcdac_max = ((val >>10 ) &AR5K_EEPROM_PCDAC_M ); + cdata->pcdac_min = ((val >>4 ) &AR5K_EEPROM_PCDAC_M ); + cdata->pwr[0 ] = ((val <<2 ) &AR5K_EEPROM_POWER_M ); -AR5K_EEPROM_READ (offset++, val); - ee->ee_adc_desired_size[mode] = (s8)((val >>8 ) &0xff ); - ee->ee_ob[mode][1 ] = (val >>4 ) &0x7 ; - ee->ee_db[mode][1 ] = val &0x7 ; +AR5K_EEPROM_READ (offset++, val); + cdata->pwr[0 ] |= ((val >>14 ) &0x3 ); + cdata->pwr[1 ] = ((val >>8 ) &AR5K_EEPROM_POWER_M ); + cdata->pwr[2 ] = ((val >>2 ) &AR5K_EEPROM_POWER_M ); + cdata->pwr[3 ] = ((val <<4 ) &AR5K_EEPROM_POWER_M ); - ret =ath5k_eeprom_read_modes (ah, &offset, mode); -if (ret) -return ret; +AR5K_EEPROM_READ (offset++, val); + cdata->pwr[3 ] |= ((val >>12 ) &0xf ); + cdata->pwr[4 ] = ((val >>6 ) &AR5K_EEPROM_POWER_M ); + cdata->pwr[5 ] = (val &AR5K_EEPROM_POWER_M ); -if (ah->ah_ee_version >=AR5K_EEPROM_VERSION_4_0 ) {AR5K_EEPROM_READ (offset++, val); - ee->ee_cal_pier[mode][0 ] = -ath5k_eeprom_bin2freq (ah, val &0xff , mode); - ee->ee_cal_pier[mode][1 ] = -ath5k_eeprom_bin2freq (ah, (val >>8 ) &0xff , mode); + cdata->pwr[6 ] = ((val >>10 ) &AR5K_EEPROM_POWER_M ); + cdata->pwr[7 ] = ((val >>4 ) &AR5K_EEPROM_POWER_M ); + cdata->pwr[8 ] = ((val <<2 ) &AR5K_EEPROM_POWER_M );AR5K_EEPROM_READ (offset++, val); - ee->ee_cal_pier[mode][2 ] = -ath5k_eeprom_bin2freq (ah, val &0xff , mode); + cdata->pwr[8 ] |= ((val >>14 ) &0x3 ); + cdata->pwr[9 ] = ((val >>8 ) &AR5K_EEPROM_POWER_M ); + cdata->pwr[10 ] = ((val >>2 ) &AR5K_EEPROM_POWER_M ); + +ath5k_get_pcdac_intercepts (ah, cdata->pcdac_min, + cdata->pcdac_max, cdata->pcdac); + +for (j =0 ; j <AR5K_EEPROM_N_PCDAC ; j++) { + cdata->pwr[j] = (u16) + (AR5K_EEPROM_POWER_STEP * cdata->pwr[j]); + } } -if (ah->ah_ee_version >=AR5K_EEPROM_VERSION_4_1 ) - ee->ee_margin_tx_rx[mode] = (val >>8 ) &0x3f ; +return 0 ; +} -/* -* Get values for 802.11g (2.4GHz) -*/ - mode =AR5K_EEPROM_MODE_11G ; - offset =AR5K_EEPROM_MODES_11G (ah->ah_ee_version); +static int +ath5k_eeprom_read_pcal_info_5112 (struct ath5k_hw *ah,int mode) +{ +struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; +struct ath5k_chan_pcal_info_rf5112 *chan_pcal_info; +struct ath5k_chan_pcal_info *gen_chan_info; +u32 offset; +unsigned int i, c; +u16 val; +int ret; - ret =ath5k_eeprom_read_ants (ah, &offset, mode); -if (ret) -return ret; +switch (mode) { +case AR5K_EEPROM_MODE_11A : +/* +* Read 5GHz EEPROM channels +*/ + offset =AR5K_EEPROM_GROUPS_START (ee->ee_version); +ath5k_eeprom_init_11a_pcal_freq (ah, offset); + + offset +=AR5K_EEPROM_GROUP2_OFFSET ; + gen_chan_info = ee->ee_pwr_cal_a; +break ; +case AR5K_EEPROM_MODE_11B : + offset =AR5K_EEPROM_GROUPS_START (ee->ee_version); +if (AR5K_EEPROM_HDR_11A (ee->ee_header)) + offset +=AR5K_EEPROM_GROUP3_OFFSET ; + +/* NB: frequency piers parsed during mode init */ + gen_chan_info = ee->ee_pwr_cal_b; +break ; +case AR5K_EEPROM_MODE_11G : + offset =AR5K_EEPROM_GROUPS_START (ee->ee_version); +if (AR5K_EEPROM_HDR_11A (ee->ee_header)) + offset +=AR5K_EEPROM_GROUP4_OFFSET ; +else if (AR5K_EEPROM_HDR_11B (ee->ee_header)) + offset +=AR5K_EEPROM_GROUP2_OFFSET ; + +/* NB: frequency piers parsed during mode init */ + gen_chan_info = ee->ee_pwr_cal_g; +break ; +default : +return -EINVAL ; + } -AR5K_EEPROM_READ (offset++, val); - ee->ee_adc_desired_size[mode] = (s8)((val >>8 ) &0xff ); - ee->ee_ob[mode][1 ] = (val >>4 ) &0x7 ; - ee->ee_db[mode][1 ] = val &0x7 ; +for (i =0 ; i < ee->ee_n_piers[mode]; i++) { + chan_pcal_info = &gen_chan_info[i].rf5112_info; - ret =ath5k_eeprom_read_modes (ah, &offset, mode); -if (ret) -return ret; +/* Power values in dBm * 4 +* for the lower xpd gain curve +* (0 dBm -> higher output power) */ +for (c =0 ; c <AR5K_EEPROM_N_XPD0_POINTS ; c++) { +AR5K_EEPROM_READ (offset++, val); + chan_pcal_info->pwr_x0[c] = (val &0xff ); + chan_pcal_info->pwr_x0[++c] = ((val >>8 ) &0xff ); + } -if (ah->ah_ee_version >=AR5K_EEPROM_VERSION_4_0 ) { +/* PCDAC steps +* corresponding to the above power +* measurements */ +AR5K_EEPROM_READ (offset++, val); + chan_pcal_info->pcdac_x0[1 ] = (val &0x1f ); + chan_pcal_info->pcdac_x0[2 ] = ((val >>5 ) &0x1f ); + chan_pcal_info->pcdac_x0[3 ] = ((val >>10 ) &0x1f ); + +/* Power values in dBm * 4 +* for the higher xpd gain curve +* (18 dBm -> lower output power) */ AR5K_EEPROM_READ (offset++, val); - ee->ee_cal_pier[mode][0 ] = -ath5k_eeprom_bin2freq (ah, val &0xff , mode); - ee->ee_cal_pier[mode][1 ] = -ath5k_eeprom_bin2freq (ah, (val >>8 ) &0xff , mode); + chan_pcal_info->pwr_x3[0 ] = (val &0xff ); + chan_pcal_info->pwr_x3[1 ] = ((val >>8 ) &0xff );AR5K_EEPROM_READ (offset++, val); - ee->ee_turbo_max_power[mode] = val &0x7f ; - ee->ee_xr_power[mode] = (val >>7 ) &0x3f ; + chan_pcal_info->pwr_x3[2 ] = (val &0xff ); + +/* PCDAC steps +* corresponding to the above power +* measurements (static) */ + chan_pcal_info->pcdac_x3[0 ] =20 ; + chan_pcal_info->pcdac_x3[1 ] =35 ; + chan_pcal_info->pcdac_x3[2 ] =63 ; + +if (ee->ee_version >=AR5K_EEPROM_VERSION_4_3 ) { + chan_pcal_info->pcdac_x0[0 ] = ((val >>8 ) &0xff ); + +/* Last xpd0 power level is also channel maximum */ + gen_chan_info[i].max_pwr = chan_pcal_info->pwr_x0[3 ]; + }else { + chan_pcal_info->pcdac_x0[0 ] =1 ; + gen_chan_info[i].max_pwr = ((val >>8 ) &0xff ); + } + +/* Recreate pcdac_x0 table for this channel using pcdac steps */ + chan_pcal_info->pcdac_x0[1 ] += chan_pcal_info->pcdac_x0[0 ]; + chan_pcal_info->pcdac_x0[2 ] += chan_pcal_info->pcdac_x0[1 ]; + chan_pcal_info->pcdac_x0[3 ] += chan_pcal_info->pcdac_x0[2 ]; + } + +return 0 ; +} + +static inline unsigned int +ath5k_pdgains_size_2413 (struct ath5k_eeprom_info *ee,unsigned int mode) +{ +static const unsigned int pdgains_size[] = {4 ,6 ,9 ,12 }; +unsigned int sz; + + sz = pdgains_size[ee->ee_pd_gains[mode] -1 ]; + sz *= ee->ee_n_piers[mode]; + +return sz; +} +static unsigned int +ath5k_cal_data_offset_2413 (struct ath5k_eeprom_info *ee,int mode) +{ +u32 offset =AR5K_EEPROM_CAL_DATA_START (ee->ee_misc4); + +switch (mode) { +case AR5K_EEPROM_MODE_11G : +if (AR5K_EEPROM_HDR_11B (ee->ee_header)) + offset +=ath5k_pdgains_size_2413 (ee,AR5K_EEPROM_MODE_11B ) +2 ; +/* fall through */ +case AR5K_EEPROM_MODE_11B : +if (AR5K_EEPROM_HDR_11A (ee->ee_header)) + offset +=ath5k_pdgains_size_2413 (ee,AR5K_EEPROM_MODE_11A ) +5 ; +/* fall through */ +case AR5K_EEPROM_MODE_11A : +break ; +default : +break ; + } + +return offset; +} + +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_rf2413 *chan_pcal_info; +struct ath5k_chan_pcal_info *gen_chan_info; +unsigned int i, c; +u32 offset; +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; + + 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 ; + 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 ; + } + +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; + +/* +* Read pwr_i, pddac_i and the first +* 2 pd points (pwr, pddac) +*/ AR5K_EEPROM_READ (offset++, val); - ee->ee_cal_pier[mode][2 ] = -ath5k_eeprom_bin2freq (ah, val &0xff , mode); + 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 ; -if (ah->ah_ee_version >=AR5K_EEPROM_VERSION_4_1 ) - ee->ee_margin_tx_rx[mode] = (val >>8 ) &0x3f ; +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 ;AR5K_EEPROM_READ (offset++, val); - ee->ee_i_cal[mode] = (val >>8 ) &0x3f ; - ee->ee_q_cal[mode] = (val >>3 ) &0x1f ; + chan_pcal_info->pwr[0 ][2 ] = val &0xf ; + chan_pcal_info->pddac[0 ][2 ] = + (val >>4 ) &0x3f ; + + chan_pcal_info->pwr[0 ][3 ] =0 ; + chan_pcal_info->pddac[0 ][3 ] =0 ; + +if (pd_gains >1 ) { +/* +* Pd gain 0 is not the last pd gain +* so it only has 2 pd points. +* Continue wih pd gain 1. +*/ + chan_pcal_info->pwr_i[1 ] = (val >>10 ) &0x1f ; -if (ah->ah_ee_version >=AR5K_EEPROM_VERSION_4_2 ) { + chan_pcal_info->pddac_i[1 ] = (val >>15 ) &0x1 ;AR5K_EEPROM_READ (offset++, val); - ee->ee_cck_ofdm_gain_delta = val &0xff ; + chan_pcal_info->pddac_i[1 ] |= (val &0x3F ) <<1 ; + + chan_pcal_info->pwr[1 ][0 ] = (val >>6 ) &0xf ; + chan_pcal_info->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 ; + + chan_pcal_info->pddac[1 ][2 ] = + (val >>14 ) &0x3 ; +AR5K_EEPROM_READ (offset++, val); + chan_pcal_info->pddac[1 ][2 ] |= + (val &0xF ) <<2 ; + + chan_pcal_info->pwr[1 ][3 ] =0 ; + chan_pcal_info->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 ; + + chan_pcal_info->pddac[0 ][3 ] = + (val >>14 ) &0x3 ; +AR5K_EEPROM_READ (offset++, val); + chan_pcal_info->pddac[0 ][3 ] |= + (val &0xF ) <<2 ; + } + +/* +* Proceed with the other pd_gains +* as above. +*/ +if (pd_gains >2 ) { + chan_pcal_info->pwr_i[2 ] = (val >>4 ) &0x1f ; + chan_pcal_info->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 ; + + chan_pcal_info->pwr[2 ][3 ] =0 ; + chan_pcal_info->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 ; + } + +if (pd_gains >3 ) { + chan_pcal_info->pwr_i[3 ] = (val >>14 ) &0x3 ; +AR5K_EEPROM_READ (offset++, val); + chan_pcal_info->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 ; + +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 ; + + chan_pcal_info->pwr[3 ][2 ] = + (val >>14 ) &0x3 ; +AR5K_EEPROM_READ (offset++, val); + chan_pcal_info->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 ; + + chan_pcal_info->pddac[3 ][3 ] = + (val >>12 ) &0xF ; +AR5K_EEPROM_READ (offset++, val); + chan_pcal_info->pddac[3 ][3 ] |= + ((val >>0 ) &0x3 ) <<4 ; + }else if (pd_gains ==3 ) { + chan_pcal_info->pwr[2 ][3 ] = + (val >>14 ) &0x3 ; +AR5K_EEPROM_READ (offset++, val); + chan_pcal_info->pwr[2 ][3 ] |= + ((val >>0 ) &0x3 ) <<2 ; + + chan_pcal_info->pddac[2 ][3 ] = + (val >>2 ) &0x3f ; + } + +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 ; } } -/* -* Read 5GHz EEPROM channels -*/ +return 0 ; +} + +/* +* Read per rate target power (this is the maximum tx power +* supported by the card). This info is used when setting +* tx power, no matter the channel. +* +* This also works for v5 EEPROMs. +*/ +static int ath5k_eeprom_read_target_rate_pwr_info (struct ath5k_hw *ah,unsigned int mode) +{ +struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; +struct ath5k_rate_pcal_info *rate_pcal_info; +u16 *rate_target_pwr_num; +u32 offset; +u16 val; +int ret, i; + + offset =AR5K_EEPROM_TARGET_PWRSTART (ee->ee_misc1); + rate_target_pwr_num = &ee->ee_rate_target_pwr_num[mode]; +switch (mode) { +case AR5K_EEPROM_MODE_11A : + offset +=AR5K_EEPROM_TARGET_PWR_OFF_11A (ee->ee_version); + rate_pcal_info = ee->ee_rate_tpwr_a; + ee->ee_rate_target_pwr_num[mode] =AR5K_EEPROM_N_5GHZ_CHAN ; +break ; +case AR5K_EEPROM_MODE_11B : + offset +=AR5K_EEPROM_TARGET_PWR_OFF_11B (ee->ee_version); + rate_pcal_info = ee->ee_rate_tpwr_b; + ee->ee_rate_target_pwr_num[mode] =2 ;/* 3rd is g mode's 1st */ +break ; +case AR5K_EEPROM_MODE_11G : + offset +=AR5K_EEPROM_TARGET_PWR_OFF_11G (ee->ee_version); + rate_pcal_info = ee->ee_rate_tpwr_g; + ee->ee_rate_target_pwr_num[mode] =AR5K_EEPROM_N_2GHZ_CHAN ; +break ; +default : +return -EINVAL ; + } + +/* Different freq mask for older eeproms (<= v3.2) */ +if (ee->ee_version <=AR5K_EEPROM_VERSION_3_2 ) { +for (i =0 ; i < (*rate_target_pwr_num); i++) { +AR5K_EEPROM_READ (offset++, val); + rate_pcal_info[i].freq = +ath5k_eeprom_bin2freq (ee, (val >>9 ) &0x7f , mode); + + rate_pcal_info[i].target_power_6to24 = ((val >>3 ) &0x3f ); + rate_pcal_info[i].target_power_36 = (val <<3 ) &0x3f ; + +AR5K_EEPROM_READ (offset++, val); + +if (rate_pcal_info[i].freq ==AR5K_EEPROM_CHANNEL_DIS || + val ==0 ) { + (*rate_target_pwr_num) = i; +break ; + } + + rate_pcal_info[i].target_power_36 |= ((val >>13 ) &0x7 ); + rate_pcal_info[i].target_power_48 = ((val >>7 ) &0x3f ); + rate_pcal_info[i].target_power_54 = ((val >>1 ) &0x3f ); + } + }else { +for (i =0 ; i < (*rate_target_pwr_num); i++) { +AR5K_EEPROM_READ (offset++, val); + rate_pcal_info[i].freq = +ath5k_eeprom_bin2freq (ee, (val >>8 ) &0xff , mode); + + rate_pcal_info[i].target_power_6to24 = ((val >>2 ) &0x3f ); + rate_pcal_info[i].target_power_36 = (val <<4 ) &0x3f ; + +AR5K_EEPROM_READ (offset++, val); + +if (rate_pcal_info[i].freq ==AR5K_EEPROM_CHANNEL_DIS || + val ==0 ) { + (*rate_target_pwr_num) = i; +break ; + } + + rate_pcal_info[i].target_power_36 |= (val >>12 ) &0xf ; + rate_pcal_info[i].target_power_48 = ((val >>6 ) &0x3f ); + rate_pcal_info[i].target_power_54 = (val &0x3f ); + } + } + +return 0 ; +} + +static int +ath5k_eeprom_read_pcal_info (struct ath5k_hw *ah) +{ +struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; +int (*read_pcal)(struct ath5k_hw *hw,int mode); +int mode; +int err; + +if ((ah->ah_ee_version >=AR5K_EEPROM_VERSION_4_0 ) && + (AR5K_EEPROM_EEMAP (ee->ee_misc0) ==1 )) + read_pcal = ath5k_eeprom_read_pcal_info_5112; +else if ((ah->ah_ee_version >=AR5K_EEPROM_VERSION_5_0 ) && + (AR5K_EEPROM_EEMAP (ee->ee_misc0) ==2 )) + read_pcal = ath5k_eeprom_read_pcal_info_2413; +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) +return err; + + err =ath5k_eeprom_read_target_rate_pwr_info (ah, mode); +if (err <0 ) +return err; + } + +return 0 ; +} + +/* Read conformance test limits */ +static int +ath5k_eeprom_read_ctl_info (struct ath5k_hw *ah) +{ +struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; +struct ath5k_edge_power *rep; +unsigned int fmask, pmask; +unsigned int ctl_mode; +int ret, i, j; +u32 offset; +u16 val; + + pmask =AR5K_EEPROM_POWER_M ; + fmask =AR5K_EEPROM_FREQ_M (ee->ee_version); + offset =AR5K_EEPROM_CTL (ee->ee_version); + ee->ee_ctls =AR5K_EEPROM_N_CTLS (ee->ee_version); +for (i =0 ; i < ee->ee_ctls; i +=2 ) { +AR5K_EEPROM_READ (offset++, val); + ee->ee_ctl[i] = (val >>8 ) &0xff ; + ee->ee_ctl[i +1 ] = val &0xff ; + } + + offset =AR5K_EEPROM_GROUP8_OFFSET ; +if (ee->ee_version >=AR5K_EEPROM_VERSION_4_0 ) + offset +=AR5K_EEPROM_TARGET_PWRSTART (ee->ee_misc1) - +AR5K_EEPROM_GROUP5_OFFSET ; +else + offset +=AR5K_EEPROM_GROUPS_START (ee->ee_version); + + rep = ee->ee_ctl_pwr; +for (i =0 ; i < ee->ee_ctls; i++) { +switch (ee->ee_ctl[i] &AR5K_CTL_MODE_M ) { +case AR5K_CTL_11A : +case AR5K_CTL_TURBO : + ctl_mode =AR5K_EEPROM_MODE_11A ; +break ; +default : + ctl_mode =AR5K_EEPROM_MODE_11G ; +break ; + } +if (ee->ee_ctl[i] ==0 ) { +if (ee->ee_version >=AR5K_EEPROM_VERSION_3_3 ) + offset +=8 ; +else + offset +=7 ; + rep +=AR5K_EEPROM_N_EDGES ; +continue ; + } +if (ee->ee_version >=AR5K_EEPROM_VERSION_3_3 ) { +for (j =0 ; j <AR5K_EEPROM_N_EDGES ; j +=2 ) { +AR5K_EEPROM_READ (offset++, val); + rep[j].freq = (val >>8 ) & fmask; + rep[j +1 ].freq = val & fmask; + } +for (j =0 ; j <AR5K_EEPROM_N_EDGES ; j +=2 ) { +AR5K_EEPROM_READ (offset++, val); + rep[j].edge = (val >>8 ) & pmask; + rep[j].flag = (val >>14 ) &1 ; + rep[j +1 ].edge = val & pmask; + rep[j +1 ].flag = (val >>6 ) &1 ; + } + }else { +AR5K_EEPROM_READ (offset++, val); + rep[0 ].freq = (val >>9 ) & fmask; + rep[1 ].freq = (val >>2 ) & fmask; + rep[2 ].freq = (val <<5 ) & fmask; + +AR5K_EEPROM_READ (offset++, val); + rep[2 ].freq |= (val >>11 ) &0x1f ; + rep[3 ].freq = (val >>4 ) & fmask; + rep[4 ].freq = (val <<3 ) & fmask; + +AR5K_EEPROM_READ (offset++, val); + rep[4 ].freq |= (val >>13 ) &0x7 ; + rep[5 ].freq = (val >>6 ) & fmask; + rep[6 ].freq = (val <<1 ) & fmask; + +AR5K_EEPROM_READ (offset++, val); + rep[6 ].freq |= (val >>15 ) &0x1 ; + rep[7 ].freq = (val >>8 ) & fmask; + + rep[0 ].edge = (val >>2 ) & pmask; + rep[1 ].edge = (val <<4 ) & pmask; + +AR5K_EEPROM_READ (offset++, val); + rep[1 ].edge |= (val >>12 ) &0xf ; + rep[2 ].edge = (val >>6 ) & pmask; + rep[3 ].edge = val & pmask; + +AR5K_EEPROM_READ (offset++, val); + rep[4 ].edge = (val >>10 ) & pmask; + rep[5 ].edge = (val >>4 ) & pmask; + rep[6 ].edge = (val <<2 ) & pmask; + +AR5K_EEPROM_READ (offset++, val); + rep[6 ].edge |= (val >>14 ) &0x3 ; + rep[7 ].edge = (val >>8 ) & pmask; + } +for (j =0 ; j <AR5K_EEPROM_N_EDGES ; j++) { + rep[j].freq =ath5k_eeprom_bin2freq (ee, + rep[j].freq, ctl_mode); + } + rep +=AR5K_EEPROM_N_EDGES ; + }return 0 ; } + +/* +* Initialize eeprom power tables +*/ +int +ath5k_eeprom_init (struct ath5k_hw *ah) +{ +int err; + + err =ath5k_eeprom_init_header (ah); +if (err <0 ) +return err; + + err =ath5k_eeprom_init_modes (ah); +if (err <0 ) +return err; + + err =ath5k_eeprom_read_pcal_info (ah); +if (err <0 ) +return err; + + err =ath5k_eeprom_read_ctl_info (ah); +if (err <0 ) +return err; + +return 0 ; +}/* * Read the MAC address from eeprom */
drivers/net/wireless/ath5k/ath5k.h +0 -7
@@ -821,13 +821,6 @@ struct ath5k_athchan_2ghz {return (false); \ }while (0 ) -enum ath5k_ant_setting { -AR5K_ANT_VARIABLE =0 ,/* variable by programming */ -AR5K_ANT_FIXED_A =1 ,/* fixed to 11a frequencies */ -AR5K_ANT_FIXED_B =2 ,/* fixed to 11b frequencies */ - AR5K_ANT_MAX = 3, -}; -/* * Hardware interrupt abstraction */
drivers/net/wireless/ath5k/eeprom.h +216 -37
343 lines not on this page · raw message
drivers/net/wireless/ath5k/reset.c +1 -1
@@ -674,7 +674,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, (ee->ee_switch_settling[ee_mode] <<7 ) &0x3f80 , 0xffffc07f);AR5K_REG_MASKED_BITS (ah,AR5K_PHY_GAIN , - (ee->ee_ant_tx_rx[ee_mode] <<12 ) &0x3f000 , + (ee->ee_atn_tx_rx[ee_mode] <<12 ) &0x3f000 ,0xfffc0fff ); AR5K_REG_MASKED_BITS(ah, AR5K_PHY_DESIRED_SIZE, (ee->ee_adc_desired_size[ee_mode] & 0x00ff) |
drivers/net/wireless/ath5k/eeprom.c static u16 ath5k_eeprom_bin2freq(struct · line 139
Quoted 4 lines · Felix Fietkau
drivers/net/wireless/ath5k/eeprom.c +4
-0+ +if (ah->ah_ee_version >=AR5K_EEPROM_VERSION_4_0 ) { +AR5K_EEPROM_READ_HDR (AR5K_EEPROM_MISC0 , ee_misc0); +AR5K_EEPROM_READ_HDR (AR5K_EEPROM_MISC1 , ee_misc1);
Can we add the rest here?
+ AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC2, ee_misc2);
+ AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC3, ee_misc3);
+ AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC4, ee_misc4);
+ AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC5, ee_misc5);
I'm adding CCMP support and it wants to use AR5K_EEPROM_AES_DIS(ee_misc5).
Signature · 1 line
Bob Copeland %% www.bobcopeland.com
2008/11/21 Bob Copeland <[email protected]>:
Quoted 13 lines · Felix Fietkau
drivers/net/wireless/ath5k/eeprom.c static u16 ath5k_eeprom_bin2freq(struct · line 139
Quoted 4 lines
drivers/net/wireless/ath5k/eeprom.c +4
-0+ +if (ah->ah_ee_version >=AR5K_EEPROM_VERSION_4_0 ) { +AR5K_EEPROM_READ_HDR (AR5K_EEPROM_MISC0 , ee_misc0); +AR5K_EEPROM_READ_HDR (AR5K_EEPROM_MISC1 , ee_misc1);Can we add the rest here?
(quoted diff) +4
-0+ AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC2, ee_misc2); + AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC3, ee_misc3); + AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC4, ee_misc4); + AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC5, ee_misc5);
Quoted 2 lines
I'm adding CCMP support and it wants to use
AR5K_EEPROM_AES_DIS(ee_misc5).
Problem is that legacy-hal doesn't make use of these infos (along with many other infos stored in eeprom !), so i don't know what eeprom versions have them. Go on and use them but for now assume that they are only available for eeprom versions 5 and above and i'll check out my eeprom dumps etc to find out.
Right now i'm working on a debugfs entry for eeprom stuff to make debuging of this code easier.
Signature · 3 lines
GPG ID: 0xD21DB2DB As you read this post global entropy rises. Have Fun ;-) Nick
Quoted 10 lines · Nick Kossifidis
2008/11/21 Bob Copeland <[email protected]>:
Quoted 3 lines
Can we add the rest here?
+
AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC2, ee_misc2);Problem is that legacy-hal doesn't make use of these infos (along with many other infos stored in eeprom !), so i don't know what eeprom versions have them. Go on and use them but for now assume that they are only available for eeprom versions 5 and above and i'll check out my eeprom dumps etc to find out.
Ok, no rush on this - we can add the patch for these later when we know which versions specify misc5.
The legacy-hal uses this bit, but does so by directly reading that offset in attach for some reason. It's the same address as AR5K_EEPROM_MISC5, offset 0xc9. From the HAL:
Quoted 3 lines
HAL_BOOLar5212FillCapabilityInfo(struct ath_hal *ah)
{
[...]
Quoted 11 lines
HAL_CAPABILITIES *pCap = &ahpriv->ah_caps;
u_int16_t capField;
u_int16_t regcap;
/* Read the capability EEPROM location */
capField = 0;
if (ahp->ah_eeversion >= AR_EEPROM_VER5_1 &&
!ath_hal_eepromRead(ah, AR_EEPROM_CAPABILITIES_OFFSET, &capField)) {
HDPRINTF(ah, HAL_DBG_EEPROM, "%s: unable to read caps from eeprom\n", __func__);
return AH_FALSE;
}Ok, so it only works for eeprom 5.1 and better...
[...]
Quoted 5 lines
pCap->halCipherAesCcmSupport = (!(capField & AR_EEPROM_EEPCAP_AES_DIS) && ((AH_PRIVATE(ah)->ah_macVersion > AR_SREV_VERSION_VENICE) || ((AH_PRIVATE(ah)->ah_macVersion == AR_SREV_VERSION_VENICE) && (AH_PRIVATE(ah)->ah_macRev >= AR_SREV_VERSION_OAHU))));
Signature · 1 line
Bob Copeland %% www.bobcopeland.com