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.
22 #include "ah_internal.h"
23 #include "ah_eeprom_v14.h"
26 v14EepromGet(struct ath_hal
*ah
, int param
, void *val
)
30 #define IS_VERS(op, v) ((pBase->version & AR5416_EEP_VER_MINOR_MASK) op (v))
31 HAL_EEPROM_v14
*ee
= AH_PRIVATE(ah
)->ah_eeprom
;
32 const MODAL_EEP_HEADER
*pModal
= ee
->ee_base
.modalHeader
;
33 const BASE_EEP_HEADER
*pBase
= &ee
->ee_base
.baseEepHeader
;
39 case AR_EEP_NFTHRESH_5
:
40 *(int8_t *)val
= pModal
[0].noiseFloorThreshCh
[0];
42 case AR_EEP_NFTHRESH_2
:
43 *(int8_t *)val
= pModal
[1].noiseFloorThreshCh
[0];
45 case AR_EEP_MACADDR
: /* Get MAC Address */
48 for (i
= 0; i
< 6; i
++) {
49 macaddr
[i
] = pBase
->macAddr
[i
];
50 sum
+= pBase
->macAddr
[i
];
52 if (sum
== 0 || sum
== 0xffff*3) {
53 HALDEBUG(ah
, HAL_DEBUG_ANY
, "%s: bad mac address %s\n",
54 __func__
, ath_hal_ether_sprintf(macaddr
));
58 return pBase
->regDmn
[0];
60 return pBase
->regDmn
[1];
62 return pBase
->deviceCap
;
64 return pBase
->opCapFlags
;
66 return pBase
->rfSilent
;
68 return pModal
[CHAN_A_IDX
].ob
;
70 return pModal
[CHAN_A_IDX
].db
;
72 return pModal
[CHAN_B_IDX
].ob
;
74 return pModal
[CHAN_B_IDX
].db
;
79 case AR_EEP_RXGAIN_TYPE
:
80 return IS_VERS(>=, AR5416_EEP_MINOR_VER_17
) ?
81 pBase
->rxGainType
: AR5416_EEP_RXGAIN_ORIG
;
82 case AR_EEP_TXGAIN_TYPE
:
83 return IS_VERS(>=, AR5416_EEP_MINOR_VER_19
) ?
84 pBase
->txGainType
: AR5416_EEP_TXGAIN_ORIG
;
85 case AR_EEP_FSTCLK_5G
:
86 return IS_VERS(>, AR5416_EEP_MINOR_VER_16
) ?
87 pBase
->fastClk5g
: AH_TRUE
;
88 case AR_EEP_OL_PWRCTRL
:
89 HALASSERT(val
== AH_NULL
);
90 return pBase
->openLoopPwrCntl
? HAL_OK
: HAL_EIO
;
92 HALASSERT(val
== AH_NULL
);
93 return pBase
->opCapFlags
& AR5416_OPFLAGS_11A
?
97 HALASSERT(val
== AH_NULL
);
98 return pBase
->opCapFlags
& AR5416_OPFLAGS_11G
?
100 case AR_EEP_32KHZCRYSTAL
:
101 case AR_EEP_COMPRESS
:
102 case AR_EEP_FASTFRAME
: /* XXX policy decision, h/w can do it */
103 case AR_EEP_WRITEPROTECT
: /* NB: no write protect bit */
104 HALASSERT(val
== AH_NULL
);
106 case AR_EEP_MAXQCU
: /* NB: not in opCapFlags */
107 case AR_EEP_KCENTRIES
: /* NB: not in opCapFlags */
112 case AR_EEP_TURBO5DISABLE
:
113 case AR_EEP_TURBO2DISABLE
:
114 HALASSERT(val
== AH_NULL
);
116 case AR_EEP_ANTGAINMAX_2
:
117 *(int8_t *) val
= ee
->ee_antennaGainMax
[1];
119 case AR_EEP_ANTGAINMAX_5
:
120 *(int8_t *) val
= ee
->ee_antennaGainMax
[0];
132 v14EepromSet(struct ath_hal
*ah
, int param
, int v
)
134 HAL_EEPROM_v14
*ee
= AH_PRIVATE(ah
)->ah_eeprom
;
137 case AR_EEP_ANTGAINMAX_2
:
138 ee
->ee_antennaGainMax
[1] = (int8_t) v
;
140 case AR_EEP_ANTGAINMAX_5
:
141 ee
->ee_antennaGainMax
[0] = (int8_t) v
;
148 v14EepromDiag(struct ath_hal
*ah
, int request
,
149 const void *args
, uint32_t argsize
, void **result
, uint32_t *resultsize
)
151 HAL_EEPROM_v14
*ee
= AH_PRIVATE(ah
)->ah_eeprom
;
154 case HAL_DIAG_EEPROM
:
155 *result
= &ee
->ee_base
;
156 *resultsize
= sizeof(ee
->ee_base
);
162 /* XXX conditionalize by target byte order */
164 static __inline__
uint16_t
165 __bswap16(uint16_t _x
)
168 (((const uint8_t *)(&_x
))[0] ) |
169 (((const uint8_t *)(&_x
))[1]<< 8))
174 /* Do structure specific swaps if Eeprom format is non native to host */
176 eepromSwap(struct ar5416eeprom
*ee
)
178 uint32_t integer
, i
, j
;
180 MODAL_EEP_HEADER
*pModal
;
182 /* convert Base Eep header */
183 word
= __bswap16(ee
->baseEepHeader
.length
);
184 ee
->baseEepHeader
.length
= word
;
186 word
= __bswap16(ee
->baseEepHeader
.checksum
);
187 ee
->baseEepHeader
.checksum
= word
;
189 word
= __bswap16(ee
->baseEepHeader
.version
);
190 ee
->baseEepHeader
.version
= word
;
192 word
= __bswap16(ee
->baseEepHeader
.regDmn
[0]);
193 ee
->baseEepHeader
.regDmn
[0] = word
;
195 word
= __bswap16(ee
->baseEepHeader
.regDmn
[1]);
196 ee
->baseEepHeader
.regDmn
[1] = word
;
198 word
= __bswap16(ee
->baseEepHeader
.rfSilent
);
199 ee
->baseEepHeader
.rfSilent
= word
;
201 word
= __bswap16(ee
->baseEepHeader
.blueToothOptions
);
202 ee
->baseEepHeader
.blueToothOptions
= word
;
204 word
= __bswap16(ee
->baseEepHeader
.deviceCap
);
205 ee
->baseEepHeader
.deviceCap
= word
;
207 /* convert Modal Eep header */
208 for (j
= 0; j
< 2; j
++) {
209 pModal
= &ee
->modalHeader
[j
];
211 /* XXX linux/ah_osdep.h only defines __bswap32 for BE */
212 integer
= __bswap32(pModal
->antCtrlCommon
);
213 pModal
->antCtrlCommon
= integer
;
215 for (i
= 0; i
< AR5416_MAX_CHAINS
; i
++) {
216 integer
= __bswap32(pModal
->antCtrlChain
[i
]);
217 pModal
->antCtrlChain
[i
] = integer
;
220 for (i
= 0; i
< AR5416_EEPROM_MODAL_SPURS
; i
++) {
221 word
= __bswap16(pModal
->spurChans
[i
].spurChan
);
222 pModal
->spurChans
[i
].spurChan
= word
;
228 v14EepromGetSpurChan(struct ath_hal
*ah
, int ix
, HAL_BOOL is2GHz
)
230 HAL_EEPROM_v14
*ee
= AH_PRIVATE(ah
)->ah_eeprom
;
232 HALASSERT(0 <= ix
&& ix
< AR5416_EEPROM_MODAL_SPURS
);
233 return ee
->ee_base
.modalHeader
[is2GHz
].spurChans
[ix
].spurChan
;
236 /**************************************************************************
239 * Get channel value from binary representation held in eeprom
240 * RETURNS: the frequency in MHz
243 fbin2freq(uint8_t fbin
, HAL_BOOL is2GHz
)
246 * Reserved value 0xFF provides an empty definition both as
247 * an fbin and as a frequency - do not convert
249 if (fbin
== AR5416_BCHAN_UNUSED
)
251 return (uint16_t)((is2GHz
) ? (2300 + fbin
) : (4800 + 5 * fbin
));
255 * Copy EEPROM Conformance Testing Limits contents
256 * into the allocated space
258 /* USE CTLS from chain zero */
262 v14EepromReadCTLInfo(struct ath_hal
*ah
, HAL_EEPROM_v14
*ee
)
264 RD_EDGES_POWER
*rep
= ee
->ee_rdEdgesPower
;
267 HALASSERT(AR5416_NUM_CTLS
<= sizeof(ee
->ee_rdEdgesPower
)/NUM_EDGES
);
269 for (i
= 0; ee
->ee_base
.ctlIndex
[i
] != 0 && i
< AR5416_NUM_CTLS
; i
++) {
270 for (j
= 0; j
< NUM_EDGES
; j
++) {
271 /* XXX Confirm this is the right thing to do when an invalid channel is stored */
272 if (ee
->ee_base
.ctlData
[i
].ctlEdges
[CTL_CHAIN
][j
].bChannel
== AR5416_BCHAN_UNUSED
) {
274 rep
[j
].twice_rdEdgePower
= 0;
277 rep
[j
].rdEdge
= fbin2freq(
278 ee
->ee_base
.ctlData
[i
].ctlEdges
[CTL_CHAIN
][j
].bChannel
,
279 (ee
->ee_base
.ctlIndex
[i
] & CTL_MODE_M
) != CTL_11A
);
280 rep
[j
].twice_rdEdgePower
= MS(ee
->ee_base
.ctlData
[i
].ctlEdges
[CTL_CHAIN
][j
].tPowerFlag
, CAL_CTL_EDGES_POWER
);
281 rep
[j
].flag
= MS(ee
->ee_base
.ctlData
[i
].ctlEdges
[CTL_CHAIN
][j
].tPowerFlag
, CAL_CTL_EDGES_FLAG
) != 0;
287 HALDEBUG(ah
, HAL_DEBUG_ATTACH
| HAL_DEBUG_EEPROM
,
288 "%s Numctls = %u\n",__func__
,i
);
292 * Reclaim any EEPROM-related storage.
295 v14EepromDetach(struct ath_hal
*ah
)
297 HAL_EEPROM_v14
*ee
= AH_PRIVATE(ah
)->ah_eeprom
;
300 AH_PRIVATE(ah
)->ah_eeprom
= AH_NULL
;
303 #define owl_get_eep_ver(_ee) \
304 (((_ee)->ee_base.baseEepHeader.version >> 12) & 0xF)
305 #define owl_get_eep_rev(_ee) \
306 (((_ee)->ee_base.baseEepHeader.version) & 0xFFF)
309 ath_hal_v14EepromAttach(struct ath_hal
*ah
)
311 #define NW(a) (sizeof(a) / sizeof(uint16_t))
312 HAL_EEPROM_v14
*ee
= AH_PRIVATE(ah
)->ah_eeprom
;
313 uint16_t *eep_data
, magic
;
318 HALASSERT(ee
== AH_NULL
);
320 if (!ath_hal_eepromRead(ah
, AR5416_EEPROM_MAGIC_OFFSET
, &magic
)) {
321 HALDEBUG(ah
, HAL_DEBUG_ANY
,
322 "%s Error reading Eeprom MAGIC\n", __func__
);
325 HALDEBUG(ah
, HAL_DEBUG_ATTACH
, "%s Eeprom Magic = 0x%x\n",
327 if (magic
!= AR5416_EEPROM_MAGIC
) {
328 HALDEBUG(ah
, HAL_DEBUG_ANY
, "Bad magic number\n");
332 ee
= ath_hal_malloc(sizeof(HAL_EEPROM_v14
));
338 eep_data
= (uint16_t *)&ee
->ee_base
;
339 for (w
= 0; w
< NW(struct ar5416eeprom
); w
++) {
340 off
= owl_eep_start_loc
+ w
; /* NB: AP71 starts at 0 */
341 if (!ath_hal_eepromRead(ah
, off
, &eep_data
[w
])) {
342 HALDEBUG(ah
, HAL_DEBUG_ANY
,
343 "%s eeprom read error at offset 0x%x\n",
348 /* Convert to eeprom native eeprom endian format */
350 for (w
= 0; w
< NW(struct ar5416eeprom
); w
++)
351 eep_data
[w
] = __bswap16(eep_data
[w
]);
355 * At this point, we're in the native eeprom endian format
356 * Now, determine the eeprom endian by looking at byte 26??
358 need_swap
= ((ee
->ee_base
.baseEepHeader
.eepMisc
& AR5416_EEPMISC_BIG_ENDIAN
) != 0) ^ isBigEndian();
360 HALDEBUG(ah
, HAL_DEBUG_ATTACH
| HAL_DEBUG_EEPROM
,
361 "Byte swap EEPROM contents.\n");
362 len
= __bswap16(ee
->ee_base
.baseEepHeader
.length
);
364 len
= ee
->ee_base
.baseEepHeader
.length
;
366 len
= AH_MIN(len
, sizeof(struct ar5416eeprom
)) / sizeof(uint16_t);
368 /* Apply the checksum, done in native eeprom format */
369 /* XXX - Need to check to make sure checksum calculation is done
370 * in the correct endian format. Right now, it seems it would
371 * cast the raw data to host format and do the calculation, which may
372 * not be correct as the calculation may need to be done in the native
376 for (w
= 0; w
< len
; w
++)
378 /* Check CRC - Attach should fail on a bad checksum */
380 HALDEBUG(ah
, HAL_DEBUG_ANY
,
381 "Bad EEPROM checksum 0x%x (Len=%u)\n", sum
, len
);
386 eepromSwap(&ee
->ee_base
); /* byte swap multi-byte data */
388 /* swap words 0+2 so version is at the front */
390 eep_data
[0] = eep_data
[2];
393 HALDEBUG(ah
, HAL_DEBUG_ATTACH
| HAL_DEBUG_EEPROM
,
394 "%s Eeprom Version %u.%u\n", __func__
,
395 owl_get_eep_ver(ee
), owl_get_eep_rev(ee
));
397 /* NB: must be after all byte swapping */
398 if (owl_get_eep_ver(ee
) != AR5416_EEP_VER
) {
399 HALDEBUG(ah
, HAL_DEBUG_ANY
,
400 "Bad EEPROM version 0x%x\n", owl_get_eep_ver(ee
));
404 v14EepromReadCTLInfo(ah
, ee
); /* Get CTLs */
406 AH_PRIVATE(ah
)->ah_eeprom
= ee
;
407 AH_PRIVATE(ah
)->ah_eeversion
= ee
->ee_base
.baseEepHeader
.version
;
408 AH_PRIVATE(ah
)->ah_eepromDetach
= v14EepromDetach
;
409 AH_PRIVATE(ah
)->ah_eepromGet
= v14EepromGet
;
410 AH_PRIVATE(ah
)->ah_eepromSet
= v14EepromSet
;
411 AH_PRIVATE(ah
)->ah_getSpurChan
= v14EepromGetSpurChan
;
412 AH_PRIVATE(ah
)->ah_eepromDiag
= v14EepromDiag
;