sys/dev/netif/ath/ath_hal/ah_eeprom_v1.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 | /* * Copyright (c) 2008 Sam Leffler, Errno Consulting * Copyright (c) 2008 Atheros Communications, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * $FreeBSD$ */ #include "opt_ah.h" #include "ah.h" #include "ah_internal.h" #include "ah_eeprom_v1.h" static HAL_STATUS v1EepromGet(struct ath_hal *ah, int param, void *val) { HAL_EEPROM_v1 *ee = AH_PRIVATE(ah)->ah_eeprom; uint32_t sum; uint16_t eeval; uint8_t *macaddr; int i; switch (param) { case AR_EEP_MACADDR: /* Get MAC Address */ sum = 0; macaddr = val; for (i = 0; i < 3; i++) { if (!ath_hal_eepromRead(ah, AR_EEPROM_MAC(i), &eeval)) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: cannot read EEPROM location %u\n", __func__, i); return HAL_EEREAD; } sum += eeval; macaddr[2*i + 0] = eeval >> 8; macaddr[2*i + 1] = eeval & 0xff; } if (sum == 0 || sum == 0xffff*3) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad mac address %s\n", __func__, ath_hal_ether_sprintf(macaddr)); return HAL_EEBADMAC; } return HAL_OK; case AR_EEP_REGDMN_0: *(uint16_t *) val = ee->ee_regDomain[0]; return HAL_OK; case AR_EEP_RFKILL: HALASSERT(val == AH_NULL); return ee->ee_rfKill ? HAL_OK : HAL_EIO; case AR_EEP_WRITEPROTECT: HALASSERT(val == AH_NULL); return (ee->ee_protect & AR_EEPROM_PROTOTECT_WP_128_191) ? HAL_OK : HAL_EIO; default: HALASSERT(0); return HAL_EINVAL; } } static HAL_STATUS v1EepromSet(struct ath_hal *ah, int param, int v) { return HAL_EINVAL; } static HAL_BOOL v1EepromDiag(struct ath_hal *ah, int request, const void *args, uint32_t argsize, void **result, uint32_t *resultsize) { HAL_EEPROM_v1 *ee = AH_PRIVATE(ah)->ah_eeprom; switch (request) { case HAL_DIAG_EEPROM: *result = ee; *resultsize = sizeof(*ee); return AH_TRUE; } return AH_FALSE; } static uint16_t v1EepromGetSpurChan(struct ath_hal *ah, int ix, HAL_BOOL is2GHz) { return AR_NO_SPUR; } /* * Reclaim any EEPROM-related storage. */ static void v1EepromDetach(struct ath_hal *ah) { HAL_EEPROM_v1 *ee = AH_PRIVATE(ah)->ah_eeprom; ath_hal_free(ee); AH_PRIVATE(ah)->ah_eeprom = AH_NULL; } HAL_STATUS ath_hal_v1EepromAttach(struct ath_hal *ah) { HAL_EEPROM_v1 *ee = AH_PRIVATE(ah)->ah_eeprom; uint16_t athvals[AR_EEPROM_ATHEROS_MAX]; /* XXX off stack */ uint16_t protect, eeprom_version, eeval; uint32_t sum; int i, loc; HALASSERT(ee == AH_NULL); if (!ath_hal_eepromRead(ah, AR_EEPROM_MAGIC, &eeval)) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: cannot read EEPROM magic number\n", __func__); return HAL_EEREAD; } if (eeval != 0x5aa5) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid EEPROM magic number 0x%x\n", __func__, eeval); return HAL_EEMAGIC; } if (!ath_hal_eepromRead(ah, AR_EEPROM_PROTECT, &protect)) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: cannot read EEPROM protection bits; read locked?\n", __func__); return HAL_EEREAD; } HALDEBUG(ah, HAL_DEBUG_ATTACH, "EEPROM protect 0x%x\n", protect); /* XXX check proper access before continuing */ if (!ath_hal_eepromRead(ah, AR_EEPROM_VERSION, &eeprom_version)) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unable to read EEPROM version\n", __func__); return HAL_EEREAD; } if (((eeprom_version>>12) & 0xf) != 1) { /* * This code only groks the version 1 EEPROM layout. */ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unsupported EEPROM version 0x%x found\n", __func__, eeprom_version); return HAL_EEVERSION; } /* * Read the Atheros EEPROM entries and calculate the checksum. */ sum = 0; for (i = 0; i < AR_EEPROM_ATHEROS_MAX; i++) { if (!ath_hal_eepromRead(ah, AR_EEPROM_ATHEROS(i), &athvals[i])) return HAL_EEREAD; sum ^= athvals[i]; } if (sum != 0xffff) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad EEPROM checksum 0x%x\n", __func__, sum); return HAL_EEBADSUM; } /* * Valid checksum, fetch the regulatory domain and save values. */ if (!ath_hal_eepromRead(ah, AR_EEPROM_REG_DOMAIN, &eeval)) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: cannot read regdomain from EEPROM\n", __func__); return HAL_EEREAD; } ee = ath_hal_malloc(sizeof(HAL_EEPROM_v1)); if (ee == AH_NULL) { /* XXX message */ return HAL_ENOMEM; } ee->ee_version = eeprom_version; ee->ee_protect = protect; ee->ee_antenna = athvals[2]; ee->ee_biasCurrents = athvals[3]; ee->ee_thresh62 = athvals[4] & 0xff; ee->ee_xlnaOn = (athvals[4] >> 8) & 0xff; ee->ee_xpaOn = athvals[5] & 0xff; ee->ee_xpaOff = (athvals[5] >> 8) & 0xff; ee->ee_regDomain[0] = (athvals[6] >> 8) & 0xff; ee->ee_regDomain[1] = athvals[6] & 0xff; ee->ee_regDomain[2] = (athvals[7] >> 8) & 0xff; ee->ee_regDomain[3] = athvals[7] & 0xff; ee->ee_rfKill = athvals[8] & 0x1; ee->ee_devType = (athvals[8] >> 1) & 0x7; for (i = 0, loc = AR_EEPROM_ATHEROS_TP_SETTINGS; i < AR_CHANNELS_MAX; i++, loc += AR_TP_SETTINGS_SIZE) { struct tpcMap *chan = &ee->ee_tpc[i]; /* Copy pcdac and gain_f values from EEPROM */ chan->pcdac[0] = (athvals[loc] >> 10) & 0x3F; chan->gainF[0] = (athvals[loc] >> 4) & 0x3F; chan->pcdac[1] = ((athvals[loc] << 2) & 0x3C) | ((athvals[loc+1] >> 14) & 0x03); chan->gainF[1] = (athvals[loc+1] >> 8) & 0x3F; chan->pcdac[2] = (athvals[loc+1] >> 2) & 0x3F; chan->gainF[2] = ((athvals[loc+1] << 4) & 0x30) | ((athvals[loc+2] >> 12) & 0x0F); chan->pcdac[3] = (athvals[loc+2] >> 6) & 0x3F; chan->gainF[3] = athvals[loc+2] & 0x3F; chan->pcdac[4] = (athvals[loc+3] >> 10) & 0x3F; chan->gainF[4] = (athvals[loc+3] >> 4) & 0x3F; chan->pcdac[5] = ((athvals[loc+3] << 2) & 0x3C) | ((athvals[loc+4] >> 14) & 0x03); chan->gainF[5] = (athvals[loc+4] >> 8) & 0x3F; chan->pcdac[6] = (athvals[loc+4] >> 2) & 0x3F; chan->gainF[6] = ((athvals[loc+4] << 4) & 0x30) | ((athvals[loc+5] >> 12) & 0x0F); chan->pcdac[7] = (athvals[loc+5] >> 6) & 0x3F; chan->gainF[7] = athvals[loc+5] & 0x3F; chan->pcdac[8] = (athvals[loc+6] >> 10) & 0x3F; chan->gainF[8] = (athvals[loc+6] >> 4) & 0x3F; chan->pcdac[9] = ((athvals[loc+6] << 2) & 0x3C) | ((athvals[loc+7] >> 14) & 0x03); chan->gainF[9] = (athvals[loc+7] >> 8) & 0x3F; chan->pcdac[10] = (athvals[loc+7] >> 2) & 0x3F; chan->gainF[10] = ((athvals[loc+7] << 4) & 0x30) | ((athvals[loc+8] >> 12) & 0x0F); /* Copy Regulatory Domain and Rate Information from EEPROM */ chan->rate36 = (athvals[loc+8] >> 6) & 0x3F; chan->rate48 = athvals[loc+8] & 0x3F; chan->rate54 = (athvals[loc+9] >> 10) & 0x3F; chan->regdmn[0] = (athvals[loc+9] >> 4) & 0x3F; chan->regdmn[1] = ((athvals[loc+9] << 2) & 0x3C) | ((athvals[loc+10] >> 14) & 0x03); chan->regdmn[2] = (athvals[loc+10] >> 8) & 0x3F; chan->regdmn[3] = (athvals[loc+10] >> 2) & 0x3F; } AH_PRIVATE(ah)->ah_eeprom = ee; AH_PRIVATE(ah)->ah_eeversion = eeprom_version; AH_PRIVATE(ah)->ah_eepromDetach = v1EepromDetach; AH_PRIVATE(ah)->ah_eepromGet = v1EepromGet; AH_PRIVATE(ah)->ah_eepromSet = v1EepromSet; AH_PRIVATE(ah)->ah_getSpurChan = v1EepromGetSpurChan; AH_PRIVATE(ah)->ah_eepromDiag = v1EepromDiag; return HAL_OK; } |