xref: /freebsd/sys/dev/ath/ath_hal/ah_eeprom_v14.c (revision 95ee2897e98f5d444f26ed2334cc7c439f9c16c6)
1*6e778a7eSPedro F. Giffuni /*-
2*6e778a7eSPedro F. Giffuni  * SPDX-License-Identifier: ISC
3*6e778a7eSPedro F. Giffuni  *
414779705SSam Leffler  * Copyright (c) 2008 Sam Leffler, Errno Consulting
514779705SSam Leffler  * Copyright (c) 2008 Atheros Communications, Inc.
614779705SSam Leffler  *
714779705SSam Leffler  * Permission to use, copy, modify, and/or distribute this software for any
814779705SSam Leffler  * purpose with or without fee is hereby granted, provided that the above
914779705SSam Leffler  * copyright notice and this permission notice appear in all copies.
1014779705SSam Leffler  *
1114779705SSam Leffler  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1214779705SSam Leffler  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1314779705SSam Leffler  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1414779705SSam Leffler  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1514779705SSam Leffler  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1614779705SSam Leffler  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1714779705SSam Leffler  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1814779705SSam Leffler  */
1914779705SSam Leffler #include "opt_ah.h"
2014779705SSam Leffler 
2114779705SSam Leffler #include "ah.h"
2214779705SSam Leffler #include "ah_internal.h"
2314779705SSam Leffler #include "ah_eeprom_v14.h"
2414779705SSam Leffler 
2514779705SSam Leffler static HAL_STATUS
v14EepromGet(struct ath_hal * ah,int param,void * val)2614779705SSam Leffler v14EepromGet(struct ath_hal *ah, int param, void *val)
2714779705SSam Leffler {
2814779705SSam Leffler #define	CHAN_A_IDX	0
2914779705SSam Leffler #define	CHAN_B_IDX	1
3014779705SSam Leffler #define	IS_VERS(op, v)	((pBase->version & AR5416_EEP_VER_MINOR_MASK) op (v))
3114779705SSam Leffler 	HAL_EEPROM_v14 *ee = AH_PRIVATE(ah)->ah_eeprom;
3214779705SSam Leffler 	const MODAL_EEP_HEADER *pModal = ee->ee_base.modalHeader;
3314779705SSam Leffler 	const BASE_EEP_HEADER  *pBase  = &ee->ee_base.baseEepHeader;
3414779705SSam Leffler 	uint32_t sum;
3514779705SSam Leffler 	uint8_t *macaddr;
3614779705SSam Leffler 	int i;
3714779705SSam Leffler 
3814779705SSam Leffler 	switch (param) {
3914779705SSam Leffler         case AR_EEP_NFTHRESH_5:
4014779705SSam Leffler 		*(int16_t *)val = pModal[0].noiseFloorThreshCh[0];
4114779705SSam Leffler 		return HAL_OK;
4214779705SSam Leffler         case AR_EEP_NFTHRESH_2:
4314779705SSam Leffler 		*(int16_t *)val = pModal[1].noiseFloorThreshCh[0];
4414779705SSam Leffler 		return HAL_OK;
4514779705SSam Leffler         case AR_EEP_MACADDR:		/* Get MAC Address */
4614779705SSam Leffler 		sum = 0;
4714779705SSam Leffler 		macaddr = val;
4814779705SSam Leffler 		for (i = 0; i < 6; i++) {
4914779705SSam Leffler 			macaddr[i] = pBase->macAddr[i];
5014779705SSam Leffler 			sum += pBase->macAddr[i];
5114779705SSam Leffler 		}
5214779705SSam Leffler 		if (sum == 0 || sum == 0xffff*3) {
5314779705SSam Leffler 			HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad mac address %s\n",
5414779705SSam Leffler 			    __func__, ath_hal_ether_sprintf(macaddr));
5514779705SSam Leffler 			return HAL_EEBADMAC;
5614779705SSam Leffler 		}
57eef5acf2SSam Leffler 		return HAL_OK;
5814779705SSam Leffler         case AR_EEP_REGDMN_0:
5914779705SSam Leffler 		return pBase->regDmn[0];
6014779705SSam Leffler         case AR_EEP_REGDMN_1:
6114779705SSam Leffler 		return pBase->regDmn[1];
6214779705SSam Leffler         case AR_EEP_OPCAP:
6314779705SSam Leffler 		return pBase->deviceCap;
6414779705SSam Leffler         case AR_EEP_OPMODE:
6514779705SSam Leffler 		return pBase->opCapFlags;
6614779705SSam Leffler         case AR_EEP_RFSILENT:
6714779705SSam Leffler 		return pBase->rfSilent;
6814779705SSam Leffler 	case AR_EEP_OB_5:
6914779705SSam Leffler 		return pModal[CHAN_A_IDX].ob;
7014779705SSam Leffler     	case AR_EEP_DB_5:
7114779705SSam Leffler 		return pModal[CHAN_A_IDX].db;
7214779705SSam Leffler     	case AR_EEP_OB_2:
7314779705SSam Leffler 		return pModal[CHAN_B_IDX].ob;
7414779705SSam Leffler     	case AR_EEP_DB_2:
7514779705SSam Leffler 		return pModal[CHAN_B_IDX].db;
7614779705SSam Leffler 	case AR_EEP_TXMASK:
7714779705SSam Leffler 		return pBase->txMask;
7814779705SSam Leffler 	case AR_EEP_RXMASK:
7914779705SSam Leffler 		return pBase->rxMask;
8014779705SSam Leffler 	case AR_EEP_RXGAIN_TYPE:
8114779705SSam Leffler 		return IS_VERS(>=, AR5416_EEP_MINOR_VER_17) ?
8214779705SSam Leffler 		    pBase->rxGainType : AR5416_EEP_RXGAIN_ORIG;
8314779705SSam Leffler 	case AR_EEP_TXGAIN_TYPE:
8414779705SSam Leffler 		return IS_VERS(>=, AR5416_EEP_MINOR_VER_19) ?
8514779705SSam Leffler 		    pBase->txGainType : AR5416_EEP_TXGAIN_ORIG;
8614779705SSam Leffler 	case AR_EEP_FSTCLK_5G:
87acc81227SAdrian Chadd 		/* 5ghz fastclock is always enabled for Merlin minor <= 16 */
88acc81227SAdrian Chadd 		if (IS_VERS(<=, AR5416_EEP_MINOR_VER_16))
89acc81227SAdrian Chadd 			return HAL_OK;
90acc81227SAdrian Chadd 		return pBase->fastClk5g ? HAL_OK : HAL_EIO;
9114779705SSam Leffler 	case AR_EEP_OL_PWRCTRL:
9214779705SSam Leffler 		HALASSERT(val == AH_NULL);
9314779705SSam Leffler 		return pBase->openLoopPwrCntl ?  HAL_OK : HAL_EIO;
94c485136bSAdrian Chadd 	case AR_EEP_DAC_HPWR_5G:
95c485136bSAdrian Chadd 		if (IS_VERS(>=, AR5416_EEP_MINOR_VER_20)) {
961a506b1aSAdrian Chadd 			*(uint8_t *) val = pBase->dacHiPwrMode_5G;
97c485136bSAdrian Chadd 			return HAL_OK;
98c485136bSAdrian Chadd 		} else
99c485136bSAdrian Chadd 			return HAL_EIO;
1007239f9f7SAdrian Chadd 	case AR_EEP_FRAC_N_5G:
1017239f9f7SAdrian Chadd 		if (IS_VERS(>=, AR5416_EEP_MINOR_VER_22)) {
1027239f9f7SAdrian Chadd 			*(uint8_t *) val = pBase->frac_n_5g;
1037239f9f7SAdrian Chadd 		} else
1047239f9f7SAdrian Chadd 			*(uint8_t *) val = 0;
1057239f9f7SAdrian Chadd 		return HAL_OK;
10614779705SSam Leffler 	case AR_EEP_AMODE:
10714779705SSam Leffler 		HALASSERT(val == AH_NULL);
10814779705SSam Leffler 		return pBase->opCapFlags & AR5416_OPFLAGS_11A ?
10914779705SSam Leffler 		    HAL_OK : HAL_EIO;
11014779705SSam Leffler 	case AR_EEP_BMODE:
11114779705SSam Leffler 	case AR_EEP_GMODE:
11214779705SSam Leffler 		HALASSERT(val == AH_NULL);
11314779705SSam Leffler 		return pBase->opCapFlags & AR5416_OPFLAGS_11G ?
11414779705SSam Leffler 		    HAL_OK : HAL_EIO;
11514779705SSam Leffler 	case AR_EEP_32KHZCRYSTAL:
11614779705SSam Leffler 	case AR_EEP_COMPRESS:
11714779705SSam Leffler 	case AR_EEP_FASTFRAME:		/* XXX policy decision, h/w can do it */
11814779705SSam Leffler 	case AR_EEP_WRITEPROTECT:	/* NB: no write protect bit */
11914779705SSam Leffler 		HALASSERT(val == AH_NULL);
12014779705SSam Leffler 		/* fall thru... */
12114779705SSam Leffler 	case AR_EEP_MAXQCU:		/* NB: not in opCapFlags */
12214779705SSam Leffler 	case AR_EEP_KCENTRIES:		/* NB: not in opCapFlags */
12314779705SSam Leffler 		return HAL_EIO;
12414779705SSam Leffler 	case AR_EEP_AES:
12514779705SSam Leffler 	case AR_EEP_BURST:
12614779705SSam Leffler         case AR_EEP_RFKILL:
12714779705SSam Leffler 	case AR_EEP_TURBO5DISABLE:
12814779705SSam Leffler 	case AR_EEP_TURBO2DISABLE:
12914779705SSam Leffler 		HALASSERT(val == AH_NULL);
13014779705SSam Leffler 		return HAL_OK;
13114779705SSam Leffler 	case AR_EEP_ANTGAINMAX_2:
13214779705SSam Leffler 		*(int8_t *) val = ee->ee_antennaGainMax[1];
13314779705SSam Leffler 		return HAL_OK;
13414779705SSam Leffler 	case AR_EEP_ANTGAINMAX_5:
13514779705SSam Leffler 		*(int8_t *) val = ee->ee_antennaGainMax[0];
13614779705SSam Leffler 		return HAL_OK;
13788237142SAdrian Chadd 	case AR_EEP_PWR_TABLE_OFFSET:
13888237142SAdrian Chadd 		if (IS_VERS(>=, AR5416_EEP_MINOR_VER_21))
13988237142SAdrian Chadd 			*(int8_t *) val = pBase->pwr_table_offset;
14088237142SAdrian Chadd 		else
14188237142SAdrian Chadd 			*(int8_t *) val = AR5416_PWR_TABLE_OFFSET_DB;
14288237142SAdrian Chadd 		return HAL_OK;
143c5067868SAdrian Chadd 	case AR_EEP_PWDCLKIND:
144c5067868SAdrian Chadd 		if (IS_VERS(>=, AR5416_EEP_MINOR_VER_10)) {
145c5067868SAdrian Chadd 			*(uint8_t *) val = pBase->pwdclkind;
146c5067868SAdrian Chadd 			return HAL_OK;
147c5067868SAdrian Chadd 		}
148c5067868SAdrian Chadd 		return HAL_EIO;
14988237142SAdrian Chadd 
15014779705SSam Leffler         default:
15114779705SSam Leffler 		HALASSERT(0);
15214779705SSam Leffler 		return HAL_EINVAL;
15314779705SSam Leffler 	}
15414779705SSam Leffler #undef IS_VERS
15514779705SSam Leffler #undef CHAN_A_IDX
15614779705SSam Leffler #undef CHAN_B_IDX
15714779705SSam Leffler }
15814779705SSam Leffler 
15992ffeb63SAdrian Chadd static HAL_STATUS
v14EepromSet(struct ath_hal * ah,int param,int v)16014779705SSam Leffler v14EepromSet(struct ath_hal *ah, int param, int v)
16114779705SSam Leffler {
16214779705SSam Leffler 	HAL_EEPROM_v14 *ee = AH_PRIVATE(ah)->ah_eeprom;
16314779705SSam Leffler 
16414779705SSam Leffler 	switch (param) {
16514779705SSam Leffler 	case AR_EEP_ANTGAINMAX_2:
16614779705SSam Leffler 		ee->ee_antennaGainMax[1] = (int8_t) v;
16714779705SSam Leffler 		return HAL_OK;
16814779705SSam Leffler 	case AR_EEP_ANTGAINMAX_5:
16914779705SSam Leffler 		ee->ee_antennaGainMax[0] = (int8_t) v;
17014779705SSam Leffler 		return HAL_OK;
17114779705SSam Leffler 	}
17214779705SSam Leffler 	return HAL_EINVAL;
17314779705SSam Leffler }
17414779705SSam Leffler 
17514779705SSam Leffler static HAL_BOOL
v14EepromDiag(struct ath_hal * ah,int request,const void * args,uint32_t argsize,void ** result,uint32_t * resultsize)17614779705SSam Leffler v14EepromDiag(struct ath_hal *ah, int request,
17714779705SSam Leffler      const void *args, uint32_t argsize, void **result, uint32_t *resultsize)
17814779705SSam Leffler {
17914779705SSam Leffler 	HAL_EEPROM_v14 *ee = AH_PRIVATE(ah)->ah_eeprom;
18014779705SSam Leffler 
18114779705SSam Leffler 	switch (request) {
18214779705SSam Leffler 	case HAL_DIAG_EEPROM:
183a5314ffdSAdrian Chadd 		*result = ee;
184a5314ffdSAdrian Chadd 		*resultsize = sizeof(HAL_EEPROM_v14);
18514779705SSam Leffler 		return AH_TRUE;
18614779705SSam Leffler 	}
18714779705SSam Leffler 	return AH_FALSE;
18814779705SSam Leffler }
18914779705SSam Leffler 
19014779705SSam Leffler /* Do structure specific swaps if Eeprom format is non native to host */
19114779705SSam Leffler static void
eepromSwap(struct ar5416eeprom * ee)19214779705SSam Leffler eepromSwap(struct ar5416eeprom *ee)
19314779705SSam Leffler {
19414779705SSam Leffler 	uint32_t integer, i, j;
19514779705SSam Leffler 	uint16_t word;
19614779705SSam Leffler 	MODAL_EEP_HEADER *pModal;
19714779705SSam Leffler 
19814779705SSam Leffler 	/* convert Base Eep header */
19914779705SSam Leffler 	word = __bswap16(ee->baseEepHeader.length);
20014779705SSam Leffler 	ee->baseEepHeader.length = word;
20114779705SSam Leffler 
20214779705SSam Leffler 	word = __bswap16(ee->baseEepHeader.checksum);
20314779705SSam Leffler 	ee->baseEepHeader.checksum = word;
20414779705SSam Leffler 
20514779705SSam Leffler 	word = __bswap16(ee->baseEepHeader.version);
20614779705SSam Leffler 	ee->baseEepHeader.version = word;
20714779705SSam Leffler 
20814779705SSam Leffler 	word = __bswap16(ee->baseEepHeader.regDmn[0]);
20914779705SSam Leffler 	ee->baseEepHeader.regDmn[0] = word;
21014779705SSam Leffler 
21114779705SSam Leffler 	word = __bswap16(ee->baseEepHeader.regDmn[1]);
21214779705SSam Leffler 	ee->baseEepHeader.regDmn[1] = word;
21314779705SSam Leffler 
21414779705SSam Leffler 	word = __bswap16(ee->baseEepHeader.rfSilent);
21514779705SSam Leffler 	ee->baseEepHeader.rfSilent = word;
21614779705SSam Leffler 
21714779705SSam Leffler 	word = __bswap16(ee->baseEepHeader.blueToothOptions);
21814779705SSam Leffler 	ee->baseEepHeader.blueToothOptions = word;
21914779705SSam Leffler 
22014779705SSam Leffler 	word = __bswap16(ee->baseEepHeader.deviceCap);
22114779705SSam Leffler 	ee->baseEepHeader.deviceCap = word;
22214779705SSam Leffler 
22314779705SSam Leffler 	/* convert Modal Eep header */
22414779705SSam Leffler 	for (j = 0; j < 2; j++) {
22514779705SSam Leffler 		pModal = &ee->modalHeader[j];
22614779705SSam Leffler 
22714779705SSam Leffler 		/* XXX linux/ah_osdep.h only defines __bswap32 for BE */
22814779705SSam Leffler 		integer = __bswap32(pModal->antCtrlCommon);
22914779705SSam Leffler 		pModal->antCtrlCommon = integer;
23014779705SSam Leffler 
23114779705SSam Leffler 		for (i = 0; i < AR5416_MAX_CHAINS; i++) {
23214779705SSam Leffler 			integer = __bswap32(pModal->antCtrlChain[i]);
23314779705SSam Leffler 			pModal->antCtrlChain[i] = integer;
23414779705SSam Leffler 		}
23574e3a021SAdrian Chadd 		for (i = 0; i < 3; i++) {
23674e3a021SAdrian Chadd 			word = __bswap16(pModal->xpaBiasLvlFreq[i]);
23774e3a021SAdrian Chadd 			pModal->xpaBiasLvlFreq[i] = word;
23874e3a021SAdrian Chadd 		}
23914779705SSam Leffler 		for (i = 0; i < AR5416_EEPROM_MODAL_SPURS; i++) {
24014779705SSam Leffler 			word = __bswap16(pModal->spurChans[i].spurChan);
24114779705SSam Leffler 			pModal->spurChans[i].spurChan = word;
24214779705SSam Leffler 		}
24314779705SSam Leffler 	}
24414779705SSam Leffler }
24514779705SSam Leffler 
24614779705SSam Leffler static uint16_t
v14EepromGetSpurChan(struct ath_hal * ah,int ix,HAL_BOOL is2GHz)24714779705SSam Leffler v14EepromGetSpurChan(struct ath_hal *ah, int ix, HAL_BOOL is2GHz)
24814779705SSam Leffler {
24914779705SSam Leffler 	HAL_EEPROM_v14 *ee = AH_PRIVATE(ah)->ah_eeprom;
25014779705SSam Leffler 
25114779705SSam Leffler 	HALASSERT(0 <= ix && ix <  AR5416_EEPROM_MODAL_SPURS);
25214779705SSam Leffler 	return ee->ee_base.modalHeader[is2GHz].spurChans[ix].spurChan;
25314779705SSam Leffler }
25414779705SSam Leffler 
25514779705SSam Leffler /**************************************************************************
25614779705SSam Leffler  * fbin2freq
25714779705SSam Leffler  *
25814779705SSam Leffler  * Get channel value from binary representation held in eeprom
25914779705SSam Leffler  * RETURNS: the frequency in MHz
26014779705SSam Leffler  */
26114779705SSam Leffler static uint16_t
fbin2freq(uint8_t fbin,HAL_BOOL is2GHz)26214779705SSam Leffler fbin2freq(uint8_t fbin, HAL_BOOL is2GHz)
26314779705SSam Leffler {
26414779705SSam Leffler 	/*
26514779705SSam Leffler 	 * Reserved value 0xFF provides an empty definition both as
26614779705SSam Leffler 	 * an fbin and as a frequency - do not convert
26714779705SSam Leffler 	 */
26814779705SSam Leffler 	if (fbin == AR5416_BCHAN_UNUSED)
26914779705SSam Leffler 		return fbin;
27014779705SSam Leffler 	return (uint16_t)((is2GHz) ? (2300 + fbin) : (4800 + 5 * fbin));
27114779705SSam Leffler }
27214779705SSam Leffler 
27314779705SSam Leffler /*
27414779705SSam Leffler  * Copy EEPROM Conformance Testing Limits contents
27514779705SSam Leffler  * into the allocated space
27614779705SSam Leffler  */
27714779705SSam Leffler /* USE CTLS from chain zero */
27814779705SSam Leffler #define CTL_CHAIN	0
27914779705SSam Leffler 
28014779705SSam Leffler static void
v14EepromReadCTLInfo(struct ath_hal * ah,HAL_EEPROM_v14 * ee)28114779705SSam Leffler v14EepromReadCTLInfo(struct ath_hal *ah, HAL_EEPROM_v14 *ee)
28214779705SSam Leffler {
28314779705SSam Leffler 	RD_EDGES_POWER *rep = ee->ee_rdEdgesPower;
28414779705SSam Leffler 	int i, j;
28514779705SSam Leffler 
28614779705SSam Leffler 	HALASSERT(AR5416_NUM_CTLS <= sizeof(ee->ee_rdEdgesPower)/NUM_EDGES);
28714779705SSam Leffler 
28814779705SSam Leffler 	for (i = 0; ee->ee_base.ctlIndex[i] != 0 && i < AR5416_NUM_CTLS; i++) {
28914779705SSam Leffler 		for (j = 0; j < NUM_EDGES; j ++) {
29014779705SSam Leffler 			/* XXX Confirm this is the right thing to do when an invalid channel is stored */
29114779705SSam Leffler 			if (ee->ee_base.ctlData[i].ctlEdges[CTL_CHAIN][j].bChannel == AR5416_BCHAN_UNUSED) {
29214779705SSam Leffler 				rep[j].rdEdge = 0;
29314779705SSam Leffler 				rep[j].twice_rdEdgePower = 0;
29414779705SSam Leffler 				rep[j].flag = 0;
29514779705SSam Leffler 			} else {
29614779705SSam Leffler 				rep[j].rdEdge = fbin2freq(
29714779705SSam Leffler 				    ee->ee_base.ctlData[i].ctlEdges[CTL_CHAIN][j].bChannel,
29814779705SSam Leffler 				    (ee->ee_base.ctlIndex[i] & CTL_MODE_M) != CTL_11A);
29914779705SSam Leffler 				rep[j].twice_rdEdgePower = MS(ee->ee_base.ctlData[i].ctlEdges[CTL_CHAIN][j].tPowerFlag, CAL_CTL_EDGES_POWER);
30014779705SSam Leffler 				rep[j].flag = MS(ee->ee_base.ctlData[i].ctlEdges[CTL_CHAIN][j].tPowerFlag, CAL_CTL_EDGES_FLAG) != 0;
30114779705SSam Leffler 			}
30214779705SSam Leffler 		}
30314779705SSam Leffler 		rep += NUM_EDGES;
30414779705SSam Leffler 	}
30514779705SSam Leffler 	ee->ee_numCtls = i;
30614779705SSam Leffler 	HALDEBUG(ah, HAL_DEBUG_ATTACH | HAL_DEBUG_EEPROM,
30714779705SSam Leffler 	    "%s Numctls = %u\n",__func__,i);
30814779705SSam Leffler }
30914779705SSam Leffler 
31014779705SSam Leffler /*
31114779705SSam Leffler  * Reclaim any EEPROM-related storage.
31214779705SSam Leffler  */
31314779705SSam Leffler static void
v14EepromDetach(struct ath_hal * ah)31414779705SSam Leffler v14EepromDetach(struct ath_hal *ah)
31514779705SSam Leffler {
31614779705SSam Leffler 	HAL_EEPROM_v14 *ee = AH_PRIVATE(ah)->ah_eeprom;
31714779705SSam Leffler 
31814779705SSam Leffler 	ath_hal_free(ee);
31914779705SSam Leffler 	AH_PRIVATE(ah)->ah_eeprom = AH_NULL;
32014779705SSam Leffler }
32114779705SSam Leffler 
32214779705SSam Leffler #define owl_get_eep_ver(_ee)   \
32314779705SSam Leffler     (((_ee)->ee_base.baseEepHeader.version >> 12) & 0xF)
32414779705SSam Leffler #define owl_get_eep_rev(_ee)   \
32514779705SSam Leffler     (((_ee)->ee_base.baseEepHeader.version) & 0xFFF)
32614779705SSam Leffler 
3279f25ad52SAdrian Chadd /*
3289f25ad52SAdrian Chadd  * Howl is (hopefully) a special case where the endian-ness of the EEPROM
3299f25ad52SAdrian Chadd  * matches the native endian-ness; and that supplied EEPROMs don't have
3309f25ad52SAdrian Chadd  * a magic value to check.
3319f25ad52SAdrian Chadd  */
33214779705SSam Leffler HAL_STATUS
ath_hal_v14EepromAttach(struct ath_hal * ah)33314779705SSam Leffler ath_hal_v14EepromAttach(struct ath_hal *ah)
33414779705SSam Leffler {
33514779705SSam Leffler #define	NW(a)	(sizeof(a) / sizeof(uint16_t))
33614779705SSam Leffler 	HAL_EEPROM_v14 *ee = AH_PRIVATE(ah)->ah_eeprom;
33714779705SSam Leffler 	uint16_t *eep_data, magic;
33814779705SSam Leffler 	HAL_BOOL need_swap;
33914779705SSam Leffler 	u_int w, off, len;
34014779705SSam Leffler 	uint32_t sum;
34114779705SSam Leffler 
34214779705SSam Leffler 	HALASSERT(ee == AH_NULL);
34314779705SSam Leffler 
3449f25ad52SAdrian Chadd 	/*
3459f25ad52SAdrian Chadd 	 * Don't check magic if we're supplied with an EEPROM block,
3469f25ad52SAdrian Chadd 	 * typically this is from Howl but it may also be from later
3479f25ad52SAdrian Chadd 	 * boards w/ an embedded Merlin.
3489f25ad52SAdrian Chadd 	 */
3499f25ad52SAdrian Chadd 	if (ah->ah_eepromdata == NULL) {
35014779705SSam Leffler 		if (!ath_hal_eepromRead(ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) {
35114779705SSam Leffler 			HALDEBUG(ah, HAL_DEBUG_ANY,
35214779705SSam Leffler 			    "%s Error reading Eeprom MAGIC\n", __func__);
35314779705SSam Leffler 			return HAL_EEREAD;
35414779705SSam Leffler 		}
35514779705SSam Leffler 		HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s Eeprom Magic = 0x%x\n",
35614779705SSam Leffler 		    __func__, magic);
35714779705SSam Leffler 		if (magic != AR5416_EEPROM_MAGIC) {
35814779705SSam Leffler 			HALDEBUG(ah, HAL_DEBUG_ANY, "Bad magic number\n");
35914779705SSam Leffler 			return HAL_EEMAGIC;
36014779705SSam Leffler 		}
3619f25ad52SAdrian Chadd 	}
36214779705SSam Leffler 
36314779705SSam Leffler 	ee = ath_hal_malloc(sizeof(HAL_EEPROM_v14));
36414779705SSam Leffler 	if (ee == AH_NULL) {
36514779705SSam Leffler 		/* XXX message */
36614779705SSam Leffler 		return HAL_ENOMEM;
36714779705SSam Leffler 	}
36814779705SSam Leffler 
36914779705SSam Leffler 	eep_data = (uint16_t *)&ee->ee_base;
37014779705SSam Leffler 	for (w = 0; w < NW(struct ar5416eeprom); w++) {
37114779705SSam Leffler 		off = owl_eep_start_loc + w;	/* NB: AP71 starts at 0 */
37214779705SSam Leffler 		if (!ath_hal_eepromRead(ah, off, &eep_data[w])) {
37314779705SSam Leffler 			HALDEBUG(ah, HAL_DEBUG_ANY,
37414779705SSam Leffler 			    "%s eeprom read error at offset 0x%x\n",
37514779705SSam Leffler 			    __func__, off);
37614779705SSam Leffler 			return HAL_EEREAD;
37714779705SSam Leffler 		}
37814779705SSam Leffler 	}
37914779705SSam Leffler 	/* Convert to eeprom native eeprom endian format */
3809f25ad52SAdrian Chadd 	/* XXX this is likely incorrect but will do for now to get howl/ap83 working. */
3819f25ad52SAdrian Chadd 	if (ah->ah_eepromdata == NULL && isBigEndian()) {
38214779705SSam Leffler 		for (w = 0; w < NW(struct ar5416eeprom); w++)
38314779705SSam Leffler 			eep_data[w] = __bswap16(eep_data[w]);
38414779705SSam Leffler 	}
38514779705SSam Leffler 
38614779705SSam Leffler 	/*
38714779705SSam Leffler 	 * At this point, we're in the native eeprom endian format
38814779705SSam Leffler 	 * Now, determine the eeprom endian by looking at byte 26??
38914779705SSam Leffler 	 */
39014779705SSam Leffler 	need_swap = ((ee->ee_base.baseEepHeader.eepMisc & AR5416_EEPMISC_BIG_ENDIAN) != 0) ^ isBigEndian();
39114779705SSam Leffler 	if (need_swap) {
39214779705SSam Leffler 		HALDEBUG(ah, HAL_DEBUG_ATTACH | HAL_DEBUG_EEPROM,
39314779705SSam Leffler 		    "Byte swap EEPROM contents.\n");
39414779705SSam Leffler 		len = __bswap16(ee->ee_base.baseEepHeader.length);
39514779705SSam Leffler 	} else {
39614779705SSam Leffler 		len = ee->ee_base.baseEepHeader.length;
39714779705SSam Leffler 	}
39814779705SSam Leffler 	len = AH_MIN(len, sizeof(struct ar5416eeprom)) / sizeof(uint16_t);
39914779705SSam Leffler 
40014779705SSam Leffler 	/* Apply the checksum, done in native eeprom format */
40114779705SSam Leffler 	/* XXX - Need to check to make sure checksum calculation is done
40214779705SSam Leffler 	 * in the correct endian format.  Right now, it seems it would
40314779705SSam Leffler 	 * cast the raw data to host format and do the calculation, which may
40414779705SSam Leffler 	 * not be correct as the calculation may need to be done in the native
40514779705SSam Leffler 	 * eeprom format
40614779705SSam Leffler 	 */
40714779705SSam Leffler 	sum = 0;
40814779705SSam Leffler 	for (w = 0; w < len; w++)
40914779705SSam Leffler 		sum ^= eep_data[w];
41014779705SSam Leffler 	/* Check CRC - Attach should fail on a bad checksum */
41114779705SSam Leffler 	if (sum != 0xffff) {
41214779705SSam Leffler 		HALDEBUG(ah, HAL_DEBUG_ANY,
41314779705SSam Leffler 		    "Bad EEPROM checksum 0x%x (Len=%u)\n", sum, len);
41414779705SSam Leffler 		return HAL_EEBADSUM;
41514779705SSam Leffler 	}
41614779705SSam Leffler 
41714779705SSam Leffler 	if (need_swap)
41814779705SSam Leffler 		eepromSwap(&ee->ee_base);	/* byte swap multi-byte data */
41914779705SSam Leffler 
42014779705SSam Leffler 	/* swap words 0+2 so version is at the front */
42114779705SSam Leffler 	magic = eep_data[0];
42214779705SSam Leffler 	eep_data[0] = eep_data[2];
42314779705SSam Leffler 	eep_data[2] = magic;
42414779705SSam Leffler 
42514779705SSam Leffler 	HALDEBUG(ah, HAL_DEBUG_ATTACH | HAL_DEBUG_EEPROM,
42614779705SSam Leffler 	    "%s Eeprom Version %u.%u\n", __func__,
42714779705SSam Leffler 	    owl_get_eep_ver(ee), owl_get_eep_rev(ee));
42814779705SSam Leffler 
42914779705SSam Leffler 	/* NB: must be after all byte swapping */
43014779705SSam Leffler 	if (owl_get_eep_ver(ee) != AR5416_EEP_VER) {
43114779705SSam Leffler 		HALDEBUG(ah, HAL_DEBUG_ANY,
43214779705SSam Leffler 		    "Bad EEPROM version 0x%x\n", owl_get_eep_ver(ee));
43314779705SSam Leffler 		return HAL_EEBADSUM;
43414779705SSam Leffler 	}
43514779705SSam Leffler 
43614779705SSam Leffler 	v14EepromReadCTLInfo(ah, ee);		/* Get CTLs */
43714779705SSam Leffler 
43814779705SSam Leffler 	AH_PRIVATE(ah)->ah_eeprom = ee;
43914779705SSam Leffler 	AH_PRIVATE(ah)->ah_eeversion = ee->ee_base.baseEepHeader.version;
44014779705SSam Leffler 	AH_PRIVATE(ah)->ah_eepromDetach = v14EepromDetach;
44114779705SSam Leffler 	AH_PRIVATE(ah)->ah_eepromGet = v14EepromGet;
44214779705SSam Leffler 	AH_PRIVATE(ah)->ah_eepromSet = v14EepromSet;
44314779705SSam Leffler 	AH_PRIVATE(ah)->ah_getSpurChan = v14EepromGetSpurChan;
44414779705SSam Leffler 	AH_PRIVATE(ah)->ah_eepromDiag = v14EepromDiag;
44514779705SSam Leffler 	return HAL_OK;
44614779705SSam Leffler #undef NW
44714779705SSam Leffler }
448