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