2 * Copyright (c) 2008 Sam Leffler, Errno Consulting
3 * Copyright (c) 2008 Atheros Communications, Inc.
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 * $Id: ah_eeprom_v14.c,v 1.4 2008/12/31 14:08:46 christos Exp $
19 #include <sys/endian.h>
23 #include "ah_internal.h"
24 #include "ah_eeprom_v14.h"
27 v14EepromGet(struct ath_hal
*ah
, int param
, void *val
)
31 #define IS_VERS(op, v) ((pBase->version & AR5416_EEP_VER_MINOR_MASK) op (v))
32 HAL_EEPROM_v14
*ee
= AH_PRIVATE(ah
)->ah_eeprom
;
33 const MODAL_EEP_HEADER
*pModal
= ee
->ee_base
.modalHeader
;
34 const BASE_EEP_HEADER
*pBase
= &ee
->ee_base
.baseEepHeader
;
40 case AR_EEP_NFTHRESH_5
:
41 *(int16_t *)val
= pModal
[0].noiseFloorThreshCh
[0];
43 case AR_EEP_NFTHRESH_2
:
44 *(int16_t *)val
= pModal
[1].noiseFloorThreshCh
[0];
46 case AR_EEP_MACADDR
: /* Get MAC Address */
49 for (i
= 0; i
< 6; i
++) {
50 macaddr
[i
] = pBase
->macAddr
[i
];
51 sum
+= pBase
->macAddr
[i
];
53 if (sum
== 0 || sum
== 0xffff*3) {
54 HALDEBUG(ah
, HAL_DEBUG_ANY
, "%s: bad mac address %s\n",
55 __func__
, ath_hal_ether_sprintf(macaddr
));
60 return pBase
->regDmn
[0];
62 return pBase
->regDmn
[1];
64 return pBase
->deviceCap
;
66 return pBase
->opCapFlags
;
68 return pBase
->rfSilent
;
70 return pModal
[CHAN_A_IDX
].ob
;
72 return pModal
[CHAN_A_IDX
].db
;
74 return pModal
[CHAN_B_IDX
].ob
;
76 return pModal
[CHAN_B_IDX
].db
;
81 case AR_EEP_RXGAIN_TYPE
:
82 return IS_VERS(>=, AR5416_EEP_MINOR_VER_17
) ?
83 pBase
->rxGainType
: AR5416_EEP_RXGAIN_ORIG
;
84 case AR_EEP_TXGAIN_TYPE
:
85 return IS_VERS(>=, AR5416_EEP_MINOR_VER_19
) ?
86 pBase
->txGainType
: AR5416_EEP_TXGAIN_ORIG
;
87 case AR_EEP_FSTCLK_5G
:
88 return IS_VERS(>, AR5416_EEP_MINOR_VER_16
) ?
89 pBase
->fastClk5g
: AH_TRUE
;
90 case AR_EEP_OL_PWRCTRL
:
91 HALASSERT(val
== AH_NULL
);
92 return pBase
->openLoopPwrCntl
? HAL_OK
: HAL_EIO
;
94 HALASSERT(val
== AH_NULL
);
95 return pBase
->opCapFlags
& AR5416_OPFLAGS_11A
?
99 HALASSERT(val
== AH_NULL
);
100 return pBase
->opCapFlags
& AR5416_OPFLAGS_11G
?
102 case AR_EEP_32KHZCRYSTAL
:
103 case AR_EEP_COMPRESS
:
104 case AR_EEP_FASTFRAME
: /* XXX policy decision, h/w can do it */
105 case AR_EEP_WRITEPROTECT
: /* NB: no write protect bit */
106 HALASSERT(val
== AH_NULL
);
108 case AR_EEP_MAXQCU
: /* NB: not in opCapFlags */
109 case AR_EEP_KCENTRIES
: /* NB: not in opCapFlags */
114 case AR_EEP_TURBO5DISABLE
:
115 case AR_EEP_TURBO2DISABLE
:
116 HALASSERT(val
== AH_NULL
);
118 case AR_EEP_ANTGAINMAX_2
:
119 *(int8_t *) val
= ee
->ee_antennaGainMax
[1];
121 case AR_EEP_ANTGAINMAX_5
:
122 *(int8_t *) val
= ee
->ee_antennaGainMax
[0];
134 v14EepromSet(struct ath_hal
*ah
, int param
, int v
)
136 HAL_EEPROM_v14
*ee
= AH_PRIVATE(ah
)->ah_eeprom
;
139 case AR_EEP_ANTGAINMAX_2
:
140 ee
->ee_antennaGainMax
[1] = (int8_t) v
;
142 case AR_EEP_ANTGAINMAX_5
:
143 ee
->ee_antennaGainMax
[0] = (int8_t) v
;
150 v14EepromDiag(struct ath_hal
*ah
, int request
,
151 const void *args
, uint32_t argsize
, void **result
, uint32_t *resultsize
)
153 HAL_EEPROM_v14
*ee
= AH_PRIVATE(ah
)->ah_eeprom
;
156 case HAL_DIAG_EEPROM
:
157 *result
= &ee
->ee_base
;
158 *resultsize
= sizeof(ee
->ee_base
);
165 /* XXX conditionalize by target byte order */
167 static __inline__
uint16_t
168 __bswap16(uint16_t _x
)
171 (((const uint8_t *)(&_x
))[0] ) |
172 (((const uint8_t *)(&_x
))[1]<< 8))
178 /* Do structure specific swaps if Eeprom format is non native to host */
180 eepromSwap(struct ar5416eeprom
*ee
)
182 uint32_t integer
, i
, j
;
184 MODAL_EEP_HEADER
*pModal
;
186 /* convert Base Eep header */
187 word
= __bswap16(ee
->baseEepHeader
.length
);
188 ee
->baseEepHeader
.length
= word
;
190 word
= __bswap16(ee
->baseEepHeader
.checksum
);
191 ee
->baseEepHeader
.checksum
= word
;
193 word
= __bswap16(ee
->baseEepHeader
.version
);
194 ee
->baseEepHeader
.version
= word
;
196 word
= __bswap16(ee
->baseEepHeader
.regDmn
[0]);
197 ee
->baseEepHeader
.regDmn
[0] = word
;
199 word
= __bswap16(ee
->baseEepHeader
.regDmn
[1]);
200 ee
->baseEepHeader
.regDmn
[1] = word
;
202 word
= __bswap16(ee
->baseEepHeader
.rfSilent
);
203 ee
->baseEepHeader
.rfSilent
= word
;
205 word
= __bswap16(ee
->baseEepHeader
.blueToothOptions
);
206 ee
->baseEepHeader
.blueToothOptions
= word
;
208 word
= __bswap16(ee
->baseEepHeader
.deviceCap
);
209 ee
->baseEepHeader
.deviceCap
= word
;
211 /* convert Modal Eep header */
212 for (j
= 0; j
< 2; j
++) {
213 pModal
= &ee
->modalHeader
[j
];
215 /* XXX linux/ah_osdep.h only defines __bswap32 for BE */
216 integer
= __bswap32(pModal
->antCtrlCommon
);
217 pModal
->antCtrlCommon
= integer
;
219 for (i
= 0; i
< AR5416_MAX_CHAINS
; i
++) {
220 integer
= __bswap32(pModal
->antCtrlChain
[i
]);
221 pModal
->antCtrlChain
[i
] = integer
;
224 for (i
= 0; i
< AR5416_EEPROM_MODAL_SPURS
; i
++) {
225 word
= __bswap16(pModal
->spurChans
[i
].spurChan
);
226 pModal
->spurChans
[i
].spurChan
= word
;
232 v14EepromGetSpurChan(struct ath_hal
*ah
, int ix
, HAL_BOOL is2GHz
)
234 HAL_EEPROM_v14
*ee
= AH_PRIVATE(ah
)->ah_eeprom
;
236 HALASSERT(0 <= ix
&& ix
< AR5416_EEPROM_MODAL_SPURS
);
237 return ee
->ee_base
.modalHeader
[is2GHz
].spurChans
[ix
].spurChan
;
240 /**************************************************************************
243 * Get channel value from binary representation held in eeprom
244 * RETURNS: the frequency in MHz
247 fbin2freq(uint8_t fbin
, HAL_BOOL is2GHz
)
250 * Reserved value 0xFF provides an empty definition both as
251 * an fbin and as a frequency - do not convert
253 if (fbin
== AR5416_BCHAN_UNUSED
)
255 return (uint16_t)((is2GHz
) ? (2300 + fbin
) : (4800 + 5 * fbin
));
259 * Copy EEPROM Conformance Testing Limits contents
260 * into the allocated space
262 /* USE CTLS from chain zero */
266 v14EepromReadCTLInfo(struct ath_hal
*ah
, HAL_EEPROM_v14
*ee
)
268 RD_EDGES_POWER
*rep
= ee
->ee_rdEdgesPower
;
271 HALASSERT(AR5416_NUM_CTLS
<= sizeof(ee
->ee_rdEdgesPower
)/NUM_EDGES
);
273 for (i
= 0; ee
->ee_base
.ctlIndex
[i
] != 0 && i
< AR5416_NUM_CTLS
; i
++) {
274 for (j
= 0; j
< NUM_EDGES
; j
++) {
275 /* XXX Confirm this is the right thing to do when an invalid channel is stored */
276 if (ee
->ee_base
.ctlData
[i
].ctlEdges
[CTL_CHAIN
][j
].bChannel
== AR5416_BCHAN_UNUSED
) {
278 rep
[j
].twice_rdEdgePower
= 0;
281 rep
[j
].rdEdge
= fbin2freq(
282 ee
->ee_base
.ctlData
[i
].ctlEdges
[CTL_CHAIN
][j
].bChannel
,
283 (ee
->ee_base
.ctlIndex
[i
] & CTL_MODE_M
) != CTL_11A
);
284 rep
[j
].twice_rdEdgePower
= MS(ee
->ee_base
.ctlData
[i
].ctlEdges
[CTL_CHAIN
][j
].tPowerFlag
, CAL_CTL_EDGES_POWER
);
285 rep
[j
].flag
= MS(ee
->ee_base
.ctlData
[i
].ctlEdges
[CTL_CHAIN
][j
].tPowerFlag
, CAL_CTL_EDGES_FLAG
) != 0;
291 HALDEBUG(ah
, HAL_DEBUG_ATTACH
| HAL_DEBUG_EEPROM
,
292 "%s Numctls = %u\n",__func__
,i
);
296 * Reclaim any EEPROM-related storage.
299 v14EepromDetach(struct ath_hal
*ah
)
301 HAL_EEPROM_v14
*ee
= AH_PRIVATE(ah
)->ah_eeprom
;
304 AH_PRIVATE(ah
)->ah_eeprom
= AH_NULL
;
307 #define owl_get_eep_ver(_ee) \
308 (((_ee)->ee_base.baseEepHeader.version >> 12) & 0xF)
309 #define owl_get_eep_rev(_ee) \
310 (((_ee)->ee_base.baseEepHeader.version) & 0xFFF)
313 ath_hal_v14EepromAttach(struct ath_hal
*ah
)
315 #define NW(a) (sizeof(a) / sizeof(uint16_t))
316 HAL_EEPROM_v14
*ee
= AH_PRIVATE(ah
)->ah_eeprom
;
317 uint16_t *eep_data
, magic
;
322 HALASSERT(ee
== AH_NULL
);
324 if (!ath_hal_eepromRead(ah
, AR5416_EEPROM_MAGIC_OFFSET
, &magic
)) {
325 HALDEBUG(ah
, HAL_DEBUG_ANY
,
326 "%s Error reading Eeprom MAGIC\n", __func__
);
329 HALDEBUG(ah
, HAL_DEBUG_ATTACH
, "%s Eeprom Magic = 0x%x\n",
331 if (magic
!= AR5416_EEPROM_MAGIC
) {
332 HALDEBUG(ah
, HAL_DEBUG_ANY
, "Bad magic number\n");
336 ee
= ath_hal_malloc(sizeof(HAL_EEPROM_v14
));
342 eep_data
= (uint16_t *)&ee
->ee_base
;
343 for (w
= 0; w
< NW(struct ar5416eeprom
); w
++) {
344 off
= owl_eep_start_loc
+ w
; /* NB: AP71 starts at 0 */
345 if (!ath_hal_eepromRead(ah
, off
, &eep_data
[w
])) {
346 HALDEBUG(ah
, HAL_DEBUG_ANY
,
347 "%s eeprom read error at offset 0x%x\n",
352 /* Convert to eeprom native eeprom endian format */
354 for (w
= 0; w
< NW(struct ar5416eeprom
); w
++)
355 eep_data
[w
] = __bswap16(eep_data
[w
]);
359 * At this point, we're in the native eeprom endian format
360 * Now, determine the eeprom endian by looking at byte 26??
362 need_swap
= ((ee
->ee_base
.baseEepHeader
.eepMisc
& AR5416_EEPMISC_BIG_ENDIAN
) != 0) ^ isBigEndian();
364 HALDEBUG(ah
, HAL_DEBUG_ATTACH
| HAL_DEBUG_EEPROM
,
365 "Byte swap EEPROM contents.\n");
366 len
= __bswap16(ee
->ee_base
.baseEepHeader
.length
);
368 len
= ee
->ee_base
.baseEepHeader
.length
;
370 len
= AH_MIN(len
, sizeof(struct ar5416eeprom
)) / sizeof(uint16_t);
372 /* Apply the checksum, done in native eeprom format */
373 /* XXX - Need to check to make sure checksum calculation is done
374 * in the correct endian format. Right now, it seems it would
375 * cast the raw data to host format and do the calculation, which may
376 * not be correct as the calculation may need to be done in the native
380 for (w
= 0; w
< len
; w
++)
382 /* Check CRC - Attach should fail on a bad checksum */
384 HALDEBUG(ah
, HAL_DEBUG_ANY
,
385 "Bad EEPROM checksum 0x%x (Len=%u)\n", sum
, len
);
390 eepromSwap(&ee
->ee_base
); /* byte swap multi-byte data */
392 /* swap words 0+2 so version is at the front */
394 eep_data
[0] = eep_data
[2];
397 HALDEBUG(ah
, HAL_DEBUG_ATTACH
| HAL_DEBUG_EEPROM
,
398 "%s Eeprom Version %u.%u\n", __func__
,
399 owl_get_eep_ver(ee
), owl_get_eep_rev(ee
));
401 /* NB: must be after all byte swapping */
402 if (owl_get_eep_ver(ee
) != AR5416_EEP_VER
) {
403 HALDEBUG(ah
, HAL_DEBUG_ANY
,
404 "Bad EEPROM version 0x%x\n", owl_get_eep_ver(ee
));
408 v14EepromReadCTLInfo(ah
, ee
); /* Get CTLs */
410 AH_PRIVATE(ah
)->ah_eeprom
= ee
;
411 AH_PRIVATE(ah
)->ah_eeversion
= ee
->ee_base
.baseEepHeader
.version
;
412 AH_PRIVATE(ah
)->ah_eepromDetach
= v14EepromDetach
;
413 AH_PRIVATE(ah
)->ah_eepromGet
= v14EepromGet
;
414 AH_PRIVATE(ah
)->ah_eepromSet
= v14EepromSet
;
415 AH_PRIVATE(ah
)->ah_getSpurChan
= v14EepromGetSpurChan
;
416 AH_PRIVATE(ah
)->ah_eepromDiag
= v14EepromDiag
;