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 * $FreeBSD: head/sys/dev/ath/ath_hal/ah_eeprom_v14.c 186019 2008-12-13 03:49:01Z sam $
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 *(int16_t *)val
= pModal
[0].noiseFloorThreshCh
[0];
42 case AR_EEP_NFTHRESH_2
:
43 *(int16_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
));
59 return pBase
->regDmn
[0];
61 return pBase
->regDmn
[1];
63 return pBase
->deviceCap
;
65 return pBase
->opCapFlags
;
67 return pBase
->rfSilent
;
69 return pModal
[CHAN_A_IDX
].ob
;
71 return pModal
[CHAN_A_IDX
].db
;
73 return pModal
[CHAN_B_IDX
].ob
;
75 return pModal
[CHAN_B_IDX
].db
;
80 case AR_EEP_RXGAIN_TYPE
:
81 return IS_VERS(>=, AR5416_EEP_MINOR_VER_17
) ?
82 pBase
->rxGainType
: AR5416_EEP_RXGAIN_ORIG
;
83 case AR_EEP_TXGAIN_TYPE
:
84 return IS_VERS(>=, AR5416_EEP_MINOR_VER_19
) ?
85 pBase
->txGainType
: AR5416_EEP_TXGAIN_ORIG
;
86 case AR_EEP_FSTCLK_5G
:
87 return IS_VERS(>, AR5416_EEP_MINOR_VER_16
) ?
88 pBase
->fastClk5g
: AH_TRUE
;
89 case AR_EEP_OL_PWRCTRL
:
90 HALASSERT(val
== AH_NULL
);
91 return pBase
->openLoopPwrCntl
? HAL_OK
: HAL_EIO
;
93 HALASSERT(val
== AH_NULL
);
94 return pBase
->opCapFlags
& AR5416_OPFLAGS_11A
?
98 HALASSERT(val
== AH_NULL
);
99 return pBase
->opCapFlags
& AR5416_OPFLAGS_11G
?
101 case AR_EEP_32KHZCRYSTAL
:
102 case AR_EEP_COMPRESS
:
103 case AR_EEP_FASTFRAME
: /* XXX policy decision, h/w can do it */
104 case AR_EEP_WRITEPROTECT
: /* NB: no write protect bit */
105 HALASSERT(val
== AH_NULL
);
107 case AR_EEP_MAXQCU
: /* NB: not in opCapFlags */
108 case AR_EEP_KCENTRIES
: /* NB: not in opCapFlags */
113 case AR_EEP_TURBO5DISABLE
:
114 case AR_EEP_TURBO2DISABLE
:
115 HALASSERT(val
== AH_NULL
);
117 case AR_EEP_ANTGAINMAX_2
:
118 *(int8_t *) val
= ee
->ee_antennaGainMax
[1];
120 case AR_EEP_ANTGAINMAX_5
:
121 *(int8_t *) val
= ee
->ee_antennaGainMax
[0];
133 v14EepromSet(struct ath_hal
*ah
, int param
, int v
)
135 HAL_EEPROM_v14
*ee
= AH_PRIVATE(ah
)->ah_eeprom
;
138 case AR_EEP_ANTGAINMAX_2
:
139 ee
->ee_antennaGainMax
[1] = (int8_t) v
;
141 case AR_EEP_ANTGAINMAX_5
:
142 ee
->ee_antennaGainMax
[0] = (int8_t) v
;
149 v14EepromDiag(struct ath_hal
*ah
, int request
,
150 const void *args
, uint32_t argsize
, void **result
, uint32_t *resultsize
)
152 HAL_EEPROM_v14
*ee
= AH_PRIVATE(ah
)->ah_eeprom
;
155 case HAL_DIAG_EEPROM
:
156 *result
= &ee
->ee_base
;
157 *resultsize
= sizeof(ee
->ee_base
);
163 /* Do structure specific swaps if Eeprom format is non native to host */
165 eepromSwap(struct ar5416eeprom
*ee
)
167 uint32_t integer
, i
, j
;
169 MODAL_EEP_HEADER
*pModal
;
171 /* convert Base Eep header */
172 word
= __bswap16(ee
->baseEepHeader
.length
);
173 ee
->baseEepHeader
.length
= word
;
175 word
= __bswap16(ee
->baseEepHeader
.checksum
);
176 ee
->baseEepHeader
.checksum
= word
;
178 word
= __bswap16(ee
->baseEepHeader
.version
);
179 ee
->baseEepHeader
.version
= word
;
181 word
= __bswap16(ee
->baseEepHeader
.regDmn
[0]);
182 ee
->baseEepHeader
.regDmn
[0] = word
;
184 word
= __bswap16(ee
->baseEepHeader
.regDmn
[1]);
185 ee
->baseEepHeader
.regDmn
[1] = word
;
187 word
= __bswap16(ee
->baseEepHeader
.rfSilent
);
188 ee
->baseEepHeader
.rfSilent
= word
;
190 word
= __bswap16(ee
->baseEepHeader
.blueToothOptions
);
191 ee
->baseEepHeader
.blueToothOptions
= word
;
193 word
= __bswap16(ee
->baseEepHeader
.deviceCap
);
194 ee
->baseEepHeader
.deviceCap
= word
;
196 /* convert Modal Eep header */
197 for (j
= 0; j
< 2; j
++) {
198 pModal
= &ee
->modalHeader
[j
];
200 /* XXX linux/ah_osdep.h only defines __bswap32 for BE */
201 integer
= __bswap32(pModal
->antCtrlCommon
);
202 pModal
->antCtrlCommon
= integer
;
204 for (i
= 0; i
< AR5416_MAX_CHAINS
; i
++) {
205 integer
= __bswap32(pModal
->antCtrlChain
[i
]);
206 pModal
->antCtrlChain
[i
] = integer
;
209 for (i
= 0; i
< AR5416_EEPROM_MODAL_SPURS
; i
++) {
210 word
= __bswap16(pModal
->spurChans
[i
].spurChan
);
211 pModal
->spurChans
[i
].spurChan
= word
;
217 v14EepromGetSpurChan(struct ath_hal
*ah
, int ix
, HAL_BOOL is2GHz
)
219 HAL_EEPROM_v14
*ee
= AH_PRIVATE(ah
)->ah_eeprom
;
221 HALASSERT(0 <= ix
&& ix
< AR5416_EEPROM_MODAL_SPURS
);
222 return ee
->ee_base
.modalHeader
[is2GHz
].spurChans
[ix
].spurChan
;
225 /**************************************************************************
228 * Get channel value from binary representation held in eeprom
229 * RETURNS: the frequency in MHz
232 fbin2freq(uint8_t fbin
, HAL_BOOL is2GHz
)
235 * Reserved value 0xFF provides an empty definition both as
236 * an fbin and as a frequency - do not convert
238 if (fbin
== AR5416_BCHAN_UNUSED
)
240 return (uint16_t)((is2GHz
) ? (2300 + fbin
) : (4800 + 5 * fbin
));
244 * Copy EEPROM Conformance Testing Limits contents
245 * into the allocated space
247 /* USE CTLS from chain zero */
251 v14EepromReadCTLInfo(struct ath_hal
*ah
, HAL_EEPROM_v14
*ee
)
253 RD_EDGES_POWER
*rep
= ee
->ee_rdEdgesPower
;
256 HALASSERT(AR5416_NUM_CTLS
<= sizeof(ee
->ee_rdEdgesPower
)/NUM_EDGES
);
258 for (i
= 0; ee
->ee_base
.ctlIndex
[i
] != 0 && i
< AR5416_NUM_CTLS
; i
++) {
259 for (j
= 0; j
< NUM_EDGES
; j
++) {
260 /* XXX Confirm this is the right thing to do when an invalid channel is stored */
261 if (ee
->ee_base
.ctlData
[i
].ctlEdges
[CTL_CHAIN
][j
].bChannel
== AR5416_BCHAN_UNUSED
) {
263 rep
[j
].twice_rdEdgePower
= 0;
266 rep
[j
].rdEdge
= fbin2freq(
267 ee
->ee_base
.ctlData
[i
].ctlEdges
[CTL_CHAIN
][j
].bChannel
,
268 (ee
->ee_base
.ctlIndex
[i
] & CTL_MODE_M
) != CTL_11A
);
269 rep
[j
].twice_rdEdgePower
= MS(ee
->ee_base
.ctlData
[i
].ctlEdges
[CTL_CHAIN
][j
].tPowerFlag
, CAL_CTL_EDGES_POWER
);
270 rep
[j
].flag
= MS(ee
->ee_base
.ctlData
[i
].ctlEdges
[CTL_CHAIN
][j
].tPowerFlag
, CAL_CTL_EDGES_FLAG
) != 0;
276 HALDEBUG(ah
, HAL_DEBUG_ATTACH
| HAL_DEBUG_EEPROM
,
277 "%s Numctls = %u\n",__func__
,i
);
281 * Reclaim any EEPROM-related storage.
284 v14EepromDetach(struct ath_hal
*ah
)
286 HAL_EEPROM_v14
*ee
= AH_PRIVATE(ah
)->ah_eeprom
;
289 AH_PRIVATE(ah
)->ah_eeprom
= AH_NULL
;
292 #define owl_get_eep_ver(_ee) \
293 (((_ee)->ee_base.baseEepHeader.version >> 12) & 0xF)
294 #define owl_get_eep_rev(_ee) \
295 (((_ee)->ee_base.baseEepHeader.version) & 0xFFF)
298 ath_hal_v14EepromAttach(struct ath_hal
*ah
)
300 #define NW(a) (sizeof(a) / sizeof(uint16_t))
301 HAL_EEPROM_v14
*ee
= AH_PRIVATE(ah
)->ah_eeprom
;
302 uint16_t *eep_data
, magic
;
307 HALASSERT(ee
== AH_NULL
);
309 if (!ath_hal_eepromRead(ah
, AR5416_EEPROM_MAGIC_OFFSET
, &magic
)) {
310 HALDEBUG(ah
, HAL_DEBUG_ANY
,
311 "%s Error reading Eeprom MAGIC\n", __func__
);
314 HALDEBUG(ah
, HAL_DEBUG_ATTACH
, "%s Eeprom Magic = 0x%x\n",
316 if (magic
!= AR5416_EEPROM_MAGIC
) {
317 HALDEBUG(ah
, HAL_DEBUG_ANY
, "Bad magic number\n");
321 ee
= ath_hal_malloc(sizeof(HAL_EEPROM_v14
));
327 eep_data
= (uint16_t *)&ee
->ee_base
;
328 for (w
= 0; w
< NW(struct ar5416eeprom
); w
++) {
329 off
= owl_eep_start_loc
+ w
; /* NB: AP71 starts at 0 */
330 if (!ath_hal_eepromRead(ah
, off
, &eep_data
[w
])) {
331 HALDEBUG(ah
, HAL_DEBUG_ANY
,
332 "%s eeprom read error at offset 0x%x\n",
337 /* Convert to eeprom native eeprom endian format */
339 for (w
= 0; w
< NW(struct ar5416eeprom
); w
++)
340 eep_data
[w
] = __bswap16(eep_data
[w
]);
344 * At this point, we're in the native eeprom endian format
345 * Now, determine the eeprom endian by looking at byte 26??
347 need_swap
= ((ee
->ee_base
.baseEepHeader
.eepMisc
& AR5416_EEPMISC_BIG_ENDIAN
) != 0) ^ isBigEndian();
349 HALDEBUG(ah
, HAL_DEBUG_ATTACH
| HAL_DEBUG_EEPROM
,
350 "Byte swap EEPROM contents.\n");
351 len
= __bswap16(ee
->ee_base
.baseEepHeader
.length
);
353 len
= ee
->ee_base
.baseEepHeader
.length
;
355 len
= AH_MIN(len
, sizeof(struct ar5416eeprom
)) / sizeof(uint16_t);
357 /* Apply the checksum, done in native eeprom format */
358 /* XXX - Need to check to make sure checksum calculation is done
359 * in the correct endian format. Right now, it seems it would
360 * cast the raw data to host format and do the calculation, which may
361 * not be correct as the calculation may need to be done in the native
365 for (w
= 0; w
< len
; w
++)
367 /* Check CRC - Attach should fail on a bad checksum */
369 HALDEBUG(ah
, HAL_DEBUG_ANY
,
370 "Bad EEPROM checksum 0x%x (Len=%u)\n", sum
, len
);
375 eepromSwap(&ee
->ee_base
); /* byte swap multi-byte data */
377 /* swap words 0+2 so version is at the front */
379 eep_data
[0] = eep_data
[2];
382 HALDEBUG(ah
, HAL_DEBUG_ATTACH
| HAL_DEBUG_EEPROM
,
383 "%s Eeprom Version %u.%u\n", __func__
,
384 owl_get_eep_ver(ee
), owl_get_eep_rev(ee
));
386 /* NB: must be after all byte swapping */
387 if (owl_get_eep_ver(ee
) != AR5416_EEP_VER
) {
388 HALDEBUG(ah
, HAL_DEBUG_ANY
,
389 "Bad EEPROM version 0x%x\n", owl_get_eep_ver(ee
));
393 v14EepromReadCTLInfo(ah
, ee
); /* Get CTLs */
395 AH_PRIVATE(ah
)->ah_eeprom
= ee
;
396 AH_PRIVATE(ah
)->ah_eeversion
= ee
->ee_base
.baseEepHeader
.version
;
397 AH_PRIVATE(ah
)->ah_eepromDetach
= v14EepromDetach
;
398 AH_PRIVATE(ah
)->ah_eepromGet
= v14EepromGet
;
399 AH_PRIVATE(ah
)->ah_eepromSet
= v14EepromSet
;
400 AH_PRIVATE(ah
)->ah_getSpurChan
= v14EepromGetSpurChan
;
401 AH_PRIVATE(ah
)->ah_eepromDiag
= v14EepromDiag
;