/*
* Copyright (c) 2008-2009 Atheros Communications Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "hw.h"
#include "ar9002_phy.h"
static int ath9k_hw_4k_get_eeprom_ver(struct ath_hw *ah)
{
return ((ah->eeprom.map4k.baseEepHeader.version >> 12) & 0xF);
}
static int ath9k_hw_4k_get_eeprom_rev(struct ath_hw *ah)
{
return ((ah->eeprom.map4k.baseEepHeader.version) & 0xFFF);
}
#define SIZE_EEPROM_4K (sizeof(struct ar5416_eeprom_4k) / sizeof(u16))
static bool __ath9k_hw_4k_fill_eeprom(struct ath_hw *ah)
{
struct ath_common *common = ath9k_hw_common(ah);
u16 *eep_data = (u16 *)&ah->eeprom.map4k;
int addr, eep_start_loc = 64;
for (addr = 0; addr < SIZE_EEPROM_4K; addr++) {
if (!ath9k_hw_nvram_read(common, addr + eep_start_loc, eep_data)) {
ath_dbg(common, ATH_DBG_EEPROM,
"Unable to read eeprom region\n");
return false;
}
eep_data++;
}
return true;
}
static bool __ath9k_hw_usb_4k_fill_eeprom(struct ath_hw *ah)
{
u16 *eep_data = (u16 *)&ah->eeprom.map4k;
ath9k_hw_usb_gen_fill_eeprom(ah, eep_data, 64, SIZE_EEPROM_4K);
return true;
}
static bool ath9k_hw_4k_fill_eeprom(struct ath_hw *ah)
{
struct ath_common *common = ath9k_hw_common(ah);
if (!ath9k_hw_use_flash(ah)) {
ath_dbg(common, ATH_DBG_EEPROM,
"Reading from EEPROM, not flash\n");
}
if (common->bus_ops->ath_bus_type == ATH_USB)
return __ath9k_hw_usb_4k_fill_eeprom(ah);
else
return __ath9k_hw_4k_fill_eeprom(ah);
}
#undef SIZE_EEPROM_4K
static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah)
{
#define EEPROM_4K_SIZE (sizeof(struct ar5416_eeprom_4k) / sizeof(u16))
struct ath_common *common = ath9k_hw_common(ah);
struct ar5416_eeprom_4k *eep =
(struct ar5416_eeprom_4k *) &ah->eeprom.map4k;
u16 *eepdata, temp, magic, magic2;
u32 sum = 0, el;
bool need_swap = false;
int i, addr;
if (!ath9k_hw_use_flash(ah)) {
if (!ath9k_hw_nvram_read(common, AR5416_EEPROM_MAGIC_OFFSET,
&magic)) {
ath_err(common, "Reading Magic # failed\n");
return false;
}
ath_dbg(common, ATH_DBG_EEPROM,
"Read Magic = 0x%04X\n", magic);
if (magic != AR5416_EEPROM_MAGIC) {
magic2 = swab16(magic);
if (magic2 == AR5416_EEPROM_MAGIC) {
need_swap = true;
eepdata = (u16 *) (&ah->eeprom);
for (addr = 0; addr < EEPROM_4K_SIZE; addr++) {
temp = swab16(*eepdata);
*eepdata = temp;
eepdata++;
}
} else {
ath_err(common,
"Invalid EEPROM Magic. Endianness mismatch.\n");
return -EINVAL;
}
}
}
ath_dbg(common, ATH_DBG_EEPROM, "need_swap = %s.\n",
need_swap ? "True" : "False");
if (need_swap)
el = swab16(ah->eeprom.map4k.baseEepHeader.length);
else
el = ah->eeprom.map4k.baseEepHeader.length;
if (el > sizeof(struct ar5416_eeprom_4k))
el = sizeof(struct