1250003Sadrian/* 2250003Sadrian * Copyright (c) 2013 Qualcomm Atheros, Inc. 3250003Sadrian * 4250003Sadrian * Permission to use, copy, modify, and/or distribute this software for any 5250003Sadrian * purpose with or without fee is hereby granted, provided that the above 6250003Sadrian * copyright notice and this permission notice appear in all copies. 7250003Sadrian * 8250003Sadrian * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 9250003Sadrian * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 10250003Sadrian * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 11250003Sadrian * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 12250003Sadrian * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR 13250003Sadrian * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 14250003Sadrian * PERFORMANCE OF THIS SOFTWARE. 15250003Sadrian */ 16250003Sadrian 17250003Sadrian#include "opt_ah.h" 18250003Sadrian 19250003Sadrian#include "ah.h" 20250003Sadrian#include "ah_internal.h" 21250003Sadrian#include "ah_devid.h" 22250003Sadrian#ifdef AH_DEBUG 23250003Sadrian#include "ah_desc.h" /* NB: for HAL_PHYERR* */ 24250003Sadrian#endif 25250003Sadrian#include "ar9300/ar9300.h" 26250003Sadrian#include "ar9300/ar9300eep.h" 27250003Sadrian#include "ar9300/ar9300template_generic.h" 28250003Sadrian#include "ar9300/ar9300template_xb112.h" 29250003Sadrian#include "ar9300/ar9300template_hb116.h" 30250003Sadrian#include "ar9300/ar9300template_xb113.h" 31250003Sadrian#include "ar9300/ar9300template_hb112.h" 32250003Sadrian#include "ar9300/ar9300template_ap121.h" 33250003Sadrian#include "ar9300/ar9300template_osprey_k31.h" 34250003Sadrian#include "ar9300/ar9300template_wasp_2.h" 35250003Sadrian#include "ar9300/ar9300template_wasp_k31.h" 36250003Sadrian#include "ar9300/ar9300template_aphrodite.h" 37250003Sadrian#include "ar9300/ar9300reg.h" 38250003Sadrian#include "ar9300/ar9300phy.h" 39250003Sadrian 40250003Sadrian 41250003Sadrian 42250003Sadrian#if AH_BYTE_ORDER == AH_BIG_ENDIAN 43250003Sadrianvoid ar9300_swap_eeprom(ar9300_eeprom_t *eep); 44250003Sadrianvoid ar9300_eeprom_template_swap(void); 45250003Sadrian#endif 46250003Sadrian 47250003Sadrianstatic u_int16_t ar9300_eeprom_get_spur_chan(struct ath_hal *ah, 48250008Sadrian int spur_chan, HAL_BOOL is_2ghz); 49250003Sadrian#ifdef UNUSED 50250003Sadrianstatic inline HAL_BOOL ar9300_fill_eeprom(struct ath_hal *ah); 51250003Sadrianstatic inline HAL_STATUS ar9300_check_eeprom(struct ath_hal *ah); 52250003Sadrian#endif 53250003Sadrian 54250003Sadrianstatic ar9300_eeprom_t *default9300[] = 55250003Sadrian{ 56250003Sadrian &ar9300_template_generic, 57250003Sadrian &ar9300_template_xb112, 58250003Sadrian &ar9300_template_hb116, 59250003Sadrian &ar9300_template_hb112, 60250003Sadrian &ar9300_template_xb113, 61250003Sadrian &ar9300_template_ap121, 62250003Sadrian &ar9300_template_wasp_2, 63250003Sadrian &ar9300_template_wasp_k31, 64250003Sadrian &ar9300_template_osprey_k31, 65250003Sadrian &ar9300_template_aphrodite, 66250003Sadrian}; 67250003Sadrian 68250003Sadrian/* 69250003Sadrian * Different types of memory where the calibration data might be stored. 70250003Sadrian * All types are searched in ar9300_eeprom_restore() 71250003Sadrian * in the order flash, eeprom, otp. 72250003Sadrian * To disable searching a type, set its parameter to 0. 73250003Sadrian */ 74250003Sadrian 75250003Sadrian/* 76250003Sadrian * This is where we look for the calibration data. 77250003Sadrian * must be set before ath_attach() is called 78250003Sadrian */ 79250003Sadrianstatic int calibration_data_try = calibration_data_none; 80250003Sadrianstatic int calibration_data_try_address = 0; 81250003Sadrian 82250003Sadrian/* 83250003Sadrian * Set the type of memory used to store calibration data. 84250003Sadrian * Used by nart to force reading/writing of a specific type. 85250003Sadrian * The driver can normally allow autodetection 86250003Sadrian * by setting source to calibration_data_none=0. 87250003Sadrian */ 88250003Sadrianvoid ar9300_calibration_data_set(struct ath_hal *ah, int32_t source) 89250003Sadrian{ 90250003Sadrian if (ah != 0) { 91250003Sadrian AH9300(ah)->calibration_data_source = source; 92250003Sadrian } else { 93250003Sadrian calibration_data_try = source; 94250003Sadrian } 95250003Sadrian} 96250003Sadrian 97250003Sadrianint32_t ar9300_calibration_data_get(struct ath_hal *ah) 98250003Sadrian{ 99250003Sadrian if (ah != 0) { 100250003Sadrian return AH9300(ah)->calibration_data_source; 101250003Sadrian } else { 102250003Sadrian return calibration_data_try; 103250003Sadrian } 104250003Sadrian} 105250003Sadrian 106250003Sadrian/* 107250003Sadrian * Set the address of first byte used to store calibration data. 108250003Sadrian * Used by nart to force reading/writing at a specific address. 109250003Sadrian * The driver can normally allow autodetection by setting size=0. 110250003Sadrian */ 111250003Sadrianvoid ar9300_calibration_data_address_set(struct ath_hal *ah, int32_t size) 112250003Sadrian{ 113250003Sadrian if (ah != 0) { 114250003Sadrian AH9300(ah)->calibration_data_source_address = size; 115250003Sadrian } else { 116250003Sadrian calibration_data_try_address = size; 117250003Sadrian } 118250003Sadrian} 119250003Sadrian 120250003Sadrianint32_t ar9300_calibration_data_address_get(struct ath_hal *ah) 121250003Sadrian{ 122250003Sadrian if (ah != 0) { 123250003Sadrian return AH9300(ah)->calibration_data_source_address; 124250003Sadrian } else { 125250003Sadrian return calibration_data_try_address; 126250003Sadrian } 127250003Sadrian} 128250003Sadrian 129250003Sadrian/* 130250003Sadrian * This is the template that is loaded if ar9300_eeprom_restore() 131250003Sadrian * can't find valid data in the memory. 132250003Sadrian */ 133250003Sadrianstatic int Ar9300_eeprom_template_preference = ar9300_eeprom_template_generic; 134250003Sadrian 135250003Sadrianvoid ar9300_eeprom_template_preference(int32_t value) 136250003Sadrian{ 137250003Sadrian Ar9300_eeprom_template_preference = value; 138250003Sadrian} 139250003Sadrian 140250003Sadrian/* 141250003Sadrian * Install the specified default template. 142250003Sadrian * Overwrites any existing calibration and configuration information in memory. 143250003Sadrian */ 144250003Sadrianint32_t ar9300_eeprom_template_install(struct ath_hal *ah, int32_t value) 145250003Sadrian{ 146250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 147250003Sadrian ar9300_eeprom_t *mptr, *dptr; 148250003Sadrian int mdata_size; 149250003Sadrian 150250003Sadrian mptr = &ahp->ah_eeprom; 151250003Sadrian mdata_size = ar9300_eeprom_struct_size(); 152250003Sadrian if (mptr != 0) { 153250003Sadrian#if 0 154250003Sadrian calibration_data_source = calibration_data_none; 155250003Sadrian calibration_data_source_address = 0; 156250003Sadrian#endif 157250003Sadrian dptr = ar9300_eeprom_struct_default_find_by_id(value); 158250003Sadrian if (dptr != 0) { 159250003Sadrian OS_MEMCPY(mptr, dptr, mdata_size); 160250003Sadrian return 0; 161250003Sadrian } 162250003Sadrian } 163250003Sadrian return -1; 164250003Sadrian} 165250003Sadrian 166250003Sadrianstatic int 167250003Sadrianar9300_eeprom_restore_something(struct ath_hal *ah, ar9300_eeprom_t *mptr, 168250003Sadrian int mdata_size) 169250003Sadrian{ 170250003Sadrian int it; 171250003Sadrian ar9300_eeprom_t *dptr; 172250003Sadrian int nptr; 173250003Sadrian 174250003Sadrian nptr = -1; 175250003Sadrian /* 176250003Sadrian * if we didn't find any blocks in the memory, 177250003Sadrian * put the prefered template in place 178250003Sadrian */ 179250003Sadrian if (nptr < 0) { 180250003Sadrian AH9300(ah)->calibration_data_source = calibration_data_none; 181250003Sadrian AH9300(ah)->calibration_data_source_address = 0; 182250003Sadrian dptr = ar9300_eeprom_struct_default_find_by_id( 183250003Sadrian Ar9300_eeprom_template_preference); 184250003Sadrian if (dptr != 0) { 185250003Sadrian OS_MEMCPY(mptr, dptr, mdata_size); 186250003Sadrian nptr = 0; 187250003Sadrian } 188250003Sadrian } 189250003Sadrian /* 190250003Sadrian * if we didn't find the prefered one, 191250003Sadrian * put the normal default template in place 192250003Sadrian */ 193250003Sadrian if (nptr < 0) { 194250003Sadrian AH9300(ah)->calibration_data_source = calibration_data_none; 195250003Sadrian AH9300(ah)->calibration_data_source_address = 0; 196250003Sadrian dptr = ar9300_eeprom_struct_default_find_by_id( 197250003Sadrian ar9300_eeprom_template_default); 198250003Sadrian if (dptr != 0) { 199250003Sadrian OS_MEMCPY(mptr, dptr, mdata_size); 200250003Sadrian nptr = 0; 201250003Sadrian } 202250003Sadrian } 203250003Sadrian /* 204250003Sadrian * if we can't find the best template, put any old template in place 205250003Sadrian * presume that newer ones are better, so search backwards 206250003Sadrian */ 207250003Sadrian if (nptr < 0) { 208250003Sadrian AH9300(ah)->calibration_data_source = calibration_data_none; 209250003Sadrian AH9300(ah)->calibration_data_source_address = 0; 210250003Sadrian for (it = ar9300_eeprom_struct_default_many() - 1; it >= 0; it--) { 211250003Sadrian dptr = ar9300_eeprom_struct_default(it); 212250003Sadrian if (dptr != 0) { 213250003Sadrian OS_MEMCPY(mptr, dptr, mdata_size); 214250003Sadrian nptr = 0; 215250003Sadrian break; 216250003Sadrian } 217250003Sadrian } 218250003Sadrian } 219250003Sadrian return nptr; 220250003Sadrian} 221250003Sadrian 222250003Sadrian/* 223250003Sadrian * Read 16 bits of data from offset into *data 224250003Sadrian */ 225250003SadrianHAL_BOOL 226250003Sadrianar9300_eeprom_read_word(struct ath_hal *ah, u_int off, u_int16_t *data) 227250003Sadrian{ 228250003Sadrian if (AR_SREV_OSPREY(ah) || AR_SREV_POSEIDON(ah)) 229250003Sadrian { 230250003Sadrian (void) OS_REG_READ(ah, AR9300_EEPROM_OFFSET + (off << AR9300_EEPROM_S)); 231250003Sadrian if (!ath_hal_wait(ah, 232250003Sadrian AR_HOSTIF_REG(ah, AR_EEPROM_STATUS_DATA), 233250003Sadrian AR_EEPROM_STATUS_DATA_BUSY | AR_EEPROM_STATUS_DATA_PROT_ACCESS, 234250008Sadrian 0)) 235250003Sadrian { 236250003Sadrian return AH_FALSE; 237250003Sadrian } 238250003Sadrian *data = MS(OS_REG_READ(ah, 239250003Sadrian AR_HOSTIF_REG(ah, AR_EEPROM_STATUS_DATA)), AR_EEPROM_STATUS_DATA_VAL); 240250003Sadrian return AH_TRUE; 241250003Sadrian } 242250003Sadrian else 243250003Sadrian { 244250003Sadrian *data = 0; 245250003Sadrian return AH_FALSE; 246250003Sadrian } 247250003Sadrian} 248250003Sadrian 249250003Sadrian 250250003SadrianHAL_BOOL 251250003Sadrianar9300_otp_read(struct ath_hal *ah, u_int off, u_int32_t *data, HAL_BOOL is_wifi) 252250003Sadrian{ 253250003Sadrian int time_out = 1000; 254250003Sadrian int status = 0; 255250003Sadrian u_int32_t addr; 256250003Sadrian 257250003Sadrian addr = (AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah))? 258250003Sadrian OTP_MEM_START_ADDRESS_WASP : OTP_MEM_START_ADDRESS; 259250003Sadrian if (!is_wifi) { 260250003Sadrian addr = BTOTP_MEM_START_ADDRESS; 261250003Sadrian } 262250003Sadrian addr += off * 4; /* OTP is 32 bit addressable */ 263250003Sadrian (void) OS_REG_READ(ah, addr); 264250003Sadrian 265250003Sadrian addr = (AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) ? 266250003Sadrian OTP_STATUS0_OTP_SM_BUSY_WASP : OTP_STATUS0_OTP_SM_BUSY; 267250003Sadrian if (!is_wifi) { 268250003Sadrian addr = BTOTP_STATUS0_OTP_SM_BUSY; 269250003Sadrian } 270250003Sadrian while ((time_out > 0) && (!status)) { /* wait for access complete */ 271250003Sadrian /* Read data valid, access not busy, sm not busy */ 272250003Sadrian status = ((OS_REG_READ(ah, addr) & 0x7) == 0x4) ? 1 : 0; 273250003Sadrian time_out--; 274250003Sadrian } 275250003Sadrian if (time_out == 0) { 276250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, 277250003Sadrian "%s: Timed out during OTP Status0 validation\n", __func__); 278250003Sadrian return AH_FALSE; 279250003Sadrian } 280250003Sadrian 281250003Sadrian addr = (AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) ? 282250003Sadrian OTP_STATUS1_EFUSE_READ_DATA_WASP : OTP_STATUS1_EFUSE_READ_DATA; 283250003Sadrian if (!is_wifi) { 284250003Sadrian addr = BTOTP_STATUS1_EFUSE_READ_DATA; 285250003Sadrian } 286250003Sadrian *data = OS_REG_READ(ah, addr); 287250003Sadrian return AH_TRUE; 288250003Sadrian} 289250003Sadrian 290250003Sadrian 291250003Sadrian 292250003Sadrian 293250003Sadrianstatic HAL_STATUS 294250003Sadrianar9300_flash_map(struct ath_hal *ah) 295250003Sadrian{ 296250008Sadrian /* XXX disable flash remapping for now (ie, SoC support) */ 297250008Sadrian ath_hal_printf(ah, "%s: unimplemented for now\n", __func__); 298250008Sadrian#if 0 299250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 300250003Sadrian#if defined(AR9100) || defined(__NetBSD__) 301250003Sadrian ahp->ah_cal_mem = OS_REMAP(ah, AR9300_EEPROM_START_ADDR, AR9300_EEPROM_MAX); 302250003Sadrian#else 303250003Sadrian ahp->ah_cal_mem = OS_REMAP((uintptr_t)(AH_PRIVATE(ah)->ah_st), 304250003Sadrian (AR9300_EEPROM_MAX + AR9300_FLASH_CAL_START_OFFSET)); 305250003Sadrian#endif 306250003Sadrian if (!ahp->ah_cal_mem) { 307250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, 308250003Sadrian "%s: cannot remap eeprom region \n", __func__); 309250003Sadrian return HAL_EIO; 310250003Sadrian } 311250008Sadrian#endif 312250003Sadrian return HAL_OK; 313250003Sadrian} 314250003Sadrian 315250003SadrianHAL_BOOL 316250003Sadrianar9300_flash_read(struct ath_hal *ah, u_int off, u_int16_t *data) 317250003Sadrian{ 318250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 319250003Sadrian 320250003Sadrian *data = ((u_int16_t *)ahp->ah_cal_mem)[off]; 321250003Sadrian return AH_TRUE; 322250003Sadrian} 323250003Sadrian 324250003SadrianHAL_BOOL 325250003Sadrianar9300_flash_write(struct ath_hal *ah, u_int off, u_int16_t data) 326250003Sadrian{ 327250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 328250003Sadrian 329250003Sadrian ((u_int16_t *)ahp->ah_cal_mem)[off] = data; 330250003Sadrian return AH_TRUE; 331250003Sadrian} 332250003Sadrian 333250003SadrianHAL_STATUS 334250003Sadrianar9300_eeprom_attach(struct ath_hal *ah) 335250003Sadrian{ 336250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 337250003Sadrian ahp->try_dram = 1; 338250003Sadrian ahp->try_eeprom = 1; 339250003Sadrian ahp->try_otp = 1; 340250003Sadrian#ifdef ATH_CAL_NAND_FLASH 341250003Sadrian ahp->try_nand = 1; 342250003Sadrian#else 343250003Sadrian ahp->try_flash = 1; 344250003Sadrian#endif 345250003Sadrian ahp->calibration_data_source = calibration_data_none; 346250003Sadrian ahp->calibration_data_source_address = 0; 347250003Sadrian ahp->calibration_data_try = calibration_data_try; 348250003Sadrian ahp->calibration_data_try_address = 0; 349250003Sadrian 350250003Sadrian /* 351250003Sadrian * In case flash will be used for EEPROM. Otherwise ahp->ah_cal_mem 352250003Sadrian * must be set to NULL or the real EEPROM address. 353250003Sadrian */ 354250003Sadrian ar9300_flash_map(ah); 355250003Sadrian /* 356250003Sadrian * ###### This function always return NO SPUR. 357250003Sadrian * This is not AH_TRUE for many board designs. 358250003Sadrian * Does anyone use this? 359250003Sadrian */ 360250008Sadrian AH_PRIVATE(ah)->ah_getSpurChan = ar9300_eeprom_get_spur_chan; 361250003Sadrian 362250003Sadrian#ifdef OLDCODE 363250003Sadrian /* XXX Needs to be moved for dynamic selection */ 364250003Sadrian ahp->ah_eeprom = *(default9300[ar9300_eeprom_template_default]); 365250003Sadrian 366250003Sadrian 367250003Sadrian if (AR_SREV_HORNET(ah)) { 368250003Sadrian /* Set default values for Hornet. */ 369250003Sadrian ahp->ah_eeprom.base_eep_header.op_cap_flags.op_flags = 370250003Sadrian AR9300_OPFLAGS_11G; 371250003Sadrian ahp->ah_eeprom.base_eep_header.txrx_mask = 0x11; 372250003Sadrian } else if (AR_SREV_POSEIDON(ah)) { 373250003Sadrian /* Set default values for Poseidon. */ 374250003Sadrian ahp->ah_eeprom.base_eep_header.op_cap_flags.op_flags = 375250003Sadrian AR9300_OPFLAGS_11G; 376250003Sadrian ahp->ah_eeprom.base_eep_header.txrx_mask = 0x11; 377250003Sadrian } 378250003Sadrian 379250003Sadrian if (AH_PRIVATE(ah)->ah_config.ath_hal_skip_eeprom_read) { 380250003Sadrian ahp->ah_emu_eeprom = 1; 381250003Sadrian return HAL_OK; 382250003Sadrian } 383250003Sadrian 384250003Sadrian ahp->ah_emu_eeprom = 1; 385250003Sadrian 386250003Sadrian#ifdef UNUSED 387250003Sadrian#endif 388250003Sadrian 389250003Sadrian if (!ar9300_fill_eeprom(ah)) { 390250003Sadrian return HAL_EIO; 391250003Sadrian } 392250003Sadrian 393250003Sadrian return HAL_OK; 394250003Sadrian /* return ar9300_check_eeprom(ah); */ 395250003Sadrian#else 396250003Sadrian ahp->ah_emu_eeprom = 1; 397250003Sadrian 398250003Sadrian#if 0 399250003Sadrian/*#ifdef MDK_AP*/ /* MDK_AP is defined only in NART AP build */ 400250003Sadrian u_int8_t buffer[10]; 401250003Sadrian int caldata_check = 0; 402250003Sadrian 403250003Sadrian ar9300_calibration_data_read_flash( 404250003Sadrian ah, FLASH_BASE_CALDATA_OFFSET, buffer, 4); 405250003Sadrian printf("flash caldata:: %x\n", buffer[0]); 406250003Sadrian if (buffer[0] != 0xff) { 407250003Sadrian caldata_check = 1; 408250003Sadrian } 409250003Sadrian if (!caldata_check) { 410250003Sadrian ar9300_eeprom_t *mptr; 411250003Sadrian int mdata_size; 412250003Sadrian if (AR_SREV_HORNET(ah)) { 413250003Sadrian /* XXX: For initial testing */ 414250003Sadrian mptr = &ahp->ah_eeprom; 415250003Sadrian mdata_size = ar9300_eeprom_struct_size(); 416250003Sadrian ahp->ah_eeprom = ar9300_template_ap121; 417250003Sadrian ahp->ah_emu_eeprom = 1; 418250003Sadrian /* need it to let art save in to flash ????? */ 419250003Sadrian calibration_data_source = calibration_data_flash; 420250003Sadrian } else if (AR_SREV_WASP(ah)) { 421250003Sadrian /* XXX: For initial testing */ 422250003Sadrian ath_hal_printf(ah, " wasp eep attach\n"); 423250003Sadrian mptr = &ahp->ah_eeprom; 424250003Sadrian mdata_size = ar9300_eeprom_struct_size(); 425250003Sadrian ahp->ah_eeprom = ar9300_template_generic; 426250003Sadrian ahp->ah_eeprom.mac_addr[0] = 0x00; 427250003Sadrian ahp->ah_eeprom.mac_addr[1] = 0x03; 428250003Sadrian ahp->ah_eeprom.mac_addr[2] = 0x7F; 429250003Sadrian ahp->ah_eeprom.mac_addr[3] = 0xBA; 430250003Sadrian ahp->ah_eeprom.mac_addr[4] = 0xD0; 431250003Sadrian ahp->ah_eeprom.mac_addr[5] = 0x00; 432250003Sadrian ahp->ah_emu_eeprom = 1; 433250003Sadrian ahp->ah_eeprom.base_eep_header.txrx_mask = 0x33; 434250003Sadrian ahp->ah_eeprom.base_eep_header.txrxgain = 0x10; 435250003Sadrian /* need it to let art save in to flash ????? */ 436250003Sadrian calibration_data_source = calibration_data_flash; 437250003Sadrian } 438250003Sadrian return HAL_OK; 439250003Sadrian } 440250003Sadrian#endif 441250003Sadrian if (AR_SREV_HORNET(ah) || AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) { 442250003Sadrian ahp->try_eeprom = 0; 443250003Sadrian } 444250003Sadrian 445250003Sadrian if (!ar9300_eeprom_restore(ah)) { 446250003Sadrian return HAL_EIO; 447250003Sadrian } 448250003Sadrian return HAL_OK; 449250003Sadrian#endif 450250003Sadrian} 451250003Sadrian 452250003Sadrianu_int32_t 453250003Sadrianar9300_eeprom_get(struct ath_hal_9300 *ahp, EEPROM_PARAM param) 454250003Sadrian{ 455250003Sadrian ar9300_eeprom_t *eep = &ahp->ah_eeprom; 456250003Sadrian OSPREY_BASE_EEP_HEADER *p_base = &eep->base_eep_header; 457250003Sadrian OSPREY_BASE_EXTENSION_1 *base_ext1 = &eep->base_ext1; 458250003Sadrian 459250003Sadrian switch (param) { 460250008Sadrian#ifdef NOTYET 461250003Sadrian case EEP_NFTHRESH_5: 462250003Sadrian return p_modal[0].noise_floor_thresh_ch[0]; 463250003Sadrian case EEP_NFTHRESH_2: 464250003Sadrian return p_modal[1].noise_floor_thresh_ch[0]; 465250003Sadrian#endif 466250003Sadrian case EEP_MAC_LSW: 467250003Sadrian return eep->mac_addr[0] << 8 | eep->mac_addr[1]; 468250003Sadrian case EEP_MAC_MID: 469250003Sadrian return eep->mac_addr[2] << 8 | eep->mac_addr[3]; 470250003Sadrian case EEP_MAC_MSW: 471250003Sadrian return eep->mac_addr[4] << 8 | eep->mac_addr[5]; 472250003Sadrian case EEP_REG_0: 473250003Sadrian return p_base->reg_dmn[0]; 474250003Sadrian case EEP_REG_1: 475250003Sadrian return p_base->reg_dmn[1]; 476250003Sadrian case EEP_OP_CAP: 477250003Sadrian return p_base->device_cap; 478250003Sadrian case EEP_OP_MODE: 479250003Sadrian return p_base->op_cap_flags.op_flags; 480250003Sadrian case EEP_RF_SILENT: 481250003Sadrian return p_base->rf_silent; 482250008Sadrian#ifdef NOTYET 483250003Sadrian case EEP_OB_5: 484250003Sadrian return p_modal[0].ob; 485250003Sadrian case EEP_DB_5: 486250003Sadrian return p_modal[0].db; 487250003Sadrian case EEP_OB_2: 488250003Sadrian return p_modal[1].ob; 489250003Sadrian case EEP_DB_2: 490250003Sadrian return p_modal[1].db; 491250003Sadrian case EEP_MINOR_REV: 492250003Sadrian return p_base->eeprom_version & AR9300_EEP_VER_MINOR_MASK; 493250003Sadrian#endif 494250003Sadrian case EEP_TX_MASK: 495250003Sadrian return (p_base->txrx_mask >> 4) & 0xf; 496250003Sadrian case EEP_RX_MASK: 497250003Sadrian return p_base->txrx_mask & 0xf; 498250008Sadrian#ifdef NOTYET 499250003Sadrian case EEP_FSTCLK_5G: 500250003Sadrian return p_base->fast_clk5g; 501250003Sadrian case EEP_RXGAIN_TYPE: 502250003Sadrian return p_base->rx_gain_type; 503250003Sadrian#endif 504250003Sadrian case EEP_DRIVE_STRENGTH: 505250003Sadrian#define AR9300_EEP_BASE_DRIVE_STRENGTH 0x1 506250003Sadrian return p_base->misc_configuration & AR9300_EEP_BASE_DRIVE_STRENGTH; 507250003Sadrian case EEP_INTERNAL_REGULATOR: 508250003Sadrian /* Bit 4 is internal regulator flag */ 509250003Sadrian return ((p_base->feature_enable & 0x10) >> 4); 510250003Sadrian case EEP_SWREG: 511250003Sadrian return (p_base->swreg); 512250003Sadrian case EEP_PAPRD_ENABLED: 513250003Sadrian /* Bit 5 is paprd flag */ 514250003Sadrian return ((p_base->feature_enable & 0x20) >> 5); 515250003Sadrian case EEP_ANTDIV_control: 516250003Sadrian return (u_int32_t)(base_ext1->ant_div_control); 517250003Sadrian case EEP_CHAIN_MASK_REDUCE: 518250003Sadrian return ((p_base->misc_configuration >> 3) & 0x1); 519250003Sadrian case EEP_OL_PWRCTRL: 520250003Sadrian return 0; 521250003Sadrian case EEP_DEV_TYPE: 522250003Sadrian return p_base->device_type; 523250003Sadrian default: 524250003Sadrian HALASSERT(0); 525250003Sadrian return 0; 526250003Sadrian } 527250003Sadrian} 528250003Sadrian 529250003Sadrian 530250003Sadrian 531250003Sadrian/******************************************************************************/ 532250003Sadrian/*! 533250003Sadrian** \brief EEPROM fixup code for INI values 534250003Sadrian** 535250003Sadrian** This routine provides a place to insert "fixup" code for specific devices 536250003Sadrian** that need to modify INI values based on EEPROM values, BEFORE the INI values 537250003Sadrian** are written. 538250003Sadrian** Certain registers in the INI file can only be written once without 539250003Sadrian** undesired side effects, and this provides a place for EEPROM overrides 540250003Sadrian** in these cases. 541250003Sadrian** 542250003Sadrian** This is called at attach time once. It should not affect run time 543250003Sadrian** performance at all 544250003Sadrian** 545250003Sadrian** \param ah Pointer to HAL object (this) 546250003Sadrian** \param p_eep_data Pointer to (filled in) eeprom data structure 547250003Sadrian** \param reg register being inspected on this call 548250003Sadrian** \param value value in INI file 549250003Sadrian** 550250003Sadrian** \return Updated value for INI file. 551250003Sadrian*/ 552250003Sadrianu_int32_t 553250003Sadrianar9300_ini_fixup(struct ath_hal *ah, ar9300_eeprom_t *p_eep_data, 554250003Sadrian u_int32_t reg, u_int32_t value) 555250003Sadrian{ 556250003Sadrian HALDEBUG(AH_NULL, HAL_DEBUG_UNMASKABLE, 557250003Sadrian "ar9300_eeprom_def_ini_fixup: FIXME\n"); 558250003Sadrian#if 0 559250003Sadrian BASE_EEPDEF_HEADER *p_base = &(p_eep_data->base_eep_header); 560250003Sadrian 561250003Sadrian switch (AH_PRIVATE(ah)->ah_devid) 562250003Sadrian { 563250003Sadrian case AR9300_DEVID_AR9300_PCI: 564250003Sadrian /* 565250003Sadrian ** Need to set the external/internal regulator bit to the proper value. 566250003Sadrian ** Can only write this ONCE. 567250003Sadrian */ 568250003Sadrian 569250003Sadrian if ( reg == 0x7894 ) 570250003Sadrian { 571250003Sadrian /* 572250003Sadrian ** Check for an EEPROM data structure of "0x0b" or better 573250003Sadrian */ 574250003Sadrian 575250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, "ini VAL: %x EEPROM: %x\n", 576250003Sadrian value, (p_base->version & 0xff)); 577250003Sadrian 578250003Sadrian if ( (p_base->version & 0xff) > 0x0a) { 579250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, 580250003Sadrian "PWDCLKIND: %d\n", p_base->pwdclkind); 581250003Sadrian value &= ~AR_AN_TOP2_PWDCLKIND; 582250003Sadrian value |= 583250003Sadrian AR_AN_TOP2_PWDCLKIND & 584250003Sadrian (p_base->pwdclkind << AR_AN_TOP2_PWDCLKIND_S); 585250003Sadrian } else { 586250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, "PWDCLKIND Earlier Rev\n"); 587250003Sadrian } 588250003Sadrian 589250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, "final ini VAL: %x\n", value); 590250003Sadrian } 591250003Sadrian break; 592250003Sadrian 593250003Sadrian } 594250003Sadrian 595250003Sadrian return (value); 596250003Sadrian#else 597250003Sadrian return 0; 598250003Sadrian#endif 599250003Sadrian} 600250003Sadrian 601250003Sadrian/* 602250003Sadrian * Returns the interpolated y value corresponding to the specified x value 603250003Sadrian * from the np ordered pairs of data (px,py). 604250003Sadrian * The pairs do not have to be in any order. 605250003Sadrian * If the specified x value is less than any of the px, 606250003Sadrian * the returned y value is equal to the py for the lowest px. 607250003Sadrian * If the specified x value is greater than any of the px, 608250003Sadrian * the returned y value is equal to the py for the highest px. 609250003Sadrian */ 610250003Sadrianstatic int 611250003Sadrianinterpolate(int32_t x, int32_t *px, int32_t *py, u_int16_t np) 612250003Sadrian{ 613250003Sadrian int ip = 0; 614250003Sadrian int lx = 0, ly = 0, lhave = 0; 615250003Sadrian int hx = 0, hy = 0, hhave = 0; 616250003Sadrian int dx = 0; 617250003Sadrian int y = 0; 618250003Sadrian int bf, factor, plus; 619250003Sadrian 620250003Sadrian lhave = 0; 621250003Sadrian hhave = 0; 622250003Sadrian /* 623250003Sadrian * identify best lower and higher x calibration measurement 624250003Sadrian */ 625250003Sadrian for (ip = 0; ip < np; ip++) { 626250003Sadrian dx = x - px[ip]; 627250003Sadrian /* this measurement is higher than our desired x */ 628250003Sadrian if (dx <= 0) { 629250003Sadrian if (!hhave || dx > (x - hx)) { 630250003Sadrian /* new best higher x measurement */ 631250003Sadrian hx = px[ip]; 632250003Sadrian hy = py[ip]; 633250003Sadrian hhave = 1; 634250003Sadrian } 635250003Sadrian } 636250003Sadrian /* this measurement is lower than our desired x */ 637250003Sadrian if (dx >= 0) { 638250003Sadrian if (!lhave || dx < (x - lx)) { 639250003Sadrian /* new best lower x measurement */ 640250003Sadrian lx = px[ip]; 641250003Sadrian ly = py[ip]; 642250003Sadrian lhave = 1; 643250003Sadrian } 644250003Sadrian } 645250003Sadrian } 646250003Sadrian /* the low x is good */ 647250003Sadrian if (lhave) { 648250003Sadrian /* so is the high x */ 649250003Sadrian if (hhave) { 650250003Sadrian /* they're the same, so just pick one */ 651250003Sadrian if (hx == lx) { 652250003Sadrian y = ly; 653250003Sadrian } else { 654250003Sadrian /* interpolate with round off */ 655250003Sadrian bf = (2 * (hy - ly) * (x - lx)) / (hx - lx); 656250003Sadrian plus = (bf % 2); 657250003Sadrian factor = bf / 2; 658250003Sadrian y = ly + factor + plus; 659250003Sadrian } 660250003Sadrian } else { 661250003Sadrian /* only low is good, use it */ 662250003Sadrian y = ly; 663250003Sadrian } 664250003Sadrian } else if (hhave) { 665250003Sadrian /* only high is good, use it */ 666250003Sadrian y = hy; 667250003Sadrian } else { 668250003Sadrian /* nothing is good,this should never happen unless np=0, ???? */ 669250003Sadrian y = -(1 << 30); 670250003Sadrian } 671250003Sadrian 672250003Sadrian return y; 673250003Sadrian} 674250003Sadrian 675250003Sadrianu_int8_t 676250003Sadrianar9300_eeprom_get_legacy_trgt_pwr(struct ath_hal *ah, u_int16_t rate_index, 677250003Sadrian u_int16_t freq, HAL_BOOL is_2ghz) 678250003Sadrian{ 679250003Sadrian u_int16_t num_piers, i; 680250003Sadrian int32_t target_power_array[OSPREY_NUM_5G_20_TARGET_POWERS]; 681250003Sadrian int32_t freq_array[OSPREY_NUM_5G_20_TARGET_POWERS]; 682250003Sadrian u_int8_t *p_freq_bin; 683250003Sadrian ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom; 684250003Sadrian CAL_TARGET_POWER_LEG *p_eeprom_target_pwr; 685250003Sadrian 686250003Sadrian if (is_2ghz) { 687250003Sadrian num_piers = OSPREY_NUM_2G_20_TARGET_POWERS; 688250003Sadrian p_eeprom_target_pwr = eep->cal_target_power_2g; 689250003Sadrian p_freq_bin = eep->cal_target_freqbin_2g; 690250003Sadrian } else { 691250003Sadrian num_piers = OSPREY_NUM_5G_20_TARGET_POWERS; 692250003Sadrian p_eeprom_target_pwr = eep->cal_target_power_5g; 693250003Sadrian p_freq_bin = eep->cal_target_freqbin_5g; 694250003Sadrian } 695250003Sadrian 696250003Sadrian /* 697250003Sadrian * create array of channels and targetpower from 698250003Sadrian * targetpower piers stored on eeprom 699250003Sadrian */ 700250003Sadrian for (i = 0; i < num_piers; i++) { 701250003Sadrian freq_array[i] = FBIN2FREQ(p_freq_bin[i], is_2ghz); 702250003Sadrian target_power_array[i] = p_eeprom_target_pwr[i].t_pow2x[rate_index]; 703250003Sadrian } 704250003Sadrian 705250003Sadrian /* interpolate to get target power for given frequency */ 706250003Sadrian return 707250003Sadrian ((u_int8_t)interpolate( 708250003Sadrian (int32_t)freq, freq_array, target_power_array, num_piers)); 709250003Sadrian} 710250003Sadrian 711250003Sadrianu_int8_t 712250003Sadrianar9300_eeprom_get_ht20_trgt_pwr(struct ath_hal *ah, u_int16_t rate_index, 713250003Sadrian u_int16_t freq, HAL_BOOL is_2ghz) 714250003Sadrian{ 715250003Sadrian u_int16_t num_piers, i; 716250003Sadrian int32_t target_power_array[OSPREY_NUM_5G_20_TARGET_POWERS]; 717250003Sadrian int32_t freq_array[OSPREY_NUM_5G_20_TARGET_POWERS]; 718250003Sadrian u_int8_t *p_freq_bin; 719250003Sadrian ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom; 720250003Sadrian OSP_CAL_TARGET_POWER_HT *p_eeprom_target_pwr; 721250003Sadrian 722250003Sadrian if (is_2ghz) { 723250003Sadrian num_piers = OSPREY_NUM_2G_20_TARGET_POWERS; 724250003Sadrian p_eeprom_target_pwr = eep->cal_target_power_2g_ht20; 725250003Sadrian p_freq_bin = eep->cal_target_freqbin_2g_ht20; 726250003Sadrian } else { 727250003Sadrian num_piers = OSPREY_NUM_5G_20_TARGET_POWERS; 728250003Sadrian p_eeprom_target_pwr = eep->cal_target_power_5g_ht20; 729250003Sadrian p_freq_bin = eep->cal_target_freqbin_5g_ht20; 730250003Sadrian } 731250003Sadrian 732250003Sadrian /* 733250003Sadrian * create array of channels and targetpower from 734250003Sadrian * targetpower piers stored on eeprom 735250003Sadrian */ 736250003Sadrian for (i = 0; i < num_piers; i++) { 737250003Sadrian freq_array[i] = FBIN2FREQ(p_freq_bin[i], is_2ghz); 738250003Sadrian target_power_array[i] = p_eeprom_target_pwr[i].t_pow2x[rate_index]; 739250003Sadrian } 740250003Sadrian 741250003Sadrian /* interpolate to get target power for given frequency */ 742250003Sadrian return 743250003Sadrian ((u_int8_t)interpolate( 744250003Sadrian (int32_t)freq, freq_array, target_power_array, num_piers)); 745250003Sadrian} 746250003Sadrian 747250003Sadrianu_int8_t 748250003Sadrianar9300_eeprom_get_ht40_trgt_pwr(struct ath_hal *ah, u_int16_t rate_index, 749250003Sadrian u_int16_t freq, HAL_BOOL is_2ghz) 750250003Sadrian{ 751250003Sadrian u_int16_t num_piers, i; 752250003Sadrian int32_t target_power_array[OSPREY_NUM_5G_40_TARGET_POWERS]; 753250003Sadrian int32_t freq_array[OSPREY_NUM_5G_40_TARGET_POWERS]; 754250003Sadrian u_int8_t *p_freq_bin; 755250003Sadrian ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom; 756250003Sadrian OSP_CAL_TARGET_POWER_HT *p_eeprom_target_pwr; 757250003Sadrian 758250003Sadrian if (is_2ghz) { 759250003Sadrian num_piers = OSPREY_NUM_2G_40_TARGET_POWERS; 760250003Sadrian p_eeprom_target_pwr = eep->cal_target_power_2g_ht40; 761250003Sadrian p_freq_bin = eep->cal_target_freqbin_2g_ht40; 762250003Sadrian } else { 763250003Sadrian num_piers = OSPREY_NUM_5G_40_TARGET_POWERS; 764250003Sadrian p_eeprom_target_pwr = eep->cal_target_power_5g_ht40; 765250003Sadrian p_freq_bin = eep->cal_target_freqbin_5g_ht40; 766250003Sadrian } 767250003Sadrian 768250003Sadrian /* 769250003Sadrian * create array of channels and targetpower from 770250003Sadrian * targetpower piers stored on eeprom 771250003Sadrian */ 772250003Sadrian for (i = 0; i < num_piers; i++) { 773250003Sadrian freq_array[i] = FBIN2FREQ(p_freq_bin[i], is_2ghz); 774250003Sadrian target_power_array[i] = p_eeprom_target_pwr[i].t_pow2x[rate_index]; 775250003Sadrian } 776250003Sadrian 777250003Sadrian /* interpolate to get target power for given frequency */ 778250003Sadrian return 779250003Sadrian ((u_int8_t)interpolate( 780250003Sadrian (int32_t)freq, freq_array, target_power_array, num_piers)); 781250003Sadrian} 782250003Sadrian 783250003Sadrianu_int8_t 784250003Sadrianar9300_eeprom_get_cck_trgt_pwr(struct ath_hal *ah, u_int16_t rate_index, 785250003Sadrian u_int16_t freq) 786250003Sadrian{ 787250003Sadrian u_int16_t num_piers = OSPREY_NUM_2G_CCK_TARGET_POWERS, i; 788250003Sadrian int32_t target_power_array[OSPREY_NUM_2G_CCK_TARGET_POWERS]; 789250003Sadrian int32_t freq_array[OSPREY_NUM_2G_CCK_TARGET_POWERS]; 790250003Sadrian ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom; 791250003Sadrian u_int8_t *p_freq_bin = eep->cal_target_freqbin_cck; 792250003Sadrian CAL_TARGET_POWER_LEG *p_eeprom_target_pwr = eep->cal_target_power_cck; 793250003Sadrian 794250003Sadrian /* 795250003Sadrian * create array of channels and targetpower from 796250003Sadrian * targetpower piers stored on eeprom 797250003Sadrian */ 798250003Sadrian for (i = 0; i < num_piers; i++) { 799250003Sadrian freq_array[i] = FBIN2FREQ(p_freq_bin[i], 1); 800250003Sadrian target_power_array[i] = p_eeprom_target_pwr[i].t_pow2x[rate_index]; 801250003Sadrian } 802250003Sadrian 803250003Sadrian /* interpolate to get target power for given frequency */ 804250003Sadrian return 805250003Sadrian ((u_int8_t)interpolate( 806250003Sadrian (int32_t)freq, freq_array, target_power_array, num_piers)); 807250003Sadrian} 808250003Sadrian 809250003Sadrian/* 810250003Sadrian * Set tx power registers to array of values passed in 811250003Sadrian */ 812250003Sadrianint 813250003Sadrianar9300_transmit_power_reg_write(struct ath_hal *ah, u_int8_t *p_pwr_array) 814250003Sadrian{ 815250003Sadrian#define POW_SM(_r, _s) (((_r) & 0x3f) << (_s)) 816250003Sadrian /* make sure forced gain is not set */ 817250003Sadrian#if 0 818250003Sadrian field_write("force_dac_gain", 0); 819250003Sadrian OS_REG_WRITE(ah, 0xa3f8, 0); 820250003Sadrian field_write("force_tx_gain", 0); 821250003Sadrian#endif 822250003Sadrian 823250003Sadrian OS_REG_WRITE(ah, 0xa458, 0); 824250003Sadrian 825250003Sadrian /* Write the OFDM power per rate set */ 826250003Sadrian /* 6 (LSB), 9, 12, 18 (MSB) */ 827250003Sadrian OS_REG_WRITE(ah, 0xa3c0, 828250003Sadrian POW_SM(p_pwr_array[ALL_TARGET_LEGACY_6_24], 24) 829250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_LEGACY_6_24], 16) 830250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_LEGACY_6_24], 8) 831250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_LEGACY_6_24], 0) 832250003Sadrian ); 833250003Sadrian /* 24 (LSB), 36, 48, 54 (MSB) */ 834250003Sadrian OS_REG_WRITE(ah, 0xa3c4, 835250003Sadrian POW_SM(p_pwr_array[ALL_TARGET_LEGACY_54], 24) 836250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_LEGACY_48], 16) 837250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_LEGACY_36], 8) 838250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_LEGACY_6_24], 0) 839250003Sadrian ); 840250003Sadrian 841250003Sadrian /* Write the CCK power per rate set */ 842250003Sadrian /* 1L (LSB), reserved, 2L, 2S (MSB) */ 843250003Sadrian OS_REG_WRITE(ah, 0xa3c8, 844250003Sadrian POW_SM(p_pwr_array[ALL_TARGET_LEGACY_1L_5L], 24) 845250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_LEGACY_1L_5L], 16) 846250003Sadrian/* | POW_SM(tx_power_times2, 8)*/ /* this is reserved for Osprey */ 847250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_LEGACY_1L_5L], 0) 848250003Sadrian ); 849250003Sadrian /* 5.5L (LSB), 5.5S, 11L, 11S (MSB) */ 850250003Sadrian OS_REG_WRITE(ah, 0xa3cc, 851250003Sadrian POW_SM(p_pwr_array[ALL_TARGET_LEGACY_11S], 24) 852250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_LEGACY_11L], 16) 853250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_LEGACY_5S], 8) 854250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_LEGACY_1L_5L], 0) 855250003Sadrian ); 856250003Sadrian 857250003Sadrian /* write the power for duplicated frames - HT40 */ 858250003Sadrian /* dup40_cck (LSB), dup40_ofdm, ext20_cck, ext20_ofdm (MSB) */ 859250003Sadrian OS_REG_WRITE(ah, 0xa3e0, 860250003Sadrian POW_SM(p_pwr_array[ALL_TARGET_LEGACY_6_24], 24) 861250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_LEGACY_1L_5L], 16) 862250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_LEGACY_6_24], 8) 863250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_LEGACY_1L_5L], 0) 864250003Sadrian ); 865250003Sadrian 866250003Sadrian /* Write the HT20 power per rate set */ 867250003Sadrian /* 0/8/16 (LSB), 1-3/9-11/17-19, 4, 5 (MSB) */ 868250003Sadrian OS_REG_WRITE(ah, 0xa3d0, 869250003Sadrian POW_SM(p_pwr_array[ALL_TARGET_HT20_5], 24) 870250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_HT20_4], 16) 871250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_HT20_1_3_9_11_17_19], 8) 872250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_HT20_0_8_16], 0) 873250003Sadrian ); 874250003Sadrian 875250003Sadrian /* 6 (LSB), 7, 12, 13 (MSB) */ 876250003Sadrian OS_REG_WRITE(ah, 0xa3d4, 877250003Sadrian POW_SM(p_pwr_array[ALL_TARGET_HT20_13], 24) 878250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_HT20_12], 16) 879250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_HT20_7], 8) 880250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_HT20_6], 0) 881250003Sadrian ); 882250003Sadrian 883250003Sadrian /* 14 (LSB), 15, 20, 21 */ 884250003Sadrian OS_REG_WRITE(ah, 0xa3e4, 885250003Sadrian POW_SM(p_pwr_array[ALL_TARGET_HT20_21], 24) 886250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_HT20_20], 16) 887250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_HT20_15], 8) 888250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_HT20_14], 0) 889250003Sadrian ); 890250003Sadrian 891250003Sadrian /* Mixed HT20 and HT40 rates */ 892250003Sadrian /* HT20 22 (LSB), HT20 23, HT40 22, HT40 23 (MSB) */ 893250003Sadrian OS_REG_WRITE(ah, 0xa3e8, 894250003Sadrian POW_SM(p_pwr_array[ALL_TARGET_HT40_23], 24) 895250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_HT40_22], 16) 896250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_HT20_23], 8) 897250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_HT20_22], 0) 898250003Sadrian ); 899250003Sadrian 900250003Sadrian /* Write the HT40 power per rate set */ 901250003Sadrian /* correct PAR difference between HT40 and HT20/LEGACY */ 902250003Sadrian /* 0/8/16 (LSB), 1-3/9-11/17-19, 4, 5 (MSB) */ 903250003Sadrian OS_REG_WRITE(ah, 0xa3d8, 904250003Sadrian POW_SM(p_pwr_array[ALL_TARGET_HT40_5], 24) 905250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_HT40_4], 16) 906250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_HT40_1_3_9_11_17_19], 8) 907250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_HT40_0_8_16], 0) 908250003Sadrian ); 909250003Sadrian 910250003Sadrian /* 6 (LSB), 7, 12, 13 (MSB) */ 911250003Sadrian OS_REG_WRITE(ah, 0xa3dc, 912250003Sadrian POW_SM(p_pwr_array[ALL_TARGET_HT40_13], 24) 913250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_HT40_12], 16) 914250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_HT40_7], 8) 915250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_HT40_6], 0) 916250003Sadrian ); 917250003Sadrian 918250003Sadrian /* 14 (LSB), 15, 20, 21 */ 919250003Sadrian OS_REG_WRITE(ah, 0xa3ec, 920250003Sadrian POW_SM(p_pwr_array[ALL_TARGET_HT40_21], 24) 921250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_HT40_20], 16) 922250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_HT40_15], 8) 923250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_HT40_14], 0) 924250003Sadrian ); 925250003Sadrian 926250003Sadrian return 0; 927250003Sadrian#undef POW_SM 928250003Sadrian} 929250003Sadrian 930250003Sadrianstatic void 931250008Sadrianar9300_selfgen_tpc_reg_write(struct ath_hal *ah, const struct ieee80211_channel *chan, 932250003Sadrian u_int8_t *p_pwr_array) 933250003Sadrian{ 934250003Sadrian u_int32_t tpc_reg_val; 935250003Sadrian 936250003Sadrian /* Set the target power values for self generated frames (ACK,RTS/CTS) to 937250003Sadrian * be within limits. This is just a safety measure.With per packet TPC mode 938250003Sadrian * enabled the target power value used with self generated frames will be 939250003Sadrian * MIN( TPC reg, BB_powertx_rate register) 940250003Sadrian */ 941250003Sadrian 942250008Sadrian if (IEEE80211_IS_CHAN_2GHZ(chan)) { 943250003Sadrian tpc_reg_val = (SM(p_pwr_array[ALL_TARGET_LEGACY_1L_5L], AR_TPC_ACK) | 944250003Sadrian SM(p_pwr_array[ALL_TARGET_LEGACY_1L_5L], AR_TPC_CTS) | 945250003Sadrian SM(0x3f, AR_TPC_CHIRP) | 946250003Sadrian SM(0x3f, AR_TPC_RPT)); 947250003Sadrian } else { 948250003Sadrian tpc_reg_val = (SM(p_pwr_array[ALL_TARGET_LEGACY_6_24], AR_TPC_ACK) | 949250003Sadrian SM(p_pwr_array[ALL_TARGET_LEGACY_6_24], AR_TPC_CTS) | 950250003Sadrian SM(0x3f, AR_TPC_CHIRP) | 951250003Sadrian SM(0x3f, AR_TPC_RPT)); 952250003Sadrian } 953250003Sadrian OS_REG_WRITE(ah, AR_TPC, tpc_reg_val); 954250003Sadrian} 955250003Sadrian 956250003Sadrianvoid 957250003Sadrianar9300_set_target_power_from_eeprom(struct ath_hal *ah, u_int16_t freq, 958250003Sadrian u_int8_t *target_power_val_t2) 959250003Sadrian{ 960250003Sadrian /* hard code for now, need to get from eeprom struct */ 961250003Sadrian u_int8_t ht40_power_inc_for_pdadc = 0; 962250003Sadrian HAL_BOOL is_2ghz = 0; 963250003Sadrian 964250003Sadrian if (freq < 4000) { 965250003Sadrian is_2ghz = 1; 966250003Sadrian } 967250003Sadrian 968250003Sadrian target_power_val_t2[ALL_TARGET_LEGACY_6_24] = 969250003Sadrian ar9300_eeprom_get_legacy_trgt_pwr( 970250003Sadrian ah, LEGACY_TARGET_RATE_6_24, freq, is_2ghz); 971250003Sadrian target_power_val_t2[ALL_TARGET_LEGACY_36] = 972250003Sadrian ar9300_eeprom_get_legacy_trgt_pwr( 973250003Sadrian ah, LEGACY_TARGET_RATE_36, freq, is_2ghz); 974250003Sadrian target_power_val_t2[ALL_TARGET_LEGACY_48] = 975250003Sadrian ar9300_eeprom_get_legacy_trgt_pwr( 976250003Sadrian ah, LEGACY_TARGET_RATE_48, freq, is_2ghz); 977250003Sadrian target_power_val_t2[ALL_TARGET_LEGACY_54] = 978250003Sadrian ar9300_eeprom_get_legacy_trgt_pwr( 979250003Sadrian ah, LEGACY_TARGET_RATE_54, freq, is_2ghz); 980250003Sadrian target_power_val_t2[ALL_TARGET_LEGACY_1L_5L] = 981250003Sadrian ar9300_eeprom_get_cck_trgt_pwr( 982250003Sadrian ah, LEGACY_TARGET_RATE_1L_5L, freq); 983250003Sadrian target_power_val_t2[ALL_TARGET_LEGACY_5S] = 984250003Sadrian ar9300_eeprom_get_cck_trgt_pwr( 985250003Sadrian ah, LEGACY_TARGET_RATE_5S, freq); 986250003Sadrian target_power_val_t2[ALL_TARGET_LEGACY_11L] = 987250003Sadrian ar9300_eeprom_get_cck_trgt_pwr( 988250003Sadrian ah, LEGACY_TARGET_RATE_11L, freq); 989250003Sadrian target_power_val_t2[ALL_TARGET_LEGACY_11S] = 990250003Sadrian ar9300_eeprom_get_cck_trgt_pwr( 991250003Sadrian ah, LEGACY_TARGET_RATE_11S, freq); 992250003Sadrian target_power_val_t2[ALL_TARGET_HT20_0_8_16] = 993250003Sadrian ar9300_eeprom_get_ht20_trgt_pwr( 994250003Sadrian ah, HT_TARGET_RATE_0_8_16, freq, is_2ghz); 995250003Sadrian target_power_val_t2[ALL_TARGET_HT20_1_3_9_11_17_19] = 996250003Sadrian ar9300_eeprom_get_ht20_trgt_pwr( 997250003Sadrian ah, HT_TARGET_RATE_1_3_9_11_17_19, freq, is_2ghz); 998250003Sadrian target_power_val_t2[ALL_TARGET_HT20_4] = 999250003Sadrian ar9300_eeprom_get_ht20_trgt_pwr( 1000250003Sadrian ah, HT_TARGET_RATE_4, freq, is_2ghz); 1001250003Sadrian target_power_val_t2[ALL_TARGET_HT20_5] = 1002250003Sadrian ar9300_eeprom_get_ht20_trgt_pwr( 1003250003Sadrian ah, HT_TARGET_RATE_5, freq, is_2ghz); 1004250003Sadrian target_power_val_t2[ALL_TARGET_HT20_6] = 1005250003Sadrian ar9300_eeprom_get_ht20_trgt_pwr( 1006250003Sadrian ah, HT_TARGET_RATE_6, freq, is_2ghz); 1007250003Sadrian target_power_val_t2[ALL_TARGET_HT20_7] = 1008250003Sadrian ar9300_eeprom_get_ht20_trgt_pwr( 1009250003Sadrian ah, HT_TARGET_RATE_7, freq, is_2ghz); 1010250003Sadrian target_power_val_t2[ALL_TARGET_HT20_12] = 1011250003Sadrian ar9300_eeprom_get_ht20_trgt_pwr( 1012250003Sadrian ah, HT_TARGET_RATE_12, freq, is_2ghz); 1013250003Sadrian target_power_val_t2[ALL_TARGET_HT20_13] = 1014250003Sadrian ar9300_eeprom_get_ht20_trgt_pwr( 1015250003Sadrian ah, HT_TARGET_RATE_13, freq, is_2ghz); 1016250003Sadrian target_power_val_t2[ALL_TARGET_HT20_14] = 1017250003Sadrian ar9300_eeprom_get_ht20_trgt_pwr( 1018250003Sadrian ah, HT_TARGET_RATE_14, freq, is_2ghz); 1019250003Sadrian target_power_val_t2[ALL_TARGET_HT20_15] = 1020250003Sadrian ar9300_eeprom_get_ht20_trgt_pwr( 1021250003Sadrian ah, HT_TARGET_RATE_15, freq, is_2ghz); 1022250003Sadrian target_power_val_t2[ALL_TARGET_HT20_20] = 1023250003Sadrian ar9300_eeprom_get_ht20_trgt_pwr( 1024250003Sadrian ah, HT_TARGET_RATE_20, freq, is_2ghz); 1025250003Sadrian target_power_val_t2[ALL_TARGET_HT20_21] = 1026250003Sadrian ar9300_eeprom_get_ht20_trgt_pwr( 1027250003Sadrian ah, HT_TARGET_RATE_21, freq, is_2ghz); 1028250003Sadrian target_power_val_t2[ALL_TARGET_HT20_22] = 1029250003Sadrian ar9300_eeprom_get_ht20_trgt_pwr( 1030250003Sadrian ah, HT_TARGET_RATE_22, freq, is_2ghz); 1031250003Sadrian target_power_val_t2[ALL_TARGET_HT20_23] = 1032250003Sadrian ar9300_eeprom_get_ht20_trgt_pwr( 1033250003Sadrian ah, HT_TARGET_RATE_23, freq, is_2ghz); 1034250003Sadrian target_power_val_t2[ALL_TARGET_HT40_0_8_16] = 1035250003Sadrian ar9300_eeprom_get_ht40_trgt_pwr( 1036250003Sadrian ah, HT_TARGET_RATE_0_8_16, freq, is_2ghz) + 1037250003Sadrian ht40_power_inc_for_pdadc; 1038250003Sadrian target_power_val_t2[ALL_TARGET_HT40_1_3_9_11_17_19] = 1039250003Sadrian ar9300_eeprom_get_ht40_trgt_pwr( 1040250003Sadrian ah, HT_TARGET_RATE_1_3_9_11_17_19, freq, is_2ghz) + 1041250003Sadrian ht40_power_inc_for_pdadc; 1042250003Sadrian target_power_val_t2[ALL_TARGET_HT40_4] = 1043250003Sadrian ar9300_eeprom_get_ht40_trgt_pwr( 1044250003Sadrian ah, HT_TARGET_RATE_4, freq, is_2ghz) + ht40_power_inc_for_pdadc; 1045250003Sadrian target_power_val_t2[ALL_TARGET_HT40_5] = 1046250003Sadrian ar9300_eeprom_get_ht40_trgt_pwr( 1047250003Sadrian ah, HT_TARGET_RATE_5, freq, is_2ghz) + ht40_power_inc_for_pdadc; 1048250003Sadrian target_power_val_t2[ALL_TARGET_HT40_6] = 1049250003Sadrian ar9300_eeprom_get_ht40_trgt_pwr( 1050250003Sadrian ah, HT_TARGET_RATE_6, freq, is_2ghz) + ht40_power_inc_for_pdadc; 1051250003Sadrian target_power_val_t2[ALL_TARGET_HT40_7] = 1052250003Sadrian ar9300_eeprom_get_ht40_trgt_pwr( 1053250003Sadrian ah, HT_TARGET_RATE_7, freq, is_2ghz) + ht40_power_inc_for_pdadc; 1054250003Sadrian target_power_val_t2[ALL_TARGET_HT40_12] = 1055250003Sadrian ar9300_eeprom_get_ht40_trgt_pwr( 1056250003Sadrian ah, HT_TARGET_RATE_12, freq, is_2ghz) + ht40_power_inc_for_pdadc; 1057250003Sadrian target_power_val_t2[ALL_TARGET_HT40_13] = 1058250003Sadrian ar9300_eeprom_get_ht40_trgt_pwr( 1059250003Sadrian ah, HT_TARGET_RATE_13, freq, is_2ghz) + ht40_power_inc_for_pdadc; 1060250003Sadrian target_power_val_t2[ALL_TARGET_HT40_14] = 1061250003Sadrian ar9300_eeprom_get_ht40_trgt_pwr( 1062250003Sadrian ah, HT_TARGET_RATE_14, freq, is_2ghz) + ht40_power_inc_for_pdadc; 1063250003Sadrian target_power_val_t2[ALL_TARGET_HT40_15] = 1064250003Sadrian ar9300_eeprom_get_ht40_trgt_pwr( 1065250003Sadrian ah, HT_TARGET_RATE_15, freq, is_2ghz) + ht40_power_inc_for_pdadc; 1066250003Sadrian target_power_val_t2[ALL_TARGET_HT40_20] = 1067250003Sadrian ar9300_eeprom_get_ht40_trgt_pwr( 1068250003Sadrian ah, HT_TARGET_RATE_20, freq, is_2ghz) + ht40_power_inc_for_pdadc; 1069250003Sadrian target_power_val_t2[ALL_TARGET_HT40_21] = 1070250003Sadrian ar9300_eeprom_get_ht40_trgt_pwr( 1071250003Sadrian ah, HT_TARGET_RATE_21, freq, is_2ghz) + ht40_power_inc_for_pdadc; 1072250003Sadrian target_power_val_t2[ALL_TARGET_HT40_22] = 1073250003Sadrian ar9300_eeprom_get_ht40_trgt_pwr( 1074250003Sadrian ah, HT_TARGET_RATE_22, freq, is_2ghz) + ht40_power_inc_for_pdadc; 1075250003Sadrian target_power_val_t2[ALL_TARGET_HT40_23] = 1076250003Sadrian ar9300_eeprom_get_ht40_trgt_pwr( 1077250003Sadrian ah, HT_TARGET_RATE_23, freq, is_2ghz) + ht40_power_inc_for_pdadc; 1078250003Sadrian 1079250003Sadrian#ifdef AH_DEBUG 1080250003Sadrian { 1081250003Sadrian int i = 0; 1082250003Sadrian 1083250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, "%s: APPLYING TARGET POWERS\n", __func__); 1084250003Sadrian while (i < ar9300_rate_size) { 1085250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, "%s: TPC[%02d] 0x%08x ", 1086250003Sadrian __func__, i, target_power_val_t2[i]); 1087250003Sadrian i++; 1088250003Sadrian if (i == ar9300_rate_size) { 1089250003Sadrian break; 1090250003Sadrian } 1091250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, "%s: TPC[%02d] 0x%08x ", 1092250003Sadrian __func__, i, target_power_val_t2[i]); 1093250003Sadrian i++; 1094250003Sadrian if (i == ar9300_rate_size) { 1095250003Sadrian break; 1096250003Sadrian } 1097250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, "%s: TPC[%02d] 0x%08x ", 1098250003Sadrian __func__, i, target_power_val_t2[i]); 1099250003Sadrian i++; 1100250003Sadrian if (i == ar9300_rate_size) { 1101250003Sadrian break; 1102250003Sadrian } 1103250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, "%s: TPC[%02d] 0x%08x \n", 1104250003Sadrian __func__, i, target_power_val_t2[i]); 1105250003Sadrian i++; 1106250003Sadrian } 1107250003Sadrian } 1108250003Sadrian#endif 1109250003Sadrian} 1110250003Sadrian 1111250003Sadrianu_int16_t *ar9300_regulatory_domain_get(struct ath_hal *ah) 1112250003Sadrian{ 1113250003Sadrian ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom; 1114250003Sadrian return eep->base_eep_header.reg_dmn; 1115250003Sadrian} 1116250003Sadrian 1117250003Sadrian 1118250003Sadrianint32_t 1119250003Sadrianar9300_eeprom_write_enable_gpio_get(struct ath_hal *ah) 1120250003Sadrian{ 1121250003Sadrian ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom; 1122250003Sadrian return eep->base_eep_header.eeprom_write_enable_gpio; 1123250003Sadrian} 1124250003Sadrian 1125250003Sadrianint32_t 1126250003Sadrianar9300_wlan_disable_gpio_get(struct ath_hal *ah) 1127250003Sadrian{ 1128250003Sadrian ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom; 1129250003Sadrian return eep->base_eep_header.wlan_disable_gpio; 1130250003Sadrian} 1131250003Sadrian 1132250003Sadrianint32_t 1133250003Sadrianar9300_wlan_led_gpio_get(struct ath_hal *ah) 1134250003Sadrian{ 1135250003Sadrian ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom; 1136250003Sadrian return eep->base_eep_header.wlan_led_gpio; 1137250003Sadrian} 1138250003Sadrian 1139250003Sadrianint32_t 1140250003Sadrianar9300_rx_band_select_gpio_get(struct ath_hal *ah) 1141250003Sadrian{ 1142250003Sadrian ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom; 1143250003Sadrian return eep->base_eep_header.rx_band_select_gpio; 1144250003Sadrian} 1145250003Sadrian 1146250003Sadrian/* 1147250003Sadrian * since valid noise floor values are negative, returns 1 on error 1148250003Sadrian */ 1149250003Sadrianint32_t 1150250003Sadrianar9300_noise_floor_cal_or_power_get(struct ath_hal *ah, int32_t frequency, 1151250003Sadrian int32_t ichain, HAL_BOOL use_cal) 1152250003Sadrian{ 1153250003Sadrian int nf_use = 1; /* start with an error return value */ 1154250003Sadrian int32_t fx[OSPREY_NUM_5G_CAL_PIERS + OSPREY_NUM_2G_CAL_PIERS]; 1155250003Sadrian int32_t nf[OSPREY_NUM_5G_CAL_PIERS + OSPREY_NUM_2G_CAL_PIERS]; 1156250003Sadrian int nnf; 1157250003Sadrian int is_2ghz; 1158250003Sadrian int ipier, npier; 1159250003Sadrian ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom; 1160250003Sadrian u_int8_t *p_cal_pier; 1161250003Sadrian OSP_CAL_DATA_PER_FREQ_OP_LOOP *p_cal_pier_struct; 1162250003Sadrian 1163250003Sadrian /* 1164250003Sadrian * check chain value 1165250003Sadrian */ 1166250003Sadrian if (ichain < 0 || ichain >= OSPREY_MAX_CHAINS) { 1167250003Sadrian return 1; 1168250003Sadrian } 1169250003Sadrian 1170250003Sadrian /* figure out which band we're using */ 1171250003Sadrian is_2ghz = (frequency < 4000); 1172250003Sadrian if (is_2ghz) { 1173250003Sadrian npier = OSPREY_NUM_2G_CAL_PIERS; 1174250003Sadrian p_cal_pier = eep->cal_freq_pier_2g; 1175250003Sadrian p_cal_pier_struct = eep->cal_pier_data_2g[ichain]; 1176250003Sadrian } else { 1177250003Sadrian npier = OSPREY_NUM_5G_CAL_PIERS; 1178250003Sadrian p_cal_pier = eep->cal_freq_pier_5g; 1179250003Sadrian p_cal_pier_struct = eep->cal_pier_data_5g[ichain]; 1180250003Sadrian } 1181250003Sadrian /* look for valid noise floor values */ 1182250003Sadrian nnf = 0; 1183250003Sadrian for (ipier = 0; ipier < npier; ipier++) { 1184250003Sadrian fx[nnf] = FBIN2FREQ(p_cal_pier[ipier], is_2ghz); 1185250003Sadrian nf[nnf] = use_cal ? 1186250003Sadrian p_cal_pier_struct[ipier].rx_noisefloor_cal : 1187250003Sadrian p_cal_pier_struct[ipier].rx_noisefloor_power; 1188250003Sadrian if (nf[nnf] < 0) { 1189250003Sadrian nnf++; 1190250003Sadrian } 1191250003Sadrian } 1192250003Sadrian /* 1193250003Sadrian * If we have some valid values, interpolate to find the value 1194250003Sadrian * at the desired frequency. 1195250003Sadrian */ 1196250003Sadrian if (nnf > 0) { 1197250003Sadrian nf_use = interpolate(frequency, fx, nf, nnf); 1198250003Sadrian } 1199250003Sadrian 1200250003Sadrian return nf_use; 1201250003Sadrian} 1202250003Sadrian 1203250003Sadrianint32_t ar9300_rx_gain_index_get(struct ath_hal *ah) 1204250003Sadrian{ 1205250003Sadrian ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom; 1206250003Sadrian 1207250003Sadrian return (eep->base_eep_header.txrxgain) & 0xf; /* bits 3:0 */ 1208250003Sadrian} 1209250003Sadrian 1210250003Sadrian 1211250003Sadrianint32_t ar9300_tx_gain_index_get(struct ath_hal *ah) 1212250003Sadrian{ 1213250003Sadrian ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom; 1214250003Sadrian 1215250003Sadrian return (eep->base_eep_header.txrxgain >> 4) & 0xf; /* bits 7:4 */ 1216250003Sadrian} 1217250003Sadrian 1218250003SadrianHAL_BOOL ar9300_internal_regulator_apply(struct ath_hal *ah) 1219250003Sadrian{ 1220250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 1221250003Sadrian int internal_regulator = ar9300_eeprom_get(ahp, EEP_INTERNAL_REGULATOR); 1222250003Sadrian int reg_pmu1, reg_pmu2, reg_pmu1_set, reg_pmu2_set; 1223250003Sadrian u_int32_t reg_PMU1, reg_PMU2; 1224250003Sadrian unsigned long eep_addr; 1225250003Sadrian u_int32_t reg_val, reg_usb = 0, reg_pmu = 0; 1226250003Sadrian int usb_valid = 0, pmu_valid = 0; 1227250003Sadrian unsigned char pmu_refv; 1228250003Sadrian 1229250003Sadrian if (AR_SREV_JUPITER(ah) || AR_SREV_APHRODITE(ah)) { 1230250003Sadrian reg_PMU1 = AR_PHY_PMU1_JUPITER; 1231250003Sadrian reg_PMU2 = AR_PHY_PMU2_JUPITER; 1232250003Sadrian } 1233250003Sadrian else { 1234250003Sadrian reg_PMU1 = AR_PHY_PMU1; 1235250003Sadrian reg_PMU2 = AR_PHY_PMU2; 1236250003Sadrian } 1237250003Sadrian 1238250003Sadrian if (internal_regulator) { 1239250003Sadrian if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah)) { 1240250003Sadrian if (AR_SREV_HORNET(ah)) { 1241250003Sadrian /* Read OTP first */ 1242250003Sadrian for (eep_addr = 0x14; ; eep_addr -= 0x10) { 1243250003Sadrian 1244250003Sadrian ar9300_otp_read(ah, eep_addr / 4, ®_val, 1); 1245250003Sadrian 1246250003Sadrian if ((reg_val & 0x80) == 0x80){ 1247250003Sadrian usb_valid = 1; 1248250003Sadrian reg_usb = reg_val & 0x000000ff; 1249250003Sadrian } 1250250003Sadrian 1251250003Sadrian if ((reg_val & 0x80000000) == 0x80000000){ 1252250003Sadrian pmu_valid = 1; 1253250003Sadrian reg_pmu = (reg_val & 0xff000000) >> 24; 1254250003Sadrian } 1255250003Sadrian 1256250003Sadrian if (eep_addr == 0x4) { 1257250003Sadrian break; 1258250003Sadrian } 1259250003Sadrian } 1260250003Sadrian 1261250003Sadrian if (pmu_valid) { 1262250003Sadrian pmu_refv = reg_pmu & 0xf; 1263250003Sadrian } else { 1264250003Sadrian pmu_refv = 0x8; 1265250003Sadrian } 1266250003Sadrian 1267250003Sadrian /* 1268250003Sadrian * If (valid) { 1269250003Sadrian * Usb_phy_ctrl2_tx_cal_en -> 0 1270250003Sadrian * Usb_phy_ctrl2_tx_cal_sel -> 0 1271250003Sadrian * Usb_phy_ctrl2_tx_man_cal -> 0, 1, 3, 7 or 15 from OTP 1272250003Sadrian * } 1273250003Sadrian */ 1274250003Sadrian if (usb_valid) { 1275250003Sadrian OS_REG_RMW_FIELD(ah, 0x16c88, AR_PHY_CTRL2_TX_CAL_EN, 0x0); 1276250003Sadrian OS_REG_RMW_FIELD(ah, 0x16c88, AR_PHY_CTRL2_TX_CAL_SEL, 0x0); 1277250003Sadrian OS_REG_RMW_FIELD(ah, 0x16c88, 1278250003Sadrian AR_PHY_CTRL2_TX_MAN_CAL, (reg_usb & 0xf)); 1279250003Sadrian } 1280250003Sadrian 1281250003Sadrian } else { 1282250003Sadrian pmu_refv = 0x8; 1283250003Sadrian } 1284250003Sadrian /*#ifndef USE_HIF*/ 1285250003Sadrian /* Follow the MDK settings for Hornet PMU. 1286250003Sadrian * my $pwd = 0x0; 1287250003Sadrian * my $Nfdiv = 0x3; # xtal_freq = 25MHz 1288250003Sadrian * my $Nfdiv = 0x4; # xtal_freq = 40MHz 1289250003Sadrian * my $Refv = 0x7; # 0x5:1.22V; 0x8:1.29V 1290250003Sadrian * my $Gm1 = 0x3; #Poseidon $Gm1=1 1291250003Sadrian * my $classb = 0x0; 1292250003Sadrian * my $Cc = 0x1; #Poseidon $Cc=7 1293250003Sadrian * my $Rc = 0x6; 1294250003Sadrian * my $ramp_slope = 0x1; 1295250003Sadrian * my $Segm = 0x3; 1296250003Sadrian * my $use_local_osc = 0x0; 1297250003Sadrian * my $force_xosc_stable = 0x0; 1298250003Sadrian * my $Selfb = 0x0; #Poseidon $Selfb=1 1299250003Sadrian * my $Filterfb = 0x3; #Poseidon $Filterfb=0 1300250003Sadrian * my $Filtervc = 0x0; 1301250003Sadrian * my $disc = 0x0; 1302250003Sadrian * my $discdel = 0x4; 1303250003Sadrian * my $spare = 0x0; 1304250003Sadrian * $reg_PMU1 = 1305250003Sadrian * $pwd | ($Nfdiv<<1) | ($Refv<<4) | ($Gm1<<8) | 1306250003Sadrian * ($classb<<11) | ($Cc<<14) | ($Rc<<17) | ($ramp_slope<<20) | 1307250003Sadrian * ($Segm<<24) | ($use_local_osc<<26) | 1308250003Sadrian * ($force_xosc_stable<<27) | ($Selfb<<28) | ($Filterfb<<29); 1309250003Sadrian * $reg_PMU2 = $handle->reg_rd("ch0_PMU2"); 1310250003Sadrian * $reg_PMU2 = ($reg_PMU2 & 0xfe3fffff) | ($Filtervc<<22); 1311250003Sadrian * $reg_PMU2 = ($reg_PMU2 & 0xe3ffffff) | ($discdel<<26); 1312250003Sadrian * $reg_PMU2 = ($reg_PMU2 & 0x1fffffff) | ($spare<<29); 1313250003Sadrian */ 1314250003Sadrian if (ahp->clk_25mhz) { 1315250003Sadrian reg_pmu1_set = 0 | 1316250003Sadrian (3 << 1) | (pmu_refv << 4) | (3 << 8) | (0 << 11) | 1317250003Sadrian (1 << 14) | (6 << 17) | (1 << 20) | (3 << 24) | 1318250003Sadrian (0 << 26) | (0 << 27) | (0 << 28) | (0 << 29); 1319250003Sadrian } else { 1320250003Sadrian if (AR_SREV_POSEIDON(ah)) { 1321250003Sadrian reg_pmu1_set = 0 | 1322250003Sadrian (5 << 1) | (7 << 4) | (2 << 8) | (0 << 11) | 1323250003Sadrian (2 << 14) | (6 << 17) | (1 << 20) | (3 << 24) | 1324250003Sadrian (0 << 26) | (0 << 27) | (1 << 28) | (0 << 29) ; 1325250003Sadrian } else { 1326250003Sadrian reg_pmu1_set = 0 | 1327250003Sadrian (4 << 1) | (7 << 4) | (3 << 8) | (0 << 11) | 1328250003Sadrian (1 << 14) | (6 << 17) | (1 << 20) | (3 << 24) | 1329250003Sadrian (0 << 26) | (0 << 27) | (0 << 28) | (0 << 29) ; 1330250003Sadrian } 1331250003Sadrian } 1332250003Sadrian OS_REG_RMW_FIELD(ah, reg_PMU2, AR_PHY_PMU2_PGM, 0x0); 1333250003Sadrian 1334250003Sadrian OS_REG_WRITE(ah, reg_PMU1, reg_pmu1_set); /* 0x638c8376 */ 1335250003Sadrian reg_pmu1 = OS_REG_READ(ah, reg_PMU1); 1336250003Sadrian while (reg_pmu1 != reg_pmu1_set) { 1337250003Sadrian OS_REG_WRITE(ah, reg_PMU1, reg_pmu1_set); /* 0x638c8376 */ 1338250003Sadrian OS_DELAY(10); 1339250003Sadrian reg_pmu1 = OS_REG_READ(ah, reg_PMU1); 1340250003Sadrian } 1341250003Sadrian 1342250003Sadrian reg_pmu2_set = 1343250003Sadrian (OS_REG_READ(ah, reg_PMU2) & (~0xFFC00000)) | (4 << 26); 1344250003Sadrian OS_REG_WRITE(ah, reg_PMU2, reg_pmu2_set); 1345250003Sadrian reg_pmu2 = OS_REG_READ(ah, reg_PMU2); 1346250003Sadrian while (reg_pmu2 != reg_pmu2_set) { 1347250003Sadrian OS_REG_WRITE(ah, reg_PMU2, reg_pmu2_set); 1348250003Sadrian OS_DELAY(10); 1349250003Sadrian reg_pmu2 = OS_REG_READ(ah, reg_PMU2); 1350250003Sadrian } 1351250003Sadrian reg_pmu2_set = 1352250003Sadrian (OS_REG_READ(ah, reg_PMU2) & (~0x00200000)) | (1 << 21); 1353250003Sadrian OS_REG_WRITE(ah, reg_PMU2, reg_pmu2_set); 1354250003Sadrian reg_pmu2 = OS_REG_READ(ah, reg_PMU2); 1355250003Sadrian while (reg_pmu2 != reg_pmu2_set) { 1356250003Sadrian OS_REG_WRITE(ah, reg_PMU2, reg_pmu2_set); 1357250003Sadrian OS_DELAY(10); 1358250003Sadrian reg_pmu2 = OS_REG_READ(ah, reg_PMU2); 1359250003Sadrian } 1360250003Sadrian /*#endif*/ 1361250003Sadrian } else if (AR_SREV_JUPITER(ah) || AR_SREV_APHRODITE(ah)) { 1362250003Sadrian /* Internal regulator is ON. Write swreg register. */ 1363250003Sadrian int swreg = ar9300_eeprom_get(ahp, EEP_SWREG); 1364250003Sadrian OS_REG_WRITE(ah, reg_PMU1, swreg); 1365250003Sadrian } else { 1366250003Sadrian /* Internal regulator is ON. Write swreg register. */ 1367250003Sadrian int swreg = ar9300_eeprom_get(ahp, EEP_SWREG); 1368250003Sadrian OS_REG_WRITE(ah, AR_RTC_REG_CONTROL1, 1369250003Sadrian OS_REG_READ(ah, AR_RTC_REG_CONTROL1) & 1370250003Sadrian (~AR_RTC_REG_CONTROL1_SWREG_PROGRAM)); 1371250003Sadrian OS_REG_WRITE(ah, AR_RTC_REG_CONTROL0, swreg); 1372250003Sadrian /* Set REG_CONTROL1.SWREG_PROGRAM */ 1373250003Sadrian OS_REG_WRITE(ah, AR_RTC_REG_CONTROL1, 1374250003Sadrian OS_REG_READ(ah, AR_RTC_REG_CONTROL1) | 1375250003Sadrian AR_RTC_REG_CONTROL1_SWREG_PROGRAM); 1376250003Sadrian } 1377250003Sadrian } else { 1378250003Sadrian if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah)) { 1379250003Sadrian OS_REG_RMW_FIELD(ah, reg_PMU2, AR_PHY_PMU2_PGM, 0x0); 1380250003Sadrian reg_pmu2 = OS_REG_READ_FIELD(ah, reg_PMU2, AR_PHY_PMU2_PGM); 1381250003Sadrian while (reg_pmu2) { 1382250003Sadrian OS_DELAY(10); 1383250003Sadrian reg_pmu2 = OS_REG_READ_FIELD(ah, reg_PMU2, AR_PHY_PMU2_PGM); 1384250003Sadrian } 1385250003Sadrian OS_REG_RMW_FIELD(ah, reg_PMU1, AR_PHY_PMU1_PWD, 0x1); 1386250003Sadrian reg_pmu1 = OS_REG_READ_FIELD(ah, reg_PMU1, AR_PHY_PMU1_PWD); 1387250003Sadrian while (!reg_pmu1) { 1388250003Sadrian OS_DELAY(10); 1389250003Sadrian reg_pmu1 = OS_REG_READ_FIELD(ah, reg_PMU1, AR_PHY_PMU1_PWD); 1390250003Sadrian } 1391250003Sadrian OS_REG_RMW_FIELD(ah, reg_PMU2, AR_PHY_PMU2_PGM, 0x1); 1392250003Sadrian reg_pmu2 = OS_REG_READ_FIELD(ah, reg_PMU2, AR_PHY_PMU2_PGM); 1393250003Sadrian while (!reg_pmu2) { 1394250003Sadrian OS_DELAY(10); 1395250003Sadrian reg_pmu2 = OS_REG_READ_FIELD(ah, reg_PMU2, AR_PHY_PMU2_PGM); 1396250003Sadrian } 1397250003Sadrian } else if (AR_SREV_JUPITER(ah) || AR_SREV_APHRODITE(ah)) { 1398250003Sadrian OS_REG_RMW_FIELD(ah, reg_PMU1, AR_PHY_PMU1_PWD, 0x1); 1399250003Sadrian } else { 1400250003Sadrian OS_REG_WRITE(ah, AR_RTC_SLEEP_CLK, 1401250003Sadrian (OS_REG_READ(ah, AR_RTC_SLEEP_CLK) | 1402250003Sadrian AR_RTC_FORCE_SWREG_PRD | AR_RTC_PCIE_RST_PWDN_EN)); 1403250003Sadrian } 1404250003Sadrian } 1405250003Sadrian 1406250003Sadrian return 0; 1407250003Sadrian} 1408250003Sadrian 1409250003SadrianHAL_BOOL ar9300_drive_strength_apply(struct ath_hal *ah) 1410250003Sadrian{ 1411250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 1412250003Sadrian int drive_strength; 1413250003Sadrian unsigned long reg; 1414250003Sadrian 1415250003Sadrian drive_strength = ar9300_eeprom_get(ahp, EEP_DRIVE_STRENGTH); 1416250003Sadrian if (drive_strength) { 1417250003Sadrian reg = OS_REG_READ(ah, AR_PHY_65NM_CH0_BIAS1); 1418250003Sadrian reg &= ~0x00ffffc0; 1419250003Sadrian reg |= 0x5 << 21; 1420250003Sadrian reg |= 0x5 << 18; 1421250003Sadrian reg |= 0x5 << 15; 1422250003Sadrian reg |= 0x5 << 12; 1423250003Sadrian reg |= 0x5 << 9; 1424250003Sadrian reg |= 0x5 << 6; 1425250003Sadrian OS_REG_WRITE(ah, AR_PHY_65NM_CH0_BIAS1, reg); 1426250003Sadrian 1427250003Sadrian reg = OS_REG_READ(ah, AR_PHY_65NM_CH0_BIAS2); 1428250003Sadrian reg &= ~0xffffffe0; 1429250003Sadrian reg |= 0x5 << 29; 1430250003Sadrian reg |= 0x5 << 26; 1431250003Sadrian reg |= 0x5 << 23; 1432250003Sadrian reg |= 0x5 << 20; 1433250003Sadrian reg |= 0x5 << 17; 1434250003Sadrian reg |= 0x5 << 14; 1435250003Sadrian reg |= 0x5 << 11; 1436250003Sadrian reg |= 0x5 << 8; 1437250003Sadrian reg |= 0x5 << 5; 1438250003Sadrian OS_REG_WRITE(ah, AR_PHY_65NM_CH0_BIAS2, reg); 1439250003Sadrian 1440250003Sadrian reg = OS_REG_READ(ah, AR_PHY_65NM_CH0_BIAS4); 1441250003Sadrian reg &= ~0xff800000; 1442250003Sadrian reg |= 0x5 << 29; 1443250003Sadrian reg |= 0x5 << 26; 1444250003Sadrian reg |= 0x5 << 23; 1445250003Sadrian OS_REG_WRITE(ah, AR_PHY_65NM_CH0_BIAS4, reg); 1446250003Sadrian } 1447250003Sadrian return 0; 1448250003Sadrian} 1449250003Sadrian 1450250003Sadrianint32_t ar9300_xpa_bias_level_get(struct ath_hal *ah, HAL_BOOL is_2ghz) 1451250003Sadrian{ 1452250003Sadrian ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom; 1453250003Sadrian if (is_2ghz) { 1454250003Sadrian return eep->modal_header_2g.xpa_bias_lvl; 1455250003Sadrian } else { 1456250003Sadrian return eep->modal_header_5g.xpa_bias_lvl; 1457250003Sadrian } 1458250003Sadrian} 1459250003Sadrian 1460250003SadrianHAL_BOOL ar9300_xpa_bias_level_apply(struct ath_hal *ah, HAL_BOOL is_2ghz) 1461250003Sadrian{ 1462250003Sadrian /* 1463250003Sadrian * In ar9330 emu, we can't access radio registers, 1464250003Sadrian * merlin is used for radio part. 1465250003Sadrian */ 1466250003Sadrian int bias; 1467250003Sadrian bias = ar9300_xpa_bias_level_get(ah, is_2ghz); 1468250003Sadrian 1469250003Sadrian if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah) || AR_SREV_WASP(ah)) { 1470250003Sadrian OS_REG_RMW_FIELD(ah, 1471250003Sadrian AR_HORNET_CH0_TOP2, AR_HORNET_CH0_TOP2_XPABIASLVL, bias); 1472250003Sadrian } else if (AR_SREV_SCORPION(ah)) { 1473250003Sadrian OS_REG_RMW_FIELD(ah, 1474250003Sadrian AR_SCORPION_CH0_TOP, AR_SCORPION_CH0_TOP_XPABIASLVL, bias); 1475250003Sadrian } else if (AR_SREV_JUPITER(ah) || AR_SREV_APHRODITE(ah)) { 1476250003Sadrian OS_REG_RMW_FIELD(ah, 1477250003Sadrian AR_PHY_65NM_CH0_TOP_JUPITER, AR_PHY_65NM_CH0_TOP_XPABIASLVL, bias); 1478250003Sadrian } else { 1479250003Sadrian OS_REG_RMW_FIELD(ah, 1480250003Sadrian AR_PHY_65NM_CH0_TOP, AR_PHY_65NM_CH0_TOP_XPABIASLVL, bias); 1481250003Sadrian OS_REG_RMW_FIELD(ah, 1482250003Sadrian AR_PHY_65NM_CH0_THERM, AR_PHY_65NM_CH0_THERM_XPABIASLVL_MSB, 1483250003Sadrian bias >> 2); 1484250003Sadrian OS_REG_RMW_FIELD(ah, 1485250003Sadrian AR_PHY_65NM_CH0_THERM, AR_PHY_65NM_CH0_THERM_XPASHORT2GND, 1); 1486250003Sadrian } 1487250003Sadrian return 0; 1488250003Sadrian} 1489250003Sadrian 1490250003Sadrianu_int32_t ar9300_ant_ctrl_common_get(struct ath_hal *ah, HAL_BOOL is_2ghz) 1491250003Sadrian{ 1492250003Sadrian ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom; 1493250003Sadrian if (is_2ghz) { 1494250003Sadrian return eep->modal_header_2g.ant_ctrl_common; 1495250003Sadrian } else { 1496250003Sadrian return eep->modal_header_5g.ant_ctrl_common; 1497250003Sadrian } 1498250003Sadrian} 1499250003Sadrianstatic u_int16_t 1500250003Sadrianar9300_switch_com_spdt_get(struct ath_hal *ah, HAL_BOOL is_2ghz) 1501250003Sadrian{ 1502250003Sadrian ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom; 1503250003Sadrian if (is_2ghz) { 1504250003Sadrian return eep->modal_header_2g.switchcomspdt; 1505250003Sadrian } else { 1506250003Sadrian return eep->modal_header_5g.switchcomspdt; 1507250003Sadrian } 1508250003Sadrian} 1509250003Sadrianu_int32_t ar9300_ant_ctrl_common2_get(struct ath_hal *ah, HAL_BOOL is_2ghz) 1510250003Sadrian{ 1511250003Sadrian ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom; 1512250003Sadrian if (is_2ghz) { 1513250003Sadrian return eep->modal_header_2g.ant_ctrl_common2; 1514250003Sadrian } else { 1515250003Sadrian return eep->modal_header_5g.ant_ctrl_common2; 1516250003Sadrian } 1517250003Sadrian} 1518250003Sadrian 1519250003Sadrianu_int16_t ar9300_ant_ctrl_chain_get(struct ath_hal *ah, int chain, 1520250003Sadrian HAL_BOOL is_2ghz) 1521250003Sadrian{ 1522250003Sadrian ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom; 1523250003Sadrian if (chain >= 0 && chain < OSPREY_MAX_CHAINS) { 1524250003Sadrian if (is_2ghz) { 1525250003Sadrian return eep->modal_header_2g.ant_ctrl_chain[chain]; 1526250003Sadrian } else { 1527250003Sadrian return eep->modal_header_5g.ant_ctrl_chain[chain]; 1528250003Sadrian } 1529250003Sadrian } 1530250003Sadrian return 0; 1531250003Sadrian} 1532250003Sadrian 1533250003SadrianHAL_BOOL ar9300_ant_ctrl_apply(struct ath_hal *ah, HAL_BOOL is_2ghz) 1534250003Sadrian{ 1535250003Sadrian u_int32_t value; 1536250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 1537250003Sadrian u_int32_t regval; 1538250003Sadrian struct ath_hal_private *ahpriv = AH_PRIVATE(ah); 1539250003Sadrian#if ATH_ANT_DIV_COMB 1540250003Sadrian HAL_CAPABILITIES *pcap = &ahpriv->ah_caps; 1541250003Sadrian#endif /* ATH_ANT_DIV_COMB */ 1542250003Sadrian u_int32_t xlan_gpio_cfg; 1543250003Sadrian u_int8_t i; 1544250003Sadrian 1545250003Sadrian if (AR_SREV_POSEIDON(ah)) { 1546250008Sadrian xlan_gpio_cfg = ah->ah_config.ath_hal_ext_lna_ctl_gpio; 1547250003Sadrian if (xlan_gpio_cfg) { 1548250003Sadrian for (i = 0; i < 32; i++) { 1549250003Sadrian if (xlan_gpio_cfg & (1 << i)) { 1550250008Sadrian ath_hal_gpioCfgOutput(ah, i, 1551250008Sadrian HAL_GPIO_OUTPUT_MUX_PCIE_ATTENTION_LED); 1552250003Sadrian } 1553250003Sadrian } 1554250003Sadrian } 1555250003Sadrian } 1556250003Sadrian#define AR_SWITCH_TABLE_COM_ALL (0xffff) 1557250003Sadrian#define AR_SWITCH_TABLE_COM_ALL_S (0) 1558250003Sadrian#define AR_SWITCH_TABLE_COM_JUPITER_ALL (0xffffff) 1559250003Sadrian#define AR_SWITCH_TABLE_COM_JUPITER_ALL_S (0) 1560250003Sadrian#define AR_SWITCH_TABLE_COM_SCORPION_ALL (0xffffff) 1561250003Sadrian#define AR_SWITCH_TABLE_COM_SCORPION_ALL_S (0) 1562250003Sadrian#define AR_SWITCH_TABLE_COM_SPDT (0x00f00000) 1563250003Sadrian value = ar9300_ant_ctrl_common_get(ah, is_2ghz); 1564250003Sadrian if (AR_SREV_JUPITER(ah) || AR_SREV_APHRODITE(ah)) { 1565250003Sadrian if (AR_SREV_JUPITER_10(ah)) { 1566250003Sadrian /* Force SPDT setting for Jupiter 1.0 chips. */ 1567250003Sadrian value &= ~AR_SWITCH_TABLE_COM_SPDT; 1568250003Sadrian value |= 0x00100000; 1569250003Sadrian } 1570250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM, 1571250003Sadrian AR_SWITCH_TABLE_COM_JUPITER_ALL, value); 1572250003Sadrian } 1573250003Sadrian else if (AR_SREV_SCORPION(ah)) { 1574250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM, 1575250003Sadrian AR_SWITCH_TABLE_COM_SCORPION_ALL, value); 1576250003Sadrian } 1577250003Sadrian else { 1578250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM, 1579250003Sadrian AR_SWITCH_TABLE_COM_ALL, value); 1580250003Sadrian } 1581250003Sadrian/* 1582250003Sadrian* Jupiter2.0 defines new switch table for BT/WLAN, 1583250003Sadrian* here's new field name in WB222.ref for both 2G and 5G. 1584250003Sadrian* Register: [GLB_CONTROL] GLB_CONTROL (@0x20044) 1585250003Sadrian* 15:12 R/W SWITCH_TABLE_COM_SPDT_WLAN_RX SWITCH_TABLE_COM_SPDT_WLAN_RX 1586250003Sadrian* 11:8 R/W SWITCH_TABLE_COM_SPDT_WLAN_TX SWITCH_TABLE_COM_SPDT_WLAN_TX 1587250003Sadrian* 7:4 R/W SWITCH_TABLE_COM_SPDT_WLAN_IDLE SWITCH_TABLE_COM_SPDT_WLAN_IDLE 1588250003Sadrian*/ 1589250003Sadrian#define AR_SWITCH_TABLE_COM_SPDT_ALL (0x0000fff0) 1590250003Sadrian#define AR_SWITCH_TABLE_COM_SPDT_ALL_S (4) 1591250003Sadrian if (AR_SREV_JUPITER_20_OR_LATER(ah) || AR_SREV_APHRODITE(ah)) { 1592250003Sadrian value = ar9300_switch_com_spdt_get(ah, is_2ghz); 1593250003Sadrian OS_REG_RMW_FIELD(ah, AR_GLB_CONTROL, 1594250003Sadrian AR_SWITCH_TABLE_COM_SPDT_ALL, value); 1595250003Sadrian 1596250003Sadrian OS_REG_SET_BIT(ah, AR_GLB_CONTROL, 1597250003Sadrian AR_BTCOEX_CTRL_SPDT_ENABLE); 1598250003Sadrian //OS_REG_SET_BIT(ah, AR_GLB_CONTROL, 1599250003Sadrian // AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL); 1600250003Sadrian } 1601250003Sadrian 1602250003Sadrian#define AR_SWITCH_TABLE_COM2_ALL (0xffffff) 1603250003Sadrian#define AR_SWITCH_TABLE_COM2_ALL_S (0) 1604250003Sadrian value = ar9300_ant_ctrl_common2_get(ah, is_2ghz); 1605250003Sadrian#if ATH_ANT_DIV_COMB 1606250003Sadrian if ( AR_SREV_POSEIDON(ah) && (ahp->ah_lna_div_use_bt_ant_enable == TRUE) ) { 1607250003Sadrian value &= ~AR_SWITCH_TABLE_COM2_ALL; 1608250008Sadrian value |= ah->ah_config.ath_hal_ant_ctrl_comm2g_switch_enable; 1609250003Sadrian } 1610250003Sadrian#endif /* ATH_ANT_DIV_COMB */ 1611250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM_2, AR_SWITCH_TABLE_COM2_ALL, value); 1612250003Sadrian 1613250003Sadrian#define AR_SWITCH_TABLE_ALL (0xfff) 1614250003Sadrian#define AR_SWITCH_TABLE_ALL_S (0) 1615250003Sadrian value = ar9300_ant_ctrl_chain_get(ah, 0, is_2ghz); 1616250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_SWITCH_CHAIN_0, AR_SWITCH_TABLE_ALL, value); 1617250003Sadrian 1618250003Sadrian if (!AR_SREV_HORNET(ah) && !AR_SREV_POSEIDON(ah) && !AR_SREV_APHRODITE(ah)) { 1619250003Sadrian value = ar9300_ant_ctrl_chain_get(ah, 1, is_2ghz); 1620250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_SWITCH_CHAIN_1, AR_SWITCH_TABLE_ALL, value); 1621250003Sadrian 1622250003Sadrian if (!AR_SREV_WASP(ah) && !AR_SREV_JUPITER(ah)) { 1623250003Sadrian value = ar9300_ant_ctrl_chain_get(ah, 2, is_2ghz); 1624250003Sadrian OS_REG_RMW_FIELD(ah, 1625250003Sadrian AR_PHY_SWITCH_CHAIN_2, AR_SWITCH_TABLE_ALL, value); 1626250003Sadrian } 1627250003Sadrian } 1628250003Sadrian if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah)) { 1629250003Sadrian value = ar9300_eeprom_get(ahp, EEP_ANTDIV_control); 1630250003Sadrian /* main_lnaconf, alt_lnaconf, main_tb, alt_tb */ 1631250003Sadrian regval = OS_REG_READ(ah, AR_PHY_MC_GAIN_CTRL); 1632250003Sadrian regval &= (~ANT_DIV_CONTROL_ALL); /* clear bit 25~30 */ 1633250003Sadrian regval |= (value & 0x3f) << ANT_DIV_CONTROL_ALL_S; 1634250003Sadrian /* enable_lnadiv */ 1635250003Sadrian regval &= (~MULTICHAIN_GAIN_CTRL__ENABLE_ANT_DIV_LNADIV__MASK); 1636250003Sadrian regval |= ((value >> 6) & 0x1) << 1637250003Sadrian MULTICHAIN_GAIN_CTRL__ENABLE_ANT_DIV_LNADIV__SHIFT; 1638250003Sadrian#if ATH_ANT_DIV_COMB 1639250003Sadrian if ( AR_SREV_POSEIDON(ah) && (ahp->ah_lna_div_use_bt_ant_enable == TRUE) ) { 1640250003Sadrian regval |= ANT_DIV_ENABLE; 1641250003Sadrian } 1642250003Sadrian#endif /* ATH_ANT_DIV_COMB */ 1643250003Sadrian OS_REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval); 1644250003Sadrian 1645250003Sadrian /* enable fast_div */ 1646250003Sadrian regval = OS_REG_READ(ah, AR_PHY_CCK_DETECT); 1647250003Sadrian regval &= (~BBB_SIG_DETECT__ENABLE_ANT_FAST_DIV__MASK); 1648250003Sadrian regval |= ((value >> 7) & 0x1) << 1649250003Sadrian BBB_SIG_DETECT__ENABLE_ANT_FAST_DIV__SHIFT; 1650250003Sadrian#if ATH_ANT_DIV_COMB 1651250003Sadrian if ( AR_SREV_POSEIDON(ah) && (ahp->ah_lna_div_use_bt_ant_enable == TRUE) ) { 1652250003Sadrian regval |= FAST_DIV_ENABLE; 1653250003Sadrian } 1654250003Sadrian#endif /* ATH_ANT_DIV_COMB */ 1655250003Sadrian OS_REG_WRITE(ah, AR_PHY_CCK_DETECT, regval); 1656250003Sadrian } 1657250003Sadrian 1658250003Sadrian#if ATH_ANT_DIV_COMB 1659250003Sadrian if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON_11_OR_LATER(ah)) { 1660250008Sadrian if (pcap->halAntDivCombSupport) { 1661250003Sadrian /* If support DivComb, set MAIN to LNA1, ALT to LNA2 at beginning */ 1662250003Sadrian regval = OS_REG_READ(ah, AR_PHY_MC_GAIN_CTRL); 1663250003Sadrian /* clear bit 25~30 main_lnaconf, alt_lnaconf, main_tb, alt_tb */ 1664250003Sadrian regval &= (~(MULTICHAIN_GAIN_CTRL__ANT_DIV_MAIN_LNACONF__MASK | 1665250003Sadrian MULTICHAIN_GAIN_CTRL__ANT_DIV_ALT_LNACONF__MASK | 1666250003Sadrian MULTICHAIN_GAIN_CTRL__ANT_DIV_ALT_GAINTB__MASK | 1667250003Sadrian MULTICHAIN_GAIN_CTRL__ANT_DIV_MAIN_GAINTB__MASK)); 1668250003Sadrian regval |= (HAL_ANT_DIV_COMB_LNA1 << 1669250003Sadrian MULTICHAIN_GAIN_CTRL__ANT_DIV_MAIN_LNACONF__SHIFT); 1670250003Sadrian regval |= (HAL_ANT_DIV_COMB_LNA2 << 1671250003Sadrian MULTICHAIN_GAIN_CTRL__ANT_DIV_ALT_LNACONF__SHIFT); 1672250003Sadrian OS_REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval); 1673250003Sadrian } 1674250003Sadrian 1675250003Sadrian } 1676250003Sadrian#endif /* ATH_ANT_DIV_COMB */ 1677250003Sadrian if (AR_SREV_POSEIDON(ah) && ( ahp->ah_diversity_control == HAL_ANT_FIXED_A 1678250003Sadrian || ahp->ah_diversity_control == HAL_ANT_FIXED_B)) 1679250003Sadrian { 1680250003Sadrian u_int32_t reg_val = OS_REG_READ(ah, AR_PHY_MC_GAIN_CTRL); 1681250003Sadrian reg_val &= ~(MULTICHAIN_GAIN_CTRL__ANT_DIV_MAIN_LNACONF__MASK | 1682250003Sadrian MULTICHAIN_GAIN_CTRL__ANT_DIV_ALT_LNACONF__MASK | 1683250003Sadrian MULTICHAIN_GAIN_CTRL__ANT_FAST_DIV_BIAS__MASK | 1684250003Sadrian MULTICHAIN_GAIN_CTRL__ANT_DIV_MAIN_GAINTB__MASK | 1685250003Sadrian MULTICHAIN_GAIN_CTRL__ANT_DIV_ALT_GAINTB__MASK ); 1686250003Sadrian 1687250003Sadrian switch (ahp->ah_diversity_control) { 1688250003Sadrian case HAL_ANT_FIXED_A: 1689250003Sadrian /* Enable first antenna only */ 1690250003Sadrian reg_val |= (HAL_ANT_DIV_COMB_LNA1 << 1691250003Sadrian MULTICHAIN_GAIN_CTRL__ANT_DIV_MAIN_LNACONF__SHIFT); 1692250003Sadrian reg_val |= (HAL_ANT_DIV_COMB_LNA2 << 1693250003Sadrian MULTICHAIN_GAIN_CTRL__ANT_DIV_ALT_LNACONF__SHIFT); 1694250003Sadrian /* main/alt gain table and Fast Div Bias all set to 0 */ 1695250003Sadrian OS_REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, reg_val); 1696250003Sadrian regval = OS_REG_READ(ah, AR_PHY_CCK_DETECT); 1697250003Sadrian regval &= (~BBB_SIG_DETECT__ENABLE_ANT_FAST_DIV__MASK); 1698250003Sadrian OS_REG_WRITE(ah, AR_PHY_CCK_DETECT, regval); 1699250003Sadrian break; 1700250003Sadrian case HAL_ANT_FIXED_B: 1701250003Sadrian /* Enable second antenna only, after checking capability */ 1702250003Sadrian reg_val |= (HAL_ANT_DIV_COMB_LNA2 << 1703250003Sadrian MULTICHAIN_GAIN_CTRL__ANT_DIV_MAIN_LNACONF__SHIFT); 1704250003Sadrian reg_val |= (HAL_ANT_DIV_COMB_LNA1 << 1705250003Sadrian MULTICHAIN_GAIN_CTRL__ANT_DIV_ALT_LNACONF__SHIFT); 1706250003Sadrian /* main/alt gain table and Fast Div all set to 0 */ 1707250003Sadrian OS_REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, reg_val); 1708250003Sadrian regval = OS_REG_READ(ah, AR_PHY_CCK_DETECT); 1709250003Sadrian regval &= (~BBB_SIG_DETECT__ENABLE_ANT_FAST_DIV__MASK); 1710250003Sadrian OS_REG_WRITE(ah, AR_PHY_CCK_DETECT, regval); 1711250003Sadrian /* For WB225, need to swith ANT2 from BT to Wifi 1712250003Sadrian * This will not affect HB125 LNA diversity feature. 1713250003Sadrian */ 1714250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM_2, AR_SWITCH_TABLE_COM2_ALL, 1715250008Sadrian ah->ah_config.ath_hal_ant_ctrl_comm2g_switch_enable); 1716250003Sadrian break; 1717250003Sadrian default: 1718250003Sadrian break; 1719250003Sadrian } 1720250003Sadrian } 1721250003Sadrian return 0; 1722250003Sadrian} 1723250003Sadrian 1724250003Sadrianstatic u_int16_t 1725250003Sadrianar9300_attenuation_chain_get(struct ath_hal *ah, int chain, u_int16_t channel) 1726250003Sadrian{ 1727250003Sadrian int32_t f[3], t[3]; 1728250003Sadrian u_int16_t value; 1729250003Sadrian ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom; 1730250003Sadrian if (chain >= 0 && chain < OSPREY_MAX_CHAINS) { 1731250003Sadrian if (channel < 4000) { 1732250003Sadrian return eep->modal_header_2g.xatten1_db[chain]; 1733250003Sadrian } else { 1734250003Sadrian if (eep->base_ext2.xatten1_db_low[chain] != 0) { 1735250003Sadrian t[0] = eep->base_ext2.xatten1_db_low[chain]; 1736250003Sadrian f[0] = 5180; 1737250003Sadrian t[1] = eep->modal_header_5g.xatten1_db[chain]; 1738250003Sadrian f[1] = 5500; 1739250003Sadrian t[2] = eep->base_ext2.xatten1_db_high[chain]; 1740250003Sadrian f[2] = 5785; 1741250003Sadrian value = interpolate(channel, f, t, 3); 1742250003Sadrian return value; 1743250003Sadrian } else { 1744250003Sadrian return eep->modal_header_5g.xatten1_db[chain]; 1745250003Sadrian } 1746250003Sadrian } 1747250003Sadrian } 1748250003Sadrian return 0; 1749250003Sadrian} 1750250003Sadrian 1751250003Sadrianstatic u_int16_t 1752250003Sadrianar9300_attenuation_margin_chain_get(struct ath_hal *ah, int chain, 1753250003Sadrian u_int16_t channel) 1754250003Sadrian{ 1755250003Sadrian int32_t f[3], t[3]; 1756250003Sadrian u_int16_t value; 1757250003Sadrian ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom; 1758250003Sadrian if (chain >= 0 && chain < OSPREY_MAX_CHAINS) { 1759250003Sadrian if (channel < 4000) { 1760250003Sadrian return eep->modal_header_2g.xatten1_margin[chain]; 1761250003Sadrian } else { 1762250003Sadrian if (eep->base_ext2.xatten1_margin_low[chain] != 0) { 1763250003Sadrian t[0] = eep->base_ext2.xatten1_margin_low[chain]; 1764250003Sadrian f[0] = 5180; 1765250003Sadrian t[1] = eep->modal_header_5g.xatten1_margin[chain]; 1766250003Sadrian f[1] = 5500; 1767250003Sadrian t[2] = eep->base_ext2.xatten1_margin_high[chain]; 1768250003Sadrian f[2] = 5785; 1769250003Sadrian value = interpolate(channel, f, t, 3); 1770250003Sadrian return value; 1771250003Sadrian } else { 1772250003Sadrian return eep->modal_header_5g.xatten1_margin[chain]; 1773250003Sadrian } 1774250003Sadrian } 1775250003Sadrian } 1776250003Sadrian return 0; 1777250003Sadrian} 1778250003Sadrian 1779250003SadrianHAL_BOOL ar9300_attenuation_apply(struct ath_hal *ah, u_int16_t channel) 1780250003Sadrian{ 1781250003Sadrian u_int32_t value; 1782250008Sadrian// struct ath_hal_private *ahpriv = AH_PRIVATE(ah); 1783250003Sadrian 1784250003Sadrian /* Test value. if 0 then attenuation is unused. Don't load anything. */ 1785250003Sadrian value = ar9300_attenuation_chain_get(ah, 0, channel); 1786250003Sadrian OS_REG_RMW_FIELD(ah, 1787250003Sadrian AR_PHY_EXT_ATTEN_CTL_0, AR_PHY_EXT_ATTEN_CTL_XATTEN1_DB, value); 1788250003Sadrian value = ar9300_attenuation_margin_chain_get(ah, 0, channel); 1789250003Sadrian if (ar9300_rx_gain_index_get(ah) == 0 1790250008Sadrian && ah->ah_config.ath_hal_ext_atten_margin_cfg) 1791250003Sadrian { 1792250003Sadrian value = 5; 1793250003Sadrian } 1794250003Sadrian OS_REG_RMW_FIELD(ah, 1795250003Sadrian AR_PHY_EXT_ATTEN_CTL_0, AR_PHY_EXT_ATTEN_CTL_XATTEN1_MARGIN, value); 1796250003Sadrian 1797250003Sadrian if (!AR_SREV_HORNET(ah) && !AR_SREV_POSEIDON(ah)) { 1798250003Sadrian value = ar9300_attenuation_chain_get(ah, 1, channel); 1799250003Sadrian OS_REG_RMW_FIELD(ah, 1800250003Sadrian AR_PHY_EXT_ATTEN_CTL_1, AR_PHY_EXT_ATTEN_CTL_XATTEN1_DB, value); 1801250003Sadrian value = ar9300_attenuation_margin_chain_get(ah, 1, channel); 1802250003Sadrian OS_REG_RMW_FIELD(ah, 1803250003Sadrian AR_PHY_EXT_ATTEN_CTL_1, AR_PHY_EXT_ATTEN_CTL_XATTEN1_MARGIN, 1804250003Sadrian value); 1805250003Sadrian if (!AR_SREV_WASP(ah) && !AR_SREV_JUPITER(ah)) { 1806250003Sadrian value = ar9300_attenuation_chain_get(ah, 2, channel); 1807250003Sadrian OS_REG_RMW_FIELD(ah, 1808250003Sadrian AR_PHY_EXT_ATTEN_CTL_2, AR_PHY_EXT_ATTEN_CTL_XATTEN1_DB, value); 1809250003Sadrian value = ar9300_attenuation_margin_chain_get(ah, 2, channel); 1810250003Sadrian OS_REG_RMW_FIELD(ah, 1811250003Sadrian AR_PHY_EXT_ATTEN_CTL_2, AR_PHY_EXT_ATTEN_CTL_XATTEN1_MARGIN, 1812250003Sadrian value); 1813250003Sadrian } 1814250003Sadrian } 1815250003Sadrian return 0; 1816250003Sadrian} 1817250003Sadrian 1818250003Sadrianstatic u_int16_t ar9300_quick_drop_get(struct ath_hal *ah, 1819250003Sadrian int chain, u_int16_t channel) 1820250003Sadrian{ 1821250003Sadrian int32_t f[3], t[3]; 1822250003Sadrian u_int16_t value; 1823250003Sadrian ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom; 1824250003Sadrian 1825250003Sadrian if (channel < 4000) { 1826250003Sadrian return eep->modal_header_2g.quick_drop; 1827250003Sadrian } else { 1828250003Sadrian t[0] = eep->base_ext1.quick_drop_low; 1829250003Sadrian f[0] = 5180; 1830250003Sadrian t[1] = eep->modal_header_5g.quick_drop; 1831250003Sadrian f[1] = 5500; 1832250003Sadrian t[2] = eep->base_ext1.quick_drop_high; 1833250003Sadrian f[2] = 5785; 1834250003Sadrian value = interpolate(channel, f, t, 3); 1835250003Sadrian return value; 1836250003Sadrian } 1837250003Sadrian} 1838250003Sadrian 1839250003Sadrian 1840250003Sadrianstatic HAL_BOOL ar9300_quick_drop_apply(struct ath_hal *ah, u_int16_t channel) 1841250003Sadrian{ 1842250003Sadrian ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom; 1843250003Sadrian u_int32_t value; 1844250003Sadrian // 1845250003Sadrian // Test value. if 0 then quickDrop is unused. Don't load anything. 1846250003Sadrian // 1847250003Sadrian if (eep->base_eep_header.misc_configuration & 0x10) 1848250003Sadrian { 1849250003Sadrian if (AR_SREV_OSPREY(ah) || AR_SREV_AR9580(ah) || AR_SREV_WASP(ah)) 1850250003Sadrian { 1851250003Sadrian value = ar9300_quick_drop_get(ah, 0, channel); 1852250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_AGC, AR_PHY_AGC_QUICK_DROP, value); 1853250003Sadrian } 1854250003Sadrian } 1855250003Sadrian return 0; 1856250003Sadrian} 1857250003Sadrian 1858250003Sadrianstatic u_int16_t ar9300_tx_end_to_xpa_off_get(struct ath_hal *ah, u_int16_t channel) 1859250003Sadrian{ 1860250003Sadrian ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom; 1861250003Sadrian 1862250003Sadrian if (channel < 4000) { 1863250003Sadrian return eep->modal_header_2g.tx_end_to_xpa_off; 1864250003Sadrian } else { 1865250003Sadrian return eep->modal_header_5g.tx_end_to_xpa_off; 1866250003Sadrian } 1867250003Sadrian} 1868250003Sadrian 1869250003Sadrianstatic HAL_BOOL ar9300_tx_end_to_xpab_off_apply(struct ath_hal *ah, u_int16_t channel) 1870250003Sadrian{ 1871250003Sadrian u_int32_t value; 1872250003Sadrian 1873250003Sadrian value = ar9300_tx_end_to_xpa_off_get(ah, channel); 1874250003Sadrian /* Apply to both xpaa and xpab */ 1875250003Sadrian if (AR_SREV_OSPREY(ah) || AR_SREV_AR9580(ah) || AR_SREV_WASP(ah)) 1876250003Sadrian { 1877250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_XPA_TIMING_CTL, 1878250003Sadrian AR_PHY_XPA_TIMING_CTL_TX_END_XPAB_OFF, value); 1879250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_XPA_TIMING_CTL, 1880250003Sadrian AR_PHY_XPA_TIMING_CTL_TX_END_XPAA_OFF, value); 1881250003Sadrian } 1882250003Sadrian return 0; 1883250003Sadrian} 1884250003Sadrian 1885250003Sadrianstatic int 1886250003Sadrianar9300_eeprom_cal_pier_get(struct ath_hal *ah, int mode, int ipier, int ichain, 1887250003Sadrian int *pfrequency, int *pcorrection, int *ptemperature, int *pvoltage) 1888250003Sadrian{ 1889250003Sadrian u_int8_t *p_cal_pier; 1890250003Sadrian OSP_CAL_DATA_PER_FREQ_OP_LOOP *p_cal_pier_struct; 1891250003Sadrian int is_2ghz; 1892250003Sadrian ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom; 1893250003Sadrian 1894250003Sadrian if (ichain >= OSPREY_MAX_CHAINS) { 1895250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, 1896250003Sadrian "%s: Invalid chain index, must be less than %d\n", 1897250003Sadrian __func__, OSPREY_MAX_CHAINS); 1898250003Sadrian return -1; 1899250003Sadrian } 1900250003Sadrian 1901250003Sadrian if (mode) {/* 5GHz */ 1902250003Sadrian if (ipier >= OSPREY_NUM_5G_CAL_PIERS){ 1903250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, 1904250003Sadrian "%s: Invalid 5GHz cal pier index, must be less than %d\n", 1905250003Sadrian __func__, OSPREY_NUM_5G_CAL_PIERS); 1906250003Sadrian return -1; 1907250003Sadrian } 1908250003Sadrian p_cal_pier = &(eep->cal_freq_pier_5g[ipier]); 1909250003Sadrian p_cal_pier_struct = &(eep->cal_pier_data_5g[ichain][ipier]); 1910250003Sadrian is_2ghz = 0; 1911250003Sadrian } else { 1912250003Sadrian if (ipier >= OSPREY_NUM_2G_CAL_PIERS){ 1913250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, 1914250003Sadrian "%s: Invalid 2GHz cal pier index, must be less than %d\n", 1915250003Sadrian __func__, OSPREY_NUM_2G_CAL_PIERS); 1916250003Sadrian return -1; 1917250003Sadrian } 1918250003Sadrian 1919250003Sadrian p_cal_pier = &(eep->cal_freq_pier_2g[ipier]); 1920250003Sadrian p_cal_pier_struct = &(eep->cal_pier_data_2g[ichain][ipier]); 1921250003Sadrian is_2ghz = 1; 1922250003Sadrian } 1923250003Sadrian *pfrequency = FBIN2FREQ(*p_cal_pier, is_2ghz); 1924250003Sadrian *pcorrection = p_cal_pier_struct->ref_power; 1925250003Sadrian *ptemperature = p_cal_pier_struct->temp_meas; 1926250003Sadrian *pvoltage = p_cal_pier_struct->volt_meas; 1927250003Sadrian return 0; 1928250003Sadrian} 1929250003Sadrian 1930250003Sadrian/* 1931250003Sadrian * Apply the recorded correction values. 1932250003Sadrian */ 1933250003Sadrianstatic int 1934250003Sadrianar9300_calibration_apply(struct ath_hal *ah, int frequency) 1935250003Sadrian{ 1936250008Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 1937250008Sadrian 1938250003Sadrian int ichain, ipier, npier; 1939250003Sadrian int mode; 1940250003Sadrian int fdiff; 1941250003Sadrian int pfrequency, pcorrection, ptemperature, pvoltage; 1942250003Sadrian int bf, factor, plus; 1943250003Sadrian 1944250003Sadrian int lfrequency[AR9300_MAX_CHAINS]; 1945250003Sadrian int hfrequency[AR9300_MAX_CHAINS]; 1946250003Sadrian 1947250003Sadrian int lcorrection[AR9300_MAX_CHAINS]; 1948250003Sadrian int hcorrection[AR9300_MAX_CHAINS]; 1949250003Sadrian int correction[AR9300_MAX_CHAINS]; 1950250003Sadrian 1951250003Sadrian int ltemperature[AR9300_MAX_CHAINS]; 1952250003Sadrian int htemperature[AR9300_MAX_CHAINS]; 1953250003Sadrian int temperature[AR9300_MAX_CHAINS]; 1954250003Sadrian 1955250003Sadrian int lvoltage[AR9300_MAX_CHAINS]; 1956250003Sadrian int hvoltage[AR9300_MAX_CHAINS]; 1957250003Sadrian int voltage[AR9300_MAX_CHAINS]; 1958250003Sadrian 1959250003Sadrian mode = (frequency >= 4000); 1960250003Sadrian npier = (mode) ? OSPREY_NUM_5G_CAL_PIERS : OSPREY_NUM_2G_CAL_PIERS; 1961250003Sadrian 1962250003Sadrian for (ichain = 0; ichain < AR9300_MAX_CHAINS; ichain++) { 1963250003Sadrian lfrequency[ichain] = 0; 1964250003Sadrian hfrequency[ichain] = 100000; 1965250003Sadrian } 1966250003Sadrian /* 1967250003Sadrian * identify best lower and higher frequency calibration measurement 1968250003Sadrian */ 1969250003Sadrian for (ichain = 0; ichain < AR9300_MAX_CHAINS; ichain++) { 1970250003Sadrian for (ipier = 0; ipier < npier; ipier++) { 1971250003Sadrian if (ar9300_eeprom_cal_pier_get( 1972250003Sadrian ah, mode, ipier, ichain, 1973250003Sadrian &pfrequency, &pcorrection, &ptemperature, &pvoltage) == 0) 1974250003Sadrian { 1975250003Sadrian fdiff = frequency - pfrequency; 1976250003Sadrian /* 1977250003Sadrian * this measurement is higher than our desired frequency 1978250003Sadrian */ 1979250003Sadrian if (fdiff <= 0) { 1980250003Sadrian if (hfrequency[ichain] <= 0 || 1981250003Sadrian hfrequency[ichain] >= 100000 || 1982250003Sadrian fdiff > (frequency - hfrequency[ichain])) 1983250003Sadrian { 1984250003Sadrian /* 1985250003Sadrian * new best higher frequency measurement 1986250003Sadrian */ 1987250003Sadrian hfrequency[ichain] = pfrequency; 1988250003Sadrian hcorrection[ichain] = pcorrection; 1989250003Sadrian htemperature[ichain] = ptemperature; 1990250003Sadrian hvoltage[ichain] = pvoltage; 1991250003Sadrian } 1992250003Sadrian } 1993250003Sadrian if (fdiff >= 0) { 1994250003Sadrian if (lfrequency[ichain] <= 0 || 1995250003Sadrian fdiff < (frequency - lfrequency[ichain])) 1996250003Sadrian { 1997250003Sadrian /* 1998250003Sadrian * new best lower frequency measurement 1999250003Sadrian */ 2000250003Sadrian lfrequency[ichain] = pfrequency; 2001250003Sadrian lcorrection[ichain] = pcorrection; 2002250003Sadrian ltemperature[ichain] = ptemperature; 2003250003Sadrian lvoltage[ichain] = pvoltage; 2004250003Sadrian } 2005250003Sadrian } 2006250003Sadrian } 2007250003Sadrian } 2008250003Sadrian } 2009250003Sadrian /* interpolate */ 2010250003Sadrian for (ichain = 0; ichain < AR9300_MAX_CHAINS; ichain++) { 2011250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, 2012250003Sadrian "%s: ch=%d f=%d low=%d %d h=%d %d\n", 2013250003Sadrian __func__, ichain, frequency, 2014250003Sadrian lfrequency[ichain], lcorrection[ichain], 2015250003Sadrian hfrequency[ichain], hcorrection[ichain]); 2016250003Sadrian /* 2017250003Sadrian * they're the same, so just pick one 2018250003Sadrian */ 2019250003Sadrian if (hfrequency[ichain] == lfrequency[ichain]) { 2020250003Sadrian correction[ichain] = lcorrection[ichain]; 2021250003Sadrian voltage[ichain] = lvoltage[ichain]; 2022250003Sadrian temperature[ichain] = ltemperature[ichain]; 2023250003Sadrian } else if (frequency - lfrequency[ichain] < 1000) { 2024250003Sadrian /* the low frequency is good */ 2025250003Sadrian if (hfrequency[ichain] - frequency < 1000) { 2026250003Sadrian /* 2027250003Sadrian * The high frequency is good too - 2028250003Sadrian * interpolate with round off. 2029250003Sadrian */ 2030250003Sadrian int mult, div, diff; 2031250003Sadrian mult = frequency - lfrequency[ichain]; 2032250003Sadrian div = hfrequency[ichain] - lfrequency[ichain]; 2033250003Sadrian 2034250003Sadrian diff = hcorrection[ichain] - lcorrection[ichain]; 2035250003Sadrian bf = 2 * diff * mult / div; 2036250003Sadrian plus = (bf % 2); 2037250003Sadrian factor = bf / 2; 2038250003Sadrian correction[ichain] = lcorrection[ichain] + factor + plus; 2039250003Sadrian 2040250003Sadrian diff = htemperature[ichain] - ltemperature[ichain]; 2041250003Sadrian bf = 2 * diff * mult / div; 2042250003Sadrian plus = (bf % 2); 2043250003Sadrian factor = bf / 2; 2044250003Sadrian temperature[ichain] = ltemperature[ichain] + factor + plus; 2045250003Sadrian 2046250003Sadrian diff = hvoltage[ichain] - lvoltage[ichain]; 2047250003Sadrian bf = 2 * diff * mult / div; 2048250003Sadrian plus = (bf % 2); 2049250003Sadrian factor = bf / 2; 2050250003Sadrian voltage[ichain] = lvoltage[ichain] + factor + plus; 2051250003Sadrian } else { 2052250003Sadrian /* only low is good, use it */ 2053250003Sadrian correction[ichain] = lcorrection[ichain]; 2054250003Sadrian temperature[ichain] = ltemperature[ichain]; 2055250003Sadrian voltage[ichain] = lvoltage[ichain]; 2056250003Sadrian } 2057250003Sadrian } else if (hfrequency[ichain] - frequency < 1000) { 2058250003Sadrian /* only high is good, use it */ 2059250003Sadrian correction[ichain] = hcorrection[ichain]; 2060250003Sadrian temperature[ichain] = htemperature[ichain]; 2061250003Sadrian voltage[ichain] = hvoltage[ichain]; 2062250003Sadrian } else { 2063250003Sadrian /* nothing is good, presume 0???? */ 2064250003Sadrian correction[ichain] = 0; 2065250003Sadrian temperature[ichain] = 0; 2066250003Sadrian voltage[ichain] = 0; 2067250003Sadrian } 2068250003Sadrian } 2069250003Sadrian 2070250008Sadrian /* GreenTx isn't currently supported */ 2071250003Sadrian /* GreenTx */ 2072250008Sadrian if (ah->ah_config.ath_hal_sta_update_tx_pwr_enable) { 2073250003Sadrian if (AR_SREV_POSEIDON(ah)) { 2074250003Sadrian /* Get calibrated OLPC gain delta value for GreenTx */ 2075250008Sadrian ahp->ah_db2[POSEIDON_STORED_REG_G2_OLPC_OFFSET] = 2076250003Sadrian (u_int32_t) correction[0]; 2077250003Sadrian } 2078250003Sadrian } 2079250003Sadrian 2080250003Sadrian ar9300_power_control_override( 2081250003Sadrian ah, frequency, correction, voltage, temperature); 2082250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, 2083250003Sadrian "%s: for frequency=%d, calibration correction = %d %d %d\n", 2084250003Sadrian __func__, frequency, correction[0], correction[1], correction[2]); 2085250003Sadrian 2086250003Sadrian return 0; 2087250003Sadrian} 2088250003Sadrian 2089250003Sadrianint 2090250003Sadrianar9300_power_control_override(struct ath_hal *ah, int frequency, 2091250003Sadrian int *correction, int *voltage, int *temperature) 2092250003Sadrian{ 2093250003Sadrian int temp_slope = 0; 2094250003Sadrian int temp_slope_1 = 0; 2095250003Sadrian int temp_slope_2 = 0; 2096250003Sadrian ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom; 2097250003Sadrian int32_t f[8], t[8],t1[3], t2[3]; 2098250003Sadrian int i; 2099250003Sadrian 2100250003Sadrian OS_REG_RMW(ah, AR_PHY_TPC_11_B0, 2101250003Sadrian (correction[0] << AR_PHY_TPC_OLPC_GAIN_DELTA_S), 2102250003Sadrian AR_PHY_TPC_OLPC_GAIN_DELTA); 2103250003Sadrian if (!AR_SREV_POSEIDON(ah)) { 2104250003Sadrian OS_REG_RMW(ah, AR_PHY_TPC_11_B1, 2105250003Sadrian (correction[1] << AR_PHY_TPC_OLPC_GAIN_DELTA_S), 2106250003Sadrian AR_PHY_TPC_OLPC_GAIN_DELTA); 2107250003Sadrian if (!AR_SREV_WASP(ah) && !AR_SREV_JUPITER(ah)) { 2108250003Sadrian OS_REG_RMW(ah, AR_PHY_TPC_11_B2, 2109250003Sadrian (correction[2] << AR_PHY_TPC_OLPC_GAIN_DELTA_S), 2110250003Sadrian AR_PHY_TPC_OLPC_GAIN_DELTA); 2111250003Sadrian } 2112250003Sadrian } 2113250003Sadrian /* 2114250003Sadrian * enable open loop power control on chip 2115250003Sadrian */ 2116250003Sadrian OS_REG_RMW(ah, AR_PHY_TPC_6_B0, 2117250003Sadrian (3 << AR_PHY_TPC_6_ERROR_EST_MODE_S), AR_PHY_TPC_6_ERROR_EST_MODE); 2118250003Sadrian if (!AR_SREV_POSEIDON(ah)) { 2119250003Sadrian OS_REG_RMW(ah, AR_PHY_TPC_6_B1, 2120250003Sadrian (3 << AR_PHY_TPC_6_ERROR_EST_MODE_S), AR_PHY_TPC_6_ERROR_EST_MODE); 2121250003Sadrian if (!AR_SREV_WASP(ah) && !AR_SREV_JUPITER(ah)) { 2122250003Sadrian OS_REG_RMW(ah, AR_PHY_TPC_6_B2, 2123250003Sadrian (3 << AR_PHY_TPC_6_ERROR_EST_MODE_S), 2124250003Sadrian AR_PHY_TPC_6_ERROR_EST_MODE); 2125250003Sadrian } 2126250003Sadrian } 2127250003Sadrian 2128250003Sadrian /* 2129250003Sadrian * Enable temperature compensation 2130250003Sadrian * Need to use register names 2131250003Sadrian */ 2132250003Sadrian if (frequency < 4000) { 2133250003Sadrian temp_slope = eep->modal_header_2g.temp_slope; 2134250003Sadrian } else { 2135250003Sadrian if ((eep->base_eep_header.misc_configuration & 0x20) != 0) 2136250003Sadrian { 2137250003Sadrian for(i=0;i<8;i++) 2138250003Sadrian { 2139250003Sadrian t[i]=eep->base_ext1.tempslopextension[i]; 2140250003Sadrian f[i]=FBIN2FREQ(eep->cal_freq_pier_5g[i], 0); 2141250003Sadrian } 2142250003Sadrian temp_slope=interpolate(frequency,f,t,8); 2143250003Sadrian } 2144250003Sadrian else 2145250003Sadrian { 2146250003Sadrian if(!AR_SREV_SCORPION(ah)) { 2147250003Sadrian if (eep->base_ext2.temp_slope_low != 0) { 2148250003Sadrian t[0] = eep->base_ext2.temp_slope_low; 2149250003Sadrian f[0] = 5180; 2150250003Sadrian t[1] = eep->modal_header_5g.temp_slope; 2151250003Sadrian f[1] = 5500; 2152250003Sadrian t[2] = eep->base_ext2.temp_slope_high; 2153250003Sadrian f[2] = 5785; 2154250003Sadrian temp_slope = interpolate(frequency, f, t, 3); 2155250003Sadrian } else { 2156250003Sadrian temp_slope = eep->modal_header_5g.temp_slope; 2157250003Sadrian } 2158250003Sadrian } else { 2159250003Sadrian /* 2160250003Sadrian * Scorpion has individual chain tempslope values 2161250003Sadrian */ 2162250003Sadrian t[0] = eep->base_ext1.tempslopextension[2]; 2163250003Sadrian t1[0]= eep->base_ext1.tempslopextension[3]; 2164250003Sadrian t2[0]= eep->base_ext1.tempslopextension[4]; 2165250003Sadrian f[0] = 5180; 2166250003Sadrian t[1] = eep->modal_header_5g.temp_slope; 2167250003Sadrian t1[1]= eep->base_ext1.tempslopextension[0]; 2168250003Sadrian t2[1]= eep->base_ext1.tempslopextension[1]; 2169250003Sadrian f[1] = 5500; 2170250003Sadrian t[2] = eep->base_ext1.tempslopextension[5]; 2171250003Sadrian t1[2]= eep->base_ext1.tempslopextension[6]; 2172250003Sadrian t2[2]= eep->base_ext1.tempslopextension[7]; 2173250003Sadrian f[2] = 5785; 2174250003Sadrian temp_slope = interpolate(frequency, f, t, 3); 2175250003Sadrian temp_slope_1=interpolate(frequency, f, t1,3); 2176250003Sadrian temp_slope_2=interpolate(frequency, f, t2,3); 2177250003Sadrian } 2178250003Sadrian } 2179250003Sadrian } 2180250003Sadrian 2181250003Sadrian if (!AR_SREV_SCORPION(ah)) { 2182250003Sadrian OS_REG_RMW_FIELD(ah, 2183250003Sadrian AR_PHY_TPC_19, AR_PHY_TPC_19_ALPHA_THERM, temp_slope); 2184250003Sadrian } else { 2185250003Sadrian /*Scorpion has tempSlope register for each chain*/ 2186250003Sadrian /*Check whether temp_compensation feature is enabled or not*/ 2187250003Sadrian if (eep->base_eep_header.feature_enable & 0x1){ 2188250003Sadrian if(frequency < 4000) { 2189250003Sadrian OS_REG_RMW_FIELD(ah, 2190250003Sadrian AR_PHY_TPC_19, AR_PHY_TPC_19_ALPHA_THERM, 2191250003Sadrian eep->base_ext2.temp_slope_low); 2192250003Sadrian OS_REG_RMW_FIELD(ah, 2193250003Sadrian AR_SCORPION_PHY_TPC_19_B1, AR_PHY_TPC_19_ALPHA_THERM, 2194250003Sadrian temp_slope); 2195250003Sadrian OS_REG_RMW_FIELD(ah, 2196250003Sadrian AR_SCORPION_PHY_TPC_19_B2, AR_PHY_TPC_19_ALPHA_THERM, 2197250003Sadrian eep->base_ext2.temp_slope_high); 2198250003Sadrian } else { 2199250003Sadrian OS_REG_RMW_FIELD(ah, 2200250003Sadrian AR_PHY_TPC_19, AR_PHY_TPC_19_ALPHA_THERM, 2201250003Sadrian temp_slope); 2202250003Sadrian OS_REG_RMW_FIELD(ah, 2203250003Sadrian AR_SCORPION_PHY_TPC_19_B1, AR_PHY_TPC_19_ALPHA_THERM, 2204250003Sadrian temp_slope_1); 2205250003Sadrian OS_REG_RMW_FIELD(ah, 2206250003Sadrian AR_SCORPION_PHY_TPC_19_B2, AR_PHY_TPC_19_ALPHA_THERM, 2207250003Sadrian temp_slope_2); 2208250003Sadrian } 2209250003Sadrian }else { 2210250003Sadrian /* If temp compensation is not enabled, set all registers to 0*/ 2211250003Sadrian OS_REG_RMW_FIELD(ah, 2212250003Sadrian AR_PHY_TPC_19, AR_PHY_TPC_19_ALPHA_THERM, 0); 2213250003Sadrian OS_REG_RMW_FIELD(ah, 2214250003Sadrian AR_SCORPION_PHY_TPC_19_B1, AR_PHY_TPC_19_ALPHA_THERM, 0); 2215250003Sadrian OS_REG_RMW_FIELD(ah, 2216250003Sadrian AR_SCORPION_PHY_TPC_19_B2, AR_PHY_TPC_19_ALPHA_THERM, 0); 2217250003Sadrian } 2218250003Sadrian } 2219250003Sadrian OS_REG_RMW_FIELD(ah, 2220250003Sadrian AR_PHY_TPC_18, AR_PHY_TPC_18_THERM_CAL_VALUE, temperature[0]); 2221250003Sadrian 2222250003Sadrian return 0; 2223250003Sadrian} 2224250003Sadrian 2225250003Sadrian/************************************************************** 2226250003Sadrian * ar9300_eep_def_get_max_edge_power 2227250003Sadrian * 2228250003Sadrian * Find the maximum conformance test limit for the given channel and CTL info 2229250003Sadrian */ 2230250003Sadrianstatic inline u_int16_t 2231250003Sadrianar9300_eep_def_get_max_edge_power(ar9300_eeprom_t *p_eep_data, u_int16_t freq, 2232250003Sadrian int idx, HAL_BOOL is_2ghz) 2233250003Sadrian{ 2234250003Sadrian u_int16_t twice_max_edge_power = AR9300_MAX_RATE_POWER; 2235250003Sadrian u_int8_t *ctl_freqbin = is_2ghz ? 2236250003Sadrian &p_eep_data->ctl_freqbin_2G[idx][0] : 2237250003Sadrian &p_eep_data->ctl_freqbin_5G[idx][0]; 2238250003Sadrian u_int16_t num_edges = is_2ghz ? 2239250003Sadrian OSPREY_NUM_BAND_EDGES_2G : OSPREY_NUM_BAND_EDGES_5G; 2240250003Sadrian int i; 2241250003Sadrian 2242250003Sadrian /* Get the edge power */ 2243250003Sadrian for (i = 0; (i < num_edges) && (ctl_freqbin[i] != AR9300_BCHAN_UNUSED); i++) 2244250003Sadrian { 2245250003Sadrian /* 2246250003Sadrian * If there's an exact channel match or an inband flag set 2247250003Sadrian * on the lower channel use the given rd_edge_power 2248250003Sadrian */ 2249250003Sadrian if (freq == fbin2freq(ctl_freqbin[i], is_2ghz)) { 2250250003Sadrian if (is_2ghz) { 2251250003Sadrian twice_max_edge_power = 2252250003Sadrian p_eep_data->ctl_power_data_2g[idx].ctl_edges[i].t_power; 2253250003Sadrian } else { 2254250003Sadrian twice_max_edge_power = 2255250003Sadrian p_eep_data->ctl_power_data_5g[idx].ctl_edges[i].t_power; 2256250003Sadrian } 2257250003Sadrian break; 2258250003Sadrian } else if ((i > 0) && (freq < fbin2freq(ctl_freqbin[i], is_2ghz))) { 2259250003Sadrian if (is_2ghz) { 2260250003Sadrian if (fbin2freq(ctl_freqbin[i - 1], 1) < freq && 2261250003Sadrian p_eep_data->ctl_power_data_2g[idx].ctl_edges[i - 1].flag) 2262250003Sadrian { 2263250003Sadrian twice_max_edge_power = 2264250003Sadrian p_eep_data->ctl_power_data_2g[idx]. 2265250003Sadrian ctl_edges[i - 1].t_power; 2266250003Sadrian } 2267250003Sadrian } else { 2268250003Sadrian if (fbin2freq(ctl_freqbin[i - 1], 0) < freq && 2269250003Sadrian p_eep_data->ctl_power_data_5g[idx].ctl_edges[i - 1].flag) 2270250003Sadrian { 2271250003Sadrian twice_max_edge_power = 2272250003Sadrian p_eep_data->ctl_power_data_5g[idx]. 2273250003Sadrian ctl_edges[i - 1].t_power; 2274250003Sadrian } 2275250003Sadrian } 2276250003Sadrian /* 2277250003Sadrian * Leave loop - no more affecting edges possible 2278250003Sadrian * in this monotonic increasing list 2279250003Sadrian */ 2280250003Sadrian break; 2281250003Sadrian } 2282250003Sadrian } 2283250003Sadrian /* 2284250003Sadrian * EV89475: EEPROM might contain 0 txpower in CTL table for certain 2285250003Sadrian * 2.4GHz channels. We workaround it by overwriting 60 (30 dBm) here. 2286250003Sadrian */ 2287250003Sadrian if (is_2ghz && (twice_max_edge_power == 0)) { 2288250003Sadrian twice_max_edge_power = 60; 2289250003Sadrian } 2290250003Sadrian 2291250003Sadrian HALASSERT(twice_max_edge_power > 0); 2292250003Sadrian return twice_max_edge_power; 2293250003Sadrian} 2294250003Sadrian 2295250003SadrianHAL_BOOL 2296250003Sadrianar9300_eeprom_set_power_per_rate_table( 2297250003Sadrian struct ath_hal *ah, 2298250003Sadrian ar9300_eeprom_t *p_eep_data, 2299250008Sadrian const struct ieee80211_channel *chan, 2300250003Sadrian u_int8_t *p_pwr_array, 2301250003Sadrian u_int16_t cfg_ctl, 2302250003Sadrian u_int16_t antenna_reduction, 2303250003Sadrian u_int16_t twice_max_regulatory_power, 2304250003Sadrian u_int16_t power_limit, 2305250003Sadrian u_int8_t chainmask) 2306250003Sadrian{ 2307250003Sadrian /* Local defines to distinguish between extension and control CTL's */ 2308250003Sadrian#define EXT_ADDITIVE (0x8000) 2309250003Sadrian#define CTL_11A_EXT (CTL_11A | EXT_ADDITIVE) 2310250003Sadrian#define CTL_11G_EXT (CTL_11G | EXT_ADDITIVE) 2311250003Sadrian#define CTL_11B_EXT (CTL_11B | EXT_ADDITIVE) 2312250003Sadrian#define REDUCE_SCALED_POWER_BY_TWO_CHAIN 6 /* 10*log10(2)*2 */ 2313250003Sadrian#define REDUCE_SCALED_POWER_BY_THREE_CHAIN 10 /* 10*log10(3)*2 */ 2314250003Sadrian#define PWRINCR_3_TO_1_CHAIN 9 /* 10*log(3)*2 */ 2315250003Sadrian#define PWRINCR_3_TO_2_CHAIN 3 /* floor(10*log(3/2)*2) */ 2316250003Sadrian#define PWRINCR_2_TO_1_CHAIN 6 /* 10*log(2)*2 */ 2317250003Sadrian 2318250003Sadrian static const u_int16_t tp_scale_reduction_table[5] = 2319250003Sadrian { 0, 3, 6, 9, AR9300_MAX_RATE_POWER }; 2320250003Sadrian int i; 2321250003Sadrian int16_t twice_largest_antenna; 2322250003Sadrian u_int16_t twice_antenna_reduction = 2*antenna_reduction ; 2323250003Sadrian int16_t scaled_power = 0, min_ctl_power, max_reg_allowed_power; 2324250003Sadrian#define SUB_NUM_CTL_MODES_AT_5G_40 2 /* excluding HT40, EXT-OFDM */ 2325250003Sadrian#define SUB_NUM_CTL_MODES_AT_2G_40 3 /* excluding HT40, EXT-OFDM, EXT-CCK */ 2326250003Sadrian u_int16_t ctl_modes_for11a[] = 2327250003Sadrian {CTL_11A, CTL_5GHT20, CTL_11A_EXT, CTL_5GHT40}; 2328250003Sadrian u_int16_t ctl_modes_for11g[] = 2329250003Sadrian {CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT, CTL_2GHT40}; 2330250003Sadrian u_int16_t num_ctl_modes, *p_ctl_mode, ctl_mode, freq; 2331250003Sadrian CHAN_CENTERS centers; 2332250003Sadrian int tx_chainmask; 2333250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 2334250003Sadrian u_int8_t *ctl_index; 2335250003Sadrian u_int8_t ctl_num; 2336250003Sadrian u_int16_t twice_min_edge_power; 2337250003Sadrian u_int16_t twice_max_edge_power = AR9300_MAX_RATE_POWER; 2338250008Sadrian#ifdef AH_DEBUG 2339250008Sadrian HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan); 2340250008Sadrian#endif 2341250003Sadrian 2342250003Sadrian tx_chainmask = chainmask ? chainmask : ahp->ah_tx_chainmask; 2343250003Sadrian 2344250003Sadrian ar9300_get_channel_centers(ah, chan, ¢ers); 2345250003Sadrian 2346250008Sadrian if (IEEE80211_IS_CHAN_2GHZ(chan)) { 2347250003Sadrian ahp->twice_antenna_gain = p_eep_data->modal_header_2g.antenna_gain; 2348250003Sadrian } else { 2349250003Sadrian ahp->twice_antenna_gain = p_eep_data->modal_header_5g.antenna_gain; 2350250003Sadrian } 2351250003Sadrian 2352250003Sadrian /* Save max allowed antenna gain to ease future lookups */ 2353250003Sadrian ahp->twice_antenna_reduction = twice_antenna_reduction; 2354250003Sadrian 2355250003Sadrian /* Deduct antenna gain from EIRP to get the upper limit */ 2356250003Sadrian twice_largest_antenna = (int16_t)AH_MIN((twice_antenna_reduction - 2357250003Sadrian ahp->twice_antenna_gain), 0); 2358250003Sadrian max_reg_allowed_power = twice_max_regulatory_power + twice_largest_antenna; 2359250003Sadrian 2360250003Sadrian /* Use ah_tp_scale - see bug 30070. */ 2361250008Sadrian if (AH_PRIVATE(ah)->ah_tpScale != HAL_TP_SCALE_MAX) { 2362250003Sadrian max_reg_allowed_power -= 2363250008Sadrian (tp_scale_reduction_table[(AH_PRIVATE(ah)->ah_tpScale)] * 2); 2364250003Sadrian } 2365250003Sadrian 2366250003Sadrian scaled_power = AH_MIN(power_limit, max_reg_allowed_power); 2367250003Sadrian 2368250003Sadrian /* 2369250003Sadrian * Reduce scaled Power by number of chains active to get to 2370250003Sadrian * per chain tx power level 2371250003Sadrian */ 2372250003Sadrian /* TODO: better value than these? */ 2373250003Sadrian switch (ar9300_get_ntxchains(tx_chainmask)) { 2374250003Sadrian case 1: 2375250003Sadrian ahp->upper_limit[0] = AH_MAX(0, scaled_power); 2376250003Sadrian break; 2377250003Sadrian case 2: 2378250003Sadrian scaled_power -= REDUCE_SCALED_POWER_BY_TWO_CHAIN; 2379250003Sadrian ahp->upper_limit[1] = AH_MAX(0, scaled_power); 2380250003Sadrian break; 2381250003Sadrian case 3: 2382250003Sadrian scaled_power -= REDUCE_SCALED_POWER_BY_THREE_CHAIN; 2383250003Sadrian ahp->upper_limit[2] = AH_MAX(0, scaled_power); 2384250003Sadrian break; 2385250003Sadrian default: 2386250003Sadrian HALASSERT(0); /* Unsupported number of chains */ 2387250003Sadrian } 2388250003Sadrian 2389250003Sadrian scaled_power = AH_MAX(0, scaled_power); 2390250003Sadrian 2391250003Sadrian /* Get target powers from EEPROM - our baseline for TX Power */ 2392250008Sadrian if (IEEE80211_IS_CHAN_2GHZ(chan)) { 2393250003Sadrian /* Setup for CTL modes */ 2394250003Sadrian /* CTL_11B, CTL_11G, CTL_2GHT20 */ 2395250003Sadrian num_ctl_modes = 2396250003Sadrian ARRAY_LENGTH(ctl_modes_for11g) - SUB_NUM_CTL_MODES_AT_2G_40; 2397250003Sadrian p_ctl_mode = ctl_modes_for11g; 2398250003Sadrian 2399250008Sadrian if (IEEE80211_IS_CHAN_HT40(chan)) { 2400250003Sadrian num_ctl_modes = ARRAY_LENGTH(ctl_modes_for11g); /* All 2G CTL's */ 2401250003Sadrian } 2402250003Sadrian } else { 2403250003Sadrian /* Setup for CTL modes */ 2404250003Sadrian /* CTL_11A, CTL_5GHT20 */ 2405250003Sadrian num_ctl_modes = 2406250003Sadrian ARRAY_LENGTH(ctl_modes_for11a) - SUB_NUM_CTL_MODES_AT_5G_40; 2407250003Sadrian p_ctl_mode = ctl_modes_for11a; 2408250003Sadrian 2409250008Sadrian if (IEEE80211_IS_CHAN_HT40(chan)) { 2410250003Sadrian num_ctl_modes = ARRAY_LENGTH(ctl_modes_for11a); /* All 5G CTL's */ 2411250003Sadrian } 2412250003Sadrian } 2413250003Sadrian 2414250003Sadrian /* 2415250003Sadrian * For MIMO, need to apply regulatory caps individually across dynamically 2416250003Sadrian * running modes: CCK, OFDM, HT20, HT40 2417250003Sadrian * 2418250003Sadrian * The outer loop walks through each possible applicable runtime mode. 2419250003Sadrian * The inner loop walks through each ctl_index entry in EEPROM. 2420250003Sadrian * The ctl value is encoded as [7:4] == test group, [3:0] == test mode. 2421250003Sadrian * 2422250003Sadrian */ 2423250003Sadrian for (ctl_mode = 0; ctl_mode < num_ctl_modes; ctl_mode++) { 2424250003Sadrian HAL_BOOL is_ht40_ctl_mode = 2425250003Sadrian (p_ctl_mode[ctl_mode] == CTL_5GHT40) || 2426250003Sadrian (p_ctl_mode[ctl_mode] == CTL_2GHT40); 2427250003Sadrian if (is_ht40_ctl_mode) { 2428250003Sadrian freq = centers.synth_center; 2429250003Sadrian } else if (p_ctl_mode[ctl_mode] & EXT_ADDITIVE) { 2430250003Sadrian freq = centers.ext_center; 2431250003Sadrian } else { 2432250003Sadrian freq = centers.ctl_center; 2433250003Sadrian } 2434250003Sadrian 2435250003Sadrian HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, 2436250003Sadrian "LOOP-Mode ctl_mode %d < %d, " 2437250003Sadrian "is_ht40_ctl_mode %d, EXT_ADDITIVE %d\n", 2438250003Sadrian ctl_mode, num_ctl_modes, is_ht40_ctl_mode, 2439250003Sadrian (p_ctl_mode[ctl_mode] & EXT_ADDITIVE)); 2440250003Sadrian /* walk through each CTL index stored in EEPROM */ 2441250008Sadrian if (IEEE80211_IS_CHAN_2GHZ(chan)) { 2442250003Sadrian ctl_index = p_eep_data->ctl_index_2g; 2443250003Sadrian ctl_num = OSPREY_NUM_CTLS_2G; 2444250003Sadrian } else { 2445250003Sadrian ctl_index = p_eep_data->ctl_index_5g; 2446250003Sadrian ctl_num = OSPREY_NUM_CTLS_5G; 2447250003Sadrian } 2448250003Sadrian 2449250003Sadrian for (i = 0; (i < ctl_num) && ctl_index[i]; i++) { 2450250003Sadrian HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, 2451250003Sadrian " LOOP-Ctlidx %d: cfg_ctl 0x%2.2x p_ctl_mode 0x%2.2x " 2452250003Sadrian "ctl_index 0x%2.2x chan %d chanctl 0x%x\n", 2453250003Sadrian i, cfg_ctl, p_ctl_mode[ctl_mode], ctl_index[i], 2454250008Sadrian ichan->channel, ath_hal_getctl(ah, chan)); 2455250003Sadrian 2456250008Sadrian 2457250003Sadrian /* 2458250003Sadrian * compare test group from regulatory channel list 2459250003Sadrian * with test mode from p_ctl_mode list 2460250003Sadrian */ 2461250003Sadrian if ((((cfg_ctl & ~CTL_MODE_M) | 2462250003Sadrian (p_ctl_mode[ctl_mode] & CTL_MODE_M)) == ctl_index[i]) || 2463250003Sadrian (((cfg_ctl & ~CTL_MODE_M) | 2464250003Sadrian (p_ctl_mode[ctl_mode] & CTL_MODE_M)) == 2465250003Sadrian ((ctl_index[i] & CTL_MODE_M) | SD_NO_CTL))) 2466250003Sadrian { 2467250003Sadrian twice_min_edge_power = 2468250003Sadrian ar9300_eep_def_get_max_edge_power( 2469250008Sadrian p_eep_data, freq, i, IEEE80211_IS_CHAN_2GHZ(chan)); 2470250003Sadrian 2471250003Sadrian HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, 2472250003Sadrian " MATCH-EE_IDX %d: ch %d is2 %d " 2473250003Sadrian "2xMinEdge %d chainmask %d chains %d\n", 2474250008Sadrian i, freq, IEEE80211_IS_CHAN_2GHZ(chan), 2475250003Sadrian twice_min_edge_power, tx_chainmask, 2476250003Sadrian ar9300_get_ntxchains(tx_chainmask)); 2477250003Sadrian 2478250003Sadrian if ((cfg_ctl & ~CTL_MODE_M) == SD_NO_CTL) { 2479250003Sadrian /* 2480250003Sadrian * Find the minimum of all CTL edge powers 2481250003Sadrian * that apply to this channel 2482250003Sadrian */ 2483250003Sadrian twice_max_edge_power = 2484250003Sadrian AH_MIN(twice_max_edge_power, twice_min_edge_power); 2485250003Sadrian } else { 2486250003Sadrian /* specific */ 2487250003Sadrian twice_max_edge_power = twice_min_edge_power; 2488250003Sadrian break; 2489250003Sadrian } 2490250003Sadrian } 2491250003Sadrian } 2492250003Sadrian 2493250003Sadrian min_ctl_power = (u_int8_t)AH_MIN(twice_max_edge_power, scaled_power); 2494250003Sadrian 2495250003Sadrian HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, 2496250003Sadrian " SEL-Min ctl_mode %d p_ctl_mode %d " 2497250003Sadrian "2xMaxEdge %d sP %d min_ctl_pwr %d\n", 2498250003Sadrian ctl_mode, p_ctl_mode[ctl_mode], 2499250003Sadrian twice_max_edge_power, scaled_power, min_ctl_power); 2500250003Sadrian 2501250003Sadrian /* Apply ctl mode to correct target power set */ 2502250003Sadrian switch (p_ctl_mode[ctl_mode]) { 2503250003Sadrian case CTL_11B: 2504250003Sadrian for (i = ALL_TARGET_LEGACY_1L_5L; i <= ALL_TARGET_LEGACY_11S; i++) { 2505250003Sadrian p_pwr_array[i] = 2506250003Sadrian (u_int8_t)AH_MIN(p_pwr_array[i], min_ctl_power); 2507250003Sadrian } 2508250003Sadrian break; 2509250003Sadrian case CTL_11A: 2510250003Sadrian case CTL_11G: 2511250003Sadrian for (i = ALL_TARGET_LEGACY_6_24; i <= ALL_TARGET_LEGACY_54; i++) { 2512250003Sadrian p_pwr_array[i] = 2513250003Sadrian (u_int8_t)AH_MIN(p_pwr_array[i], min_ctl_power); 2514250003Sadrian#ifdef ATH_BT_COEX 2515250003Sadrian if ((ahp->ah_bt_coex_config_type == HAL_BT_COEX_CFG_3WIRE) || 2516250003Sadrian (ahp->ah_bt_coex_config_type == HAL_BT_COEX_CFG_MCI)) 2517250003Sadrian { 2518250003Sadrian if ((ahp->ah_bt_coex_flag & HAL_BT_COEX_FLAG_LOWER_TX_PWR) 2519250003Sadrian && (ahp->ah_bt_wlan_isolation 2520250003Sadrian < HAL_BT_COEX_ISOLATION_FOR_NO_COEX)) 2521250003Sadrian { 2522250003Sadrian 2523250003Sadrian u_int8_t reduce_pow; 2524250003Sadrian 2525250003Sadrian reduce_pow = (HAL_BT_COEX_ISOLATION_FOR_NO_COEX 2526250003Sadrian - ahp->ah_bt_wlan_isolation) << 1; 2527250003Sadrian 2528250003Sadrian if (reduce_pow <= p_pwr_array[i]) { 2529250003Sadrian p_pwr_array[i] -= reduce_pow; 2530250003Sadrian } 2531250003Sadrian } 2532250003Sadrian if ((ahp->ah_bt_coex_flag & 2533250003Sadrian HAL_BT_COEX_FLAG_LOW_ACK_PWR) && 2534250003Sadrian (i != ALL_TARGET_LEGACY_36) && 2535250003Sadrian (i != ALL_TARGET_LEGACY_48) && 2536250003Sadrian (i != ALL_TARGET_LEGACY_54) && 2537250003Sadrian (p_ctl_mode[ctl_mode] == CTL_11G)) 2538250003Sadrian { 2539250003Sadrian p_pwr_array[i] = 0; 2540250003Sadrian } 2541250003Sadrian } 2542250003Sadrian#endif 2543250003Sadrian } 2544250003Sadrian break; 2545250003Sadrian case CTL_5GHT20: 2546250003Sadrian case CTL_2GHT20: 2547250003Sadrian for (i = ALL_TARGET_HT20_0_8_16; i <= ALL_TARGET_HT20_23; i++) { 2548250003Sadrian p_pwr_array[i] = 2549250003Sadrian (u_int8_t)AH_MIN(p_pwr_array[i], min_ctl_power); 2550250003Sadrian#ifdef ATH_BT_COEX 2551250003Sadrian if (((ahp->ah_bt_coex_config_type == HAL_BT_COEX_CFG_3WIRE) || 2552250003Sadrian (ahp->ah_bt_coex_config_type == HAL_BT_COEX_CFG_MCI)) && 2553250003Sadrian (ahp->ah_bt_coex_flag & HAL_BT_COEX_FLAG_LOWER_TX_PWR) && 2554250003Sadrian (ahp->ah_bt_wlan_isolation 2555250003Sadrian < HAL_BT_COEX_ISOLATION_FOR_NO_COEX)) { 2556250003Sadrian 2557250003Sadrian u_int8_t reduce_pow = (HAL_BT_COEX_ISOLATION_FOR_NO_COEX 2558250003Sadrian - ahp->ah_bt_wlan_isolation) << 1; 2559250003Sadrian 2560250003Sadrian if (reduce_pow <= p_pwr_array[i]) { 2561250003Sadrian p_pwr_array[i] -= reduce_pow; 2562250003Sadrian } 2563250003Sadrian } 2564250003Sadrian#if ATH_SUPPORT_MCI 2565250003Sadrian else if ((ahp->ah_bt_coex_flag & 2566250003Sadrian HAL_BT_COEX_FLAG_MCI_MAX_TX_PWR) && 2567250003Sadrian (p_ctl_mode[ctl_mode] == CTL_2GHT20) && 2568250003Sadrian (ahp->ah_bt_coex_config_type == HAL_BT_COEX_CFG_MCI)) 2569250003Sadrian { 2570250003Sadrian u_int8_t max_pwr; 2571250003Sadrian 2572250003Sadrian max_pwr = MS(mci_concur_tx_max_pwr[2][1], 2573250003Sadrian ATH_MCI_CONCUR_TX_LOWEST_PWR_MASK); 2574250003Sadrian if (p_pwr_array[i] > max_pwr) { 2575250003Sadrian p_pwr_array[i] = max_pwr; 2576250003Sadrian } 2577250003Sadrian } 2578250003Sadrian#endif 2579250003Sadrian#endif 2580250003Sadrian } 2581250003Sadrian break; 2582250003Sadrian case CTL_11B_EXT: 2583250003Sadrian#ifdef NOT_YET 2584250003Sadrian target_power_cck_ext.t_pow2x[0] = (u_int8_t) 2585250003Sadrian AH_MIN(target_power_cck_ext.t_pow2x[0], min_ctl_power); 2586250003Sadrian#endif /* NOT_YET */ 2587250003Sadrian break; 2588250003Sadrian case CTL_11A_EXT: 2589250003Sadrian case CTL_11G_EXT: 2590250003Sadrian#ifdef NOT_YET 2591250003Sadrian target_power_ofdm_ext.t_pow2x[0] = (u_int8_t) 2592250003Sadrian AH_MIN(target_power_ofdm_ext.t_pow2x[0], min_ctl_power); 2593250003Sadrian#endif /* NOT_YET */ 2594250003Sadrian break; 2595250003Sadrian case CTL_5GHT40: 2596250003Sadrian case CTL_2GHT40: 2597250003Sadrian for (i = ALL_TARGET_HT40_0_8_16; i <= ALL_TARGET_HT40_23; i++) { 2598250003Sadrian p_pwr_array[i] = (u_int8_t) 2599250003Sadrian AH_MIN(p_pwr_array[i], min_ctl_power); 2600250003Sadrian#ifdef ATH_BT_COEX 2601250003Sadrian if (((ahp->ah_bt_coex_config_type == HAL_BT_COEX_CFG_3WIRE) || 2602250003Sadrian (ahp->ah_bt_coex_config_type == HAL_BT_COEX_CFG_MCI)) && 2603250003Sadrian (ahp->ah_bt_coex_flag & HAL_BT_COEX_FLAG_LOWER_TX_PWR) && 2604250003Sadrian (ahp->ah_bt_wlan_isolation 2605250003Sadrian < HAL_BT_COEX_ISOLATION_FOR_NO_COEX)) { 2606250003Sadrian 2607250003Sadrian u_int8_t reduce_pow = (HAL_BT_COEX_ISOLATION_FOR_NO_COEX 2608250003Sadrian - ahp->ah_bt_wlan_isolation) << 1; 2609250003Sadrian 2610250003Sadrian if (reduce_pow <= p_pwr_array[i]) { 2611250003Sadrian p_pwr_array[i] -= reduce_pow; 2612250003Sadrian } 2613250003Sadrian } 2614250003Sadrian#if ATH_SUPPORT_MCI 2615250003Sadrian else if ((ahp->ah_bt_coex_flag & 2616250003Sadrian HAL_BT_COEX_FLAG_MCI_MAX_TX_PWR) && 2617250003Sadrian (p_ctl_mode[ctl_mode] == CTL_2GHT40) && 2618250003Sadrian (ahp->ah_bt_coex_config_type == HAL_BT_COEX_CFG_MCI)) 2619250003Sadrian { 2620250003Sadrian u_int8_t max_pwr; 2621250003Sadrian 2622250003Sadrian max_pwr = MS(mci_concur_tx_max_pwr[3][1], 2623250003Sadrian ATH_MCI_CONCUR_TX_LOWEST_PWR_MASK); 2624250003Sadrian if (p_pwr_array[i] > max_pwr) { 2625250003Sadrian p_pwr_array[i] = max_pwr; 2626250003Sadrian } 2627250003Sadrian } 2628250003Sadrian#endif 2629250003Sadrian#endif 2630250003Sadrian } 2631250003Sadrian break; 2632250003Sadrian default: 2633250003Sadrian HALASSERT(0); 2634250003Sadrian break; 2635250003Sadrian } 2636250003Sadrian } /* end ctl mode checking */ 2637250003Sadrian 2638250003Sadrian return AH_TRUE; 2639250003Sadrian#undef EXT_ADDITIVE 2640250003Sadrian#undef CTL_11A_EXT 2641250003Sadrian#undef CTL_11G_EXT 2642250003Sadrian#undef CTL_11B_EXT 2643250003Sadrian#undef REDUCE_SCALED_POWER_BY_TWO_CHAIN 2644250003Sadrian#undef REDUCE_SCALED_POWER_BY_THREE_CHAIN 2645250003Sadrian} 2646250003Sadrian 2647250003Sadrian/************************************************************** 2648250003Sadrian * ar9300_eeprom_set_transmit_power 2649250003Sadrian * 2650250003Sadrian * Set the transmit power in the baseband for the given 2651250003Sadrian * operating channel and mode. 2652250003Sadrian */ 2653250003SadrianHAL_STATUS 2654250003Sadrianar9300_eeprom_set_transmit_power(struct ath_hal *ah, 2655250008Sadrian ar9300_eeprom_t *p_eep_data, const struct ieee80211_channel *chan, u_int16_t cfg_ctl, 2656250003Sadrian u_int16_t antenna_reduction, u_int16_t twice_max_regulatory_power, 2657250003Sadrian u_int16_t power_limit) 2658250003Sadrian{ 2659250003Sadrian#define ABS(_x, _y) ((int)_x > (int)_y ? (int)_x - (int)_y : (int)_y - (int)_x) 2660250003Sadrian#define INCREASE_MAXPOW_BY_TWO_CHAIN 6 /* 10*log10(2)*2 */ 2661250003Sadrian#define INCREASE_MAXPOW_BY_THREE_CHAIN 10 /* 10*log10(3)*2 */ 2662250003Sadrian u_int8_t target_power_val_t2[ar9300_rate_size]; 2663250003Sadrian u_int8_t target_power_val_t2_eep[ar9300_rate_size]; 2664250003Sadrian int16_t twice_array_gain = 0, max_power_level = 0; 2665250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 2666250003Sadrian int i = 0; 2667250003Sadrian u_int32_t tmp_paprd_rate_mask = 0, *tmp_ptr = NULL; 2668250003Sadrian int paprd_scale_factor = 5; 2669250008Sadrian HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan); 2670250003Sadrian 2671250003Sadrian u_int8_t *ptr_mcs_rate2power_table_index; 2672250003Sadrian u_int8_t mcs_rate2power_table_index_ht20[24] = 2673250003Sadrian { 2674250003Sadrian ALL_TARGET_HT20_0_8_16, 2675250003Sadrian ALL_TARGET_HT20_1_3_9_11_17_19, 2676250003Sadrian ALL_TARGET_HT20_1_3_9_11_17_19, 2677250003Sadrian ALL_TARGET_HT20_1_3_9_11_17_19, 2678250003Sadrian ALL_TARGET_HT20_4, 2679250003Sadrian ALL_TARGET_HT20_5, 2680250003Sadrian ALL_TARGET_HT20_6, 2681250003Sadrian ALL_TARGET_HT20_7, 2682250003Sadrian ALL_TARGET_HT20_0_8_16, 2683250003Sadrian ALL_TARGET_HT20_1_3_9_11_17_19, 2684250003Sadrian ALL_TARGET_HT20_1_3_9_11_17_19, 2685250003Sadrian ALL_TARGET_HT20_1_3_9_11_17_19, 2686250003Sadrian ALL_TARGET_HT20_12, 2687250003Sadrian ALL_TARGET_HT20_13, 2688250003Sadrian ALL_TARGET_HT20_14, 2689250003Sadrian ALL_TARGET_HT20_15, 2690250003Sadrian ALL_TARGET_HT20_0_8_16, 2691250003Sadrian ALL_TARGET_HT20_1_3_9_11_17_19, 2692250003Sadrian ALL_TARGET_HT20_1_3_9_11_17_19, 2693250003Sadrian ALL_TARGET_HT20_1_3_9_11_17_19, 2694250003Sadrian ALL_TARGET_HT20_20, 2695250003Sadrian ALL_TARGET_HT20_21, 2696250003Sadrian ALL_TARGET_HT20_22, 2697250003Sadrian ALL_TARGET_HT20_23 2698250003Sadrian }; 2699250003Sadrian 2700250003Sadrian u_int8_t mcs_rate2power_table_index_ht40[24] = 2701250003Sadrian { 2702250003Sadrian ALL_TARGET_HT40_0_8_16, 2703250003Sadrian ALL_TARGET_HT40_1_3_9_11_17_19, 2704250003Sadrian ALL_TARGET_HT40_1_3_9_11_17_19, 2705250003Sadrian ALL_TARGET_HT40_1_3_9_11_17_19, 2706250003Sadrian ALL_TARGET_HT40_4, 2707250003Sadrian ALL_TARGET_HT40_5, 2708250003Sadrian ALL_TARGET_HT40_6, 2709250003Sadrian ALL_TARGET_HT40_7, 2710250003Sadrian ALL_TARGET_HT40_0_8_16, 2711250003Sadrian ALL_TARGET_HT40_1_3_9_11_17_19, 2712250003Sadrian ALL_TARGET_HT40_1_3_9_11_17_19, 2713250003Sadrian ALL_TARGET_HT40_1_3_9_11_17_19, 2714250003Sadrian ALL_TARGET_HT40_12, 2715250003Sadrian ALL_TARGET_HT40_13, 2716250003Sadrian ALL_TARGET_HT40_14, 2717250003Sadrian ALL_TARGET_HT40_15, 2718250003Sadrian ALL_TARGET_HT40_0_8_16, 2719250003Sadrian ALL_TARGET_HT40_1_3_9_11_17_19, 2720250003Sadrian ALL_TARGET_HT40_1_3_9_11_17_19, 2721250003Sadrian ALL_TARGET_HT40_1_3_9_11_17_19, 2722250003Sadrian ALL_TARGET_HT40_20, 2723250003Sadrian ALL_TARGET_HT40_21, 2724250003Sadrian ALL_TARGET_HT40_22, 2725250003Sadrian ALL_TARGET_HT40_23, 2726250003Sadrian }; 2727250003Sadrian 2728250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 2729250003Sadrian "%s[%d] +++chan %d,cfgctl 0x%04x " 2730250003Sadrian "antenna_reduction 0x%04x, twice_max_regulatory_power 0x%04x " 2731250003Sadrian "power_limit 0x%04x\n", 2732250008Sadrian __func__, __LINE__, ichan->channel, cfg_ctl, 2733250003Sadrian antenna_reduction, twice_max_regulatory_power, power_limit); 2734250008Sadrian ar9300_set_target_power_from_eeprom(ah, ichan->channel, target_power_val_t2); 2735250003Sadrian 2736250003Sadrian if (ar9300_eeprom_get(ahp, EEP_PAPRD_ENABLED)) { 2737250008Sadrian if (IEEE80211_IS_CHAN_2GHZ(chan)) { 2738250008Sadrian if (IEEE80211_IS_CHAN_HT40(chan)) { 2739250003Sadrian tmp_paprd_rate_mask = 2740250003Sadrian p_eep_data->modal_header_2g.paprd_rate_mask_ht40; 2741250003Sadrian tmp_ptr = &AH9300(ah)->ah_2g_paprd_rate_mask_ht40; 2742250003Sadrian } else { 2743250003Sadrian tmp_paprd_rate_mask = 2744250003Sadrian p_eep_data->modal_header_2g.paprd_rate_mask_ht20; 2745250003Sadrian tmp_ptr = &AH9300(ah)->ah_2g_paprd_rate_mask_ht20; 2746250003Sadrian } 2747250003Sadrian } else { 2748250008Sadrian if (IEEE80211_IS_CHAN_HT40(chan)) { 2749250003Sadrian tmp_paprd_rate_mask = 2750250003Sadrian p_eep_data->modal_header_5g.paprd_rate_mask_ht40; 2751250003Sadrian tmp_ptr = &AH9300(ah)->ah_5g_paprd_rate_mask_ht40; 2752250003Sadrian } else { 2753250003Sadrian tmp_paprd_rate_mask = 2754250003Sadrian p_eep_data->modal_header_5g.paprd_rate_mask_ht20; 2755250003Sadrian tmp_ptr = &AH9300(ah)->ah_5g_paprd_rate_mask_ht20; 2756250003Sadrian } 2757250003Sadrian } 2758250003Sadrian AH_PAPRD_GET_SCALE_FACTOR( 2759250008Sadrian paprd_scale_factor, p_eep_data, IEEE80211_IS_CHAN_2GHZ(chan), ichan->channel); 2760250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s[%d] paprd_scale_factor %d\n", 2761250003Sadrian __func__, __LINE__, paprd_scale_factor); 2762250003Sadrian /* PAPRD is not done yet, Scale down the EEP power */ 2763250008Sadrian if (IEEE80211_IS_CHAN_HT40(chan)) { 2764250003Sadrian ptr_mcs_rate2power_table_index = 2765250003Sadrian &mcs_rate2power_table_index_ht40[0]; 2766250003Sadrian } else { 2767250003Sadrian ptr_mcs_rate2power_table_index = 2768250003Sadrian &mcs_rate2power_table_index_ht20[0]; 2769250003Sadrian } 2770250008Sadrian if (! ichan->paprd_table_write_done) { 2771250003Sadrian for (i = 0; i < 24; i++) { 2772250003Sadrian /* PAPRD is done yet, so Scale down Power for PAPRD Rates*/ 2773250003Sadrian if (tmp_paprd_rate_mask & (1 << i)) { 2774250003Sadrian target_power_val_t2[ptr_mcs_rate2power_table_index[i]] -= 2775250003Sadrian paprd_scale_factor; 2776250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 2777250003Sadrian "%s[%d]: Chan %d " 2778250003Sadrian "Scale down target_power_val_t2[%d] = 0x%04x\n", 2779250003Sadrian __func__, __LINE__, 2780250008Sadrian ichan->channel, i, target_power_val_t2[i]); 2781250003Sadrian } 2782250003Sadrian } 2783250003Sadrian } else { 2784250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 2785250003Sadrian "%s[%d]: PAPRD Done No TGT PWR Scaling\n", __func__, __LINE__); 2786250003Sadrian } 2787250003Sadrian } 2788250003Sadrian 2789250003Sadrian /* Save the Target power for future use */ 2790250003Sadrian OS_MEMCPY(target_power_val_t2_eep, target_power_val_t2, 2791250003Sadrian sizeof(target_power_val_t2)); 2792250003Sadrian ar9300_eeprom_set_power_per_rate_table(ah, p_eep_data, chan, 2793250003Sadrian target_power_val_t2, cfg_ctl, 2794250003Sadrian antenna_reduction, 2795250003Sadrian twice_max_regulatory_power, 2796250003Sadrian power_limit, 0); 2797250003Sadrian 2798250003Sadrian /* Save this for quick lookup */ 2799250008Sadrian ahp->reg_dmn = ath_hal_getctl(ah, chan); 2800250003Sadrian 2801250003Sadrian /* 2802250003Sadrian * Always use CDD/direct per rate power table for register based approach. 2803250003Sadrian * For FCC, CDD calculations should factor in the array gain, hence 2804250003Sadrian * this adjust call. ETSI and MKK does not have this requirement. 2805250003Sadrian */ 2806250003Sadrian if (is_reg_dmn_fcc(ahp->reg_dmn)) { 2807250008Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 2808250008Sadrian "%s: FCC regdomain, calling reg_txpower_cdd\n", 2809250008Sadrian __func__); 2810250003Sadrian ar9300_adjust_reg_txpower_cdd(ah, target_power_val_t2); 2811250003Sadrian } 2812250003Sadrian 2813250003Sadrian if (ar9300_eeprom_get(ahp, EEP_PAPRD_ENABLED)) { 2814250003Sadrian for (i = 0; i < ar9300_rate_size; i++) { 2815250003Sadrian /* 2816250003Sadrian * EEPROM TGT PWR is not same as current TGT PWR, 2817250003Sadrian * so Disable PAPRD for this rate. 2818250003Sadrian * Some of APs might ask to reduce Target Power, 2819250003Sadrian * if target power drops significantly, 2820250003Sadrian * disable PAPRD for that rate. 2821250003Sadrian */ 2822250003Sadrian if (tmp_paprd_rate_mask & (1 << i)) { 2823250003Sadrian if (ABS(target_power_val_t2_eep[i], target_power_val_t2[i]) > 2824250003Sadrian paprd_scale_factor) 2825250003Sadrian { 2826250003Sadrian tmp_paprd_rate_mask &= ~(1 << i); 2827250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 2828250003Sadrian "%s: EEP TPC[%02d] 0x%08x " 2829250003Sadrian "Curr TPC[%02d] 0x%08x mask = 0x%08x\n", 2830250003Sadrian __func__, i, target_power_val_t2_eep[i], i, 2831250003Sadrian target_power_val_t2[i], tmp_paprd_rate_mask); 2832250003Sadrian } 2833250003Sadrian } 2834250003Sadrian 2835250003Sadrian } 2836250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 2837250003Sadrian "%s: Chan %d After tmp_paprd_rate_mask = 0x%08x\n", 2838250008Sadrian __func__, ichan->channel, tmp_paprd_rate_mask); 2839250003Sadrian if (tmp_ptr) { 2840250003Sadrian *tmp_ptr = tmp_paprd_rate_mask; 2841250003Sadrian } 2842250003Sadrian } 2843250003Sadrian 2844250003Sadrian /* Write target power array to registers */ 2845250003Sadrian ar9300_transmit_power_reg_write(ah, target_power_val_t2); 2846250003Sadrian 2847250003Sadrian /* Write target power for self generated frames to the TPC register */ 2848250003Sadrian ar9300_selfgen_tpc_reg_write(ah, chan, target_power_val_t2); 2849250003Sadrian 2850250003Sadrian /* GreenTx or Paprd */ 2851250008Sadrian if (ah->ah_config.ath_hal_sta_update_tx_pwr_enable || 2852250008Sadrian AH_PRIVATE(ah)->ah_caps.halPaprdEnabled) 2853250003Sadrian { 2854250003Sadrian if (AR_SREV_POSEIDON(ah)) { 2855250003Sadrian /*For HAL_RSSI_TX_POWER_NONE array*/ 2856250003Sadrian OS_MEMCPY(ahp->ah_default_tx_power, 2857250003Sadrian target_power_val_t2, 2858250003Sadrian sizeof(target_power_val_t2)); 2859250003Sadrian /* Get defautl tx related register setting for GreenTx */ 2860250003Sadrian /* Record OB/DB */ 2861250008Sadrian ahp->ah_ob_db1[POSEIDON_STORED_REG_OBDB] = 2862250003Sadrian OS_REG_READ(ah, AR_PHY_65NM_CH0_TXRF2); 2863250003Sadrian /* Record TPC settting */ 2864250008Sadrian ahp->ah_ob_db1[POSEIDON_STORED_REG_TPC] = 2865250003Sadrian OS_REG_READ(ah, AR_TPC); 2866250003Sadrian /* Record BB_powertx_rate9 setting */ 2867250008Sadrian ahp->ah_ob_db1[POSEIDON_STORED_REG_BB_PWRTX_RATE9] = 2868250003Sadrian OS_REG_READ(ah, AR_PHY_BB_POWERTX_RATE9); 2869250003Sadrian } 2870250003Sadrian } 2871250003Sadrian 2872250003Sadrian /* 2873250003Sadrian * Return tx power used to iwconfig. 2874250003Sadrian * Since power is rate dependent, use one of the indices from the 2875250003Sadrian * AR9300_Rates enum to select an entry from target_power_val_t2[] 2876250003Sadrian * to report. 2877250003Sadrian * Currently returns the power for HT40 MCS 0, HT20 MCS 0, or OFDM 6 Mbps 2878250003Sadrian * as CCK power is less interesting (?). 2879250003Sadrian */ 2880250003Sadrian i = ALL_TARGET_LEGACY_6_24; /* legacy */ 2881250008Sadrian if (IEEE80211_IS_CHAN_HT40(chan)) { 2882250003Sadrian i = ALL_TARGET_HT40_0_8_16; /* ht40 */ 2883250008Sadrian } else if (IEEE80211_IS_CHAN_HT20(chan)) { 2884250003Sadrian i = ALL_TARGET_HT20_0_8_16; /* ht20 */ 2885250003Sadrian } 2886250003Sadrian max_power_level = target_power_val_t2[i]; 2887250003Sadrian /* Adjusting the ah_max_power_level based on chains and antennaGain*/ 2888250003Sadrian switch (ar9300_get_ntxchains(ahp->ah_tx_chainmask)) 2889250003Sadrian { 2890250003Sadrian case 1: 2891250003Sadrian break; 2892250003Sadrian case 2: 2893250003Sadrian twice_array_gain = (ahp->twice_antenna_gain >= ahp->twice_antenna_reduction)? 0: 2894250003Sadrian ((int16_t)AH_MIN((ahp->twice_antenna_reduction - 2895250003Sadrian (ahp->twice_antenna_gain + INCREASE_MAXPOW_BY_TWO_CHAIN)), 0)); 2896250003Sadrian /* Adjusting maxpower with antennaGain */ 2897250003Sadrian max_power_level -= twice_array_gain; 2898250003Sadrian /* Adjusting maxpower based on chain */ 2899250003Sadrian max_power_level += INCREASE_MAXPOW_BY_TWO_CHAIN; 2900250003Sadrian break; 2901250003Sadrian case 3: 2902250003Sadrian twice_array_gain = (ahp->twice_antenna_gain >= ahp->twice_antenna_reduction)? 0: 2903250003Sadrian ((int16_t)AH_MIN((ahp->twice_antenna_reduction - 2904250003Sadrian (ahp->twice_antenna_gain + INCREASE_MAXPOW_BY_THREE_CHAIN)), 0)); 2905250003Sadrian 2906250003Sadrian /* Adjusting maxpower with antennaGain */ 2907250003Sadrian max_power_level -= twice_array_gain; 2908250003Sadrian /* Adjusting maxpower based on chain */ 2909250003Sadrian max_power_level += INCREASE_MAXPOW_BY_THREE_CHAIN; 2910250003Sadrian break; 2911250003Sadrian default: 2912250003Sadrian HALASSERT(0); /* Unsupported number of chains */ 2913250003Sadrian } 2914250008Sadrian AH_PRIVATE(ah)->ah_maxPowerLevel = (int8_t)max_power_level; 2915250003Sadrian 2916250008Sadrian ar9300_calibration_apply(ah, ichan->channel); 2917250003Sadrian#undef ABS 2918250003Sadrian 2919250003Sadrian /* Handle per packet TPC initializations */ 2920250008Sadrian if (ah->ah_config.ath_hal_desc_tpc) { 2921250003Sadrian /* Transmit Power per-rate per-chain are computed here. A separate 2922250003Sadrian * power table is maintained for different MIMO modes (i.e. TXBF ON, 2923250003Sadrian * STBC) to enable easy lookup during packet transmit. 2924250003Sadrian * The reason for maintaing each of these tables per chain is that 2925250003Sadrian * the transmit power used for different number of chains is different 2926250003Sadrian * depending on whether the power has been limited by the target power, 2927250003Sadrian * the regulatory domain or the CTL limits. 2928250003Sadrian */ 2929250003Sadrian u_int mode = ath_hal_get_curmode(ah, chan); 2930250003Sadrian u_int32_t val = 0; 2931250003Sadrian u_int8_t chainmasks[AR9300_MAX_CHAINS] = 2932250003Sadrian {OSPREY_1_CHAINMASK, OSPREY_2LOHI_CHAINMASK, OSPREY_3_CHAINMASK}; 2933250003Sadrian for (i = 0; i < AR9300_MAX_CHAINS; i++) { 2934250003Sadrian OS_MEMCPY(target_power_val_t2, target_power_val_t2_eep, 2935250003Sadrian sizeof(target_power_val_t2_eep)); 2936250003Sadrian ar9300_eeprom_set_power_per_rate_table(ah, p_eep_data, chan, 2937250003Sadrian target_power_val_t2, cfg_ctl, 2938250003Sadrian antenna_reduction, 2939250003Sadrian twice_max_regulatory_power, 2940250003Sadrian power_limit, chainmasks[i]); 2941250003Sadrian HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, 2942250003Sadrian " Channel = %d Chainmask = %d, Upper Limit = [%2d.%1d dBm]\n", 2943250008Sadrian ichan->channel, i, ahp->upper_limit[i]/2, 2944250003Sadrian ahp->upper_limit[i]%2 * 5); 2945250003Sadrian ar9300_init_rate_txpower(ah, mode, chan, target_power_val_t2, 2946250003Sadrian chainmasks[i]); 2947250003Sadrian 2948250003Sadrian } 2949250003Sadrian 2950250003Sadrian /* Enable TPC */ 2951250003Sadrian OS_REG_WRITE(ah, AR_PHY_PWRTX_MAX, AR_PHY_PWRTX_MAX_TPC_ENABLE); 2952250003Sadrian /* 2953250003Sadrian * Disable per chain power reduction since we are already 2954250003Sadrian * accounting for this in our calculations 2955250003Sadrian */ 2956250003Sadrian val = OS_REG_READ(ah, AR_PHY_POWER_TX_SUB); 2957250003Sadrian if (AR_SREV_WASP(ah)) { 2958250003Sadrian OS_REG_WRITE(ah, AR_PHY_POWER_TX_SUB, 2959250003Sadrian val & AR_PHY_POWER_TX_SUB_2_DISABLE); 2960250003Sadrian } else { 2961250003Sadrian OS_REG_WRITE(ah, AR_PHY_POWER_TX_SUB, 2962250003Sadrian val & AR_PHY_POWER_TX_SUB_3_DISABLE); 2963250003Sadrian } 2964250003Sadrian } 2965250003Sadrian 2966250003Sadrian return HAL_OK; 2967250003Sadrian} 2968250003Sadrian 2969250003Sadrian/************************************************************** 2970250003Sadrian * ar9300_eeprom_set_addac 2971250003Sadrian * 2972250003Sadrian * Set the ADDAC from eeprom. 2973250003Sadrian */ 2974250003Sadrianvoid 2975250008Sadrianar9300_eeprom_set_addac(struct ath_hal *ah, struct ieee80211_channel *chan) 2976250003Sadrian{ 2977250003Sadrian 2978250003Sadrian HALDEBUG(AH_NULL, HAL_DEBUG_UNMASKABLE, 2979250003Sadrian "FIXME: ar9300_eeprom_def_set_addac called\n"); 2980250003Sadrian#if 0 2981250003Sadrian MODAL_EEPDEF_HEADER *p_modal; 2982250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 2983250003Sadrian ar9300_eeprom_t *eep = &ahp->ah_eeprom.def; 2984250003Sadrian u_int8_t biaslevel; 2985250003Sadrian 2986250003Sadrian if (AH_PRIVATE(ah)->ah_macVersion != AR_SREV_VERSION_SOWL) { 2987250003Sadrian return; 2988250003Sadrian } 2989250003Sadrian 2990250003Sadrian HALASSERT(owl_get_eepdef_ver(ahp) == AR9300_EEP_VER); 2991250003Sadrian 2992250003Sadrian /* Xpa bias levels in eeprom are valid from rev 14.7 */ 2993250003Sadrian if (owl_get_eepdef_rev(ahp) < AR9300_EEP_MINOR_VER_7) { 2994250003Sadrian return; 2995250003Sadrian } 2996250003Sadrian 2997250003Sadrian if (ahp->ah_emu_eeprom) { 2998250003Sadrian return; 2999250003Sadrian } 3000250003Sadrian 3001250008Sadrian p_modal = &(eep->modal_header[IEEE80211_IS_CHAN_2GHZ(chan)]); 3002250003Sadrian 3003250003Sadrian if (p_modal->xpa_bias_lvl != 0xff) { 3004250003Sadrian biaslevel = p_modal->xpa_bias_lvl; 3005250003Sadrian } else { 3006250003Sadrian /* Use freqeuncy specific xpa bias level */ 3007250003Sadrian u_int16_t reset_freq_bin, freq_bin, freq_count = 0; 3008250003Sadrian CHAN_CENTERS centers; 3009250003Sadrian 3010250003Sadrian ar9300_get_channel_centers(ah, chan, ¢ers); 3011250003Sadrian 3012250008Sadrian reset_freq_bin = FREQ2FBIN(centers.synth_center, IEEE80211_IS_CHAN_2GHZ(chan)); 3013250003Sadrian freq_bin = p_modal->xpa_bias_lvl_freq[0] & 0xff; 3014250003Sadrian biaslevel = (u_int8_t)(p_modal->xpa_bias_lvl_freq[0] >> 14); 3015250003Sadrian 3016250003Sadrian freq_count++; 3017250003Sadrian 3018250003Sadrian while (freq_count < 3) { 3019250003Sadrian if (p_modal->xpa_bias_lvl_freq[freq_count] == 0x0) { 3020250003Sadrian break; 3021250003Sadrian } 3022250003Sadrian 3023250003Sadrian freq_bin = p_modal->xpa_bias_lvl_freq[freq_count] & 0xff; 3024250003Sadrian if (reset_freq_bin >= freq_bin) { 3025250003Sadrian biaslevel = 3026250003Sadrian (u_int8_t)(p_modal->xpa_bias_lvl_freq[freq_count] >> 14); 3027250003Sadrian } else { 3028250003Sadrian break; 3029250003Sadrian } 3030250003Sadrian freq_count++; 3031250003Sadrian } 3032250003Sadrian } 3033250003Sadrian 3034250003Sadrian /* Apply bias level to the ADDAC values in the INI array */ 3035250008Sadrian if (IEEE80211_IS_CHAN_2GHZ(chan)) { 3036250003Sadrian INI_RA(&ahp->ah_ini_addac, 7, 1) = 3037250003Sadrian (INI_RA(&ahp->ah_ini_addac, 7, 1) & (~0x18)) | biaslevel << 3; 3038250003Sadrian } else { 3039250003Sadrian INI_RA(&ahp->ah_ini_addac, 6, 1) = 3040250003Sadrian (INI_RA(&ahp->ah_ini_addac, 6, 1) & (~0xc0)) | biaslevel << 6; 3041250003Sadrian } 3042250003Sadrian#endif 3043250003Sadrian} 3044250003Sadrian 3045250003Sadrianu_int 3046250003Sadrianar9300_eeprom_dump_support(struct ath_hal *ah, void **pp_e) 3047250003Sadrian{ 3048250003Sadrian *pp_e = &(AH9300(ah)->ah_eeprom); 3049250003Sadrian return sizeof(ar9300_eeprom_t); 3050250003Sadrian} 3051250003Sadrian 3052250003Sadrianu_int8_t 3053250003Sadrianar9300_eeprom_get_num_ant_config(struct ath_hal_9300 *ahp, 3054250003Sadrian HAL_FREQ_BAND freq_band) 3055250003Sadrian{ 3056250003Sadrian#if 0 3057250003Sadrian ar9300_eeprom_t *eep = &ahp->ah_eeprom.def; 3058250003Sadrian MODAL_EEPDEF_HEADER *p_modal = 3059250003Sadrian &(eep->modal_header[HAL_FREQ_BAND_2GHZ == freq_band]); 3060250003Sadrian BASE_EEPDEF_HEADER *p_base = &eep->base_eep_header; 3061250003Sadrian u_int8_t num_ant_config; 3062250003Sadrian 3063250003Sadrian num_ant_config = 1; /* default antenna configuration */ 3064250003Sadrian 3065250003Sadrian if (p_base->version >= 0x0E0D) { 3066250003Sadrian if (p_modal->use_ant1) { 3067250003Sadrian num_ant_config += 1; 3068250003Sadrian } 3069250003Sadrian } 3070250003Sadrian 3071250003Sadrian return num_ant_config; 3072250003Sadrian#else 3073250003Sadrian return 1; 3074250003Sadrian#endif 3075250003Sadrian} 3076250003Sadrian 3077250003SadrianHAL_STATUS 3078250008Sadrianar9300_eeprom_get_ant_cfg(struct ath_hal_9300 *ahp, 3079250008Sadrian const struct ieee80211_channel *chan, 3080250008Sadrian u_int8_t index, u_int16_t *config) 3081250003Sadrian{ 3082250003Sadrian#if 0 3083250003Sadrian ar9300_eeprom_t *eep = &ahp->ah_eeprom.def; 3084250008Sadrian MODAL_EEPDEF_HEADER *p_modal = &(eep->modal_header[IEEE80211_IS_CHAN_2GHZ(chan)]); 3085250003Sadrian BASE_EEPDEF_HEADER *p_base = &eep->base_eep_header; 3086250003Sadrian 3087250003Sadrian switch (index) { 3088250003Sadrian case 0: 3089250003Sadrian *config = p_modal->ant_ctrl_common & 0xFFFF; 3090250003Sadrian return HAL_OK; 3091250003Sadrian case 1: 3092250003Sadrian if (p_base->version >= 0x0E0D) { 3093250003Sadrian if (p_modal->use_ant1) { 3094250003Sadrian *config = ((p_modal->ant_ctrl_common & 0xFFFF0000) >> 16); 3095250003Sadrian return HAL_OK; 3096250003Sadrian } 3097250003Sadrian } 3098250003Sadrian break; 3099250003Sadrian default: 3100250003Sadrian break; 3101250003Sadrian } 3102250003Sadrian#endif 3103250003Sadrian return HAL_EINVAL; 3104250003Sadrian} 3105250003Sadrian 3106250003Sadrianu_int8_t* 3107250003Sadrianar9300_eeprom_get_cust_data(struct ath_hal_9300 *ahp) 3108250003Sadrian{ 3109250003Sadrian return (u_int8_t *)ahp; 3110250003Sadrian} 3111250003Sadrian 3112250003Sadrian#ifdef UNUSED 3113250003Sadrianstatic inline HAL_STATUS 3114250003Sadrianar9300_check_eeprom(struct ath_hal *ah) 3115250003Sadrian{ 3116250003Sadrian#if 0 3117250003Sadrian u_int32_t sum = 0, el; 3118250003Sadrian u_int16_t *eepdata; 3119250003Sadrian int i; 3120250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 3121250003Sadrian HAL_BOOL need_swap = AH_FALSE; 3122250003Sadrian ar9300_eeprom_t *eep = (ar9300_eeprom_t *)&ahp->ah_eeprom.def; 3123250003Sadrian u_int16_t magic, magic2; 3124250003Sadrian int addr; 3125250003Sadrian u_int16_t temp; 3126250003Sadrian 3127250003Sadrian /* 3128250003Sadrian ** We need to check the EEPROM data regardless of if it's in flash or 3129250003Sadrian ** in EEPROM. 3130250003Sadrian */ 3131250003Sadrian 3132250003Sadrian if (!ahp->ah_priv.priv.ah_eeprom_read( 3133250003Sadrian ah, AR9300_EEPROM_MAGIC_OFFSET, &magic)) 3134250003Sadrian { 3135250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, "%s: Reading Magic # failed\n", __func__); 3136250003Sadrian return AH_FALSE; 3137250003Sadrian } 3138250003Sadrian 3139250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, "%s: Read Magic = 0x%04X\n", __func__, magic); 3140250003Sadrian 3141250003Sadrian if (!ar9300_eep_data_in_flash(ah)) { 3142250003Sadrian 3143250003Sadrian if (magic != AR9300_EEPROM_MAGIC) { 3144250003Sadrian magic2 = SWAP16(magic); 3145250003Sadrian 3146250003Sadrian if (magic2 == AR9300_EEPROM_MAGIC) { 3147250003Sadrian need_swap = AH_TRUE; 3148250003Sadrian eepdata = (u_int16_t *)(&ahp->ah_eeprom); 3149250003Sadrian 3150250003Sadrian for (addr = 0; 3151250003Sadrian addr < sizeof(ar9300_eeprom_t) / sizeof(u_int16_t); 3152250003Sadrian addr++) 3153250003Sadrian { 3154250003Sadrian temp = SWAP16(*eepdata); 3155250003Sadrian *eepdata = temp; 3156250003Sadrian eepdata++; 3157250003Sadrian 3158250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM_DUMP, "0x%04X ", *eepdata); 3159250003Sadrian if (((addr + 1) % 6) == 0) { 3160250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM_DUMP, "\n"); 3161250003Sadrian } 3162250003Sadrian } 3163250003Sadrian } else { 3164250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, 3165250003Sadrian "Invalid EEPROM Magic. endianness missmatch.\n"); 3166250003Sadrian return HAL_EEBADSUM; 3167250003Sadrian } 3168250003Sadrian } 3169250003Sadrian } else { 3170250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, 3171250003Sadrian "EEPROM being read from flash @0x%p\n", AH_PRIVATE(ah)->ah_st); 3172250003Sadrian } 3173250003Sadrian 3174250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, "need_swap = %s.\n", need_swap?"True":"False"); 3175250003Sadrian 3176250003Sadrian if (need_swap) { 3177250003Sadrian el = SWAP16(ahp->ah_eeprom.def.base_eep_header.length); 3178250003Sadrian } else { 3179250003Sadrian el = ahp->ah_eeprom.def.base_eep_header.length; 3180250003Sadrian } 3181250003Sadrian 3182250003Sadrian eepdata = (u_int16_t *)(&ahp->ah_eeprom.def); 3183250003Sadrian for (i = 0; 3184250003Sadrian i < AH_MIN(el, sizeof(ar9300_eeprom_t)) / sizeof(u_int16_t); 3185250003Sadrian i++) { 3186250003Sadrian sum ^= *eepdata++; 3187250003Sadrian } 3188250003Sadrian 3189250003Sadrian if (need_swap) { 3190250003Sadrian /* 3191250003Sadrian * preddy: EEPROM endianness does not match. So change it 3192250003Sadrian * 8bit values in eeprom data structure does not need to be swapped 3193250003Sadrian * Only >8bits (16 & 32) values need to be swapped 3194250003Sadrian * If a new 16 or 32 bit field is added to the EEPROM contents, 3195250003Sadrian * please make sure to swap the field here 3196250003Sadrian */ 3197250003Sadrian u_int32_t integer, j; 3198250003Sadrian u_int16_t word; 3199250003Sadrian 3200250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, 3201250003Sadrian "EEPROM Endianness is not native.. Changing \n"); 3202250003Sadrian 3203250003Sadrian /* convert Base Eep header */ 3204250003Sadrian word = SWAP16(eep->base_eep_header.length); 3205250003Sadrian eep->base_eep_header.length = word; 3206250003Sadrian 3207250003Sadrian word = SWAP16(eep->base_eep_header.checksum); 3208250003Sadrian eep->base_eep_header.checksum = word; 3209250003Sadrian 3210250003Sadrian word = SWAP16(eep->base_eep_header.version); 3211250003Sadrian eep->base_eep_header.version = word; 3212250003Sadrian 3213250003Sadrian word = SWAP16(eep->base_eep_header.reg_dmn[0]); 3214250003Sadrian eep->base_eep_header.reg_dmn[0] = word; 3215250003Sadrian 3216250003Sadrian word = SWAP16(eep->base_eep_header.reg_dmn[1]); 3217250003Sadrian eep->base_eep_header.reg_dmn[1] = word; 3218250003Sadrian 3219250003Sadrian word = SWAP16(eep->base_eep_header.rf_silent); 3220250003Sadrian eep->base_eep_header.rf_silent = word; 3221250003Sadrian 3222250003Sadrian word = SWAP16(eep->base_eep_header.blue_tooth_options); 3223250003Sadrian eep->base_eep_header.blue_tooth_options = word; 3224250003Sadrian 3225250003Sadrian word = SWAP16(eep->base_eep_header.device_cap); 3226250003Sadrian eep->base_eep_header.device_cap = word; 3227250003Sadrian 3228250003Sadrian /* convert Modal Eep header */ 3229250003Sadrian for (j = 0; j < ARRAY_LENGTH(eep->modal_header); j++) { 3230250003Sadrian MODAL_EEPDEF_HEADER *p_modal = &eep->modal_header[j]; 3231250003Sadrian integer = SWAP32(p_modal->ant_ctrl_common); 3232250003Sadrian p_modal->ant_ctrl_common = integer; 3233250003Sadrian 3234250003Sadrian for (i = 0; i < AR9300_MAX_CHAINS; i++) { 3235250003Sadrian integer = SWAP32(p_modal->ant_ctrl_chain[i]); 3236250003Sadrian p_modal->ant_ctrl_chain[i] = integer; 3237250003Sadrian } 3238250003Sadrian 3239250003Sadrian for (i = 0; i < AR9300_EEPROM_MODAL_SPURS; i++) { 3240250003Sadrian word = SWAP16(p_modal->spur_chans[i].spur_chan); 3241250003Sadrian p_modal->spur_chans[i].spur_chan = word; 3242250003Sadrian } 3243250003Sadrian } 3244250003Sadrian } 3245250003Sadrian 3246250003Sadrian /* Check CRC - Attach should fail on a bad checksum */ 3247250003Sadrian if (sum != 0xffff || owl_get_eepdef_ver(ahp) != AR9300_EEP_VER || 3248250003Sadrian owl_get_eepdef_rev(ahp) < AR9300_EEP_NO_BACK_VER) { 3249250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, 3250250003Sadrian "Bad EEPROM checksum 0x%x or revision 0x%04x\n", 3251250003Sadrian sum, owl_get_eepdef_ver(ahp)); 3252250003Sadrian return HAL_EEBADSUM; 3253250003Sadrian } 3254250003Sadrian#ifdef EEPROM_DUMP 3255250003Sadrian ar9300_eeprom_def_dump(ah, eep); 3256250003Sadrian#endif 3257250003Sadrian 3258250003Sadrian#if 0 3259250003Sadrian#ifdef AH_AR9300_OVRD_TGT_PWR 3260250003Sadrian 3261250003Sadrian /* 3262250003Sadrian * 14.4 EEPROM contains low target powers. 3263250003Sadrian * Hardcode until EEPROM > 14.4 3264250003Sadrian */ 3265250003Sadrian if (owl_get_eepdef_ver(ahp) == 14 && owl_get_eepdef_rev(ahp) <= 4) { 3266250003Sadrian MODAL_EEPDEF_HEADER *p_modal; 3267250003Sadrian 3268250003Sadrian#ifdef EEPROM_DUMP 3269250003Sadrian HALDEBUG(ah, HAL_DEBUG_POWER_OVERRIDE, "Original Target Powers\n"); 3270250003Sadrian ar9300_eep_def_dump_tgt_power(ah, eep); 3271250003Sadrian#endif 3272250003Sadrian HALDEBUG(ah, HAL_DEBUG_POWER_OVERRIDE, 3273250003Sadrian "Override Target Powers. EEPROM Version is %d.%d, " 3274250003Sadrian "Device Type %d\n", 3275250003Sadrian owl_get_eepdef_ver(ahp), 3276250003Sadrian owl_get_eepdef_rev(ahp), 3277250003Sadrian eep->base_eep_header.device_type); 3278250003Sadrian 3279250003Sadrian 3280250003Sadrian ar9300_eep_def_override_tgt_power(ah, eep); 3281250003Sadrian 3282250003Sadrian if (eep->base_eep_header.device_type == 5) { 3283250003Sadrian /* for xb72 only: improve transmit EVM for interop */ 3284250003Sadrian p_modal = &eep->modal_header[1]; 3285250003Sadrian p_modal->tx_frame_to_data_start = 0x23; 3286250003Sadrian p_modal->tx_frame_to_xpa_on = 0x23; 3287250003Sadrian p_modal->tx_frame_to_pa_on = 0x23; 3288250003Sadrian } 3289250003Sadrian 3290250003Sadrian#ifdef EEPROM_DUMP 3291250003Sadrian HALDEBUG(ah, HAL_DEBUG_POWER_OVERRIDE, "Modified Target Powers\n"); 3292250003Sadrian ar9300_eep_def_dump_tgt_power(ah, eep); 3293250003Sadrian#endif 3294250003Sadrian } 3295250003Sadrian#endif /* AH_AR9300_OVRD_TGT_PWR */ 3296250003Sadrian#endif 3297250003Sadrian#endif 3298250003Sadrian return HAL_OK; 3299250003Sadrian} 3300250003Sadrian#endif 3301250003Sadrian 3302250003Sadrianstatic u_int16_t 3303250008Sadrianar9300_eeprom_get_spur_chan(struct ath_hal *ah, int i, HAL_BOOL is_2ghz) 3304250003Sadrian{ 3305250003Sadrian u_int16_t spur_val = AR_NO_SPUR; 3306250003Sadrian#if 0 3307250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 3308250003Sadrian ar9300_eeprom_t *eep = (ar9300_eeprom_t *)&ahp->ah_eeprom; 3309250003Sadrian 3310250003Sadrian HALASSERT(i < AR_EEPROM_MODAL_SPURS ); 3311250003Sadrian 3312250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, 3313250003Sadrian "Getting spur idx %d is2Ghz. %d val %x\n", 3314250003Sadrian i, is_2ghz, 3315250003Sadrian AH_PRIVATE(ah)->ah_config.ath_hal_spur_chans[i][is_2ghz]); 3316250003Sadrian 3317250003Sadrian switch (AH_PRIVATE(ah)->ah_config.ath_hal_spur_mode) { 3318250003Sadrian case SPUR_DISABLE: 3319250003Sadrian /* returns AR_NO_SPUR */ 3320250003Sadrian break; 3321250003Sadrian case SPUR_ENABLE_IOCTL: 3322250003Sadrian spur_val = AH_PRIVATE(ah)->ah_config.ath_hal_spur_chans[i][is_2ghz]; 3323250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, 3324250003Sadrian "Getting spur val from new loc. %d\n", spur_val); 3325250003Sadrian break; 3326250003Sadrian case SPUR_ENABLE_EEPROM: 3327250003Sadrian spur_val = eep->modal_header[is_2ghz].spur_chans[i].spur_chan; 3328250003Sadrian break; 3329250003Sadrian 3330250003Sadrian } 3331250003Sadrian#endif 3332250003Sadrian return spur_val; 3333250003Sadrian} 3334250003Sadrian 3335250003Sadrian#ifdef UNUSED 3336250003Sadrianstatic inline HAL_BOOL 3337250003Sadrianar9300_fill_eeprom(struct ath_hal *ah) 3338250003Sadrian{ 3339250003Sadrian return ar9300_eeprom_restore(ah); 3340250003Sadrian} 3341250003Sadrian#endif 3342250003Sadrian 3343250003Sadrianu_int16_t 3344250003Sadrianar9300_eeprom_struct_size(void) 3345250003Sadrian{ 3346250003Sadrian return sizeof(ar9300_eeprom_t); 3347250003Sadrian} 3348250003Sadrian 3349250003Sadrianint ar9300_eeprom_struct_default_many(void) 3350250003Sadrian{ 3351250003Sadrian return ARRAY_LENGTH(default9300); 3352250003Sadrian} 3353250003Sadrian 3354250003Sadrian 3355250003Sadrianar9300_eeprom_t * 3356250003Sadrianar9300_eeprom_struct_default(int default_index) 3357250003Sadrian{ 3358250003Sadrian if (default_index >= 0 && 3359250003Sadrian default_index < ARRAY_LENGTH(default9300)) 3360250003Sadrian { 3361250003Sadrian return default9300[default_index]; 3362250003Sadrian } else { 3363250003Sadrian return 0; 3364250003Sadrian } 3365250003Sadrian} 3366250003Sadrian 3367250003Sadrianar9300_eeprom_t * 3368250003Sadrianar9300_eeprom_struct_default_find_by_id(int id) 3369250003Sadrian{ 3370250003Sadrian int it; 3371250003Sadrian 3372250003Sadrian for (it = 0; it < ARRAY_LENGTH(default9300); it++) { 3373250003Sadrian if (default9300[it] != 0 && default9300[it]->template_version == id) { 3374250003Sadrian return default9300[it]; 3375250003Sadrian } 3376250003Sadrian } 3377250003Sadrian return 0; 3378250003Sadrian} 3379250003Sadrian 3380250003Sadrian 3381250003SadrianHAL_BOOL 3382250003Sadrianar9300_calibration_data_read_flash(struct ath_hal *ah, long address, 3383250003Sadrian u_int8_t *buffer, int many) 3384250003Sadrian{ 3385250003Sadrian 3386250003Sadrian if (((address) < 0) || ((address + many) > AR9300_EEPROM_SIZE - 1)) { 3387250003Sadrian return AH_FALSE; 3388250003Sadrian } 3389250003Sadrian return AH_FALSE; 3390250003Sadrian} 3391250003Sadrian 3392250003SadrianHAL_BOOL 3393250003Sadrianar9300_calibration_data_read_eeprom(struct ath_hal *ah, long address, 3394250003Sadrian u_int8_t *buffer, int many) 3395250003Sadrian{ 3396250003Sadrian int i; 3397250003Sadrian u_int8_t value[2]; 3398250003Sadrian unsigned long eep_addr; 3399250003Sadrian unsigned long byte_addr; 3400250003Sadrian u_int16_t *svalue; 3401250003Sadrian 3402250003Sadrian if (((address) < 0) || ((address + many) > AR9300_EEPROM_SIZE)) { 3403250003Sadrian return AH_FALSE; 3404250003Sadrian } 3405250003Sadrian 3406250003Sadrian for (i = 0; i < many; i++) { 3407250003Sadrian eep_addr = (u_int16_t) (address + i) / 2; 3408250003Sadrian byte_addr = (u_int16_t) (address + i) % 2; 3409250003Sadrian svalue = (u_int16_t *) value; 3410250008Sadrian if (! ath_hal_eepromRead(ah, eep_addr, svalue)) { 3411250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, 3412250003Sadrian "%s: Unable to read eeprom region \n", __func__); 3413250003Sadrian return AH_FALSE; 3414250003Sadrian } 3415250003Sadrian buffer[i] = (*svalue >> (8 * byte_addr)) & 0xff; 3416250003Sadrian } 3417250003Sadrian return AH_TRUE; 3418250003Sadrian} 3419250003Sadrian 3420250003SadrianHAL_BOOL 3421250003Sadrianar9300_calibration_data_read_otp(struct ath_hal *ah, long address, 3422250003Sadrian u_int8_t *buffer, int many, HAL_BOOL is_wifi) 3423250003Sadrian{ 3424250003Sadrian int i; 3425250003Sadrian unsigned long eep_addr; 3426250003Sadrian unsigned long byte_addr; 3427250003Sadrian u_int32_t svalue; 3428250003Sadrian 3429250003Sadrian if (((address) < 0) || ((address + many) > 0x400)) { 3430250003Sadrian return AH_FALSE; 3431250003Sadrian } 3432250003Sadrian 3433250003Sadrian for (i = 0; i < many; i++) { 3434250003Sadrian eep_addr = (u_int16_t) (address + i) / 4; /* otp is 4 bytes long???? */ 3435250003Sadrian byte_addr = (u_int16_t) (address + i) % 4; 3436250003Sadrian if (!ar9300_otp_read(ah, eep_addr, &svalue, is_wifi)) { 3437250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, 3438250003Sadrian "%s: Unable to read otp region \n", __func__); 3439250003Sadrian return AH_FALSE; 3440250003Sadrian } 3441250003Sadrian buffer[i] = (svalue >> (8 * byte_addr)) & 0xff; 3442250003Sadrian } 3443250003Sadrian return AH_TRUE; 3444250003Sadrian} 3445250003Sadrian 3446250003Sadrian#ifdef ATH_CAL_NAND_FLASH 3447250003SadrianHAL_BOOL 3448250003Sadrianar9300_calibration_data_read_nand(struct ath_hal *ah, long address, 3449250003Sadrian u_int8_t *buffer, int many) 3450250003Sadrian{ 3451250003Sadrian int ret_len; 3452250003Sadrian int ret_val = 1; 3453250003Sadrian 3454250003Sadrian /* Calling OS based API to read NAND */ 3455250003Sadrian ret_val = OS_NAND_FLASH_READ(ATH_CAL_NAND_PARTITION, address, many, &ret_len, buffer); 3456250003Sadrian 3457250003Sadrian return (ret_val ? AH_FALSE: AH_TRUE); 3458250003Sadrian} 3459250003Sadrian#endif 3460250003Sadrian 3461250003SadrianHAL_BOOL 3462250003Sadrianar9300_calibration_data_read(struct ath_hal *ah, long address, 3463250003Sadrian u_int8_t *buffer, int many) 3464250003Sadrian{ 3465250003Sadrian switch (AH9300(ah)->calibration_data_source) { 3466250003Sadrian case calibration_data_flash: 3467250003Sadrian return ar9300_calibration_data_read_flash(ah, address, buffer, many); 3468250003Sadrian case calibration_data_eeprom: 3469250003Sadrian return ar9300_calibration_data_read_eeprom(ah, address, buffer, many); 3470250003Sadrian case calibration_data_otp: 3471250003Sadrian return ar9300_calibration_data_read_otp(ah, address, buffer, many, 1); 3472250003Sadrian#ifdef ATH_CAL_NAND_FLASH 3473250003Sadrian case calibration_data_nand: 3474250003Sadrian return ar9300_calibration_data_read_nand(ah,address,buffer,many); 3475250003Sadrian#endif 3476250003Sadrian 3477250003Sadrian } 3478250003Sadrian return AH_FALSE; 3479250003Sadrian} 3480250003Sadrian 3481250003Sadrian 3482250003SadrianHAL_BOOL 3483250003Sadrianar9300_calibration_data_read_array(struct ath_hal *ah, int address, 3484250003Sadrian u_int8_t *buffer, int many) 3485250003Sadrian{ 3486250003Sadrian int it; 3487250003Sadrian 3488250003Sadrian for (it = 0; it < many; it++) { 3489250003Sadrian (void)ar9300_calibration_data_read(ah, address - it, buffer + it, 1); 3490250003Sadrian } 3491250003Sadrian return AH_TRUE; 3492250003Sadrian} 3493250003Sadrian 3494250003Sadrian 3495250003Sadrian/* 3496250003Sadrian * the address where the first configuration block is written 3497250003Sadrian */ 3498250003Sadrianstatic const int base_address = 0x3ff; /* 1KB */ 3499250003Sadrianstatic const int base_address_512 = 0x1ff; /* 512Bytes */ 3500250003Sadrian 3501250003Sadrian/* 3502250003Sadrian * the address where the NAND first configuration block is written 3503250003Sadrian */ 3504250003Sadrian#ifdef ATH_CAL_NAND_FLASH 3505250003Sadrianstatic const int base_address_nand = AR9300_FLASH_CAL_START_OFFSET; 3506250003Sadrian#endif 3507250003Sadrian 3508250003Sadrian 3509250003Sadrian/* 3510250003Sadrian * the lower limit on configuration data 3511250003Sadrian */ 3512250003Sadrianstatic const int low_limit = 0x040; 3513250003Sadrian 3514250003Sadrian/* 3515250003Sadrian * returns size of the physical eeprom in bytes. 3516250003Sadrian * 1024 and 2048 are normal sizes. 3517250003Sadrian * 0 means there is no eeprom. 3518250003Sadrian */ 3519250003Sadrianint32_t 3520250003Sadrianar9300_eeprom_size(struct ath_hal *ah) 3521250003Sadrian{ 3522250003Sadrian u_int16_t data; 3523250003Sadrian /* 3524250003Sadrian * first we'll try for 4096 bytes eeprom 3525250003Sadrian */ 3526250003Sadrian if (ar9300_eeprom_read_word(ah, 2047, &data)) { 3527250003Sadrian if (data != 0) { 3528250003Sadrian return 4096; 3529250003Sadrian } 3530250003Sadrian } 3531250003Sadrian /* 3532250003Sadrian * then we'll try for 2048 bytes eeprom 3533250003Sadrian */ 3534250003Sadrian if (ar9300_eeprom_read_word(ah, 1023, &data)) { 3535250003Sadrian if (data != 0) { 3536250003Sadrian return 2048; 3537250003Sadrian } 3538250003Sadrian } 3539250003Sadrian /* 3540250003Sadrian * then we'll try for 1024 bytes eeprom 3541250003Sadrian */ 3542250003Sadrian if (ar9300_eeprom_read_word(ah, 511, &data)) { 3543250003Sadrian if (data != 0) { 3544250003Sadrian return 1024; 3545250003Sadrian } 3546250003Sadrian } 3547250003Sadrian return 0; 3548250003Sadrian} 3549250003Sadrian 3550250003Sadrian/* 3551250003Sadrian * returns size of the physical otp in bytes. 3552250003Sadrian * 1024 and 2048 are normal sizes. 3553250003Sadrian * 0 means there is no eeprom. 3554250003Sadrian */ 3555250003Sadrianint32_t 3556250003Sadrianar9300_otp_size(struct ath_hal *ah) 3557250003Sadrian{ 3558250003Sadrian if (AR_SREV_POSEIDON(ah) || AR_SREV_HORNET(ah)) { 3559250003Sadrian return base_address_512+1; 3560250003Sadrian } else { 3561250003Sadrian return base_address+1; 3562250003Sadrian } 3563250003Sadrian} 3564250003Sadrian 3565250003Sadrian 3566250003Sadrian/* 3567250003Sadrian * find top of memory 3568250003Sadrian */ 3569250003Sadrianint 3570250003Sadrianar9300_eeprom_base_address(struct ath_hal *ah) 3571250003Sadrian{ 3572250003Sadrian int size; 3573250003Sadrian 3574250003Sadrian if (AH9300(ah)->calibration_data_source == calibration_data_otp) { 3575250003Sadrian return ar9300_otp_size(ah)-1; 3576250003Sadrian } 3577250003Sadrian else 3578250003Sadrian { 3579250003Sadrian size = ar9300_eeprom_size(ah); 3580250003Sadrian if (size > 0) { 3581250003Sadrian return size - 1; 3582250003Sadrian } else { 3583250003Sadrian return ar9300_otp_size(ah)-1; 3584250003Sadrian } 3585250003Sadrian } 3586250003Sadrian} 3587250003Sadrian 3588250003Sadrianint 3589250003Sadrianar9300_eeprom_volatile(struct ath_hal *ah) 3590250003Sadrian{ 3591250003Sadrian if (AH9300(ah)->calibration_data_source == calibration_data_otp) { 3592250003Sadrian return 0; /* no eeprom, use otp */ 3593250003Sadrian } else { 3594250003Sadrian return 1; /* board has eeprom or flash */ 3595250003Sadrian } 3596250003Sadrian} 3597250003Sadrian 3598250003Sadrian/* 3599250003Sadrian * need to change this to look for the pcie data in the low parts of memory 3600250003Sadrian * cal data needs to stop a few locations above 3601250003Sadrian */ 3602250003Sadrianint 3603250003Sadrianar9300_eeprom_low_limit(struct ath_hal *ah) 3604250003Sadrian{ 3605250003Sadrian return low_limit; 3606250003Sadrian} 3607250003Sadrian 3608250003Sadrianu_int16_t 3609250003Sadrianar9300_compression_checksum(u_int8_t *data, int dsize) 3610250003Sadrian{ 3611250003Sadrian int it; 3612250003Sadrian int checksum = 0; 3613250003Sadrian 3614250003Sadrian for (it = 0; it < dsize; it++) { 3615250003Sadrian checksum += data[it]; 3616250003Sadrian checksum &= 0xffff; 3617250003Sadrian } 3618250003Sadrian 3619250003Sadrian return checksum; 3620250003Sadrian} 3621250003Sadrian 3622250003Sadrianint 3623250003Sadrianar9300_compression_header_unpack(u_int8_t *best, int *code, int *reference, 3624250003Sadrian int *length, int *major, int *minor) 3625250003Sadrian{ 3626250003Sadrian unsigned long value[4]; 3627250003Sadrian 3628250003Sadrian value[0] = best[0]; 3629250003Sadrian value[1] = best[1]; 3630250003Sadrian value[2] = best[2]; 3631250003Sadrian value[3] = best[3]; 3632250003Sadrian *code = ((value[0] >> 5) & 0x0007); 3633250003Sadrian *reference = (value[0] & 0x001f) | ((value[1] >> 2) & 0x0020); 3634250003Sadrian *length = ((value[1] << 4) & 0x07f0) | ((value[2] >> 4) & 0x000f); 3635250003Sadrian *major = (value[2] & 0x000f); 3636250003Sadrian *minor = (value[3] & 0x00ff); 3637250003Sadrian 3638250003Sadrian return 4; 3639250003Sadrian} 3640250003Sadrian 3641250003Sadrian 3642250003Sadrianstatic HAL_BOOL 3643250003Sadrianar9300_uncompress_block(struct ath_hal *ah, u_int8_t *mptr, int mdata_size, 3644250003Sadrian u_int8_t *block, int size) 3645250003Sadrian{ 3646250003Sadrian int it; 3647250003Sadrian int spot; 3648250003Sadrian int offset; 3649250003Sadrian int length; 3650250003Sadrian 3651250003Sadrian spot = 0; 3652250003Sadrian for (it = 0; it < size; it += (length + 2)) { 3653250003Sadrian offset = block[it]; 3654250003Sadrian offset &= 0xff; 3655250003Sadrian spot += offset; 3656250003Sadrian length = block[it + 1]; 3657250003Sadrian length &= 0xff; 3658250003Sadrian if (length > 0 && spot >= 0 && spot + length <= mdata_size) { 3659250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, 3660250003Sadrian "%s: Restore at %d: spot=%d offset=%d length=%d\n", 3661250003Sadrian __func__, it, spot, offset, length); 3662250003Sadrian OS_MEMCPY(&mptr[spot], &block[it + 2], length); 3663250003Sadrian spot += length; 3664250003Sadrian } else if (length > 0) { 3665250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, 3666250003Sadrian "%s: Bad restore at %d: spot=%d offset=%d length=%d\n", 3667250003Sadrian __func__, it, spot, offset, length); 3668250003Sadrian return AH_FALSE; 3669250003Sadrian } 3670250003Sadrian } 3671250003Sadrian return AH_TRUE; 3672250003Sadrian} 3673250003Sadrian 3674250003Sadrianstatic int 3675250003Sadrianar9300_eeprom_restore_internal_address(struct ath_hal *ah, 3676250003Sadrian ar9300_eeprom_t *mptr, int mdata_size, int cptr, u_int8_t blank) 3677250003Sadrian{ 3678250003Sadrian u_int8_t word[MOUTPUT]; 3679250003Sadrian ar9300_eeprom_t *dptr; /* was uint8 */ 3680250003Sadrian int code; 3681250003Sadrian int reference, length, major, minor; 3682250003Sadrian int osize; 3683250003Sadrian int it; 3684250003Sadrian int restored; 3685250003Sadrian u_int16_t checksum, mchecksum; 3686250003Sadrian 3687250003Sadrian restored = 0; 3688250003Sadrian for (it = 0; it < MSTATE; it++) { 3689250003Sadrian (void) ar9300_calibration_data_read_array( 3690250003Sadrian ah, cptr, word, compression_header_length); 3691250003Sadrian if (word[0] == blank && word[1] == blank && word[2] == blank && word[3] == blank) 3692250003Sadrian { 3693250003Sadrian break; 3694250003Sadrian } 3695250003Sadrian ar9300_compression_header_unpack( 3696250003Sadrian word, &code, &reference, &length, &major, &minor); 3697250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, 3698250003Sadrian "%s: Found block at %x: " 3699250003Sadrian "code=%d ref=%d length=%d major=%d minor=%d\n", 3700250003Sadrian __func__, cptr, code, reference, length, major, minor); 3701250003Sadrian#ifdef DONTUSE 3702250003Sadrian if (length >= 1024) { 3703250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, "%s: Skipping bad header\n", __func__); 3704250003Sadrian cptr -= compression_header_length; 3705250003Sadrian continue; 3706250003Sadrian } 3707250003Sadrian#endif 3708250003Sadrian osize = length; 3709250003Sadrian (void) ar9300_calibration_data_read_array( 3710250003Sadrian ah, cptr, word, 3711250003Sadrian compression_header_length + osize + compression_checksum_length); 3712250003Sadrian checksum = ar9300_compression_checksum( 3713250003Sadrian &word[compression_header_length], length); 3714250003Sadrian mchecksum = 3715250003Sadrian word[compression_header_length + osize] | 3716250003Sadrian (word[compression_header_length + osize + 1] << 8); 3717250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, 3718250003Sadrian "%s: checksum %x %x\n", __func__, checksum, mchecksum); 3719250003Sadrian if (checksum == mchecksum) { 3720250003Sadrian switch (code) { 3721250003Sadrian case _compress_none: 3722250003Sadrian if (length != mdata_size) { 3723250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, 3724250003Sadrian "%s: EEPROM structure size mismatch " 3725250003Sadrian "memory=%d eeprom=%d\n", __func__, mdata_size, length); 3726250003Sadrian return -1; 3727250003Sadrian } 3728250003Sadrian OS_MEMCPY((u_int8_t *)mptr, 3729250003Sadrian (u_int8_t *)(word + compression_header_length), length); 3730250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, 3731250003Sadrian "%s: restored eeprom %d: uncompressed, length %d\n", 3732250003Sadrian __func__, it, length); 3733250003Sadrian restored = 1; 3734250003Sadrian break; 3735250003Sadrian#ifdef UNUSED 3736250003Sadrian case _compress_lzma: 3737250003Sadrian if (reference == reference_current) { 3738250003Sadrian dptr = mptr; 3739250003Sadrian } else { 3740250003Sadrian dptr = (u_int8_t *)ar9300_eeprom_struct_default_find_by_id( 3741250003Sadrian reference); 3742250003Sadrian if (dptr == 0) { 3743250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, 3744250003Sadrian "%s: Can't find reference eeprom struct %d\n", 3745250003Sadrian __func__, reference); 3746250003Sadrian goto done; 3747250003Sadrian } 3748250003Sadrian } 3749250003Sadrian usize = -1; 3750250003Sadrian if (usize != mdata_size) { 3751250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, 3752250003Sadrian "%s: uncompressed data is wrong size %d %d\n", 3753250003Sadrian __func__, usize, mdata_size); 3754250003Sadrian goto done; 3755250003Sadrian } 3756250003Sadrian 3757250003Sadrian for (ib = 0; ib < mdata_size; ib++) { 3758250003Sadrian mptr[ib] = dptr[ib] ^ word[ib + overhead]; 3759250003Sadrian } 3760250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, 3761250003Sadrian "%s: restored eeprom %d: compressed, " 3762250003Sadrian "reference %d, length %d\n", 3763250003Sadrian __func__, it, reference, length); 3764250003Sadrian break; 3765250003Sadrian case _compress_pairs: 3766250003Sadrian if (reference == reference_current) { 3767250003Sadrian dptr = mptr; 3768250003Sadrian } else { 3769250003Sadrian dptr = (u_int8_t *)ar9300_eeprom_struct_default_find_by_id( 3770250003Sadrian reference); 3771250003Sadrian if (dptr == 0) { 3772250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, 3773250003Sadrian "%s: Can't find the reference " 3774250003Sadrian "eeprom structure %d\n", 3775250003Sadrian __func__, reference); 3776250003Sadrian goto done; 3777250003Sadrian } 3778250003Sadrian } 3779250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, 3780250003Sadrian "%s: restored eeprom %d: " 3781250003Sadrian "pairs, reference %d, length %d,\n", 3782250003Sadrian __func__, it, reference, length); 3783250003Sadrian break; 3784250003Sadrian#endif 3785250003Sadrian case _compress_block: 3786250003Sadrian if (reference == reference_current) { 3787250003Sadrian dptr = mptr; 3788250003Sadrian } else { 3789250003Sadrian dptr = ar9300_eeprom_struct_default_find_by_id(reference); 3790250003Sadrian if (dptr == 0) { 3791250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, 3792250003Sadrian "%s: cant find reference eeprom struct %d\n", 3793250003Sadrian __func__, reference); 3794250003Sadrian break; 3795250003Sadrian } 3796250003Sadrian OS_MEMCPY(mptr, dptr, mdata_size); 3797250003Sadrian } 3798250003Sadrian 3799250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, 3800250003Sadrian "%s: restore eeprom %d: block, reference %d, length %d\n", 3801250003Sadrian __func__, it, reference, length); 3802250003Sadrian (void) ar9300_uncompress_block(ah, 3803250003Sadrian (u_int8_t *) mptr, mdata_size, 3804250003Sadrian (u_int8_t *) (word + compression_header_length), length); 3805250003Sadrian restored = 1; 3806250003Sadrian break; 3807250003Sadrian default: 3808250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, 3809250003Sadrian "%s: unknown compression code %d\n", __func__, code); 3810250003Sadrian break; 3811250003Sadrian } 3812250003Sadrian } else { 3813250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, 3814250003Sadrian "%s: skipping block with bad checksum\n", __func__); 3815250003Sadrian } 3816250003Sadrian cptr -= compression_header_length + osize + compression_checksum_length; 3817250003Sadrian } 3818250003Sadrian 3819250003Sadrian if (!restored) { 3820250003Sadrian cptr = -1; 3821250003Sadrian } 3822250003Sadrian return cptr; 3823250003Sadrian} 3824250003Sadrian 3825250003Sadrianstatic int 3826250003Sadrianar9300_eeprom_restore_from_dram(struct ath_hal *ah, ar9300_eeprom_t *mptr, 3827250003Sadrian int mdata_size) 3828250003Sadrian{ 3829250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 3830250003Sadrian#if !defined(USE_PLATFORM_FRAMEWORK) 3831250003Sadrian char *cal_ptr; 3832250003Sadrian#endif 3833250003Sadrian 3834250003Sadrian HALASSERT(mdata_size > 0); 3835250003Sadrian 3836250003Sadrian /* if cal_in_flash is AH_TRUE, the address sent by LMAC to HAL 3837250003Sadrian (i.e. ah->ah_st) is corresponding to Flash. so return from 3838250003Sadrian here if ar9300_eep_data_in_flash(ah) returns AH_TRUE */ 3839250003Sadrian if(ar9300_eep_data_in_flash(ah)) 3840250003Sadrian return -1; 3841250003Sadrian 3842250008Sadrian#if 0 3843250003Sadrian /* check if LMAC sent DRAM address is valid */ 3844250003Sadrian if (!(uintptr_t)(AH_PRIVATE(ah)->ah_st)) { 3845250003Sadrian return -1; 3846250003Sadrian } 3847250008Sadrian#endif 3848250003Sadrian 3849250003Sadrian /* When calibration data is from host, Host will copy the 3850250003Sadrian compressed data to the predefined DRAM location saved at ah->ah_st */ 3851250008Sadrian#if 0 3852250003Sadrian ath_hal_printf(ah, "Restoring Cal data from DRAM\n"); 3853250003Sadrian ahp->ah_cal_mem = OS_REMAP((uintptr_t)(AH_PRIVATE(ah)->ah_st), 3854250003Sadrian HOST_CALDATA_SIZE); 3855250008Sadrian#endif 3856250003Sadrian if (!ahp->ah_cal_mem) 3857250003Sadrian { 3858250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM,"%s: can't remap dram region\n", __func__); 3859250003Sadrian return -1; 3860250003Sadrian } 3861250003Sadrian#if !defined(USE_PLATFORM_FRAMEWORK) 3862250003Sadrian cal_ptr = &((char *)(ahp->ah_cal_mem))[AR9300_FLASH_CAL_START_OFFSET]; 3863250003Sadrian OS_MEMCPY(mptr, cal_ptr, mdata_size); 3864250003Sadrian#else 3865250003Sadrian OS_MEMCPY(mptr, ahp->ah_cal_mem, mdata_size); 3866250003Sadrian#endif 3867250003Sadrian 3868250003Sadrian if (mptr->eeprom_version == 0xff || 3869250003Sadrian mptr->template_version == 0xff || 3870250003Sadrian mptr->eeprom_version == 0 || 3871250003Sadrian mptr->template_version == 0) 3872250003Sadrian { 3873250003Sadrian /* The board is uncalibrated */ 3874250003Sadrian return -1; 3875250003Sadrian } 3876250003Sadrian if (mptr->eeprom_version != 0x2) 3877250003Sadrian { 3878250003Sadrian return -1; 3879250003Sadrian } 3880250003Sadrian 3881250003Sadrian return mdata_size; 3882250003Sadrian 3883250003Sadrian} 3884250003Sadrian 3885250003Sadrianstatic int 3886250003Sadrianar9300_eeprom_restore_from_flash(struct ath_hal *ah, ar9300_eeprom_t *mptr, 3887250003Sadrian int mdata_size) 3888250003Sadrian{ 3889250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 3890250003Sadrian char *cal_ptr; 3891250003Sadrian 3892250003Sadrian HALASSERT(mdata_size > 0); 3893250003Sadrian 3894250003Sadrian if (!ahp->ah_cal_mem) { 3895250003Sadrian return -1; 3896250003Sadrian } 3897250003Sadrian 3898250003Sadrian ath_hal_printf(ah, "Restoring Cal data from Flash\n"); 3899250003Sadrian /* 3900250003Sadrian * When calibration data is saved in flash, read 3901250003Sadrian * uncompressed eeprom structure from flash and return 3902250003Sadrian */ 3903250003Sadrian cal_ptr = &((char *)(ahp->ah_cal_mem))[AR9300_FLASH_CAL_START_OFFSET]; 3904250003Sadrian OS_MEMCPY(mptr, cal_ptr, mdata_size); 3905250003Sadrian#if 0 3906250003Sadrian ar9300_swap_eeprom((ar9300_eeprom_t *)mptr); DONE IN ar9300_restore() 3907250003Sadrian#endif 3908250003Sadrian if (mptr->eeprom_version == 0xff || 3909250003Sadrian mptr->template_version == 0xff || 3910250003Sadrian mptr->eeprom_version == 0 || 3911250003Sadrian mptr->template_version == 0) 3912250003Sadrian { 3913250003Sadrian /* The board is uncalibrated */ 3914250003Sadrian return -1; 3915250003Sadrian } 3916250003Sadrian if (mptr->eeprom_version != 0x2) 3917250003Sadrian { 3918250003Sadrian return -1; 3919250003Sadrian } 3920250003Sadrian return mdata_size; 3921250003Sadrian} 3922250003Sadrian 3923250003Sadrian/* 3924250003Sadrian * Read the configuration data from the storage. We try the order with: 3925250003Sadrian * EEPROM, Flash, OTP. If all of above failed, use the default template. 3926250003Sadrian * The data can be put in any specified memory buffer. 3927250003Sadrian * 3928250003Sadrian * Returns -1 on error. 3929250003Sadrian * Returns address of next memory location on success. 3930250003Sadrian */ 3931250003Sadrianint 3932250003Sadrianar9300_eeprom_restore_internal(struct ath_hal *ah, ar9300_eeprom_t *mptr, 3933250003Sadrian int mdata_size) 3934250003Sadrian{ 3935250003Sadrian int nptr; 3936250003Sadrian 3937250003Sadrian nptr = -1; 3938250003Sadrian 3939250003Sadrian if ((AH9300(ah)->calibration_data_try == calibration_data_none || 3940250003Sadrian AH9300(ah)->calibration_data_try == calibration_data_dram) && 3941250003Sadrian AH9300(ah)->try_dram && nptr < 0) 3942250003Sadrian { 3943250008Sadrian ath_hal_printf(ah, "Restoring Cal data from DRAM\n"); 3944250003Sadrian AH9300(ah)->calibration_data_source = calibration_data_dram; 3945250003Sadrian AH9300(ah)->calibration_data_source_address = 0; 3946250003Sadrian nptr = ar9300_eeprom_restore_from_dram(ah, mptr, mdata_size); 3947250003Sadrian if (nptr < 0) { 3948250003Sadrian AH9300(ah)->calibration_data_source = calibration_data_none; 3949250003Sadrian AH9300(ah)->calibration_data_source_address = 0; 3950250003Sadrian } 3951250003Sadrian } 3952250003Sadrian 3953250003Sadrian if ((AH9300(ah)->calibration_data_try == calibration_data_none || 3954250003Sadrian AH9300(ah)->calibration_data_try == calibration_data_eeprom) && 3955250003Sadrian AH9300(ah)->try_eeprom && nptr < 0) 3956250003Sadrian { 3957250003Sadrian /* 3958250003Sadrian * need to look at highest eeprom address as well as at 3959250003Sadrian * base_address=0x3ff where we used to write the data 3960250003Sadrian */ 3961250008Sadrian ath_hal_printf(ah, "Restoring Cal data from EEPROM\n"); 3962250003Sadrian AH9300(ah)->calibration_data_source = calibration_data_eeprom; 3963250003Sadrian if (AH9300(ah)->calibration_data_try_address != 0) { 3964250003Sadrian AH9300(ah)->calibration_data_source_address = 3965250003Sadrian AH9300(ah)->calibration_data_try_address; 3966250003Sadrian nptr = ar9300_eeprom_restore_internal_address( 3967250003Sadrian ah, mptr, mdata_size, 3968250003Sadrian AH9300(ah)->calibration_data_source_address, 0xff); 3969250003Sadrian } else { 3970250003Sadrian AH9300(ah)->calibration_data_source_address = 3971250003Sadrian ar9300_eeprom_base_address(ah); 3972250003Sadrian nptr = ar9300_eeprom_restore_internal_address( 3973250003Sadrian ah, mptr, mdata_size, 3974250003Sadrian AH9300(ah)->calibration_data_source_address, 0xff); 3975250003Sadrian if (nptr < 0 && 3976250003Sadrian AH9300(ah)->calibration_data_source_address != base_address) 3977250003Sadrian { 3978250003Sadrian AH9300(ah)->calibration_data_source_address = base_address; 3979250003Sadrian nptr = ar9300_eeprom_restore_internal_address( 3980250003Sadrian ah, mptr, mdata_size, 3981250003Sadrian AH9300(ah)->calibration_data_source_address, 0xff); 3982250003Sadrian } 3983250003Sadrian } 3984250003Sadrian if (nptr < 0) { 3985250003Sadrian AH9300(ah)->calibration_data_source = calibration_data_none; 3986250003Sadrian AH9300(ah)->calibration_data_source_address = 0; 3987250003Sadrian } 3988250003Sadrian } 3989250003Sadrian 3990250003Sadrian /* 3991250003Sadrian * ##### should be an ifdef test for any AP usage, 3992250003Sadrian * either in driver or in nart 3993250003Sadrian */ 3994250003Sadrian if ((AH9300(ah)->calibration_data_try == calibration_data_none || 3995250003Sadrian AH9300(ah)->calibration_data_try == calibration_data_flash) && 3996250003Sadrian AH9300(ah)->try_flash && nptr < 0) 3997250003Sadrian { 3998250008Sadrian ath_hal_printf(ah, "Restoring Cal data from Flash\n"); 3999250003Sadrian AH9300(ah)->calibration_data_source = calibration_data_flash; 4000250003Sadrian /* how are we supposed to set this for flash? */ 4001250003Sadrian AH9300(ah)->calibration_data_source_address = 0; 4002250003Sadrian nptr = ar9300_eeprom_restore_from_flash(ah, mptr, mdata_size); 4003250003Sadrian if (nptr < 0) { 4004250003Sadrian AH9300(ah)->calibration_data_source = calibration_data_none; 4005250003Sadrian AH9300(ah)->calibration_data_source_address = 0; 4006250003Sadrian } 4007250003Sadrian } 4008250003Sadrian 4009250003Sadrian if ((AH9300(ah)->calibration_data_try == calibration_data_none || 4010250003Sadrian AH9300(ah)->calibration_data_try == calibration_data_otp) && 4011250003Sadrian AH9300(ah)->try_otp && nptr < 0) 4012250003Sadrian { 4013250008Sadrian ath_hal_printf(ah, "Restoring Cal data from OTP\n"); 4014250003Sadrian AH9300(ah)->calibration_data_source = calibration_data_otp; 4015250003Sadrian if (AH9300(ah)->calibration_data_try_address != 0) { 4016250003Sadrian AH9300(ah)->calibration_data_source_address = 4017250003Sadrian AH9300(ah)->calibration_data_try_address; 4018250003Sadrian } else { 4019250003Sadrian AH9300(ah)->calibration_data_source_address = 4020250003Sadrian ar9300_eeprom_base_address(ah); 4021250003Sadrian } 4022250003Sadrian nptr = ar9300_eeprom_restore_internal_address( 4023250003Sadrian ah, mptr, mdata_size, AH9300(ah)->calibration_data_source_address, 0); 4024250003Sadrian if (nptr < 0) { 4025250003Sadrian AH9300(ah)->calibration_data_source = calibration_data_none; 4026250003Sadrian AH9300(ah)->calibration_data_source_address = 0; 4027250003Sadrian } 4028250003Sadrian } 4029250003Sadrian 4030250003Sadrian#ifdef ATH_CAL_NAND_FLASH 4031250003Sadrian if ((AH9300(ah)->calibration_data_try == calibration_data_none || 4032250003Sadrian AH9300(ah)->calibration_data_try == calibration_data_nand) && 4033250003Sadrian AH9300(ah)->try_nand && nptr < 0) 4034250003Sadrian { 4035250003Sadrian AH9300(ah)->calibration_data_source = calibration_data_nand; 4036250003Sadrian AH9300(ah)->calibration_data_source_address = ((unsigned int)(AH_PRIVATE(ah)->ah_st)) + base_address_nand; 4037250003Sadrian if(ar9300_calibration_data_read( 4038250003Sadrian ah, AH9300(ah)->calibration_data_source_address, 4039250003Sadrian (u_int8_t *)mptr, mdata_size) == AH_TRUE) 4040250003Sadrian { 4041250003Sadrian nptr = mdata_size; 4042250003Sadrian } 4043250003Sadrian /*nptr=ar9300EepromRestoreInternalAddress(ah, mptr, mdataSize, CalibrationDataSourceAddress);*/ 4044250003Sadrian if(nptr < 0) 4045250003Sadrian { 4046250003Sadrian AH9300(ah)->calibration_data_source = calibration_data_none; 4047250003Sadrian AH9300(ah)->calibration_data_source_address = 0; 4048250003Sadrian } 4049250003Sadrian } 4050250003Sadrian#endif 4051250003Sadrian if (nptr < 0) { 4052250003Sadrian ath_hal_printf(ah, "%s[%d] No vaid CAL, calling default template\n", 4053250003Sadrian __func__, __LINE__); 4054250003Sadrian nptr = ar9300_eeprom_restore_something(ah, mptr, mdata_size); 4055250003Sadrian } 4056250003Sadrian 4057250003Sadrian return nptr; 4058250003Sadrian} 4059250003Sadrian 4060250003Sadrian/******************************************************************************/ 4061250003Sadrian/*! 4062250003Sadrian** \brief Eeprom Swapping Function 4063250003Sadrian** 4064250003Sadrian** This function will swap the contents of the "longer" EEPROM data items 4065250003Sadrian** to ensure they are consistent with the endian requirements for the platform 4066250003Sadrian** they are being compiled for 4067250003Sadrian** 4068250003Sadrian** \param eh Pointer to the EEPROM data structure 4069250003Sadrian** \return N/A 4070250003Sadrian*/ 4071250003Sadrian#if AH_BYTE_ORDER == AH_BIG_ENDIAN 4072250003Sadrianvoid 4073250003Sadrianar9300_swap_eeprom(ar9300_eeprom_t *eep) 4074250003Sadrian{ 4075250003Sadrian u_int32_t dword; 4076250003Sadrian u_int16_t word; 4077250003Sadrian int i; 4078250003Sadrian 4079250003Sadrian word = __bswap16(eep->base_eep_header.reg_dmn[0]); 4080250003Sadrian eep->base_eep_header.reg_dmn[0] = word; 4081250003Sadrian 4082250003Sadrian word = __bswap16(eep->base_eep_header.reg_dmn[1]); 4083250003Sadrian eep->base_eep_header.reg_dmn[1] = word; 4084250003Sadrian 4085250003Sadrian dword = __bswap32(eep->base_eep_header.swreg); 4086250003Sadrian eep->base_eep_header.swreg = dword; 4087250003Sadrian 4088250003Sadrian dword = __bswap32(eep->modal_header_2g.ant_ctrl_common); 4089250003Sadrian eep->modal_header_2g.ant_ctrl_common = dword; 4090250003Sadrian 4091250003Sadrian dword = __bswap32(eep->modal_header_2g.ant_ctrl_common2); 4092250003Sadrian eep->modal_header_2g.ant_ctrl_common2 = dword; 4093250003Sadrian 4094250003Sadrian dword = __bswap32(eep->modal_header_2g.paprd_rate_mask_ht20); 4095250003Sadrian eep->modal_header_2g.paprd_rate_mask_ht20 = dword; 4096250003Sadrian 4097250003Sadrian dword = __bswap32(eep->modal_header_2g.paprd_rate_mask_ht40); 4098250003Sadrian eep->modal_header_2g.paprd_rate_mask_ht40 = dword; 4099250003Sadrian 4100250003Sadrian dword = __bswap32(eep->modal_header_5g.ant_ctrl_common); 4101250003Sadrian eep->modal_header_5g.ant_ctrl_common = dword; 4102250003Sadrian 4103250003Sadrian dword = __bswap32(eep->modal_header_5g.ant_ctrl_common2); 4104250003Sadrian eep->modal_header_5g.ant_ctrl_common2 = dword; 4105250003Sadrian 4106250003Sadrian dword = __bswap32(eep->modal_header_5g.paprd_rate_mask_ht20); 4107250003Sadrian eep->modal_header_5g.paprd_rate_mask_ht20 = dword; 4108250003Sadrian 4109250003Sadrian dword = __bswap32(eep->modal_header_5g.paprd_rate_mask_ht40); 4110250003Sadrian eep->modal_header_5g.paprd_rate_mask_ht40 = dword; 4111250003Sadrian 4112250003Sadrian for (i = 0; i < OSPREY_MAX_CHAINS; i++) { 4113250003Sadrian word = __bswap16(eep->modal_header_2g.ant_ctrl_chain[i]); 4114250003Sadrian eep->modal_header_2g.ant_ctrl_chain[i] = word; 4115250003Sadrian 4116250003Sadrian word = __bswap16(eep->modal_header_5g.ant_ctrl_chain[i]); 4117250003Sadrian eep->modal_header_5g.ant_ctrl_chain[i] = word; 4118250003Sadrian } 4119250003Sadrian} 4120250003Sadrian 4121250003Sadrianvoid ar9300_eeprom_template_swap(void) 4122250003Sadrian{ 4123250003Sadrian int it; 4124250003Sadrian ar9300_eeprom_t *dptr; 4125250003Sadrian 4126250003Sadrian for (it = 0; it < ARRAY_LENGTH(default9300); it++) { 4127250003Sadrian dptr = ar9300_eeprom_struct_default(it); 4128250003Sadrian if (dptr != 0) { 4129250003Sadrian ar9300_swap_eeprom(dptr); 4130250003Sadrian } 4131250003Sadrian } 4132250003Sadrian} 4133250003Sadrian#endif 4134250003Sadrian 4135250003Sadrian 4136250003Sadrian/* 4137250003Sadrian * Restore the configuration structure by reading the eeprom. 4138250003Sadrian * This function destroys any existing in-memory structure content. 4139250003Sadrian */ 4140250003SadrianHAL_BOOL 4141250003Sadrianar9300_eeprom_restore(struct ath_hal *ah) 4142250003Sadrian{ 4143250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 4144250003Sadrian ar9300_eeprom_t *mptr; 4145250003Sadrian int mdata_size; 4146250003Sadrian HAL_BOOL status = AH_FALSE; 4147250003Sadrian 4148250003Sadrian mptr = &ahp->ah_eeprom; 4149250003Sadrian mdata_size = ar9300_eeprom_struct_size(); 4150250003Sadrian 4151250003Sadrian if (mptr != 0 && mdata_size > 0) { 4152250003Sadrian#if AH_BYTE_ORDER == AH_BIG_ENDIAN 4153250003Sadrian ar9300_eeprom_template_swap(); 4154250003Sadrian ar9300_swap_eeprom(mptr); 4155250003Sadrian#endif 4156250003Sadrian /* 4157250003Sadrian * At this point, mptr points to the eeprom data structure 4158250003Sadrian * in it's "default" state. If this is big endian, swap the 4159250003Sadrian * data structures back to "little endian" form. 4160250003Sadrian */ 4161250003Sadrian if (ar9300_eeprom_restore_internal(ah, mptr, mdata_size) >= 0) { 4162250003Sadrian status = AH_TRUE; 4163250003Sadrian } 4164250003Sadrian 4165250003Sadrian#if AH_BYTE_ORDER == AH_BIG_ENDIAN 4166250003Sadrian /* Second Swap, back to Big Endian */ 4167250003Sadrian ar9300_eeprom_template_swap(); 4168250003Sadrian ar9300_swap_eeprom(mptr); 4169250003Sadrian#endif 4170250003Sadrian 4171250003Sadrian } 4172250003Sadrian ahp->ah_2g_paprd_rate_mask_ht40 = 4173250003Sadrian mptr->modal_header_2g.paprd_rate_mask_ht40; 4174250003Sadrian ahp->ah_2g_paprd_rate_mask_ht20 = 4175250003Sadrian mptr->modal_header_2g.paprd_rate_mask_ht20; 4176250003Sadrian ahp->ah_5g_paprd_rate_mask_ht40 = 4177250003Sadrian mptr->modal_header_5g.paprd_rate_mask_ht40; 4178250003Sadrian ahp->ah_5g_paprd_rate_mask_ht20 = 4179250003Sadrian mptr->modal_header_5g.paprd_rate_mask_ht20; 4180250003Sadrian return status; 4181250003Sadrian} 4182250003Sadrian 4183250003Sadrianint32_t ar9300_thermometer_get(struct ath_hal *ah) 4184250003Sadrian{ 4185250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 4186250003Sadrian int thermometer; 4187250003Sadrian thermometer = 4188250003Sadrian (ahp->ah_eeprom.base_eep_header.misc_configuration >> 1) & 0x3; 4189250003Sadrian thermometer--; 4190250003Sadrian return thermometer; 4191250003Sadrian} 4192250003Sadrian 4193250003SadrianHAL_BOOL ar9300_thermometer_apply(struct ath_hal *ah) 4194250003Sadrian{ 4195250003Sadrian int thermometer = ar9300_thermometer_get(ah); 4196250003Sadrian 4197250003Sadrian/* ch0_RXTX4 */ 4198250003Sadrian/*#define AR_PHY_65NM_CH0_RXTX4 AR_PHY_65NM(ch0_RXTX4)*/ 4199250003Sadrian#define AR_PHY_65NM_CH1_RXTX4 AR_PHY_65NM(ch1_RXTX4) 4200250003Sadrian#define AR_PHY_65NM_CH2_RXTX4 AR_PHY_65NM(ch2_RXTX4) 4201250003Sadrian/*#define AR_PHY_65NM_CH0_RXTX4_THERM_ON 0x10000000*/ 4202250003Sadrian/*#define AR_PHY_65NM_CH0_RXTX4_THERM_ON_S 28*/ 4203250003Sadrian#define AR_PHY_65NM_CH0_RXTX4_THERM_ON_OVR_S 29 4204250003Sadrian#define AR_PHY_65NM_CH0_RXTX4_THERM_ON_OVR \ 4205250003Sadrian (0x1<<AR_PHY_65NM_CH0_RXTX4_THERM_ON_OVR_S) 4206250003Sadrian 4207250003Sadrian if (thermometer < 0) { 4208250003Sadrian OS_REG_RMW_FIELD(ah, 4209250003Sadrian AR_PHY_65NM_CH0_RXTX4, AR_PHY_65NM_CH0_RXTX4_THERM_ON_OVR, 0); 4210250003Sadrian if (!AR_SREV_HORNET(ah) && !AR_SREV_POSEIDON(ah)) { 4211250003Sadrian OS_REG_RMW_FIELD(ah, 4212250003Sadrian AR_PHY_65NM_CH1_RXTX4, AR_PHY_65NM_CH0_RXTX4_THERM_ON_OVR, 0); 4213250003Sadrian if (!AR_SREV_WASP(ah) && !AR_SREV_JUPITER(ah)) { 4214250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_65NM_CH2_RXTX4, 4215250003Sadrian AR_PHY_65NM_CH0_RXTX4_THERM_ON_OVR, 0); 4216250003Sadrian } 4217250003Sadrian } 4218250003Sadrian OS_REG_RMW_FIELD(ah, 4219250003Sadrian AR_PHY_65NM_CH0_RXTX4, AR_PHY_65NM_CH0_RXTX4_THERM_ON, 0); 4220250003Sadrian if (!AR_SREV_HORNET(ah) && !AR_SREV_POSEIDON(ah)) { 4221250003Sadrian OS_REG_RMW_FIELD(ah, 4222250003Sadrian AR_PHY_65NM_CH1_RXTX4, AR_PHY_65NM_CH0_RXTX4_THERM_ON, 0); 4223250003Sadrian if (!AR_SREV_WASP(ah) && !AR_SREV_JUPITER(ah)) { 4224250003Sadrian OS_REG_RMW_FIELD(ah, 4225250003Sadrian AR_PHY_65NM_CH2_RXTX4, AR_PHY_65NM_CH0_RXTX4_THERM_ON, 0); 4226250003Sadrian } 4227250003Sadrian } 4228250003Sadrian } else { 4229250003Sadrian OS_REG_RMW_FIELD(ah, 4230250003Sadrian AR_PHY_65NM_CH0_RXTX4, AR_PHY_65NM_CH0_RXTX4_THERM_ON_OVR, 1); 4231250003Sadrian if (!AR_SREV_HORNET(ah) && !AR_SREV_POSEIDON(ah)) { 4232250003Sadrian OS_REG_RMW_FIELD(ah, 4233250003Sadrian AR_PHY_65NM_CH1_RXTX4, AR_PHY_65NM_CH0_RXTX4_THERM_ON_OVR, 1); 4234250003Sadrian if (!AR_SREV_WASP(ah) && !AR_SREV_JUPITER(ah)) { 4235250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_65NM_CH2_RXTX4, 4236250003Sadrian AR_PHY_65NM_CH0_RXTX4_THERM_ON_OVR, 1); 4237250003Sadrian } 4238250003Sadrian } 4239250003Sadrian if (thermometer == 0) { 4240250003Sadrian OS_REG_RMW_FIELD(ah, 4241250003Sadrian AR_PHY_65NM_CH0_RXTX4, AR_PHY_65NM_CH0_RXTX4_THERM_ON, 1); 4242250003Sadrian if (!AR_SREV_HORNET(ah) && !AR_SREV_POSEIDON(ah)) { 4243250003Sadrian OS_REG_RMW_FIELD(ah, 4244250003Sadrian AR_PHY_65NM_CH1_RXTX4, AR_PHY_65NM_CH0_RXTX4_THERM_ON, 0); 4245250003Sadrian if (!AR_SREV_WASP(ah) && !AR_SREV_JUPITER(ah)) { 4246250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_65NM_CH2_RXTX4, 4247250003Sadrian AR_PHY_65NM_CH0_RXTX4_THERM_ON, 0); 4248250003Sadrian } 4249250003Sadrian } 4250250003Sadrian } else if (thermometer == 1) { 4251250003Sadrian OS_REG_RMW_FIELD(ah, 4252250003Sadrian AR_PHY_65NM_CH0_RXTX4, AR_PHY_65NM_CH0_RXTX4_THERM_ON, 0); 4253250003Sadrian if (!AR_SREV_HORNET(ah) && !AR_SREV_POSEIDON(ah)) { 4254250003Sadrian OS_REG_RMW_FIELD(ah, 4255250003Sadrian AR_PHY_65NM_CH1_RXTX4, AR_PHY_65NM_CH0_RXTX4_THERM_ON, 1); 4256250003Sadrian if (!AR_SREV_WASP(ah) && !AR_SREV_JUPITER(ah)) { 4257250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_65NM_CH2_RXTX4, 4258250003Sadrian AR_PHY_65NM_CH0_RXTX4_THERM_ON, 0); 4259250003Sadrian } 4260250003Sadrian } 4261250003Sadrian } else if (thermometer == 2) { 4262250003Sadrian OS_REG_RMW_FIELD(ah, 4263250003Sadrian AR_PHY_65NM_CH0_RXTX4, AR_PHY_65NM_CH0_RXTX4_THERM_ON, 0); 4264250003Sadrian if (!AR_SREV_HORNET(ah) && !AR_SREV_POSEIDON(ah)) { 4265250003Sadrian OS_REG_RMW_FIELD(ah, 4266250003Sadrian AR_PHY_65NM_CH1_RXTX4, AR_PHY_65NM_CH0_RXTX4_THERM_ON, 0); 4267250003Sadrian if (!AR_SREV_WASP(ah) && !AR_SREV_JUPITER(ah)) { 4268250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_65NM_CH2_RXTX4, 4269250003Sadrian AR_PHY_65NM_CH0_RXTX4_THERM_ON, 1); 4270250003Sadrian } 4271250003Sadrian } 4272250003Sadrian } 4273250003Sadrian } 4274250003Sadrian return AH_TRUE; 4275250003Sadrian} 4276250003Sadrian 4277250003Sadrianstatic int32_t ar9300_tuning_caps_params_get(struct ath_hal *ah) 4278250003Sadrian{ 4279250003Sadrian int tuning_caps_params; 4280250003Sadrian ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom; 4281250003Sadrian tuning_caps_params = eep->base_eep_header.params_for_tuning_caps[0]; 4282250003Sadrian return tuning_caps_params; 4283250003Sadrian} 4284250003Sadrian 4285250003Sadrian/* 4286250003Sadrian * Read the tuning caps params from eeprom and set to correct register. 4287250003Sadrian * To regulation the frequency accuracy. 4288250003Sadrian */ 4289250003SadrianHAL_BOOL ar9300_tuning_caps_apply(struct ath_hal *ah) 4290250003Sadrian{ 4291250003Sadrian int tuning_caps_params; 4292250003Sadrian ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom; 4293250003Sadrian tuning_caps_params = ar9300_tuning_caps_params_get(ah); 4294250003Sadrian if ((eep->base_eep_header.feature_enable & 0x40) >> 6) { 4295250003Sadrian tuning_caps_params &= 0x7f; 4296250003Sadrian 4297250003Sadrian if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah) || AR_SREV_WASP(ah)) { 4298250003Sadrian return AH_TRUE; 4299250003Sadrian } else if (AR_SREV_SCORPION(ah)) { 4300250003Sadrian OS_REG_RMW_FIELD(ah, 4301250003Sadrian AR_SCORPION_CH0_XTAL, AR_OSPREY_CHO_XTAL_CAPINDAC, 4302250003Sadrian tuning_caps_params); 4303250003Sadrian OS_REG_RMW_FIELD(ah, 4304250003Sadrian AR_SCORPION_CH0_XTAL, AR_OSPREY_CHO_XTAL_CAPOUTDAC, 4305250003Sadrian tuning_caps_params); 4306250003Sadrian } else { 4307250003Sadrian OS_REG_RMW_FIELD(ah, 4308250003Sadrian AR_OSPREY_CH0_XTAL, AR_OSPREY_CHO_XTAL_CAPINDAC, 4309250003Sadrian tuning_caps_params); 4310250003Sadrian OS_REG_RMW_FIELD(ah, 4311250003Sadrian AR_OSPREY_CH0_XTAL, AR_OSPREY_CHO_XTAL_CAPOUTDAC, 4312250003Sadrian tuning_caps_params); 4313250003Sadrian } 4314250003Sadrian 4315250003Sadrian } 4316250003Sadrian return AH_TRUE; 4317250003Sadrian} 4318250003Sadrian 4319250003Sadrian/* 4320250003Sadrian * Read the tx_frame_to_xpa_on param from eeprom and apply the value to 4321250003Sadrian * correct register. 4322250003Sadrian */ 4323250003SadrianHAL_BOOL ar9300_xpa_timing_control_apply(struct ath_hal *ah, HAL_BOOL is_2ghz) 4324250003Sadrian{ 4325250003Sadrian u_int8_t xpa_timing_control; 4326250003Sadrian ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom; 4327250003Sadrian if ((eep->base_eep_header.feature_enable & 0x80) >> 7) { 4328250003Sadrian if (AR_SREV_OSPREY(ah) || AR_SREV_AR9580(ah) || AR_SREV_WASP(ah)) { 4329250003Sadrian if (is_2ghz) { 4330250003Sadrian xpa_timing_control = eep->modal_header_2g.tx_frame_to_xpa_on; 4331250003Sadrian OS_REG_RMW_FIELD(ah, 4332250003Sadrian AR_PHY_XPA_TIMING_CTL, AR_PHY_XPA_TIMING_CTL_FRAME_XPAB_ON, 4333250003Sadrian xpa_timing_control); 4334250003Sadrian } else { 4335250003Sadrian xpa_timing_control = eep->modal_header_5g.tx_frame_to_xpa_on; 4336250003Sadrian OS_REG_RMW_FIELD(ah, 4337250003Sadrian AR_PHY_XPA_TIMING_CTL, AR_PHY_XPA_TIMING_CTL_FRAME_XPAA_ON, 4338250003Sadrian xpa_timing_control); 4339250003Sadrian } 4340250003Sadrian } 4341250003Sadrian } 4342250003Sadrian return AH_TRUE; 4343250003Sadrian} 4344250003Sadrian 4345250003Sadrian 4346250003Sadrian/* 4347250003Sadrian * Read the xLNA_bias_strength param from eeprom and apply the value to 4348250003Sadrian * correct register. 4349250003Sadrian */ 4350250003SadrianHAL_BOOL ar9300_x_lNA_bias_strength_apply(struct ath_hal *ah, HAL_BOOL is_2ghz) 4351250003Sadrian{ 4352250003Sadrian u_int8_t x_lNABias; 4353250003Sadrian u_int32_t value = 0; 4354250003Sadrian ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom; 4355250003Sadrian 4356250003Sadrian if ((eep->base_eep_header.misc_configuration & 0x40) >> 6) { 4357250003Sadrian if (AR_SREV_OSPREY(ah)) { 4358250003Sadrian if (is_2ghz) { 4359250003Sadrian x_lNABias = eep->modal_header_2g.xLNA_bias_strength; 4360250003Sadrian } else { 4361250003Sadrian x_lNABias = eep->modal_header_5g.xLNA_bias_strength; 4362250003Sadrian } 4363250003Sadrian value = x_lNABias & ( 0x03 ); // bit0,1 for chain0 4364250003Sadrian OS_REG_RMW_FIELD(ah, 4365250003Sadrian AR_PHY_65NM_CH0_RXTX4, AR_PHY_65NM_RXTX4_XLNA_BIAS, value); 4366250003Sadrian value = (x_lNABias >> 2) & ( 0x03 ); // bit2,3 for chain1 4367250003Sadrian OS_REG_RMW_FIELD(ah, 4368250003Sadrian AR_PHY_65NM_CH1_RXTX4, AR_PHY_65NM_RXTX4_XLNA_BIAS, value); 4369250003Sadrian value = (x_lNABias >> 4) & ( 0x03 ); // bit4,5 for chain2 4370250003Sadrian OS_REG_RMW_FIELD(ah, 4371250003Sadrian AR_PHY_65NM_CH2_RXTX4, AR_PHY_65NM_RXTX4_XLNA_BIAS, value); 4372250003Sadrian } 4373250003Sadrian } 4374250003Sadrian return AH_TRUE; 4375250003Sadrian} 4376250003Sadrian 4377250003Sadrian 4378250003Sadrian/* 4379250003Sadrian * Read EEPROM header info and program the device for correct operation 4380250003Sadrian * given the channel value. 4381250003Sadrian */ 4382250003SadrianHAL_BOOL 4383250008Sadrianar9300_eeprom_set_board_values(struct ath_hal *ah, const struct ieee80211_channel *chan) 4384250003Sadrian{ 4385250008Sadrian HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan); 4386250003Sadrian 4387250008Sadrian ar9300_xpa_bias_level_apply(ah, IEEE80211_IS_CHAN_2GHZ(chan)); 4388250003Sadrian 4389250008Sadrian ar9300_xpa_timing_control_apply(ah, IEEE80211_IS_CHAN_2GHZ(chan)); 4390250008Sadrian 4391250008Sadrian ar9300_ant_ctrl_apply(ah, IEEE80211_IS_CHAN_2GHZ(chan)); 4392250003Sadrian ar9300_drive_strength_apply(ah); 4393250003Sadrian 4394250008Sadrian ar9300_x_lNA_bias_strength_apply(ah, IEEE80211_IS_CHAN_2GHZ(chan)); 4395250003Sadrian 4396250003Sadrian /* wait for Poseidon internal regular turnning */ 4397250003Sadrian /* for Hornet we move it before initPLL to avoid an access issue */ 4398250003Sadrian /* Function not used when EMULATION. */ 4399250003Sadrian if (!AR_SREV_HORNET(ah) && !AR_SREV_WASP(ah)) { 4400250003Sadrian ar9300_internal_regulator_apply(ah); 4401250003Sadrian } 4402250003Sadrian 4403250008Sadrian ar9300_attenuation_apply(ah, ichan->channel); 4404250008Sadrian ar9300_quick_drop_apply(ah, ichan->channel); 4405250003Sadrian ar9300_thermometer_apply(ah); 4406250003Sadrian if(!AR_SREV_WASP(ah)) 4407250003Sadrian { 4408250003Sadrian ar9300_tuning_caps_apply(ah); 4409250003Sadrian } 4410250003Sadrian 4411250008Sadrian ar9300_tx_end_to_xpab_off_apply(ah, ichan->channel); 4412250003Sadrian 4413250003Sadrian return AH_TRUE; 4414250003Sadrian} 4415250003Sadrian 4416250003Sadrianu_int8_t * 4417250003Sadrianar9300_eeprom_get_spur_chans_ptr(struct ath_hal *ah, HAL_BOOL is_2ghz) 4418250003Sadrian{ 4419250003Sadrian ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom; 4420250003Sadrian 4421250003Sadrian if (is_2ghz) { 4422250003Sadrian return &(eep->modal_header_2g.spur_chans[0]); 4423250003Sadrian } else { 4424250003Sadrian return &(eep->modal_header_5g.spur_chans[0]); 4425250003Sadrian } 4426250003Sadrian} 4427250003Sadrian 4428250003Sadrianstatic u_int8_t ar9300_eeprom_get_tx_gain_table_number_max(struct ath_hal *ah) 4429250003Sadrian{ 4430250003Sadrian unsigned long tx_gain_table_max; 4431250003Sadrian tx_gain_table_max = OS_REG_READ_FIELD(ah, 4432250003Sadrian AR_PHY_TPC_7, AR_PHY_TPC_7_TX_GAIN_TABLE_MAX); 4433250003Sadrian return tx_gain_table_max; 4434250003Sadrian} 4435250003Sadrian 4436250003Sadrianu_int8_t ar9300_eeprom_tx_gain_table_index_max_apply(struct ath_hal *ah, u_int16_t channel) 4437250003Sadrian{ 4438250003Sadrian unsigned int index; 4439250003Sadrian ar9300_eeprom_t *ahp_Eeprom; 4440250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 4441250003Sadrian 4442250003Sadrian ahp_Eeprom = &ahp->ah_eeprom; 4443250003Sadrian 4444250003Sadrian if (ahp_Eeprom->base_ext1.misc_enable == 0) 4445250003Sadrian return AH_FALSE; 4446250003Sadrian 4447250003Sadrian if (channel < 4000) 4448250003Sadrian { 4449250003Sadrian index = ahp_Eeprom->modal_header_2g.tx_gain_cap; 4450250003Sadrian } 4451250003Sadrian else 4452250003Sadrian { 4453250003Sadrian index = ahp_Eeprom->modal_header_5g.tx_gain_cap; 4454250003Sadrian } 4455250003Sadrian 4456250003Sadrian OS_REG_RMW_FIELD(ah, 4457250003Sadrian AR_PHY_TPC_7, AR_PHY_TPC_7_TX_GAIN_TABLE_MAX, index); 4458250003Sadrian return AH_TRUE; 4459250003Sadrian} 4460250003Sadrian 4461250003Sadrianstatic u_int8_t ar9300_eeprom_get_pcdac_tx_gain_table_i(struct ath_hal *ah, 4462250003Sadrian int i, u_int8_t *pcdac) 4463250003Sadrian{ 4464250003Sadrian unsigned long tx_gain; 4465250003Sadrian u_int8_t tx_gain_table_max; 4466250003Sadrian tx_gain_table_max = ar9300_eeprom_get_tx_gain_table_number_max(ah); 4467250003Sadrian if (i <= 0 || i > tx_gain_table_max) { 4468250003Sadrian *pcdac = 0; 4469250003Sadrian return AH_FALSE; 4470250003Sadrian } 4471250003Sadrian 4472250003Sadrian tx_gain = OS_REG_READ(ah, AR_PHY_TXGAIN_TAB(1) + i * 4); 4473250003Sadrian *pcdac = ((tx_gain >> 24) & 0xff); 4474250003Sadrian return AH_TRUE; 4475250003Sadrian} 4476250003Sadrian 4477250003Sadrianu_int8_t ar9300_eeprom_set_tx_gain_cap(struct ath_hal *ah, 4478250003Sadrian int *tx_gain_max) 4479250003Sadrian// pcdac read back from reg, read back value depends on reset 2GHz/5GHz ini 4480250003Sadrian// tx_gain_table, this function will be called twice after each 4481250003Sadrian// band's calibration. 4482250003Sadrian// after 2GHz cal, tx_gain_max[0] has 2GHz, calibration max txgain, 4483250003Sadrian// tx_gain_max[1]=-100 4484250003Sadrian// after 5GHz cal, tx_gain_max[0],tx_gain_max[1] have calibration 4485250003Sadrian// value for both band 4486250003Sadrian// reset is on 5GHz, reg reading from tx_gain_table is for 5GHz, 4487250003Sadrian// so program can't recalculate 2g.tx_gain_cap at this point. 4488250003Sadrian{ 4489250003Sadrian int i = 0, ig, im = 0; 4490250003Sadrian u_int8_t pcdac = 0; 4491250003Sadrian u_int8_t tx_gain_table_max; 4492250003Sadrian ar9300_eeprom_t *ahp_Eeprom; 4493250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 4494250003Sadrian 4495250003Sadrian ahp_Eeprom = &ahp->ah_eeprom; 4496250003Sadrian 4497250003Sadrian if (ahp_Eeprom->base_ext1.misc_enable == 0) 4498250003Sadrian return AH_FALSE; 4499250003Sadrian 4500250003Sadrian tx_gain_table_max = ar9300_eeprom_get_tx_gain_table_number_max(ah); 4501250003Sadrian 4502250003Sadrian for (i = 0; i < 2; i++) { 4503250003Sadrian if (tx_gain_max[i]>-100) { // -100 didn't cal that band. 4504250003Sadrian if ( i== 0) { 4505250003Sadrian if (tx_gain_max[1]>-100) { 4506250003Sadrian continue; 4507250003Sadrian // both band are calibrated, skip 2GHz 2g.tx_gain_cap reset 4508250003Sadrian } 4509250003Sadrian } 4510250003Sadrian for (ig = 1; ig <= tx_gain_table_max; ig++) { 4511250003Sadrian if (ah != 0 && ah->ah_reset != 0) 4512250003Sadrian { 4513250003Sadrian ar9300_eeprom_get_pcdac_tx_gain_table_i(ah, ig, &pcdac); 4514250003Sadrian if (pcdac >= tx_gain_max[i]) 4515250003Sadrian break; 4516250003Sadrian } 4517250003Sadrian } 4518250003Sadrian if (ig+1 <= tx_gain_table_max) { 4519250003Sadrian if (pcdac == tx_gain_max[i]) 4520250003Sadrian im = ig; 4521250003Sadrian else 4522250003Sadrian im = ig + 1; 4523250003Sadrian if (i == 0) { 4524250003Sadrian ahp_Eeprom->modal_header_2g.tx_gain_cap = im; 4525250003Sadrian } else { 4526250003Sadrian ahp_Eeprom->modal_header_5g.tx_gain_cap = im; 4527250003Sadrian } 4528250003Sadrian } else { 4529250003Sadrian if (i == 0) { 4530250003Sadrian ahp_Eeprom->modal_header_2g.tx_gain_cap = ig; 4531250003Sadrian } else { 4532250003Sadrian ahp_Eeprom->modal_header_5g.tx_gain_cap = ig; 4533250003Sadrian } 4534250003Sadrian } 4535250003Sadrian } 4536250003Sadrian } 4537250003Sadrian return AH_TRUE; 4538250003Sadrian} 4539