--- a/tools/ath_info.c +++ b/tools/ath_info.c @@ -16,78 +16,8 @@ * along with this program. If not, see . */ -/* So here is how it works: - * - * First compile... - * - * gcc ath_info.c -o ath_info - * - * then find card's physical address - * - * lspci -v - * - * 02:02.0 Ethernet controller: Atheros Communications, Inc. AR5212 802.11abg NIC (rev 01) - * Subsystem: Fujitsu Limited. Unknown device 1234 - * Flags: bus master, medium devsel, latency 168, IRQ 23 - * Memory at c2000000 (32-bit, non-prefetchable) [size=64K] - * Capabilities: [44] Power Management version 2 - * - * address here is 0xc2000000 - * - * load madwifi-ng or madwifi-old if not already loaded (be sure the - * interface is down!) - * - * modprobe ath_pci - * - * OR - * - * call: - * setpci -s 02:02.0 command=0x41f cache_line_size=0x10 - * - * to enable access to the PCI device. - * - * and we run the thing... - * - * ./ath_info 0xc2000000 - * - * In order to change the regdomain to 0, call: - * - * ./ath_info -w 0xc2000000 regdomain 0 - * - * to change any PCI ID value, say: - * - * ./ath_info -w 0xc2000000 X - * - * with ::= pci_dev_id | pci_vendor_id | pci_class | - * pci_subsys_dev_id | pci_subsys_vendor_id - * - * With newer chipsets (>= AR5004x, i.e. MAC >= AR5213), Atheros introduced - * write protection on the EEPROM. On a GIGABYTE GN-WI01HT you can set GPIO 4 - * to low to be able to write the EEPROM. This depends highly on the PCB layout, - * so there may be different GPIO used. - * This program currently sets GPIO 4 to low for a MAC >= AR5213, but you can - * override this with the -g option: - * - * ./ath_info -g 5:0 -w 0xc2000000 regdomain X - * - * would set GPIO 5 to low (and wouldn't touch GPIO 4). -g can be given several times. - * - * The write function is currently not tested with 5210 devices. - * - * Use at your own risk, entering a false device address will have really - * nasty results! - * - * Writing wrong values to the PCI id fields may prevent the driver from - * detecting the card! - * - * Transmitting on illegal frequencies may violate state laws. Stick to the local - * regulations! - * - * DISCLAIMER: - * The authors are in no case responsible for damaged hardware or violation of - * local laws by operating modified hardware. - * - */ +/* Try accepting 64-bit device address even with 32-bit userspace */ +#define _FILE_OFFSET_BITS 64 #include #include @@ -130,109 +60,103 @@ fprintf(stderr, "#ERR %s: " fmt "\n", __ */ #define AR5K_GPIODI 0x401c -/* - * Common silicon revision/version values - */ -enum ath5k_srev_type { - AR5K_VERSION_VER, - AR5K_VERSION_REV, - AR5K_VERSION_RAD, -}; - struct ath5k_srev_name { const char *sr_name; - enum ath5k_srev_type sr_type; - u_int sr_val; + u_int8_t sr_val; }; -#define AR5K_SREV_UNKNOWN 0xffff - /* Known MAC revision numbers */ -#define AR5K_SREV_VER_AR5210 0x00 -#define AR5K_SREV_VER_AR5311 0x10 -#define AR5K_SREV_VER_AR5311A 0x20 -#define AR5K_SREV_VER_AR5311B 0x30 -#define AR5K_SREV_VER_AR5211 0x40 -#define AR5K_SREV_VER_AR5212 0x50 -#define AR5K_SREV_VER_AR5213 0x55 -#define AR5K_SREV_VER_AR5213A 0x59 -#define AR5K_SREV_VER_AR2424 0xa0 -#define AR5K_SREV_VER_AR5424 0xa3 -#define AR5K_SREV_VER_AR5413 0xa4 -#define AR5K_SREV_VER_AR5414 0xa5 -#define AR5K_SREV_VER_AR5416 0xc0 -#define AR5K_SREV_VER_AR5418 0xca -#define AR5K_SREV_VER_AR2425 0xe0 - -/* Known PHY revision nymbers */ -#define AR5K_SREV_RAD_5110 0x00 -#define AR5K_SREV_RAD_5111 0x10 -#define AR5K_SREV_RAD_5111A 0x15 -#define AR5K_SREV_RAD_2111 0x20 -#define AR5K_SREV_RAD_5112 0x30 -#define AR5K_SREV_RAD_5112A 0x35 -#define AR5K_SREV_RAD_2112 0x40 -#define AR5K_SREV_RAD_2112A 0x45 -#define AR5K_SREV_RAD_SC1 0x63 /* Found on 5413/5414 */ -#define AR5K_SREV_RAD_SC2 0xa2 /* Found on 2424/5424 */ -#define AR5K_SREV_RAD_5133 0xc0 /* MIMO found on 5418 */ - -static const struct ath5k_srev_name ath5k_srev_names[] = { - {"5210", AR5K_VERSION_VER, AR5K_SREV_VER_AR5210}, - {"5311", AR5K_VERSION_VER, AR5K_SREV_VER_AR5311}, - {"5311A", AR5K_VERSION_VER, AR5K_SREV_VER_AR5311A}, - {"5311B", AR5K_VERSION_VER, AR5K_SREV_VER_AR5311B}, - {"5211", AR5K_VERSION_VER, AR5K_SREV_VER_AR5211}, - {"5212", AR5K_VERSION_VER, AR5K_SREV_VER_AR5212}, - {"5213", AR5K_VERSION_VER, AR5K_SREV_VER_AR5213}, - {"5213A", AR5K_VERSION_VER, AR5K_SREV_VER_AR5213A}, - {"2424", AR5K_VERSION_VER, AR5K_SREV_VER_AR2424}, - {"5424", AR5K_VERSION_VER, AR5K_SREV_VER_AR5424}, - {"5413", AR5K_VERSION_VER, AR5K_SREV_VER_AR5413}, - {"5414", AR5K_VERSION_VER, AR5K_SREV_VER_AR5414}, - {"5416", AR5K_VERSION_VER, AR5K_SREV_VER_AR5416}, - {"5418", AR5K_VERSION_VER, AR5K_SREV_VER_AR5418}, - {"2425", AR5K_VERSION_VER, AR5K_SREV_VER_AR2425}, - {"xxxxx", AR5K_VERSION_VER, AR5K_SREV_UNKNOWN}, - {"5110", AR5K_VERSION_RAD, AR5K_SREV_RAD_5110}, - {"5111", AR5K_VERSION_RAD, AR5K_SREV_RAD_5111}, - {"2111", AR5K_VERSION_RAD, AR5K_SREV_RAD_2111}, - {"5112", AR5K_VERSION_RAD, AR5K_SREV_RAD_5112}, - {"5112a", AR5K_VERSION_RAD, AR5K_SREV_RAD_5112A}, - {"2112", AR5K_VERSION_RAD, AR5K_SREV_RAD_2112}, - {"2112a", AR5K_VERSION_RAD, AR5K_SREV_RAD_2112A}, - {"SChip", AR5K_VERSION_RAD, AR5K_SREV_RAD_SC1}, - {"SChip", AR5K_VERSION_RAD, AR5K_SREV_RAD_SC2}, - {"5133", AR5K_VERSION_RAD, AR5K_SREV_RAD_5133}, - {"xxxxx", AR5K_VERSION_RAD, AR5K_SREV_UNKNOWN}, +#define AR5K_SREV_MAC_AR5210 0x00 +#define AR5K_SREV_MAC_AR5311 0x10 +#define AR5K_SREV_MAC_AR5311A 0x20 +#define AR5K_SREV_MAC_AR5311B 0x30 +#define AR5K_SREV_MAC_AR5211 0x40 +#define AR5K_SREV_MAC_AR5212 0x50 +#define AR5K_SREV_MAC_AR5213 0x55 +#define AR5K_SREV_MAC_AR5213A 0x59 +#define AR5K_SREV_MAC_AR5513 0x61 +#define AR5K_SREV_MAC_AR2413 0x78 +#define AR5K_SREV_MAC_AR2414 0x79 +#define AR5K_SREV_MAC_AR2424 0xa0 +#define AR5K_SREV_MAC_AR5424 0xa3 +#define AR5K_SREV_MAC_AR5413 0xa4 +#define AR5K_SREV_MAC_AR5414 0xa5 +#define AR5K_SREV_MAC_AR5416 0xc0 +#define AR5K_SREV_MAC_AR5418 0xca +#define AR5K_SREV_MAC_AR2425 0xe2 + +/* Known PHY revision numbers */ +#define AR5K_SREV_PHY_5110 0x00 +#define AR5K_SREV_PHY_5111 0x10 +#define AR5K_SREV_PHY_5111A 0x15 +#define AR5K_SREV_PHY_2111 0x20 +#define AR5K_SREV_PHY_5112 0x30 +#define AR5K_SREV_PHY_5112A 0x35 +#define AR5K_SREV_PHY_2112 0x40 +#define AR5K_SREV_PHY_2112A 0x45 +#define AR5K_SREV_PHY_SC0 0x56 /* Found on 2413/2414 */ +#define AR5K_SREV_PHY_SC1 0x63 /* Found on 5413/5414 */ +#define AR5K_SREV_PHY_SC2 0xa2 /* Found on 2424/5424 */ +#define AR5K_SREV_PHY_5133 0xc0 /* MIMO found on 5418 */ + +static const struct ath5k_srev_name ath5k_mac_names[] = { + {"5210", AR5K_SREV_MAC_AR5210}, + {"5311", AR5K_SREV_MAC_AR5311}, + {"5311A", AR5K_SREV_MAC_AR5311A}, + {"5311B", AR5K_SREV_MAC_AR5311B}, + {"5211", AR5K_SREV_MAC_AR5211}, + {"5212", AR5K_SREV_MAC_AR5212}, + {"5213", AR5K_SREV_MAC_AR5213}, + {"5213A", AR5K_SREV_MAC_AR5213A}, + {"2413", AR5K_SREV_MAC_AR2413}, + {"2414", AR5K_SREV_MAC_AR2414}, + {"2424", AR5K_SREV_MAC_AR2424}, + {"5424", AR5K_SREV_MAC_AR5424}, + {"5413", AR5K_SREV_MAC_AR5413}, + {"5414", AR5K_SREV_MAC_AR5414}, + {"5416", AR5K_SREV_MAC_AR5416}, + {"5418", AR5K_SREV_MAC_AR5418}, + {"2425", AR5K_SREV_MAC_AR2425}, +}; + +static const struct ath5k_srev_name ath5k_phy_names[] = { + {"5110", AR5K_SREV_PHY_5110}, + {"5111", AR5K_SREV_PHY_5111}, + {"2111", AR5K_SREV_PHY_2111}, + {"5112", AR5K_SREV_PHY_5112}, + {"5112A", AR5K_SREV_PHY_5112A}, + {"2112", AR5K_SREV_PHY_2112}, + {"2112A", AR5K_SREV_PHY_2112A}, + {"SChip", AR5K_SREV_PHY_SC0}, + {"SChip", AR5K_SREV_PHY_SC1}, + {"SChip", AR5K_SREV_PHY_SC2}, + {"5133", AR5K_SREV_PHY_5133}, }; /* * Silicon revision register */ #define AR5K_SREV 0x4020 /* Register Address */ -#define AR5K_SREV_REV 0x0000000f /* Mask for revision */ -#define AR5K_SREV_REV_S 0 -#define AR5K_SREV_VER 0x000000ff /* Mask for version */ -#define AR5K_SREV_VER_S 4 +#define AR5K_SREV_VER 0x000000f0 /* Mask for version */ +#define AR5K_SREV_REV 0x000000ff /* Mask for revision */ /* * PHY chip revision register */ -#define AR5K_PHY_CHIP_ID 0x9818 +#define AR5K_PHY_CHIP_ID 0x9818 /* * PHY register */ -#define AR5K_PHY_BASE 0x9800 -#define AR5K_PHY(_n) (AR5K_PHY_BASE + ((_n) << 2)) +#define AR5K_PHY_BASE 0x9800 +#define AR5K_PHY(_n) (AR5K_PHY_BASE + ((_n) << 2)) #define AR5K_PHY_SHIFT_2GHZ 0x00004007 #define AR5K_PHY_SHIFT_5GHZ 0x00000007 #define AR5K_RESET_CTL 0x4000 /* Register Address */ #define AR5K_RESET_CTL_PCU 0x00000001 /* Protocol Control Unit reset */ #define AR5K_RESET_CTL_DMA 0x00000002 /* DMA (Rx/Tx) reset -5210 only */ -#define AR5K_RESET_CTL_BASEBAND 0x00000002 /* Baseband reset (5211/5212) */ +#define AR5K_RESET_CTL_BASEBAND 0x00000002 /* Baseband reset (5211/5212) */ #define AR5K_RESET_CTL_MAC 0x00000004 /* MAC reset (PCU+Baseband?) -5210 only */ #define AR5K_RESET_CTL_PHY 0x00000008 /* PHY reset -5210 only */ #define AR5K_RESET_CTL_PCI 0x00000010 /* PCI Core reset (interrupts etc) */ @@ -253,7 +177,7 @@ static const struct ath5k_srev_name ath5 #define AR5K_SLEEP_CTL_SLE_UNITS 0x00000008 /* not on 5210 */ #define AR5K_PCICFG 0x4010 /* Register Address */ -#define AR5K_PCICFG_EEAE 0x00000001 /* Eeprom access enable [5210] */ +#define AR5K_PCICFG_EEAE 0x00000001 /* EEPROM access enable [5210] */ #define AR5K_PCICFG_CLKRUNEN 0x00000004 /* CLKRUN enable [5211+] */ #define AR5K_PCICFG_EESIZE 0x00000018 /* Mask for EEPROM size [5211+] */ #define AR5K_PCICFG_EESIZE_S 3 @@ -264,26 +188,118 @@ static const struct ath5k_srev_name ath5 #define AR5K_PCICFG_SPWR_DN 0x00010000 /* Mask for power status (5210) */ -#define AR5K_EEPROM_BASE 0x6000 +#define AR5K_EEPROM_BASE 0x6000 -#define AR5K_EEPROM_MAGIC 0x003d /* Offset for EEPROM Magic number */ +/* + * Common AR5xxx EEPROM data offsets (set these on AR5K_EEPROM_BASE) + */ +#define AR5K_EEPROM_MAGIC 0x003d /* EEPROM Magic number */ #define AR5K_EEPROM_MAGIC_VALUE 0x5aa5 /* Default - found on EEPROM */ #define AR5K_EEPROM_MAGIC_5212 0x0000145c /* 5212 */ #define AR5K_EEPROM_MAGIC_5211 0x0000145b /* 5211 */ #define AR5K_EEPROM_MAGIC_5210 0x0000145a /* 5210 */ +#define AR5K_EEPROM_PROTECT 0x003f /* EEPROM protect status */ +#define AR5K_EEPROM_PROTECT_RD_0_31 0x0001 /* Read protection bit for offsets 0x0 - 0x1f */ +#define AR5K_EEPROM_PROTECT_WR_0_31 0x0002 /* Write protection bit for offsets 0x0 - 0x1f */ +#define AR5K_EEPROM_PROTECT_RD_32_63 0x0004 /* 0x20 - 0x3f */ +#define AR5K_EEPROM_PROTECT_WR_32_63 0x0008 +#define AR5K_EEPROM_PROTECT_RD_64_127 0x0010 /* 0x40 - 0x7f */ +#define AR5K_EEPROM_PROTECT_WR_64_127 0x0020 +#define AR5K_EEPROM_PROTECT_RD_128_191 0x0040 /* 0x80 - 0xbf (regdom) */ +#define AR5K_EEPROM_PROTECT_WR_128_191 0x0080 +#define AR5K_EEPROM_PROTECT_RD_192_207 0x0100 /* 0xc0 - 0xcf */ +#define AR5K_EEPROM_PROTECT_WR_192_207 0x0200 +#define AR5K_EEPROM_PROTECT_RD_208_223 0x0400 /* 0xd0 - 0xdf */ +#define AR5K_EEPROM_PROTECT_WR_208_223 0x0800 +#define AR5K_EEPROM_PROTECT_RD_224_239 0x1000 /* 0xe0 - 0xef */ +#define AR5K_EEPROM_PROTECT_WR_224_239 0x2000 +#define AR5K_EEPROM_PROTECT_RD_240_255 0x4000 /* 0xf0 - 0xff */ +#define AR5K_EEPROM_PROTECT_WR_240_255 0x8000 +#define AR5K_EEPROM_REG_DOMAIN 0x00bf /* EEPROM regdom */ +#define AR5K_EEPROM_INFO_BASE 0x00c0 /* EEPROM header */ +#define AR5K_EEPROM_INFO_MAX (0x400 - AR5K_EEPROM_INFO_BASE) +#define AR5K_EEPROM_INFO_CKSUM 0xffff +#define AR5K_EEPROM_INFO(_n) (AR5K_EEPROM_INFO_BASE + (_n)) + +#define AR5K_EEPROM_VERSION AR5K_EEPROM_INFO(1) /* EEPROM Version */ +#define AR5K_EEPROM_VERSION_3_0 0x3000 /* No idea what's going on before this version */ +#define AR5K_EEPROM_VERSION_3_1 0x3001 /* ob/db values for 2GHz (AR5211_rfregs) */ +#define AR5K_EEPROM_VERSION_3_2 0x3002 /* different frequency representation (eeprom_bin2freq) */ +#define AR5K_EEPROM_VERSION_3_3 0x3003 /* offsets changed, has 32 CTLs (see below) and ee_false_detect (eeprom_read_modes) */ +#define AR5K_EEPROM_VERSION_3_4 0x3004 /* has ee_i_gain ee_cck_ofdm_power_delta (eeprom_read_modes) */ +#define AR5K_EEPROM_VERSION_4_0 0x4000 /* has ee_misc*, ee_cal_pier, ee_turbo_max_power and ee_xr_power (eeprom_init) */ +#define AR5K_EEPROM_VERSION_4_1 0x4001 /* has ee_margin_tx_rx (eeprom_init) */ +#define AR5K_EEPROM_VERSION_4_2 0x4002 /* has ee_cck_ofdm_gain_delta (eeprom_init) */ +#define AR5K_EEPROM_VERSION_4_3 0x4003 +#define AR5K_EEPROM_VERSION_4_4 0x4004 +#define AR5K_EEPROM_VERSION_4_5 0x4005 +#define AR5K_EEPROM_VERSION_4_6 0x4006 /* has ee_scaled_cck_delta */ +#define AR5K_EEPROM_VERSION_4_7 0x3007 + +#define AR5K_EEPROM_MODE_11A 0 +#define AR5K_EEPROM_MODE_11B 1 +#define AR5K_EEPROM_MODE_11G 2 + +#define AR5K_EEPROM_HDR AR5K_EEPROM_INFO(2) /* Header that contains the device caps */ +#define AR5K_EEPROM_HDR_11A(_v) (((_v) >> AR5K_EEPROM_MODE_11A) & 0x1) +#define AR5K_EEPROM_HDR_11B(_v) (((_v) >> AR5K_EEPROM_MODE_11B) & 0x1) +#define AR5K_EEPROM_HDR_11G(_v) (((_v) >> AR5K_EEPROM_MODE_11G) & 0x1) +#define AR5K_EEPROM_HDR_T_2GHZ_DIS(_v) (((_v) >> 3) & 0x1) /* Disable turbo for 2GHz (?) */ +#define AR5K_EEPROM_HDR_T_5GHZ_DBM(_v) (((_v) >> 4) & 0x7f) /* Max turbo power for a/XR mode (eeprom_init) */ +#define AR5K_EEPROM_HDR_DEVICE(_v) (((_v) >> 11) & 0x7) +#define AR5K_EEPROM_HDR_T_5GHZ_DIS(_v) (((_v) >> 15) & 0x1) /* Disable turbo for 5GHz (?) */ +#define AR5K_EEPROM_HDR_RFKILL(_v) (((_v) >> 14) & 0x1) /* Device has RFKill support */ + +/* Misc values available since EEPROM 4.0 */ +#define AR5K_EEPROM_MISC0 AR5K_EEPROM_INFO(4) +#define AR5K_EEPROM_EARSTART(_v) ((_v) & 0xfff) +#define AR5K_EEPROM_HDR_XR2_DIS(_v) (((_v) >> 12) & 0x1) +#define AR5K_EEPROM_HDR_XR5_DIS(_v) (((_v) >> 13) & 0x1) +#define AR5K_EEPROM_EEMAP(_v) (((_v) >> 14) & 0x3) +#define AR5K_EEPROM_MISC1 AR5K_EEPROM_INFO(5) +#define AR5K_EEPROM_TARGET_PWRSTART(_v) ((_v) & 0xfff) +#define AR5K_EEPROM_HAS32KHZCRYSTAL(_v) (((_v) >> 14) & 0x1) + +#define AR5K_EEPROM_RFKILL_GPIO_SEL 0x0000001c +#define AR5K_EEPROM_RFKILL_GPIO_SEL_S 2 +#define AR5K_EEPROM_RFKILL_POLARITY 0x00000002 +#define AR5K_EEPROM_RFKILL_POLARITY_S 1 + +/* Newer EEPROMs are using a different offset */ +#define AR5K_EEPROM_OFF(_v, _v3_0, _v3_3) \ + (((_v) >= AR5K_EEPROM_VERSION_3_3) ? _v3_3 : _v3_0) + +#define AR5K_EEPROM_ANT_GAIN(_v) AR5K_EEPROM_OFF(_v, 0x00c4, 0x00c3) +#define AR5K_EEPROM_ANT_GAIN_5GHZ(_v) ((int8_t)(((_v) >> 8) & 0xff)) +#define AR5K_EEPROM_ANT_GAIN_2GHZ(_v) ((int8_t)((_v) & 0xff)) + +/* calibration settings */ +#define AR5K_EEPROM_MODES_11A(_v) AR5K_EEPROM_OFF(_v, 0x00c5, 0x00d4) +#define AR5K_EEPROM_MODES_11B(_v) AR5K_EEPROM_OFF(_v, 0x00d0, 0x00f2) +#define AR5K_EEPROM_MODES_11G(_v) AR5K_EEPROM_OFF(_v, 0x00da, 0x010d) +#define AR5K_EEPROM_CTL(_v) AR5K_EEPROM_OFF(_v, 0x00e4, 0x0128) /* Conformance test limits */ +#define AR5K_EEPROM_CHANNELS_5GHZ(_v) AR5K_EEPROM_OFF(_v, 0x0100, 0x0150) /* List of calibrated 5GHz chans */ +#define AR5K_EEPROM_TARGET_PWR_OFF_11A(_v) AR5K_EEPROM_OFF(_v, AR5K_EEPROM_CHANNELS_5GHZ(_v) + 0x0055, 0x0000) +#define AR5K_EEPROM_TARGET_PWR_OFF_11B(_v) AR5K_EEPROM_OFF(_v, AR5K_EEPROM_CHANNELS_5GHZ(_v) + 0x0065, 0x0010) +#define AR5K_EEPROM_TARGET_PWR_OFF_11G(_v) AR5K_EEPROM_OFF(_v, AR5K_EEPROM_CHANNELS_5GHZ(_v) + 0x0069, 0x0014) + +/* [3.1 - 3.3] */ +#define AR5K_EEPROM_OBDB0_2GHZ 0x00ec +#define AR5K_EEPROM_OBDB1_2GHZ 0x00ed + /* * EEPROM data register */ #define AR5K_EEPROM_DATA_5211 0x6004 #define AR5K_EEPROM_DATA_5210 0x6800 -#define AR5K_EEPROM_DATA (mac_version == AR5K_SREV_VER_AR5210 ? \ +#define AR5K_EEPROM_DATA (mac_version == AR5K_SREV_MAC_AR5210 ? \ AR5K_EEPROM_DATA_5210 : AR5K_EEPROM_DATA_5211) /* * EEPROM command register */ -#define AR5K_EEPROM_CMD 0x6008 /* Register Addres */ +#define AR5K_EEPROM_CMD 0x6008 /* Register Address */ #define AR5K_EEPROM_CMD_READ 0x00000001 /* EEPROM read */ #define AR5K_EEPROM_CMD_WRITE 0x00000002 /* EEPROM write */ #define AR5K_EEPROM_CMD_RESET 0x00000004 /* EEPROM reset */ @@ -291,43 +307,163 @@ static const struct ath5k_srev_name ath5 /* * EEPROM status register */ -#define AR5K_EEPROM_STAT_5210 0x6c00 /* Register Address [5210] */ -#define AR5K_EEPROM_STAT_5211 0x600c /* Register Address [5211+] */ -#define AR5K_EEPROM_STATUS (mac_version == AR5K_SREV_VER_AR5210 ? \ +#define AR5K_EEPROM_STAT_5210 0x6c00 /* Register Address [5210] */ +#define AR5K_EEPROM_STAT_5211 0x600c /* Register Address [5211+] */ +#define AR5K_EEPROM_STATUS (mac_version == AR5K_SREV_MAC_AR5210 ? \ AR5K_EEPROM_STAT_5210 : AR5K_EEPROM_STAT_5211) #define AR5K_EEPROM_STAT_RDERR 0x00000001 /* EEPROM read failed */ #define AR5K_EEPROM_STAT_RDDONE 0x00000002 /* EEPROM read successful */ #define AR5K_EEPROM_STAT_WRERR 0x00000004 /* EEPROM write failed */ #define AR5K_EEPROM_STAT_WRDONE 0x00000008 /* EEPROM write successful */ -#define AR5K_EEPROM_REG_DOMAIN 0x00bf /* Offset for EEPROM regulatory domain */ -#define AR5K_EEPROM_INFO_BASE 0x00c0 /* Offset for EEPROM header */ -#define AR5K_EEPROM_INFO_MAX (0x400 - AR5K_EEPROM_INFO_BASE) -#define AR5K_EEPROM_INFO_CKSUM 0xffff -#define AR5K_EEPROM_INFO(_n) (AR5K_EEPROM_INFO_BASE + (_n)) -#define AR5K_EEPROM_MODE_11A 0 -#define AR5K_EEPROM_MODE_11B 1 -#define AR5K_EEPROM_MODE_11G 2 +/* + * EEPROM config register (?) + */ +#define AR5K_EEPROM_CFG 0x6010 -#define AR5K_EEPROM_VERSION AR5K_EEPROM_INFO(1) +/* Some EEPROM defines */ +#define AR5K_EEPROM_EEP_SCALE 100 +#define AR5K_EEPROM_EEP_DELTA 10 +#define AR5K_EEPROM_N_MODES 3 +#define AR5K_EEPROM_N_5GHZ_CHAN 10 +#define AR5K_EEPROM_N_2GHZ_CHAN 3 +#define AR5K_EEPROM_MAX_CHAN 10 +#define AR5K_EEPROM_N_PCDAC 11 +#define AR5K_EEPROM_N_TEST_FREQ 8 +#define AR5K_EEPROM_N_EDGES 8 +#define AR5K_EEPROM_N_INTERCEPTS 11 +#define AR5K_EEPROM_FREQ_M(_v) AR5K_EEPROM_OFF(_v, 0x7f, 0xff) +#define AR5K_EEPROM_PCDAC_M 0x3f +#define AR5K_EEPROM_PCDAC_START 1 +#define AR5K_EEPROM_PCDAC_STOP 63 +#define AR5K_EEPROM_PCDAC_STEP 1 +#define AR5K_EEPROM_NON_EDGE_M 0x40 +#define AR5K_EEPROM_CHANNEL_POWER 8 +#define AR5K_EEPROM_N_OBDB 4 +#define AR5K_EEPROM_OBDB_DIS 0xffff +#define AR5K_EEPROM_CHANNEL_DIS 0xff +#define AR5K_EEPROM_SCALE_OC_DELTA(_x) (((_x) * 2) / 10) +#define AR5K_EEPROM_N_CTLS(_v) AR5K_EEPROM_OFF(_v, 16, 32) +#define AR5K_EEPROM_MAX_CTLS 32 +#define AR5K_EEPROM_N_XPD_PER_CHANNEL 4 +#define AR5K_EEPROM_N_XPD0_POINTS 4 +#define AR5K_EEPROM_N_XPD3_POINTS 3 +#define AR5K_EEPROM_N_INTERCEPT_10_2GHZ 35 +#define AR5K_EEPROM_N_INTERCEPT_10_5GHZ 55 +#define AR5K_EEPROM_POWER_M 0x3f +#define AR5K_EEPROM_POWER_MIN 0 +#define AR5K_EEPROM_POWER_MAX 3150 +#define AR5K_EEPROM_POWER_STEP 50 +#define AR5K_EEPROM_POWER_TABLE_SIZE 64 +#define AR5K_EEPROM_N_POWER_LOC_11B 4 +#define AR5K_EEPROM_N_POWER_LOC_11G 6 +#define AR5K_EEPROM_I_GAIN 10 +#define AR5K_EEPROM_CCK_OFDM_DELTA 15 +#define AR5K_EEPROM_N_IQ_CAL 2 + +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, +}; -#define AR5K_EEPROM_HDR AR5K_EEPROM_INFO(2) /* Header that contains the device caps */ -#define AR5K_EEPROM_HDR_11A(_v) (((_v) >> AR5K_EEPROM_MODE_11A) & 0x1) /* Device has a support */ -#define AR5K_EEPROM_HDR_11B(_v) (((_v) >> AR5K_EEPROM_MODE_11B) & 0x1) /* Device has b support */ -#define AR5K_EEPROM_HDR_11G(_v) (((_v) >> AR5K_EEPROM_MODE_11G) & 0x1) /* Device has g support */ -#define AR5K_EEPROM_HDR_T_2GHZ_DIS(_v) (((_v) >> 3) & 0x1) /* Disable turbo for 2Ghz (?) */ -#define AR5K_EEPROM_HDR_T_5GHZ_DBM(_v) (((_v) >> 4) & 0x7f) /* Max turbo power for a/XR mode (eeprom_init) */ -#define AR5K_EEPROM_HDR_DEVICE(_v) (((_v) >> 11) & 0x7) -#define AR5K_EEPROM_HDR_T_5GHZ_DIS(_v) (((_v) >> 15) & 0x1) /* Disable turbo for 5Ghz (?) */ -#define AR5K_EEPROM_HDR_RFKILL(_v) (((_v) >> 14) & 0x1) /* Device has RFKill support */ +/* Per channel calibration data, used for power table setup */ +struct ath5k_chan_pcal_info { + u_int16_t freq; /* Frequency */ + /* Power levels in dBm * 4 units */ + int16_t pwr_x0[AR5K_EEPROM_N_XPD0_POINTS]; + int16_t pwr_x3[AR5K_EEPROM_N_XPD3_POINTS]; + /* PCDAC tables in dBm * 2 units */ + u_int16_t pcdac_x0[AR5K_EEPROM_N_XPD0_POINTS]; + u_int16_t pcdac_x3[AR5K_EEPROM_N_XPD3_POINTS]; + /* Max available power */ + u_int16_t max_pwr; +}; -/* Misc values available since EEPROM 4.0 */ -#define AR5K_EEPROM_MISC0 0x00c4 -#define AR5K_EEPROM_EARSTART(_v) ((_v) & 0xfff) -#define AR5K_EEPROM_EEMAP(_v) (((_v) >> 14) & 0x3) -#define AR5K_EEPROM_MISC1 0x00c5 -#define AR5K_EEPROM_TARGET_PWRSTART(_v) ((_v) & 0xfff) -#define AR5K_EEPROM_HAS32KHZCRYSTAL(_v) (((_v) >> 14) & 0x1) +/* Per rate calibration data for each mode, used for power table setup */ +struct ath5k_rate_pcal_info { + u_int16_t freq; /* Frequency */ + /* Power level for 6-24Mbit/s rates */ + u_int16_t target_power_6to24; + /* Power level for 36Mbit rate */ + u_int16_t target_power_36; + /* Power level for 48Mbit rate */ + u_int16_t target_power_48; + /* Power level for 54Mbit rate */ + u_int16_t target_power_54; +}; + +/* EEPROM calibration data */ +struct ath5k_eeprom_info { + + /* Header information */ + u_int16_t ee_magic; + u_int16_t ee_protect; + u_int16_t ee_regdomain; + u_int16_t ee_version; + u_int16_t ee_header; + u_int16_t ee_ant_gain; + u_int16_t ee_misc0; + u_int16_t ee_misc1; + u_int16_t ee_cck_ofdm_gain_delta; + u_int16_t ee_cck_ofdm_power_delta; + u_int16_t ee_scaled_cck_delta; + + /* Used for tx thermal adjustment (eeprom_init, rfregs) */ + u_int16_t ee_tx_clip; + u_int16_t ee_pwd_84; + u_int16_t ee_pwd_90; + u_int16_t ee_gain_select; + + /* RF Calibration settings (reset, rfregs) */ + u_int16_t ee_i_cal[AR5K_EEPROM_N_MODES]; + u_int16_t ee_q_cal[AR5K_EEPROM_N_MODES]; + u_int16_t ee_fixed_bias[AR5K_EEPROM_N_MODES]; + u_int16_t ee_turbo_max_power[AR5K_EEPROM_N_MODES]; + u_int16_t ee_xr_power[AR5K_EEPROM_N_MODES]; + u_int16_t ee_switch_settling[AR5K_EEPROM_N_MODES]; + u_int16_t ee_ant_tx_rx[AR5K_EEPROM_N_MODES]; + u_int16_t ee_ant_control[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_PCDAC]; + u_int16_t ee_ob[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_OBDB]; + u_int16_t ee_db[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_OBDB]; + u_int16_t ee_tx_end2xlna_enable[AR5K_EEPROM_N_MODES]; + u_int16_t ee_tx_end2xpa_disable[AR5K_EEPROM_N_MODES]; + u_int16_t ee_tx_frm2xpa_enable[AR5K_EEPROM_N_MODES]; + u_int16_t ee_thr_62[AR5K_EEPROM_N_MODES]; + u_int16_t ee_xlna_gain[AR5K_EEPROM_N_MODES]; + u_int16_t ee_xpd[AR5K_EEPROM_N_MODES]; + u_int16_t ee_x_gain[AR5K_EEPROM_N_MODES]; + u_int16_t ee_i_gain[AR5K_EEPROM_N_MODES]; + u_int16_t ee_margin_tx_rx[AR5K_EEPROM_N_MODES]; + + /* Power calibration data */ + u_int16_t ee_false_detect[AR5K_EEPROM_N_MODES]; + u_int16_t ee_cal_piers_a; + struct ath5k_chan_pcal_info ee_pwr_cal_a[AR5K_EEPROM_N_5GHZ_CHAN]; + u_int16_t ee_cal_piers_b; + struct ath5k_chan_pcal_info ee_pwr_cal_b[AR5K_EEPROM_N_2GHZ_CHAN]; + u_int16_t ee_cal_piers_g; + struct ath5k_chan_pcal_info ee_pwr_cal_g[AR5K_EEPROM_N_2GHZ_CHAN]; + /* Per rate target power levels */ + u_int16_t ee_rate_target_pwr_num_a; + struct ath5k_rate_pcal_info ee_rate_tpwr_a[AR5K_EEPROM_N_5GHZ_CHAN]; + u_int16_t ee_rate_target_pwr_num_b; + struct ath5k_rate_pcal_info ee_rate_tpwr_b[AR5K_EEPROM_N_2GHZ_CHAN]; + u_int16_t ee_rate_target_pwr_num_g; + struct ath5k_rate_pcal_info ee_rate_tpwr_g[AR5K_EEPROM_N_2GHZ_CHAN]; + + /* Conformance test limits (Unused) */ + u_int16_t ee_ctls; + u_int16_t ee_ctl[AR5K_EEPROM_MAX_CTLS]; + + /* Noise Floor Calibration settings */ + int16_t ee_noise_floor_thr[AR5K_EEPROM_N_MODES]; + int8_t ee_adc_desired_size[AR5K_EEPROM_N_MODES]; + int8_t ee_pga_desired_size[AR5K_EEPROM_N_MODES]; + + u_int32_t ee_antenna[AR5K_EEPROM_N_MODES][AR5K_ANT_MAX]; +}; /* * Read data by masking @@ -350,7 +486,6 @@ static const struct ath5k_srev_name ath5 (*((volatile u_int32_t *)(mem + (_reg))) = (_val)) #endif - #define AR5K_REG_ENABLE_BITS(_reg, _flags) \ AR5K_REG_WRITE(_reg, AR5K_REG_READ(_reg) | (_flags)) @@ -359,7 +494,12 @@ static const struct ath5k_srev_name ath5 #define AR5K_TUNE_REGISTER_TIMEOUT 20000 -/* names for eeprom fields */ +#define AR5K_EEPROM_READ(_o, _v) do { \ + if ((ret = ath5k_hw_eeprom_read(mem, (_o), &(_v), mac_version)) != 0) \ + return (ret); \ +} while (0) + +/* Names for EEPROM fields */ struct eeprom_entry { const char *name; int addr; @@ -375,8 +515,6 @@ static const struct eeprom_entry eeprom_ {"regdomain", AR5K_EEPROM_REG_DOMAIN}, }; -static const int eeprom_addr_len = sizeof(eeprom_addr) / sizeof(eeprom_addr[0]); - static int force_write = 0; static int verbose = 0; @@ -398,8 +536,8 @@ static u_int32_t ath5k_hw_bitswap(u_int3 /* * Get the PHY Chip revision */ -static u_int16_t -ath5k_hw_radio_revision(u_int16_t mac_version, void *mem, u_int8_t chip) +static u_int16_t ath5k_hw_radio_revision(u_int16_t mac_version, void *mem, + u_int8_t chip) { int i; u_int32_t srev; @@ -427,7 +565,7 @@ ath5k_hw_radio_revision(u_int16_t mac_ve for (i = 0; i < 8; i++) AR5K_REG_WRITE(AR5K_PHY(0x20), 0x00010000); - if (mac_version == AR5K_SREV_VER_AR5210) { + if (mac_version == AR5K_SREV_MAC_AR5210) { srev = AR5K_REG_READ(AR5K_PHY(256) >> 28) & 0xf; ret = (u_int16_t)ath5k_hw_bitswap(srev, 4) + 1; @@ -447,9 +585,8 @@ ath5k_hw_radio_revision(u_int16_t mac_ve /* * Write to EEPROM */ -static int -ath5k_hw_eeprom_write(void *mem, u_int32_t offset, u_int16_t data, - u_int8_t mac_version) +static int ath5k_hw_eeprom_write(void *mem, u_int32_t offset, u_int16_t data, + u_int8_t mac_version) { u_int32_t status, timeout; @@ -457,7 +594,7 @@ ath5k_hw_eeprom_write(void *mem, u_int32 * Initialize EEPROM access */ - if (mac_version == AR5K_SREV_VER_AR5210) { + if (mac_version == AR5K_SREV_MAC_AR5210) { AR5K_REG_ENABLE_BITS(AR5K_PCICFG, AR5K_PCICFG_EEAE); @@ -466,7 +603,7 @@ ath5k_hw_eeprom_write(void *mem, u_int32 } else { /* not 5210 */ - /* reset eeprom access */ + /* reset EEPROM access */ AR5K_REG_WRITE(AR5K_EEPROM_CMD, AR5K_EEPROM_CMD_RESET); usleep(5); @@ -484,7 +621,7 @@ ath5k_hw_eeprom_write(void *mem, u_int32 status = AR5K_REG_READ(AR5K_EEPROM_STATUS); if (status & AR5K_EEPROM_STAT_WRDONE) { if (status & AR5K_EEPROM_STAT_WRERR) { - err("eeprom write access to 0x%04x failed", + err("EEPROM write access to 0x%04x failed", offset); return 1; } @@ -499,16 +636,15 @@ ath5k_hw_eeprom_write(void *mem, u_int32 /* * Read from EEPROM */ -static int -ath5k_hw_eeprom_read(void *mem, u_int32_t offset, u_int16_t *data, - u_int8_t mac_version) +static int ath5k_hw_eeprom_read(void *mem, u_int32_t offset, u_int16_t *data, + u_int8_t mac_version) { u_int32_t status, timeout; /* * Initialize EEPROM access */ - if (mac_version == AR5K_SREV_VER_AR5210) { + if (mac_version == AR5K_SREV_MAC_AR5210) { AR5K_REG_ENABLE_BITS(AR5K_PCICFG, AR5K_PCICFG_EEAE); (void)AR5K_REG_READ(AR5K_EEPROM_BASE + (4 * offset)); } else { @@ -531,50 +667,701 @@ ath5k_hw_eeprom_read(void *mem, u_int32_ return 1; } -static const char *ath5k_hw_get_part_name(enum ath5k_srev_type type, - u_int32_t val) +/* + * Translate binary channel representation in EEPROM to frequency + */ +static u_int16_t ath5k_eeprom_bin2freq(struct ath5k_eeprom_info *ee, + u_int16_t bin, unsigned int mode) { - const char *name = "xxxxx"; - int i; + u_int16_t val; - for (i = 0; i < ARRAY_SIZE(ath5k_srev_names); i++) { - if (ath5k_srev_names[i].sr_type != type || - ath5k_srev_names[i].sr_val == AR5K_SREV_UNKNOWN) - continue; - if ((val & 0xff) < ath5k_srev_names[i + 1].sr_val) { - name = ath5k_srev_names[i].sr_name; + if (bin == AR5K_EEPROM_CHANNEL_DIS) + return bin; + + if (mode == AR5K_EEPROM_MODE_11A) { + 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 (ee->ee_version > AR5K_EEPROM_VERSION_3_2) + val = bin + 2300; + else + val = bin + 2400; + } + + return val; +} + +/* + * Read antenna info from EEPROM + */ +static int ath5k_eeprom_read_ants(void *mem, u_int8_t mac_version, + struct ath5k_eeprom_info *ee, + u_int32_t *offset, unsigned int mode) +{ + u_int32_t o = *offset; + u_int16_t val; + int ret, i = 0; + + AR5K_EEPROM_READ(o++, val); + ee->ee_switch_settling[mode] = (val >> 8) & 0x7f; + ee->ee_ant_tx_rx[mode] = (val >> 2) & 0x3f; + ee->ee_ant_control[mode][i] = (val << 4) & 0x3f; + + AR5K_EEPROM_READ(o++, val); + ee->ee_ant_control[mode][i++] |= (val >> 12) & 0xf; + ee->ee_ant_control[mode][i++] = (val >> 6) & 0x3f; + ee->ee_ant_control[mode][i++] = val & 0x3f; + + AR5K_EEPROM_READ(o++, val); + ee->ee_ant_control[mode][i++] = (val >> 10) & 0x3f; + ee->ee_ant_control[mode][i++] = (val >> 4) & 0x3f; + ee->ee_ant_control[mode][i] = (val << 2) & 0x3f; + + AR5K_EEPROM_READ(o++, val); + ee->ee_ant_control[mode][i++] |= (val >> 14) & 0x3; + ee->ee_ant_control[mode][i++] = (val >> 8) & 0x3f; + ee->ee_ant_control[mode][i++] = (val >> 2) & 0x3f; + ee->ee_ant_control[mode][i] = (val << 4) & 0x3f; + + AR5K_EEPROM_READ(o++, val); + ee->ee_ant_control[mode][i++] |= (val >> 12) & 0xf; + ee->ee_ant_control[mode][i++] = (val >> 6) & 0x3f; + ee->ee_ant_control[mode][i++] = val & 0x3f; + + /* Get antenna modes */ + ee->ee_antenna[mode][0] = + (ee->ee_ant_control[mode][0] << 4) | 0x1; + ee->ee_antenna[mode][AR5K_ANT_FIXED_A] = + ee->ee_ant_control[mode][1] | + (ee->ee_ant_control[mode][2] << 6) | + (ee->ee_ant_control[mode][3] << 12) | + (ee->ee_ant_control[mode][4] << 18) | + (ee->ee_ant_control[mode][5] << 24); + ee->ee_antenna[mode][AR5K_ANT_FIXED_B] = + ee->ee_ant_control[mode][6] | + (ee->ee_ant_control[mode][7] << 6) | + (ee->ee_ant_control[mode][8] << 12) | + (ee->ee_ant_control[mode][9] << 18) | + (ee->ee_ant_control[mode][10] << 24); + + /* return new offset */ + *offset = o; + + return 0; +} + +/* + * Read supported modes from EEPROM + */ +static int ath5k_eeprom_read_modes(void *mem, u_int8_t mac_version, + struct ath5k_eeprom_info *ee, + u_int32_t *offset, unsigned int mode) +{ + u_int32_t o = *offset; + u_int16_t val; + int ret; + + AR5K_EEPROM_READ(o++, val); + ee->ee_tx_end2xlna_enable[mode] = (val >> 8) & 0xff; + ee->ee_thr_62[mode] = val & 0xff; + + if (ee->ee_version <= AR5K_EEPROM_VERSION_3_2) + ee->ee_thr_62[mode] = mode == AR5K_EEPROM_MODE_11A ? 15 : 28; + + AR5K_EEPROM_READ(o++, val); + ee->ee_tx_end2xpa_disable[mode] = (val >> 8) & 0xff; + ee->ee_tx_frm2xpa_enable[mode] = val & 0xff; + + AR5K_EEPROM_READ(o++, val); + ee->ee_pga_desired_size[mode] = (val >> 8) & 0xff; + + if ((val & 0xff) & 0x80) + ee->ee_noise_floor_thr[mode] = -((((val & 0xff) ^ 0xff)) + 1); + else + ee->ee_noise_floor_thr[mode] = val & 0xff; + + if (ee->ee_version <= AR5K_EEPROM_VERSION_3_2) + ee->ee_noise_floor_thr[mode] = + mode == AR5K_EEPROM_MODE_11A ? -54 : -1; + + AR5K_EEPROM_READ(o++, val); + ee->ee_xlna_gain[mode] = (val >> 5) & 0xff; + ee->ee_x_gain[mode] = (val >> 1) & 0xf; + ee->ee_xpd[mode] = val & 0x1; + + if (ee->ee_version >= AR5K_EEPROM_VERSION_4_0) + ee->ee_fixed_bias[mode] = (val >> 13) & 0x1; + + if (ee->ee_version >= AR5K_EEPROM_VERSION_3_3) { + AR5K_EEPROM_READ(o++, val); + ee->ee_false_detect[mode] = (val >> 6) & 0x7f; + + if (mode == AR5K_EEPROM_MODE_11A) + ee->ee_xr_power[mode] = val & 0x3f; + else { + ee->ee_ob[mode][0] = val & 0x7; + ee->ee_db[mode][0] = (val >> 3) & 0x7; + } + } + + if (ee->ee_version < AR5K_EEPROM_VERSION_3_4) { + ee->ee_i_gain[mode] = AR5K_EEPROM_I_GAIN; + ee->ee_cck_ofdm_power_delta = AR5K_EEPROM_CCK_OFDM_DELTA; + } else { + ee->ee_i_gain[mode] = (val >> 13) & 0x7; + + AR5K_EEPROM_READ(o++, val); + ee->ee_i_gain[mode] |= (val << 3) & 0x38; + + if (mode == AR5K_EEPROM_MODE_11G) + ee->ee_cck_ofdm_power_delta = (val >> 3) & 0xff; + } + + if (ee->ee_version >= AR5K_EEPROM_VERSION_4_0 && + mode == AR5K_EEPROM_MODE_11A) { + ee->ee_i_cal[mode] = (val >> 8) & 0x3f; + ee->ee_q_cal[mode] = (val >> 3) & 0x1f; + } + + if (ee->ee_version >= AR5K_EEPROM_VERSION_4_6 && + mode == AR5K_EEPROM_MODE_11G) + ee->ee_scaled_cck_delta = (val >> 11) & 0x1f; + + /* return new offset */ + *offset = o; + + return 0; +} + +/* + * Read per channel calibration info from EEPROM + * This doesn't work on 2112+ chips (EEPROM versions >= 4.6), + * I only tested it on 5213 + 5112. This is still work in progress... + * + * This info is used to calibrate the baseband power table. Imagine + * that for each channel there is a power curve that's hw specific + * (depends on amplifier) and we try to "correct" this curve using offests + * we pass on to phy chip (baseband -> before amplifier) so that it can + * use acurate power values when setting tx power (takes amplifier's performance + * on each channel into account). + * + * EEPROM provides us with the offsets for some pre-calibrated channels + * and we have to scale (to create the full table for these channels) and + * interpolate (in order to create the table for any channel). + */ +static int ath5k_eeprom_read_pcal_info(void *mem, u_int8_t mac_version, + struct ath5k_eeprom_info *ee, + u_int32_t *offset, unsigned int mode) +{ + u_int32_t o = *offset; + unsigned int i, c; + int ret; + u_int16_t val; + struct ath5k_chan_pcal_info *chan_pcal_info; + u_int16_t cal_piers; + + switch (mode) { + case AR5K_EEPROM_MODE_11A: + chan_pcal_info = ee->ee_pwr_cal_a; + cal_piers = ee->ee_cal_piers_a; + break; + case AR5K_EEPROM_MODE_11B: + chan_pcal_info = ee->ee_pwr_cal_b; + cal_piers = ee->ee_cal_piers_b; + break; + case AR5K_EEPROM_MODE_11G: + chan_pcal_info = ee->ee_pwr_cal_g; + cal_piers = ee->ee_cal_piers_g; + break; + default: + return -EINVAL; + } + + for (i = 0; i < cal_piers; i++) { + /* Power values in dBm * 4 */ + for (c = 0; c < AR5K_EEPROM_N_XPD0_POINTS; c++) { + AR5K_EEPROM_READ(o++, val); + chan_pcal_info[i].pwr_x0[c] = (val & 0xff); + chan_pcal_info[i].pwr_x0[++c] = ((val >> 8) & 0xff); + } + + /* PCDAC steps (dBm * 2) */ + AR5K_EEPROM_READ(o++, val); + chan_pcal_info[i].pcdac_x0[1] = (val & 0x1f); + chan_pcal_info[i].pcdac_x0[2] = ((val >> 5) & 0x1f); + chan_pcal_info[i].pcdac_x0[3] = ((val >> 10) & 0x1f); + + /* No idea what these power levels are for (4 xpds ?) + I got zeroes on my card and the EEPROM info + dumps we found on the net also have weird values */ + AR5K_EEPROM_READ(o++, val); + chan_pcal_info[i].pwr_x3[0] = (val & 0xff); + chan_pcal_info[i].pwr_x3[1] = ((val >> 8) & 0xff); + + AR5K_EEPROM_READ(o++, val); + chan_pcal_info[i].pwr_x3[2] = (val & 0xff); + /* It's weird but they put it here, that's the + PCDAC starting step */ + chan_pcal_info[i].pcdac_x0[0] = ((val >> 8) & 0xff); + + /* Static values seen on EEPROM info dumps */ + chan_pcal_info[i].pcdac_x3[0] = 20; + chan_pcal_info[i].pcdac_x3[1] = 35; + chan_pcal_info[i].pcdac_x3[2] = 63; + + /* Last xpd0 power level is also channel maximum */ + chan_pcal_info[i].max_pwr = chan_pcal_info[i].pwr_x0[3]; + + /* Recreate pcdac_x0 table for this channel using pcdac steps */ + chan_pcal_info[i].pcdac_x0[1] += chan_pcal_info[i].pcdac_x0[0]; + chan_pcal_info[i].pcdac_x0[2] += chan_pcal_info[i].pcdac_x0[1]; + chan_pcal_info[i].pcdac_x0[3] += chan_pcal_info[i].pcdac_x0[2]; + } + + /* return new offset */ + (*offset) = o; + + 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(void *mem, + u_int8_t mac_version, + struct ath5k_eeprom_info *ee, + u_int32_t *offset, + unsigned int mode) +{ + u_int32_t o = *offset; + u_int16_t val; + struct ath5k_rate_pcal_info *rate_pcal_info; + u_int16_t *rate_target_pwr_num; + int ret, i; + + switch (mode) { + case AR5K_EEPROM_MODE_11A: + rate_pcal_info = ee->ee_rate_tpwr_a; + ee->ee_rate_target_pwr_num_a = AR5K_EEPROM_N_5GHZ_CHAN; + rate_target_pwr_num = &ee->ee_rate_target_pwr_num_a; + break; + case AR5K_EEPROM_MODE_11B: + rate_pcal_info = ee->ee_rate_tpwr_b; + ee->ee_rate_target_pwr_num_b = 2; /* 3rd is g mode'ss 1st */ + rate_target_pwr_num = &ee->ee_rate_target_pwr_num_b; + break; + case AR5K_EEPROM_MODE_11G: + rate_pcal_info = ee->ee_rate_tpwr_g; + ee->ee_rate_target_pwr_num_g = AR5K_EEPROM_N_2GHZ_CHAN; + rate_target_pwr_num = &ee->ee_rate_target_pwr_num_g; + break; + default: + return -EINVAL; + } + + /* Different freq mask for older eeproms (<= v3.2) */ + if(ee->ee_version <= 0x3002){ + for (i = 0; i < (*rate_target_pwr_num); i++) { + AR5K_EEPROM_READ(o++, 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(o++, 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(o++, 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(o++, 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 new offset */ + (*offset) = o; + + return 0; +} + +/* + * Initialize EEPROM & capabilities data + */ +static int ath5k_eeprom_init(void *mem, u_int8_t mac_version, + struct ath5k_eeprom_info *ee) +{ + unsigned int mode, i; + int ret; + u_int32_t offset; + u_int16_t 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(AR5K_EEPROM_MAGIC, ee->ee_magic); + AR5K_EEPROM_READ(AR5K_EEPROM_PROTECT, ee->ee_protect); + AR5K_EEPROM_READ(AR5K_EEPROM_REG_DOMAIN, ee->ee_regdomain); + AR5K_EEPROM_READ(AR5K_EEPROM_VERSION, ee->ee_version); + AR5K_EEPROM_READ(AR5K_EEPROM_HDR, ee->ee_header); + + /* Return if we have an old EEPROM */ + if (ee->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) { + AR5K_PRINTF("Invalid EEPROM checksum 0x%04x\n", cksum); + return -EIO; + } +#endif + + AR5K_EEPROM_READ(AR5K_EEPROM_ANT_GAIN(ee->ee_version), ee->ee_ant_gain); + + if (ee->ee_version >= AR5K_EEPROM_VERSION_4_0) { + AR5K_EEPROM_READ(AR5K_EEPROM_MISC0, ee->ee_misc0); + AR5K_EEPROM_READ(AR5K_EEPROM_MISC1, ee->ee_misc1); + } + + if (ee->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; + } + + /* + * Get conformance test limit values + */ + offset = AR5K_EEPROM_CTL(ee->ee_version); + ee->ee_ctls = 0; + + for (i = 0; i < AR5K_EEPROM_N_CTLS(ee->ee_version); i++) { + AR5K_EEPROM_READ(offset++, val); + + if (((val >> 8) & 0xff) == 0) + break; + + ee->ee_ctl[i] = (val >> 8) & 0xff; + ee->ee_ctls++; + + if ((val & 0xff) == 0) break; + + ee->ee_ctl[i + 1] = val & 0xff; + ee->ee_ctls++; + } + + /* + * Get values for 802.11a (5GHz) + */ + mode = AR5K_EEPROM_MODE_11A; + + ee->ee_turbo_max_power[mode] = + AR5K_EEPROM_HDR_T_5GHZ_DBM(ee->ee_header); + + offset = AR5K_EEPROM_MODES_11A(ee->ee_version); + + ret = ath5k_eeprom_read_ants(mem, mac_version, ee, &offset, mode); + if (ret) + return ret; + + AR5K_EEPROM_READ(offset++, val); + ee->ee_adc_desired_size[mode] = (int8_t)((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; + + ret = ath5k_eeprom_read_modes(mem, mac_version, ee, &offset, mode); + if (ret) + return ret; + + if (ee->ee_version >= AR5K_EEPROM_VERSION_4_1) { + AR5K_EEPROM_READ(offset++, val); + ee->ee_margin_tx_rx[mode] = val & 0x3f; + } + + /* + * Get values for 802.11b (2.4GHz) + */ + mode = AR5K_EEPROM_MODE_11B; + offset = AR5K_EEPROM_MODES_11B(ee->ee_version); + + ret = ath5k_eeprom_read_ants(mem, mac_version, ee, &offset, mode); + if (ret) + return ret; + + AR5K_EEPROM_READ(offset++, val); + ee->ee_adc_desired_size[mode] = (int8_t)((val >> 8) & 0xff); + ee->ee_ob[mode][1] = (val >> 4) & 0x7; + ee->ee_db[mode][1] = val & 0x7; + + ret = ath5k_eeprom_read_modes(mem, mac_version, ee, &offset, mode); + if (ret) + return ret; + + if (ee->ee_version >= AR5K_EEPROM_VERSION_4_0) { + AR5K_EEPROM_READ(offset++, val); + + ee->ee_cal_piers_b = 0; + + 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_cal_piers_b++; + + 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_cal_piers_b++; + + AR5K_EEPROM_READ(offset++, 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_cal_piers_b++; + } + + if (ee->ee_version >= AR5K_EEPROM_VERSION_4_1) + ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f; + + /* + * Get values for 802.11g (2.4GHz) + */ + mode = AR5K_EEPROM_MODE_11G; + offset = AR5K_EEPROM_MODES_11G(ee->ee_version); + + ret = ath5k_eeprom_read_ants(mem, mac_version, ee, &offset, mode); + if (ret) + return ret; + + AR5K_EEPROM_READ(offset++, val); + ee->ee_adc_desired_size[mode] = (signed short int)((val >> 8) & 0xff); + ee->ee_ob[mode][1] = (val >> 4) & 0x7; + ee->ee_db[mode][1] = val & 0x7; + + ret = ath5k_eeprom_read_modes(mem, mac_version, ee, &offset, mode); + if (ret) + return ret; + + if (ee->ee_version >= AR5K_EEPROM_VERSION_4_0) { + AR5K_EEPROM_READ(offset++, val); + + ee->ee_cal_piers_g = 0; + + 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_cal_piers_g++; + + 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_cal_piers_g++; + + AR5K_EEPROM_READ(offset++, val); + ee->ee_turbo_max_power[mode] = val & 0x7f; + ee->ee_xr_power[mode] = (val >> 7) & 0x3f; + + AR5K_EEPROM_READ(offset++, 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_cal_piers_g++; + + if (ee->ee_version >= AR5K_EEPROM_VERSION_4_1) + ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f; + + AR5K_EEPROM_READ(offset++, val); + ee->ee_i_cal[mode] = (val >> 8) & 0x3f; + ee->ee_q_cal[mode] = (val >> 3) & 0x1f; + + if (ee->ee_version >= AR5K_EEPROM_VERSION_4_2) { + AR5K_EEPROM_READ(offset++, val); + ee->ee_cck_ofdm_gain_delta = val & 0xff; } } - return (name); + /* + * Read 5GHz EEPROM channels + */ + offset = AR5K_EEPROM_CHANNELS_5GHZ(ee->ee_version); + ee->ee_cal_piers_a = 0; + for (i = 0; i < AR5K_EEPROM_N_5GHZ_CHAN; i++) { + AR5K_EEPROM_READ(offset++, val); + + if ((val & 0xff) == 0) + break; + + ee->ee_pwr_cal_a[i].freq = + ath5k_eeprom_bin2freq(ee, val & 0xff, AR5K_EEPROM_MODE_11A); + ee->ee_cal_piers_a++; + + if (((val >> 8) & 0xff) == 0) + break; + + ee->ee_pwr_cal_a[++i].freq = + ath5k_eeprom_bin2freq(ee, (val >> 8) & 0xff, AR5K_EEPROM_MODE_11A); + ee->ee_cal_piers_a++; + + } + + /* + * Read power calibration info + */ + mode = AR5K_EEPROM_MODE_11A; + ret = ath5k_eeprom_read_pcal_info(mem, mac_version, ee, &offset, mode); + if (ret) + return ret; + + mode = AR5K_EEPROM_MODE_11B; + ret = ath5k_eeprom_read_pcal_info(mem, mac_version, ee, &offset, mode); + if (ret) + return ret; + + mode = AR5K_EEPROM_MODE_11G; + ret = ath5k_eeprom_read_pcal_info(mem, mac_version, ee, &offset, mode); + if (ret) + return ret; + + + /* + * Read per rate target power info + */ + offset = AR5K_EEPROM_TARGET_PWRSTART(ee->ee_misc1) + AR5K_EEPROM_TARGET_PWR_OFF_11A(ee->ee_version); + mode = AR5K_EEPROM_MODE_11A; + ret = ath5k_eeprom_read_target_rate_pwr_info(mem, mac_version, ee, &offset, mode); + if (ret) + return ret; + + offset = AR5K_EEPROM_TARGET_PWRSTART(ee->ee_misc1) + AR5K_EEPROM_TARGET_PWR_OFF_11B(ee->ee_version); + mode = AR5K_EEPROM_MODE_11B; + ret = ath5k_eeprom_read_target_rate_pwr_info(mem, mac_version, ee, &offset, mode); + if (ret) + return ret; + + offset = AR5K_EEPROM_TARGET_PWRSTART(ee->ee_misc1) + AR5K_EEPROM_TARGET_PWR_OFF_11G(ee->ee_version); + mode = AR5K_EEPROM_MODE_11G; + ret = ath5k_eeprom_read_target_rate_pwr_info(mem, mac_version, ee, &offset, mode); + if (ret) + return ret; + + return 0; +} + +static const char *ath5k_hw_get_mac_name(u_int8_t val) +{ + static char name[16]; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(ath5k_mac_names); i++) { + if (val <= ath5k_mac_names[i].sr_val) + break; + } + + if (val == ath5k_mac_names[i].sr_val) + return ath5k_mac_names[i].sr_name; + + snprintf(name, sizeof(name), "%s+", ath5k_mac_names[i - 1].sr_name); + return name; +} + +static const char *ath5k_hw_get_phy_name(u_int8_t val) +{ + const char *name = "?????"; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(ath5k_phy_names); i++) { + if (val < ath5k_phy_names[i + 1].sr_val) { + name = ath5k_phy_names[i].sr_name; + break; + } + } + + return name; } /* returns -1 on unknown name */ static int eeprom_name2addr(const char *name) { - int i; + unsigned int i; + if (!name || !name[0]) return -1; - for (i = 0; i < eeprom_addr_len; i++) + for (i = 0; i < ARRAY_SIZE(eeprom_addr); i++) if (!strcmp(name, eeprom_addr[i].name)) return eeprom_addr[i].addr; return -1; -} /* eeprom_name2addr */ +} /* returns "" on unknown address */ static const char *eeprom_addr2name(int addr) { - int i; - for (i = 0; i < eeprom_addr_len; i++) + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(eeprom_addr); i++) if (eeprom_addr[i].addr == addr) return eeprom_addr[i].name; return ""; -} /* eeprom_addr2name */ +} -static int -do_write_pairs(int anr, int argc, char **argv, unsigned char *mem, - int mac_version) +static int do_write_pairs(int anr, int argc, char **argv, unsigned char *mem, + int mac_version) { #define MAX_NR_WRITES 16 struct { @@ -635,7 +1422,7 @@ do_write_pairs(int anr, int argc, char * } anr++; i++; - } /* while (anr < (argc-1)) */ + } if (!(wr_ops_len = i)) { err("no (addr,val) pairs given"); @@ -702,20 +1489,22 @@ do_write_pairs(int anr, int argc, char * } return errors ? 11 : 0; -} /* do_write_pairs */ +} static void usage(const char *n) { - int i; + unsigned int i; - fprintf(stderr, "%s [-w [-g N:M]] [-v] [-f] [-d] " + fprintf(stderr, "%s [-w [-g N:M]] [-v] [-f] [-d] [-R addr] [-W addr val] " "[ [ ...]]\n\n", n); fprintf(stderr, "-w write values into EEPROM\n" "-g N:M set GPIO N to level M (only used with -w)\n" "-v verbose output\n" "-f force; suppress question before writing\n" - "-d dump eeprom (file 'ath-eeprom-dump.bin' and screen)\n" + "-d dump EEPROM (file 'ath-eeprom-dump.bin' and screen)\n" + "-R read register at (hex)\n" + "-W write (hex) into register at (hex)\n" " device base address (see lspci output)\n\n"); fprintf(stderr, @@ -725,8 +1514,8 @@ static void usage(const char *n) " %s -w regdomain N\n\n" "- set a PCI id field to value N:\n" " %s -w N\n" - " where is on of:\n ", n, n, n); - for (i = 0; i < eeprom_addr_len; i++) + " where is one of:\n ", n, n, n); + for (i = 0; i < ARRAY_SIZE(eeprom_addr); i++) fprintf(stderr, " %s", eeprom_addr[i].name); fprintf(stderr, "\n\n"); fprintf(stderr, @@ -739,19 +1528,457 @@ static void usage(const char *n) "unlawful radio transmissions!\n\n"); } +static void dump_capabilities(struct ath5k_eeprom_info *ee) +{ + u_int8_t has_a, has_b, has_g, has_rfkill, turbog_dis, turboa_dis; + u_int8_t xr2_dis, xr5_dis, has_crystal; + + has_a = AR5K_EEPROM_HDR_11A(ee->ee_header); + has_b = AR5K_EEPROM_HDR_11B(ee->ee_header); + has_g = AR5K_EEPROM_HDR_11G(ee->ee_header); + has_rfkill = AR5K_EEPROM_HDR_RFKILL(ee->ee_header); + has_crystal = AR5K_EEPROM_HAS32KHZCRYSTAL(ee->ee_misc1); + turbog_dis = AR5K_EEPROM_HDR_T_2GHZ_DIS(ee->ee_header); + turboa_dis = AR5K_EEPROM_HDR_T_5GHZ_DIS(ee->ee_header); + xr2_dis = AR5K_EEPROM_HDR_XR2_DIS(ee->ee_misc0); + xr5_dis = AR5K_EEPROM_HDR_XR5_DIS(ee->ee_misc0); + + printf("|================= Capabilities ================|\n"); + + printf("| 802.11a Support: "); + if (has_a) + printf(" yes |"); + else + printf(" no |"); + + printf(" Turbo-A disabled:"); + if (turboa_dis) + printf(" yes |\n"); + else + printf(" no |\n"); + + printf("| 802.11b Support: "); + if (has_b) + printf(" yes |"); + else + printf(" no |"); + + printf(" Turbo-G disabled:"); + if (turbog_dis) + printf(" yes |\n"); + else + printf(" no |\n"); + + printf("| 802.11g Support: "); + if (has_g) + printf(" yes |"); + else + printf(" no |"); + + printf(" 2GHz XR disabled:"); + if (xr2_dis) + printf(" yes |\n"); + else + printf(" no |\n"); + + printf("| RFKill Support: "); + if (has_rfkill) + printf(" yes |"); + else + printf(" no |"); + + printf(" 5GHz XR disabled:"); + if (xr5_dis) + printf(" yes |\n"); + else + printf(" no |\n"); + + if (has_crystal != 2) { + printf("| 32kHz Crystal: "); + if (has_crystal) + printf(" yes |"); + else + printf(" no |"); + + printf(" |\n"); + } + + printf("\\===============================================/\n"); +} + +static void dump_calinfo_for_mode(int mode, struct ath5k_eeprom_info *ee) +{ + int i; + + printf("|=========================================================|\n"); + printf("| I power: 0x%02x |", ee->ee_i_cal[mode]); + printf(" Q power: 0x%02x |\n", ee->ee_q_cal[mode]); + printf("| Use fixed bias: 0x%02x |", ee->ee_fixed_bias[mode]); + printf(" Max turbo power: 0x%02x |\n", ee->ee_turbo_max_power[mode]); + printf("| Max XR power: 0x%02x |", ee->ee_xr_power[mode]); + printf(" Switch Settling Time: 0x%02x |\n", ee->ee_switch_settling[mode]); + printf("| Tx/Rx attenuation: 0x%02x |", ee->ee_ant_tx_rx[mode]); + printf(" TX end to XLNA On: 0x%02x |\n", ee->ee_tx_end2xlna_enable[mode]); + printf("| TX end to XPA Off: 0x%02x |", ee->ee_tx_end2xpa_disable[mode]); + printf(" TX end to XPA On: 0x%02x |\n", ee->ee_tx_frm2xpa_enable[mode]); + printf("| 62db Threshold: 0x%02x |", ee->ee_thr_62[mode]); + printf(" XLNA gain: 0x%02x |\n", ee->ee_xlna_gain[mode]); + printf("| XPD: 0x%02x |", ee->ee_xpd[mode]); + printf(" XPD gain: 0x%02x |\n", ee->ee_x_gain[mode]); + printf("| I gain: 0x%02x |", ee->ee_i_gain[mode]); + printf(" Tx/Rx margin: 0x%02x |\n", ee->ee_margin_tx_rx[mode]); + printf("| False detect backoff: 0x%02x |", ee->ee_false_detect[mode]); + printf(" Noise Floor Threshold: %3d |\n", ee->ee_noise_floor_thr[mode]); + printf("| ADC desired size: %3d |", ee->ee_adc_desired_size[mode]); + printf(" PGA desired size: %3d |\n", ee->ee_pga_desired_size[mode]); + printf("|=========================================================|\n"); + for (i = 0; i < AR5K_EEPROM_N_PCDAC; i++) { + printf("| Antenna control %2i: 0x%02x |", i, ee->ee_ant_control[mode][i]); + i++; + printf(" Antenna control %2i: 0x%02x |\n", i, ee->ee_ant_control[mode][i]); + } + printf("|=========================================================|\n"); + for (i = 0; i < AR5K_EEPROM_N_OBDB; i++) { + printf("| Octave Band %i: %2i |", i, ee->ee_ob[mode][i]); + printf(" db %i: %2i |\n", i, ee->ee_db[mode][i]); + } + printf("\\=========================================================/\n"); +} + +static void dump_power_calinfo_for_mode(int mode, struct ath5k_eeprom_info *ee) +{ + struct ath5k_chan_pcal_info *chan_pcal_info; + u_int16_t cal_piers; + int i, c; + + switch (mode) { + case AR5K_EEPROM_MODE_11A: + chan_pcal_info = ee->ee_pwr_cal_a; + cal_piers = ee->ee_cal_piers_a; + break; + case AR5K_EEPROM_MODE_11B: + chan_pcal_info = ee->ee_pwr_cal_b; + cal_piers = ee->ee_cal_piers_b; + break; + case AR5K_EEPROM_MODE_11G: + chan_pcal_info = ee->ee_pwr_cal_g; + cal_piers = ee->ee_cal_piers_g; + break; + default: + return; + } + + printf("/=================== Per channel power calibration ====================\\\n"); + printf("| Freq | pwr_0 | pwr_1 | pwr_2 | pwr_3 |pwrx3_0|pwrx3_1|pwrx3_2|max_pwr|\n"); + printf("| | pcdac | pcdac | pcdac | pcdac | pcdac | pcdac | pcdac | |\n"); + + for (i = 0; i < cal_piers; i++) { + char buf[16]; + + printf("|======|=======|=======|=======|=======|=======|=======|=======|=======|\n"); + printf("| %4i |", chan_pcal_info[i].freq); + for (c = 0; c < AR5K_EEPROM_N_XPD0_POINTS; c++) { + printf(" %2i.%02i |", chan_pcal_info[i].pwr_x0[c] / 4, + chan_pcal_info[i].pwr_x0[c] % 4); + } + for (c = 0; c < AR5K_EEPROM_N_XPD3_POINTS; c++) { + printf(" %2i.%02i |", chan_pcal_info[i].pwr_x3[c] / 4, + chan_pcal_info[i].pwr_x3[c] % 4); + } + printf(" %2i.%02i |\n", chan_pcal_info[i].max_pwr / 4, + chan_pcal_info[i].max_pwr % 4); + + printf("| |"); + for (c = 0; c < AR5K_EEPROM_N_XPD0_POINTS; c++) { + snprintf(buf, sizeof(buf), "[%i]", + chan_pcal_info[i].pcdac_x0[c]); + printf("%6s |", buf); + } + for (c = 0; c < AR5K_EEPROM_N_XPD3_POINTS; c++) { + snprintf(buf, sizeof(buf), "[%i]", + chan_pcal_info[i].pcdac_x3[c]); + printf("%6s |", buf); + } + printf(" |\n"); + + } + printf("\\======================================================================/\n"); +} + +static void dump_rate_calinfo_for_mode(int mode, struct ath5k_eeprom_info *ee) +{ + int i; + struct ath5k_rate_pcal_info *rate_pcal_info; + u_int16_t rate_target_pwr_num; + + switch (mode) { + case AR5K_EEPROM_MODE_11A: + rate_pcal_info = ee->ee_rate_tpwr_a; + rate_target_pwr_num = ee->ee_rate_target_pwr_num_a; + break; + case AR5K_EEPROM_MODE_11B: + rate_pcal_info = ee->ee_rate_tpwr_b; + rate_target_pwr_num = ee->ee_rate_target_pwr_num_b; + break; + case AR5K_EEPROM_MODE_11G: + rate_pcal_info = ee->ee_rate_tpwr_g; + rate_target_pwr_num = ee->ee_rate_target_pwr_num_g; + break; + default: + return; + } + + printf("/============== Per rate power calibration ===========\\\n"); + if (mode == AR5K_EEPROM_MODE_11B) + printf("| Freq | 1Mbit/s | 2Mbit/s | 5.5Mbit/s | 11Mbit/s |\n"); + else + printf("| Freq | 6-24Mbit/s | 36Mbit/s | 48Mbit/s | 54Mbit/s |\n"); + + for (i = 0; i < rate_target_pwr_num; i++) { + + printf("|======|============|==========|===========|==========|\n"); + printf("| %4i |", rate_pcal_info[i].freq); + printf(" %2i.%02i |",rate_pcal_info[i].target_power_6to24 /2, + rate_pcal_info[i].target_power_6to24 % 2); + printf(" %2i.%02i |",rate_pcal_info[i].target_power_36 /2, + rate_pcal_info[i].target_power_36 % 2); + printf(" %2i.%02i |",rate_pcal_info[i].target_power_48 /2, + rate_pcal_info[i].target_power_48 % 2); + printf(" %2i.%02i |\n",rate_pcal_info[i].target_power_54 /2, + rate_pcal_info[i].target_power_54 % 2); + } + printf("\\=====================================================/\n"); +} + +static u_int32_t extend_tu(u_int32_t base_tu, u_int32_t val, u_int32_t mask) +{ + u_int32_t result; + + result = (base_tu & ~mask) | (val & mask); + if ((base_tu & mask) > (val & mask)) + result += mask + 1; + return result; +} + +static void dump_timers_register(void *mem, u_int16_t mac_version) +{ +#define AR5K_TIMER0_5210 0x802c /* next TBTT */ +#define AR5K_TIMER0_5211 0x8028 +#define AR5K_TIMER0 (mac_version == AR5K_SREV_MAC_AR5210 ? \ + AR5K_TIMER0_5210 : AR5K_TIMER0_5211) + +#define AR5K_TIMER1_5210 0x8030 /* next DMA beacon */ +#define AR5K_TIMER1_5211 0x802c +#define AR5K_TIMER1 (mac_version == AR5K_SREV_MAC_AR5210 ? \ + AR5K_TIMER1_5210 : AR5K_TIMER1_5211) + +#define AR5K_TIMER2_5210 0x8034 /* next SWBA interrupt */ +#define AR5K_TIMER2_5211 0x8030 +#define AR5K_TIMER2 (mac_version == AR5K_SREV_MAC_AR5210 ? \ + AR5K_TIMER2_5210 : AR5K_TIMER2_5211) + +#define AR5K_TIMER3_5210 0x8038 /* next ATIM window */ +#define AR5K_TIMER3_5211 0x8034 +#define AR5K_TIMER3 (mac_version == AR5K_SREV_MAC_AR5210 ? \ + AR5K_TIMER3_5210 : AR5K_TIMER3_5211) + +#define AR5K_TSF_L32_5210 0x806c /* TSF (lower 32 bits) */ +#define AR5K_TSF_L32_5211 0x804c +#define AR5K_TSF_L32 (mac_version == AR5K_SREV_MAC_AR5210 ? \ + AR5K_TSF_L32_5210 : AR5K_TSF_L32_5211) + +#define AR5K_TSF_U32_5210 0x8070 +#define AR5K_TSF_U32_5211 0x8050 +#define AR5K_TSF_U32 (mac_version == AR5K_SREV_MAC_AR5210 ? \ + AR5K_TSF_U32_5210 : AR5K_TSF_U32_5211) + +#define AR5K_BEACON_5210 0x8024 +#define AR5K_BEACON_5211 0x8020 +#define AR5K_BEACON (mac_version == AR5K_SREV_MAC_AR5210 ? \ + AR5K_BEACON_5210 : AR5K_BEACON_5211) + +#define AR5K_LAST_TSTP 0x8080 + + const int timer_mask = 0xffff; + + u_int32_t timer0, timer1, timer2, timer3, now_tu; + u_int32_t timer0_tu, timer1_tu, timer2_tu, timer3_tu; + u_int64_t now_tsf; + + timer0 = AR5K_REG_READ(AR5K_TIMER0); /* 0x0000ffff */ + timer1 = AR5K_REG_READ(AR5K_TIMER1_5211); /* 0x0007ffff */ + timer2 = AR5K_REG_READ(AR5K_TIMER2_5211); /* 0x?1ffffff */ + timer3 = AR5K_REG_READ(AR5K_TIMER3_5211); /* 0x0000ffff */ + + now_tsf = ((u_int64_t)AR5K_REG_READ(AR5K_TSF_U32_5211) << 32) + | (u_int64_t)AR5K_REG_READ(AR5K_TSF_L32_5211); + + now_tu = now_tsf >> 10; + + timer0_tu = extend_tu(now_tu, timer0, 0xffff); + printf("TIMER0: 0x%08x, TBTT: %5u, TU: 0x%08x\n", timer0, + timer0 & timer_mask, timer0_tu); + timer1_tu = extend_tu(now_tu, timer1 >> 3, 0x7ffff >> 3); + printf("TIMER1: 0x%08x, DMAb: %5u, TU: 0x%08x (%+d)\n", timer1, + (timer1 >> 3) & timer_mask, timer1_tu, timer1_tu - timer0_tu); + timer2_tu = extend_tu(now_tu, timer2 >> 3, 0x1ffffff >> 3); + printf("TIMER2: 0x%08x, SWBA: %5u, TU: 0x%08x (%+d)\n", timer2, + (timer2 >> 3) & timer_mask, timer2_tu, timer2_tu - timer0_tu); + timer3_tu = extend_tu(now_tu, timer3, 0xffff); + printf("TIMER3: 0x%08x, ATIM: %5u, TU: 0x%08x (%+d)\n", timer3, + timer3 & timer_mask, timer3_tu, timer3_tu - timer0_tu); + printf("TSF: 0x%016llx, TSFTU: %5u, TU: 0x%08x\n", + (unsigned long long)now_tsf, now_tu & timer_mask, now_tu); + + printf("BEACON: 0x%08x\n", AR5K_REG_READ(AR5K_BEACON)); + printf("LAST_TSTP: 0x%08x\n", AR5K_REG_READ(AR5K_LAST_TSTP)); +} + +#define AR5K_KEYTABLE_0_5210 0x9000 +#define AR5K_KEYTABLE_0_5211 0x8800 +#define AR5K_KEYTABLE_0 (mac_version == AR5K_SREV_MAC_AR5210 ? \ + AR5K_KEYTABLE_0_5210 : \ + AR5K_KEYTABLE_0_5211) + +#define AR5K_KEYTABLE(_n) (AR5K_KEYTABLE_0_5211 + ((_n) << 5)) +#define AR5K_KEYTABLE_OFF(_n, x) (AR5K_KEYTABLE(_n) + ((x) << 2)) +#define AR5K_KEYTABLE_VALID 0x00008000 + +#define AR5K_KEYTABLE_SIZE_5210 64 +#define AR5K_KEYTABLE_SIZE_5211 128 +#define AR5K_KEYTABLE_SIZE (mac_version == AR5K_SREV_MAC_AR5210 ? \ + AR5K_KEYTABLE_SIZE_5210 : \ + AR5K_KEYTABLE_SIZE_5211) + +static void keycache_dump(void *mem, u_int16_t mac_version) +{ + int i, keylen; + u_int32_t val0, val1, val2, val3, val4, keytype, ant, mac0, mac1; + + /* dump all 128 entries */ + printf("Dumping keycache entries...\n"); + for (i = 0; i < AR5K_KEYTABLE_SIZE; i++) { + mac1 = AR5K_REG_READ(AR5K_KEYTABLE_OFF(i, 7)); + if (mac1 & AR5K_KEYTABLE_VALID) { + val0 = AR5K_REG_READ(AR5K_KEYTABLE_OFF(i, 0)); + val1 = AR5K_REG_READ(AR5K_KEYTABLE_OFF(i, 1)); + val2 = AR5K_REG_READ(AR5K_KEYTABLE_OFF(i, 2)); + val3 = AR5K_REG_READ(AR5K_KEYTABLE_OFF(i, 3)); + val4 = AR5K_REG_READ(AR5K_KEYTABLE_OFF(i, 4)); + keytype = AR5K_REG_READ(AR5K_KEYTABLE_OFF(i, 5)); + ant = keytype & 8; + keytype &= ~8; + switch (keytype) { + case 0: /* WEP40 */ keylen = 40 / 8; break; + case 1: /* WEP104 */ keylen = 104 / 8; break; + case 3: /* WEP128 */ keylen = 128 / 8; break; + case 4: /* TKIP */ keylen = 128 / 8; break; + case 5: /* AES */ keylen = 128 / 8; break; + case 6: /* CCM */ keylen = 128 / 8; break; + default: keylen = 0; break; + } + mac0 = AR5K_REG_READ(AR5K_KEYTABLE_OFF(i, 6)); + + printf("[%3u] keytype %d [%s%s%s%s%s%s%s%s] mac %02x:%02x:%02x:%02x:%02x:%02x key:%08x-%08x-%08x-%08x-%08x\n", + i, + keytype, + keytype == 0 ? "WEP40 " : "", + keytype == 1 ? "WEP104" : "", + keytype == 3 ? "WEP128" : "", + keytype == 4 ? "TKIP " : "", + keytype == 5 ? "AES " : "", + keytype == 6 ? "CCM " : "", + keytype == 7 ? "NULL " : "", + ant == 8 ? "+ANT" : "", + ((mac0 << 1) & 0xff), + ((mac0 >> 7) & 0xff), + ((mac0 >> 15) & 0xff), + ((mac0 >> 23) & 0xff), + ((mac1 << 1) & 0xff) | (mac0 >> 31), + ((mac1 >> 7) & 0xff), + val0, val1, val2, val3, val4); + } + } +} + +/* copy key index (0) to key index (idx) */ + +static void keycache_copy(void *mem, u_int16_t mac_version, int idx) +{ + u_int32_t val0, val1, val2, val3, val4, keytype, mac0, mac1; + + printf("Copying keycache entry 0 to %d\n", idx); + if (idx < 0 || idx >= AR5K_KEYTABLE_SIZE) { + printf("invalid keycache index\n"); + return; + } + + val0 = AR5K_REG_READ(AR5K_KEYTABLE_OFF(0, 0)); + val1 = AR5K_REG_READ(AR5K_KEYTABLE_OFF(0, 1)); + val2 = AR5K_REG_READ(AR5K_KEYTABLE_OFF(0, 2)); + val3 = AR5K_REG_READ(AR5K_KEYTABLE_OFF(0, 3)); + val4 = AR5K_REG_READ(AR5K_KEYTABLE_OFF(0, 4)); + keytype = AR5K_REG_READ(AR5K_KEYTABLE_OFF(0, 5)); + mac0 = AR5K_REG_READ(AR5K_KEYTABLE_OFF(0, 6)); + mac1 = AR5K_REG_READ(AR5K_KEYTABLE_OFF(0, 7)); + + AR5K_REG_WRITE(AR5K_KEYTABLE_OFF(idx, 0), val0); + AR5K_REG_WRITE(AR5K_KEYTABLE_OFF(idx, 1), val1); + AR5K_REG_WRITE(AR5K_KEYTABLE_OFF(idx, 2), val2); + AR5K_REG_WRITE(AR5K_KEYTABLE_OFF(idx, 3), val3); + AR5K_REG_WRITE(AR5K_KEYTABLE_OFF(idx, 4), val4); + AR5K_REG_WRITE(AR5K_KEYTABLE_OFF(idx, 5), keytype); + AR5K_REG_WRITE(AR5K_KEYTABLE_OFF(idx, 6), mac0); + AR5K_REG_WRITE(AR5K_KEYTABLE_OFF(idx, 7), mac1); +} + +static void sta_id0_id1_dump(void *mem) +{ +#define AR5K_STA_ID0 0x8000 +#define AR5K_STA_ID1 0x8004 +#define AR5K_STA_ID1_AP 0x00010000 +#define AR5K_STA_ID1_ADHOC 0x00020000 +#define AR5K_STA_ID1_NO_KEYSRCH 0x00080000 + + u_int32_t sta_id0, sta_id1; + + sta_id0 = AR5K_REG_READ(AR5K_STA_ID0); + sta_id1 = AR5K_REG_READ(AR5K_STA_ID1); + printf("STA_ID0: %02x:%02x:%02x:%02x:%02x:%02x\n", + (sta_id0 >> 0) & 0xff, + (sta_id0 >> 8) & 0xff, + (sta_id0 >> 16) & 0xff, + (sta_id0 >> 24) & 0xff, + (sta_id1 >> 0) & 0xff, + (sta_id1 >> 8) & 0xff); + printf("STA_ID1: 0x%08x, AP: %d, IBSS: %d, KeyCache Disable: %d\n", + sta_id1, + sta_id1 & AR5K_STA_ID1_AP ? 1 : 0, + sta_id1 & AR5K_STA_ID1_ADHOC ? 1 : 0, + sta_id1 & AR5K_STA_ID1_NO_KEYSRCH ? 1 : 0); +} + int CMD(athinfo)(int argc, char *argv[]) { - u_int32_t dev_addr; - u_int16_t eeprom_header, srev, phy_rev_5ghz, phy_rev_2ghz; - u_int16_t eeprom_version, mac_version, regdomain, has_crystal, ee_magic; - u_int8_t error, has_a, has_b, has_g, has_rfkill, eeprom_size; - int byte_size = 0; + unsigned long long dev_addr; + u_int16_t srev, phy_rev_5ghz, phy_rev_2ghz, ee_magic; + u_int8_t mac_version, mac_revision; + u_int8_t error, eeprom_size, dev_type, eemap; + struct ath5k_eeprom_info *ee; + unsigned int byte_size = 0; void *mem; int fd; - int i, anr = 1; + unsigned int i; + int anr = 1; int do_write = 0; /* default: read only */ int do_dump = 0; + int reg_read = 0; + int reg_write = 0; + unsigned int reg_write_val = 0; + unsigned int timer_count = 1; + int do_keycache_dump = 0; + int keycache_copy_idx = 0; struct { int valid; @@ -759,7 +1986,7 @@ CMD(athinfo)(int argc, char *argv[]) } gpio_set[AR5K_NUM_GPIO]; int nr_gpio_set = 0; - for (i = 0; i < sizeof(gpio_set) / sizeof(gpio_set[0]); i++) + for (i = 0; i < ARRAY_SIZE(gpio_set); i++) gpio_set[i].valid = 0; if (argc < 2) { @@ -769,6 +1996,15 @@ CMD(athinfo)(int argc, char *argv[]) while (anr < argc && argv[anr][0] == '-') { switch (argv[anr][1]) { + case 't': + if (++anr < argc) { + timer_count = atoi(argv[anr]); + printf("timer_count:%d\n", timer_count); + } else { + usage(argv[0]); + return 0; + } + break; case 'w': do_write = 1; break; @@ -777,7 +2013,7 @@ CMD(athinfo)(int argc, char *argv[]) if (strlen(argv[anr]) != 3 || argv[anr][1] != ':' || argv[anr][0] < '0' || argv[anr][0] > '5' || (argv[anr][2] != '0' && argv[anr][2] != '1')) { - err("invalid gpio spec. %s", argv[anr]); + err("invalid GPIO spec. %s", argv[anr]); return 2; } gpio_set[argv[anr][0] - '0'].valid = 1; @@ -797,6 +2033,25 @@ CMD(athinfo)(int argc, char *argv[]) do_dump = 1; break; + case 'R': + anr++; + reg_read = strtoul(argv[anr], NULL, 16); + break; + + case 'W': + anr++; + reg_write = strtoul(argv[anr++], NULL, 16); + reg_write_val = strtoul(argv[anr], NULL, 16); + break; + + case 'k': + do_keycache_dump = 1; + break; + + case 'K': + keycache_copy_idx = atoi(argv[++anr]); + break; + case 'h': usage(argv[0]); return 0; @@ -805,10 +2060,10 @@ CMD(athinfo)(int argc, char *argv[]) default: err("unknown option %s", argv[anr]); return 2; - } /* switch (argv[anr][1]) */ + } anr++; - } /* while (anr < argc && ...) */ + } if (anr >= argc) { err("missing device address"); @@ -816,7 +2071,7 @@ CMD(athinfo)(int argc, char *argv[]) return 3; } - dev_addr = strtoul(argv[anr], NULL, 16); + dev_addr = strtoull(argv[anr], NULL, 16); fd = open("/dev/mem", O_RDWR); if (fd < 0) { @@ -828,7 +2083,7 @@ CMD(athinfo)(int argc, char *argv[]) MAP_SHARED | MAP_FILE, fd, dev_addr); if (mem == MAP_FAILED) { - printf("Mmap of device at 0x%08X for 0x%X bytes failed - " + printf("mmap of device at 0x%08llX for 0x%X bytes failed - " "%s\n", dev_addr, AR5K_PCI_MEM_SIZE, strerror(errno)); return -3; } @@ -856,10 +2111,31 @@ CMD(athinfo)(int argc, char *argv[]) AR5K_REG_DISABLE_BITS(AR5K_PCICFG, AR5K_PCICFG_SPWR_DN); usleep(500); + if (reg_read) { + printf("READ %04x = %08x\n", reg_read, AR5K_REG_READ(reg_read)); + return 0; + } + + if (reg_write) { + printf("WRITE %04x = %08x\n", reg_write, reg_write_val); + AR5K_REG_WRITE(reg_write, reg_write_val); + return 0; + } + srev = AR5K_REG_READ(AR5K_SREV); - mac_version = AR5K_REG_MS(srev, AR5K_SREV_VER) << 4; + if (srev >= 0x0100) { + printf("MAC revision 0x%04x is not supported!\n", srev); + return -1; + } + mac_version = srev & AR5K_SREV_VER; + mac_revision = srev & AR5K_SREV_REV; - /* Verify eeprom magic value first */ + printf(" -==Device Information==-\n"); + + printf("MAC Revision: %-5s (0x%02x)\n", + ath5k_hw_get_mac_name(mac_revision), mac_revision); + + /* Verify EEPROM magic value first */ error = ath5k_hw_eeprom_read(mem, AR5K_EEPROM_MAGIC, &ee_magic, mac_version); @@ -872,157 +2148,114 @@ CMD(athinfo)(int argc, char *argv[]) printf("Warning: Invalid EEPROM Magic number!\n"); } - error = ath5k_hw_eeprom_read(mem, AR5K_EEPROM_HDR, &eeprom_header, - mac_version); - - if (error) { - printf("Unable to read EEPROM Header!\n"); - return -1; - } - - error = ath5k_hw_eeprom_read(mem, AR5K_EEPROM_VERSION, &eeprom_version, - mac_version); - - if (error) { - printf("Unable to read EEPROM version!\n"); + ee = calloc(sizeof(struct ath5k_eeprom_info), 1); + if (!ee) { + printf("Cannot allocate memory for EEPROM information\n"); return -1; } - error = ath5k_hw_eeprom_read(mem, AR5K_EEPROM_REG_DOMAIN, ®domain, - mac_version); - - if (error) { - printf("Unable to read Regdomain!\n"); + if (ath5k_eeprom_init(mem, mac_version, ee)) { + printf("EEPROM init failed\n"); return -1; } - if (eeprom_version >= 0x4000) { - error = ath5k_hw_eeprom_read(mem, AR5K_EEPROM_MISC0, - &has_crystal, mac_version); - - if (error) { - printf("Unable to read EEPROM Misc data!\n"); - return -1; - } - - has_crystal = AR5K_EEPROM_HAS32KHZCRYSTAL(has_crystal); - } else { - has_crystal = 2; - } - eeprom_size = AR5K_REG_MS(AR5K_REG_READ(AR5K_PCICFG), AR5K_PCICFG_EESIZE); - has_a = AR5K_EEPROM_HDR_11A(eeprom_header); - has_b = AR5K_EEPROM_HDR_11B(eeprom_header); - has_g = AR5K_EEPROM_HDR_11G(eeprom_header); - has_rfkill = AR5K_EEPROM_HDR_RFKILL(eeprom_header); + dev_type = AR5K_EEPROM_HDR_DEVICE(ee->ee_header); + eemap = AR5K_EEPROM_EEMAP(ee->ee_misc0); - if (has_a) + /* 1 = ?? 2 = ?? 3 = card 4 = wmac */ + printf("Device type: %1i\n", dev_type); + + if (AR5K_EEPROM_HDR_11A(ee->ee_header)) phy_rev_5ghz = ath5k_hw_radio_revision(mac_version, mem, 1); else phy_rev_5ghz = 0; - if (has_b) + if (AR5K_EEPROM_HDR_11B(ee->ee_header)) phy_rev_2ghz = ath5k_hw_radio_revision(mac_version, mem, 0); else phy_rev_2ghz = 0; - printf(" -==Device Information==-\n"); - - printf("MAC Version: %-5s (0x%02x)\n", - ath5k_hw_get_part_name(AR5K_VERSION_VER, mac_version), - mac_version); - - printf("MAC Revision: %-5s (0x%02x)\n", - ath5k_hw_get_part_name(AR5K_VERSION_VER, srev), srev); - - /* Single-chip PHY with a/b/g support */ - if (has_b && !phy_rev_2ghz) { - printf("PHY Revision: %-5s (0x%02x)\n", - ath5k_hw_get_part_name(AR5K_VERSION_RAD, phy_rev_5ghz), - phy_rev_5ghz); - phy_rev_5ghz = 0; - } - - /* Single-chip PHY with b/g support */ - if (!has_a) { - printf("PHY Revision: %-5s (0x%02x)\n", - ath5k_hw_get_part_name(AR5K_VERSION_RAD, phy_rev_2ghz), - phy_rev_2ghz); - phy_rev_2ghz = 0; - } - - /* Different chip for 5Ghz and 2Ghz */ if (phy_rev_5ghz) { - printf("5Ghz PHY Revision: %-5s (0x%2x)\n", - ath5k_hw_get_part_name(AR5K_VERSION_RAD, phy_rev_5ghz), - phy_rev_5ghz); + printf("5GHz PHY Revision: %-5s (0x%02x)\n", + ath5k_hw_get_phy_name(phy_rev_5ghz), phy_rev_5ghz); } if (phy_rev_2ghz) { - printf("2Ghz PHY Revision: %-5s (0x%2x)\n", - ath5k_hw_get_part_name(AR5K_VERSION_RAD, phy_rev_2ghz), - phy_rev_2ghz); + printf("2GHz PHY Revision: %-5s (0x%02x)\n", + ath5k_hw_get_phy_name(phy_rev_2ghz), phy_rev_2ghz); } - printf(" -==EEPROM Information==-\n"); - - printf("EEPROM Version: %x.%x\n", - (eeprom_version & 0xF000) >> 12, eeprom_version & 0xFFF); + printf("\n"); + printf("/============== EEPROM Information =============\\\n"); + printf("| EEPROM Version: %1x.%1x |", + (ee->ee_version & 0xF000) >> 12, ee->ee_version & 0xFFF); - printf("EEPROM Size: "); + printf(" EEPROM Size: "); if (eeprom_size == 0) { - printf(" 4K\n"); - byte_size = 4096; + printf(" 4 kbit |\n"); + byte_size = 4096 / 8; } else if (eeprom_size == 1) { - printf(" 8K\n"); - byte_size = 8192; + printf(" 8 kbit |\n"); + byte_size = 8192 / 8; } else if (eeprom_size == 2) { - printf(" 16K\n"); - byte_size = 16384; + printf(" 16 kbit |\n"); + byte_size = 16384 / 8; } else - printf(" ??\n"); + printf(" unknown |\n"); - printf("Regulatory Domain: 0x%X\n", regdomain); - - printf(" -==== Capabilities ====-\n"); - - printf("| 802.11a Support: "); - if (has_a) - printf("yes |\n"); - else - printf("no |\n"); - - printf("| 802.11b Support: "); - if (has_b) - printf("yes |\n"); - else - printf("no |\n"); + printf("| EEMAP: %i |", eemap); - printf("| 802.11g Support: "); - if (has_g) - printf("yes |\n"); - else - printf("no |\n"); + printf(" Reg. Domain: 0x%02X |\n", ee->ee_regdomain); - printf("| RFKill Support: "); - if (has_rfkill) - printf("yes |\n"); - else - printf("no |\n"); + dump_capabilities(ee); + printf("\n"); - if (has_crystal != 2) { - printf("| 32KHz Crystal: "); - if (has_crystal) - printf("yes |\n"); - else - printf("no |\n"); + printf("/=========================================================\\\n"); + printf("| Calibration data common for all modes |\n"); + printf("|=========================================================|\n"); + printf("| CCK/OFDM gain delta: %2i |\n", ee->ee_cck_ofdm_gain_delta); + printf("| CCK/OFDM power delta: %2i |\n", ee->ee_cck_ofdm_power_delta); + printf("| Scaled CCK delta: %2i |\n", ee->ee_scaled_cck_delta); + printf("| 2GHz Antenna gain: %2i |\n", AR5K_EEPROM_ANT_GAIN_2GHZ(ee->ee_ant_gain)); + printf("| 5GHz Antenna gain: %2i |\n", AR5K_EEPROM_ANT_GAIN_5GHZ(ee->ee_ant_gain)); + printf("| Turbo 2W maximum dBm: %2i |\n", AR5K_EEPROM_HDR_T_5GHZ_DBM(ee->ee_header)); + printf("| Target power start: 0x%03x |\n", AR5K_EEPROM_TARGET_PWRSTART(ee->ee_misc1)); + printf("| EAR Start: 0x%03x |\n", AR5K_EEPROM_EARSTART(ee->ee_misc0)); + printf("\\=========================================================/\n"); + + printf("\n"); + if (AR5K_EEPROM_HDR_11A(ee->ee_header)) { + printf("/=========================================================\\\n"); + printf("| Calibration data for 802.11a operation |\n"); + dump_calinfo_for_mode(AR5K_EEPROM_MODE_11A, ee); + dump_rate_calinfo_for_mode(AR5K_EEPROM_MODE_11A, ee); + dump_power_calinfo_for_mode(AR5K_EEPROM_MODE_11A, ee); + printf("\n"); + } + + if (AR5K_EEPROM_HDR_11B(ee->ee_header)) { + printf("/=========================================================\\\n"); + printf("| Calibration data for 802.11b operation |\n"); + dump_calinfo_for_mode(AR5K_EEPROM_MODE_11B, ee); + dump_rate_calinfo_for_mode(AR5K_EEPROM_MODE_11B, ee); + dump_power_calinfo_for_mode(AR5K_EEPROM_MODE_11B, ee); + printf("\n"); + } + + if (AR5K_EEPROM_HDR_11G(ee->ee_header)) { + printf("/=========================================================\\\n"); + printf("| Calibration data for 802.11g operation |\n"); + dump_calinfo_for_mode(AR5K_EEPROM_MODE_11G, ee); + dump_rate_calinfo_for_mode(AR5K_EEPROM_MODE_11G, ee); + dump_power_calinfo_for_mode(AR5K_EEPROM_MODE_11G, ee); + printf("\n"); } - printf(" ========================\n"); /* print current GPIO settings */ - printf("GPIO registers: CR %08x DO %08x DI %08x\n", + printf("GPIO registers: CR 0x%08x, DO 0x%08x, DI 0x%08x\n", AR5K_REG_READ(AR5K_GPIOCR), AR5K_REG_READ(AR5K_GPIODO), AR5K_REG_READ(AR5K_GPIODI)); @@ -1030,18 +2263,18 @@ CMD(athinfo)(int argc, char *argv[]) u_int16_t data; FILE *dumpfile = fopen("ath-eeprom-dump.bin", "w"); - printf("\nEEPROM dump (%d byte)\n", byte_size); + printf("\nEEPROM dump (%d bytes)\n", byte_size); printf("=============================================="); - for (i = 1; i <= (byte_size / 2); i++) { + for (i = 0; i < byte_size / 2; i++) { error = ath5k_hw_eeprom_read(mem, i, &data, mac_version); if (error) { printf("\nUnable to read at %04x\n", i); continue; } - if (!((i - 1) % 8)) - printf("\n%04x: ", i); - printf("%04x ", data); + if (!(i % 8)) + printf("\n%04x: ", i); + printf(" %04x", data); fwrite(&data, 2, 1, dumpfile); } printf("\n==============================================\n"); @@ -1054,18 +2287,18 @@ CMD(athinfo)(int argc, char *argv[]) u_int32_t old_cr = rcr, old_do = rdo; int rc; - if (mac_version >= AR5K_SREV_VER_AR5213 && !nr_gpio_set) { - dbg("new MAC %x (>= AR5213) set gpio4 to low", + if (mac_version >= AR5K_SREV_MAC_AR5213 && !nr_gpio_set) { + dbg("new MAC %x (>= AR5213) set GPIO4 to low", mac_version); gpio_set[4].valid = 1; gpio_set[4].value = 0; } - /* set gpios */ + /* set GPIOs */ dbg("old GPIO CR %08x DO %08x DI %08x", rcr, rdo, AR5K_REG_READ(AR5K_GPIODI)); - for (i = 0; i < sizeof(gpio_set) / sizeof(gpio_set[0]); i++) { + for (i = 0; i < ARRAY_SIZE(gpio_set); i++) { if (gpio_set[i].valid) { rcr |= AR5K_GPIOCR_OUT(i); /* we use mode 3 */ rcr &= ~AR5K_GPIOCR_INT_SEL(i); @@ -1111,5 +2344,17 @@ CMD(athinfo)(int argc, char *argv[]) return rc; } + + sta_id0_id1_dump(mem); + + for (i = 0; i < timer_count; i++) + dump_timers_register(mem, mac_version); + + if (do_keycache_dump) + keycache_dump(mem, mac_version); + + if (keycache_copy_idx > 0) + keycache_copy(mem, mac_version, keycache_copy_idx); + return 0; }