Commit 488f6ba7 authored by Felix Fietkau's avatar Felix Fietkau Committed by John W. Linville

ath9k_hw: add support for reading EEPROM data from the internal OTP ROM

Some of the new AR9003 cards do not come with an external EEPROM chip
anymore. Calibration data on these cards is stored in the OTP ROM on
the chip.
This patch adds support for reading this data, and also adds support
for different EEPROM chip sizes (512 bytes instead of 1K).
Signed-off-by: default avatarFelix Fietkau <nbd@openwrt.org>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 2d42efc4
...@@ -3104,6 +3104,36 @@ static bool ar9300_read_eeprom(struct ath_hw *ah, int address, u8 *buffer, ...@@ -3104,6 +3104,36 @@ static bool ar9300_read_eeprom(struct ath_hw *ah, int address, u8 *buffer,
return false; return false;
} }
static bool ar9300_otp_read_word(struct ath_hw *ah, int addr, u32 *data)
{
REG_READ(ah, AR9300_OTP_BASE + (4 * addr));
if (!ath9k_hw_wait(ah, AR9300_OTP_STATUS, AR9300_OTP_STATUS_TYPE,
AR9300_OTP_STATUS_VALID, 1000))
return false;
*data = REG_READ(ah, AR9300_OTP_READ_DATA);
return true;
}
static bool ar9300_read_otp(struct ath_hw *ah, int address, u8 *buffer,
int count)
{
u32 data;
int i;
for (i = 0; i < count; i++) {
int offset = 8 * ((address - i) % 4);
if (!ar9300_otp_read_word(ah, (address - i) / 4, &data))
return false;
buffer[i] = (data >> offset) & 0xff;
}
return true;
}
static void ar9300_comp_hdr_unpack(u8 *best, int *code, int *reference, static void ar9300_comp_hdr_unpack(u8 *best, int *code, int *reference,
int *length, int *major, int *minor) int *length, int *major, int *minor)
{ {
...@@ -3221,6 +3251,26 @@ static int ar9300_compress_decision(struct ath_hw *ah, ...@@ -3221,6 +3251,26 @@ static int ar9300_compress_decision(struct ath_hw *ah,
return 0; return 0;
} }
typedef bool (*eeprom_read_op)(struct ath_hw *ah, int address, u8 *buffer,
int count);
static bool ar9300_check_header(void *data)
{
u32 *word = data;
return !(*word == 0 || *word == ~0);
}
static bool ar9300_check_eeprom_header(struct ath_hw *ah, eeprom_read_op read,
int base_addr)
{
u8 header[4];
if (!read(ah, base_addr, header, 4))
return false;
return ar9300_check_header(header);
}
/* /*
* Read the configuration data from the eeprom. * Read the configuration data from the eeprom.
* The data can be put in any specified memory buffer. * The data can be put in any specified memory buffer.
...@@ -3241,6 +3291,7 @@ static int ar9300_eeprom_restore_internal(struct ath_hw *ah, ...@@ -3241,6 +3291,7 @@ static int ar9300_eeprom_restore_internal(struct ath_hw *ah,
int it; int it;
u16 checksum, mchecksum; u16 checksum, mchecksum;
struct ath_common *common = ath9k_hw_common(ah); struct ath_common *common = ath9k_hw_common(ah);
eeprom_read_op read;
word = kzalloc(2048, GFP_KERNEL); word = kzalloc(2048, GFP_KERNEL);
if (!word) if (!word)
...@@ -3248,14 +3299,42 @@ static int ar9300_eeprom_restore_internal(struct ath_hw *ah, ...@@ -3248,14 +3299,42 @@ static int ar9300_eeprom_restore_internal(struct ath_hw *ah,
memcpy(mptr, &ar9300_default, mdata_size); memcpy(mptr, &ar9300_default, mdata_size);
read = ar9300_read_eeprom;
cptr = AR9300_BASE_ADDR; cptr = AR9300_BASE_ADDR;
ath_print(common, ATH_DBG_EEPROM,
"Trying EEPROM accesss at Address 0x%04x\n", cptr);
if (ar9300_check_eeprom_header(ah, read, cptr))
goto found;
cptr = AR9300_BASE_ADDR_512;
ath_print(common, ATH_DBG_EEPROM,
"Trying EEPROM accesss at Address 0x%04x\n", cptr);
if (ar9300_check_eeprom_header(ah, read, cptr))
goto found;
read = ar9300_read_otp;
cptr = AR9300_BASE_ADDR;
ath_print(common, ATH_DBG_EEPROM,
"Trying OTP accesss at Address 0x%04x\n", cptr);
if (ar9300_check_eeprom_header(ah, read, cptr))
goto found;
cptr = AR9300_BASE_ADDR_512;
ath_print(common, ATH_DBG_EEPROM,
"Trying OTP accesss at Address 0x%04x\n", cptr);
if (ar9300_check_eeprom_header(ah, read, cptr))
goto found;
goto fail;
found:
ath_print(common, ATH_DBG_EEPROM, "Found valid EEPROM data");
for (it = 0; it < MSTATE; it++) { for (it = 0; it < MSTATE; it++) {
if (!ar9300_read_eeprom(ah, cptr, word, COMP_HDR_LEN)) if (!read(ah, cptr, word, COMP_HDR_LEN))
goto fail; goto fail;
if ((word[0] == 0 && word[1] == 0 && word[2] == 0 && if (!ar9300_check_header(word))
word[3] == 0) || (word[0] == 0xff && word[1] == 0xff
&& word[2] == 0xff && word[3] == 0xff))
break; break;
ar9300_comp_hdr_unpack(word, &code, &reference, ar9300_comp_hdr_unpack(word, &code, &reference,
...@@ -3272,8 +3351,7 @@ static int ar9300_eeprom_restore_internal(struct ath_hw *ah, ...@@ -3272,8 +3351,7 @@ static int ar9300_eeprom_restore_internal(struct ath_hw *ah,
} }
osize = length; osize = length;
ar9300_read_eeprom(ah, cptr, word, read(ah, cptr, word, COMP_HDR_LEN + osize + COMP_CKSUM_LEN);
COMP_HDR_LEN + osize + COMP_CKSUM_LEN);
checksum = ar9300_comp_cksum(&word[COMP_HDR_LEN], length); checksum = ar9300_comp_cksum(&word[COMP_HDR_LEN], length);
mchecksum = word[COMP_HDR_LEN + osize] | mchecksum = word[COMP_HDR_LEN + osize] |
(word[COMP_HDR_LEN + osize + 1] << 8); (word[COMP_HDR_LEN + osize + 1] << 8);
......
...@@ -79,6 +79,15 @@ ...@@ -79,6 +79,15 @@
#define FIXED_CCA_THRESHOLD 15 #define FIXED_CCA_THRESHOLD 15
#define AR9300_BASE_ADDR 0x3ff #define AR9300_BASE_ADDR 0x3ff
#define AR9300_BASE_ADDR_512 0x1ff
#define AR9300_OTP_BASE 0x14000
#define AR9300_OTP_STATUS 0x15f18
#define AR9300_OTP_STATUS_TYPE 0x7
#define AR9300_OTP_STATUS_VALID 0x4
#define AR9300_OTP_STATUS_ACCESS_BUSY 0x2
#define AR9300_OTP_STATUS_SM_BUSY 0x1
#define AR9300_OTP_READ_DATA 0x15f1c
enum targetPowerHTRates { enum targetPowerHTRates {
HT_TARGET_RATE_0_8_16, HT_TARGET_RATE_0_8_16,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment