ah_eeprom_v1.c revision 204644
192494Ssobomax/* 292494Ssobomax * Copyright (c) 2008 Sam Leffler, Errno Consulting 392494Ssobomax * Copyright (c) 2008 Atheros Communications, Inc. 492494Ssobomax * 592494Ssobomax * Permission to use, copy, modify, and/or distribute this software for any 692494Ssobomax * purpose with or without fee is hereby granted, provided that the above 792494Ssobomax * copyright notice and this permission notice appear in all copies. 892494Ssobomax * 992494Ssobomax * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1092494Ssobomax * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1192494Ssobomax * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1292494Ssobomax * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1392494Ssobomax * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1492494Ssobomax * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1592494Ssobomax * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1692494Ssobomax * 1792494Ssobomax * $FreeBSD: head/sys/dev/ath/ath_hal/ah_eeprom_v1.c 204644 2010-03-03 17:32:32Z rpaulo $ 1892494Ssobomax */ 1992494Ssobomax#include "opt_ah.h" 2092494Ssobomax 2192494Ssobomax#include "ah.h" 2292494Ssobomax#include "ah_internal.h" 2392494Ssobomax#include "ah_eeprom_v1.h" 2492494Ssobomax 2592494Ssobomaxstatic HAL_STATUS 2692494Ssobomaxv1EepromGet(struct ath_hal *ah, int param, void *val) 2792494Ssobomax{ 2892494Ssobomax HAL_EEPROM_v1 *ee = AH_PRIVATE(ah)->ah_eeprom; 2992494Ssobomax uint32_t sum; 3092494Ssobomax uint16_t eeval; 3192494Ssobomax uint8_t *macaddr; 3292494Ssobomax int i; 3392494Ssobomax 3492494Ssobomax switch (param) { 3592494Ssobomax case AR_EEP_MACADDR: /* Get MAC Address */ 3692494Ssobomax sum = 0; 3792494Ssobomax macaddr = val; 3892494Ssobomax for (i = 0; i < 3; i++) { 3992494Ssobomax if (!ath_hal_eepromRead(ah, AR_EEPROM_MAC(i), &eeval)) { 4092494Ssobomax HALDEBUG(ah, HAL_DEBUG_ANY, 4192494Ssobomax "%s: cannot read EEPROM location %u\n", 4292494Ssobomax __func__, i); 4392494Ssobomax return HAL_EEREAD; 4492494Ssobomax } 4592494Ssobomax sum += eeval; 4692494Ssobomax macaddr[2*i + 0] = eeval >> 8; 47124572Sjhb macaddr[2*i + 1] = eeval & 0xff; 4892494Ssobomax } 4992494Ssobomax if (sum == 0 || sum == 0xffff*3) { 5092494Ssobomax HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad mac address %s\n", 5192494Ssobomax __func__, ath_hal_ether_sprintf(macaddr)); 5292494Ssobomax return HAL_EEBADMAC; 5392494Ssobomax } 5492494Ssobomax return HAL_OK; 5592494Ssobomax case AR_EEP_REGDMN_0: 5692494Ssobomax *(uint16_t *) val = ee->ee_regDomain[0]; 5792494Ssobomax return HAL_OK; 5892494Ssobomax case AR_EEP_RFKILL: 5992494Ssobomax HALASSERT(val == AH_NULL); 6092494Ssobomax return ee->ee_rfKill ? HAL_OK : HAL_EIO; 6192494Ssobomax case AR_EEP_WRITEPROTECT: 6292494Ssobomax HALASSERT(val == AH_NULL); 6392494Ssobomax return (ee->ee_protect & AR_EEPROM_PROTOTECT_WP_128_191) ? 6492494Ssobomax HAL_OK : HAL_EIO; 6592494Ssobomax default: 6692494Ssobomax HALASSERT(0); 6792494Ssobomax return HAL_EINVAL; 68124571Sjhb } 6992494Ssobomax} 70124571Sjhb 7192494Ssobomaxstatic HAL_BOOL 7292494Ssobomaxv1EepromSet(struct ath_hal *ah, int param, int v) 7392494Ssobomax{ 7492494Ssobomax return HAL_EINVAL; 7592494Ssobomax} 7692494Ssobomax 77124571Sjhbstatic HAL_BOOL 78124571Sjhbv1EepromDiag(struct ath_hal *ah, int request, 7992494Ssobomax const void *args, uint32_t argsize, void **result, uint32_t *resultsize) 8092494Ssobomax{ 8192494Ssobomax HAL_EEPROM_v1 *ee = AH_PRIVATE(ah)->ah_eeprom; 82124572Sjhb 83124572Sjhb switch (request) { 84124572Sjhb case HAL_DIAG_EEPROM: 85124572Sjhb *result = ee; 86124572Sjhb *resultsize = sizeof(*ee); 87124572Sjhb return AH_TRUE; 88124572Sjhb } 89124572Sjhb return AH_FALSE; 90124572Sjhb} 91124572Sjhb 92124572Sjhbstatic uint16_t 93124572Sjhbv1EepromGetSpurChan(struct ath_hal *ah, int ix, HAL_BOOL is2GHz) 94124572Sjhb{ 95124572Sjhb return AR_NO_SPUR; 96124572Sjhb} 97124572Sjhb 98124572Sjhb/* 99124572Sjhb * Reclaim any EEPROM-related storage. 100124572Sjhb */ 101124572Sjhbstatic void 102124572Sjhbv1EepromDetach(struct ath_hal *ah) 103124572Sjhb{ 10492494Ssobomax HAL_EEPROM_v1 *ee = AH_PRIVATE(ah)->ah_eeprom; 10592494Ssobomax 10692494Ssobomax ath_hal_free(ee); 10792494Ssobomax AH_PRIVATE(ah)->ah_eeprom = AH_NULL; 10892494Ssobomax} 10992494Ssobomax 11092494SsobomaxHAL_STATUS 11192494Ssobomaxath_hal_v1EepromAttach(struct ath_hal *ah) 11292494Ssobomax{ 11392494Ssobomax HAL_EEPROM_v1 *ee = AH_PRIVATE(ah)->ah_eeprom; 11492494Ssobomax uint16_t athvals[AR_EEPROM_ATHEROS_MAX]; /* XXX off stack */ 11592494Ssobomax uint16_t protect, version, eeval; 11692494Ssobomax uint32_t sum; 11792494Ssobomax int i, loc; 11892494Ssobomax 11992494Ssobomax HALASSERT(ee == AH_NULL); 12092494Ssobomax 12192494Ssobomax if (!ath_hal_eepromRead(ah, AR_EEPROM_MAGIC, &eeval)) { 12292494Ssobomax HALDEBUG(ah, HAL_DEBUG_ANY, 12392494Ssobomax "%s: cannot read EEPROM magic number\n", __func__); 12492494Ssobomax return HAL_EEREAD; 12592494Ssobomax } 12692494Ssobomax if (eeval != 0x5aa5) { 12792494Ssobomax HALDEBUG(ah, HAL_DEBUG_ANY, 12892494Ssobomax "%s: invalid EEPROM magic number 0x%x\n", __func__, eeval); 12992494Ssobomax return HAL_EEMAGIC; 13092494Ssobomax } 13192494Ssobomax 13292494Ssobomax if (!ath_hal_eepromRead(ah, AR_EEPROM_PROTECT, &protect)) { 13392494Ssobomax HALDEBUG(ah, HAL_DEBUG_ANY, 13492494Ssobomax "%s: cannot read EEPROM protection bits; read locked?\n", 13592494Ssobomax __func__); 13692494Ssobomax return HAL_EEREAD; 13792494Ssobomax } 13892494Ssobomax HALDEBUG(ah, HAL_DEBUG_ATTACH, "EEPROM protect 0x%x\n", protect); 13992494Ssobomax /* XXX check proper access before continuing */ 14092494Ssobomax 14192494Ssobomax if (!ath_hal_eepromRead(ah, AR_EEPROM_VERSION, &version)) { 14292494Ssobomax HALDEBUG(ah, HAL_DEBUG_ANY, 14392494Ssobomax "%s: unable to read EEPROM version\n", __func__); 14492494Ssobomax return HAL_EEREAD; 14592494Ssobomax } 14692494Ssobomax if (((version>>12) & 0xf) != 1) { 14792494Ssobomax /* 14892494Ssobomax * This code only groks the version 1 EEPROM layout. 14992494Ssobomax */ 15092494Ssobomax HALDEBUG(ah, HAL_DEBUG_ANY, 15192494Ssobomax "%s: unsupported EEPROM version 0x%x found\n", 15292494Ssobomax __func__, version); 15392494Ssobomax return HAL_EEVERSION; 15492494Ssobomax } 15592494Ssobomax 15692494Ssobomax /* 15792494Ssobomax * Read the Atheros EEPROM entries and calculate the checksum. 15892494Ssobomax */ 15992494Ssobomax sum = 0; 16092494Ssobomax for (i = 0; i < AR_EEPROM_ATHEROS_MAX; i++) { 16192494Ssobomax if (!ath_hal_eepromRead(ah, AR_EEPROM_ATHEROS(i), &athvals[i])) 16292494Ssobomax return HAL_EEREAD; 16392494Ssobomax sum ^= athvals[i]; 16492494Ssobomax } 165124572Sjhb if (sum != 0xffff) { 16692494Ssobomax HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad EEPROM checksum 0x%x\n", 16792494Ssobomax __func__, sum); 16892494Ssobomax return HAL_EEBADSUM; 169124572Sjhb } 170124572Sjhb 171124572Sjhb /* 172124572Sjhb * Valid checksum, fetch the regulatory domain and save values. 173124572Sjhb */ 17492494Ssobomax if (!ath_hal_eepromRead(ah, AR_EEPROM_REG_DOMAIN, &eeval)) { 17592494Ssobomax HALDEBUG(ah, HAL_DEBUG_ANY, 17692494Ssobomax "%s: cannot read regdomain from EEPROM\n", __func__); 17792494Ssobomax return HAL_EEREAD; 17892494Ssobomax } 17992494Ssobomax 18092494Ssobomax ee = ath_hal_malloc(sizeof(HAL_EEPROM_v1)); 18192494Ssobomax if (ee == AH_NULL) { 18292494Ssobomax /* XXX message */ 18392494Ssobomax return HAL_ENOMEM; 18492494Ssobomax } 18592494Ssobomax 18692494Ssobomax ee->ee_version = version; 18792494Ssobomax ee->ee_protect = protect; 18892494Ssobomax ee->ee_antenna = athvals[2]; 18992494Ssobomax ee->ee_biasCurrents = athvals[3]; 19092494Ssobomax ee->ee_thresh62 = athvals[4] & 0xff; 19192494Ssobomax ee->ee_xlnaOn = (athvals[4] >> 8) & 0xff; 19292494Ssobomax ee->ee_xpaOn = athvals[5] & 0xff; 19392494Ssobomax ee->ee_xpaOff = (athvals[5] >> 8) & 0xff; 19492494Ssobomax ee->ee_regDomain[0] = (athvals[6] >> 8) & 0xff; 195146443Scharnier ee->ee_regDomain[1] = athvals[6] & 0xff; 196146443Scharnier ee->ee_regDomain[2] = (athvals[7] >> 8) & 0xff; 19792494Ssobomax ee->ee_regDomain[3] = athvals[7] & 0xff; 19892494Ssobomax ee->ee_rfKill = athvals[8] & 0x1; 19992494Ssobomax ee->ee_devType = (athvals[8] >> 1) & 0x7; 20092494Ssobomax 20192494Ssobomax for (i = 0, loc = AR_EEPROM_ATHEROS_TP_SETTINGS; i < AR_CHANNELS_MAX; i++, loc += AR_TP_SETTINGS_SIZE) { 20292494Ssobomax struct tpcMap *chan = &ee->ee_tpc[i]; 20392494Ssobomax 20492494Ssobomax /* Copy pcdac and gain_f values from EEPROM */ 20592494Ssobomax chan->pcdac[0] = (athvals[loc] >> 10) & 0x3F; 20692494Ssobomax chan->gainF[0] = (athvals[loc] >> 4) & 0x3F; 20792494Ssobomax chan->pcdac[1] = ((athvals[loc] << 2) & 0x3C) 20892494Ssobomax | ((athvals[loc+1] >> 14) & 0x03); 20992494Ssobomax chan->gainF[1] = (athvals[loc+1] >> 8) & 0x3F; 21092494Ssobomax chan->pcdac[2] = (athvals[loc+1] >> 2) & 0x3F; 211136093Sstefanf chan->gainF[2] = ((athvals[loc+1] << 4) & 0x30) 21292494Ssobomax | ((athvals[loc+2] >> 12) & 0x0F); 21392494Ssobomax chan->pcdac[3] = (athvals[loc+2] >> 6) & 0x3F; 21492494Ssobomax chan->gainF[3] = athvals[loc+2] & 0x3F; 21592494Ssobomax chan->pcdac[4] = (athvals[loc+3] >> 10) & 0x3F; 21692494Ssobomax chan->gainF[4] = (athvals[loc+3] >> 4) & 0x3F; 21792494Ssobomax chan->pcdac[5] = ((athvals[loc+3] << 2) & 0x3C) 21892494Ssobomax | ((athvals[loc+4] >> 14) & 0x03); 21992494Ssobomax chan->gainF[5] = (athvals[loc+4] >> 8) & 0x3F; 22092494Ssobomax chan->pcdac[6] = (athvals[loc+4] >> 2) & 0x3F; 22192494Ssobomax chan->gainF[6] = ((athvals[loc+4] << 4) & 0x30) 222124572Sjhb | ((athvals[loc+5] >> 12) & 0x0F); 223124572Sjhb chan->pcdac[7] = (athvals[loc+5] >> 6) & 0x3F; 22492494Ssobomax chan->gainF[7] = athvals[loc+5] & 0x3F; 22592494Ssobomax chan->pcdac[8] = (athvals[loc+6] >> 10) & 0x3F; 22692494Ssobomax chan->gainF[8] = (athvals[loc+6] >> 4) & 0x3F; 22792494Ssobomax chan->pcdac[9] = ((athvals[loc+6] << 2) & 0x3C) 22892494Ssobomax | ((athvals[loc+7] >> 14) & 0x03); 22992494Ssobomax chan->gainF[9] = (athvals[loc+7] >> 8) & 0x3F; 23092494Ssobomax chan->pcdac[10] = (athvals[loc+7] >> 2) & 0x3F; 23192494Ssobomax chan->gainF[10] = ((athvals[loc+7] << 4) & 0x30) 23292494Ssobomax | ((athvals[loc+8] >> 12) & 0x0F); 23392494Ssobomax 23492494Ssobomax /* Copy Regulatory Domain and Rate Information from EEPROM */ 23592494Ssobomax chan->rate36 = (athvals[loc+8] >> 6) & 0x3F; 23692494Ssobomax chan->rate48 = athvals[loc+8] & 0x3F; 23792494Ssobomax chan->rate54 = (athvals[loc+9] >> 10) & 0x3F; 23892494Ssobomax chan->regdmn[0] = (athvals[loc+9] >> 4) & 0x3F; 23992494Ssobomax chan->regdmn[1] = ((athvals[loc+9] << 2) & 0x3C) 24092494Ssobomax | ((athvals[loc+10] >> 14) & 0x03); 24192494Ssobomax chan->regdmn[2] = (athvals[loc+10] >> 8) & 0x3F; 24292494Ssobomax chan->regdmn[3] = (athvals[loc+10] >> 2) & 0x3F; 24392494Ssobomax } 24492494Ssobomax 24592494Ssobomax AH_PRIVATE(ah)->ah_eeprom = ee; 24692494Ssobomax AH_PRIVATE(ah)->ah_eeversion = version; 24792494Ssobomax AH_PRIVATE(ah)->ah_eepromDetach = v1EepromDetach; 24892494Ssobomax AH_PRIVATE(ah)->ah_eepromGet = v1EepromGet; 24992494Ssobomax AH_PRIVATE(ah)->ah_eepromSet = v1EepromSet; 25092494Ssobomax AH_PRIVATE(ah)->ah_getSpurChan = v1EepromGetSpurChan; 25192494Ssobomax AH_PRIVATE(ah)->ah_eepromDiag = v1EepromDiag; 25292494Ssobomax return HAL_OK; 25392494Ssobomax} 254124811Sjhb