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 257291437Sadrian if (AR_SREV_HONEYBEE(ah)){ /* no OTP for Honeybee */ 258291437Sadrian return false; 259291437Sadrian } 260250003Sadrian addr = (AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah))? 261250003Sadrian OTP_MEM_START_ADDRESS_WASP : OTP_MEM_START_ADDRESS; 262250003Sadrian if (!is_wifi) { 263250003Sadrian addr = BTOTP_MEM_START_ADDRESS; 264250003Sadrian } 265250003Sadrian addr += off * 4; /* OTP is 32 bit addressable */ 266250003Sadrian (void) OS_REG_READ(ah, addr); 267250003Sadrian 268250003Sadrian addr = (AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) ? 269250003Sadrian OTP_STATUS0_OTP_SM_BUSY_WASP : OTP_STATUS0_OTP_SM_BUSY; 270250003Sadrian if (!is_wifi) { 271250003Sadrian addr = BTOTP_STATUS0_OTP_SM_BUSY; 272250003Sadrian } 273250003Sadrian while ((time_out > 0) && (!status)) { /* wait for access complete */ 274250003Sadrian /* Read data valid, access not busy, sm not busy */ 275250003Sadrian status = ((OS_REG_READ(ah, addr) & 0x7) == 0x4) ? 1 : 0; 276250003Sadrian time_out--; 277250003Sadrian } 278250003Sadrian if (time_out == 0) { 279250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, 280250003Sadrian "%s: Timed out during OTP Status0 validation\n", __func__); 281250003Sadrian return AH_FALSE; 282250003Sadrian } 283250003Sadrian 284250003Sadrian addr = (AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) ? 285250003Sadrian OTP_STATUS1_EFUSE_READ_DATA_WASP : OTP_STATUS1_EFUSE_READ_DATA; 286250003Sadrian if (!is_wifi) { 287250003Sadrian addr = BTOTP_STATUS1_EFUSE_READ_DATA; 288250003Sadrian } 289250003Sadrian *data = OS_REG_READ(ah, addr); 290250003Sadrian return AH_TRUE; 291250003Sadrian} 292250003Sadrian 293250003Sadrian 294250003Sadrian 295250003Sadrian 296250003Sadrianstatic HAL_STATUS 297250003Sadrianar9300_flash_map(struct ath_hal *ah) 298250003Sadrian{ 299250008Sadrian /* XXX disable flash remapping for now (ie, SoC support) */ 300250008Sadrian ath_hal_printf(ah, "%s: unimplemented for now\n", __func__); 301250008Sadrian#if 0 302250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 303250003Sadrian#if defined(AR9100) || defined(__NetBSD__) 304250003Sadrian ahp->ah_cal_mem = OS_REMAP(ah, AR9300_EEPROM_START_ADDR, AR9300_EEPROM_MAX); 305250003Sadrian#else 306250003Sadrian ahp->ah_cal_mem = OS_REMAP((uintptr_t)(AH_PRIVATE(ah)->ah_st), 307250003Sadrian (AR9300_EEPROM_MAX + AR9300_FLASH_CAL_START_OFFSET)); 308250003Sadrian#endif 309250003Sadrian if (!ahp->ah_cal_mem) { 310250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, 311250003Sadrian "%s: cannot remap eeprom region \n", __func__); 312250003Sadrian return HAL_EIO; 313250003Sadrian } 314250008Sadrian#endif 315250003Sadrian return HAL_OK; 316250003Sadrian} 317250003Sadrian 318250003SadrianHAL_BOOL 319250003Sadrianar9300_flash_read(struct ath_hal *ah, u_int off, u_int16_t *data) 320250003Sadrian{ 321250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 322250003Sadrian 323250003Sadrian *data = ((u_int16_t *)ahp->ah_cal_mem)[off]; 324250003Sadrian return AH_TRUE; 325250003Sadrian} 326250003Sadrian 327250003SadrianHAL_BOOL 328250003Sadrianar9300_flash_write(struct ath_hal *ah, u_int off, u_int16_t data) 329250003Sadrian{ 330250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 331250003Sadrian 332250003Sadrian ((u_int16_t *)ahp->ah_cal_mem)[off] = data; 333250003Sadrian return AH_TRUE; 334250003Sadrian} 335250003Sadrian 336250003SadrianHAL_STATUS 337250003Sadrianar9300_eeprom_attach(struct ath_hal *ah) 338250003Sadrian{ 339250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 340250003Sadrian ahp->try_dram = 1; 341250003Sadrian ahp->try_eeprom = 1; 342250003Sadrian ahp->try_otp = 1; 343250003Sadrian#ifdef ATH_CAL_NAND_FLASH 344250003Sadrian ahp->try_nand = 1; 345250003Sadrian#else 346250003Sadrian ahp->try_flash = 1; 347250003Sadrian#endif 348250003Sadrian ahp->calibration_data_source = calibration_data_none; 349250003Sadrian ahp->calibration_data_source_address = 0; 350250003Sadrian ahp->calibration_data_try = calibration_data_try; 351250003Sadrian ahp->calibration_data_try_address = 0; 352250003Sadrian 353250003Sadrian /* 354250003Sadrian * In case flash will be used for EEPROM. Otherwise ahp->ah_cal_mem 355250003Sadrian * must be set to NULL or the real EEPROM address. 356250003Sadrian */ 357250003Sadrian ar9300_flash_map(ah); 358250003Sadrian /* 359250003Sadrian * ###### This function always return NO SPUR. 360291437Sadrian * This is not true for many board designs. 361250003Sadrian * Does anyone use this? 362250003Sadrian */ 363250008Sadrian AH_PRIVATE(ah)->ah_getSpurChan = ar9300_eeprom_get_spur_chan; 364250003Sadrian 365250003Sadrian#ifdef OLDCODE 366250003Sadrian /* XXX Needs to be moved for dynamic selection */ 367250003Sadrian ahp->ah_eeprom = *(default9300[ar9300_eeprom_template_default]); 368250003Sadrian 369250003Sadrian 370250003Sadrian if (AR_SREV_HORNET(ah)) { 371250003Sadrian /* Set default values for Hornet. */ 372250003Sadrian ahp->ah_eeprom.base_eep_header.op_cap_flags.op_flags = 373250003Sadrian AR9300_OPFLAGS_11G; 374250003Sadrian ahp->ah_eeprom.base_eep_header.txrx_mask = 0x11; 375250003Sadrian } else if (AR_SREV_POSEIDON(ah)) { 376250003Sadrian /* Set default values for Poseidon. */ 377250003Sadrian ahp->ah_eeprom.base_eep_header.op_cap_flags.op_flags = 378250003Sadrian AR9300_OPFLAGS_11G; 379250003Sadrian ahp->ah_eeprom.base_eep_header.txrx_mask = 0x11; 380250003Sadrian } 381250003Sadrian 382250003Sadrian if (AH_PRIVATE(ah)->ah_config.ath_hal_skip_eeprom_read) { 383250003Sadrian ahp->ah_emu_eeprom = 1; 384250003Sadrian return HAL_OK; 385250003Sadrian } 386250003Sadrian 387250003Sadrian ahp->ah_emu_eeprom = 1; 388250003Sadrian 389250003Sadrian#ifdef UNUSED 390250003Sadrian#endif 391250003Sadrian 392250003Sadrian if (!ar9300_fill_eeprom(ah)) { 393250003Sadrian return HAL_EIO; 394250003Sadrian } 395250003Sadrian 396250003Sadrian return HAL_OK; 397250003Sadrian /* return ar9300_check_eeprom(ah); */ 398250003Sadrian#else 399250003Sadrian ahp->ah_emu_eeprom = 1; 400250003Sadrian 401250003Sadrian#if 0 402250003Sadrian/*#ifdef MDK_AP*/ /* MDK_AP is defined only in NART AP build */ 403250003Sadrian u_int8_t buffer[10]; 404250003Sadrian int caldata_check = 0; 405250003Sadrian 406250003Sadrian ar9300_calibration_data_read_flash( 407250003Sadrian ah, FLASH_BASE_CALDATA_OFFSET, buffer, 4); 408250003Sadrian printf("flash caldata:: %x\n", buffer[0]); 409250003Sadrian if (buffer[0] != 0xff) { 410250003Sadrian caldata_check = 1; 411250003Sadrian } 412250003Sadrian if (!caldata_check) { 413250003Sadrian ar9300_eeprom_t *mptr; 414250003Sadrian int mdata_size; 415250003Sadrian if (AR_SREV_HORNET(ah)) { 416250003Sadrian /* XXX: For initial testing */ 417250003Sadrian mptr = &ahp->ah_eeprom; 418250003Sadrian mdata_size = ar9300_eeprom_struct_size(); 419250003Sadrian ahp->ah_eeprom = ar9300_template_ap121; 420250003Sadrian ahp->ah_emu_eeprom = 1; 421250003Sadrian /* need it to let art save in to flash ????? */ 422250003Sadrian calibration_data_source = calibration_data_flash; 423250003Sadrian } else if (AR_SREV_WASP(ah)) { 424250003Sadrian /* XXX: For initial testing */ 425250003Sadrian ath_hal_printf(ah, " wasp eep attach\n"); 426250003Sadrian mptr = &ahp->ah_eeprom; 427250003Sadrian mdata_size = ar9300_eeprom_struct_size(); 428250003Sadrian ahp->ah_eeprom = ar9300_template_generic; 429250003Sadrian ahp->ah_eeprom.mac_addr[0] = 0x00; 430250003Sadrian ahp->ah_eeprom.mac_addr[1] = 0x03; 431250003Sadrian ahp->ah_eeprom.mac_addr[2] = 0x7F; 432250003Sadrian ahp->ah_eeprom.mac_addr[3] = 0xBA; 433250003Sadrian ahp->ah_eeprom.mac_addr[4] = 0xD0; 434250003Sadrian ahp->ah_eeprom.mac_addr[5] = 0x00; 435250003Sadrian ahp->ah_emu_eeprom = 1; 436250003Sadrian ahp->ah_eeprom.base_eep_header.txrx_mask = 0x33; 437250003Sadrian ahp->ah_eeprom.base_eep_header.txrxgain = 0x10; 438250003Sadrian /* need it to let art save in to flash ????? */ 439250003Sadrian calibration_data_source = calibration_data_flash; 440250003Sadrian } 441250003Sadrian return HAL_OK; 442250003Sadrian } 443250003Sadrian#endif 444291437Sadrian if (AR_SREV_HORNET(ah) || AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah) 445291437Sadrian || AR_SREV_HONEYBEE(ah)) { 446250003Sadrian ahp->try_eeprom = 0; 447250003Sadrian } 448250003Sadrian 449291437Sadrian if (AR_SREV_HONEYBEE(ah)) { 450291437Sadrian ahp->try_otp = 0; 451291437Sadrian } 452291437Sadrian 453250003Sadrian if (!ar9300_eeprom_restore(ah)) { 454250003Sadrian return HAL_EIO; 455250003Sadrian } 456250003Sadrian return HAL_OK; 457250003Sadrian#endif 458250003Sadrian} 459250003Sadrian 460250003Sadrianu_int32_t 461250003Sadrianar9300_eeprom_get(struct ath_hal_9300 *ahp, EEPROM_PARAM param) 462250003Sadrian{ 463250003Sadrian ar9300_eeprom_t *eep = &ahp->ah_eeprom; 464250003Sadrian OSPREY_BASE_EEP_HEADER *p_base = &eep->base_eep_header; 465250003Sadrian OSPREY_BASE_EXTENSION_1 *base_ext1 = &eep->base_ext1; 466250003Sadrian 467250003Sadrian switch (param) { 468250008Sadrian#ifdef NOTYET 469250003Sadrian case EEP_NFTHRESH_5: 470250003Sadrian return p_modal[0].noise_floor_thresh_ch[0]; 471250003Sadrian case EEP_NFTHRESH_2: 472250003Sadrian return p_modal[1].noise_floor_thresh_ch[0]; 473250003Sadrian#endif 474250003Sadrian case EEP_MAC_LSW: 475250003Sadrian return eep->mac_addr[0] << 8 | eep->mac_addr[1]; 476250003Sadrian case EEP_MAC_MID: 477250003Sadrian return eep->mac_addr[2] << 8 | eep->mac_addr[3]; 478250003Sadrian case EEP_MAC_MSW: 479250003Sadrian return eep->mac_addr[4] << 8 | eep->mac_addr[5]; 480250003Sadrian case EEP_REG_0: 481250003Sadrian return p_base->reg_dmn[0]; 482250003Sadrian case EEP_REG_1: 483250003Sadrian return p_base->reg_dmn[1]; 484250003Sadrian case EEP_OP_CAP: 485250003Sadrian return p_base->device_cap; 486250003Sadrian case EEP_OP_MODE: 487250003Sadrian return p_base->op_cap_flags.op_flags; 488250003Sadrian case EEP_RF_SILENT: 489250003Sadrian return p_base->rf_silent; 490250008Sadrian#ifdef NOTYET 491250003Sadrian case EEP_OB_5: 492250003Sadrian return p_modal[0].ob; 493250003Sadrian case EEP_DB_5: 494250003Sadrian return p_modal[0].db; 495250003Sadrian case EEP_OB_2: 496250003Sadrian return p_modal[1].ob; 497250003Sadrian case EEP_DB_2: 498250003Sadrian return p_modal[1].db; 499250003Sadrian case EEP_MINOR_REV: 500250003Sadrian return p_base->eeprom_version & AR9300_EEP_VER_MINOR_MASK; 501250003Sadrian#endif 502250003Sadrian case EEP_TX_MASK: 503250003Sadrian return (p_base->txrx_mask >> 4) & 0xf; 504250003Sadrian case EEP_RX_MASK: 505250003Sadrian return p_base->txrx_mask & 0xf; 506250008Sadrian#ifdef NOTYET 507250003Sadrian case EEP_FSTCLK_5G: 508250003Sadrian return p_base->fast_clk5g; 509250003Sadrian case EEP_RXGAIN_TYPE: 510250003Sadrian return p_base->rx_gain_type; 511250003Sadrian#endif 512250003Sadrian case EEP_DRIVE_STRENGTH: 513250003Sadrian#define AR9300_EEP_BASE_DRIVE_STRENGTH 0x1 514250003Sadrian return p_base->misc_configuration & AR9300_EEP_BASE_DRIVE_STRENGTH; 515250003Sadrian case EEP_INTERNAL_REGULATOR: 516250003Sadrian /* Bit 4 is internal regulator flag */ 517250003Sadrian return ((p_base->feature_enable & 0x10) >> 4); 518250003Sadrian case EEP_SWREG: 519250003Sadrian return (p_base->swreg); 520250003Sadrian case EEP_PAPRD_ENABLED: 521250003Sadrian /* Bit 5 is paprd flag */ 522250003Sadrian return ((p_base->feature_enable & 0x20) >> 5); 523250003Sadrian case EEP_ANTDIV_control: 524250003Sadrian return (u_int32_t)(base_ext1->ant_div_control); 525250003Sadrian case EEP_CHAIN_MASK_REDUCE: 526250003Sadrian return ((p_base->misc_configuration >> 3) & 0x1); 527250003Sadrian case EEP_OL_PWRCTRL: 528250003Sadrian return 0; 529250003Sadrian case EEP_DEV_TYPE: 530250003Sadrian return p_base->device_type; 531250003Sadrian default: 532250003Sadrian HALASSERT(0); 533250003Sadrian return 0; 534250003Sadrian } 535250003Sadrian} 536250003Sadrian 537250003Sadrian 538250003Sadrian 539250003Sadrian/******************************************************************************/ 540250003Sadrian/*! 541250003Sadrian** \brief EEPROM fixup code for INI values 542250003Sadrian** 543250003Sadrian** This routine provides a place to insert "fixup" code for specific devices 544250003Sadrian** that need to modify INI values based on EEPROM values, BEFORE the INI values 545250003Sadrian** are written. 546250003Sadrian** Certain registers in the INI file can only be written once without 547250003Sadrian** undesired side effects, and this provides a place for EEPROM overrides 548250003Sadrian** in these cases. 549250003Sadrian** 550250003Sadrian** This is called at attach time once. It should not affect run time 551250003Sadrian** performance at all 552250003Sadrian** 553250003Sadrian** \param ah Pointer to HAL object (this) 554250003Sadrian** \param p_eep_data Pointer to (filled in) eeprom data structure 555250003Sadrian** \param reg register being inspected on this call 556250003Sadrian** \param value value in INI file 557250003Sadrian** 558250003Sadrian** \return Updated value for INI file. 559250003Sadrian*/ 560250003Sadrianu_int32_t 561250003Sadrianar9300_ini_fixup(struct ath_hal *ah, ar9300_eeprom_t *p_eep_data, 562250003Sadrian u_int32_t reg, u_int32_t value) 563250003Sadrian{ 564250003Sadrian HALDEBUG(AH_NULL, HAL_DEBUG_UNMASKABLE, 565250003Sadrian "ar9300_eeprom_def_ini_fixup: FIXME\n"); 566250003Sadrian#if 0 567250003Sadrian BASE_EEPDEF_HEADER *p_base = &(p_eep_data->base_eep_header); 568250003Sadrian 569250003Sadrian switch (AH_PRIVATE(ah)->ah_devid) 570250003Sadrian { 571250003Sadrian case AR9300_DEVID_AR9300_PCI: 572250003Sadrian /* 573250003Sadrian ** Need to set the external/internal regulator bit to the proper value. 574250003Sadrian ** Can only write this ONCE. 575250003Sadrian */ 576250003Sadrian 577250003Sadrian if ( reg == 0x7894 ) 578250003Sadrian { 579250003Sadrian /* 580250003Sadrian ** Check for an EEPROM data structure of "0x0b" or better 581250003Sadrian */ 582250003Sadrian 583250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, "ini VAL: %x EEPROM: %x\n", 584250003Sadrian value, (p_base->version & 0xff)); 585250003Sadrian 586250003Sadrian if ( (p_base->version & 0xff) > 0x0a) { 587250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, 588250003Sadrian "PWDCLKIND: %d\n", p_base->pwdclkind); 589250003Sadrian value &= ~AR_AN_TOP2_PWDCLKIND; 590250003Sadrian value |= 591250003Sadrian AR_AN_TOP2_PWDCLKIND & 592250003Sadrian (p_base->pwdclkind << AR_AN_TOP2_PWDCLKIND_S); 593250003Sadrian } else { 594250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, "PWDCLKIND Earlier Rev\n"); 595250003Sadrian } 596250003Sadrian 597250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, "final ini VAL: %x\n", value); 598250003Sadrian } 599250003Sadrian break; 600250003Sadrian 601250003Sadrian } 602250003Sadrian 603250003Sadrian return (value); 604250003Sadrian#else 605250003Sadrian return 0; 606250003Sadrian#endif 607250003Sadrian} 608250003Sadrian 609250003Sadrian/* 610250003Sadrian * Returns the interpolated y value corresponding to the specified x value 611250003Sadrian * from the np ordered pairs of data (px,py). 612250003Sadrian * The pairs do not have to be in any order. 613250003Sadrian * If the specified x value is less than any of the px, 614250003Sadrian * the returned y value is equal to the py for the lowest px. 615250003Sadrian * If the specified x value is greater than any of the px, 616250003Sadrian * the returned y value is equal to the py for the highest px. 617250003Sadrian */ 618250003Sadrianstatic int 619250003Sadrianinterpolate(int32_t x, int32_t *px, int32_t *py, u_int16_t np) 620250003Sadrian{ 621250003Sadrian int ip = 0; 622250003Sadrian int lx = 0, ly = 0, lhave = 0; 623250003Sadrian int hx = 0, hy = 0, hhave = 0; 624250003Sadrian int dx = 0; 625250003Sadrian int y = 0; 626250003Sadrian int bf, factor, plus; 627250003Sadrian 628250003Sadrian lhave = 0; 629250003Sadrian hhave = 0; 630250003Sadrian /* 631250003Sadrian * identify best lower and higher x calibration measurement 632250003Sadrian */ 633250003Sadrian for (ip = 0; ip < np; ip++) { 634250003Sadrian dx = x - px[ip]; 635250003Sadrian /* this measurement is higher than our desired x */ 636250003Sadrian if (dx <= 0) { 637250003Sadrian if (!hhave || dx > (x - hx)) { 638250003Sadrian /* new best higher x measurement */ 639250003Sadrian hx = px[ip]; 640250003Sadrian hy = py[ip]; 641250003Sadrian hhave = 1; 642250003Sadrian } 643250003Sadrian } 644250003Sadrian /* this measurement is lower than our desired x */ 645250003Sadrian if (dx >= 0) { 646250003Sadrian if (!lhave || dx < (x - lx)) { 647250003Sadrian /* new best lower x measurement */ 648250003Sadrian lx = px[ip]; 649250003Sadrian ly = py[ip]; 650250003Sadrian lhave = 1; 651250003Sadrian } 652250003Sadrian } 653250003Sadrian } 654250003Sadrian /* the low x is good */ 655250003Sadrian if (lhave) { 656250003Sadrian /* so is the high x */ 657250003Sadrian if (hhave) { 658250003Sadrian /* they're the same, so just pick one */ 659250003Sadrian if (hx == lx) { 660250003Sadrian y = ly; 661250003Sadrian } else { 662250003Sadrian /* interpolate with round off */ 663250003Sadrian bf = (2 * (hy - ly) * (x - lx)) / (hx - lx); 664250003Sadrian plus = (bf % 2); 665250003Sadrian factor = bf / 2; 666250003Sadrian y = ly + factor + plus; 667250003Sadrian } 668250003Sadrian } else { 669250003Sadrian /* only low is good, use it */ 670250003Sadrian y = ly; 671250003Sadrian } 672250003Sadrian } else if (hhave) { 673250003Sadrian /* only high is good, use it */ 674250003Sadrian y = hy; 675250003Sadrian } else { 676250003Sadrian /* nothing is good,this should never happen unless np=0, ???? */ 677250003Sadrian y = -(1 << 30); 678250003Sadrian } 679250003Sadrian 680250003Sadrian return y; 681250003Sadrian} 682250003Sadrian 683250003Sadrianu_int8_t 684250003Sadrianar9300_eeprom_get_legacy_trgt_pwr(struct ath_hal *ah, u_int16_t rate_index, 685250003Sadrian u_int16_t freq, HAL_BOOL is_2ghz) 686250003Sadrian{ 687250003Sadrian u_int16_t num_piers, i; 688250003Sadrian int32_t target_power_array[OSPREY_NUM_5G_20_TARGET_POWERS]; 689250003Sadrian int32_t freq_array[OSPREY_NUM_5G_20_TARGET_POWERS]; 690250003Sadrian u_int8_t *p_freq_bin; 691250003Sadrian ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom; 692250003Sadrian CAL_TARGET_POWER_LEG *p_eeprom_target_pwr; 693250003Sadrian 694250003Sadrian if (is_2ghz) { 695250003Sadrian num_piers = OSPREY_NUM_2G_20_TARGET_POWERS; 696250003Sadrian p_eeprom_target_pwr = eep->cal_target_power_2g; 697250003Sadrian p_freq_bin = eep->cal_target_freqbin_2g; 698250003Sadrian } else { 699250003Sadrian num_piers = OSPREY_NUM_5G_20_TARGET_POWERS; 700250003Sadrian p_eeprom_target_pwr = eep->cal_target_power_5g; 701250003Sadrian p_freq_bin = eep->cal_target_freqbin_5g; 702250003Sadrian } 703250003Sadrian 704250003Sadrian /* 705250003Sadrian * create array of channels and targetpower from 706250003Sadrian * targetpower piers stored on eeprom 707250003Sadrian */ 708250003Sadrian for (i = 0; i < num_piers; i++) { 709250003Sadrian freq_array[i] = FBIN2FREQ(p_freq_bin[i], is_2ghz); 710250003Sadrian target_power_array[i] = p_eeprom_target_pwr[i].t_pow2x[rate_index]; 711250003Sadrian } 712250003Sadrian 713250003Sadrian /* interpolate to get target power for given frequency */ 714250003Sadrian return 715250003Sadrian ((u_int8_t)interpolate( 716250003Sadrian (int32_t)freq, freq_array, target_power_array, num_piers)); 717250003Sadrian} 718250003Sadrian 719250003Sadrianu_int8_t 720250003Sadrianar9300_eeprom_get_ht20_trgt_pwr(struct ath_hal *ah, u_int16_t rate_index, 721250003Sadrian u_int16_t freq, HAL_BOOL is_2ghz) 722250003Sadrian{ 723250003Sadrian u_int16_t num_piers, i; 724250003Sadrian int32_t target_power_array[OSPREY_NUM_5G_20_TARGET_POWERS]; 725250003Sadrian int32_t freq_array[OSPREY_NUM_5G_20_TARGET_POWERS]; 726250003Sadrian u_int8_t *p_freq_bin; 727250003Sadrian ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom; 728250003Sadrian OSP_CAL_TARGET_POWER_HT *p_eeprom_target_pwr; 729250003Sadrian 730250003Sadrian if (is_2ghz) { 731250003Sadrian num_piers = OSPREY_NUM_2G_20_TARGET_POWERS; 732250003Sadrian p_eeprom_target_pwr = eep->cal_target_power_2g_ht20; 733250003Sadrian p_freq_bin = eep->cal_target_freqbin_2g_ht20; 734250003Sadrian } else { 735250003Sadrian num_piers = OSPREY_NUM_5G_20_TARGET_POWERS; 736250003Sadrian p_eeprom_target_pwr = eep->cal_target_power_5g_ht20; 737250003Sadrian p_freq_bin = eep->cal_target_freqbin_5g_ht20; 738250003Sadrian } 739250003Sadrian 740250003Sadrian /* 741250003Sadrian * create array of channels and targetpower from 742250003Sadrian * targetpower piers stored on eeprom 743250003Sadrian */ 744250003Sadrian for (i = 0; i < num_piers; i++) { 745250003Sadrian freq_array[i] = FBIN2FREQ(p_freq_bin[i], is_2ghz); 746250003Sadrian target_power_array[i] = p_eeprom_target_pwr[i].t_pow2x[rate_index]; 747250003Sadrian } 748250003Sadrian 749250003Sadrian /* interpolate to get target power for given frequency */ 750250003Sadrian return 751250003Sadrian ((u_int8_t)interpolate( 752250003Sadrian (int32_t)freq, freq_array, target_power_array, num_piers)); 753250003Sadrian} 754250003Sadrian 755250003Sadrianu_int8_t 756250003Sadrianar9300_eeprom_get_ht40_trgt_pwr(struct ath_hal *ah, u_int16_t rate_index, 757250003Sadrian u_int16_t freq, HAL_BOOL is_2ghz) 758250003Sadrian{ 759250003Sadrian u_int16_t num_piers, i; 760250003Sadrian int32_t target_power_array[OSPREY_NUM_5G_40_TARGET_POWERS]; 761250003Sadrian int32_t freq_array[OSPREY_NUM_5G_40_TARGET_POWERS]; 762250003Sadrian u_int8_t *p_freq_bin; 763250003Sadrian ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom; 764250003Sadrian OSP_CAL_TARGET_POWER_HT *p_eeprom_target_pwr; 765250003Sadrian 766250003Sadrian if (is_2ghz) { 767250003Sadrian num_piers = OSPREY_NUM_2G_40_TARGET_POWERS; 768250003Sadrian p_eeprom_target_pwr = eep->cal_target_power_2g_ht40; 769250003Sadrian p_freq_bin = eep->cal_target_freqbin_2g_ht40; 770250003Sadrian } else { 771250003Sadrian num_piers = OSPREY_NUM_5G_40_TARGET_POWERS; 772250003Sadrian p_eeprom_target_pwr = eep->cal_target_power_5g_ht40; 773250003Sadrian p_freq_bin = eep->cal_target_freqbin_5g_ht40; 774250003Sadrian } 775250003Sadrian 776250003Sadrian /* 777250003Sadrian * create array of channels and targetpower from 778250003Sadrian * targetpower piers stored on eeprom 779250003Sadrian */ 780250003Sadrian for (i = 0; i < num_piers; i++) { 781250003Sadrian freq_array[i] = FBIN2FREQ(p_freq_bin[i], is_2ghz); 782250003Sadrian target_power_array[i] = p_eeprom_target_pwr[i].t_pow2x[rate_index]; 783250003Sadrian } 784250003Sadrian 785250003Sadrian /* interpolate to get target power for given frequency */ 786250003Sadrian return 787250003Sadrian ((u_int8_t)interpolate( 788250003Sadrian (int32_t)freq, freq_array, target_power_array, num_piers)); 789250003Sadrian} 790250003Sadrian 791250003Sadrianu_int8_t 792250003Sadrianar9300_eeprom_get_cck_trgt_pwr(struct ath_hal *ah, u_int16_t rate_index, 793250003Sadrian u_int16_t freq) 794250003Sadrian{ 795250003Sadrian u_int16_t num_piers = OSPREY_NUM_2G_CCK_TARGET_POWERS, i; 796250003Sadrian int32_t target_power_array[OSPREY_NUM_2G_CCK_TARGET_POWERS]; 797250003Sadrian int32_t freq_array[OSPREY_NUM_2G_CCK_TARGET_POWERS]; 798250003Sadrian ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom; 799250003Sadrian u_int8_t *p_freq_bin = eep->cal_target_freqbin_cck; 800250003Sadrian CAL_TARGET_POWER_LEG *p_eeprom_target_pwr = eep->cal_target_power_cck; 801250003Sadrian 802250003Sadrian /* 803250003Sadrian * create array of channels and targetpower from 804250003Sadrian * targetpower piers stored on eeprom 805250003Sadrian */ 806250003Sadrian for (i = 0; i < num_piers; i++) { 807250003Sadrian freq_array[i] = FBIN2FREQ(p_freq_bin[i], 1); 808250003Sadrian target_power_array[i] = p_eeprom_target_pwr[i].t_pow2x[rate_index]; 809250003Sadrian } 810250003Sadrian 811250003Sadrian /* interpolate to get target power for given frequency */ 812250003Sadrian return 813250003Sadrian ((u_int8_t)interpolate( 814250003Sadrian (int32_t)freq, freq_array, target_power_array, num_piers)); 815250003Sadrian} 816250003Sadrian 817250003Sadrian/* 818250003Sadrian * Set tx power registers to array of values passed in 819250003Sadrian */ 820250003Sadrianint 821250003Sadrianar9300_transmit_power_reg_write(struct ath_hal *ah, u_int8_t *p_pwr_array) 822250003Sadrian{ 823250003Sadrian#define POW_SM(_r, _s) (((_r) & 0x3f) << (_s)) 824250003Sadrian /* make sure forced gain is not set */ 825250003Sadrian#if 0 826250003Sadrian field_write("force_dac_gain", 0); 827250003Sadrian OS_REG_WRITE(ah, 0xa3f8, 0); 828250003Sadrian field_write("force_tx_gain", 0); 829250003Sadrian#endif 830250003Sadrian 831250003Sadrian OS_REG_WRITE(ah, 0xa458, 0); 832250003Sadrian 833250003Sadrian /* Write the OFDM power per rate set */ 834250003Sadrian /* 6 (LSB), 9, 12, 18 (MSB) */ 835250003Sadrian OS_REG_WRITE(ah, 0xa3c0, 836250003Sadrian POW_SM(p_pwr_array[ALL_TARGET_LEGACY_6_24], 24) 837250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_LEGACY_6_24], 16) 838250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_LEGACY_6_24], 8) 839250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_LEGACY_6_24], 0) 840250003Sadrian ); 841250003Sadrian /* 24 (LSB), 36, 48, 54 (MSB) */ 842250003Sadrian OS_REG_WRITE(ah, 0xa3c4, 843250003Sadrian POW_SM(p_pwr_array[ALL_TARGET_LEGACY_54], 24) 844250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_LEGACY_48], 16) 845250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_LEGACY_36], 8) 846250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_LEGACY_6_24], 0) 847250003Sadrian ); 848250003Sadrian 849250003Sadrian /* Write the CCK power per rate set */ 850250003Sadrian /* 1L (LSB), reserved, 2L, 2S (MSB) */ 851250003Sadrian OS_REG_WRITE(ah, 0xa3c8, 852250003Sadrian POW_SM(p_pwr_array[ALL_TARGET_LEGACY_1L_5L], 24) 853250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_LEGACY_1L_5L], 16) 854250003Sadrian/* | POW_SM(tx_power_times2, 8)*/ /* this is reserved for Osprey */ 855250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_LEGACY_1L_5L], 0) 856250003Sadrian ); 857250003Sadrian /* 5.5L (LSB), 5.5S, 11L, 11S (MSB) */ 858250003Sadrian OS_REG_WRITE(ah, 0xa3cc, 859250003Sadrian POW_SM(p_pwr_array[ALL_TARGET_LEGACY_11S], 24) 860250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_LEGACY_11L], 16) 861250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_LEGACY_5S], 8) 862250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_LEGACY_1L_5L], 0) 863250003Sadrian ); 864250003Sadrian 865250003Sadrian /* write the power for duplicated frames - HT40 */ 866250003Sadrian /* dup40_cck (LSB), dup40_ofdm, ext20_cck, ext20_ofdm (MSB) */ 867250003Sadrian OS_REG_WRITE(ah, 0xa3e0, 868250003Sadrian POW_SM(p_pwr_array[ALL_TARGET_LEGACY_6_24], 24) 869250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_LEGACY_1L_5L], 16) 870250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_LEGACY_6_24], 8) 871250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_LEGACY_1L_5L], 0) 872250003Sadrian ); 873250003Sadrian 874250003Sadrian /* Write the HT20 power per rate set */ 875250003Sadrian /* 0/8/16 (LSB), 1-3/9-11/17-19, 4, 5 (MSB) */ 876250003Sadrian OS_REG_WRITE(ah, 0xa3d0, 877250003Sadrian POW_SM(p_pwr_array[ALL_TARGET_HT20_5], 24) 878250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_HT20_4], 16) 879250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_HT20_1_3_9_11_17_19], 8) 880250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_HT20_0_8_16], 0) 881250003Sadrian ); 882250003Sadrian 883250003Sadrian /* 6 (LSB), 7, 12, 13 (MSB) */ 884250003Sadrian OS_REG_WRITE(ah, 0xa3d4, 885250003Sadrian POW_SM(p_pwr_array[ALL_TARGET_HT20_13], 24) 886250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_HT20_12], 16) 887250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_HT20_7], 8) 888250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_HT20_6], 0) 889250003Sadrian ); 890250003Sadrian 891250003Sadrian /* 14 (LSB), 15, 20, 21 */ 892250003Sadrian OS_REG_WRITE(ah, 0xa3e4, 893250003Sadrian POW_SM(p_pwr_array[ALL_TARGET_HT20_21], 24) 894250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_HT20_20], 16) 895250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_HT20_15], 8) 896250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_HT20_14], 0) 897250003Sadrian ); 898250003Sadrian 899250003Sadrian /* Mixed HT20 and HT40 rates */ 900250003Sadrian /* HT20 22 (LSB), HT20 23, HT40 22, HT40 23 (MSB) */ 901250003Sadrian OS_REG_WRITE(ah, 0xa3e8, 902250003Sadrian POW_SM(p_pwr_array[ALL_TARGET_HT40_23], 24) 903250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_HT40_22], 16) 904250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_HT20_23], 8) 905250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_HT20_22], 0) 906250003Sadrian ); 907250003Sadrian 908250003Sadrian /* Write the HT40 power per rate set */ 909250003Sadrian /* correct PAR difference between HT40 and HT20/LEGACY */ 910250003Sadrian /* 0/8/16 (LSB), 1-3/9-11/17-19, 4, 5 (MSB) */ 911250003Sadrian OS_REG_WRITE(ah, 0xa3d8, 912250003Sadrian POW_SM(p_pwr_array[ALL_TARGET_HT40_5], 24) 913250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_HT40_4], 16) 914250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_HT40_1_3_9_11_17_19], 8) 915250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_HT40_0_8_16], 0) 916250003Sadrian ); 917250003Sadrian 918250003Sadrian /* 6 (LSB), 7, 12, 13 (MSB) */ 919250003Sadrian OS_REG_WRITE(ah, 0xa3dc, 920250003Sadrian POW_SM(p_pwr_array[ALL_TARGET_HT40_13], 24) 921250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_HT40_12], 16) 922250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_HT40_7], 8) 923250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_HT40_6], 0) 924250003Sadrian ); 925250003Sadrian 926250003Sadrian /* 14 (LSB), 15, 20, 21 */ 927250003Sadrian OS_REG_WRITE(ah, 0xa3ec, 928250003Sadrian POW_SM(p_pwr_array[ALL_TARGET_HT40_21], 24) 929250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_HT40_20], 16) 930250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_HT40_15], 8) 931250003Sadrian | POW_SM(p_pwr_array[ALL_TARGET_HT40_14], 0) 932250003Sadrian ); 933250003Sadrian 934250003Sadrian return 0; 935250003Sadrian#undef POW_SM 936250003Sadrian} 937250003Sadrian 938250003Sadrianstatic void 939250008Sadrianar9300_selfgen_tpc_reg_write(struct ath_hal *ah, const struct ieee80211_channel *chan, 940250003Sadrian u_int8_t *p_pwr_array) 941250003Sadrian{ 942250003Sadrian u_int32_t tpc_reg_val; 943250003Sadrian 944250003Sadrian /* Set the target power values for self generated frames (ACK,RTS/CTS) to 945250003Sadrian * be within limits. This is just a safety measure.With per packet TPC mode 946250003Sadrian * enabled the target power value used with self generated frames will be 947250003Sadrian * MIN( TPC reg, BB_powertx_rate register) 948250003Sadrian */ 949250003Sadrian 950250008Sadrian if (IEEE80211_IS_CHAN_2GHZ(chan)) { 951250003Sadrian tpc_reg_val = (SM(p_pwr_array[ALL_TARGET_LEGACY_1L_5L], AR_TPC_ACK) | 952250003Sadrian SM(p_pwr_array[ALL_TARGET_LEGACY_1L_5L], AR_TPC_CTS) | 953250003Sadrian SM(0x3f, AR_TPC_CHIRP) | 954250003Sadrian SM(0x3f, AR_TPC_RPT)); 955250003Sadrian } else { 956250003Sadrian tpc_reg_val = (SM(p_pwr_array[ALL_TARGET_LEGACY_6_24], AR_TPC_ACK) | 957250003Sadrian SM(p_pwr_array[ALL_TARGET_LEGACY_6_24], AR_TPC_CTS) | 958250003Sadrian SM(0x3f, AR_TPC_CHIRP) | 959250003Sadrian SM(0x3f, AR_TPC_RPT)); 960250003Sadrian } 961250003Sadrian OS_REG_WRITE(ah, AR_TPC, tpc_reg_val); 962250003Sadrian} 963250003Sadrian 964250003Sadrianvoid 965250003Sadrianar9300_set_target_power_from_eeprom(struct ath_hal *ah, u_int16_t freq, 966250003Sadrian u_int8_t *target_power_val_t2) 967250003Sadrian{ 968250003Sadrian /* hard code for now, need to get from eeprom struct */ 969250003Sadrian u_int8_t ht40_power_inc_for_pdadc = 0; 970250003Sadrian HAL_BOOL is_2ghz = 0; 971250003Sadrian 972250003Sadrian if (freq < 4000) { 973250003Sadrian is_2ghz = 1; 974250003Sadrian } 975250003Sadrian 976250003Sadrian target_power_val_t2[ALL_TARGET_LEGACY_6_24] = 977250003Sadrian ar9300_eeprom_get_legacy_trgt_pwr( 978250003Sadrian ah, LEGACY_TARGET_RATE_6_24, freq, is_2ghz); 979250003Sadrian target_power_val_t2[ALL_TARGET_LEGACY_36] = 980250003Sadrian ar9300_eeprom_get_legacy_trgt_pwr( 981250003Sadrian ah, LEGACY_TARGET_RATE_36, freq, is_2ghz); 982250003Sadrian target_power_val_t2[ALL_TARGET_LEGACY_48] = 983250003Sadrian ar9300_eeprom_get_legacy_trgt_pwr( 984250003Sadrian ah, LEGACY_TARGET_RATE_48, freq, is_2ghz); 985250003Sadrian target_power_val_t2[ALL_TARGET_LEGACY_54] = 986250003Sadrian ar9300_eeprom_get_legacy_trgt_pwr( 987250003Sadrian ah, LEGACY_TARGET_RATE_54, freq, is_2ghz); 988250003Sadrian target_power_val_t2[ALL_TARGET_LEGACY_1L_5L] = 989250003Sadrian ar9300_eeprom_get_cck_trgt_pwr( 990250003Sadrian ah, LEGACY_TARGET_RATE_1L_5L, freq); 991250003Sadrian target_power_val_t2[ALL_TARGET_LEGACY_5S] = 992250003Sadrian ar9300_eeprom_get_cck_trgt_pwr( 993250003Sadrian ah, LEGACY_TARGET_RATE_5S, freq); 994250003Sadrian target_power_val_t2[ALL_TARGET_LEGACY_11L] = 995250003Sadrian ar9300_eeprom_get_cck_trgt_pwr( 996250003Sadrian ah, LEGACY_TARGET_RATE_11L, freq); 997250003Sadrian target_power_val_t2[ALL_TARGET_LEGACY_11S] = 998250003Sadrian ar9300_eeprom_get_cck_trgt_pwr( 999250003Sadrian ah, LEGACY_TARGET_RATE_11S, freq); 1000250003Sadrian target_power_val_t2[ALL_TARGET_HT20_0_8_16] = 1001250003Sadrian ar9300_eeprom_get_ht20_trgt_pwr( 1002250003Sadrian ah, HT_TARGET_RATE_0_8_16, freq, is_2ghz); 1003250003Sadrian target_power_val_t2[ALL_TARGET_HT20_1_3_9_11_17_19] = 1004250003Sadrian ar9300_eeprom_get_ht20_trgt_pwr( 1005250003Sadrian ah, HT_TARGET_RATE_1_3_9_11_17_19, freq, is_2ghz); 1006250003Sadrian target_power_val_t2[ALL_TARGET_HT20_4] = 1007250003Sadrian ar9300_eeprom_get_ht20_trgt_pwr( 1008250003Sadrian ah, HT_TARGET_RATE_4, freq, is_2ghz); 1009250003Sadrian target_power_val_t2[ALL_TARGET_HT20_5] = 1010250003Sadrian ar9300_eeprom_get_ht20_trgt_pwr( 1011250003Sadrian ah, HT_TARGET_RATE_5, freq, is_2ghz); 1012250003Sadrian target_power_val_t2[ALL_TARGET_HT20_6] = 1013250003Sadrian ar9300_eeprom_get_ht20_trgt_pwr( 1014250003Sadrian ah, HT_TARGET_RATE_6, freq, is_2ghz); 1015250003Sadrian target_power_val_t2[ALL_TARGET_HT20_7] = 1016250003Sadrian ar9300_eeprom_get_ht20_trgt_pwr( 1017250003Sadrian ah, HT_TARGET_RATE_7, freq, is_2ghz); 1018250003Sadrian target_power_val_t2[ALL_TARGET_HT20_12] = 1019250003Sadrian ar9300_eeprom_get_ht20_trgt_pwr( 1020250003Sadrian ah, HT_TARGET_RATE_12, freq, is_2ghz); 1021250003Sadrian target_power_val_t2[ALL_TARGET_HT20_13] = 1022250003Sadrian ar9300_eeprom_get_ht20_trgt_pwr( 1023250003Sadrian ah, HT_TARGET_RATE_13, freq, is_2ghz); 1024250003Sadrian target_power_val_t2[ALL_TARGET_HT20_14] = 1025250003Sadrian ar9300_eeprom_get_ht20_trgt_pwr( 1026250003Sadrian ah, HT_TARGET_RATE_14, freq, is_2ghz); 1027250003Sadrian target_power_val_t2[ALL_TARGET_HT20_15] = 1028250003Sadrian ar9300_eeprom_get_ht20_trgt_pwr( 1029250003Sadrian ah, HT_TARGET_RATE_15, freq, is_2ghz); 1030250003Sadrian target_power_val_t2[ALL_TARGET_HT20_20] = 1031250003Sadrian ar9300_eeprom_get_ht20_trgt_pwr( 1032250003Sadrian ah, HT_TARGET_RATE_20, freq, is_2ghz); 1033250003Sadrian target_power_val_t2[ALL_TARGET_HT20_21] = 1034250003Sadrian ar9300_eeprom_get_ht20_trgt_pwr( 1035250003Sadrian ah, HT_TARGET_RATE_21, freq, is_2ghz); 1036250003Sadrian target_power_val_t2[ALL_TARGET_HT20_22] = 1037250003Sadrian ar9300_eeprom_get_ht20_trgt_pwr( 1038250003Sadrian ah, HT_TARGET_RATE_22, freq, is_2ghz); 1039250003Sadrian target_power_val_t2[ALL_TARGET_HT20_23] = 1040250003Sadrian ar9300_eeprom_get_ht20_trgt_pwr( 1041250003Sadrian ah, HT_TARGET_RATE_23, freq, is_2ghz); 1042250003Sadrian target_power_val_t2[ALL_TARGET_HT40_0_8_16] = 1043250003Sadrian ar9300_eeprom_get_ht40_trgt_pwr( 1044250003Sadrian ah, HT_TARGET_RATE_0_8_16, freq, is_2ghz) + 1045250003Sadrian ht40_power_inc_for_pdadc; 1046250003Sadrian target_power_val_t2[ALL_TARGET_HT40_1_3_9_11_17_19] = 1047250003Sadrian ar9300_eeprom_get_ht40_trgt_pwr( 1048250003Sadrian ah, HT_TARGET_RATE_1_3_9_11_17_19, freq, is_2ghz) + 1049250003Sadrian ht40_power_inc_for_pdadc; 1050250003Sadrian target_power_val_t2[ALL_TARGET_HT40_4] = 1051250003Sadrian ar9300_eeprom_get_ht40_trgt_pwr( 1052250003Sadrian ah, HT_TARGET_RATE_4, freq, is_2ghz) + ht40_power_inc_for_pdadc; 1053250003Sadrian target_power_val_t2[ALL_TARGET_HT40_5] = 1054250003Sadrian ar9300_eeprom_get_ht40_trgt_pwr( 1055250003Sadrian ah, HT_TARGET_RATE_5, freq, is_2ghz) + ht40_power_inc_for_pdadc; 1056250003Sadrian target_power_val_t2[ALL_TARGET_HT40_6] = 1057250003Sadrian ar9300_eeprom_get_ht40_trgt_pwr( 1058250003Sadrian ah, HT_TARGET_RATE_6, freq, is_2ghz) + ht40_power_inc_for_pdadc; 1059250003Sadrian target_power_val_t2[ALL_TARGET_HT40_7] = 1060250003Sadrian ar9300_eeprom_get_ht40_trgt_pwr( 1061250003Sadrian ah, HT_TARGET_RATE_7, freq, is_2ghz) + ht40_power_inc_for_pdadc; 1062250003Sadrian target_power_val_t2[ALL_TARGET_HT40_12] = 1063250003Sadrian ar9300_eeprom_get_ht40_trgt_pwr( 1064250003Sadrian ah, HT_TARGET_RATE_12, freq, is_2ghz) + ht40_power_inc_for_pdadc; 1065250003Sadrian target_power_val_t2[ALL_TARGET_HT40_13] = 1066250003Sadrian ar9300_eeprom_get_ht40_trgt_pwr( 1067250003Sadrian ah, HT_TARGET_RATE_13, freq, is_2ghz) + ht40_power_inc_for_pdadc; 1068250003Sadrian target_power_val_t2[ALL_TARGET_HT40_14] = 1069250003Sadrian ar9300_eeprom_get_ht40_trgt_pwr( 1070250003Sadrian ah, HT_TARGET_RATE_14, freq, is_2ghz) + ht40_power_inc_for_pdadc; 1071250003Sadrian target_power_val_t2[ALL_TARGET_HT40_15] = 1072250003Sadrian ar9300_eeprom_get_ht40_trgt_pwr( 1073250003Sadrian ah, HT_TARGET_RATE_15, freq, is_2ghz) + ht40_power_inc_for_pdadc; 1074250003Sadrian target_power_val_t2[ALL_TARGET_HT40_20] = 1075250003Sadrian ar9300_eeprom_get_ht40_trgt_pwr( 1076250003Sadrian ah, HT_TARGET_RATE_20, freq, is_2ghz) + ht40_power_inc_for_pdadc; 1077250003Sadrian target_power_val_t2[ALL_TARGET_HT40_21] = 1078250003Sadrian ar9300_eeprom_get_ht40_trgt_pwr( 1079250003Sadrian ah, HT_TARGET_RATE_21, freq, is_2ghz) + ht40_power_inc_for_pdadc; 1080250003Sadrian target_power_val_t2[ALL_TARGET_HT40_22] = 1081250003Sadrian ar9300_eeprom_get_ht40_trgt_pwr( 1082250003Sadrian ah, HT_TARGET_RATE_22, freq, is_2ghz) + ht40_power_inc_for_pdadc; 1083250003Sadrian target_power_val_t2[ALL_TARGET_HT40_23] = 1084250003Sadrian ar9300_eeprom_get_ht40_trgt_pwr( 1085250003Sadrian ah, HT_TARGET_RATE_23, freq, is_2ghz) + ht40_power_inc_for_pdadc; 1086250003Sadrian 1087250003Sadrian#ifdef AH_DEBUG 1088250003Sadrian { 1089250003Sadrian int i = 0; 1090250003Sadrian 1091250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, "%s: APPLYING TARGET POWERS\n", __func__); 1092250003Sadrian while (i < ar9300_rate_size) { 1093250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, "%s: TPC[%02d] 0x%08x ", 1094250003Sadrian __func__, i, target_power_val_t2[i]); 1095250003Sadrian i++; 1096250003Sadrian if (i == ar9300_rate_size) { 1097250003Sadrian break; 1098250003Sadrian } 1099250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, "%s: TPC[%02d] 0x%08x ", 1100250003Sadrian __func__, i, target_power_val_t2[i]); 1101250003Sadrian i++; 1102250003Sadrian if (i == ar9300_rate_size) { 1103250003Sadrian break; 1104250003Sadrian } 1105250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, "%s: TPC[%02d] 0x%08x ", 1106250003Sadrian __func__, i, target_power_val_t2[i]); 1107250003Sadrian i++; 1108250003Sadrian if (i == ar9300_rate_size) { 1109250003Sadrian break; 1110250003Sadrian } 1111250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, "%s: TPC[%02d] 0x%08x \n", 1112250003Sadrian __func__, i, target_power_val_t2[i]); 1113250003Sadrian i++; 1114250003Sadrian } 1115250003Sadrian } 1116250003Sadrian#endif 1117250003Sadrian} 1118250003Sadrian 1119250003Sadrianu_int16_t *ar9300_regulatory_domain_get(struct ath_hal *ah) 1120250003Sadrian{ 1121250003Sadrian ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom; 1122250003Sadrian return eep->base_eep_header.reg_dmn; 1123250003Sadrian} 1124250003Sadrian 1125250003Sadrian 1126250003Sadrianint32_t 1127250003Sadrianar9300_eeprom_write_enable_gpio_get(struct ath_hal *ah) 1128250003Sadrian{ 1129250003Sadrian ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom; 1130250003Sadrian return eep->base_eep_header.eeprom_write_enable_gpio; 1131250003Sadrian} 1132250003Sadrian 1133250003Sadrianint32_t 1134250003Sadrianar9300_wlan_disable_gpio_get(struct ath_hal *ah) 1135250003Sadrian{ 1136250003Sadrian ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom; 1137250003Sadrian return eep->base_eep_header.wlan_disable_gpio; 1138250003Sadrian} 1139250003Sadrian 1140250003Sadrianint32_t 1141250003Sadrianar9300_wlan_led_gpio_get(struct ath_hal *ah) 1142250003Sadrian{ 1143250003Sadrian ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom; 1144250003Sadrian return eep->base_eep_header.wlan_led_gpio; 1145250003Sadrian} 1146250003Sadrian 1147250003Sadrianint32_t 1148250003Sadrianar9300_rx_band_select_gpio_get(struct ath_hal *ah) 1149250003Sadrian{ 1150250003Sadrian ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom; 1151250003Sadrian return eep->base_eep_header.rx_band_select_gpio; 1152250003Sadrian} 1153250003Sadrian 1154250003Sadrian/* 1155250003Sadrian * since valid noise floor values are negative, returns 1 on error 1156250003Sadrian */ 1157250003Sadrianint32_t 1158250003Sadrianar9300_noise_floor_cal_or_power_get(struct ath_hal *ah, int32_t frequency, 1159250003Sadrian int32_t ichain, HAL_BOOL use_cal) 1160250003Sadrian{ 1161250003Sadrian int nf_use = 1; /* start with an error return value */ 1162250003Sadrian int32_t fx[OSPREY_NUM_5G_CAL_PIERS + OSPREY_NUM_2G_CAL_PIERS]; 1163250003Sadrian int32_t nf[OSPREY_NUM_5G_CAL_PIERS + OSPREY_NUM_2G_CAL_PIERS]; 1164250003Sadrian int nnf; 1165250003Sadrian int is_2ghz; 1166250003Sadrian int ipier, npier; 1167250003Sadrian ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom; 1168250003Sadrian u_int8_t *p_cal_pier; 1169250003Sadrian OSP_CAL_DATA_PER_FREQ_OP_LOOP *p_cal_pier_struct; 1170250003Sadrian 1171250003Sadrian /* 1172250003Sadrian * check chain value 1173250003Sadrian */ 1174250003Sadrian if (ichain < 0 || ichain >= OSPREY_MAX_CHAINS) { 1175250003Sadrian return 1; 1176250003Sadrian } 1177250003Sadrian 1178250003Sadrian /* figure out which band we're using */ 1179250003Sadrian is_2ghz = (frequency < 4000); 1180250003Sadrian if (is_2ghz) { 1181250003Sadrian npier = OSPREY_NUM_2G_CAL_PIERS; 1182250003Sadrian p_cal_pier = eep->cal_freq_pier_2g; 1183250003Sadrian p_cal_pier_struct = eep->cal_pier_data_2g[ichain]; 1184250003Sadrian } else { 1185250003Sadrian npier = OSPREY_NUM_5G_CAL_PIERS; 1186250003Sadrian p_cal_pier = eep->cal_freq_pier_5g; 1187250003Sadrian p_cal_pier_struct = eep->cal_pier_data_5g[ichain]; 1188250003Sadrian } 1189250003Sadrian /* look for valid noise floor values */ 1190250003Sadrian nnf = 0; 1191250003Sadrian for (ipier = 0; ipier < npier; ipier++) { 1192250003Sadrian fx[nnf] = FBIN2FREQ(p_cal_pier[ipier], is_2ghz); 1193250003Sadrian nf[nnf] = use_cal ? 1194250003Sadrian p_cal_pier_struct[ipier].rx_noisefloor_cal : 1195250003Sadrian p_cal_pier_struct[ipier].rx_noisefloor_power; 1196250003Sadrian if (nf[nnf] < 0) { 1197250003Sadrian nnf++; 1198250003Sadrian } 1199250003Sadrian } 1200250003Sadrian /* 1201250003Sadrian * If we have some valid values, interpolate to find the value 1202250003Sadrian * at the desired frequency. 1203250003Sadrian */ 1204250003Sadrian if (nnf > 0) { 1205250003Sadrian nf_use = interpolate(frequency, fx, nf, nnf); 1206250003Sadrian } 1207250003Sadrian 1208250003Sadrian return nf_use; 1209250003Sadrian} 1210250003Sadrian 1211278741Sadrian/* 1212278741Sadrian * Return the Rx NF offset for specific channel. 1213278741Sadrian * The values saved in EEPROM/OTP/Flash is converted through the following way: 1214278741Sadrian * ((_p) - NOISE_PWR_DATA_OFFSET) << 2 1215278741Sadrian * So we need to convert back to the original values. 1216278741Sadrian */ 1217278741Sadrianint ar9300_get_rx_nf_offset(struct ath_hal *ah, struct ieee80211_channel *chan, int8_t *nf_pwr, int8_t *nf_cal) { 1218278741Sadrian HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan); 1219278741Sadrian int8_t rx_nf_pwr, rx_nf_cal; 1220278741Sadrian int i; 1221278741Sadrian //HALASSERT(ichan); 1222278741Sadrian 1223278741Sadrian /* Fill 0 if valid internal channel is not found */ 1224278741Sadrian if (ichan == AH_NULL) { 1225278741Sadrian OS_MEMZERO(nf_pwr, sizeof(nf_pwr[0])*OSPREY_MAX_CHAINS); 1226278741Sadrian OS_MEMZERO(nf_cal, sizeof(nf_cal[0])*OSPREY_MAX_CHAINS); 1227278741Sadrian return -1; 1228278741Sadrian } 1229278741Sadrian 1230278741Sadrian for (i = 0; i < OSPREY_MAX_CHAINS; i++) { 1231278741Sadrian if ((rx_nf_pwr = ar9300_noise_floor_cal_or_power_get(ah, ichan->channel, i, 0)) == 1) { 1232278741Sadrian nf_pwr[i] = 0; 1233278741Sadrian } else { 1234278741Sadrian //printk("%s: raw nf_pwr[%d] = %d\n", __func__, i, rx_nf_pwr); 1235278741Sadrian nf_pwr[i] = NOISE_PWR_DBM_2_INT(rx_nf_pwr); 1236278741Sadrian } 1237278741Sadrian 1238278741Sadrian if ((rx_nf_cal = ar9300_noise_floor_cal_or_power_get(ah, ichan->channel, i, 1)) == 1) { 1239278741Sadrian nf_cal[i] = 0; 1240278741Sadrian } else { 1241278741Sadrian //printk("%s: raw nf_cal[%d] = %d\n", __func__, i, rx_nf_cal); 1242278741Sadrian nf_cal[i] = NOISE_PWR_DBM_2_INT(rx_nf_cal); 1243278741Sadrian } 1244278741Sadrian } 1245278741Sadrian 1246278741Sadrian return 0; 1247278741Sadrian} 1248278741Sadrian 1249250003Sadrianint32_t ar9300_rx_gain_index_get(struct ath_hal *ah) 1250250003Sadrian{ 1251250003Sadrian ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom; 1252250003Sadrian 1253250003Sadrian return (eep->base_eep_header.txrxgain) & 0xf; /* bits 3:0 */ 1254250003Sadrian} 1255250003Sadrian 1256250003Sadrian 1257250003Sadrianint32_t ar9300_tx_gain_index_get(struct ath_hal *ah) 1258250003Sadrian{ 1259250003Sadrian ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom; 1260250003Sadrian 1261250003Sadrian return (eep->base_eep_header.txrxgain >> 4) & 0xf; /* bits 7:4 */ 1262250003Sadrian} 1263250003Sadrian 1264250003SadrianHAL_BOOL ar9300_internal_regulator_apply(struct ath_hal *ah) 1265250003Sadrian{ 1266250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 1267250003Sadrian int internal_regulator = ar9300_eeprom_get(ahp, EEP_INTERNAL_REGULATOR); 1268250003Sadrian int reg_pmu1, reg_pmu2, reg_pmu1_set, reg_pmu2_set; 1269250003Sadrian u_int32_t reg_PMU1, reg_PMU2; 1270250003Sadrian unsigned long eep_addr; 1271250003Sadrian u_int32_t reg_val, reg_usb = 0, reg_pmu = 0; 1272250003Sadrian int usb_valid = 0, pmu_valid = 0; 1273250003Sadrian unsigned char pmu_refv; 1274250003Sadrian 1275250003Sadrian if (AR_SREV_JUPITER(ah) || AR_SREV_APHRODITE(ah)) { 1276250003Sadrian reg_PMU1 = AR_PHY_PMU1_JUPITER; 1277250003Sadrian reg_PMU2 = AR_PHY_PMU2_JUPITER; 1278250003Sadrian } 1279250003Sadrian else { 1280250003Sadrian reg_PMU1 = AR_PHY_PMU1; 1281250003Sadrian reg_PMU2 = AR_PHY_PMU2; 1282250003Sadrian } 1283250003Sadrian 1284250003Sadrian if (internal_regulator) { 1285250003Sadrian if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah)) { 1286250003Sadrian if (AR_SREV_HORNET(ah)) { 1287250003Sadrian /* Read OTP first */ 1288250003Sadrian for (eep_addr = 0x14; ; eep_addr -= 0x10) { 1289250003Sadrian 1290250003Sadrian ar9300_otp_read(ah, eep_addr / 4, ®_val, 1); 1291250003Sadrian 1292250003Sadrian if ((reg_val & 0x80) == 0x80){ 1293250003Sadrian usb_valid = 1; 1294250003Sadrian reg_usb = reg_val & 0x000000ff; 1295250003Sadrian } 1296250003Sadrian 1297250003Sadrian if ((reg_val & 0x80000000) == 0x80000000){ 1298250003Sadrian pmu_valid = 1; 1299250003Sadrian reg_pmu = (reg_val & 0xff000000) >> 24; 1300250003Sadrian } 1301250003Sadrian 1302250003Sadrian if (eep_addr == 0x4) { 1303250003Sadrian break; 1304250003Sadrian } 1305250003Sadrian } 1306250003Sadrian 1307250003Sadrian if (pmu_valid) { 1308250003Sadrian pmu_refv = reg_pmu & 0xf; 1309250003Sadrian } else { 1310250003Sadrian pmu_refv = 0x8; 1311250003Sadrian } 1312250003Sadrian 1313250003Sadrian /* 1314250003Sadrian * If (valid) { 1315250003Sadrian * Usb_phy_ctrl2_tx_cal_en -> 0 1316250003Sadrian * Usb_phy_ctrl2_tx_cal_sel -> 0 1317250003Sadrian * Usb_phy_ctrl2_tx_man_cal -> 0, 1, 3, 7 or 15 from OTP 1318250003Sadrian * } 1319250003Sadrian */ 1320250003Sadrian if (usb_valid) { 1321250003Sadrian OS_REG_RMW_FIELD(ah, 0x16c88, AR_PHY_CTRL2_TX_CAL_EN, 0x0); 1322250003Sadrian OS_REG_RMW_FIELD(ah, 0x16c88, AR_PHY_CTRL2_TX_CAL_SEL, 0x0); 1323250003Sadrian OS_REG_RMW_FIELD(ah, 0x16c88, 1324250003Sadrian AR_PHY_CTRL2_TX_MAN_CAL, (reg_usb & 0xf)); 1325250003Sadrian } 1326250003Sadrian 1327250003Sadrian } else { 1328250003Sadrian pmu_refv = 0x8; 1329250003Sadrian } 1330250003Sadrian /*#ifndef USE_HIF*/ 1331250003Sadrian /* Follow the MDK settings for Hornet PMU. 1332250003Sadrian * my $pwd = 0x0; 1333250003Sadrian * my $Nfdiv = 0x3; # xtal_freq = 25MHz 1334250003Sadrian * my $Nfdiv = 0x4; # xtal_freq = 40MHz 1335250003Sadrian * my $Refv = 0x7; # 0x5:1.22V; 0x8:1.29V 1336250003Sadrian * my $Gm1 = 0x3; #Poseidon $Gm1=1 1337250003Sadrian * my $classb = 0x0; 1338250003Sadrian * my $Cc = 0x1; #Poseidon $Cc=7 1339250003Sadrian * my $Rc = 0x6; 1340250003Sadrian * my $ramp_slope = 0x1; 1341250003Sadrian * my $Segm = 0x3; 1342250003Sadrian * my $use_local_osc = 0x0; 1343250003Sadrian * my $force_xosc_stable = 0x0; 1344250003Sadrian * my $Selfb = 0x0; #Poseidon $Selfb=1 1345250003Sadrian * my $Filterfb = 0x3; #Poseidon $Filterfb=0 1346250003Sadrian * my $Filtervc = 0x0; 1347250003Sadrian * my $disc = 0x0; 1348250003Sadrian * my $discdel = 0x4; 1349250003Sadrian * my $spare = 0x0; 1350250003Sadrian * $reg_PMU1 = 1351250003Sadrian * $pwd | ($Nfdiv<<1) | ($Refv<<4) | ($Gm1<<8) | 1352250003Sadrian * ($classb<<11) | ($Cc<<14) | ($Rc<<17) | ($ramp_slope<<20) | 1353250003Sadrian * ($Segm<<24) | ($use_local_osc<<26) | 1354250003Sadrian * ($force_xosc_stable<<27) | ($Selfb<<28) | ($Filterfb<<29); 1355250003Sadrian * $reg_PMU2 = $handle->reg_rd("ch0_PMU2"); 1356250003Sadrian * $reg_PMU2 = ($reg_PMU2 & 0xfe3fffff) | ($Filtervc<<22); 1357250003Sadrian * $reg_PMU2 = ($reg_PMU2 & 0xe3ffffff) | ($discdel<<26); 1358250003Sadrian * $reg_PMU2 = ($reg_PMU2 & 0x1fffffff) | ($spare<<29); 1359250003Sadrian */ 1360250003Sadrian if (ahp->clk_25mhz) { 1361250003Sadrian reg_pmu1_set = 0 | 1362250003Sadrian (3 << 1) | (pmu_refv << 4) | (3 << 8) | (0 << 11) | 1363250003Sadrian (1 << 14) | (6 << 17) | (1 << 20) | (3 << 24) | 1364250003Sadrian (0 << 26) | (0 << 27) | (0 << 28) | (0 << 29); 1365250003Sadrian } else { 1366250003Sadrian if (AR_SREV_POSEIDON(ah)) { 1367250003Sadrian reg_pmu1_set = 0 | 1368250003Sadrian (5 << 1) | (7 << 4) | (2 << 8) | (0 << 11) | 1369250003Sadrian (2 << 14) | (6 << 17) | (1 << 20) | (3 << 24) | 1370250003Sadrian (0 << 26) | (0 << 27) | (1 << 28) | (0 << 29) ; 1371250003Sadrian } else { 1372250003Sadrian reg_pmu1_set = 0 | 1373250003Sadrian (4 << 1) | (7 << 4) | (3 << 8) | (0 << 11) | 1374250003Sadrian (1 << 14) | (6 << 17) | (1 << 20) | (3 << 24) | 1375250003Sadrian (0 << 26) | (0 << 27) | (0 << 28) | (0 << 29) ; 1376250003Sadrian } 1377250003Sadrian } 1378250003Sadrian OS_REG_RMW_FIELD(ah, reg_PMU2, AR_PHY_PMU2_PGM, 0x0); 1379250003Sadrian 1380250003Sadrian OS_REG_WRITE(ah, reg_PMU1, reg_pmu1_set); /* 0x638c8376 */ 1381250003Sadrian reg_pmu1 = OS_REG_READ(ah, reg_PMU1); 1382250003Sadrian while (reg_pmu1 != reg_pmu1_set) { 1383250003Sadrian OS_REG_WRITE(ah, reg_PMU1, reg_pmu1_set); /* 0x638c8376 */ 1384250003Sadrian OS_DELAY(10); 1385250003Sadrian reg_pmu1 = OS_REG_READ(ah, reg_PMU1); 1386250003Sadrian } 1387250003Sadrian 1388250003Sadrian reg_pmu2_set = 1389250003Sadrian (OS_REG_READ(ah, reg_PMU2) & (~0xFFC00000)) | (4 << 26); 1390250003Sadrian OS_REG_WRITE(ah, reg_PMU2, reg_pmu2_set); 1391250003Sadrian reg_pmu2 = OS_REG_READ(ah, reg_PMU2); 1392250003Sadrian while (reg_pmu2 != reg_pmu2_set) { 1393250003Sadrian OS_REG_WRITE(ah, reg_PMU2, reg_pmu2_set); 1394250003Sadrian OS_DELAY(10); 1395250003Sadrian reg_pmu2 = OS_REG_READ(ah, reg_PMU2); 1396250003Sadrian } 1397250003Sadrian reg_pmu2_set = 1398250003Sadrian (OS_REG_READ(ah, reg_PMU2) & (~0x00200000)) | (1 << 21); 1399250003Sadrian OS_REG_WRITE(ah, reg_PMU2, reg_pmu2_set); 1400250003Sadrian reg_pmu2 = OS_REG_READ(ah, reg_PMU2); 1401250003Sadrian while (reg_pmu2 != reg_pmu2_set) { 1402250003Sadrian OS_REG_WRITE(ah, reg_PMU2, reg_pmu2_set); 1403250003Sadrian OS_DELAY(10); 1404250003Sadrian reg_pmu2 = OS_REG_READ(ah, reg_PMU2); 1405250003Sadrian } 1406250003Sadrian /*#endif*/ 1407250003Sadrian } else if (AR_SREV_JUPITER(ah) || AR_SREV_APHRODITE(ah)) { 1408250003Sadrian /* Internal regulator is ON. Write swreg register. */ 1409250003Sadrian int swreg = ar9300_eeprom_get(ahp, EEP_SWREG); 1410250003Sadrian OS_REG_WRITE(ah, reg_PMU1, swreg); 1411250003Sadrian } else { 1412250003Sadrian /* Internal regulator is ON. Write swreg register. */ 1413250003Sadrian int swreg = ar9300_eeprom_get(ahp, EEP_SWREG); 1414250003Sadrian OS_REG_WRITE(ah, AR_RTC_REG_CONTROL1, 1415250003Sadrian OS_REG_READ(ah, AR_RTC_REG_CONTROL1) & 1416250003Sadrian (~AR_RTC_REG_CONTROL1_SWREG_PROGRAM)); 1417250003Sadrian OS_REG_WRITE(ah, AR_RTC_REG_CONTROL0, swreg); 1418250003Sadrian /* Set REG_CONTROL1.SWREG_PROGRAM */ 1419250003Sadrian OS_REG_WRITE(ah, AR_RTC_REG_CONTROL1, 1420250003Sadrian OS_REG_READ(ah, AR_RTC_REG_CONTROL1) | 1421250003Sadrian AR_RTC_REG_CONTROL1_SWREG_PROGRAM); 1422250003Sadrian } 1423250003Sadrian } else { 1424250003Sadrian if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah)) { 1425250003Sadrian OS_REG_RMW_FIELD(ah, reg_PMU2, AR_PHY_PMU2_PGM, 0x0); 1426250003Sadrian reg_pmu2 = OS_REG_READ_FIELD(ah, reg_PMU2, AR_PHY_PMU2_PGM); 1427250003Sadrian while (reg_pmu2) { 1428250003Sadrian OS_DELAY(10); 1429250003Sadrian reg_pmu2 = OS_REG_READ_FIELD(ah, reg_PMU2, AR_PHY_PMU2_PGM); 1430250003Sadrian } 1431250003Sadrian OS_REG_RMW_FIELD(ah, reg_PMU1, AR_PHY_PMU1_PWD, 0x1); 1432250003Sadrian reg_pmu1 = OS_REG_READ_FIELD(ah, reg_PMU1, AR_PHY_PMU1_PWD); 1433250003Sadrian while (!reg_pmu1) { 1434250003Sadrian OS_DELAY(10); 1435250003Sadrian reg_pmu1 = OS_REG_READ_FIELD(ah, reg_PMU1, AR_PHY_PMU1_PWD); 1436250003Sadrian } 1437250003Sadrian OS_REG_RMW_FIELD(ah, reg_PMU2, AR_PHY_PMU2_PGM, 0x1); 1438250003Sadrian reg_pmu2 = OS_REG_READ_FIELD(ah, reg_PMU2, AR_PHY_PMU2_PGM); 1439250003Sadrian while (!reg_pmu2) { 1440250003Sadrian OS_DELAY(10); 1441250003Sadrian reg_pmu2 = OS_REG_READ_FIELD(ah, reg_PMU2, AR_PHY_PMU2_PGM); 1442250003Sadrian } 1443250003Sadrian } else if (AR_SREV_JUPITER(ah) || AR_SREV_APHRODITE(ah)) { 1444250003Sadrian OS_REG_RMW_FIELD(ah, reg_PMU1, AR_PHY_PMU1_PWD, 0x1); 1445250003Sadrian } else { 1446250003Sadrian OS_REG_WRITE(ah, AR_RTC_SLEEP_CLK, 1447250003Sadrian (OS_REG_READ(ah, AR_RTC_SLEEP_CLK) | 1448250003Sadrian AR_RTC_FORCE_SWREG_PRD | AR_RTC_PCIE_RST_PWDN_EN)); 1449250003Sadrian } 1450250003Sadrian } 1451250003Sadrian 1452250003Sadrian return 0; 1453250003Sadrian} 1454250003Sadrian 1455250003SadrianHAL_BOOL ar9300_drive_strength_apply(struct ath_hal *ah) 1456250003Sadrian{ 1457250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 1458250003Sadrian int drive_strength; 1459250003Sadrian unsigned long reg; 1460250003Sadrian 1461250003Sadrian drive_strength = ar9300_eeprom_get(ahp, EEP_DRIVE_STRENGTH); 1462250003Sadrian if (drive_strength) { 1463250003Sadrian reg = OS_REG_READ(ah, AR_PHY_65NM_CH0_BIAS1); 1464250003Sadrian reg &= ~0x00ffffc0; 1465250003Sadrian reg |= 0x5 << 21; 1466250003Sadrian reg |= 0x5 << 18; 1467250003Sadrian reg |= 0x5 << 15; 1468250003Sadrian reg |= 0x5 << 12; 1469250003Sadrian reg |= 0x5 << 9; 1470250003Sadrian reg |= 0x5 << 6; 1471250003Sadrian OS_REG_WRITE(ah, AR_PHY_65NM_CH0_BIAS1, reg); 1472250003Sadrian 1473250003Sadrian reg = OS_REG_READ(ah, AR_PHY_65NM_CH0_BIAS2); 1474250003Sadrian reg &= ~0xffffffe0; 1475250003Sadrian reg |= 0x5 << 29; 1476250003Sadrian reg |= 0x5 << 26; 1477250003Sadrian reg |= 0x5 << 23; 1478250003Sadrian reg |= 0x5 << 20; 1479250003Sadrian reg |= 0x5 << 17; 1480250003Sadrian reg |= 0x5 << 14; 1481250003Sadrian reg |= 0x5 << 11; 1482250003Sadrian reg |= 0x5 << 8; 1483250003Sadrian reg |= 0x5 << 5; 1484250003Sadrian OS_REG_WRITE(ah, AR_PHY_65NM_CH0_BIAS2, reg); 1485250003Sadrian 1486250003Sadrian reg = OS_REG_READ(ah, AR_PHY_65NM_CH0_BIAS4); 1487250003Sadrian reg &= ~0xff800000; 1488250003Sadrian reg |= 0x5 << 29; 1489250003Sadrian reg |= 0x5 << 26; 1490250003Sadrian reg |= 0x5 << 23; 1491250003Sadrian OS_REG_WRITE(ah, AR_PHY_65NM_CH0_BIAS4, reg); 1492250003Sadrian } 1493250003Sadrian return 0; 1494250003Sadrian} 1495250003Sadrian 1496250003Sadrianint32_t ar9300_xpa_bias_level_get(struct ath_hal *ah, HAL_BOOL is_2ghz) 1497250003Sadrian{ 1498250003Sadrian ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom; 1499250003Sadrian if (is_2ghz) { 1500250003Sadrian return eep->modal_header_2g.xpa_bias_lvl; 1501250003Sadrian } else { 1502250003Sadrian return eep->modal_header_5g.xpa_bias_lvl; 1503250003Sadrian } 1504250003Sadrian} 1505250003Sadrian 1506250003SadrianHAL_BOOL ar9300_xpa_bias_level_apply(struct ath_hal *ah, HAL_BOOL is_2ghz) 1507250003Sadrian{ 1508250003Sadrian /* 1509250003Sadrian * In ar9330 emu, we can't access radio registers, 1510250003Sadrian * merlin is used for radio part. 1511250003Sadrian */ 1512250003Sadrian int bias; 1513250003Sadrian bias = ar9300_xpa_bias_level_get(ah, is_2ghz); 1514250003Sadrian 1515250003Sadrian if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah) || AR_SREV_WASP(ah)) { 1516250003Sadrian OS_REG_RMW_FIELD(ah, 1517250003Sadrian AR_HORNET_CH0_TOP2, AR_HORNET_CH0_TOP2_XPABIASLVL, bias); 1518250003Sadrian } else if (AR_SREV_SCORPION(ah)) { 1519250003Sadrian OS_REG_RMW_FIELD(ah, 1520250003Sadrian AR_SCORPION_CH0_TOP, AR_SCORPION_CH0_TOP_XPABIASLVL, bias); 1521250003Sadrian } else if (AR_SREV_JUPITER(ah) || AR_SREV_APHRODITE(ah)) { 1522250003Sadrian OS_REG_RMW_FIELD(ah, 1523250003Sadrian AR_PHY_65NM_CH0_TOP_JUPITER, AR_PHY_65NM_CH0_TOP_XPABIASLVL, bias); 1524250003Sadrian } else { 1525250003Sadrian OS_REG_RMW_FIELD(ah, 1526250003Sadrian AR_PHY_65NM_CH0_TOP, AR_PHY_65NM_CH0_TOP_XPABIASLVL, bias); 1527250003Sadrian OS_REG_RMW_FIELD(ah, 1528250003Sadrian AR_PHY_65NM_CH0_THERM, AR_PHY_65NM_CH0_THERM_XPABIASLVL_MSB, 1529250003Sadrian bias >> 2); 1530250003Sadrian OS_REG_RMW_FIELD(ah, 1531250003Sadrian AR_PHY_65NM_CH0_THERM, AR_PHY_65NM_CH0_THERM_XPASHORT2GND, 1); 1532250003Sadrian } 1533250003Sadrian return 0; 1534250003Sadrian} 1535250003Sadrian 1536250003Sadrianu_int32_t ar9300_ant_ctrl_common_get(struct ath_hal *ah, HAL_BOOL is_2ghz) 1537250003Sadrian{ 1538250003Sadrian ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom; 1539250003Sadrian if (is_2ghz) { 1540250003Sadrian return eep->modal_header_2g.ant_ctrl_common; 1541250003Sadrian } else { 1542250003Sadrian return eep->modal_header_5g.ant_ctrl_common; 1543250003Sadrian } 1544250003Sadrian} 1545250003Sadrianstatic u_int16_t 1546250003Sadrianar9300_switch_com_spdt_get(struct ath_hal *ah, HAL_BOOL is_2ghz) 1547250003Sadrian{ 1548250003Sadrian ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom; 1549250003Sadrian if (is_2ghz) { 1550250003Sadrian return eep->modal_header_2g.switchcomspdt; 1551250003Sadrian } else { 1552250003Sadrian return eep->modal_header_5g.switchcomspdt; 1553250003Sadrian } 1554250003Sadrian} 1555250003Sadrianu_int32_t ar9300_ant_ctrl_common2_get(struct ath_hal *ah, HAL_BOOL is_2ghz) 1556250003Sadrian{ 1557250003Sadrian ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom; 1558250003Sadrian if (is_2ghz) { 1559250003Sadrian return eep->modal_header_2g.ant_ctrl_common2; 1560250003Sadrian } else { 1561250003Sadrian return eep->modal_header_5g.ant_ctrl_common2; 1562250003Sadrian } 1563250003Sadrian} 1564250003Sadrian 1565250003Sadrianu_int16_t ar9300_ant_ctrl_chain_get(struct ath_hal *ah, int chain, 1566250003Sadrian HAL_BOOL is_2ghz) 1567250003Sadrian{ 1568250003Sadrian ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom; 1569250003Sadrian if (chain >= 0 && chain < OSPREY_MAX_CHAINS) { 1570250003Sadrian if (is_2ghz) { 1571250003Sadrian return eep->modal_header_2g.ant_ctrl_chain[chain]; 1572250003Sadrian } else { 1573250003Sadrian return eep->modal_header_5g.ant_ctrl_chain[chain]; 1574250003Sadrian } 1575250003Sadrian } 1576250003Sadrian return 0; 1577250003Sadrian} 1578250003Sadrian 1579278741Sadrian/* 1580278741Sadrian * Select the usage of antenna via the RF switch. 1581278741Sadrian * Default values are loaded from eeprom. 1582278741Sadrian */ 1583278741SadrianHAL_BOOL ar9300_ant_swcom_sel(struct ath_hal *ah, u_int8_t ops, 1584278741Sadrian u_int32_t *common_tbl1, u_int32_t *common_tbl2) 1585278741Sadrian{ 1586278741Sadrian ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom; 1587278741Sadrian struct ath_hal_private *ap = AH_PRIVATE(ah); 1588278741Sadrian const struct ieee80211_channel *curchan = ap->ah_curchan; 1589278741Sadrian enum { 1590278741Sadrian ANT_SELECT_OPS_GET, 1591278741Sadrian ANT_SELECT_OPS_SET, 1592278741Sadrian }; 1593278741Sadrian 1594278741Sadrian if (AR_SREV_JUPITER(ah) || AR_SREV_SCORPION(ah)) 1595278741Sadrian return AH_FALSE; 1596278741Sadrian 1597278741Sadrian if (!curchan) 1598278741Sadrian return AH_FALSE; 1599278741Sadrian 1600278741Sadrian#define AR_SWITCH_TABLE_COM_ALL (0xffff) 1601278741Sadrian#define AR_SWITCH_TABLE_COM_ALL_S (0) 1602278741Sadrian#define AR_SWITCH_TABLE_COM2_ALL (0xffffff) 1603278741Sadrian#define AR_SWITCH_TABLE_COM2_ALL_S (0) 1604278741Sadrian switch (ops) { 1605278741Sadrian case ANT_SELECT_OPS_GET: 1606278741Sadrian *common_tbl1 = OS_REG_READ_FIELD(ah, AR_PHY_SWITCH_COM, 1607278741Sadrian AR_SWITCH_TABLE_COM_ALL); 1608278741Sadrian *common_tbl2 = OS_REG_READ_FIELD(ah, AR_PHY_SWITCH_COM_2, 1609278741Sadrian AR_SWITCH_TABLE_COM2_ALL); 1610278741Sadrian break; 1611278741Sadrian case ANT_SELECT_OPS_SET: 1612278741Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM, 1613278741Sadrian AR_SWITCH_TABLE_COM_ALL, *common_tbl1); 1614278741Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM_2, 1615278741Sadrian AR_SWITCH_TABLE_COM2_ALL, *common_tbl2); 1616278741Sadrian 1617278741Sadrian /* write back to eeprom */ 1618278741Sadrian if (IEEE80211_IS_CHAN_2GHZ(curchan)) { 1619278741Sadrian eep->modal_header_2g.ant_ctrl_common = *common_tbl1; 1620278741Sadrian eep->modal_header_2g.ant_ctrl_common2 = *common_tbl2; 1621278741Sadrian } else { 1622278741Sadrian eep->modal_header_5g.ant_ctrl_common = *common_tbl1; 1623278741Sadrian eep->modal_header_5g.ant_ctrl_common2 = *common_tbl2; 1624278741Sadrian } 1625278741Sadrian 1626278741Sadrian break; 1627278741Sadrian default: 1628278741Sadrian break; 1629278741Sadrian } 1630278741Sadrian 1631278741Sadrian return AH_TRUE; 1632278741Sadrian} 1633278741Sadrian 1634250003SadrianHAL_BOOL ar9300_ant_ctrl_apply(struct ath_hal *ah, HAL_BOOL is_2ghz) 1635250003Sadrian{ 1636250003Sadrian u_int32_t value; 1637250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 1638250003Sadrian u_int32_t regval; 1639250003Sadrian struct ath_hal_private *ahpriv = AH_PRIVATE(ah); 1640250003Sadrian#if ATH_ANT_DIV_COMB 1641250003Sadrian HAL_CAPABILITIES *pcap = &ahpriv->ah_caps; 1642250003Sadrian#endif /* ATH_ANT_DIV_COMB */ 1643250003Sadrian u_int32_t xlan_gpio_cfg; 1644250003Sadrian u_int8_t i; 1645250003Sadrian 1646301092Sadrian HALDEBUG(ah, HAL_DEBUG_BT_COEX, "%s: use_bt_ant_enable=%d\n", 1647301092Sadrian __func__, ahp->ah_lna_div_use_bt_ant_enable); 1648301092Sadrian 1649301092Sadrian /* XXX TODO: only if rx_gain_idx == 0 */ 1650250003Sadrian if (AR_SREV_POSEIDON(ah)) { 1651250008Sadrian xlan_gpio_cfg = ah->ah_config.ath_hal_ext_lna_ctl_gpio; 1652250003Sadrian if (xlan_gpio_cfg) { 1653250003Sadrian for (i = 0; i < 32; i++) { 1654250003Sadrian if (xlan_gpio_cfg & (1 << i)) { 1655250008Sadrian ath_hal_gpioCfgOutput(ah, i, 1656250008Sadrian HAL_GPIO_OUTPUT_MUX_PCIE_ATTENTION_LED); 1657250003Sadrian } 1658250003Sadrian } 1659250003Sadrian } 1660250003Sadrian } 1661250003Sadrian#define AR_SWITCH_TABLE_COM_ALL (0xffff) 1662250003Sadrian#define AR_SWITCH_TABLE_COM_ALL_S (0) 1663250003Sadrian#define AR_SWITCH_TABLE_COM_JUPITER_ALL (0xffffff) 1664250003Sadrian#define AR_SWITCH_TABLE_COM_JUPITER_ALL_S (0) 1665250003Sadrian#define AR_SWITCH_TABLE_COM_SCORPION_ALL (0xffffff) 1666250003Sadrian#define AR_SWITCH_TABLE_COM_SCORPION_ALL_S (0) 1667291437Sadrian#define AR_SWITCH_TABLE_COM_HONEYBEE_ALL (0xffffff) 1668291437Sadrian#define AR_SWITCH_TABLE_COM_HONEYBEE_ALL_S (0) 1669250003Sadrian#define AR_SWITCH_TABLE_COM_SPDT (0x00f00000) 1670250003Sadrian value = ar9300_ant_ctrl_common_get(ah, is_2ghz); 1671250003Sadrian if (AR_SREV_JUPITER(ah) || AR_SREV_APHRODITE(ah)) { 1672250003Sadrian if (AR_SREV_JUPITER_10(ah)) { 1673250003Sadrian /* Force SPDT setting for Jupiter 1.0 chips. */ 1674250003Sadrian value &= ~AR_SWITCH_TABLE_COM_SPDT; 1675250003Sadrian value |= 0x00100000; 1676250003Sadrian } 1677250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM, 1678250003Sadrian AR_SWITCH_TABLE_COM_JUPITER_ALL, value); 1679250003Sadrian } 1680250003Sadrian else if (AR_SREV_SCORPION(ah)) { 1681250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM, 1682250003Sadrian AR_SWITCH_TABLE_COM_SCORPION_ALL, value); 1683250003Sadrian } 1684291437Sadrian else if (AR_SREV_HONEYBEE(ah)) { 1685291437Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM, 1686291437Sadrian AR_SWITCH_TABLE_COM_HONEYBEE_ALL, value); 1687291437Sadrian } 1688250003Sadrian else { 1689250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM, 1690250003Sadrian AR_SWITCH_TABLE_COM_ALL, value); 1691250003Sadrian } 1692250003Sadrian/* 1693250003Sadrian* Jupiter2.0 defines new switch table for BT/WLAN, 1694250003Sadrian* here's new field name in WB222.ref for both 2G and 5G. 1695250003Sadrian* Register: [GLB_CONTROL] GLB_CONTROL (@0x20044) 1696250003Sadrian* 15:12 R/W SWITCH_TABLE_COM_SPDT_WLAN_RX SWITCH_TABLE_COM_SPDT_WLAN_RX 1697250003Sadrian* 11:8 R/W SWITCH_TABLE_COM_SPDT_WLAN_TX SWITCH_TABLE_COM_SPDT_WLAN_TX 1698250003Sadrian* 7:4 R/W SWITCH_TABLE_COM_SPDT_WLAN_IDLE SWITCH_TABLE_COM_SPDT_WLAN_IDLE 1699250003Sadrian*/ 1700250003Sadrian#define AR_SWITCH_TABLE_COM_SPDT_ALL (0x0000fff0) 1701250003Sadrian#define AR_SWITCH_TABLE_COM_SPDT_ALL_S (4) 1702250003Sadrian if (AR_SREV_JUPITER_20_OR_LATER(ah) || AR_SREV_APHRODITE(ah)) { 1703250003Sadrian value = ar9300_switch_com_spdt_get(ah, is_2ghz); 1704250003Sadrian OS_REG_RMW_FIELD(ah, AR_GLB_CONTROL, 1705250003Sadrian AR_SWITCH_TABLE_COM_SPDT_ALL, value); 1706250003Sadrian 1707250003Sadrian OS_REG_SET_BIT(ah, AR_GLB_CONTROL, 1708250003Sadrian AR_BTCOEX_CTRL_SPDT_ENABLE); 1709250003Sadrian //OS_REG_SET_BIT(ah, AR_GLB_CONTROL, 1710250003Sadrian // AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL); 1711250003Sadrian } 1712250003Sadrian 1713250003Sadrian#define AR_SWITCH_TABLE_COM2_ALL (0xffffff) 1714250003Sadrian#define AR_SWITCH_TABLE_COM2_ALL_S (0) 1715250003Sadrian value = ar9300_ant_ctrl_common2_get(ah, is_2ghz); 1716250003Sadrian#if ATH_ANT_DIV_COMB 1717250003Sadrian if ( AR_SREV_POSEIDON(ah) && (ahp->ah_lna_div_use_bt_ant_enable == TRUE) ) { 1718250003Sadrian value &= ~AR_SWITCH_TABLE_COM2_ALL; 1719250008Sadrian value |= ah->ah_config.ath_hal_ant_ctrl_comm2g_switch_enable; 1720272292Sadrian HALDEBUG(ah, HAL_DEBUG_RESET, "%s: com2=0x%08x\n", __func__, value) 1721250003Sadrian } 1722250003Sadrian#endif /* ATH_ANT_DIV_COMB */ 1723250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM_2, AR_SWITCH_TABLE_COM2_ALL, value); 1724250003Sadrian 1725250003Sadrian#define AR_SWITCH_TABLE_ALL (0xfff) 1726250003Sadrian#define AR_SWITCH_TABLE_ALL_S (0) 1727250003Sadrian value = ar9300_ant_ctrl_chain_get(ah, 0, is_2ghz); 1728250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_SWITCH_CHAIN_0, AR_SWITCH_TABLE_ALL, value); 1729250003Sadrian 1730250003Sadrian if (!AR_SREV_HORNET(ah) && !AR_SREV_POSEIDON(ah) && !AR_SREV_APHRODITE(ah)) { 1731250003Sadrian value = ar9300_ant_ctrl_chain_get(ah, 1, is_2ghz); 1732250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_SWITCH_CHAIN_1, AR_SWITCH_TABLE_ALL, value); 1733250003Sadrian 1734291437Sadrian if (!AR_SREV_WASP(ah) && !AR_SREV_JUPITER(ah) && !AR_SREV_HONEYBEE(ah)) { 1735250003Sadrian value = ar9300_ant_ctrl_chain_get(ah, 2, is_2ghz); 1736250003Sadrian OS_REG_RMW_FIELD(ah, 1737250003Sadrian AR_PHY_SWITCH_CHAIN_2, AR_SWITCH_TABLE_ALL, value); 1738250003Sadrian } 1739250003Sadrian } 1740301092Sadrian if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah) || AR_SREV_APHRODITE(ah)) { 1741250003Sadrian value = ar9300_eeprom_get(ahp, EEP_ANTDIV_control); 1742250003Sadrian /* main_lnaconf, alt_lnaconf, main_tb, alt_tb */ 1743250003Sadrian regval = OS_REG_READ(ah, AR_PHY_MC_GAIN_CTRL); 1744250003Sadrian regval &= (~ANT_DIV_CONTROL_ALL); /* clear bit 25~30 */ 1745250003Sadrian regval |= (value & 0x3f) << ANT_DIV_CONTROL_ALL_S; 1746250003Sadrian /* enable_lnadiv */ 1747250003Sadrian regval &= (~MULTICHAIN_GAIN_CTRL__ENABLE_ANT_DIV_LNADIV__MASK); 1748250003Sadrian regval |= ((value >> 6) & 0x1) << 1749250003Sadrian MULTICHAIN_GAIN_CTRL__ENABLE_ANT_DIV_LNADIV__SHIFT; 1750250003Sadrian#if ATH_ANT_DIV_COMB 1751250003Sadrian if ( AR_SREV_POSEIDON(ah) && (ahp->ah_lna_div_use_bt_ant_enable == TRUE) ) { 1752250003Sadrian regval |= ANT_DIV_ENABLE; 1753250003Sadrian } 1754301092Sadrian if (AR_SREV_APHRODITE(ah)) { 1755301092Sadrian if (ahp->ah_lna_div_use_bt_ant_enable) { 1756301092Sadrian regval |= (1 << MULTICHAIN_GAIN_CTRL__ENABLE_ANT_SW_RX_PROT__SHIFT); 1757301092Sadrian 1758301092Sadrian OS_REG_SET_BIT(ah, AR_PHY_RESTART, 1759301092Sadrian RESTART__ENABLE_ANT_FAST_DIV_M2FLAG__MASK); 1760301092Sadrian 1761301092Sadrian /* Force WLAN LNA diversity ON */ 1762301092Sadrian OS_REG_SET_BIT(ah, AR_BTCOEX_WL_LNADIV, 1763301092Sadrian AR_BTCOEX_WL_LNADIV_FORCE_ON); 1764301092Sadrian } else { 1765301092Sadrian regval &= ~(1 << MULTICHAIN_GAIN_CTRL__ENABLE_ANT_DIV_LNADIV__SHIFT); 1766301092Sadrian regval &= ~(1 << MULTICHAIN_GAIN_CTRL__ENABLE_ANT_SW_RX_PROT__SHIFT); 1767301092Sadrian 1768301092Sadrian OS_REG_CLR_BIT(ah, AR_PHY_MC_GAIN_CTRL, 1769301092Sadrian (1 << MULTICHAIN_GAIN_CTRL__ENABLE_ANT_SW_RX_PROT__SHIFT)); 1770301092Sadrian 1771301092Sadrian /* Force WLAN LNA diversity OFF */ 1772301092Sadrian OS_REG_CLR_BIT(ah, AR_BTCOEX_WL_LNADIV, 1773301092Sadrian AR_BTCOEX_WL_LNADIV_FORCE_ON); 1774301092Sadrian } 1775301092Sadrian } 1776301092Sadrian 1777250003Sadrian#endif /* ATH_ANT_DIV_COMB */ 1778250003Sadrian OS_REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval); 1779250003Sadrian 1780250003Sadrian /* enable fast_div */ 1781250003Sadrian regval = OS_REG_READ(ah, AR_PHY_CCK_DETECT); 1782250003Sadrian regval &= (~BBB_SIG_DETECT__ENABLE_ANT_FAST_DIV__MASK); 1783250003Sadrian regval |= ((value >> 7) & 0x1) << 1784250003Sadrian BBB_SIG_DETECT__ENABLE_ANT_FAST_DIV__SHIFT; 1785250003Sadrian#if ATH_ANT_DIV_COMB 1786301092Sadrian if ((AR_SREV_POSEIDON(ah) || AR_SREV_APHRODITE(ah)) 1787301092Sadrian && (ahp->ah_lna_div_use_bt_ant_enable == TRUE) ) { 1788250003Sadrian regval |= FAST_DIV_ENABLE; 1789250003Sadrian } 1790250003Sadrian#endif /* ATH_ANT_DIV_COMB */ 1791250003Sadrian OS_REG_WRITE(ah, AR_PHY_CCK_DETECT, regval); 1792250003Sadrian } 1793250003Sadrian 1794250003Sadrian#if ATH_ANT_DIV_COMB 1795250003Sadrian if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON_11_OR_LATER(ah)) { 1796250008Sadrian if (pcap->halAntDivCombSupport) { 1797250003Sadrian /* If support DivComb, set MAIN to LNA1, ALT to LNA2 at beginning */ 1798250003Sadrian regval = OS_REG_READ(ah, AR_PHY_MC_GAIN_CTRL); 1799250003Sadrian /* clear bit 25~30 main_lnaconf, alt_lnaconf, main_tb, alt_tb */ 1800250003Sadrian regval &= (~(MULTICHAIN_GAIN_CTRL__ANT_DIV_MAIN_LNACONF__MASK | 1801250003Sadrian MULTICHAIN_GAIN_CTRL__ANT_DIV_ALT_LNACONF__MASK | 1802250003Sadrian MULTICHAIN_GAIN_CTRL__ANT_DIV_ALT_GAINTB__MASK | 1803250003Sadrian MULTICHAIN_GAIN_CTRL__ANT_DIV_MAIN_GAINTB__MASK)); 1804250003Sadrian regval |= (HAL_ANT_DIV_COMB_LNA1 << 1805250003Sadrian MULTICHAIN_GAIN_CTRL__ANT_DIV_MAIN_LNACONF__SHIFT); 1806250003Sadrian regval |= (HAL_ANT_DIV_COMB_LNA2 << 1807250003Sadrian MULTICHAIN_GAIN_CTRL__ANT_DIV_ALT_LNACONF__SHIFT); 1808250003Sadrian OS_REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval); 1809250003Sadrian } 1810250003Sadrian 1811250003Sadrian } 1812250003Sadrian#endif /* ATH_ANT_DIV_COMB */ 1813250003Sadrian if (AR_SREV_POSEIDON(ah) && ( ahp->ah_diversity_control == HAL_ANT_FIXED_A 1814250003Sadrian || ahp->ah_diversity_control == HAL_ANT_FIXED_B)) 1815250003Sadrian { 1816250003Sadrian u_int32_t reg_val = OS_REG_READ(ah, AR_PHY_MC_GAIN_CTRL); 1817250003Sadrian reg_val &= ~(MULTICHAIN_GAIN_CTRL__ANT_DIV_MAIN_LNACONF__MASK | 1818250003Sadrian MULTICHAIN_GAIN_CTRL__ANT_DIV_ALT_LNACONF__MASK | 1819250003Sadrian MULTICHAIN_GAIN_CTRL__ANT_FAST_DIV_BIAS__MASK | 1820250003Sadrian MULTICHAIN_GAIN_CTRL__ANT_DIV_MAIN_GAINTB__MASK | 1821250003Sadrian MULTICHAIN_GAIN_CTRL__ANT_DIV_ALT_GAINTB__MASK ); 1822250003Sadrian 1823250003Sadrian switch (ahp->ah_diversity_control) { 1824250003Sadrian case HAL_ANT_FIXED_A: 1825250003Sadrian /* Enable first antenna only */ 1826250003Sadrian reg_val |= (HAL_ANT_DIV_COMB_LNA1 << 1827250003Sadrian MULTICHAIN_GAIN_CTRL__ANT_DIV_MAIN_LNACONF__SHIFT); 1828250003Sadrian reg_val |= (HAL_ANT_DIV_COMB_LNA2 << 1829250003Sadrian MULTICHAIN_GAIN_CTRL__ANT_DIV_ALT_LNACONF__SHIFT); 1830250003Sadrian /* main/alt gain table and Fast Div Bias all set to 0 */ 1831250003Sadrian OS_REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, reg_val); 1832250003Sadrian regval = OS_REG_READ(ah, AR_PHY_CCK_DETECT); 1833250003Sadrian regval &= (~BBB_SIG_DETECT__ENABLE_ANT_FAST_DIV__MASK); 1834250003Sadrian OS_REG_WRITE(ah, AR_PHY_CCK_DETECT, regval); 1835250003Sadrian break; 1836250003Sadrian case HAL_ANT_FIXED_B: 1837250003Sadrian /* Enable second antenna only, after checking capability */ 1838250003Sadrian reg_val |= (HAL_ANT_DIV_COMB_LNA2 << 1839250003Sadrian MULTICHAIN_GAIN_CTRL__ANT_DIV_MAIN_LNACONF__SHIFT); 1840250003Sadrian reg_val |= (HAL_ANT_DIV_COMB_LNA1 << 1841250003Sadrian MULTICHAIN_GAIN_CTRL__ANT_DIV_ALT_LNACONF__SHIFT); 1842250003Sadrian /* main/alt gain table and Fast Div all set to 0 */ 1843250003Sadrian OS_REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, reg_val); 1844250003Sadrian regval = OS_REG_READ(ah, AR_PHY_CCK_DETECT); 1845250003Sadrian regval &= (~BBB_SIG_DETECT__ENABLE_ANT_FAST_DIV__MASK); 1846250003Sadrian OS_REG_WRITE(ah, AR_PHY_CCK_DETECT, regval); 1847250003Sadrian /* For WB225, need to swith ANT2 from BT to Wifi 1848250003Sadrian * This will not affect HB125 LNA diversity feature. 1849250003Sadrian */ 1850272292Sadrian HALDEBUG(ah, HAL_DEBUG_RESET, "%s: com2=0x%08x\n", __func__, 1851272292Sadrian ah->ah_config.ath_hal_ant_ctrl_comm2g_switch_enable) 1852250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM_2, AR_SWITCH_TABLE_COM2_ALL, 1853250008Sadrian ah->ah_config.ath_hal_ant_ctrl_comm2g_switch_enable); 1854250003Sadrian break; 1855250003Sadrian default: 1856250003Sadrian break; 1857250003Sadrian } 1858250003Sadrian } 1859250003Sadrian return 0; 1860250003Sadrian} 1861250003Sadrian 1862250003Sadrianstatic u_int16_t 1863250003Sadrianar9300_attenuation_chain_get(struct ath_hal *ah, int chain, u_int16_t channel) 1864250003Sadrian{ 1865250003Sadrian int32_t f[3], t[3]; 1866250003Sadrian u_int16_t value; 1867250003Sadrian ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom; 1868250003Sadrian if (chain >= 0 && chain < OSPREY_MAX_CHAINS) { 1869250003Sadrian if (channel < 4000) { 1870250003Sadrian return eep->modal_header_2g.xatten1_db[chain]; 1871250003Sadrian } else { 1872250003Sadrian if (eep->base_ext2.xatten1_db_low[chain] != 0) { 1873250003Sadrian t[0] = eep->base_ext2.xatten1_db_low[chain]; 1874250003Sadrian f[0] = 5180; 1875250003Sadrian t[1] = eep->modal_header_5g.xatten1_db[chain]; 1876250003Sadrian f[1] = 5500; 1877250003Sadrian t[2] = eep->base_ext2.xatten1_db_high[chain]; 1878250003Sadrian f[2] = 5785; 1879250003Sadrian value = interpolate(channel, f, t, 3); 1880250003Sadrian return value; 1881250003Sadrian } else { 1882250003Sadrian return eep->modal_header_5g.xatten1_db[chain]; 1883250003Sadrian } 1884250003Sadrian } 1885250003Sadrian } 1886250003Sadrian return 0; 1887250003Sadrian} 1888250003Sadrian 1889250003Sadrianstatic u_int16_t 1890250003Sadrianar9300_attenuation_margin_chain_get(struct ath_hal *ah, int chain, 1891250003Sadrian u_int16_t channel) 1892250003Sadrian{ 1893250003Sadrian int32_t f[3], t[3]; 1894250003Sadrian u_int16_t value; 1895250003Sadrian ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom; 1896250003Sadrian if (chain >= 0 && chain < OSPREY_MAX_CHAINS) { 1897250003Sadrian if (channel < 4000) { 1898250003Sadrian return eep->modal_header_2g.xatten1_margin[chain]; 1899250003Sadrian } else { 1900250003Sadrian if (eep->base_ext2.xatten1_margin_low[chain] != 0) { 1901250003Sadrian t[0] = eep->base_ext2.xatten1_margin_low[chain]; 1902250003Sadrian f[0] = 5180; 1903250003Sadrian t[1] = eep->modal_header_5g.xatten1_margin[chain]; 1904250003Sadrian f[1] = 5500; 1905250003Sadrian t[2] = eep->base_ext2.xatten1_margin_high[chain]; 1906250003Sadrian f[2] = 5785; 1907250003Sadrian value = interpolate(channel, f, t, 3); 1908250003Sadrian return value; 1909250003Sadrian } else { 1910250003Sadrian return eep->modal_header_5g.xatten1_margin[chain]; 1911250003Sadrian } 1912250003Sadrian } 1913250003Sadrian } 1914250003Sadrian return 0; 1915250003Sadrian} 1916250003Sadrian 1917272292Sadrian#if 0 1918250003SadrianHAL_BOOL ar9300_attenuation_apply(struct ath_hal *ah, u_int16_t channel) 1919250003Sadrian{ 1920250003Sadrian u_int32_t value; 1921250008Sadrian// struct ath_hal_private *ahpriv = AH_PRIVATE(ah); 1922250003Sadrian 1923250003Sadrian /* Test value. if 0 then attenuation is unused. Don't load anything. */ 1924250003Sadrian value = ar9300_attenuation_chain_get(ah, 0, channel); 1925250003Sadrian OS_REG_RMW_FIELD(ah, 1926250003Sadrian AR_PHY_EXT_ATTEN_CTL_0, AR_PHY_EXT_ATTEN_CTL_XATTEN1_DB, value); 1927250003Sadrian value = ar9300_attenuation_margin_chain_get(ah, 0, channel); 1928250003Sadrian if (ar9300_rx_gain_index_get(ah) == 0 1929250008Sadrian && ah->ah_config.ath_hal_ext_atten_margin_cfg) 1930250003Sadrian { 1931250003Sadrian value = 5; 1932250003Sadrian } 1933250003Sadrian OS_REG_RMW_FIELD(ah, 1934250003Sadrian AR_PHY_EXT_ATTEN_CTL_0, AR_PHY_EXT_ATTEN_CTL_XATTEN1_MARGIN, value); 1935250003Sadrian 1936250003Sadrian if (!AR_SREV_HORNET(ah) && !AR_SREV_POSEIDON(ah)) { 1937250003Sadrian value = ar9300_attenuation_chain_get(ah, 1, channel); 1938250003Sadrian OS_REG_RMW_FIELD(ah, 1939250003Sadrian AR_PHY_EXT_ATTEN_CTL_1, AR_PHY_EXT_ATTEN_CTL_XATTEN1_DB, value); 1940250003Sadrian value = ar9300_attenuation_margin_chain_get(ah, 1, channel); 1941250003Sadrian OS_REG_RMW_FIELD(ah, 1942250003Sadrian AR_PHY_EXT_ATTEN_CTL_1, AR_PHY_EXT_ATTEN_CTL_XATTEN1_MARGIN, 1943250003Sadrian value); 1944291437Sadrian if (!AR_SREV_WASP(ah) && !AR_SREV_JUPITER(ah)&& !AR_SREV_HONEYBEE(ah) ) { 1945250003Sadrian value = ar9300_attenuation_chain_get(ah, 2, channel); 1946250003Sadrian OS_REG_RMW_FIELD(ah, 1947250003Sadrian AR_PHY_EXT_ATTEN_CTL_2, AR_PHY_EXT_ATTEN_CTL_XATTEN1_DB, value); 1948250003Sadrian value = ar9300_attenuation_margin_chain_get(ah, 2, channel); 1949250003Sadrian OS_REG_RMW_FIELD(ah, 1950250003Sadrian AR_PHY_EXT_ATTEN_CTL_2, AR_PHY_EXT_ATTEN_CTL_XATTEN1_MARGIN, 1951250003Sadrian value); 1952250003Sadrian } 1953250003Sadrian } 1954250003Sadrian return 0; 1955250003Sadrian} 1956272292Sadrian#endif 1957272292SadrianHAL_BOOL 1958272292Sadrianar9300_attenuation_apply(struct ath_hal *ah, u_int16_t channel) 1959272292Sadrian{ 1960272292Sadrian int i; 1961272292Sadrian uint32_t value; 1962272292Sadrian uint32_t ext_atten_reg[3] = { 1963272292Sadrian AR_PHY_EXT_ATTEN_CTL_0, 1964272292Sadrian AR_PHY_EXT_ATTEN_CTL_1, 1965272292Sadrian AR_PHY_EXT_ATTEN_CTL_2 1966272292Sadrian }; 1967250003Sadrian 1968272292Sadrian /* 1969272292Sadrian * If it's an AR9462 and we're receiving on the second 1970272292Sadrian * chain only, set the chain 0 details from chain 1 1971272292Sadrian * calibration. 1972272292Sadrian * 1973272292Sadrian * This is from ath9k. 1974272292Sadrian */ 1975272292Sadrian if (AR_SREV_JUPITER(ah) && (AH9300(ah)->ah_rx_chainmask == 0x2)) { 1976272292Sadrian value = ar9300_attenuation_chain_get(ah, 1, channel); 1977272292Sadrian OS_REG_RMW_FIELD(ah, ext_atten_reg[0], 1978272292Sadrian AR_PHY_EXT_ATTEN_CTL_XATTEN1_DB, value); 1979272292Sadrian value = ar9300_attenuation_margin_chain_get(ah, 1, channel); 1980272292Sadrian OS_REG_RMW_FIELD(ah, ext_atten_reg[0], 1981272292Sadrian AR_PHY_EXT_ATTEN_CTL_XATTEN1_MARGIN, value); 1982272292Sadrian } 1983272292Sadrian 1984272292Sadrian /* 1985272292Sadrian * Now, loop over the configured transmit chains and 1986272292Sadrian * load in the attenuation/margin settings as appropriate. 1987272292Sadrian */ 1988272292Sadrian for (i = 0; i < 3; i++) { 1989272292Sadrian if ((AH9300(ah)->ah_tx_chainmask & (1 << i)) == 0) 1990272292Sadrian continue; 1991272292Sadrian 1992272292Sadrian value = ar9300_attenuation_chain_get(ah, i, channel); 1993272292Sadrian OS_REG_RMW_FIELD(ah, ext_atten_reg[i], 1994272292Sadrian AR_PHY_EXT_ATTEN_CTL_XATTEN1_DB, 1995272292Sadrian value); 1996272292Sadrian 1997272292Sadrian if (AR_SREV_POSEIDON(ah) && 1998272292Sadrian (ar9300_rx_gain_index_get(ah) == 0) && 1999272292Sadrian ah->ah_config.ath_hal_ext_atten_margin_cfg) { 2000272292Sadrian value = 5; 2001272292Sadrian } else { 2002272292Sadrian value = ar9300_attenuation_margin_chain_get(ah, 0, 2003272292Sadrian channel); 2004272292Sadrian } 2005272292Sadrian 2006272292Sadrian /* 2007272292Sadrian * I'm not sure why it's loading in this setting into 2008272292Sadrian * the chain 0 margin regardless of the current chain. 2009272292Sadrian */ 2010272292Sadrian if (ah->ah_config.ath_hal_min_gainidx) 2011272292Sadrian OS_REG_RMW_FIELD(ah, 2012272292Sadrian AR_PHY_EXT_ATTEN_CTL_0, 2013272292Sadrian AR_PHY_EXT_ATTEN_CTL_XATTEN1_MARGIN, 2014272292Sadrian value); 2015272292Sadrian 2016272292Sadrian OS_REG_RMW_FIELD(ah, 2017272292Sadrian ext_atten_reg[i], 2018272292Sadrian AR_PHY_EXT_ATTEN_CTL_XATTEN1_MARGIN, 2019272292Sadrian value); 2020272292Sadrian } 2021272292Sadrian 2022272292Sadrian return (0); 2023272292Sadrian} 2024272292Sadrian 2025272292Sadrian 2026250003Sadrianstatic u_int16_t ar9300_quick_drop_get(struct ath_hal *ah, 2027250003Sadrian int chain, u_int16_t channel) 2028250003Sadrian{ 2029250003Sadrian int32_t f[3], t[3]; 2030250003Sadrian u_int16_t value; 2031250003Sadrian ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom; 2032250003Sadrian 2033250003Sadrian if (channel < 4000) { 2034250003Sadrian return eep->modal_header_2g.quick_drop; 2035250003Sadrian } else { 2036250003Sadrian t[0] = eep->base_ext1.quick_drop_low; 2037250003Sadrian f[0] = 5180; 2038250003Sadrian t[1] = eep->modal_header_5g.quick_drop; 2039250003Sadrian f[1] = 5500; 2040250003Sadrian t[2] = eep->base_ext1.quick_drop_high; 2041250003Sadrian f[2] = 5785; 2042250003Sadrian value = interpolate(channel, f, t, 3); 2043250003Sadrian return value; 2044250003Sadrian } 2045250003Sadrian} 2046250003Sadrian 2047250003Sadrian 2048250003Sadrianstatic HAL_BOOL ar9300_quick_drop_apply(struct ath_hal *ah, u_int16_t channel) 2049250003Sadrian{ 2050250003Sadrian ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom; 2051250003Sadrian u_int32_t value; 2052250003Sadrian // 2053250003Sadrian // Test value. if 0 then quickDrop is unused. Don't load anything. 2054250003Sadrian // 2055250003Sadrian if (eep->base_eep_header.misc_configuration & 0x10) 2056250003Sadrian { 2057250003Sadrian if (AR_SREV_OSPREY(ah) || AR_SREV_AR9580(ah) || AR_SREV_WASP(ah)) 2058250003Sadrian { 2059250003Sadrian value = ar9300_quick_drop_get(ah, 0, channel); 2060250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_AGC, AR_PHY_AGC_QUICK_DROP, value); 2061250003Sadrian } 2062250003Sadrian } 2063250003Sadrian return 0; 2064250003Sadrian} 2065250003Sadrian 2066250003Sadrianstatic u_int16_t ar9300_tx_end_to_xpa_off_get(struct ath_hal *ah, u_int16_t channel) 2067250003Sadrian{ 2068250003Sadrian ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom; 2069250003Sadrian 2070250003Sadrian if (channel < 4000) { 2071250003Sadrian return eep->modal_header_2g.tx_end_to_xpa_off; 2072250003Sadrian } else { 2073250003Sadrian return eep->modal_header_5g.tx_end_to_xpa_off; 2074250003Sadrian } 2075250003Sadrian} 2076250003Sadrian 2077250003Sadrianstatic HAL_BOOL ar9300_tx_end_to_xpab_off_apply(struct ath_hal *ah, u_int16_t channel) 2078250003Sadrian{ 2079250003Sadrian u_int32_t value; 2080250003Sadrian 2081250003Sadrian value = ar9300_tx_end_to_xpa_off_get(ah, channel); 2082250003Sadrian /* Apply to both xpaa and xpab */ 2083250003Sadrian if (AR_SREV_OSPREY(ah) || AR_SREV_AR9580(ah) || AR_SREV_WASP(ah)) 2084250003Sadrian { 2085250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_XPA_TIMING_CTL, 2086250003Sadrian AR_PHY_XPA_TIMING_CTL_TX_END_XPAB_OFF, value); 2087250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_XPA_TIMING_CTL, 2088250003Sadrian AR_PHY_XPA_TIMING_CTL_TX_END_XPAA_OFF, value); 2089250003Sadrian } 2090250003Sadrian return 0; 2091250003Sadrian} 2092250003Sadrian 2093250003Sadrianstatic int 2094250003Sadrianar9300_eeprom_cal_pier_get(struct ath_hal *ah, int mode, int ipier, int ichain, 2095250003Sadrian int *pfrequency, int *pcorrection, int *ptemperature, int *pvoltage) 2096250003Sadrian{ 2097250003Sadrian u_int8_t *p_cal_pier; 2098250003Sadrian OSP_CAL_DATA_PER_FREQ_OP_LOOP *p_cal_pier_struct; 2099250003Sadrian int is_2ghz; 2100250003Sadrian ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom; 2101250003Sadrian 2102250003Sadrian if (ichain >= OSPREY_MAX_CHAINS) { 2103250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, 2104250003Sadrian "%s: Invalid chain index, must be less than %d\n", 2105250003Sadrian __func__, OSPREY_MAX_CHAINS); 2106250003Sadrian return -1; 2107250003Sadrian } 2108250003Sadrian 2109250003Sadrian if (mode) {/* 5GHz */ 2110250003Sadrian if (ipier >= OSPREY_NUM_5G_CAL_PIERS){ 2111250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, 2112250003Sadrian "%s: Invalid 5GHz cal pier index, must be less than %d\n", 2113250003Sadrian __func__, OSPREY_NUM_5G_CAL_PIERS); 2114250003Sadrian return -1; 2115250003Sadrian } 2116250003Sadrian p_cal_pier = &(eep->cal_freq_pier_5g[ipier]); 2117250003Sadrian p_cal_pier_struct = &(eep->cal_pier_data_5g[ichain][ipier]); 2118250003Sadrian is_2ghz = 0; 2119250003Sadrian } else { 2120250003Sadrian if (ipier >= OSPREY_NUM_2G_CAL_PIERS){ 2121250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, 2122250003Sadrian "%s: Invalid 2GHz cal pier index, must be less than %d\n", 2123250003Sadrian __func__, OSPREY_NUM_2G_CAL_PIERS); 2124250003Sadrian return -1; 2125250003Sadrian } 2126250003Sadrian 2127250003Sadrian p_cal_pier = &(eep->cal_freq_pier_2g[ipier]); 2128250003Sadrian p_cal_pier_struct = &(eep->cal_pier_data_2g[ichain][ipier]); 2129250003Sadrian is_2ghz = 1; 2130250003Sadrian } 2131250003Sadrian *pfrequency = FBIN2FREQ(*p_cal_pier, is_2ghz); 2132250003Sadrian *pcorrection = p_cal_pier_struct->ref_power; 2133250003Sadrian *ptemperature = p_cal_pier_struct->temp_meas; 2134250003Sadrian *pvoltage = p_cal_pier_struct->volt_meas; 2135250003Sadrian return 0; 2136250003Sadrian} 2137250003Sadrian 2138250003Sadrian/* 2139250003Sadrian * Apply the recorded correction values. 2140250003Sadrian */ 2141250003Sadrianstatic int 2142250003Sadrianar9300_calibration_apply(struct ath_hal *ah, int frequency) 2143250003Sadrian{ 2144250008Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 2145250008Sadrian 2146250003Sadrian int ichain, ipier, npier; 2147250003Sadrian int mode; 2148250003Sadrian int fdiff; 2149250003Sadrian int pfrequency, pcorrection, ptemperature, pvoltage; 2150250003Sadrian int bf, factor, plus; 2151250003Sadrian 2152250003Sadrian int lfrequency[AR9300_MAX_CHAINS]; 2153250003Sadrian int hfrequency[AR9300_MAX_CHAINS]; 2154250003Sadrian 2155250003Sadrian int lcorrection[AR9300_MAX_CHAINS]; 2156250003Sadrian int hcorrection[AR9300_MAX_CHAINS]; 2157250003Sadrian int correction[AR9300_MAX_CHAINS]; 2158250003Sadrian 2159250003Sadrian int ltemperature[AR9300_MAX_CHAINS]; 2160250003Sadrian int htemperature[AR9300_MAX_CHAINS]; 2161250003Sadrian int temperature[AR9300_MAX_CHAINS]; 2162250003Sadrian 2163250003Sadrian int lvoltage[AR9300_MAX_CHAINS]; 2164250003Sadrian int hvoltage[AR9300_MAX_CHAINS]; 2165250003Sadrian int voltage[AR9300_MAX_CHAINS]; 2166250003Sadrian 2167250003Sadrian mode = (frequency >= 4000); 2168250003Sadrian npier = (mode) ? OSPREY_NUM_5G_CAL_PIERS : OSPREY_NUM_2G_CAL_PIERS; 2169250003Sadrian 2170250003Sadrian for (ichain = 0; ichain < AR9300_MAX_CHAINS; ichain++) { 2171250003Sadrian lfrequency[ichain] = 0; 2172250003Sadrian hfrequency[ichain] = 100000; 2173250003Sadrian } 2174250003Sadrian /* 2175250003Sadrian * identify best lower and higher frequency calibration measurement 2176250003Sadrian */ 2177250003Sadrian for (ichain = 0; ichain < AR9300_MAX_CHAINS; ichain++) { 2178250003Sadrian for (ipier = 0; ipier < npier; ipier++) { 2179250003Sadrian if (ar9300_eeprom_cal_pier_get( 2180250003Sadrian ah, mode, ipier, ichain, 2181250003Sadrian &pfrequency, &pcorrection, &ptemperature, &pvoltage) == 0) 2182250003Sadrian { 2183250003Sadrian fdiff = frequency - pfrequency; 2184250003Sadrian /* 2185250003Sadrian * this measurement is higher than our desired frequency 2186250003Sadrian */ 2187250003Sadrian if (fdiff <= 0) { 2188250003Sadrian if (hfrequency[ichain] <= 0 || 2189250003Sadrian hfrequency[ichain] >= 100000 || 2190250003Sadrian fdiff > (frequency - hfrequency[ichain])) 2191250003Sadrian { 2192250003Sadrian /* 2193250003Sadrian * new best higher frequency measurement 2194250003Sadrian */ 2195250003Sadrian hfrequency[ichain] = pfrequency; 2196250003Sadrian hcorrection[ichain] = pcorrection; 2197250003Sadrian htemperature[ichain] = ptemperature; 2198250003Sadrian hvoltage[ichain] = pvoltage; 2199250003Sadrian } 2200250003Sadrian } 2201250003Sadrian if (fdiff >= 0) { 2202250003Sadrian if (lfrequency[ichain] <= 0 || 2203250003Sadrian fdiff < (frequency - lfrequency[ichain])) 2204250003Sadrian { 2205250003Sadrian /* 2206250003Sadrian * new best lower frequency measurement 2207250003Sadrian */ 2208250003Sadrian lfrequency[ichain] = pfrequency; 2209250003Sadrian lcorrection[ichain] = pcorrection; 2210250003Sadrian ltemperature[ichain] = ptemperature; 2211250003Sadrian lvoltage[ichain] = pvoltage; 2212250003Sadrian } 2213250003Sadrian } 2214250003Sadrian } 2215250003Sadrian } 2216250003Sadrian } 2217250003Sadrian /* interpolate */ 2218250003Sadrian for (ichain = 0; ichain < AR9300_MAX_CHAINS; ichain++) { 2219250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, 2220250003Sadrian "%s: ch=%d f=%d low=%d %d h=%d %d\n", 2221250003Sadrian __func__, ichain, frequency, 2222250003Sadrian lfrequency[ichain], lcorrection[ichain], 2223250003Sadrian hfrequency[ichain], hcorrection[ichain]); 2224250003Sadrian /* 2225250003Sadrian * they're the same, so just pick one 2226250003Sadrian */ 2227250003Sadrian if (hfrequency[ichain] == lfrequency[ichain]) { 2228250003Sadrian correction[ichain] = lcorrection[ichain]; 2229250003Sadrian voltage[ichain] = lvoltage[ichain]; 2230250003Sadrian temperature[ichain] = ltemperature[ichain]; 2231250003Sadrian } else if (frequency - lfrequency[ichain] < 1000) { 2232250003Sadrian /* the low frequency is good */ 2233250003Sadrian if (hfrequency[ichain] - frequency < 1000) { 2234250003Sadrian /* 2235250003Sadrian * The high frequency is good too - 2236250003Sadrian * interpolate with round off. 2237250003Sadrian */ 2238250003Sadrian int mult, div, diff; 2239250003Sadrian mult = frequency - lfrequency[ichain]; 2240250003Sadrian div = hfrequency[ichain] - lfrequency[ichain]; 2241250003Sadrian 2242250003Sadrian diff = hcorrection[ichain] - lcorrection[ichain]; 2243250003Sadrian bf = 2 * diff * mult / div; 2244250003Sadrian plus = (bf % 2); 2245250003Sadrian factor = bf / 2; 2246250003Sadrian correction[ichain] = lcorrection[ichain] + factor + plus; 2247250003Sadrian 2248250003Sadrian diff = htemperature[ichain] - ltemperature[ichain]; 2249250003Sadrian bf = 2 * diff * mult / div; 2250250003Sadrian plus = (bf % 2); 2251250003Sadrian factor = bf / 2; 2252250003Sadrian temperature[ichain] = ltemperature[ichain] + factor + plus; 2253250003Sadrian 2254250003Sadrian diff = hvoltage[ichain] - lvoltage[ichain]; 2255250003Sadrian bf = 2 * diff * mult / div; 2256250003Sadrian plus = (bf % 2); 2257250003Sadrian factor = bf / 2; 2258250003Sadrian voltage[ichain] = lvoltage[ichain] + factor + plus; 2259250003Sadrian } else { 2260250003Sadrian /* only low is good, use it */ 2261250003Sadrian correction[ichain] = lcorrection[ichain]; 2262250003Sadrian temperature[ichain] = ltemperature[ichain]; 2263250003Sadrian voltage[ichain] = lvoltage[ichain]; 2264250003Sadrian } 2265250003Sadrian } else if (hfrequency[ichain] - frequency < 1000) { 2266250003Sadrian /* only high is good, use it */ 2267250003Sadrian correction[ichain] = hcorrection[ichain]; 2268250003Sadrian temperature[ichain] = htemperature[ichain]; 2269250003Sadrian voltage[ichain] = hvoltage[ichain]; 2270250003Sadrian } else { 2271250003Sadrian /* nothing is good, presume 0???? */ 2272250003Sadrian correction[ichain] = 0; 2273250003Sadrian temperature[ichain] = 0; 2274250003Sadrian voltage[ichain] = 0; 2275250003Sadrian } 2276250003Sadrian } 2277250003Sadrian 2278250008Sadrian /* GreenTx isn't currently supported */ 2279250003Sadrian /* GreenTx */ 2280250008Sadrian if (ah->ah_config.ath_hal_sta_update_tx_pwr_enable) { 2281250003Sadrian if (AR_SREV_POSEIDON(ah)) { 2282250003Sadrian /* Get calibrated OLPC gain delta value for GreenTx */ 2283250008Sadrian ahp->ah_db2[POSEIDON_STORED_REG_G2_OLPC_OFFSET] = 2284250003Sadrian (u_int32_t) correction[0]; 2285250003Sadrian } 2286250003Sadrian } 2287250003Sadrian 2288250003Sadrian ar9300_power_control_override( 2289250003Sadrian ah, frequency, correction, voltage, temperature); 2290250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, 2291250003Sadrian "%s: for frequency=%d, calibration correction = %d %d %d\n", 2292250003Sadrian __func__, frequency, correction[0], correction[1], correction[2]); 2293250003Sadrian 2294250003Sadrian return 0; 2295250003Sadrian} 2296250003Sadrian 2297250003Sadrianint 2298250003Sadrianar9300_power_control_override(struct ath_hal *ah, int frequency, 2299250003Sadrian int *correction, int *voltage, int *temperature) 2300250003Sadrian{ 2301250003Sadrian int temp_slope = 0; 2302250003Sadrian int temp_slope_1 = 0; 2303250003Sadrian int temp_slope_2 = 0; 2304250003Sadrian ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom; 2305250003Sadrian int32_t f[8], t[8],t1[3], t2[3]; 2306250003Sadrian int i; 2307250003Sadrian 2308250003Sadrian OS_REG_RMW(ah, AR_PHY_TPC_11_B0, 2309250003Sadrian (correction[0] << AR_PHY_TPC_OLPC_GAIN_DELTA_S), 2310250003Sadrian AR_PHY_TPC_OLPC_GAIN_DELTA); 2311250003Sadrian if (!AR_SREV_POSEIDON(ah)) { 2312250003Sadrian OS_REG_RMW(ah, AR_PHY_TPC_11_B1, 2313250003Sadrian (correction[1] << AR_PHY_TPC_OLPC_GAIN_DELTA_S), 2314250003Sadrian AR_PHY_TPC_OLPC_GAIN_DELTA); 2315291437Sadrian if (!AR_SREV_WASP(ah) && !AR_SREV_JUPITER(ah) && !AR_SREV_HONEYBEE(ah) ) { 2316250003Sadrian OS_REG_RMW(ah, AR_PHY_TPC_11_B2, 2317250003Sadrian (correction[2] << AR_PHY_TPC_OLPC_GAIN_DELTA_S), 2318250003Sadrian AR_PHY_TPC_OLPC_GAIN_DELTA); 2319250003Sadrian } 2320250003Sadrian } 2321250003Sadrian /* 2322250003Sadrian * enable open loop power control on chip 2323250003Sadrian */ 2324250003Sadrian OS_REG_RMW(ah, AR_PHY_TPC_6_B0, 2325250003Sadrian (3 << AR_PHY_TPC_6_ERROR_EST_MODE_S), AR_PHY_TPC_6_ERROR_EST_MODE); 2326250003Sadrian if (!AR_SREV_POSEIDON(ah)) { 2327250003Sadrian OS_REG_RMW(ah, AR_PHY_TPC_6_B1, 2328250003Sadrian (3 << AR_PHY_TPC_6_ERROR_EST_MODE_S), AR_PHY_TPC_6_ERROR_EST_MODE); 2329291437Sadrian if (!AR_SREV_WASP(ah) && !AR_SREV_JUPITER(ah) && !AR_SREV_HONEYBEE(ah) ) { 2330250003Sadrian OS_REG_RMW(ah, AR_PHY_TPC_6_B2, 2331250003Sadrian (3 << AR_PHY_TPC_6_ERROR_EST_MODE_S), 2332250003Sadrian AR_PHY_TPC_6_ERROR_EST_MODE); 2333250003Sadrian } 2334250003Sadrian } 2335250003Sadrian 2336250003Sadrian /* 2337250003Sadrian * Enable temperature compensation 2338250003Sadrian * Need to use register names 2339250003Sadrian */ 2340250003Sadrian if (frequency < 4000) { 2341250003Sadrian temp_slope = eep->modal_header_2g.temp_slope; 2342250003Sadrian } else { 2343250003Sadrian if ((eep->base_eep_header.misc_configuration & 0x20) != 0) 2344250003Sadrian { 2345250003Sadrian for(i=0;i<8;i++) 2346250003Sadrian { 2347250003Sadrian t[i]=eep->base_ext1.tempslopextension[i]; 2348250003Sadrian f[i]=FBIN2FREQ(eep->cal_freq_pier_5g[i], 0); 2349250003Sadrian } 2350250003Sadrian temp_slope=interpolate(frequency,f,t,8); 2351250003Sadrian } 2352250003Sadrian else 2353250003Sadrian { 2354250003Sadrian if(!AR_SREV_SCORPION(ah)) { 2355250003Sadrian if (eep->base_ext2.temp_slope_low != 0) { 2356250003Sadrian t[0] = eep->base_ext2.temp_slope_low; 2357250003Sadrian f[0] = 5180; 2358250003Sadrian t[1] = eep->modal_header_5g.temp_slope; 2359250003Sadrian f[1] = 5500; 2360250003Sadrian t[2] = eep->base_ext2.temp_slope_high; 2361250003Sadrian f[2] = 5785; 2362250003Sadrian temp_slope = interpolate(frequency, f, t, 3); 2363250003Sadrian } else { 2364250003Sadrian temp_slope = eep->modal_header_5g.temp_slope; 2365250003Sadrian } 2366250003Sadrian } else { 2367250003Sadrian /* 2368250003Sadrian * Scorpion has individual chain tempslope values 2369250003Sadrian */ 2370250003Sadrian t[0] = eep->base_ext1.tempslopextension[2]; 2371250003Sadrian t1[0]= eep->base_ext1.tempslopextension[3]; 2372250003Sadrian t2[0]= eep->base_ext1.tempslopextension[4]; 2373250003Sadrian f[0] = 5180; 2374250003Sadrian t[1] = eep->modal_header_5g.temp_slope; 2375250003Sadrian t1[1]= eep->base_ext1.tempslopextension[0]; 2376250003Sadrian t2[1]= eep->base_ext1.tempslopextension[1]; 2377250003Sadrian f[1] = 5500; 2378250003Sadrian t[2] = eep->base_ext1.tempslopextension[5]; 2379250003Sadrian t1[2]= eep->base_ext1.tempslopextension[6]; 2380250003Sadrian t2[2]= eep->base_ext1.tempslopextension[7]; 2381250003Sadrian f[2] = 5785; 2382250003Sadrian temp_slope = interpolate(frequency, f, t, 3); 2383250003Sadrian temp_slope_1=interpolate(frequency, f, t1,3); 2384250003Sadrian temp_slope_2=interpolate(frequency, f, t2,3); 2385250003Sadrian } 2386250003Sadrian } 2387250003Sadrian } 2388250003Sadrian 2389291437Sadrian if (!AR_SREV_SCORPION(ah) && !AR_SREV_HONEYBEE(ah)) { 2390250003Sadrian OS_REG_RMW_FIELD(ah, 2391250003Sadrian AR_PHY_TPC_19, AR_PHY_TPC_19_ALPHA_THERM, temp_slope); 2392250003Sadrian } else { 2393291437Sadrian /*Scorpion and Honeybee has tempSlope register for each chain*/ 2394250003Sadrian /*Check whether temp_compensation feature is enabled or not*/ 2395250003Sadrian if (eep->base_eep_header.feature_enable & 0x1){ 2396250003Sadrian if(frequency < 4000) { 2397291437Sadrian if (((eep->base_eep_header.txrx_mask & 0xf0) >> 4) & 0x1) { 2398250003Sadrian OS_REG_RMW_FIELD(ah, 2399250003Sadrian AR_PHY_TPC_19, AR_PHY_TPC_19_ALPHA_THERM, 2400250003Sadrian eep->base_ext2.temp_slope_low); 2401291437Sadrian } 2402291437Sadrian if (((eep->base_eep_header.txrx_mask & 0xf0) >> 4) & 0x2) { 2403250003Sadrian OS_REG_RMW_FIELD(ah, 2404250003Sadrian AR_SCORPION_PHY_TPC_19_B1, AR_PHY_TPC_19_ALPHA_THERM, 2405250003Sadrian temp_slope); 2406291437Sadrian } 2407291437Sadrian if (((eep->base_eep_header.txrx_mask & 0xf0) >> 4) & 0x4) { 2408250003Sadrian OS_REG_RMW_FIELD(ah, 2409250003Sadrian AR_SCORPION_PHY_TPC_19_B2, AR_PHY_TPC_19_ALPHA_THERM, 2410250003Sadrian eep->base_ext2.temp_slope_high); 2411291437Sadrian } 2412250003Sadrian } else { 2413291437Sadrian if (((eep->base_eep_header.txrx_mask & 0xf0) >> 4) & 0x1) { 2414250003Sadrian OS_REG_RMW_FIELD(ah, 2415250003Sadrian AR_PHY_TPC_19, AR_PHY_TPC_19_ALPHA_THERM, 2416250003Sadrian temp_slope); 2417291437Sadrian } 2418291437Sadrian if (((eep->base_eep_header.txrx_mask & 0xf0) >> 4) & 0x2) { 2419250003Sadrian OS_REG_RMW_FIELD(ah, 2420250003Sadrian AR_SCORPION_PHY_TPC_19_B1, AR_PHY_TPC_19_ALPHA_THERM, 2421250003Sadrian temp_slope_1); 2422291437Sadrian } 2423291437Sadrian if (((eep->base_eep_header.txrx_mask & 0xf0) >> 4) & 0x4) { 2424250003Sadrian OS_REG_RMW_FIELD(ah, 2425250003Sadrian AR_SCORPION_PHY_TPC_19_B2, AR_PHY_TPC_19_ALPHA_THERM, 2426250003Sadrian temp_slope_2); 2427291437Sadrian } 2428250003Sadrian } 2429250003Sadrian }else { 2430250003Sadrian /* If temp compensation is not enabled, set all registers to 0*/ 2431291437Sadrian if (((eep->base_eep_header.txrx_mask & 0xf0) >> 4) & 0x1) { 2432250003Sadrian OS_REG_RMW_FIELD(ah, 2433250003Sadrian AR_PHY_TPC_19, AR_PHY_TPC_19_ALPHA_THERM, 0); 2434291437Sadrian } 2435291437Sadrian if (((eep->base_eep_header.txrx_mask & 0xf0) >> 4) & 0x2) { 2436250003Sadrian OS_REG_RMW_FIELD(ah, 2437250003Sadrian AR_SCORPION_PHY_TPC_19_B1, AR_PHY_TPC_19_ALPHA_THERM, 0); 2438291437Sadrian } 2439291437Sadrian if (((eep->base_eep_header.txrx_mask & 0xf0) >> 4) & 0x4) { 2440250003Sadrian OS_REG_RMW_FIELD(ah, 2441250003Sadrian AR_SCORPION_PHY_TPC_19_B2, AR_PHY_TPC_19_ALPHA_THERM, 0); 2442291437Sadrian } 2443250003Sadrian } 2444250003Sadrian } 2445250003Sadrian OS_REG_RMW_FIELD(ah, 2446250003Sadrian AR_PHY_TPC_18, AR_PHY_TPC_18_THERM_CAL_VALUE, temperature[0]); 2447250003Sadrian 2448250003Sadrian return 0; 2449250003Sadrian} 2450250003Sadrian 2451250003Sadrian/************************************************************** 2452250003Sadrian * ar9300_eep_def_get_max_edge_power 2453250003Sadrian * 2454250003Sadrian * Find the maximum conformance test limit for the given channel and CTL info 2455250003Sadrian */ 2456250003Sadrianstatic inline u_int16_t 2457250003Sadrianar9300_eep_def_get_max_edge_power(ar9300_eeprom_t *p_eep_data, u_int16_t freq, 2458250003Sadrian int idx, HAL_BOOL is_2ghz) 2459250003Sadrian{ 2460250003Sadrian u_int16_t twice_max_edge_power = AR9300_MAX_RATE_POWER; 2461250003Sadrian u_int8_t *ctl_freqbin = is_2ghz ? 2462250003Sadrian &p_eep_data->ctl_freqbin_2G[idx][0] : 2463250003Sadrian &p_eep_data->ctl_freqbin_5G[idx][0]; 2464250003Sadrian u_int16_t num_edges = is_2ghz ? 2465250003Sadrian OSPREY_NUM_BAND_EDGES_2G : OSPREY_NUM_BAND_EDGES_5G; 2466250003Sadrian int i; 2467250003Sadrian 2468250003Sadrian /* Get the edge power */ 2469250003Sadrian for (i = 0; (i < num_edges) && (ctl_freqbin[i] != AR9300_BCHAN_UNUSED); i++) 2470250003Sadrian { 2471250003Sadrian /* 2472250003Sadrian * If there's an exact channel match or an inband flag set 2473250003Sadrian * on the lower channel use the given rd_edge_power 2474250003Sadrian */ 2475250003Sadrian if (freq == fbin2freq(ctl_freqbin[i], is_2ghz)) { 2476250003Sadrian if (is_2ghz) { 2477250003Sadrian twice_max_edge_power = 2478250003Sadrian p_eep_data->ctl_power_data_2g[idx].ctl_edges[i].t_power; 2479250003Sadrian } else { 2480250003Sadrian twice_max_edge_power = 2481250003Sadrian p_eep_data->ctl_power_data_5g[idx].ctl_edges[i].t_power; 2482250003Sadrian } 2483250003Sadrian break; 2484250003Sadrian } else if ((i > 0) && (freq < fbin2freq(ctl_freqbin[i], is_2ghz))) { 2485250003Sadrian if (is_2ghz) { 2486250003Sadrian if (fbin2freq(ctl_freqbin[i - 1], 1) < freq && 2487250003Sadrian p_eep_data->ctl_power_data_2g[idx].ctl_edges[i - 1].flag) 2488250003Sadrian { 2489250003Sadrian twice_max_edge_power = 2490250003Sadrian p_eep_data->ctl_power_data_2g[idx]. 2491250003Sadrian ctl_edges[i - 1].t_power; 2492250003Sadrian } 2493250003Sadrian } else { 2494250003Sadrian if (fbin2freq(ctl_freqbin[i - 1], 0) < freq && 2495250003Sadrian p_eep_data->ctl_power_data_5g[idx].ctl_edges[i - 1].flag) 2496250003Sadrian { 2497250003Sadrian twice_max_edge_power = 2498250003Sadrian p_eep_data->ctl_power_data_5g[idx]. 2499250003Sadrian ctl_edges[i - 1].t_power; 2500250003Sadrian } 2501250003Sadrian } 2502250003Sadrian /* 2503250003Sadrian * Leave loop - no more affecting edges possible 2504250003Sadrian * in this monotonic increasing list 2505250003Sadrian */ 2506250003Sadrian break; 2507250003Sadrian } 2508250003Sadrian } 2509250003Sadrian /* 2510250003Sadrian * EV89475: EEPROM might contain 0 txpower in CTL table for certain 2511250003Sadrian * 2.4GHz channels. We workaround it by overwriting 60 (30 dBm) here. 2512250003Sadrian */ 2513250003Sadrian if (is_2ghz && (twice_max_edge_power == 0)) { 2514250003Sadrian twice_max_edge_power = 60; 2515250003Sadrian } 2516250003Sadrian 2517250003Sadrian HALASSERT(twice_max_edge_power > 0); 2518250003Sadrian return twice_max_edge_power; 2519250003Sadrian} 2520250003Sadrian 2521250003SadrianHAL_BOOL 2522250003Sadrianar9300_eeprom_set_power_per_rate_table( 2523250003Sadrian struct ath_hal *ah, 2524250003Sadrian ar9300_eeprom_t *p_eep_data, 2525250008Sadrian const struct ieee80211_channel *chan, 2526250003Sadrian u_int8_t *p_pwr_array, 2527250003Sadrian u_int16_t cfg_ctl, 2528250003Sadrian u_int16_t antenna_reduction, 2529250003Sadrian u_int16_t twice_max_regulatory_power, 2530250003Sadrian u_int16_t power_limit, 2531250003Sadrian u_int8_t chainmask) 2532250003Sadrian{ 2533250003Sadrian /* Local defines to distinguish between extension and control CTL's */ 2534250003Sadrian#define EXT_ADDITIVE (0x8000) 2535250003Sadrian#define CTL_11A_EXT (CTL_11A | EXT_ADDITIVE) 2536250003Sadrian#define CTL_11G_EXT (CTL_11G | EXT_ADDITIVE) 2537250003Sadrian#define CTL_11B_EXT (CTL_11B | EXT_ADDITIVE) 2538250003Sadrian#define REDUCE_SCALED_POWER_BY_TWO_CHAIN 6 /* 10*log10(2)*2 */ 2539250003Sadrian#define REDUCE_SCALED_POWER_BY_THREE_CHAIN 10 /* 10*log10(3)*2 */ 2540250003Sadrian#define PWRINCR_3_TO_1_CHAIN 9 /* 10*log(3)*2 */ 2541250003Sadrian#define PWRINCR_3_TO_2_CHAIN 3 /* floor(10*log(3/2)*2) */ 2542250003Sadrian#define PWRINCR_2_TO_1_CHAIN 6 /* 10*log(2)*2 */ 2543250003Sadrian 2544250003Sadrian static const u_int16_t tp_scale_reduction_table[5] = 2545250003Sadrian { 0, 3, 6, 9, AR9300_MAX_RATE_POWER }; 2546250003Sadrian int i; 2547250003Sadrian int16_t twice_largest_antenna; 2548250003Sadrian u_int16_t twice_antenna_reduction = 2*antenna_reduction ; 2549250003Sadrian int16_t scaled_power = 0, min_ctl_power, max_reg_allowed_power; 2550250003Sadrian#define SUB_NUM_CTL_MODES_AT_5G_40 2 /* excluding HT40, EXT-OFDM */ 2551250003Sadrian#define SUB_NUM_CTL_MODES_AT_2G_40 3 /* excluding HT40, EXT-OFDM, EXT-CCK */ 2552250003Sadrian u_int16_t ctl_modes_for11a[] = 2553250003Sadrian {CTL_11A, CTL_5GHT20, CTL_11A_EXT, CTL_5GHT40}; 2554250003Sadrian u_int16_t ctl_modes_for11g[] = 2555250003Sadrian {CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT, CTL_2GHT40}; 2556250003Sadrian u_int16_t num_ctl_modes, *p_ctl_mode, ctl_mode, freq; 2557250003Sadrian CHAN_CENTERS centers; 2558250003Sadrian int tx_chainmask; 2559250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 2560250003Sadrian u_int8_t *ctl_index; 2561250003Sadrian u_int8_t ctl_num; 2562250003Sadrian u_int16_t twice_min_edge_power; 2563250003Sadrian u_int16_t twice_max_edge_power = AR9300_MAX_RATE_POWER; 2564250008Sadrian#ifdef AH_DEBUG 2565250008Sadrian HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan); 2566250008Sadrian#endif 2567250003Sadrian 2568278741Sadrian if (chainmask) 2569278741Sadrian tx_chainmask = chainmask; 2570278741Sadrian else 2571278741Sadrian tx_chainmask = ahp->ah_tx_chainmaskopt ? 2572278741Sadrian ahp->ah_tx_chainmaskopt :ahp->ah_tx_chainmask; 2573250003Sadrian 2574250003Sadrian ar9300_get_channel_centers(ah, chan, ¢ers); 2575250003Sadrian 2576278741Sadrian#if 1 2577250008Sadrian if (IEEE80211_IS_CHAN_2GHZ(chan)) { 2578250003Sadrian ahp->twice_antenna_gain = p_eep_data->modal_header_2g.antenna_gain; 2579250003Sadrian } else { 2580250003Sadrian ahp->twice_antenna_gain = p_eep_data->modal_header_5g.antenna_gain; 2581250003Sadrian } 2582250003Sadrian 2583278741Sadrian#else 2584278741Sadrian if (IEEE80211_IS_CHAN_2GHZ(chan)) { 2585278741Sadrian ahp->twice_antenna_gain = AH_MAX(p_eep_data->modal_header_2g.antenna_gain, 2586278741Sadrian AH_PRIVATE(ah)->ah_antenna_gain_2g); 2587278741Sadrian } else { 2588278741Sadrian ahp->twice_antenna_gain = AH_MAX(p_eep_data->modal_header_5g.antenna_gain, 2589278741Sadrian AH_PRIVATE(ah)->ah_antenna_gain_5g); 2590278741Sadrian } 2591278741Sadrian#endif 2592278741Sadrian 2593250003Sadrian /* Save max allowed antenna gain to ease future lookups */ 2594250003Sadrian ahp->twice_antenna_reduction = twice_antenna_reduction; 2595250003Sadrian 2596250003Sadrian /* Deduct antenna gain from EIRP to get the upper limit */ 2597250003Sadrian twice_largest_antenna = (int16_t)AH_MIN((twice_antenna_reduction - 2598250003Sadrian ahp->twice_antenna_gain), 0); 2599250003Sadrian max_reg_allowed_power = twice_max_regulatory_power + twice_largest_antenna; 2600250003Sadrian 2601250003Sadrian /* Use ah_tp_scale - see bug 30070. */ 2602250008Sadrian if (AH_PRIVATE(ah)->ah_tpScale != HAL_TP_SCALE_MAX) { 2603250003Sadrian max_reg_allowed_power -= 2604250008Sadrian (tp_scale_reduction_table[(AH_PRIVATE(ah)->ah_tpScale)] * 2); 2605250003Sadrian } 2606250003Sadrian 2607250003Sadrian scaled_power = AH_MIN(power_limit, max_reg_allowed_power); 2608250003Sadrian 2609250003Sadrian /* 2610250003Sadrian * Reduce scaled Power by number of chains active to get to 2611250003Sadrian * per chain tx power level 2612250003Sadrian */ 2613250003Sadrian /* TODO: better value than these? */ 2614250003Sadrian switch (ar9300_get_ntxchains(tx_chainmask)) { 2615250003Sadrian case 1: 2616250003Sadrian ahp->upper_limit[0] = AH_MAX(0, scaled_power); 2617250003Sadrian break; 2618250003Sadrian case 2: 2619250003Sadrian scaled_power -= REDUCE_SCALED_POWER_BY_TWO_CHAIN; 2620250003Sadrian ahp->upper_limit[1] = AH_MAX(0, scaled_power); 2621250003Sadrian break; 2622250003Sadrian case 3: 2623250003Sadrian scaled_power -= REDUCE_SCALED_POWER_BY_THREE_CHAIN; 2624250003Sadrian ahp->upper_limit[2] = AH_MAX(0, scaled_power); 2625250003Sadrian break; 2626250003Sadrian default: 2627250003Sadrian HALASSERT(0); /* Unsupported number of chains */ 2628250003Sadrian } 2629250003Sadrian 2630250003Sadrian scaled_power = AH_MAX(0, scaled_power); 2631250003Sadrian 2632250003Sadrian /* Get target powers from EEPROM - our baseline for TX Power */ 2633250008Sadrian if (IEEE80211_IS_CHAN_2GHZ(chan)) { 2634250003Sadrian /* Setup for CTL modes */ 2635250003Sadrian /* CTL_11B, CTL_11G, CTL_2GHT20 */ 2636250003Sadrian num_ctl_modes = 2637250003Sadrian ARRAY_LENGTH(ctl_modes_for11g) - SUB_NUM_CTL_MODES_AT_2G_40; 2638250003Sadrian p_ctl_mode = ctl_modes_for11g; 2639250003Sadrian 2640250008Sadrian if (IEEE80211_IS_CHAN_HT40(chan)) { 2641250003Sadrian num_ctl_modes = ARRAY_LENGTH(ctl_modes_for11g); /* All 2G CTL's */ 2642250003Sadrian } 2643250003Sadrian } else { 2644250003Sadrian /* Setup for CTL modes */ 2645250003Sadrian /* CTL_11A, CTL_5GHT20 */ 2646250003Sadrian num_ctl_modes = 2647250003Sadrian ARRAY_LENGTH(ctl_modes_for11a) - SUB_NUM_CTL_MODES_AT_5G_40; 2648250003Sadrian p_ctl_mode = ctl_modes_for11a; 2649250003Sadrian 2650250008Sadrian if (IEEE80211_IS_CHAN_HT40(chan)) { 2651250003Sadrian num_ctl_modes = ARRAY_LENGTH(ctl_modes_for11a); /* All 5G CTL's */ 2652250003Sadrian } 2653250003Sadrian } 2654250003Sadrian 2655250003Sadrian /* 2656250003Sadrian * For MIMO, need to apply regulatory caps individually across dynamically 2657250003Sadrian * running modes: CCK, OFDM, HT20, HT40 2658250003Sadrian * 2659250003Sadrian * The outer loop walks through each possible applicable runtime mode. 2660250003Sadrian * The inner loop walks through each ctl_index entry in EEPROM. 2661250003Sadrian * The ctl value is encoded as [7:4] == test group, [3:0] == test mode. 2662250003Sadrian * 2663250003Sadrian */ 2664250003Sadrian for (ctl_mode = 0; ctl_mode < num_ctl_modes; ctl_mode++) { 2665250003Sadrian HAL_BOOL is_ht40_ctl_mode = 2666250003Sadrian (p_ctl_mode[ctl_mode] == CTL_5GHT40) || 2667250003Sadrian (p_ctl_mode[ctl_mode] == CTL_2GHT40); 2668250003Sadrian if (is_ht40_ctl_mode) { 2669250003Sadrian freq = centers.synth_center; 2670250003Sadrian } else if (p_ctl_mode[ctl_mode] & EXT_ADDITIVE) { 2671250003Sadrian freq = centers.ext_center; 2672250003Sadrian } else { 2673250003Sadrian freq = centers.ctl_center; 2674250003Sadrian } 2675250003Sadrian 2676250003Sadrian HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, 2677250003Sadrian "LOOP-Mode ctl_mode %d < %d, " 2678250003Sadrian "is_ht40_ctl_mode %d, EXT_ADDITIVE %d\n", 2679250003Sadrian ctl_mode, num_ctl_modes, is_ht40_ctl_mode, 2680250003Sadrian (p_ctl_mode[ctl_mode] & EXT_ADDITIVE)); 2681250003Sadrian /* walk through each CTL index stored in EEPROM */ 2682250008Sadrian if (IEEE80211_IS_CHAN_2GHZ(chan)) { 2683250003Sadrian ctl_index = p_eep_data->ctl_index_2g; 2684250003Sadrian ctl_num = OSPREY_NUM_CTLS_2G; 2685250003Sadrian } else { 2686250003Sadrian ctl_index = p_eep_data->ctl_index_5g; 2687250003Sadrian ctl_num = OSPREY_NUM_CTLS_5G; 2688250003Sadrian } 2689250003Sadrian 2690250003Sadrian for (i = 0; (i < ctl_num) && ctl_index[i]; i++) { 2691250003Sadrian HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, 2692250003Sadrian " LOOP-Ctlidx %d: cfg_ctl 0x%2.2x p_ctl_mode 0x%2.2x " 2693250003Sadrian "ctl_index 0x%2.2x chan %d chanctl 0x%x\n", 2694250003Sadrian i, cfg_ctl, p_ctl_mode[ctl_mode], ctl_index[i], 2695250008Sadrian ichan->channel, ath_hal_getctl(ah, chan)); 2696250003Sadrian 2697250008Sadrian 2698250003Sadrian /* 2699250003Sadrian * compare test group from regulatory channel list 2700250003Sadrian * with test mode from p_ctl_mode list 2701250003Sadrian */ 2702250003Sadrian if ((((cfg_ctl & ~CTL_MODE_M) | 2703250003Sadrian (p_ctl_mode[ctl_mode] & CTL_MODE_M)) == ctl_index[i]) || 2704250003Sadrian (((cfg_ctl & ~CTL_MODE_M) | 2705250003Sadrian (p_ctl_mode[ctl_mode] & CTL_MODE_M)) == 2706250003Sadrian ((ctl_index[i] & CTL_MODE_M) | SD_NO_CTL))) 2707250003Sadrian { 2708250003Sadrian twice_min_edge_power = 2709250003Sadrian ar9300_eep_def_get_max_edge_power( 2710250008Sadrian p_eep_data, freq, i, IEEE80211_IS_CHAN_2GHZ(chan)); 2711250003Sadrian 2712250003Sadrian HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, 2713250003Sadrian " MATCH-EE_IDX %d: ch %d is2 %d " 2714250003Sadrian "2xMinEdge %d chainmask %d chains %d\n", 2715250008Sadrian i, freq, IEEE80211_IS_CHAN_2GHZ(chan), 2716250003Sadrian twice_min_edge_power, tx_chainmask, 2717250003Sadrian ar9300_get_ntxchains(tx_chainmask)); 2718250003Sadrian 2719250003Sadrian if ((cfg_ctl & ~CTL_MODE_M) == SD_NO_CTL) { 2720250003Sadrian /* 2721250003Sadrian * Find the minimum of all CTL edge powers 2722250003Sadrian * that apply to this channel 2723250003Sadrian */ 2724250003Sadrian twice_max_edge_power = 2725250003Sadrian AH_MIN(twice_max_edge_power, twice_min_edge_power); 2726250003Sadrian } else { 2727250003Sadrian /* specific */ 2728250003Sadrian twice_max_edge_power = twice_min_edge_power; 2729250003Sadrian break; 2730250003Sadrian } 2731250003Sadrian } 2732250003Sadrian } 2733250003Sadrian 2734250003Sadrian min_ctl_power = (u_int8_t)AH_MIN(twice_max_edge_power, scaled_power); 2735250003Sadrian 2736250003Sadrian HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, 2737250003Sadrian " SEL-Min ctl_mode %d p_ctl_mode %d " 2738250003Sadrian "2xMaxEdge %d sP %d min_ctl_pwr %d\n", 2739250003Sadrian ctl_mode, p_ctl_mode[ctl_mode], 2740250003Sadrian twice_max_edge_power, scaled_power, min_ctl_power); 2741250003Sadrian 2742250003Sadrian /* Apply ctl mode to correct target power set */ 2743250003Sadrian switch (p_ctl_mode[ctl_mode]) { 2744250003Sadrian case CTL_11B: 2745250003Sadrian for (i = ALL_TARGET_LEGACY_1L_5L; i <= ALL_TARGET_LEGACY_11S; i++) { 2746250003Sadrian p_pwr_array[i] = 2747250003Sadrian (u_int8_t)AH_MIN(p_pwr_array[i], min_ctl_power); 2748250003Sadrian } 2749250003Sadrian break; 2750250003Sadrian case CTL_11A: 2751250003Sadrian case CTL_11G: 2752250003Sadrian for (i = ALL_TARGET_LEGACY_6_24; i <= ALL_TARGET_LEGACY_54; i++) { 2753250003Sadrian p_pwr_array[i] = 2754250003Sadrian (u_int8_t)AH_MIN(p_pwr_array[i], min_ctl_power); 2755250003Sadrian#ifdef ATH_BT_COEX 2756250003Sadrian if ((ahp->ah_bt_coex_config_type == HAL_BT_COEX_CFG_3WIRE) || 2757250003Sadrian (ahp->ah_bt_coex_config_type == HAL_BT_COEX_CFG_MCI)) 2758250003Sadrian { 2759250003Sadrian if ((ahp->ah_bt_coex_flag & HAL_BT_COEX_FLAG_LOWER_TX_PWR) 2760250003Sadrian && (ahp->ah_bt_wlan_isolation 2761250003Sadrian < HAL_BT_COEX_ISOLATION_FOR_NO_COEX)) 2762250003Sadrian { 2763250003Sadrian 2764250003Sadrian u_int8_t reduce_pow; 2765250003Sadrian 2766250003Sadrian reduce_pow = (HAL_BT_COEX_ISOLATION_FOR_NO_COEX 2767250003Sadrian - ahp->ah_bt_wlan_isolation) << 1; 2768250003Sadrian 2769250003Sadrian if (reduce_pow <= p_pwr_array[i]) { 2770250003Sadrian p_pwr_array[i] -= reduce_pow; 2771250003Sadrian } 2772250003Sadrian } 2773250003Sadrian if ((ahp->ah_bt_coex_flag & 2774250003Sadrian HAL_BT_COEX_FLAG_LOW_ACK_PWR) && 2775250003Sadrian (i != ALL_TARGET_LEGACY_36) && 2776250003Sadrian (i != ALL_TARGET_LEGACY_48) && 2777250003Sadrian (i != ALL_TARGET_LEGACY_54) && 2778250003Sadrian (p_ctl_mode[ctl_mode] == CTL_11G)) 2779250003Sadrian { 2780250003Sadrian p_pwr_array[i] = 0; 2781250003Sadrian } 2782250003Sadrian } 2783250003Sadrian#endif 2784250003Sadrian } 2785250003Sadrian break; 2786250003Sadrian case CTL_5GHT20: 2787250003Sadrian case CTL_2GHT20: 2788250003Sadrian for (i = ALL_TARGET_HT20_0_8_16; i <= ALL_TARGET_HT20_23; i++) { 2789250003Sadrian p_pwr_array[i] = 2790250003Sadrian (u_int8_t)AH_MIN(p_pwr_array[i], min_ctl_power); 2791250003Sadrian#ifdef ATH_BT_COEX 2792250003Sadrian if (((ahp->ah_bt_coex_config_type == HAL_BT_COEX_CFG_3WIRE) || 2793250003Sadrian (ahp->ah_bt_coex_config_type == HAL_BT_COEX_CFG_MCI)) && 2794250003Sadrian (ahp->ah_bt_coex_flag & HAL_BT_COEX_FLAG_LOWER_TX_PWR) && 2795250003Sadrian (ahp->ah_bt_wlan_isolation 2796250003Sadrian < HAL_BT_COEX_ISOLATION_FOR_NO_COEX)) { 2797250003Sadrian 2798250003Sadrian u_int8_t reduce_pow = (HAL_BT_COEX_ISOLATION_FOR_NO_COEX 2799250003Sadrian - ahp->ah_bt_wlan_isolation) << 1; 2800250003Sadrian 2801250003Sadrian if (reduce_pow <= p_pwr_array[i]) { 2802250003Sadrian p_pwr_array[i] -= reduce_pow; 2803250003Sadrian } 2804250003Sadrian } 2805250003Sadrian#if ATH_SUPPORT_MCI 2806250003Sadrian else if ((ahp->ah_bt_coex_flag & 2807250003Sadrian HAL_BT_COEX_FLAG_MCI_MAX_TX_PWR) && 2808250003Sadrian (p_ctl_mode[ctl_mode] == CTL_2GHT20) && 2809250003Sadrian (ahp->ah_bt_coex_config_type == HAL_BT_COEX_CFG_MCI)) 2810250003Sadrian { 2811250003Sadrian u_int8_t max_pwr; 2812250003Sadrian 2813250003Sadrian max_pwr = MS(mci_concur_tx_max_pwr[2][1], 2814250003Sadrian ATH_MCI_CONCUR_TX_LOWEST_PWR_MASK); 2815250003Sadrian if (p_pwr_array[i] > max_pwr) { 2816250003Sadrian p_pwr_array[i] = max_pwr; 2817250003Sadrian } 2818250003Sadrian } 2819250003Sadrian#endif 2820250003Sadrian#endif 2821250003Sadrian } 2822250003Sadrian break; 2823250003Sadrian case CTL_11B_EXT: 2824250003Sadrian#ifdef NOT_YET 2825250003Sadrian target_power_cck_ext.t_pow2x[0] = (u_int8_t) 2826250003Sadrian AH_MIN(target_power_cck_ext.t_pow2x[0], min_ctl_power); 2827250003Sadrian#endif /* NOT_YET */ 2828250003Sadrian break; 2829250003Sadrian case CTL_11A_EXT: 2830250003Sadrian case CTL_11G_EXT: 2831250003Sadrian#ifdef NOT_YET 2832250003Sadrian target_power_ofdm_ext.t_pow2x[0] = (u_int8_t) 2833250003Sadrian AH_MIN(target_power_ofdm_ext.t_pow2x[0], min_ctl_power); 2834250003Sadrian#endif /* NOT_YET */ 2835250003Sadrian break; 2836250003Sadrian case CTL_5GHT40: 2837250003Sadrian case CTL_2GHT40: 2838250003Sadrian for (i = ALL_TARGET_HT40_0_8_16; i <= ALL_TARGET_HT40_23; i++) { 2839250003Sadrian p_pwr_array[i] = (u_int8_t) 2840250003Sadrian AH_MIN(p_pwr_array[i], min_ctl_power); 2841250003Sadrian#ifdef ATH_BT_COEX 2842250003Sadrian if (((ahp->ah_bt_coex_config_type == HAL_BT_COEX_CFG_3WIRE) || 2843250003Sadrian (ahp->ah_bt_coex_config_type == HAL_BT_COEX_CFG_MCI)) && 2844250003Sadrian (ahp->ah_bt_coex_flag & HAL_BT_COEX_FLAG_LOWER_TX_PWR) && 2845250003Sadrian (ahp->ah_bt_wlan_isolation 2846250003Sadrian < HAL_BT_COEX_ISOLATION_FOR_NO_COEX)) { 2847250003Sadrian 2848250003Sadrian u_int8_t reduce_pow = (HAL_BT_COEX_ISOLATION_FOR_NO_COEX 2849250003Sadrian - ahp->ah_bt_wlan_isolation) << 1; 2850250003Sadrian 2851250003Sadrian if (reduce_pow <= p_pwr_array[i]) { 2852250003Sadrian p_pwr_array[i] -= reduce_pow; 2853250003Sadrian } 2854250003Sadrian } 2855250003Sadrian#if ATH_SUPPORT_MCI 2856250003Sadrian else if ((ahp->ah_bt_coex_flag & 2857250003Sadrian HAL_BT_COEX_FLAG_MCI_MAX_TX_PWR) && 2858250003Sadrian (p_ctl_mode[ctl_mode] == CTL_2GHT40) && 2859250003Sadrian (ahp->ah_bt_coex_config_type == HAL_BT_COEX_CFG_MCI)) 2860250003Sadrian { 2861250003Sadrian u_int8_t max_pwr; 2862250003Sadrian 2863250003Sadrian max_pwr = MS(mci_concur_tx_max_pwr[3][1], 2864250003Sadrian ATH_MCI_CONCUR_TX_LOWEST_PWR_MASK); 2865250003Sadrian if (p_pwr_array[i] > max_pwr) { 2866250003Sadrian p_pwr_array[i] = max_pwr; 2867250003Sadrian } 2868250003Sadrian } 2869250003Sadrian#endif 2870250003Sadrian#endif 2871250003Sadrian } 2872250003Sadrian break; 2873250003Sadrian default: 2874250003Sadrian HALASSERT(0); 2875250003Sadrian break; 2876250003Sadrian } 2877250003Sadrian } /* end ctl mode checking */ 2878250003Sadrian 2879250003Sadrian return AH_TRUE; 2880250003Sadrian#undef EXT_ADDITIVE 2881250003Sadrian#undef CTL_11A_EXT 2882250003Sadrian#undef CTL_11G_EXT 2883250003Sadrian#undef CTL_11B_EXT 2884250003Sadrian#undef REDUCE_SCALED_POWER_BY_TWO_CHAIN 2885250003Sadrian#undef REDUCE_SCALED_POWER_BY_THREE_CHAIN 2886250003Sadrian} 2887250003Sadrian 2888250003Sadrian/************************************************************** 2889250003Sadrian * ar9300_eeprom_set_transmit_power 2890250003Sadrian * 2891250003Sadrian * Set the transmit power in the baseband for the given 2892250003Sadrian * operating channel and mode. 2893250003Sadrian */ 2894250003SadrianHAL_STATUS 2895250003Sadrianar9300_eeprom_set_transmit_power(struct ath_hal *ah, 2896250008Sadrian ar9300_eeprom_t *p_eep_data, const struct ieee80211_channel *chan, u_int16_t cfg_ctl, 2897250003Sadrian u_int16_t antenna_reduction, u_int16_t twice_max_regulatory_power, 2898250003Sadrian u_int16_t power_limit) 2899250003Sadrian{ 2900250003Sadrian#define ABS(_x, _y) ((int)_x > (int)_y ? (int)_x - (int)_y : (int)_y - (int)_x) 2901250003Sadrian#define INCREASE_MAXPOW_BY_TWO_CHAIN 6 /* 10*log10(2)*2 */ 2902250003Sadrian#define INCREASE_MAXPOW_BY_THREE_CHAIN 10 /* 10*log10(3)*2 */ 2903250003Sadrian u_int8_t target_power_val_t2[ar9300_rate_size]; 2904250003Sadrian u_int8_t target_power_val_t2_eep[ar9300_rate_size]; 2905250003Sadrian int16_t twice_array_gain = 0, max_power_level = 0; 2906250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 2907250003Sadrian int i = 0; 2908250003Sadrian u_int32_t tmp_paprd_rate_mask = 0, *tmp_ptr = NULL; 2909250003Sadrian int paprd_scale_factor = 5; 2910250008Sadrian HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan); 2911250003Sadrian 2912250003Sadrian u_int8_t *ptr_mcs_rate2power_table_index; 2913250003Sadrian u_int8_t mcs_rate2power_table_index_ht20[24] = 2914250003Sadrian { 2915250003Sadrian ALL_TARGET_HT20_0_8_16, 2916250003Sadrian ALL_TARGET_HT20_1_3_9_11_17_19, 2917250003Sadrian ALL_TARGET_HT20_1_3_9_11_17_19, 2918250003Sadrian ALL_TARGET_HT20_1_3_9_11_17_19, 2919250003Sadrian ALL_TARGET_HT20_4, 2920250003Sadrian ALL_TARGET_HT20_5, 2921250003Sadrian ALL_TARGET_HT20_6, 2922250003Sadrian ALL_TARGET_HT20_7, 2923250003Sadrian ALL_TARGET_HT20_0_8_16, 2924250003Sadrian ALL_TARGET_HT20_1_3_9_11_17_19, 2925250003Sadrian ALL_TARGET_HT20_1_3_9_11_17_19, 2926250003Sadrian ALL_TARGET_HT20_1_3_9_11_17_19, 2927250003Sadrian ALL_TARGET_HT20_12, 2928250003Sadrian ALL_TARGET_HT20_13, 2929250003Sadrian ALL_TARGET_HT20_14, 2930250003Sadrian ALL_TARGET_HT20_15, 2931250003Sadrian ALL_TARGET_HT20_0_8_16, 2932250003Sadrian ALL_TARGET_HT20_1_3_9_11_17_19, 2933250003Sadrian ALL_TARGET_HT20_1_3_9_11_17_19, 2934250003Sadrian ALL_TARGET_HT20_1_3_9_11_17_19, 2935250003Sadrian ALL_TARGET_HT20_20, 2936250003Sadrian ALL_TARGET_HT20_21, 2937250003Sadrian ALL_TARGET_HT20_22, 2938250003Sadrian ALL_TARGET_HT20_23 2939250003Sadrian }; 2940250003Sadrian 2941250003Sadrian u_int8_t mcs_rate2power_table_index_ht40[24] = 2942250003Sadrian { 2943250003Sadrian ALL_TARGET_HT40_0_8_16, 2944250003Sadrian ALL_TARGET_HT40_1_3_9_11_17_19, 2945250003Sadrian ALL_TARGET_HT40_1_3_9_11_17_19, 2946250003Sadrian ALL_TARGET_HT40_1_3_9_11_17_19, 2947250003Sadrian ALL_TARGET_HT40_4, 2948250003Sadrian ALL_TARGET_HT40_5, 2949250003Sadrian ALL_TARGET_HT40_6, 2950250003Sadrian ALL_TARGET_HT40_7, 2951250003Sadrian ALL_TARGET_HT40_0_8_16, 2952250003Sadrian ALL_TARGET_HT40_1_3_9_11_17_19, 2953250003Sadrian ALL_TARGET_HT40_1_3_9_11_17_19, 2954250003Sadrian ALL_TARGET_HT40_1_3_9_11_17_19, 2955250003Sadrian ALL_TARGET_HT40_12, 2956250003Sadrian ALL_TARGET_HT40_13, 2957250003Sadrian ALL_TARGET_HT40_14, 2958250003Sadrian ALL_TARGET_HT40_15, 2959250003Sadrian ALL_TARGET_HT40_0_8_16, 2960250003Sadrian ALL_TARGET_HT40_1_3_9_11_17_19, 2961250003Sadrian ALL_TARGET_HT40_1_3_9_11_17_19, 2962250003Sadrian ALL_TARGET_HT40_1_3_9_11_17_19, 2963250003Sadrian ALL_TARGET_HT40_20, 2964250003Sadrian ALL_TARGET_HT40_21, 2965250003Sadrian ALL_TARGET_HT40_22, 2966250003Sadrian ALL_TARGET_HT40_23, 2967250003Sadrian }; 2968250003Sadrian 2969250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 2970250003Sadrian "%s[%d] +++chan %d,cfgctl 0x%04x " 2971250003Sadrian "antenna_reduction 0x%04x, twice_max_regulatory_power 0x%04x " 2972250003Sadrian "power_limit 0x%04x\n", 2973250008Sadrian __func__, __LINE__, ichan->channel, cfg_ctl, 2974250003Sadrian antenna_reduction, twice_max_regulatory_power, power_limit); 2975250008Sadrian ar9300_set_target_power_from_eeprom(ah, ichan->channel, target_power_val_t2); 2976250003Sadrian 2977250003Sadrian if (ar9300_eeprom_get(ahp, EEP_PAPRD_ENABLED)) { 2978250008Sadrian if (IEEE80211_IS_CHAN_2GHZ(chan)) { 2979250008Sadrian if (IEEE80211_IS_CHAN_HT40(chan)) { 2980250003Sadrian tmp_paprd_rate_mask = 2981250003Sadrian p_eep_data->modal_header_2g.paprd_rate_mask_ht40; 2982250003Sadrian tmp_ptr = &AH9300(ah)->ah_2g_paprd_rate_mask_ht40; 2983250003Sadrian } else { 2984250003Sadrian tmp_paprd_rate_mask = 2985250003Sadrian p_eep_data->modal_header_2g.paprd_rate_mask_ht20; 2986250003Sadrian tmp_ptr = &AH9300(ah)->ah_2g_paprd_rate_mask_ht20; 2987250003Sadrian } 2988250003Sadrian } else { 2989250008Sadrian if (IEEE80211_IS_CHAN_HT40(chan)) { 2990250003Sadrian tmp_paprd_rate_mask = 2991250003Sadrian p_eep_data->modal_header_5g.paprd_rate_mask_ht40; 2992250003Sadrian tmp_ptr = &AH9300(ah)->ah_5g_paprd_rate_mask_ht40; 2993250003Sadrian } else { 2994250003Sadrian tmp_paprd_rate_mask = 2995250003Sadrian p_eep_data->modal_header_5g.paprd_rate_mask_ht20; 2996250003Sadrian tmp_ptr = &AH9300(ah)->ah_5g_paprd_rate_mask_ht20; 2997250003Sadrian } 2998250003Sadrian } 2999250003Sadrian AH_PAPRD_GET_SCALE_FACTOR( 3000250008Sadrian paprd_scale_factor, p_eep_data, IEEE80211_IS_CHAN_2GHZ(chan), ichan->channel); 3001250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s[%d] paprd_scale_factor %d\n", 3002250003Sadrian __func__, __LINE__, paprd_scale_factor); 3003250003Sadrian /* PAPRD is not done yet, Scale down the EEP power */ 3004250008Sadrian if (IEEE80211_IS_CHAN_HT40(chan)) { 3005250003Sadrian ptr_mcs_rate2power_table_index = 3006250003Sadrian &mcs_rate2power_table_index_ht40[0]; 3007250003Sadrian } else { 3008250003Sadrian ptr_mcs_rate2power_table_index = 3009250003Sadrian &mcs_rate2power_table_index_ht20[0]; 3010250003Sadrian } 3011250008Sadrian if (! ichan->paprd_table_write_done) { 3012250003Sadrian for (i = 0; i < 24; i++) { 3013250003Sadrian /* PAPRD is done yet, so Scale down Power for PAPRD Rates*/ 3014250003Sadrian if (tmp_paprd_rate_mask & (1 << i)) { 3015250003Sadrian target_power_val_t2[ptr_mcs_rate2power_table_index[i]] -= 3016250003Sadrian paprd_scale_factor; 3017250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 3018250003Sadrian "%s[%d]: Chan %d " 3019250003Sadrian "Scale down target_power_val_t2[%d] = 0x%04x\n", 3020250003Sadrian __func__, __LINE__, 3021250008Sadrian ichan->channel, i, target_power_val_t2[i]); 3022250003Sadrian } 3023250003Sadrian } 3024250003Sadrian } else { 3025250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 3026250003Sadrian "%s[%d]: PAPRD Done No TGT PWR Scaling\n", __func__, __LINE__); 3027250003Sadrian } 3028250003Sadrian } 3029250003Sadrian 3030250003Sadrian /* Save the Target power for future use */ 3031250003Sadrian OS_MEMCPY(target_power_val_t2_eep, target_power_val_t2, 3032250003Sadrian sizeof(target_power_val_t2)); 3033250003Sadrian ar9300_eeprom_set_power_per_rate_table(ah, p_eep_data, chan, 3034250003Sadrian target_power_val_t2, cfg_ctl, 3035250003Sadrian antenna_reduction, 3036250003Sadrian twice_max_regulatory_power, 3037250003Sadrian power_limit, 0); 3038250003Sadrian 3039250003Sadrian /* Save this for quick lookup */ 3040250008Sadrian ahp->reg_dmn = ath_hal_getctl(ah, chan); 3041250003Sadrian 3042250003Sadrian /* 3043250003Sadrian * Always use CDD/direct per rate power table for register based approach. 3044250003Sadrian * For FCC, CDD calculations should factor in the array gain, hence 3045250003Sadrian * this adjust call. ETSI and MKK does not have this requirement. 3046250003Sadrian */ 3047250003Sadrian if (is_reg_dmn_fcc(ahp->reg_dmn)) { 3048250008Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 3049250008Sadrian "%s: FCC regdomain, calling reg_txpower_cdd\n", 3050250008Sadrian __func__); 3051250003Sadrian ar9300_adjust_reg_txpower_cdd(ah, target_power_val_t2); 3052250003Sadrian } 3053250003Sadrian 3054250003Sadrian if (ar9300_eeprom_get(ahp, EEP_PAPRD_ENABLED)) { 3055250003Sadrian for (i = 0; i < ar9300_rate_size; i++) { 3056250003Sadrian /* 3057250003Sadrian * EEPROM TGT PWR is not same as current TGT PWR, 3058250003Sadrian * so Disable PAPRD for this rate. 3059250003Sadrian * Some of APs might ask to reduce Target Power, 3060250003Sadrian * if target power drops significantly, 3061250003Sadrian * disable PAPRD for that rate. 3062250003Sadrian */ 3063250003Sadrian if (tmp_paprd_rate_mask & (1 << i)) { 3064250003Sadrian if (ABS(target_power_val_t2_eep[i], target_power_val_t2[i]) > 3065250003Sadrian paprd_scale_factor) 3066250003Sadrian { 3067250003Sadrian tmp_paprd_rate_mask &= ~(1 << i); 3068250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 3069250003Sadrian "%s: EEP TPC[%02d] 0x%08x " 3070250003Sadrian "Curr TPC[%02d] 0x%08x mask = 0x%08x\n", 3071250003Sadrian __func__, i, target_power_val_t2_eep[i], i, 3072250003Sadrian target_power_val_t2[i], tmp_paprd_rate_mask); 3073250003Sadrian } 3074250003Sadrian } 3075250003Sadrian 3076250003Sadrian } 3077250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 3078250003Sadrian "%s: Chan %d After tmp_paprd_rate_mask = 0x%08x\n", 3079250008Sadrian __func__, ichan->channel, tmp_paprd_rate_mask); 3080250003Sadrian if (tmp_ptr) { 3081250003Sadrian *tmp_ptr = tmp_paprd_rate_mask; 3082250003Sadrian } 3083250003Sadrian } 3084250003Sadrian 3085250003Sadrian /* Write target power array to registers */ 3086250003Sadrian ar9300_transmit_power_reg_write(ah, target_power_val_t2); 3087250003Sadrian 3088250003Sadrian /* Write target power for self generated frames to the TPC register */ 3089250003Sadrian ar9300_selfgen_tpc_reg_write(ah, chan, target_power_val_t2); 3090250003Sadrian 3091250003Sadrian /* GreenTx or Paprd */ 3092250008Sadrian if (ah->ah_config.ath_hal_sta_update_tx_pwr_enable || 3093250008Sadrian AH_PRIVATE(ah)->ah_caps.halPaprdEnabled) 3094250003Sadrian { 3095250003Sadrian if (AR_SREV_POSEIDON(ah)) { 3096250003Sadrian /*For HAL_RSSI_TX_POWER_NONE array*/ 3097250003Sadrian OS_MEMCPY(ahp->ah_default_tx_power, 3098250003Sadrian target_power_val_t2, 3099250003Sadrian sizeof(target_power_val_t2)); 3100250003Sadrian /* Get defautl tx related register setting for GreenTx */ 3101250003Sadrian /* Record OB/DB */ 3102250008Sadrian ahp->ah_ob_db1[POSEIDON_STORED_REG_OBDB] = 3103250003Sadrian OS_REG_READ(ah, AR_PHY_65NM_CH0_TXRF2); 3104250003Sadrian /* Record TPC settting */ 3105250008Sadrian ahp->ah_ob_db1[POSEIDON_STORED_REG_TPC] = 3106250003Sadrian OS_REG_READ(ah, AR_TPC); 3107250003Sadrian /* Record BB_powertx_rate9 setting */ 3108250008Sadrian ahp->ah_ob_db1[POSEIDON_STORED_REG_BB_PWRTX_RATE9] = 3109250003Sadrian OS_REG_READ(ah, AR_PHY_BB_POWERTX_RATE9); 3110250003Sadrian } 3111250003Sadrian } 3112250003Sadrian 3113250003Sadrian /* 3114250003Sadrian * Return tx power used to iwconfig. 3115250003Sadrian * Since power is rate dependent, use one of the indices from the 3116250003Sadrian * AR9300_Rates enum to select an entry from target_power_val_t2[] 3117250003Sadrian * to report. 3118250003Sadrian * Currently returns the power for HT40 MCS 0, HT20 MCS 0, or OFDM 6 Mbps 3119250003Sadrian * as CCK power is less interesting (?). 3120250003Sadrian */ 3121250003Sadrian i = ALL_TARGET_LEGACY_6_24; /* legacy */ 3122250008Sadrian if (IEEE80211_IS_CHAN_HT40(chan)) { 3123250003Sadrian i = ALL_TARGET_HT40_0_8_16; /* ht40 */ 3124250008Sadrian } else if (IEEE80211_IS_CHAN_HT20(chan)) { 3125250003Sadrian i = ALL_TARGET_HT20_0_8_16; /* ht20 */ 3126250003Sadrian } 3127250003Sadrian max_power_level = target_power_val_t2[i]; 3128250003Sadrian /* Adjusting the ah_max_power_level based on chains and antennaGain*/ 3129278741Sadrian switch (ar9300_get_ntxchains(((ahp->ah_tx_chainmaskopt > 0) ? 3130278741Sadrian ahp->ah_tx_chainmaskopt : ahp->ah_tx_chainmask))) 3131250003Sadrian { 3132250003Sadrian case 1: 3133250003Sadrian break; 3134250003Sadrian case 2: 3135250003Sadrian twice_array_gain = (ahp->twice_antenna_gain >= ahp->twice_antenna_reduction)? 0: 3136250003Sadrian ((int16_t)AH_MIN((ahp->twice_antenna_reduction - 3137250003Sadrian (ahp->twice_antenna_gain + INCREASE_MAXPOW_BY_TWO_CHAIN)), 0)); 3138250003Sadrian /* Adjusting maxpower with antennaGain */ 3139250003Sadrian max_power_level -= twice_array_gain; 3140250003Sadrian /* Adjusting maxpower based on chain */ 3141250003Sadrian max_power_level += INCREASE_MAXPOW_BY_TWO_CHAIN; 3142250003Sadrian break; 3143250003Sadrian case 3: 3144250003Sadrian twice_array_gain = (ahp->twice_antenna_gain >= ahp->twice_antenna_reduction)? 0: 3145250003Sadrian ((int16_t)AH_MIN((ahp->twice_antenna_reduction - 3146250003Sadrian (ahp->twice_antenna_gain + INCREASE_MAXPOW_BY_THREE_CHAIN)), 0)); 3147250003Sadrian 3148250003Sadrian /* Adjusting maxpower with antennaGain */ 3149250003Sadrian max_power_level -= twice_array_gain; 3150250003Sadrian /* Adjusting maxpower based on chain */ 3151250003Sadrian max_power_level += INCREASE_MAXPOW_BY_THREE_CHAIN; 3152250003Sadrian break; 3153250003Sadrian default: 3154250003Sadrian HALASSERT(0); /* Unsupported number of chains */ 3155250003Sadrian } 3156250008Sadrian AH_PRIVATE(ah)->ah_maxPowerLevel = (int8_t)max_power_level; 3157250003Sadrian 3158250008Sadrian ar9300_calibration_apply(ah, ichan->channel); 3159250003Sadrian#undef ABS 3160250003Sadrian 3161250003Sadrian /* Handle per packet TPC initializations */ 3162250008Sadrian if (ah->ah_config.ath_hal_desc_tpc) { 3163250003Sadrian /* Transmit Power per-rate per-chain are computed here. A separate 3164250003Sadrian * power table is maintained for different MIMO modes (i.e. TXBF ON, 3165250003Sadrian * STBC) to enable easy lookup during packet transmit. 3166250003Sadrian * The reason for maintaing each of these tables per chain is that 3167250003Sadrian * the transmit power used for different number of chains is different 3168250003Sadrian * depending on whether the power has been limited by the target power, 3169250003Sadrian * the regulatory domain or the CTL limits. 3170250003Sadrian */ 3171250003Sadrian u_int mode = ath_hal_get_curmode(ah, chan); 3172250003Sadrian u_int32_t val = 0; 3173250003Sadrian u_int8_t chainmasks[AR9300_MAX_CHAINS] = 3174250003Sadrian {OSPREY_1_CHAINMASK, OSPREY_2LOHI_CHAINMASK, OSPREY_3_CHAINMASK}; 3175250003Sadrian for (i = 0; i < AR9300_MAX_CHAINS; i++) { 3176250003Sadrian OS_MEMCPY(target_power_val_t2, target_power_val_t2_eep, 3177250003Sadrian sizeof(target_power_val_t2_eep)); 3178250003Sadrian ar9300_eeprom_set_power_per_rate_table(ah, p_eep_data, chan, 3179250003Sadrian target_power_val_t2, cfg_ctl, 3180250003Sadrian antenna_reduction, 3181250003Sadrian twice_max_regulatory_power, 3182250003Sadrian power_limit, chainmasks[i]); 3183250003Sadrian HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, 3184250003Sadrian " Channel = %d Chainmask = %d, Upper Limit = [%2d.%1d dBm]\n", 3185250008Sadrian ichan->channel, i, ahp->upper_limit[i]/2, 3186250003Sadrian ahp->upper_limit[i]%2 * 5); 3187250003Sadrian ar9300_init_rate_txpower(ah, mode, chan, target_power_val_t2, 3188250003Sadrian chainmasks[i]); 3189250003Sadrian 3190250003Sadrian } 3191250003Sadrian 3192250003Sadrian /* Enable TPC */ 3193250003Sadrian OS_REG_WRITE(ah, AR_PHY_PWRTX_MAX, AR_PHY_PWRTX_MAX_TPC_ENABLE); 3194250003Sadrian /* 3195250003Sadrian * Disable per chain power reduction since we are already 3196250003Sadrian * accounting for this in our calculations 3197250003Sadrian */ 3198250003Sadrian val = OS_REG_READ(ah, AR_PHY_POWER_TX_SUB); 3199250003Sadrian if (AR_SREV_WASP(ah)) { 3200250003Sadrian OS_REG_WRITE(ah, AR_PHY_POWER_TX_SUB, 3201250003Sadrian val & AR_PHY_POWER_TX_SUB_2_DISABLE); 3202250003Sadrian } else { 3203250003Sadrian OS_REG_WRITE(ah, AR_PHY_POWER_TX_SUB, 3204250003Sadrian val & AR_PHY_POWER_TX_SUB_3_DISABLE); 3205250003Sadrian } 3206250003Sadrian } 3207250003Sadrian 3208250003Sadrian return HAL_OK; 3209250003Sadrian} 3210250003Sadrian 3211250003Sadrian/************************************************************** 3212250003Sadrian * ar9300_eeprom_set_addac 3213250003Sadrian * 3214250003Sadrian * Set the ADDAC from eeprom. 3215250003Sadrian */ 3216250003Sadrianvoid 3217250008Sadrianar9300_eeprom_set_addac(struct ath_hal *ah, struct ieee80211_channel *chan) 3218250003Sadrian{ 3219250003Sadrian 3220250003Sadrian HALDEBUG(AH_NULL, HAL_DEBUG_UNMASKABLE, 3221250003Sadrian "FIXME: ar9300_eeprom_def_set_addac called\n"); 3222250003Sadrian#if 0 3223250003Sadrian MODAL_EEPDEF_HEADER *p_modal; 3224250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 3225250003Sadrian ar9300_eeprom_t *eep = &ahp->ah_eeprom.def; 3226250003Sadrian u_int8_t biaslevel; 3227250003Sadrian 3228250003Sadrian if (AH_PRIVATE(ah)->ah_macVersion != AR_SREV_VERSION_SOWL) { 3229250003Sadrian return; 3230250003Sadrian } 3231250003Sadrian 3232250003Sadrian HALASSERT(owl_get_eepdef_ver(ahp) == AR9300_EEP_VER); 3233250003Sadrian 3234250003Sadrian /* Xpa bias levels in eeprom are valid from rev 14.7 */ 3235250003Sadrian if (owl_get_eepdef_rev(ahp) < AR9300_EEP_MINOR_VER_7) { 3236250003Sadrian return; 3237250003Sadrian } 3238250003Sadrian 3239250003Sadrian if (ahp->ah_emu_eeprom) { 3240250003Sadrian return; 3241250003Sadrian } 3242250003Sadrian 3243250008Sadrian p_modal = &(eep->modal_header[IEEE80211_IS_CHAN_2GHZ(chan)]); 3244250003Sadrian 3245250003Sadrian if (p_modal->xpa_bias_lvl != 0xff) { 3246250003Sadrian biaslevel = p_modal->xpa_bias_lvl; 3247250003Sadrian } else { 3248250003Sadrian /* Use freqeuncy specific xpa bias level */ 3249250003Sadrian u_int16_t reset_freq_bin, freq_bin, freq_count = 0; 3250250003Sadrian CHAN_CENTERS centers; 3251250003Sadrian 3252250003Sadrian ar9300_get_channel_centers(ah, chan, ¢ers); 3253250003Sadrian 3254250008Sadrian reset_freq_bin = FREQ2FBIN(centers.synth_center, IEEE80211_IS_CHAN_2GHZ(chan)); 3255250003Sadrian freq_bin = p_modal->xpa_bias_lvl_freq[0] & 0xff; 3256250003Sadrian biaslevel = (u_int8_t)(p_modal->xpa_bias_lvl_freq[0] >> 14); 3257250003Sadrian 3258250003Sadrian freq_count++; 3259250003Sadrian 3260250003Sadrian while (freq_count < 3) { 3261250003Sadrian if (p_modal->xpa_bias_lvl_freq[freq_count] == 0x0) { 3262250003Sadrian break; 3263250003Sadrian } 3264250003Sadrian 3265250003Sadrian freq_bin = p_modal->xpa_bias_lvl_freq[freq_count] & 0xff; 3266250003Sadrian if (reset_freq_bin >= freq_bin) { 3267250003Sadrian biaslevel = 3268250003Sadrian (u_int8_t)(p_modal->xpa_bias_lvl_freq[freq_count] >> 14); 3269250003Sadrian } else { 3270250003Sadrian break; 3271250003Sadrian } 3272250003Sadrian freq_count++; 3273250003Sadrian } 3274250003Sadrian } 3275250003Sadrian 3276250003Sadrian /* Apply bias level to the ADDAC values in the INI array */ 3277250008Sadrian if (IEEE80211_IS_CHAN_2GHZ(chan)) { 3278250003Sadrian INI_RA(&ahp->ah_ini_addac, 7, 1) = 3279250003Sadrian (INI_RA(&ahp->ah_ini_addac, 7, 1) & (~0x18)) | biaslevel << 3; 3280250003Sadrian } else { 3281250003Sadrian INI_RA(&ahp->ah_ini_addac, 6, 1) = 3282250003Sadrian (INI_RA(&ahp->ah_ini_addac, 6, 1) & (~0xc0)) | biaslevel << 6; 3283250003Sadrian } 3284250003Sadrian#endif 3285250003Sadrian} 3286250003Sadrian 3287250003Sadrianu_int 3288250003Sadrianar9300_eeprom_dump_support(struct ath_hal *ah, void **pp_e) 3289250003Sadrian{ 3290250003Sadrian *pp_e = &(AH9300(ah)->ah_eeprom); 3291250003Sadrian return sizeof(ar9300_eeprom_t); 3292250003Sadrian} 3293250003Sadrian 3294250003Sadrianu_int8_t 3295250003Sadrianar9300_eeprom_get_num_ant_config(struct ath_hal_9300 *ahp, 3296250003Sadrian HAL_FREQ_BAND freq_band) 3297250003Sadrian{ 3298250003Sadrian#if 0 3299250003Sadrian ar9300_eeprom_t *eep = &ahp->ah_eeprom.def; 3300250003Sadrian MODAL_EEPDEF_HEADER *p_modal = 3301250003Sadrian &(eep->modal_header[HAL_FREQ_BAND_2GHZ == freq_band]); 3302250003Sadrian BASE_EEPDEF_HEADER *p_base = &eep->base_eep_header; 3303250003Sadrian u_int8_t num_ant_config; 3304250003Sadrian 3305250003Sadrian num_ant_config = 1; /* default antenna configuration */ 3306250003Sadrian 3307250003Sadrian if (p_base->version >= 0x0E0D) { 3308250003Sadrian if (p_modal->use_ant1) { 3309250003Sadrian num_ant_config += 1; 3310250003Sadrian } 3311250003Sadrian } 3312250003Sadrian 3313250003Sadrian return num_ant_config; 3314250003Sadrian#else 3315250003Sadrian return 1; 3316250003Sadrian#endif 3317250003Sadrian} 3318250003Sadrian 3319250003SadrianHAL_STATUS 3320250008Sadrianar9300_eeprom_get_ant_cfg(struct ath_hal_9300 *ahp, 3321250008Sadrian const struct ieee80211_channel *chan, 3322250008Sadrian u_int8_t index, u_int16_t *config) 3323250003Sadrian{ 3324250003Sadrian#if 0 3325250003Sadrian ar9300_eeprom_t *eep = &ahp->ah_eeprom.def; 3326250008Sadrian MODAL_EEPDEF_HEADER *p_modal = &(eep->modal_header[IEEE80211_IS_CHAN_2GHZ(chan)]); 3327250003Sadrian BASE_EEPDEF_HEADER *p_base = &eep->base_eep_header; 3328250003Sadrian 3329250003Sadrian switch (index) { 3330250003Sadrian case 0: 3331250003Sadrian *config = p_modal->ant_ctrl_common & 0xFFFF; 3332250003Sadrian return HAL_OK; 3333250003Sadrian case 1: 3334250003Sadrian if (p_base->version >= 0x0E0D) { 3335250003Sadrian if (p_modal->use_ant1) { 3336250003Sadrian *config = ((p_modal->ant_ctrl_common & 0xFFFF0000) >> 16); 3337250003Sadrian return HAL_OK; 3338250003Sadrian } 3339250003Sadrian } 3340250003Sadrian break; 3341250003Sadrian default: 3342250003Sadrian break; 3343250003Sadrian } 3344250003Sadrian#endif 3345250003Sadrian return HAL_EINVAL; 3346250003Sadrian} 3347250003Sadrian 3348250003Sadrianu_int8_t* 3349250003Sadrianar9300_eeprom_get_cust_data(struct ath_hal_9300 *ahp) 3350250003Sadrian{ 3351250003Sadrian return (u_int8_t *)ahp; 3352250003Sadrian} 3353250003Sadrian 3354250003Sadrian#ifdef UNUSED 3355250003Sadrianstatic inline HAL_STATUS 3356250003Sadrianar9300_check_eeprom(struct ath_hal *ah) 3357250003Sadrian{ 3358250003Sadrian#if 0 3359250003Sadrian u_int32_t sum = 0, el; 3360250003Sadrian u_int16_t *eepdata; 3361250003Sadrian int i; 3362250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 3363250003Sadrian HAL_BOOL need_swap = AH_FALSE; 3364250003Sadrian ar9300_eeprom_t *eep = (ar9300_eeprom_t *)&ahp->ah_eeprom.def; 3365250003Sadrian u_int16_t magic, magic2; 3366250003Sadrian int addr; 3367250003Sadrian u_int16_t temp; 3368250003Sadrian 3369250003Sadrian /* 3370250003Sadrian ** We need to check the EEPROM data regardless of if it's in flash or 3371250003Sadrian ** in EEPROM. 3372250003Sadrian */ 3373250003Sadrian 3374250003Sadrian if (!ahp->ah_priv.priv.ah_eeprom_read( 3375250003Sadrian ah, AR9300_EEPROM_MAGIC_OFFSET, &magic)) 3376250003Sadrian { 3377250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, "%s: Reading Magic # failed\n", __func__); 3378250003Sadrian return AH_FALSE; 3379250003Sadrian } 3380250003Sadrian 3381250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, "%s: Read Magic = 0x%04X\n", __func__, magic); 3382250003Sadrian 3383250003Sadrian if (!ar9300_eep_data_in_flash(ah)) { 3384250003Sadrian 3385250003Sadrian if (magic != AR9300_EEPROM_MAGIC) { 3386250003Sadrian magic2 = SWAP16(magic); 3387250003Sadrian 3388250003Sadrian if (magic2 == AR9300_EEPROM_MAGIC) { 3389250003Sadrian need_swap = AH_TRUE; 3390250003Sadrian eepdata = (u_int16_t *)(&ahp->ah_eeprom); 3391250003Sadrian 3392250003Sadrian for (addr = 0; 3393250003Sadrian addr < sizeof(ar9300_eeprom_t) / sizeof(u_int16_t); 3394250003Sadrian addr++) 3395250003Sadrian { 3396250003Sadrian temp = SWAP16(*eepdata); 3397250003Sadrian *eepdata = temp; 3398250003Sadrian eepdata++; 3399250003Sadrian 3400250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM_DUMP, "0x%04X ", *eepdata); 3401250003Sadrian if (((addr + 1) % 6) == 0) { 3402250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM_DUMP, "\n"); 3403250003Sadrian } 3404250003Sadrian } 3405250003Sadrian } else { 3406250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, 3407250003Sadrian "Invalid EEPROM Magic. endianness missmatch.\n"); 3408250003Sadrian return HAL_EEBADSUM; 3409250003Sadrian } 3410250003Sadrian } 3411250003Sadrian } else { 3412250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, 3413250003Sadrian "EEPROM being read from flash @0x%p\n", AH_PRIVATE(ah)->ah_st); 3414250003Sadrian } 3415250003Sadrian 3416250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, "need_swap = %s.\n", need_swap?"True":"False"); 3417250003Sadrian 3418250003Sadrian if (need_swap) { 3419250003Sadrian el = SWAP16(ahp->ah_eeprom.def.base_eep_header.length); 3420250003Sadrian } else { 3421250003Sadrian el = ahp->ah_eeprom.def.base_eep_header.length; 3422250003Sadrian } 3423250003Sadrian 3424250003Sadrian eepdata = (u_int16_t *)(&ahp->ah_eeprom.def); 3425250003Sadrian for (i = 0; 3426250003Sadrian i < AH_MIN(el, sizeof(ar9300_eeprom_t)) / sizeof(u_int16_t); 3427250003Sadrian i++) { 3428250003Sadrian sum ^= *eepdata++; 3429250003Sadrian } 3430250003Sadrian 3431250003Sadrian if (need_swap) { 3432250003Sadrian /* 3433250003Sadrian * preddy: EEPROM endianness does not match. So change it 3434250003Sadrian * 8bit values in eeprom data structure does not need to be swapped 3435250003Sadrian * Only >8bits (16 & 32) values need to be swapped 3436250003Sadrian * If a new 16 or 32 bit field is added to the EEPROM contents, 3437250003Sadrian * please make sure to swap the field here 3438250003Sadrian */ 3439250003Sadrian u_int32_t integer, j; 3440250003Sadrian u_int16_t word; 3441250003Sadrian 3442250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, 3443250003Sadrian "EEPROM Endianness is not native.. Changing \n"); 3444250003Sadrian 3445250003Sadrian /* convert Base Eep header */ 3446250003Sadrian word = SWAP16(eep->base_eep_header.length); 3447250003Sadrian eep->base_eep_header.length = word; 3448250003Sadrian 3449250003Sadrian word = SWAP16(eep->base_eep_header.checksum); 3450250003Sadrian eep->base_eep_header.checksum = word; 3451250003Sadrian 3452250003Sadrian word = SWAP16(eep->base_eep_header.version); 3453250003Sadrian eep->base_eep_header.version = word; 3454250003Sadrian 3455250003Sadrian word = SWAP16(eep->base_eep_header.reg_dmn[0]); 3456250003Sadrian eep->base_eep_header.reg_dmn[0] = word; 3457250003Sadrian 3458250003Sadrian word = SWAP16(eep->base_eep_header.reg_dmn[1]); 3459250003Sadrian eep->base_eep_header.reg_dmn[1] = word; 3460250003Sadrian 3461250003Sadrian word = SWAP16(eep->base_eep_header.rf_silent); 3462250003Sadrian eep->base_eep_header.rf_silent = word; 3463250003Sadrian 3464250003Sadrian word = SWAP16(eep->base_eep_header.blue_tooth_options); 3465250003Sadrian eep->base_eep_header.blue_tooth_options = word; 3466250003Sadrian 3467250003Sadrian word = SWAP16(eep->base_eep_header.device_cap); 3468250003Sadrian eep->base_eep_header.device_cap = word; 3469250003Sadrian 3470250003Sadrian /* convert Modal Eep header */ 3471250003Sadrian for (j = 0; j < ARRAY_LENGTH(eep->modal_header); j++) { 3472250003Sadrian MODAL_EEPDEF_HEADER *p_modal = &eep->modal_header[j]; 3473250003Sadrian integer = SWAP32(p_modal->ant_ctrl_common); 3474250003Sadrian p_modal->ant_ctrl_common = integer; 3475250003Sadrian 3476250003Sadrian for (i = 0; i < AR9300_MAX_CHAINS; i++) { 3477250003Sadrian integer = SWAP32(p_modal->ant_ctrl_chain[i]); 3478250003Sadrian p_modal->ant_ctrl_chain[i] = integer; 3479250003Sadrian } 3480250003Sadrian 3481250003Sadrian for (i = 0; i < AR9300_EEPROM_MODAL_SPURS; i++) { 3482250003Sadrian word = SWAP16(p_modal->spur_chans[i].spur_chan); 3483250003Sadrian p_modal->spur_chans[i].spur_chan = word; 3484250003Sadrian } 3485250003Sadrian } 3486250003Sadrian } 3487250003Sadrian 3488250003Sadrian /* Check CRC - Attach should fail on a bad checksum */ 3489250003Sadrian if (sum != 0xffff || owl_get_eepdef_ver(ahp) != AR9300_EEP_VER || 3490250003Sadrian owl_get_eepdef_rev(ahp) < AR9300_EEP_NO_BACK_VER) { 3491250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, 3492250003Sadrian "Bad EEPROM checksum 0x%x or revision 0x%04x\n", 3493250003Sadrian sum, owl_get_eepdef_ver(ahp)); 3494250003Sadrian return HAL_EEBADSUM; 3495250003Sadrian } 3496250003Sadrian#ifdef EEPROM_DUMP 3497250003Sadrian ar9300_eeprom_def_dump(ah, eep); 3498250003Sadrian#endif 3499250003Sadrian 3500250003Sadrian#if 0 3501250003Sadrian#ifdef AH_AR9300_OVRD_TGT_PWR 3502250003Sadrian 3503250003Sadrian /* 3504250003Sadrian * 14.4 EEPROM contains low target powers. 3505250003Sadrian * Hardcode until EEPROM > 14.4 3506250003Sadrian */ 3507250003Sadrian if (owl_get_eepdef_ver(ahp) == 14 && owl_get_eepdef_rev(ahp) <= 4) { 3508250003Sadrian MODAL_EEPDEF_HEADER *p_modal; 3509250003Sadrian 3510250003Sadrian#ifdef EEPROM_DUMP 3511250003Sadrian HALDEBUG(ah, HAL_DEBUG_POWER_OVERRIDE, "Original Target Powers\n"); 3512250003Sadrian ar9300_eep_def_dump_tgt_power(ah, eep); 3513250003Sadrian#endif 3514250003Sadrian HALDEBUG(ah, HAL_DEBUG_POWER_OVERRIDE, 3515250003Sadrian "Override Target Powers. EEPROM Version is %d.%d, " 3516250003Sadrian "Device Type %d\n", 3517250003Sadrian owl_get_eepdef_ver(ahp), 3518250003Sadrian owl_get_eepdef_rev(ahp), 3519250003Sadrian eep->base_eep_header.device_type); 3520250003Sadrian 3521250003Sadrian 3522250003Sadrian ar9300_eep_def_override_tgt_power(ah, eep); 3523250003Sadrian 3524250003Sadrian if (eep->base_eep_header.device_type == 5) { 3525250003Sadrian /* for xb72 only: improve transmit EVM for interop */ 3526250003Sadrian p_modal = &eep->modal_header[1]; 3527250003Sadrian p_modal->tx_frame_to_data_start = 0x23; 3528250003Sadrian p_modal->tx_frame_to_xpa_on = 0x23; 3529250003Sadrian p_modal->tx_frame_to_pa_on = 0x23; 3530250003Sadrian } 3531250003Sadrian 3532250003Sadrian#ifdef EEPROM_DUMP 3533250003Sadrian HALDEBUG(ah, HAL_DEBUG_POWER_OVERRIDE, "Modified Target Powers\n"); 3534250003Sadrian ar9300_eep_def_dump_tgt_power(ah, eep); 3535250003Sadrian#endif 3536250003Sadrian } 3537250003Sadrian#endif /* AH_AR9300_OVRD_TGT_PWR */ 3538250003Sadrian#endif 3539250003Sadrian#endif 3540250003Sadrian return HAL_OK; 3541250003Sadrian} 3542250003Sadrian#endif 3543250003Sadrian 3544250003Sadrianstatic u_int16_t 3545250008Sadrianar9300_eeprom_get_spur_chan(struct ath_hal *ah, int i, HAL_BOOL is_2ghz) 3546250003Sadrian{ 3547250003Sadrian u_int16_t spur_val = AR_NO_SPUR; 3548250003Sadrian#if 0 3549250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 3550250003Sadrian ar9300_eeprom_t *eep = (ar9300_eeprom_t *)&ahp->ah_eeprom; 3551250003Sadrian 3552250003Sadrian HALASSERT(i < AR_EEPROM_MODAL_SPURS ); 3553250003Sadrian 3554250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, 3555250003Sadrian "Getting spur idx %d is2Ghz. %d val %x\n", 3556250003Sadrian i, is_2ghz, 3557250003Sadrian AH_PRIVATE(ah)->ah_config.ath_hal_spur_chans[i][is_2ghz]); 3558250003Sadrian 3559250003Sadrian switch (AH_PRIVATE(ah)->ah_config.ath_hal_spur_mode) { 3560250003Sadrian case SPUR_DISABLE: 3561250003Sadrian /* returns AR_NO_SPUR */ 3562250003Sadrian break; 3563250003Sadrian case SPUR_ENABLE_IOCTL: 3564250003Sadrian spur_val = AH_PRIVATE(ah)->ah_config.ath_hal_spur_chans[i][is_2ghz]; 3565250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, 3566250003Sadrian "Getting spur val from new loc. %d\n", spur_val); 3567250003Sadrian break; 3568250003Sadrian case SPUR_ENABLE_EEPROM: 3569250003Sadrian spur_val = eep->modal_header[is_2ghz].spur_chans[i].spur_chan; 3570250003Sadrian break; 3571250003Sadrian 3572250003Sadrian } 3573250003Sadrian#endif 3574250003Sadrian return spur_val; 3575250003Sadrian} 3576250003Sadrian 3577250003Sadrian#ifdef UNUSED 3578250003Sadrianstatic inline HAL_BOOL 3579250003Sadrianar9300_fill_eeprom(struct ath_hal *ah) 3580250003Sadrian{ 3581250003Sadrian return ar9300_eeprom_restore(ah); 3582250003Sadrian} 3583250003Sadrian#endif 3584250003Sadrian 3585250003Sadrianu_int16_t 3586250003Sadrianar9300_eeprom_struct_size(void) 3587250003Sadrian{ 3588250003Sadrian return sizeof(ar9300_eeprom_t); 3589250003Sadrian} 3590250003Sadrian 3591250003Sadrianint ar9300_eeprom_struct_default_many(void) 3592250003Sadrian{ 3593250003Sadrian return ARRAY_LENGTH(default9300); 3594250003Sadrian} 3595250003Sadrian 3596250003Sadrian 3597250003Sadrianar9300_eeprom_t * 3598250003Sadrianar9300_eeprom_struct_default(int default_index) 3599250003Sadrian{ 3600250003Sadrian if (default_index >= 0 && 3601250003Sadrian default_index < ARRAY_LENGTH(default9300)) 3602250003Sadrian { 3603250003Sadrian return default9300[default_index]; 3604250003Sadrian } else { 3605250003Sadrian return 0; 3606250003Sadrian } 3607250003Sadrian} 3608250003Sadrian 3609250003Sadrianar9300_eeprom_t * 3610250003Sadrianar9300_eeprom_struct_default_find_by_id(int id) 3611250003Sadrian{ 3612250003Sadrian int it; 3613250003Sadrian 3614250003Sadrian for (it = 0; it < ARRAY_LENGTH(default9300); it++) { 3615250003Sadrian if (default9300[it] != 0 && default9300[it]->template_version == id) { 3616250003Sadrian return default9300[it]; 3617250003Sadrian } 3618250003Sadrian } 3619250003Sadrian return 0; 3620250003Sadrian} 3621250003Sadrian 3622250003Sadrian 3623250003SadrianHAL_BOOL 3624250003Sadrianar9300_calibration_data_read_flash(struct ath_hal *ah, long address, 3625250003Sadrian u_int8_t *buffer, int many) 3626250003Sadrian{ 3627250003Sadrian 3628250003Sadrian if (((address) < 0) || ((address + many) > AR9300_EEPROM_SIZE - 1)) { 3629250003Sadrian return AH_FALSE; 3630250003Sadrian } 3631250003Sadrian return AH_FALSE; 3632250003Sadrian} 3633250003Sadrian 3634250003SadrianHAL_BOOL 3635250003Sadrianar9300_calibration_data_read_eeprom(struct ath_hal *ah, long address, 3636250003Sadrian u_int8_t *buffer, int many) 3637250003Sadrian{ 3638250003Sadrian int i; 3639250003Sadrian u_int8_t value[2]; 3640250003Sadrian unsigned long eep_addr; 3641250003Sadrian unsigned long byte_addr; 3642250003Sadrian u_int16_t *svalue; 3643250003Sadrian 3644250003Sadrian if (((address) < 0) || ((address + many) > AR9300_EEPROM_SIZE)) { 3645250003Sadrian return AH_FALSE; 3646250003Sadrian } 3647250003Sadrian 3648250003Sadrian for (i = 0; i < many; i++) { 3649250003Sadrian eep_addr = (u_int16_t) (address + i) / 2; 3650250003Sadrian byte_addr = (u_int16_t) (address + i) % 2; 3651250003Sadrian svalue = (u_int16_t *) value; 3652250008Sadrian if (! ath_hal_eepromRead(ah, eep_addr, svalue)) { 3653250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, 3654250003Sadrian "%s: Unable to read eeprom region \n", __func__); 3655250003Sadrian return AH_FALSE; 3656250003Sadrian } 3657250003Sadrian buffer[i] = (*svalue >> (8 * byte_addr)) & 0xff; 3658250003Sadrian } 3659250003Sadrian return AH_TRUE; 3660250003Sadrian} 3661250003Sadrian 3662250003SadrianHAL_BOOL 3663250003Sadrianar9300_calibration_data_read_otp(struct ath_hal *ah, long address, 3664250003Sadrian u_int8_t *buffer, int many, HAL_BOOL is_wifi) 3665250003Sadrian{ 3666250003Sadrian int i; 3667250003Sadrian unsigned long eep_addr; 3668250003Sadrian unsigned long byte_addr; 3669250003Sadrian u_int32_t svalue; 3670250003Sadrian 3671250003Sadrian if (((address) < 0) || ((address + many) > 0x400)) { 3672250003Sadrian return AH_FALSE; 3673250003Sadrian } 3674250003Sadrian 3675250003Sadrian for (i = 0; i < many; i++) { 3676250003Sadrian eep_addr = (u_int16_t) (address + i) / 4; /* otp is 4 bytes long???? */ 3677250003Sadrian byte_addr = (u_int16_t) (address + i) % 4; 3678250003Sadrian if (!ar9300_otp_read(ah, eep_addr, &svalue, is_wifi)) { 3679250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, 3680250003Sadrian "%s: Unable to read otp region \n", __func__); 3681250003Sadrian return AH_FALSE; 3682250003Sadrian } 3683250003Sadrian buffer[i] = (svalue >> (8 * byte_addr)) & 0xff; 3684250003Sadrian } 3685250003Sadrian return AH_TRUE; 3686250003Sadrian} 3687250003Sadrian 3688250003Sadrian#ifdef ATH_CAL_NAND_FLASH 3689250003SadrianHAL_BOOL 3690250003Sadrianar9300_calibration_data_read_nand(struct ath_hal *ah, long address, 3691250003Sadrian u_int8_t *buffer, int many) 3692250003Sadrian{ 3693250003Sadrian int ret_len; 3694250003Sadrian int ret_val = 1; 3695250003Sadrian 3696250003Sadrian /* Calling OS based API to read NAND */ 3697250003Sadrian ret_val = OS_NAND_FLASH_READ(ATH_CAL_NAND_PARTITION, address, many, &ret_len, buffer); 3698250003Sadrian 3699250003Sadrian return (ret_val ? AH_FALSE: AH_TRUE); 3700250003Sadrian} 3701250003Sadrian#endif 3702250003Sadrian 3703250003SadrianHAL_BOOL 3704250003Sadrianar9300_calibration_data_read(struct ath_hal *ah, long address, 3705250003Sadrian u_int8_t *buffer, int many) 3706250003Sadrian{ 3707250003Sadrian switch (AH9300(ah)->calibration_data_source) { 3708250003Sadrian case calibration_data_flash: 3709250003Sadrian return ar9300_calibration_data_read_flash(ah, address, buffer, many); 3710250003Sadrian case calibration_data_eeprom: 3711250003Sadrian return ar9300_calibration_data_read_eeprom(ah, address, buffer, many); 3712250003Sadrian case calibration_data_otp: 3713250003Sadrian return ar9300_calibration_data_read_otp(ah, address, buffer, many, 1); 3714250003Sadrian#ifdef ATH_CAL_NAND_FLASH 3715250003Sadrian case calibration_data_nand: 3716250003Sadrian return ar9300_calibration_data_read_nand(ah,address,buffer,many); 3717250003Sadrian#endif 3718250003Sadrian 3719250003Sadrian } 3720250003Sadrian return AH_FALSE; 3721250003Sadrian} 3722250003Sadrian 3723250003Sadrian 3724250003SadrianHAL_BOOL 3725250003Sadrianar9300_calibration_data_read_array(struct ath_hal *ah, int address, 3726250003Sadrian u_int8_t *buffer, int many) 3727250003Sadrian{ 3728250003Sadrian int it; 3729250003Sadrian 3730250003Sadrian for (it = 0; it < many; it++) { 3731250003Sadrian (void)ar9300_calibration_data_read(ah, address - it, buffer + it, 1); 3732250003Sadrian } 3733250003Sadrian return AH_TRUE; 3734250003Sadrian} 3735250003Sadrian 3736250003Sadrian 3737250003Sadrian/* 3738250003Sadrian * the address where the first configuration block is written 3739250003Sadrian */ 3740250003Sadrianstatic const int base_address = 0x3ff; /* 1KB */ 3741250003Sadrianstatic const int base_address_512 = 0x1ff; /* 512Bytes */ 3742250003Sadrian 3743250003Sadrian/* 3744250003Sadrian * the address where the NAND first configuration block is written 3745250003Sadrian */ 3746250003Sadrian#ifdef ATH_CAL_NAND_FLASH 3747250003Sadrianstatic const int base_address_nand = AR9300_FLASH_CAL_START_OFFSET; 3748250003Sadrian#endif 3749250003Sadrian 3750250003Sadrian 3751250003Sadrian/* 3752250003Sadrian * the lower limit on configuration data 3753250003Sadrian */ 3754250003Sadrianstatic const int low_limit = 0x040; 3755250003Sadrian 3756250003Sadrian/* 3757250003Sadrian * returns size of the physical eeprom in bytes. 3758250003Sadrian * 1024 and 2048 are normal sizes. 3759250003Sadrian * 0 means there is no eeprom. 3760250003Sadrian */ 3761250003Sadrianint32_t 3762250003Sadrianar9300_eeprom_size(struct ath_hal *ah) 3763250003Sadrian{ 3764250003Sadrian u_int16_t data; 3765250003Sadrian /* 3766250003Sadrian * first we'll try for 4096 bytes eeprom 3767250003Sadrian */ 3768250003Sadrian if (ar9300_eeprom_read_word(ah, 2047, &data)) { 3769250003Sadrian if (data != 0) { 3770250003Sadrian return 4096; 3771250003Sadrian } 3772250003Sadrian } 3773250003Sadrian /* 3774250003Sadrian * then we'll try for 2048 bytes eeprom 3775250003Sadrian */ 3776250003Sadrian if (ar9300_eeprom_read_word(ah, 1023, &data)) { 3777250003Sadrian if (data != 0) { 3778250003Sadrian return 2048; 3779250003Sadrian } 3780250003Sadrian } 3781250003Sadrian /* 3782250003Sadrian * then we'll try for 1024 bytes eeprom 3783250003Sadrian */ 3784250003Sadrian if (ar9300_eeprom_read_word(ah, 511, &data)) { 3785250003Sadrian if (data != 0) { 3786250003Sadrian return 1024; 3787250003Sadrian } 3788250003Sadrian } 3789250003Sadrian return 0; 3790250003Sadrian} 3791250003Sadrian 3792250003Sadrian/* 3793250003Sadrian * returns size of the physical otp in bytes. 3794250003Sadrian * 1024 and 2048 are normal sizes. 3795250003Sadrian * 0 means there is no eeprom. 3796250003Sadrian */ 3797250003Sadrianint32_t 3798250003Sadrianar9300_otp_size(struct ath_hal *ah) 3799250003Sadrian{ 3800250003Sadrian if (AR_SREV_POSEIDON(ah) || AR_SREV_HORNET(ah)) { 3801250003Sadrian return base_address_512+1; 3802250003Sadrian } else { 3803250003Sadrian return base_address+1; 3804250003Sadrian } 3805250003Sadrian} 3806250003Sadrian 3807250003Sadrian 3808250003Sadrian/* 3809250003Sadrian * find top of memory 3810250003Sadrian */ 3811250003Sadrianint 3812250003Sadrianar9300_eeprom_base_address(struct ath_hal *ah) 3813250003Sadrian{ 3814250003Sadrian int size; 3815250003Sadrian 3816250003Sadrian if (AH9300(ah)->calibration_data_source == calibration_data_otp) { 3817250003Sadrian return ar9300_otp_size(ah)-1; 3818250003Sadrian } 3819250003Sadrian else 3820250003Sadrian { 3821250003Sadrian size = ar9300_eeprom_size(ah); 3822250003Sadrian if (size > 0) { 3823250003Sadrian return size - 1; 3824250003Sadrian } else { 3825250003Sadrian return ar9300_otp_size(ah)-1; 3826250003Sadrian } 3827250003Sadrian } 3828250003Sadrian} 3829250003Sadrian 3830250003Sadrianint 3831250003Sadrianar9300_eeprom_volatile(struct ath_hal *ah) 3832250003Sadrian{ 3833250003Sadrian if (AH9300(ah)->calibration_data_source == calibration_data_otp) { 3834250003Sadrian return 0; /* no eeprom, use otp */ 3835250003Sadrian } else { 3836250003Sadrian return 1; /* board has eeprom or flash */ 3837250003Sadrian } 3838250003Sadrian} 3839250003Sadrian 3840250003Sadrian/* 3841250003Sadrian * need to change this to look for the pcie data in the low parts of memory 3842250003Sadrian * cal data needs to stop a few locations above 3843250003Sadrian */ 3844250003Sadrianint 3845250003Sadrianar9300_eeprom_low_limit(struct ath_hal *ah) 3846250003Sadrian{ 3847250003Sadrian return low_limit; 3848250003Sadrian} 3849250003Sadrian 3850250003Sadrianu_int16_t 3851250003Sadrianar9300_compression_checksum(u_int8_t *data, int dsize) 3852250003Sadrian{ 3853250003Sadrian int it; 3854250003Sadrian int checksum = 0; 3855250003Sadrian 3856250003Sadrian for (it = 0; it < dsize; it++) { 3857250003Sadrian checksum += data[it]; 3858250003Sadrian checksum &= 0xffff; 3859250003Sadrian } 3860250003Sadrian 3861250003Sadrian return checksum; 3862250003Sadrian} 3863250003Sadrian 3864250003Sadrianint 3865250003Sadrianar9300_compression_header_unpack(u_int8_t *best, int *code, int *reference, 3866250003Sadrian int *length, int *major, int *minor) 3867250003Sadrian{ 3868250003Sadrian unsigned long value[4]; 3869250003Sadrian 3870250003Sadrian value[0] = best[0]; 3871250003Sadrian value[1] = best[1]; 3872250003Sadrian value[2] = best[2]; 3873250003Sadrian value[3] = best[3]; 3874250003Sadrian *code = ((value[0] >> 5) & 0x0007); 3875250003Sadrian *reference = (value[0] & 0x001f) | ((value[1] >> 2) & 0x0020); 3876250003Sadrian *length = ((value[1] << 4) & 0x07f0) | ((value[2] >> 4) & 0x000f); 3877250003Sadrian *major = (value[2] & 0x000f); 3878250003Sadrian *minor = (value[3] & 0x00ff); 3879250003Sadrian 3880250003Sadrian return 4; 3881250003Sadrian} 3882250003Sadrian 3883250003Sadrian 3884250003Sadrianstatic HAL_BOOL 3885250003Sadrianar9300_uncompress_block(struct ath_hal *ah, u_int8_t *mptr, int mdata_size, 3886250003Sadrian u_int8_t *block, int size) 3887250003Sadrian{ 3888250003Sadrian int it; 3889250003Sadrian int spot; 3890250003Sadrian int offset; 3891250003Sadrian int length; 3892250003Sadrian 3893250003Sadrian spot = 0; 3894250003Sadrian for (it = 0; it < size; it += (length + 2)) { 3895250003Sadrian offset = block[it]; 3896250003Sadrian offset &= 0xff; 3897250003Sadrian spot += offset; 3898250003Sadrian length = block[it + 1]; 3899250003Sadrian length &= 0xff; 3900250003Sadrian if (length > 0 && spot >= 0 && spot + length <= mdata_size) { 3901250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, 3902250003Sadrian "%s: Restore at %d: spot=%d offset=%d length=%d\n", 3903250003Sadrian __func__, it, spot, offset, length); 3904250003Sadrian OS_MEMCPY(&mptr[spot], &block[it + 2], length); 3905250003Sadrian spot += length; 3906250003Sadrian } else if (length > 0) { 3907250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, 3908250003Sadrian "%s: Bad restore at %d: spot=%d offset=%d length=%d\n", 3909250003Sadrian __func__, it, spot, offset, length); 3910250003Sadrian return AH_FALSE; 3911250003Sadrian } 3912250003Sadrian } 3913250003Sadrian return AH_TRUE; 3914250003Sadrian} 3915250003Sadrian 3916250003Sadrianstatic int 3917250003Sadrianar9300_eeprom_restore_internal_address(struct ath_hal *ah, 3918250003Sadrian ar9300_eeprom_t *mptr, int mdata_size, int cptr, u_int8_t blank) 3919250003Sadrian{ 3920250003Sadrian u_int8_t word[MOUTPUT]; 3921250003Sadrian ar9300_eeprom_t *dptr; /* was uint8 */ 3922250003Sadrian int code; 3923250003Sadrian int reference, length, major, minor; 3924250003Sadrian int osize; 3925250003Sadrian int it; 3926250003Sadrian int restored; 3927250003Sadrian u_int16_t checksum, mchecksum; 3928250003Sadrian 3929250003Sadrian restored = 0; 3930250003Sadrian for (it = 0; it < MSTATE; it++) { 3931250003Sadrian (void) ar9300_calibration_data_read_array( 3932250003Sadrian ah, cptr, word, compression_header_length); 3933250003Sadrian if (word[0] == blank && word[1] == blank && word[2] == blank && word[3] == blank) 3934250003Sadrian { 3935250003Sadrian break; 3936250003Sadrian } 3937250003Sadrian ar9300_compression_header_unpack( 3938250003Sadrian word, &code, &reference, &length, &major, &minor); 3939250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, 3940250003Sadrian "%s: Found block at %x: " 3941250003Sadrian "code=%d ref=%d length=%d major=%d minor=%d\n", 3942250003Sadrian __func__, cptr, code, reference, length, major, minor); 3943250003Sadrian#ifdef DONTUSE 3944250003Sadrian if (length >= 1024) { 3945250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, "%s: Skipping bad header\n", __func__); 3946250003Sadrian cptr -= compression_header_length; 3947250003Sadrian continue; 3948250003Sadrian } 3949250003Sadrian#endif 3950250003Sadrian osize = length; 3951250003Sadrian (void) ar9300_calibration_data_read_array( 3952250003Sadrian ah, cptr, word, 3953250003Sadrian compression_header_length + osize + compression_checksum_length); 3954250003Sadrian checksum = ar9300_compression_checksum( 3955250003Sadrian &word[compression_header_length], length); 3956250003Sadrian mchecksum = 3957250003Sadrian word[compression_header_length + osize] | 3958250003Sadrian (word[compression_header_length + osize + 1] << 8); 3959250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, 3960250003Sadrian "%s: checksum %x %x\n", __func__, checksum, mchecksum); 3961250003Sadrian if (checksum == mchecksum) { 3962250003Sadrian switch (code) { 3963250003Sadrian case _compress_none: 3964250003Sadrian if (length != mdata_size) { 3965250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, 3966250003Sadrian "%s: EEPROM structure size mismatch " 3967250003Sadrian "memory=%d eeprom=%d\n", __func__, mdata_size, length); 3968250003Sadrian return -1; 3969250003Sadrian } 3970250003Sadrian OS_MEMCPY((u_int8_t *)mptr, 3971250003Sadrian (u_int8_t *)(word + compression_header_length), length); 3972250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, 3973250003Sadrian "%s: restored eeprom %d: uncompressed, length %d\n", 3974250003Sadrian __func__, it, length); 3975250003Sadrian restored = 1; 3976250003Sadrian break; 3977250003Sadrian#ifdef UNUSED 3978250003Sadrian case _compress_lzma: 3979250003Sadrian if (reference == reference_current) { 3980250003Sadrian dptr = mptr; 3981250003Sadrian } else { 3982250003Sadrian dptr = (u_int8_t *)ar9300_eeprom_struct_default_find_by_id( 3983250003Sadrian reference); 3984250003Sadrian if (dptr == 0) { 3985250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, 3986250003Sadrian "%s: Can't find reference eeprom struct %d\n", 3987250003Sadrian __func__, reference); 3988250003Sadrian goto done; 3989250003Sadrian } 3990250003Sadrian } 3991250003Sadrian usize = -1; 3992250003Sadrian if (usize != mdata_size) { 3993250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, 3994250003Sadrian "%s: uncompressed data is wrong size %d %d\n", 3995250003Sadrian __func__, usize, mdata_size); 3996250003Sadrian goto done; 3997250003Sadrian } 3998250003Sadrian 3999250003Sadrian for (ib = 0; ib < mdata_size; ib++) { 4000250003Sadrian mptr[ib] = dptr[ib] ^ word[ib + overhead]; 4001250003Sadrian } 4002250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, 4003250003Sadrian "%s: restored eeprom %d: compressed, " 4004250003Sadrian "reference %d, length %d\n", 4005250003Sadrian __func__, it, reference, length); 4006250003Sadrian break; 4007250003Sadrian case _compress_pairs: 4008250003Sadrian if (reference == reference_current) { 4009250003Sadrian dptr = mptr; 4010250003Sadrian } else { 4011250003Sadrian dptr = (u_int8_t *)ar9300_eeprom_struct_default_find_by_id( 4012250003Sadrian reference); 4013250003Sadrian if (dptr == 0) { 4014250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, 4015250003Sadrian "%s: Can't find the reference " 4016250003Sadrian "eeprom structure %d\n", 4017250003Sadrian __func__, reference); 4018250003Sadrian goto done; 4019250003Sadrian } 4020250003Sadrian } 4021250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, 4022250003Sadrian "%s: restored eeprom %d: " 4023250003Sadrian "pairs, reference %d, length %d,\n", 4024250003Sadrian __func__, it, reference, length); 4025250003Sadrian break; 4026250003Sadrian#endif 4027250003Sadrian case _compress_block: 4028250003Sadrian if (reference == reference_current) { 4029250003Sadrian dptr = mptr; 4030250003Sadrian } else { 4031250003Sadrian dptr = ar9300_eeprom_struct_default_find_by_id(reference); 4032250003Sadrian if (dptr == 0) { 4033250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, 4034250003Sadrian "%s: cant find reference eeprom struct %d\n", 4035250003Sadrian __func__, reference); 4036250003Sadrian break; 4037250003Sadrian } 4038250003Sadrian OS_MEMCPY(mptr, dptr, mdata_size); 4039250003Sadrian } 4040250003Sadrian 4041250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, 4042250003Sadrian "%s: restore eeprom %d: block, reference %d, length %d\n", 4043250003Sadrian __func__, it, reference, length); 4044250003Sadrian (void) ar9300_uncompress_block(ah, 4045250003Sadrian (u_int8_t *) mptr, mdata_size, 4046250003Sadrian (u_int8_t *) (word + compression_header_length), length); 4047250003Sadrian restored = 1; 4048250003Sadrian break; 4049250003Sadrian default: 4050250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, 4051250003Sadrian "%s: unknown compression code %d\n", __func__, code); 4052250003Sadrian break; 4053250003Sadrian } 4054250003Sadrian } else { 4055250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, 4056250003Sadrian "%s: skipping block with bad checksum\n", __func__); 4057250003Sadrian } 4058250003Sadrian cptr -= compression_header_length + osize + compression_checksum_length; 4059250003Sadrian } 4060250003Sadrian 4061250003Sadrian if (!restored) { 4062250003Sadrian cptr = -1; 4063250003Sadrian } 4064250003Sadrian return cptr; 4065250003Sadrian} 4066250003Sadrian 4067250003Sadrianstatic int 4068250003Sadrianar9300_eeprom_restore_from_dram(struct ath_hal *ah, ar9300_eeprom_t *mptr, 4069250003Sadrian int mdata_size) 4070250003Sadrian{ 4071250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 4072250003Sadrian#if !defined(USE_PLATFORM_FRAMEWORK) 4073250003Sadrian char *cal_ptr; 4074250003Sadrian#endif 4075250003Sadrian 4076250003Sadrian HALASSERT(mdata_size > 0); 4077250003Sadrian 4078250003Sadrian /* if cal_in_flash is AH_TRUE, the address sent by LMAC to HAL 4079250003Sadrian (i.e. ah->ah_st) is corresponding to Flash. so return from 4080250003Sadrian here if ar9300_eep_data_in_flash(ah) returns AH_TRUE */ 4081250003Sadrian if(ar9300_eep_data_in_flash(ah)) 4082250003Sadrian return -1; 4083250003Sadrian 4084250008Sadrian#if 0 4085250003Sadrian /* check if LMAC sent DRAM address is valid */ 4086250003Sadrian if (!(uintptr_t)(AH_PRIVATE(ah)->ah_st)) { 4087250003Sadrian return -1; 4088250003Sadrian } 4089250008Sadrian#endif 4090250003Sadrian 4091250003Sadrian /* When calibration data is from host, Host will copy the 4092250003Sadrian compressed data to the predefined DRAM location saved at ah->ah_st */ 4093250008Sadrian#if 0 4094250003Sadrian ath_hal_printf(ah, "Restoring Cal data from DRAM\n"); 4095250003Sadrian ahp->ah_cal_mem = OS_REMAP((uintptr_t)(AH_PRIVATE(ah)->ah_st), 4096250003Sadrian HOST_CALDATA_SIZE); 4097250008Sadrian#endif 4098250003Sadrian if (!ahp->ah_cal_mem) 4099250003Sadrian { 4100250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM,"%s: can't remap dram region\n", __func__); 4101250003Sadrian return -1; 4102250003Sadrian } 4103250003Sadrian#if !defined(USE_PLATFORM_FRAMEWORK) 4104250003Sadrian cal_ptr = &((char *)(ahp->ah_cal_mem))[AR9300_FLASH_CAL_START_OFFSET]; 4105250003Sadrian OS_MEMCPY(mptr, cal_ptr, mdata_size); 4106250003Sadrian#else 4107250003Sadrian OS_MEMCPY(mptr, ahp->ah_cal_mem, mdata_size); 4108250003Sadrian#endif 4109250003Sadrian 4110250003Sadrian if (mptr->eeprom_version == 0xff || 4111250003Sadrian mptr->template_version == 0xff || 4112250003Sadrian mptr->eeprom_version == 0 || 4113250003Sadrian mptr->template_version == 0) 4114250003Sadrian { 4115250003Sadrian /* The board is uncalibrated */ 4116250003Sadrian return -1; 4117250003Sadrian } 4118250003Sadrian if (mptr->eeprom_version != 0x2) 4119250003Sadrian { 4120250003Sadrian return -1; 4121250003Sadrian } 4122250003Sadrian 4123250003Sadrian return mdata_size; 4124250003Sadrian 4125250003Sadrian} 4126250003Sadrian 4127250003Sadrianstatic int 4128250003Sadrianar9300_eeprom_restore_from_flash(struct ath_hal *ah, ar9300_eeprom_t *mptr, 4129250003Sadrian int mdata_size) 4130250003Sadrian{ 4131250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 4132250003Sadrian char *cal_ptr; 4133250003Sadrian 4134250003Sadrian HALASSERT(mdata_size > 0); 4135250003Sadrian 4136250003Sadrian if (!ahp->ah_cal_mem) { 4137250003Sadrian return -1; 4138250003Sadrian } 4139250003Sadrian 4140250003Sadrian ath_hal_printf(ah, "Restoring Cal data from Flash\n"); 4141250003Sadrian /* 4142250003Sadrian * When calibration data is saved in flash, read 4143250003Sadrian * uncompressed eeprom structure from flash and return 4144250003Sadrian */ 4145250003Sadrian cal_ptr = &((char *)(ahp->ah_cal_mem))[AR9300_FLASH_CAL_START_OFFSET]; 4146250003Sadrian OS_MEMCPY(mptr, cal_ptr, mdata_size); 4147250003Sadrian#if 0 4148250003Sadrian ar9300_swap_eeprom((ar9300_eeprom_t *)mptr); DONE IN ar9300_restore() 4149250003Sadrian#endif 4150250003Sadrian if (mptr->eeprom_version == 0xff || 4151250003Sadrian mptr->template_version == 0xff || 4152250003Sadrian mptr->eeprom_version == 0 || 4153250003Sadrian mptr->template_version == 0) 4154250003Sadrian { 4155250003Sadrian /* The board is uncalibrated */ 4156250003Sadrian return -1; 4157250003Sadrian } 4158250003Sadrian if (mptr->eeprom_version != 0x2) 4159250003Sadrian { 4160250003Sadrian return -1; 4161250003Sadrian } 4162250003Sadrian return mdata_size; 4163250003Sadrian} 4164250003Sadrian 4165250003Sadrian/* 4166250003Sadrian * Read the configuration data from the storage. We try the order with: 4167250003Sadrian * EEPROM, Flash, OTP. If all of above failed, use the default template. 4168250003Sadrian * The data can be put in any specified memory buffer. 4169250003Sadrian * 4170250003Sadrian * Returns -1 on error. 4171250003Sadrian * Returns address of next memory location on success. 4172250003Sadrian */ 4173250003Sadrianint 4174250003Sadrianar9300_eeprom_restore_internal(struct ath_hal *ah, ar9300_eeprom_t *mptr, 4175250003Sadrian int mdata_size) 4176250003Sadrian{ 4177250003Sadrian int nptr; 4178250003Sadrian 4179250003Sadrian nptr = -1; 4180250003Sadrian 4181250003Sadrian if ((AH9300(ah)->calibration_data_try == calibration_data_none || 4182250003Sadrian AH9300(ah)->calibration_data_try == calibration_data_dram) && 4183250003Sadrian AH9300(ah)->try_dram && nptr < 0) 4184250003Sadrian { 4185250008Sadrian ath_hal_printf(ah, "Restoring Cal data from DRAM\n"); 4186250003Sadrian AH9300(ah)->calibration_data_source = calibration_data_dram; 4187250003Sadrian AH9300(ah)->calibration_data_source_address = 0; 4188250003Sadrian nptr = ar9300_eeprom_restore_from_dram(ah, mptr, mdata_size); 4189250003Sadrian if (nptr < 0) { 4190250003Sadrian AH9300(ah)->calibration_data_source = calibration_data_none; 4191250003Sadrian AH9300(ah)->calibration_data_source_address = 0; 4192250003Sadrian } 4193250003Sadrian } 4194250003Sadrian 4195250003Sadrian if ((AH9300(ah)->calibration_data_try == calibration_data_none || 4196250003Sadrian AH9300(ah)->calibration_data_try == calibration_data_eeprom) && 4197250003Sadrian AH9300(ah)->try_eeprom && nptr < 0) 4198250003Sadrian { 4199250003Sadrian /* 4200250003Sadrian * need to look at highest eeprom address as well as at 4201250003Sadrian * base_address=0x3ff where we used to write the data 4202250003Sadrian */ 4203250008Sadrian ath_hal_printf(ah, "Restoring Cal data from EEPROM\n"); 4204250003Sadrian AH9300(ah)->calibration_data_source = calibration_data_eeprom; 4205250003Sadrian if (AH9300(ah)->calibration_data_try_address != 0) { 4206250003Sadrian AH9300(ah)->calibration_data_source_address = 4207250003Sadrian AH9300(ah)->calibration_data_try_address; 4208250003Sadrian nptr = ar9300_eeprom_restore_internal_address( 4209250003Sadrian ah, mptr, mdata_size, 4210250003Sadrian AH9300(ah)->calibration_data_source_address, 0xff); 4211250003Sadrian } else { 4212250003Sadrian AH9300(ah)->calibration_data_source_address = 4213250003Sadrian ar9300_eeprom_base_address(ah); 4214250003Sadrian nptr = ar9300_eeprom_restore_internal_address( 4215250003Sadrian ah, mptr, mdata_size, 4216250003Sadrian AH9300(ah)->calibration_data_source_address, 0xff); 4217250003Sadrian if (nptr < 0 && 4218250003Sadrian AH9300(ah)->calibration_data_source_address != base_address) 4219250003Sadrian { 4220250003Sadrian AH9300(ah)->calibration_data_source_address = base_address; 4221250003Sadrian nptr = ar9300_eeprom_restore_internal_address( 4222250003Sadrian ah, mptr, mdata_size, 4223250003Sadrian AH9300(ah)->calibration_data_source_address, 0xff); 4224250003Sadrian } 4225250003Sadrian } 4226250003Sadrian if (nptr < 0) { 4227250003Sadrian AH9300(ah)->calibration_data_source = calibration_data_none; 4228250003Sadrian AH9300(ah)->calibration_data_source_address = 0; 4229250003Sadrian } 4230250003Sadrian } 4231250003Sadrian 4232250003Sadrian /* 4233250003Sadrian * ##### should be an ifdef test for any AP usage, 4234250003Sadrian * either in driver or in nart 4235250003Sadrian */ 4236250003Sadrian if ((AH9300(ah)->calibration_data_try == calibration_data_none || 4237250003Sadrian AH9300(ah)->calibration_data_try == calibration_data_flash) && 4238250003Sadrian AH9300(ah)->try_flash && nptr < 0) 4239250003Sadrian { 4240250008Sadrian ath_hal_printf(ah, "Restoring Cal data from Flash\n"); 4241250003Sadrian AH9300(ah)->calibration_data_source = calibration_data_flash; 4242250003Sadrian /* how are we supposed to set this for flash? */ 4243250003Sadrian AH9300(ah)->calibration_data_source_address = 0; 4244250003Sadrian nptr = ar9300_eeprom_restore_from_flash(ah, mptr, mdata_size); 4245250003Sadrian if (nptr < 0) { 4246250003Sadrian AH9300(ah)->calibration_data_source = calibration_data_none; 4247250003Sadrian AH9300(ah)->calibration_data_source_address = 0; 4248250003Sadrian } 4249250003Sadrian } 4250250003Sadrian 4251250003Sadrian if ((AH9300(ah)->calibration_data_try == calibration_data_none || 4252250003Sadrian AH9300(ah)->calibration_data_try == calibration_data_otp) && 4253250003Sadrian AH9300(ah)->try_otp && nptr < 0) 4254250003Sadrian { 4255250008Sadrian ath_hal_printf(ah, "Restoring Cal data from OTP\n"); 4256250003Sadrian AH9300(ah)->calibration_data_source = calibration_data_otp; 4257250003Sadrian if (AH9300(ah)->calibration_data_try_address != 0) { 4258250003Sadrian AH9300(ah)->calibration_data_source_address = 4259250003Sadrian AH9300(ah)->calibration_data_try_address; 4260250003Sadrian } else { 4261250003Sadrian AH9300(ah)->calibration_data_source_address = 4262250003Sadrian ar9300_eeprom_base_address(ah); 4263250003Sadrian } 4264250003Sadrian nptr = ar9300_eeprom_restore_internal_address( 4265250003Sadrian ah, mptr, mdata_size, AH9300(ah)->calibration_data_source_address, 0); 4266250003Sadrian if (nptr < 0) { 4267250003Sadrian AH9300(ah)->calibration_data_source = calibration_data_none; 4268250003Sadrian AH9300(ah)->calibration_data_source_address = 0; 4269250003Sadrian } 4270250003Sadrian } 4271250003Sadrian 4272250003Sadrian#ifdef ATH_CAL_NAND_FLASH 4273250003Sadrian if ((AH9300(ah)->calibration_data_try == calibration_data_none || 4274250003Sadrian AH9300(ah)->calibration_data_try == calibration_data_nand) && 4275250003Sadrian AH9300(ah)->try_nand && nptr < 0) 4276250003Sadrian { 4277250003Sadrian AH9300(ah)->calibration_data_source = calibration_data_nand; 4278250003Sadrian AH9300(ah)->calibration_data_source_address = ((unsigned int)(AH_PRIVATE(ah)->ah_st)) + base_address_nand; 4279250003Sadrian if(ar9300_calibration_data_read( 4280250003Sadrian ah, AH9300(ah)->calibration_data_source_address, 4281250003Sadrian (u_int8_t *)mptr, mdata_size) == AH_TRUE) 4282250003Sadrian { 4283250003Sadrian nptr = mdata_size; 4284250003Sadrian } 4285250003Sadrian /*nptr=ar9300EepromRestoreInternalAddress(ah, mptr, mdataSize, CalibrationDataSourceAddress);*/ 4286250003Sadrian if(nptr < 0) 4287250003Sadrian { 4288250003Sadrian AH9300(ah)->calibration_data_source = calibration_data_none; 4289250003Sadrian AH9300(ah)->calibration_data_source_address = 0; 4290250003Sadrian } 4291250003Sadrian } 4292250003Sadrian#endif 4293250003Sadrian if (nptr < 0) { 4294250003Sadrian ath_hal_printf(ah, "%s[%d] No vaid CAL, calling default template\n", 4295250003Sadrian __func__, __LINE__); 4296250003Sadrian nptr = ar9300_eeprom_restore_something(ah, mptr, mdata_size); 4297250003Sadrian } 4298250003Sadrian 4299250003Sadrian return nptr; 4300250003Sadrian} 4301250003Sadrian 4302250003Sadrian/******************************************************************************/ 4303250003Sadrian/*! 4304250003Sadrian** \brief Eeprom Swapping Function 4305250003Sadrian** 4306250003Sadrian** This function will swap the contents of the "longer" EEPROM data items 4307250003Sadrian** to ensure they are consistent with the endian requirements for the platform 4308250003Sadrian** they are being compiled for 4309250003Sadrian** 4310250003Sadrian** \param eh Pointer to the EEPROM data structure 4311250003Sadrian** \return N/A 4312250003Sadrian*/ 4313250003Sadrian#if AH_BYTE_ORDER == AH_BIG_ENDIAN 4314250003Sadrianvoid 4315250003Sadrianar9300_swap_eeprom(ar9300_eeprom_t *eep) 4316250003Sadrian{ 4317250003Sadrian u_int32_t dword; 4318250003Sadrian u_int16_t word; 4319250003Sadrian int i; 4320250003Sadrian 4321250003Sadrian word = __bswap16(eep->base_eep_header.reg_dmn[0]); 4322250003Sadrian eep->base_eep_header.reg_dmn[0] = word; 4323250003Sadrian 4324250003Sadrian word = __bswap16(eep->base_eep_header.reg_dmn[1]); 4325250003Sadrian eep->base_eep_header.reg_dmn[1] = word; 4326250003Sadrian 4327250003Sadrian dword = __bswap32(eep->base_eep_header.swreg); 4328250003Sadrian eep->base_eep_header.swreg = dword; 4329250003Sadrian 4330250003Sadrian dword = __bswap32(eep->modal_header_2g.ant_ctrl_common); 4331250003Sadrian eep->modal_header_2g.ant_ctrl_common = dword; 4332250003Sadrian 4333250003Sadrian dword = __bswap32(eep->modal_header_2g.ant_ctrl_common2); 4334250003Sadrian eep->modal_header_2g.ant_ctrl_common2 = dword; 4335250003Sadrian 4336250003Sadrian dword = __bswap32(eep->modal_header_2g.paprd_rate_mask_ht20); 4337250003Sadrian eep->modal_header_2g.paprd_rate_mask_ht20 = dword; 4338250003Sadrian 4339250003Sadrian dword = __bswap32(eep->modal_header_2g.paprd_rate_mask_ht40); 4340250003Sadrian eep->modal_header_2g.paprd_rate_mask_ht40 = dword; 4341250003Sadrian 4342250003Sadrian dword = __bswap32(eep->modal_header_5g.ant_ctrl_common); 4343250003Sadrian eep->modal_header_5g.ant_ctrl_common = dword; 4344250003Sadrian 4345250003Sadrian dword = __bswap32(eep->modal_header_5g.ant_ctrl_common2); 4346250003Sadrian eep->modal_header_5g.ant_ctrl_common2 = dword; 4347250003Sadrian 4348250003Sadrian dword = __bswap32(eep->modal_header_5g.paprd_rate_mask_ht20); 4349250003Sadrian eep->modal_header_5g.paprd_rate_mask_ht20 = dword; 4350250003Sadrian 4351250003Sadrian dword = __bswap32(eep->modal_header_5g.paprd_rate_mask_ht40); 4352250003Sadrian eep->modal_header_5g.paprd_rate_mask_ht40 = dword; 4353250003Sadrian 4354250003Sadrian for (i = 0; i < OSPREY_MAX_CHAINS; i++) { 4355250003Sadrian word = __bswap16(eep->modal_header_2g.ant_ctrl_chain[i]); 4356250003Sadrian eep->modal_header_2g.ant_ctrl_chain[i] = word; 4357250003Sadrian 4358250003Sadrian word = __bswap16(eep->modal_header_5g.ant_ctrl_chain[i]); 4359250003Sadrian eep->modal_header_5g.ant_ctrl_chain[i] = word; 4360250003Sadrian } 4361250003Sadrian} 4362250003Sadrian 4363250003Sadrianvoid ar9300_eeprom_template_swap(void) 4364250003Sadrian{ 4365250003Sadrian int it; 4366250003Sadrian ar9300_eeprom_t *dptr; 4367250003Sadrian 4368250003Sadrian for (it = 0; it < ARRAY_LENGTH(default9300); it++) { 4369250003Sadrian dptr = ar9300_eeprom_struct_default(it); 4370250003Sadrian if (dptr != 0) { 4371250003Sadrian ar9300_swap_eeprom(dptr); 4372250003Sadrian } 4373250003Sadrian } 4374250003Sadrian} 4375250003Sadrian#endif 4376250003Sadrian 4377250003Sadrian 4378250003Sadrian/* 4379250003Sadrian * Restore the configuration structure by reading the eeprom. 4380250003Sadrian * This function destroys any existing in-memory structure content. 4381250003Sadrian */ 4382250003SadrianHAL_BOOL 4383250003Sadrianar9300_eeprom_restore(struct ath_hal *ah) 4384250003Sadrian{ 4385250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 4386250003Sadrian ar9300_eeprom_t *mptr; 4387250003Sadrian int mdata_size; 4388250003Sadrian HAL_BOOL status = AH_FALSE; 4389250003Sadrian 4390250003Sadrian mptr = &ahp->ah_eeprom; 4391250003Sadrian mdata_size = ar9300_eeprom_struct_size(); 4392250003Sadrian 4393250003Sadrian if (mptr != 0 && mdata_size > 0) { 4394250003Sadrian#if AH_BYTE_ORDER == AH_BIG_ENDIAN 4395250003Sadrian ar9300_eeprom_template_swap(); 4396250003Sadrian ar9300_swap_eeprom(mptr); 4397250003Sadrian#endif 4398250003Sadrian /* 4399250003Sadrian * At this point, mptr points to the eeprom data structure 4400250003Sadrian * in it's "default" state. If this is big endian, swap the 4401250003Sadrian * data structures back to "little endian" form. 4402250003Sadrian */ 4403250003Sadrian if (ar9300_eeprom_restore_internal(ah, mptr, mdata_size) >= 0) { 4404250003Sadrian status = AH_TRUE; 4405250003Sadrian } 4406250003Sadrian 4407250003Sadrian#if AH_BYTE_ORDER == AH_BIG_ENDIAN 4408250003Sadrian /* Second Swap, back to Big Endian */ 4409250003Sadrian ar9300_eeprom_template_swap(); 4410250003Sadrian ar9300_swap_eeprom(mptr); 4411250003Sadrian#endif 4412250003Sadrian 4413250003Sadrian } 4414250003Sadrian ahp->ah_2g_paprd_rate_mask_ht40 = 4415250003Sadrian mptr->modal_header_2g.paprd_rate_mask_ht40; 4416250003Sadrian ahp->ah_2g_paprd_rate_mask_ht20 = 4417250003Sadrian mptr->modal_header_2g.paprd_rate_mask_ht20; 4418250003Sadrian ahp->ah_5g_paprd_rate_mask_ht40 = 4419250003Sadrian mptr->modal_header_5g.paprd_rate_mask_ht40; 4420250003Sadrian ahp->ah_5g_paprd_rate_mask_ht20 = 4421250003Sadrian mptr->modal_header_5g.paprd_rate_mask_ht20; 4422250003Sadrian return status; 4423250003Sadrian} 4424250003Sadrian 4425250003Sadrianint32_t ar9300_thermometer_get(struct ath_hal *ah) 4426250003Sadrian{ 4427250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 4428250003Sadrian int thermometer; 4429250003Sadrian thermometer = 4430250003Sadrian (ahp->ah_eeprom.base_eep_header.misc_configuration >> 1) & 0x3; 4431250003Sadrian thermometer--; 4432250003Sadrian return thermometer; 4433250003Sadrian} 4434250003Sadrian 4435250003SadrianHAL_BOOL ar9300_thermometer_apply(struct ath_hal *ah) 4436250003Sadrian{ 4437250003Sadrian int thermometer = ar9300_thermometer_get(ah); 4438250003Sadrian 4439250003Sadrian/* ch0_RXTX4 */ 4440250003Sadrian/*#define AR_PHY_65NM_CH0_RXTX4 AR_PHY_65NM(ch0_RXTX4)*/ 4441250003Sadrian#define AR_PHY_65NM_CH1_RXTX4 AR_PHY_65NM(ch1_RXTX4) 4442250003Sadrian#define AR_PHY_65NM_CH2_RXTX4 AR_PHY_65NM(ch2_RXTX4) 4443250003Sadrian/*#define AR_PHY_65NM_CH0_RXTX4_THERM_ON 0x10000000*/ 4444250003Sadrian/*#define AR_PHY_65NM_CH0_RXTX4_THERM_ON_S 28*/ 4445250003Sadrian#define AR_PHY_65NM_CH0_RXTX4_THERM_ON_OVR_S 29 4446250003Sadrian#define AR_PHY_65NM_CH0_RXTX4_THERM_ON_OVR \ 4447250003Sadrian (0x1<<AR_PHY_65NM_CH0_RXTX4_THERM_ON_OVR_S) 4448250003Sadrian 4449250003Sadrian if (thermometer < 0) { 4450250003Sadrian OS_REG_RMW_FIELD(ah, 4451250003Sadrian AR_PHY_65NM_CH0_RXTX4, AR_PHY_65NM_CH0_RXTX4_THERM_ON_OVR, 0); 4452250003Sadrian if (!AR_SREV_HORNET(ah) && !AR_SREV_POSEIDON(ah)) { 4453250003Sadrian OS_REG_RMW_FIELD(ah, 4454250003Sadrian AR_PHY_65NM_CH1_RXTX4, AR_PHY_65NM_CH0_RXTX4_THERM_ON_OVR, 0); 4455291437Sadrian if (!AR_SREV_WASP(ah) && !AR_SREV_JUPITER(ah) && !AR_SREV_HONEYBEE(ah) ) { 4456250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_65NM_CH2_RXTX4, 4457250003Sadrian AR_PHY_65NM_CH0_RXTX4_THERM_ON_OVR, 0); 4458250003Sadrian } 4459250003Sadrian } 4460250003Sadrian OS_REG_RMW_FIELD(ah, 4461250003Sadrian AR_PHY_65NM_CH0_RXTX4, AR_PHY_65NM_CH0_RXTX4_THERM_ON, 0); 4462250003Sadrian if (!AR_SREV_HORNET(ah) && !AR_SREV_POSEIDON(ah)) { 4463250003Sadrian OS_REG_RMW_FIELD(ah, 4464250003Sadrian AR_PHY_65NM_CH1_RXTX4, AR_PHY_65NM_CH0_RXTX4_THERM_ON, 0); 4465291437Sadrian if (!AR_SREV_WASP(ah) && !AR_SREV_JUPITER(ah) && !AR_SREV_HONEYBEE(ah) ) { 4466250003Sadrian OS_REG_RMW_FIELD(ah, 4467250003Sadrian AR_PHY_65NM_CH2_RXTX4, AR_PHY_65NM_CH0_RXTX4_THERM_ON, 0); 4468250003Sadrian } 4469250003Sadrian } 4470250003Sadrian } else { 4471250003Sadrian OS_REG_RMW_FIELD(ah, 4472250003Sadrian AR_PHY_65NM_CH0_RXTX4, AR_PHY_65NM_CH0_RXTX4_THERM_ON_OVR, 1); 4473250003Sadrian if (!AR_SREV_HORNET(ah) && !AR_SREV_POSEIDON(ah)) { 4474250003Sadrian OS_REG_RMW_FIELD(ah, 4475250003Sadrian AR_PHY_65NM_CH1_RXTX4, AR_PHY_65NM_CH0_RXTX4_THERM_ON_OVR, 1); 4476291437Sadrian if (!AR_SREV_WASP(ah) && !AR_SREV_JUPITER(ah) && !AR_SREV_HONEYBEE(ah) ) { 4477250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_65NM_CH2_RXTX4, 4478250003Sadrian AR_PHY_65NM_CH0_RXTX4_THERM_ON_OVR, 1); 4479250003Sadrian } 4480250003Sadrian } 4481250003Sadrian if (thermometer == 0) { 4482250003Sadrian OS_REG_RMW_FIELD(ah, 4483250003Sadrian AR_PHY_65NM_CH0_RXTX4, AR_PHY_65NM_CH0_RXTX4_THERM_ON, 1); 4484250003Sadrian if (!AR_SREV_HORNET(ah) && !AR_SREV_POSEIDON(ah)) { 4485250003Sadrian OS_REG_RMW_FIELD(ah, 4486250003Sadrian AR_PHY_65NM_CH1_RXTX4, AR_PHY_65NM_CH0_RXTX4_THERM_ON, 0); 4487291437Sadrian if (!AR_SREV_WASP(ah) && !AR_SREV_JUPITER(ah) && !AR_SREV_HONEYBEE(ah) ) { 4488250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_65NM_CH2_RXTX4, 4489250003Sadrian AR_PHY_65NM_CH0_RXTX4_THERM_ON, 0); 4490250003Sadrian } 4491250003Sadrian } 4492250003Sadrian } else if (thermometer == 1) { 4493250003Sadrian OS_REG_RMW_FIELD(ah, 4494250003Sadrian AR_PHY_65NM_CH0_RXTX4, AR_PHY_65NM_CH0_RXTX4_THERM_ON, 0); 4495250003Sadrian if (!AR_SREV_HORNET(ah) && !AR_SREV_POSEIDON(ah)) { 4496250003Sadrian OS_REG_RMW_FIELD(ah, 4497250003Sadrian AR_PHY_65NM_CH1_RXTX4, AR_PHY_65NM_CH0_RXTX4_THERM_ON, 1); 4498291437Sadrian if (!AR_SREV_WASP(ah) && !AR_SREV_JUPITER(ah) && !AR_SREV_HONEYBEE(ah) ) { 4499250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_65NM_CH2_RXTX4, 4500250003Sadrian AR_PHY_65NM_CH0_RXTX4_THERM_ON, 0); 4501250003Sadrian } 4502250003Sadrian } 4503250003Sadrian } else if (thermometer == 2) { 4504250003Sadrian OS_REG_RMW_FIELD(ah, 4505250003Sadrian AR_PHY_65NM_CH0_RXTX4, AR_PHY_65NM_CH0_RXTX4_THERM_ON, 0); 4506250003Sadrian if (!AR_SREV_HORNET(ah) && !AR_SREV_POSEIDON(ah)) { 4507250003Sadrian OS_REG_RMW_FIELD(ah, 4508250003Sadrian AR_PHY_65NM_CH1_RXTX4, AR_PHY_65NM_CH0_RXTX4_THERM_ON, 0); 4509291437Sadrian if (!AR_SREV_WASP(ah) && !AR_SREV_JUPITER(ah) && !AR_SREV_HONEYBEE(ah) ) { 4510250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_65NM_CH2_RXTX4, 4511250003Sadrian AR_PHY_65NM_CH0_RXTX4_THERM_ON, 1); 4512250003Sadrian } 4513250003Sadrian } 4514250003Sadrian } 4515250003Sadrian } 4516250003Sadrian return AH_TRUE; 4517250003Sadrian} 4518250003Sadrian 4519250003Sadrianstatic int32_t ar9300_tuning_caps_params_get(struct ath_hal *ah) 4520250003Sadrian{ 4521250003Sadrian int tuning_caps_params; 4522250003Sadrian ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom; 4523250003Sadrian tuning_caps_params = eep->base_eep_header.params_for_tuning_caps[0]; 4524250003Sadrian return tuning_caps_params; 4525250003Sadrian} 4526250003Sadrian 4527250003Sadrian/* 4528250003Sadrian * Read the tuning caps params from eeprom and set to correct register. 4529250003Sadrian * To regulation the frequency accuracy. 4530250003Sadrian */ 4531250003SadrianHAL_BOOL ar9300_tuning_caps_apply(struct ath_hal *ah) 4532250003Sadrian{ 4533250003Sadrian int tuning_caps_params; 4534250003Sadrian ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom; 4535250003Sadrian tuning_caps_params = ar9300_tuning_caps_params_get(ah); 4536250003Sadrian if ((eep->base_eep_header.feature_enable & 0x40) >> 6) { 4537250003Sadrian tuning_caps_params &= 0x7f; 4538250003Sadrian 4539291437Sadrian if (AR_SREV_POSEIDON(ah) || AR_SREV_WASP(ah) || AR_SREV_HONEYBEE(ah)) { 4540291437Sadrian return true; 4541283309Sadrian } else if (AR_SREV_HORNET(ah)) { 4542283309Sadrian OS_REG_RMW_FIELD(ah, 4543283309Sadrian AR_HORNET_CH0_XTAL, AR_OSPREY_CHO_XTAL_CAPINDAC, 4544283309Sadrian tuning_caps_params); 4545283309Sadrian OS_REG_RMW_FIELD(ah, 4546283309Sadrian AR_HORNET_CH0_XTAL, AR_OSPREY_CHO_XTAL_CAPOUTDAC, 4547283309Sadrian tuning_caps_params); 4548250003Sadrian } else if (AR_SREV_SCORPION(ah)) { 4549250003Sadrian OS_REG_RMW_FIELD(ah, 4550250003Sadrian AR_SCORPION_CH0_XTAL, AR_OSPREY_CHO_XTAL_CAPINDAC, 4551250003Sadrian tuning_caps_params); 4552250003Sadrian OS_REG_RMW_FIELD(ah, 4553250003Sadrian AR_SCORPION_CH0_XTAL, AR_OSPREY_CHO_XTAL_CAPOUTDAC, 4554250003Sadrian tuning_caps_params); 4555250003Sadrian } else { 4556250003Sadrian OS_REG_RMW_FIELD(ah, 4557250003Sadrian AR_OSPREY_CH0_XTAL, AR_OSPREY_CHO_XTAL_CAPINDAC, 4558250003Sadrian tuning_caps_params); 4559250003Sadrian OS_REG_RMW_FIELD(ah, 4560250003Sadrian AR_OSPREY_CH0_XTAL, AR_OSPREY_CHO_XTAL_CAPOUTDAC, 4561250003Sadrian tuning_caps_params); 4562250003Sadrian } 4563250003Sadrian 4564250003Sadrian } 4565250003Sadrian return AH_TRUE; 4566250003Sadrian} 4567250003Sadrian 4568250003Sadrian/* 4569250003Sadrian * Read the tx_frame_to_xpa_on param from eeprom and apply the value to 4570250003Sadrian * correct register. 4571250003Sadrian */ 4572250003SadrianHAL_BOOL ar9300_xpa_timing_control_apply(struct ath_hal *ah, HAL_BOOL is_2ghz) 4573250003Sadrian{ 4574250003Sadrian u_int8_t xpa_timing_control; 4575250003Sadrian ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom; 4576250003Sadrian if ((eep->base_eep_header.feature_enable & 0x80) >> 7) { 4577291437Sadrian if (AR_SREV_OSPREY(ah) || AR_SREV_AR9580(ah) || AR_SREV_WASP(ah) || AR_SREV_HONEYBEE(ah)) { 4578250003Sadrian if (is_2ghz) { 4579250003Sadrian xpa_timing_control = eep->modal_header_2g.tx_frame_to_xpa_on; 4580250003Sadrian OS_REG_RMW_FIELD(ah, 4581250003Sadrian AR_PHY_XPA_TIMING_CTL, AR_PHY_XPA_TIMING_CTL_FRAME_XPAB_ON, 4582250003Sadrian xpa_timing_control); 4583250003Sadrian } else { 4584250003Sadrian xpa_timing_control = eep->modal_header_5g.tx_frame_to_xpa_on; 4585250003Sadrian OS_REG_RMW_FIELD(ah, 4586250003Sadrian AR_PHY_XPA_TIMING_CTL, AR_PHY_XPA_TIMING_CTL_FRAME_XPAA_ON, 4587250003Sadrian xpa_timing_control); 4588250003Sadrian } 4589250003Sadrian } 4590250003Sadrian } 4591250003Sadrian return AH_TRUE; 4592250003Sadrian} 4593250003Sadrian 4594250003Sadrian 4595250003Sadrian/* 4596250003Sadrian * Read the xLNA_bias_strength param from eeprom and apply the value to 4597250003Sadrian * correct register. 4598250003Sadrian */ 4599250003SadrianHAL_BOOL ar9300_x_lNA_bias_strength_apply(struct ath_hal *ah, HAL_BOOL is_2ghz) 4600250003Sadrian{ 4601250003Sadrian u_int8_t x_lNABias; 4602250003Sadrian u_int32_t value = 0; 4603250003Sadrian ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom; 4604250003Sadrian 4605250003Sadrian if ((eep->base_eep_header.misc_configuration & 0x40) >> 6) { 4606250003Sadrian if (AR_SREV_OSPREY(ah)) { 4607250003Sadrian if (is_2ghz) { 4608250003Sadrian x_lNABias = eep->modal_header_2g.xLNA_bias_strength; 4609250003Sadrian } else { 4610250003Sadrian x_lNABias = eep->modal_header_5g.xLNA_bias_strength; 4611250003Sadrian } 4612250003Sadrian value = x_lNABias & ( 0x03 ); // bit0,1 for chain0 4613250003Sadrian OS_REG_RMW_FIELD(ah, 4614250003Sadrian AR_PHY_65NM_CH0_RXTX4, AR_PHY_65NM_RXTX4_XLNA_BIAS, value); 4615250003Sadrian value = (x_lNABias >> 2) & ( 0x03 ); // bit2,3 for chain1 4616250003Sadrian OS_REG_RMW_FIELD(ah, 4617250003Sadrian AR_PHY_65NM_CH1_RXTX4, AR_PHY_65NM_RXTX4_XLNA_BIAS, value); 4618250003Sadrian value = (x_lNABias >> 4) & ( 0x03 ); // bit4,5 for chain2 4619250003Sadrian OS_REG_RMW_FIELD(ah, 4620250003Sadrian AR_PHY_65NM_CH2_RXTX4, AR_PHY_65NM_RXTX4_XLNA_BIAS, value); 4621250003Sadrian } 4622250003Sadrian } 4623250003Sadrian return AH_TRUE; 4624250003Sadrian} 4625250003Sadrian 4626250003Sadrian 4627250003Sadrian/* 4628250003Sadrian * Read EEPROM header info and program the device for correct operation 4629250003Sadrian * given the channel value. 4630250003Sadrian */ 4631250003SadrianHAL_BOOL 4632250008Sadrianar9300_eeprom_set_board_values(struct ath_hal *ah, const struct ieee80211_channel *chan) 4633250003Sadrian{ 4634250008Sadrian HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan); 4635250003Sadrian 4636250008Sadrian ar9300_xpa_bias_level_apply(ah, IEEE80211_IS_CHAN_2GHZ(chan)); 4637250003Sadrian 4638250008Sadrian ar9300_xpa_timing_control_apply(ah, IEEE80211_IS_CHAN_2GHZ(chan)); 4639250008Sadrian 4640250008Sadrian ar9300_ant_ctrl_apply(ah, IEEE80211_IS_CHAN_2GHZ(chan)); 4641250003Sadrian ar9300_drive_strength_apply(ah); 4642250003Sadrian 4643250008Sadrian ar9300_x_lNA_bias_strength_apply(ah, IEEE80211_IS_CHAN_2GHZ(chan)); 4644250003Sadrian 4645250003Sadrian /* wait for Poseidon internal regular turnning */ 4646250003Sadrian /* for Hornet we move it before initPLL to avoid an access issue */ 4647250003Sadrian /* Function not used when EMULATION. */ 4648291437Sadrian if (!AR_SREV_HORNET(ah) && !AR_SREV_WASP(ah) && !AR_SREV_HONEYBEE(ah)) { 4649250003Sadrian ar9300_internal_regulator_apply(ah); 4650250003Sadrian } 4651250003Sadrian 4652250008Sadrian ar9300_attenuation_apply(ah, ichan->channel); 4653250008Sadrian ar9300_quick_drop_apply(ah, ichan->channel); 4654250003Sadrian ar9300_thermometer_apply(ah); 4655250003Sadrian if(!AR_SREV_WASP(ah)) 4656250003Sadrian { 4657250003Sadrian ar9300_tuning_caps_apply(ah); 4658250003Sadrian } 4659250003Sadrian 4660250008Sadrian ar9300_tx_end_to_xpab_off_apply(ah, ichan->channel); 4661250003Sadrian 4662250003Sadrian return AH_TRUE; 4663250003Sadrian} 4664250003Sadrian 4665250003Sadrianu_int8_t * 4666250003Sadrianar9300_eeprom_get_spur_chans_ptr(struct ath_hal *ah, HAL_BOOL is_2ghz) 4667250003Sadrian{ 4668250003Sadrian ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom; 4669250003Sadrian 4670250003Sadrian if (is_2ghz) { 4671250003Sadrian return &(eep->modal_header_2g.spur_chans[0]); 4672250003Sadrian } else { 4673250003Sadrian return &(eep->modal_header_5g.spur_chans[0]); 4674250003Sadrian } 4675250003Sadrian} 4676250003Sadrian 4677250003Sadrianstatic u_int8_t ar9300_eeprom_get_tx_gain_table_number_max(struct ath_hal *ah) 4678250003Sadrian{ 4679250003Sadrian unsigned long tx_gain_table_max; 4680250003Sadrian tx_gain_table_max = OS_REG_READ_FIELD(ah, 4681250003Sadrian AR_PHY_TPC_7, AR_PHY_TPC_7_TX_GAIN_TABLE_MAX); 4682250003Sadrian return tx_gain_table_max; 4683250003Sadrian} 4684250003Sadrian 4685250003Sadrianu_int8_t ar9300_eeprom_tx_gain_table_index_max_apply(struct ath_hal *ah, u_int16_t channel) 4686250003Sadrian{ 4687250003Sadrian unsigned int index; 4688250003Sadrian ar9300_eeprom_t *ahp_Eeprom; 4689250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 4690250003Sadrian 4691250003Sadrian ahp_Eeprom = &ahp->ah_eeprom; 4692250003Sadrian 4693250003Sadrian if (ahp_Eeprom->base_ext1.misc_enable == 0) 4694250003Sadrian return AH_FALSE; 4695250003Sadrian 4696250003Sadrian if (channel < 4000) 4697250003Sadrian { 4698250003Sadrian index = ahp_Eeprom->modal_header_2g.tx_gain_cap; 4699250003Sadrian } 4700250003Sadrian else 4701250003Sadrian { 4702250003Sadrian index = ahp_Eeprom->modal_header_5g.tx_gain_cap; 4703250003Sadrian } 4704250003Sadrian 4705250003Sadrian OS_REG_RMW_FIELD(ah, 4706250003Sadrian AR_PHY_TPC_7, AR_PHY_TPC_7_TX_GAIN_TABLE_MAX, index); 4707250003Sadrian return AH_TRUE; 4708250003Sadrian} 4709250003Sadrian 4710250003Sadrianstatic u_int8_t ar9300_eeprom_get_pcdac_tx_gain_table_i(struct ath_hal *ah, 4711250003Sadrian int i, u_int8_t *pcdac) 4712250003Sadrian{ 4713250003Sadrian unsigned long tx_gain; 4714250003Sadrian u_int8_t tx_gain_table_max; 4715250003Sadrian tx_gain_table_max = ar9300_eeprom_get_tx_gain_table_number_max(ah); 4716250003Sadrian if (i <= 0 || i > tx_gain_table_max) { 4717250003Sadrian *pcdac = 0; 4718250003Sadrian return AH_FALSE; 4719250003Sadrian } 4720250003Sadrian 4721250003Sadrian tx_gain = OS_REG_READ(ah, AR_PHY_TXGAIN_TAB(1) + i * 4); 4722250003Sadrian *pcdac = ((tx_gain >> 24) & 0xff); 4723250003Sadrian return AH_TRUE; 4724250003Sadrian} 4725250003Sadrian 4726250003Sadrianu_int8_t ar9300_eeprom_set_tx_gain_cap(struct ath_hal *ah, 4727250003Sadrian int *tx_gain_max) 4728250003Sadrian// pcdac read back from reg, read back value depends on reset 2GHz/5GHz ini 4729250003Sadrian// tx_gain_table, this function will be called twice after each 4730250003Sadrian// band's calibration. 4731250003Sadrian// after 2GHz cal, tx_gain_max[0] has 2GHz, calibration max txgain, 4732250003Sadrian// tx_gain_max[1]=-100 4733250003Sadrian// after 5GHz cal, tx_gain_max[0],tx_gain_max[1] have calibration 4734250003Sadrian// value for both band 4735250003Sadrian// reset is on 5GHz, reg reading from tx_gain_table is for 5GHz, 4736250003Sadrian// so program can't recalculate 2g.tx_gain_cap at this point. 4737250003Sadrian{ 4738250003Sadrian int i = 0, ig, im = 0; 4739250003Sadrian u_int8_t pcdac = 0; 4740250003Sadrian u_int8_t tx_gain_table_max; 4741250003Sadrian ar9300_eeprom_t *ahp_Eeprom; 4742250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 4743250003Sadrian 4744250003Sadrian ahp_Eeprom = &ahp->ah_eeprom; 4745250003Sadrian 4746250003Sadrian if (ahp_Eeprom->base_ext1.misc_enable == 0) 4747250003Sadrian return AH_FALSE; 4748250003Sadrian 4749250003Sadrian tx_gain_table_max = ar9300_eeprom_get_tx_gain_table_number_max(ah); 4750250003Sadrian 4751250003Sadrian for (i = 0; i < 2; i++) { 4752250003Sadrian if (tx_gain_max[i]>-100) { // -100 didn't cal that band. 4753250003Sadrian if ( i== 0) { 4754250003Sadrian if (tx_gain_max[1]>-100) { 4755250003Sadrian continue; 4756250003Sadrian // both band are calibrated, skip 2GHz 2g.tx_gain_cap reset 4757250003Sadrian } 4758250003Sadrian } 4759250003Sadrian for (ig = 1; ig <= tx_gain_table_max; ig++) { 4760250003Sadrian if (ah != 0 && ah->ah_reset != 0) 4761250003Sadrian { 4762250003Sadrian ar9300_eeprom_get_pcdac_tx_gain_table_i(ah, ig, &pcdac); 4763250003Sadrian if (pcdac >= tx_gain_max[i]) 4764250003Sadrian break; 4765250003Sadrian } 4766250003Sadrian } 4767250003Sadrian if (ig+1 <= tx_gain_table_max) { 4768250003Sadrian if (pcdac == tx_gain_max[i]) 4769250003Sadrian im = ig; 4770250003Sadrian else 4771250003Sadrian im = ig + 1; 4772250003Sadrian if (i == 0) { 4773250003Sadrian ahp_Eeprom->modal_header_2g.tx_gain_cap = im; 4774250003Sadrian } else { 4775250003Sadrian ahp_Eeprom->modal_header_5g.tx_gain_cap = im; 4776250003Sadrian } 4777250003Sadrian } else { 4778250003Sadrian if (i == 0) { 4779250003Sadrian ahp_Eeprom->modal_header_2g.tx_gain_cap = ig; 4780250003Sadrian } else { 4781250003Sadrian ahp_Eeprom->modal_header_5g.tx_gain_cap = ig; 4782250003Sadrian } 4783250003Sadrian } 4784250003Sadrian } 4785250003Sadrian } 4786250003Sadrian return AH_TRUE; 4787250003Sadrian} 4788