176bd547bSAdrian Chadd /*
276bd547bSAdrian Chadd  * Copyright (c) 2013 Qualcomm Atheros, Inc.
376bd547bSAdrian Chadd  *
476bd547bSAdrian Chadd  * Permission to use, copy, modify, and/or distribute this software for any
576bd547bSAdrian Chadd  * purpose with or without fee is hereby granted, provided that the above
676bd547bSAdrian Chadd  * copyright notice and this permission notice appear in all copies.
776bd547bSAdrian Chadd  *
876bd547bSAdrian Chadd  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
976bd547bSAdrian Chadd  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
1076bd547bSAdrian Chadd  * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
1176bd547bSAdrian Chadd  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
1276bd547bSAdrian Chadd  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
1376bd547bSAdrian Chadd  * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
1476bd547bSAdrian Chadd  * PERFORMANCE OF THIS SOFTWARE.
1576bd547bSAdrian Chadd  */
1676bd547bSAdrian Chadd 
1776bd547bSAdrian Chadd #include "opt_ah.h"
1876bd547bSAdrian Chadd 
1976bd547bSAdrian Chadd #include "ah.h"
2076bd547bSAdrian Chadd #include "ah_internal.h"
2176bd547bSAdrian Chadd #include "ah_devid.h"
2276bd547bSAdrian Chadd #ifdef AH_DEBUG
2376bd547bSAdrian Chadd #include "ah_desc.h"                    /* NB: for HAL_PHYERR* */
2476bd547bSAdrian Chadd #endif
2576bd547bSAdrian Chadd #include "ar9300/ar9300.h"
2676bd547bSAdrian Chadd #include "ar9300/ar9300eep.h"
2776bd547bSAdrian Chadd #include "ar9300/ar9300template_generic.h"
2876bd547bSAdrian Chadd #include "ar9300/ar9300template_xb112.h"
2976bd547bSAdrian Chadd #include "ar9300/ar9300template_hb116.h"
3076bd547bSAdrian Chadd #include "ar9300/ar9300template_xb113.h"
3176bd547bSAdrian Chadd #include "ar9300/ar9300template_hb112.h"
3276bd547bSAdrian Chadd #include "ar9300/ar9300template_ap121.h"
3376bd547bSAdrian Chadd #include "ar9300/ar9300template_osprey_k31.h"
3476bd547bSAdrian Chadd #include "ar9300/ar9300template_wasp_2.h"
3576bd547bSAdrian Chadd #include "ar9300/ar9300template_wasp_k31.h"
3676bd547bSAdrian Chadd #include "ar9300/ar9300template_aphrodite.h"
3776bd547bSAdrian Chadd #include "ar9300/ar9300reg.h"
3876bd547bSAdrian Chadd #include "ar9300/ar9300phy.h"
3976bd547bSAdrian Chadd 
4076bd547bSAdrian Chadd 
4176bd547bSAdrian Chadd 
4276bd547bSAdrian Chadd #if AH_BYTE_ORDER == AH_BIG_ENDIAN
4376bd547bSAdrian Chadd void ar9300_swap_eeprom(ar9300_eeprom_t *eep);
4476bd547bSAdrian Chadd void ar9300_eeprom_template_swap(void);
4576bd547bSAdrian Chadd #endif
4676bd547bSAdrian Chadd 
4776bd547bSAdrian Chadd static u_int16_t ar9300_eeprom_get_spur_chan(struct ath_hal *ah,
48e113789bSAdrian Chadd     int spur_chan, HAL_BOOL is_2ghz);
4976bd547bSAdrian Chadd #ifdef UNUSED
5076bd547bSAdrian Chadd static inline HAL_BOOL ar9300_fill_eeprom(struct ath_hal *ah);
5176bd547bSAdrian Chadd static inline HAL_STATUS ar9300_check_eeprom(struct ath_hal *ah);
5276bd547bSAdrian Chadd #endif
5376bd547bSAdrian Chadd 
5476bd547bSAdrian Chadd static ar9300_eeprom_t *default9300[] =
5576bd547bSAdrian Chadd {
5676bd547bSAdrian Chadd     &ar9300_template_generic,
5776bd547bSAdrian Chadd     &ar9300_template_xb112,
5876bd547bSAdrian Chadd     &ar9300_template_hb116,
5976bd547bSAdrian Chadd     &ar9300_template_hb112,
6076bd547bSAdrian Chadd     &ar9300_template_xb113,
6176bd547bSAdrian Chadd     &ar9300_template_ap121,
6276bd547bSAdrian Chadd     &ar9300_template_wasp_2,
6376bd547bSAdrian Chadd     &ar9300_template_wasp_k31,
6476bd547bSAdrian Chadd     &ar9300_template_osprey_k31,
6576bd547bSAdrian Chadd     &ar9300_template_aphrodite,
6676bd547bSAdrian Chadd };
6776bd547bSAdrian Chadd 
6876bd547bSAdrian Chadd /*
6976bd547bSAdrian Chadd  * Different types of memory where the calibration data might be stored.
7076bd547bSAdrian Chadd  * All types are searched in ar9300_eeprom_restore()
7176bd547bSAdrian Chadd  * in the order flash, eeprom, otp.
7276bd547bSAdrian Chadd  * To disable searching a type, set its parameter to 0.
7376bd547bSAdrian Chadd  */
7476bd547bSAdrian Chadd 
7576bd547bSAdrian Chadd /*
7676bd547bSAdrian Chadd  * This is where we look for the calibration data.
7776bd547bSAdrian Chadd  * must be set before ath_attach() is called
7876bd547bSAdrian Chadd  */
7976bd547bSAdrian Chadd static int calibration_data_try = calibration_data_none;
8076bd547bSAdrian Chadd static int calibration_data_try_address = 0;
8176bd547bSAdrian Chadd 
8276bd547bSAdrian Chadd /*
8376bd547bSAdrian Chadd  * Set the type of memory used to store calibration data.
8476bd547bSAdrian Chadd  * Used by nart to force reading/writing of a specific type.
8576bd547bSAdrian Chadd  * The driver can normally allow autodetection
8676bd547bSAdrian Chadd  * by setting source to calibration_data_none=0.
8776bd547bSAdrian Chadd  */
ar9300_calibration_data_set(struct ath_hal * ah,int32_t source)8876bd547bSAdrian Chadd void ar9300_calibration_data_set(struct ath_hal *ah, int32_t source)
8976bd547bSAdrian Chadd {
9076bd547bSAdrian Chadd     if (ah != 0) {
9176bd547bSAdrian Chadd         AH9300(ah)->calibration_data_source = source;
9276bd547bSAdrian Chadd     } else {
9376bd547bSAdrian Chadd         calibration_data_try = source;
9476bd547bSAdrian Chadd     }
9576bd547bSAdrian Chadd }
9676bd547bSAdrian Chadd 
ar9300_calibration_data_get(struct ath_hal * ah)9776bd547bSAdrian Chadd int32_t ar9300_calibration_data_get(struct ath_hal *ah)
9876bd547bSAdrian Chadd {
9976bd547bSAdrian Chadd     if (ah != 0) {
10076bd547bSAdrian Chadd         return AH9300(ah)->calibration_data_source;
10176bd547bSAdrian Chadd     } else {
10276bd547bSAdrian Chadd         return calibration_data_try;
10376bd547bSAdrian Chadd     }
10476bd547bSAdrian Chadd }
10576bd547bSAdrian Chadd 
10676bd547bSAdrian Chadd /*
10776bd547bSAdrian Chadd  * Set the address of first byte used to store calibration data.
10876bd547bSAdrian Chadd  * Used by nart to force reading/writing at a specific address.
10976bd547bSAdrian Chadd  * The driver can normally allow autodetection by setting size=0.
11076bd547bSAdrian Chadd  */
ar9300_calibration_data_address_set(struct ath_hal * ah,int32_t size)11176bd547bSAdrian Chadd void ar9300_calibration_data_address_set(struct ath_hal *ah, int32_t size)
11276bd547bSAdrian Chadd {
11376bd547bSAdrian Chadd     if (ah != 0) {
11476bd547bSAdrian Chadd         AH9300(ah)->calibration_data_source_address = size;
11576bd547bSAdrian Chadd     } else {
11676bd547bSAdrian Chadd         calibration_data_try_address = size;
11776bd547bSAdrian Chadd     }
11876bd547bSAdrian Chadd }
11976bd547bSAdrian Chadd 
ar9300_calibration_data_address_get(struct ath_hal * ah)12076bd547bSAdrian Chadd int32_t ar9300_calibration_data_address_get(struct ath_hal *ah)
12176bd547bSAdrian Chadd {
12276bd547bSAdrian Chadd     if (ah != 0) {
12376bd547bSAdrian Chadd         return AH9300(ah)->calibration_data_source_address;
12476bd547bSAdrian Chadd     } else {
12576bd547bSAdrian Chadd         return calibration_data_try_address;
12676bd547bSAdrian Chadd     }
12776bd547bSAdrian Chadd }
12876bd547bSAdrian Chadd 
12976bd547bSAdrian Chadd /*
13076bd547bSAdrian Chadd  * This is the template that is loaded if ar9300_eeprom_restore()
13176bd547bSAdrian Chadd  * can't find valid data in the memory.
13276bd547bSAdrian Chadd  */
13376bd547bSAdrian Chadd static int Ar9300_eeprom_template_preference = ar9300_eeprom_template_generic;
13476bd547bSAdrian Chadd 
ar9300_eeprom_template_preference(int32_t value)13576bd547bSAdrian Chadd void ar9300_eeprom_template_preference(int32_t value)
13676bd547bSAdrian Chadd {
13776bd547bSAdrian Chadd     Ar9300_eeprom_template_preference = value;
13876bd547bSAdrian Chadd }
13976bd547bSAdrian Chadd 
14076bd547bSAdrian Chadd /*
14176bd547bSAdrian Chadd  * Install the specified default template.
14276bd547bSAdrian Chadd  * Overwrites any existing calibration and configuration information in memory.
14376bd547bSAdrian Chadd  */
ar9300_eeprom_template_install(struct ath_hal * ah,int32_t value)14476bd547bSAdrian Chadd int32_t ar9300_eeprom_template_install(struct ath_hal *ah, int32_t value)
14576bd547bSAdrian Chadd {
14676bd547bSAdrian Chadd     struct ath_hal_9300 *ahp = AH9300(ah);
14776bd547bSAdrian Chadd     ar9300_eeprom_t *mptr, *dptr;
14876bd547bSAdrian Chadd     int mdata_size;
14976bd547bSAdrian Chadd 
15076bd547bSAdrian Chadd     mptr = &ahp->ah_eeprom;
15176bd547bSAdrian Chadd     mdata_size = ar9300_eeprom_struct_size();
15276bd547bSAdrian Chadd     if (mptr != 0) {
15376bd547bSAdrian Chadd #if 0
15476bd547bSAdrian Chadd         calibration_data_source = calibration_data_none;
15576bd547bSAdrian Chadd         calibration_data_source_address = 0;
15676bd547bSAdrian Chadd #endif
15776bd547bSAdrian Chadd         dptr = ar9300_eeprom_struct_default_find_by_id(value);
15876bd547bSAdrian Chadd         if (dptr != 0) {
15976bd547bSAdrian Chadd             OS_MEMCPY(mptr, dptr, mdata_size);
16076bd547bSAdrian Chadd             return 0;
16176bd547bSAdrian Chadd         }
16276bd547bSAdrian Chadd     }
16376bd547bSAdrian Chadd     return -1;
16476bd547bSAdrian Chadd }
16576bd547bSAdrian Chadd 
16676bd547bSAdrian Chadd static int
ar9300_eeprom_restore_something(struct ath_hal * ah,ar9300_eeprom_t * mptr,int mdata_size)16776bd547bSAdrian Chadd ar9300_eeprom_restore_something(struct ath_hal *ah, ar9300_eeprom_t *mptr,
16876bd547bSAdrian Chadd     int mdata_size)
16976bd547bSAdrian Chadd {
17076bd547bSAdrian Chadd     int it;
17176bd547bSAdrian Chadd     ar9300_eeprom_t *dptr;
17276bd547bSAdrian Chadd     int nptr;
17376bd547bSAdrian Chadd 
17476bd547bSAdrian Chadd     nptr = -1;
17576bd547bSAdrian Chadd     /*
17676bd547bSAdrian Chadd      * if we didn't find any blocks in the memory,
17776bd547bSAdrian Chadd      * put the prefered template in place
17876bd547bSAdrian Chadd      */
17976bd547bSAdrian Chadd     if (nptr < 0) {
18076bd547bSAdrian Chadd         AH9300(ah)->calibration_data_source = calibration_data_none;
18176bd547bSAdrian Chadd         AH9300(ah)->calibration_data_source_address = 0;
18276bd547bSAdrian Chadd         dptr = ar9300_eeprom_struct_default_find_by_id(
18376bd547bSAdrian Chadd             Ar9300_eeprom_template_preference);
18476bd547bSAdrian Chadd         if (dptr != 0) {
18576bd547bSAdrian Chadd             OS_MEMCPY(mptr, dptr, mdata_size);
18676bd547bSAdrian Chadd             nptr = 0;
18776bd547bSAdrian Chadd         }
18876bd547bSAdrian Chadd     }
18976bd547bSAdrian Chadd     /*
19076bd547bSAdrian Chadd      * if we didn't find the prefered one,
19176bd547bSAdrian Chadd      * put the normal default template in place
19276bd547bSAdrian Chadd      */
19376bd547bSAdrian Chadd     if (nptr < 0) {
19476bd547bSAdrian Chadd         AH9300(ah)->calibration_data_source = calibration_data_none;
19576bd547bSAdrian Chadd         AH9300(ah)->calibration_data_source_address = 0;
19676bd547bSAdrian Chadd         dptr = ar9300_eeprom_struct_default_find_by_id(
19776bd547bSAdrian Chadd             ar9300_eeprom_template_default);
19876bd547bSAdrian Chadd         if (dptr != 0) {
19976bd547bSAdrian Chadd             OS_MEMCPY(mptr, dptr, mdata_size);
20076bd547bSAdrian Chadd             nptr = 0;
20176bd547bSAdrian Chadd         }
20276bd547bSAdrian Chadd     }
20376bd547bSAdrian Chadd     /*
20476bd547bSAdrian Chadd      * if we can't find the best template, put any old template in place
20576bd547bSAdrian Chadd      * presume that newer ones are better, so search backwards
20676bd547bSAdrian Chadd      */
20776bd547bSAdrian Chadd     if (nptr < 0) {
20876bd547bSAdrian Chadd         AH9300(ah)->calibration_data_source = calibration_data_none;
20976bd547bSAdrian Chadd         AH9300(ah)->calibration_data_source_address = 0;
21076bd547bSAdrian Chadd         for (it = ar9300_eeprom_struct_default_many() - 1; it >= 0; it--) {
21176bd547bSAdrian Chadd             dptr = ar9300_eeprom_struct_default(it);
21276bd547bSAdrian Chadd             if (dptr != 0) {
21376bd547bSAdrian Chadd                 OS_MEMCPY(mptr, dptr, mdata_size);
21476bd547bSAdrian Chadd                 nptr = 0;
21576bd547bSAdrian Chadd                 break;
21676bd547bSAdrian Chadd             }
21776bd547bSAdrian Chadd         }
21876bd547bSAdrian Chadd     }
21976bd547bSAdrian Chadd     return nptr;
22076bd547bSAdrian Chadd }
22176bd547bSAdrian Chadd 
22276bd547bSAdrian Chadd /*
22376bd547bSAdrian Chadd  * Read 16 bits of data from offset into *data
22476bd547bSAdrian Chadd  */
22576bd547bSAdrian Chadd HAL_BOOL
ar9300_eeprom_read_word(struct ath_hal * ah,u_int off,u_int16_t * data)22676bd547bSAdrian Chadd ar9300_eeprom_read_word(struct ath_hal *ah, u_int off, u_int16_t *data)
22776bd547bSAdrian Chadd {
228f254aad3SBjoern A. Zeeb     if (AR_SREV_OSPREY(ah) || AR_SREV_POSEIDON(ah) || AR_SREV_JUPITER(ah))
22976bd547bSAdrian Chadd     {
23076bd547bSAdrian Chadd         (void) OS_REG_READ(ah, AR9300_EEPROM_OFFSET + (off << AR9300_EEPROM_S));
23176bd547bSAdrian Chadd         if (!ath_hal_wait(ah,
23276bd547bSAdrian Chadd 			  AR_HOSTIF_REG(ah, AR_EEPROM_STATUS_DATA),
23376bd547bSAdrian Chadd 			  AR_EEPROM_STATUS_DATA_BUSY | AR_EEPROM_STATUS_DATA_PROT_ACCESS,
234e113789bSAdrian Chadd 			  0))
23576bd547bSAdrian Chadd 	{
23676bd547bSAdrian Chadd             return AH_FALSE;
23776bd547bSAdrian Chadd 	}
23876bd547bSAdrian Chadd         *data = MS(OS_REG_READ(ah,
23976bd547bSAdrian Chadd 			       AR_HOSTIF_REG(ah, AR_EEPROM_STATUS_DATA)), AR_EEPROM_STATUS_DATA_VAL);
24076bd547bSAdrian Chadd        return AH_TRUE;
24176bd547bSAdrian Chadd     }
24276bd547bSAdrian Chadd     else
24376bd547bSAdrian Chadd     {
24476bd547bSAdrian Chadd         *data = 0;
24576bd547bSAdrian Chadd         return AH_FALSE;
24676bd547bSAdrian Chadd     }
24776bd547bSAdrian Chadd }
24876bd547bSAdrian Chadd 
24976bd547bSAdrian Chadd 
25076bd547bSAdrian Chadd HAL_BOOL
ar9300_otp_read(struct ath_hal * ah,u_int off,u_int32_t * data,HAL_BOOL is_wifi)25176bd547bSAdrian Chadd ar9300_otp_read(struct ath_hal *ah, u_int off, u_int32_t *data, HAL_BOOL is_wifi)
25276bd547bSAdrian Chadd {
25376bd547bSAdrian Chadd     int time_out = 1000;
25476bd547bSAdrian Chadd     int status = 0;
25576bd547bSAdrian Chadd     u_int32_t addr;
25676bd547bSAdrian Chadd 
25727e2ad46SAdrian Chadd     if (AR_SREV_HONEYBEE(ah)){ /* no OTP for Honeybee */
25827e2ad46SAdrian Chadd         return false;
25927e2ad46SAdrian Chadd     }
26076bd547bSAdrian Chadd     addr = (AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah))?
26176bd547bSAdrian Chadd         OTP_MEM_START_ADDRESS_WASP : OTP_MEM_START_ADDRESS;
26276bd547bSAdrian Chadd 	if (!is_wifi) {
26376bd547bSAdrian Chadd         addr = BTOTP_MEM_START_ADDRESS;
26476bd547bSAdrian Chadd     }
26576bd547bSAdrian Chadd     addr += off * 4; /* OTP is 32 bit addressable */
26676bd547bSAdrian Chadd     (void) OS_REG_READ(ah, addr);
26776bd547bSAdrian Chadd 
26876bd547bSAdrian Chadd     addr = (AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) ?
26976bd547bSAdrian Chadd         OTP_STATUS0_OTP_SM_BUSY_WASP : OTP_STATUS0_OTP_SM_BUSY;
27076bd547bSAdrian Chadd 	if (!is_wifi) {
27176bd547bSAdrian Chadd         addr = BTOTP_STATUS0_OTP_SM_BUSY;
27276bd547bSAdrian Chadd     }
27376bd547bSAdrian Chadd     while ((time_out > 0) && (!status)) { /* wait for access complete */
27476bd547bSAdrian Chadd         /* Read data valid, access not busy, sm not busy */
27576bd547bSAdrian Chadd         status = ((OS_REG_READ(ah, addr) & 0x7) == 0x4) ? 1 : 0;
27676bd547bSAdrian Chadd         time_out--;
27776bd547bSAdrian Chadd     }
27876bd547bSAdrian Chadd     if (time_out == 0) {
27976bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_EEPROM,
28076bd547bSAdrian Chadd             "%s: Timed out during OTP Status0 validation\n", __func__);
28176bd547bSAdrian Chadd         return AH_FALSE;
28276bd547bSAdrian Chadd     }
28376bd547bSAdrian Chadd 
28476bd547bSAdrian Chadd     addr = (AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) ?
28576bd547bSAdrian Chadd         OTP_STATUS1_EFUSE_READ_DATA_WASP : OTP_STATUS1_EFUSE_READ_DATA;
28676bd547bSAdrian Chadd 	if (!is_wifi) {
28776bd547bSAdrian Chadd         addr = BTOTP_STATUS1_EFUSE_READ_DATA;
28876bd547bSAdrian Chadd     }
28976bd547bSAdrian Chadd     *data = OS_REG_READ(ah, addr);
29076bd547bSAdrian Chadd     return AH_TRUE;
29176bd547bSAdrian Chadd }
29276bd547bSAdrian Chadd 
29376bd547bSAdrian Chadd 
29476bd547bSAdrian Chadd 
29576bd547bSAdrian Chadd 
29676bd547bSAdrian Chadd static HAL_STATUS
ar9300_flash_map(struct ath_hal * ah)29776bd547bSAdrian Chadd ar9300_flash_map(struct ath_hal *ah)
29876bd547bSAdrian Chadd {
299e113789bSAdrian Chadd     /* XXX disable flash remapping for now (ie, SoC support) */
300e113789bSAdrian Chadd     ath_hal_printf(ah, "%s: unimplemented for now\n", __func__);
301e113789bSAdrian Chadd #if 0
30276bd547bSAdrian Chadd     struct ath_hal_9300 *ahp = AH9300(ah);
30376bd547bSAdrian Chadd #if defined(AR9100) || defined(__NetBSD__)
30476bd547bSAdrian Chadd     ahp->ah_cal_mem = OS_REMAP(ah, AR9300_EEPROM_START_ADDR, AR9300_EEPROM_MAX);
30576bd547bSAdrian Chadd #else
30676bd547bSAdrian Chadd     ahp->ah_cal_mem = OS_REMAP((uintptr_t)(AH_PRIVATE(ah)->ah_st),
30776bd547bSAdrian Chadd         (AR9300_EEPROM_MAX + AR9300_FLASH_CAL_START_OFFSET));
30876bd547bSAdrian Chadd #endif
30976bd547bSAdrian Chadd     if (!ahp->ah_cal_mem) {
31076bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_EEPROM,
31176bd547bSAdrian Chadd             "%s: cannot remap eeprom region \n", __func__);
31276bd547bSAdrian Chadd         return HAL_EIO;
31376bd547bSAdrian Chadd     }
314e113789bSAdrian Chadd #endif
31576bd547bSAdrian Chadd     return HAL_OK;
31676bd547bSAdrian Chadd }
31776bd547bSAdrian Chadd 
31876bd547bSAdrian Chadd HAL_BOOL
ar9300_flash_read(struct ath_hal * ah,u_int off,u_int16_t * data)31976bd547bSAdrian Chadd ar9300_flash_read(struct ath_hal *ah, u_int off, u_int16_t *data)
32076bd547bSAdrian Chadd {
32176bd547bSAdrian Chadd     struct ath_hal_9300 *ahp = AH9300(ah);
32276bd547bSAdrian Chadd 
32376bd547bSAdrian Chadd     *data = ((u_int16_t *)ahp->ah_cal_mem)[off];
32476bd547bSAdrian Chadd     return AH_TRUE;
32576bd547bSAdrian Chadd }
32676bd547bSAdrian Chadd 
32776bd547bSAdrian Chadd HAL_BOOL
ar9300_flash_write(struct ath_hal * ah,u_int off,u_int16_t data)32876bd547bSAdrian Chadd ar9300_flash_write(struct ath_hal *ah, u_int off, u_int16_t data)
32976bd547bSAdrian Chadd {
33076bd547bSAdrian Chadd     struct ath_hal_9300 *ahp = AH9300(ah);
33176bd547bSAdrian Chadd 
33276bd547bSAdrian Chadd     ((u_int16_t *)ahp->ah_cal_mem)[off] = data;
33376bd547bSAdrian Chadd     return AH_TRUE;
33476bd547bSAdrian Chadd }
33576bd547bSAdrian Chadd 
33676bd547bSAdrian Chadd HAL_STATUS
ar9300_eeprom_attach(struct ath_hal * ah)33776bd547bSAdrian Chadd ar9300_eeprom_attach(struct ath_hal *ah)
33876bd547bSAdrian Chadd {
33976bd547bSAdrian Chadd     struct ath_hal_9300 *ahp = AH9300(ah);
34076bd547bSAdrian Chadd     ahp->try_dram = 1;
34176bd547bSAdrian Chadd     ahp->try_eeprom = 1;
34276bd547bSAdrian Chadd     ahp->try_otp = 1;
34376bd547bSAdrian Chadd #ifdef ATH_CAL_NAND_FLASH
34476bd547bSAdrian Chadd     ahp->try_nand = 1;
34576bd547bSAdrian Chadd #else
34676bd547bSAdrian Chadd     ahp->try_flash = 1;
34776bd547bSAdrian Chadd #endif
34876bd547bSAdrian Chadd     ahp->calibration_data_source = calibration_data_none;
34976bd547bSAdrian Chadd     ahp->calibration_data_source_address = 0;
35076bd547bSAdrian Chadd     ahp->calibration_data_try = calibration_data_try;
35176bd547bSAdrian Chadd     ahp->calibration_data_try_address = 0;
35276bd547bSAdrian Chadd 
35376bd547bSAdrian Chadd     /*
35476bd547bSAdrian Chadd      * In case flash will be used for EEPROM. Otherwise ahp->ah_cal_mem
35576bd547bSAdrian Chadd      * must be set to NULL or the real EEPROM address.
35676bd547bSAdrian Chadd      */
35776bd547bSAdrian Chadd     ar9300_flash_map(ah);
35876bd547bSAdrian Chadd     /*
35976bd547bSAdrian Chadd      * ###### This function always return NO SPUR.
36027e2ad46SAdrian Chadd      * This is not true for many board designs.
36176bd547bSAdrian Chadd      * Does anyone use this?
36276bd547bSAdrian Chadd      */
363e113789bSAdrian Chadd     AH_PRIVATE(ah)->ah_getSpurChan = ar9300_eeprom_get_spur_chan;
36476bd547bSAdrian Chadd 
36576bd547bSAdrian Chadd #ifdef OLDCODE
36676bd547bSAdrian Chadd     /* XXX Needs to be moved for dynamic selection */
36776bd547bSAdrian Chadd     ahp->ah_eeprom = *(default9300[ar9300_eeprom_template_default]);
36876bd547bSAdrian Chadd 
36976bd547bSAdrian Chadd 
37076bd547bSAdrian Chadd     if (AR_SREV_HORNET(ah)) {
37176bd547bSAdrian Chadd         /* Set default values for Hornet. */
37276bd547bSAdrian Chadd         ahp->ah_eeprom.base_eep_header.op_cap_flags.op_flags =
37376bd547bSAdrian Chadd             AR9300_OPFLAGS_11G;
37476bd547bSAdrian Chadd         ahp->ah_eeprom.base_eep_header.txrx_mask = 0x11;
37576bd547bSAdrian Chadd     } else if (AR_SREV_POSEIDON(ah)) {
37676bd547bSAdrian Chadd         /* Set default values for Poseidon. */
37776bd547bSAdrian Chadd         ahp->ah_eeprom.base_eep_header.op_cap_flags.op_flags =
37876bd547bSAdrian Chadd             AR9300_OPFLAGS_11G;
37976bd547bSAdrian Chadd         ahp->ah_eeprom.base_eep_header.txrx_mask = 0x11;
38076bd547bSAdrian Chadd     }
38176bd547bSAdrian Chadd 
38276bd547bSAdrian Chadd     if (AH_PRIVATE(ah)->ah_config.ath_hal_skip_eeprom_read) {
38376bd547bSAdrian Chadd         ahp->ah_emu_eeprom = 1;
38476bd547bSAdrian Chadd         return HAL_OK;
38576bd547bSAdrian Chadd     }
38676bd547bSAdrian Chadd 
38776bd547bSAdrian Chadd     ahp->ah_emu_eeprom = 1;
38876bd547bSAdrian Chadd 
38976bd547bSAdrian Chadd #ifdef UNUSED
39076bd547bSAdrian Chadd #endif
39176bd547bSAdrian Chadd 
39276bd547bSAdrian Chadd     if (!ar9300_fill_eeprom(ah)) {
39376bd547bSAdrian Chadd         return HAL_EIO;
39476bd547bSAdrian Chadd     }
39576bd547bSAdrian Chadd 
39676bd547bSAdrian Chadd     return HAL_OK;
39776bd547bSAdrian Chadd     /* return ar9300_check_eeprom(ah); */
39876bd547bSAdrian Chadd #else
39976bd547bSAdrian Chadd     ahp->ah_emu_eeprom = 1;
40076bd547bSAdrian Chadd 
40176bd547bSAdrian Chadd #if 0
40276bd547bSAdrian Chadd /*#ifdef MDK_AP*/ /* MDK_AP is defined only in NART AP build */
40376bd547bSAdrian Chadd     u_int8_t buffer[10];
40476bd547bSAdrian Chadd     int caldata_check = 0;
40576bd547bSAdrian Chadd 
40676bd547bSAdrian Chadd     ar9300_calibration_data_read_flash(
40776bd547bSAdrian Chadd         ah, FLASH_BASE_CALDATA_OFFSET, buffer, 4);
40876bd547bSAdrian Chadd     printf("flash caldata:: %x\n", buffer[0]);
40976bd547bSAdrian Chadd     if (buffer[0] != 0xff) {
41076bd547bSAdrian Chadd         caldata_check = 1;
41176bd547bSAdrian Chadd     }
41276bd547bSAdrian Chadd     if (!caldata_check) {
41376bd547bSAdrian Chadd         ar9300_eeprom_t *mptr;
41476bd547bSAdrian Chadd         int mdata_size;
41576bd547bSAdrian Chadd         if (AR_SREV_HORNET(ah)) {
41676bd547bSAdrian Chadd             /* XXX: For initial testing */
41776bd547bSAdrian Chadd             mptr = &ahp->ah_eeprom;
41876bd547bSAdrian Chadd             mdata_size = ar9300_eeprom_struct_size();
41976bd547bSAdrian Chadd             ahp->ah_eeprom = ar9300_template_ap121;
42076bd547bSAdrian Chadd             ahp->ah_emu_eeprom = 1;
42176bd547bSAdrian Chadd             /* need it to let art save in to flash ????? */
42276bd547bSAdrian Chadd             calibration_data_source = calibration_data_flash;
42376bd547bSAdrian Chadd         } else if (AR_SREV_WASP(ah)) {
42476bd547bSAdrian Chadd             /* XXX: For initial testing */
42576bd547bSAdrian Chadd             ath_hal_printf(ah, " wasp eep attach\n");
42676bd547bSAdrian Chadd             mptr = &ahp->ah_eeprom;
42776bd547bSAdrian Chadd             mdata_size = ar9300_eeprom_struct_size();
42876bd547bSAdrian Chadd             ahp->ah_eeprom = ar9300_template_generic;
42976bd547bSAdrian Chadd             ahp->ah_eeprom.mac_addr[0] = 0x00;
43076bd547bSAdrian Chadd             ahp->ah_eeprom.mac_addr[1] = 0x03;
43176bd547bSAdrian Chadd             ahp->ah_eeprom.mac_addr[2] = 0x7F;
43276bd547bSAdrian Chadd             ahp->ah_eeprom.mac_addr[3] = 0xBA;
43376bd547bSAdrian Chadd             ahp->ah_eeprom.mac_addr[4] = 0xD0;
43476bd547bSAdrian Chadd             ahp->ah_eeprom.mac_addr[5] = 0x00;
43576bd547bSAdrian Chadd             ahp->ah_emu_eeprom = 1;
43676bd547bSAdrian Chadd             ahp->ah_eeprom.base_eep_header.txrx_mask = 0x33;
43776bd547bSAdrian Chadd             ahp->ah_eeprom.base_eep_header.txrxgain = 0x10;
43876bd547bSAdrian Chadd             /* need it to let art save in to flash ????? */
43976bd547bSAdrian Chadd             calibration_data_source = calibration_data_flash;
44076bd547bSAdrian Chadd         }
44176bd547bSAdrian Chadd         return HAL_OK;
44276bd547bSAdrian Chadd     }
44376bd547bSAdrian Chadd #endif
44427e2ad46SAdrian Chadd     if (AR_SREV_HORNET(ah) || AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)
44527e2ad46SAdrian Chadd         || AR_SREV_HONEYBEE(ah)) {
44676bd547bSAdrian Chadd         ahp->try_eeprom = 0;
44776bd547bSAdrian Chadd     }
44876bd547bSAdrian Chadd 
44927e2ad46SAdrian Chadd     if (AR_SREV_HONEYBEE(ah)) {
45027e2ad46SAdrian Chadd         ahp->try_otp = 0;
45127e2ad46SAdrian Chadd     }
45227e2ad46SAdrian Chadd 
45376bd547bSAdrian Chadd     if (!ar9300_eeprom_restore(ah)) {
45476bd547bSAdrian Chadd         return HAL_EIO;
45576bd547bSAdrian Chadd     }
45676bd547bSAdrian Chadd     return HAL_OK;
45776bd547bSAdrian Chadd #endif
45876bd547bSAdrian Chadd }
45976bd547bSAdrian Chadd 
46076bd547bSAdrian Chadd u_int32_t
ar9300_eeprom_get(struct ath_hal_9300 * ahp,EEPROM_PARAM param)46176bd547bSAdrian Chadd ar9300_eeprom_get(struct ath_hal_9300 *ahp, EEPROM_PARAM param)
46276bd547bSAdrian Chadd {
46376bd547bSAdrian Chadd     ar9300_eeprom_t *eep = &ahp->ah_eeprom;
46476bd547bSAdrian Chadd     OSPREY_BASE_EEP_HEADER *p_base = &eep->base_eep_header;
46576bd547bSAdrian Chadd     OSPREY_BASE_EXTENSION_1 *base_ext1 = &eep->base_ext1;
46676bd547bSAdrian Chadd 
46776bd547bSAdrian Chadd     switch (param) {
468e113789bSAdrian Chadd #ifdef NOTYET
46976bd547bSAdrian Chadd     case EEP_NFTHRESH_5:
47076bd547bSAdrian Chadd         return p_modal[0].noise_floor_thresh_ch[0];
47176bd547bSAdrian Chadd     case EEP_NFTHRESH_2:
47276bd547bSAdrian Chadd         return p_modal[1].noise_floor_thresh_ch[0];
47376bd547bSAdrian Chadd #endif
47476bd547bSAdrian Chadd     case EEP_MAC_LSW:
47576bd547bSAdrian Chadd         return eep->mac_addr[0] << 8 | eep->mac_addr[1];
47676bd547bSAdrian Chadd     case EEP_MAC_MID:
47776bd547bSAdrian Chadd         return eep->mac_addr[2] << 8 | eep->mac_addr[3];
47876bd547bSAdrian Chadd     case EEP_MAC_MSW:
47976bd547bSAdrian Chadd         return eep->mac_addr[4] << 8 | eep->mac_addr[5];
48076bd547bSAdrian Chadd     case EEP_REG_0:
48176bd547bSAdrian Chadd         return p_base->reg_dmn[0];
48276bd547bSAdrian Chadd     case EEP_REG_1:
48376bd547bSAdrian Chadd         return p_base->reg_dmn[1];
48476bd547bSAdrian Chadd     case EEP_OP_CAP:
48576bd547bSAdrian Chadd         return p_base->device_cap;
48676bd547bSAdrian Chadd     case EEP_OP_MODE:
48776bd547bSAdrian Chadd         return p_base->op_cap_flags.op_flags;
48876bd547bSAdrian Chadd     case EEP_RF_SILENT:
48976bd547bSAdrian Chadd         return p_base->rf_silent;
490e113789bSAdrian Chadd #ifdef NOTYET
49176bd547bSAdrian Chadd     case EEP_OB_5:
49276bd547bSAdrian Chadd         return p_modal[0].ob;
49376bd547bSAdrian Chadd     case EEP_DB_5:
49476bd547bSAdrian Chadd         return p_modal[0].db;
49576bd547bSAdrian Chadd     case EEP_OB_2:
49676bd547bSAdrian Chadd         return p_modal[1].ob;
49776bd547bSAdrian Chadd     case EEP_DB_2:
49876bd547bSAdrian Chadd         return p_modal[1].db;
49976bd547bSAdrian Chadd     case EEP_MINOR_REV:
50076bd547bSAdrian Chadd         return p_base->eeprom_version & AR9300_EEP_VER_MINOR_MASK;
50176bd547bSAdrian Chadd #endif
50276bd547bSAdrian Chadd     case EEP_TX_MASK:
50376bd547bSAdrian Chadd         return (p_base->txrx_mask >> 4) & 0xf;
50476bd547bSAdrian Chadd     case EEP_RX_MASK:
50576bd547bSAdrian Chadd         return p_base->txrx_mask & 0xf;
506e113789bSAdrian Chadd #ifdef NOTYET
50776bd547bSAdrian Chadd     case EEP_FSTCLK_5G:
50876bd547bSAdrian Chadd         return p_base->fast_clk5g;
50976bd547bSAdrian Chadd     case EEP_RXGAIN_TYPE:
51076bd547bSAdrian Chadd         return p_base->rx_gain_type;
51176bd547bSAdrian Chadd #endif
51276bd547bSAdrian Chadd     case EEP_DRIVE_STRENGTH:
51376bd547bSAdrian Chadd #define AR9300_EEP_BASE_DRIVE_STRENGTH    0x1
51476bd547bSAdrian Chadd         return p_base->misc_configuration & AR9300_EEP_BASE_DRIVE_STRENGTH;
51576bd547bSAdrian Chadd     case EEP_INTERNAL_REGULATOR:
51676bd547bSAdrian Chadd         /* Bit 4 is internal regulator flag */
51776bd547bSAdrian Chadd         return ((p_base->feature_enable & 0x10) >> 4);
51876bd547bSAdrian Chadd     case EEP_SWREG:
51976bd547bSAdrian Chadd         return (p_base->swreg);
52076bd547bSAdrian Chadd     case EEP_PAPRD_ENABLED:
52176bd547bSAdrian Chadd         /* Bit 5 is paprd flag */
52276bd547bSAdrian Chadd         return ((p_base->feature_enable & 0x20) >> 5);
52376bd547bSAdrian Chadd     case EEP_ANTDIV_control:
52476bd547bSAdrian Chadd         return (u_int32_t)(base_ext1->ant_div_control);
52576bd547bSAdrian Chadd     case EEP_CHAIN_MASK_REDUCE:
52676bd547bSAdrian Chadd         return ((p_base->misc_configuration >> 3) & 0x1);
52776bd547bSAdrian Chadd     case EEP_OL_PWRCTRL:
52876bd547bSAdrian Chadd         return 0;
52976bd547bSAdrian Chadd      case EEP_DEV_TYPE:
53076bd547bSAdrian Chadd         return p_base->device_type;
53176bd547bSAdrian Chadd     default:
53276bd547bSAdrian Chadd         HALASSERT(0);
53376bd547bSAdrian Chadd         return 0;
53476bd547bSAdrian Chadd     }
53576bd547bSAdrian Chadd }
53676bd547bSAdrian Chadd 
53776bd547bSAdrian Chadd 
53876bd547bSAdrian Chadd 
53976bd547bSAdrian Chadd /******************************************************************************/
54076bd547bSAdrian Chadd /*!
54176bd547bSAdrian Chadd **  \brief EEPROM fixup code for INI values
54276bd547bSAdrian Chadd **
54376bd547bSAdrian Chadd ** This routine provides a place to insert "fixup" code for specific devices
54476bd547bSAdrian Chadd ** that need to modify INI values based on EEPROM values, BEFORE the INI values
54576bd547bSAdrian Chadd ** are written.
54676bd547bSAdrian Chadd ** Certain registers in the INI file can only be written once without
54776bd547bSAdrian Chadd ** undesired side effects, and this provides a place for EEPROM overrides
54876bd547bSAdrian Chadd ** in these cases.
54976bd547bSAdrian Chadd **
55076bd547bSAdrian Chadd ** This is called at attach time once.  It should not affect run time
55176bd547bSAdrian Chadd ** performance at all
55276bd547bSAdrian Chadd **
55376bd547bSAdrian Chadd **  \param ah       Pointer to HAL object (this)
55476bd547bSAdrian Chadd **  \param p_eep_data Pointer to (filled in) eeprom data structure
55576bd547bSAdrian Chadd **  \param reg      register being inspected on this call
55676bd547bSAdrian Chadd **  \param value    value in INI file
55776bd547bSAdrian Chadd **
55876bd547bSAdrian Chadd **  \return Updated value for INI file.
55976bd547bSAdrian Chadd */
56076bd547bSAdrian Chadd u_int32_t
ar9300_ini_fixup(struct ath_hal * ah,ar9300_eeprom_t * p_eep_data,u_int32_t reg,u_int32_t value)56176bd547bSAdrian Chadd ar9300_ini_fixup(struct ath_hal *ah, ar9300_eeprom_t *p_eep_data,
56276bd547bSAdrian Chadd     u_int32_t reg, u_int32_t value)
56376bd547bSAdrian Chadd {
56476bd547bSAdrian Chadd     HALDEBUG(AH_NULL, HAL_DEBUG_UNMASKABLE,
56576bd547bSAdrian Chadd         "ar9300_eeprom_def_ini_fixup: FIXME\n");
56676bd547bSAdrian Chadd #if 0
56776bd547bSAdrian Chadd     BASE_EEPDEF_HEADER  *p_base  = &(p_eep_data->base_eep_header);
56876bd547bSAdrian Chadd 
56976bd547bSAdrian Chadd     switch (AH_PRIVATE(ah)->ah_devid)
57076bd547bSAdrian Chadd     {
57176bd547bSAdrian Chadd     case AR9300_DEVID_AR9300_PCI:
57276bd547bSAdrian Chadd         /*
57376bd547bSAdrian Chadd         ** Need to set the external/internal regulator bit to the proper value.
57476bd547bSAdrian Chadd         ** Can only write this ONCE.
57576bd547bSAdrian Chadd         */
57676bd547bSAdrian Chadd 
57776bd547bSAdrian Chadd         if ( reg == 0x7894 )
57876bd547bSAdrian Chadd         {
57976bd547bSAdrian Chadd             /*
58076bd547bSAdrian Chadd             ** Check for an EEPROM data structure of "0x0b" or better
58176bd547bSAdrian Chadd             */
58276bd547bSAdrian Chadd 
58376bd547bSAdrian Chadd             HALDEBUG(ah, HAL_DEBUG_EEPROM, "ini VAL: %x  EEPROM: %x\n",
58476bd547bSAdrian Chadd                      value, (p_base->version & 0xff));
58576bd547bSAdrian Chadd 
58676bd547bSAdrian Chadd             if ( (p_base->version & 0xff) > 0x0a) {
58776bd547bSAdrian Chadd                 HALDEBUG(ah, HAL_DEBUG_EEPROM,
58876bd547bSAdrian Chadd                     "PWDCLKIND: %d\n", p_base->pwdclkind);
58976bd547bSAdrian Chadd                 value &= ~AR_AN_TOP2_PWDCLKIND;
59076bd547bSAdrian Chadd                 value |=
59176bd547bSAdrian Chadd                     AR_AN_TOP2_PWDCLKIND &
59276bd547bSAdrian Chadd                     (p_base->pwdclkind <<  AR_AN_TOP2_PWDCLKIND_S);
59376bd547bSAdrian Chadd             } else {
59476bd547bSAdrian Chadd                 HALDEBUG(ah, HAL_DEBUG_EEPROM, "PWDCLKIND Earlier Rev\n");
59576bd547bSAdrian Chadd             }
59676bd547bSAdrian Chadd 
59776bd547bSAdrian Chadd             HALDEBUG(ah, HAL_DEBUG_EEPROM, "final ini VAL: %x\n", value);
59876bd547bSAdrian Chadd         }
59976bd547bSAdrian Chadd         break;
60076bd547bSAdrian Chadd 
60176bd547bSAdrian Chadd     }
60276bd547bSAdrian Chadd 
60376bd547bSAdrian Chadd     return (value);
60476bd547bSAdrian Chadd #else
60576bd547bSAdrian Chadd     return 0;
60676bd547bSAdrian Chadd #endif
60776bd547bSAdrian Chadd }
60876bd547bSAdrian Chadd 
60976bd547bSAdrian Chadd /*
61076bd547bSAdrian Chadd  * Returns the interpolated y value corresponding to the specified x value
61176bd547bSAdrian Chadd  * from the np ordered pairs of data (px,py).
61276bd547bSAdrian Chadd  * The pairs do not have to be in any order.
61376bd547bSAdrian Chadd  * If the specified x value is less than any of the px,
61476bd547bSAdrian Chadd  * the returned y value is equal to the py for the lowest px.
61576bd547bSAdrian Chadd  * If the specified x value is greater than any of the px,
61676bd547bSAdrian Chadd  * the returned y value is equal to the py for the highest px.
61776bd547bSAdrian Chadd  */
61876bd547bSAdrian Chadd static int
interpolate(int32_t x,int32_t * px,int32_t * py,u_int16_t np)61976bd547bSAdrian Chadd interpolate(int32_t x, int32_t *px, int32_t *py, u_int16_t np)
62076bd547bSAdrian Chadd {
62176bd547bSAdrian Chadd     int ip = 0;
62276bd547bSAdrian Chadd     int lx = 0, ly = 0, lhave = 0;
62376bd547bSAdrian Chadd     int hx = 0, hy = 0, hhave = 0;
62476bd547bSAdrian Chadd     int dx = 0;
62576bd547bSAdrian Chadd     int y = 0;
62676bd547bSAdrian Chadd     int bf, factor, plus;
62776bd547bSAdrian Chadd 
62876bd547bSAdrian Chadd     lhave = 0;
62976bd547bSAdrian Chadd     hhave = 0;
63076bd547bSAdrian Chadd     /*
63176bd547bSAdrian Chadd      * identify best lower and higher x calibration measurement
63276bd547bSAdrian Chadd      */
63376bd547bSAdrian Chadd     for (ip = 0; ip < np; ip++) {
63476bd547bSAdrian Chadd         dx = x - px[ip];
63576bd547bSAdrian Chadd         /* this measurement is higher than our desired x */
63676bd547bSAdrian Chadd         if (dx <= 0) {
63776bd547bSAdrian Chadd             if (!hhave || dx > (x - hx)) {
63876bd547bSAdrian Chadd                 /* new best higher x measurement */
63976bd547bSAdrian Chadd                 hx = px[ip];
64076bd547bSAdrian Chadd                 hy = py[ip];
64176bd547bSAdrian Chadd                 hhave = 1;
64276bd547bSAdrian Chadd             }
64376bd547bSAdrian Chadd         }
64476bd547bSAdrian Chadd         /* this measurement is lower than our desired x */
64576bd547bSAdrian Chadd         if (dx >= 0) {
64676bd547bSAdrian Chadd             if (!lhave || dx < (x - lx)) {
64776bd547bSAdrian Chadd                 /* new best lower x measurement */
64876bd547bSAdrian Chadd                 lx = px[ip];
64976bd547bSAdrian Chadd                 ly = py[ip];
65076bd547bSAdrian Chadd                 lhave = 1;
65176bd547bSAdrian Chadd             }
65276bd547bSAdrian Chadd         }
65376bd547bSAdrian Chadd     }
65476bd547bSAdrian Chadd     /* the low x is good */
65576bd547bSAdrian Chadd     if (lhave) {
65676bd547bSAdrian Chadd         /* so is the high x */
65776bd547bSAdrian Chadd         if (hhave) {
65876bd547bSAdrian Chadd             /* they're the same, so just pick one */
65976bd547bSAdrian Chadd             if (hx == lx) {
66076bd547bSAdrian Chadd                 y = ly;
66176bd547bSAdrian Chadd             } else {
66276bd547bSAdrian Chadd                 /* interpolate with round off */
66376bd547bSAdrian Chadd                 bf = (2 * (hy - ly) * (x - lx)) / (hx - lx);
66476bd547bSAdrian Chadd                 plus = (bf % 2);
66576bd547bSAdrian Chadd                 factor = bf / 2;
66676bd547bSAdrian Chadd                 y = ly + factor + plus;
66776bd547bSAdrian Chadd             }
66876bd547bSAdrian Chadd         } else {
66976bd547bSAdrian Chadd             /* only low is good, use it */
67076bd547bSAdrian Chadd             y = ly;
67176bd547bSAdrian Chadd         }
67276bd547bSAdrian Chadd     } else if (hhave) {
67376bd547bSAdrian Chadd         /* only high is good, use it */
67476bd547bSAdrian Chadd         y = hy;
67576bd547bSAdrian Chadd     } else {
67676bd547bSAdrian Chadd         /* nothing is good,this should never happen unless np=0, ????  */
67776bd547bSAdrian Chadd         y = -(1 << 30);
67876bd547bSAdrian Chadd     }
67976bd547bSAdrian Chadd 
68076bd547bSAdrian Chadd     return y;
68176bd547bSAdrian Chadd }
68276bd547bSAdrian Chadd 
68376bd547bSAdrian Chadd u_int8_t
ar9300_eeprom_get_legacy_trgt_pwr(struct ath_hal * ah,u_int16_t rate_index,u_int16_t freq,HAL_BOOL is_2ghz)68476bd547bSAdrian Chadd ar9300_eeprom_get_legacy_trgt_pwr(struct ath_hal *ah, u_int16_t rate_index,
68576bd547bSAdrian Chadd     u_int16_t freq, HAL_BOOL is_2ghz)
68676bd547bSAdrian Chadd {
68776bd547bSAdrian Chadd     u_int16_t            num_piers, i;
68876bd547bSAdrian Chadd     int32_t              target_power_array[OSPREY_NUM_5G_20_TARGET_POWERS];
68976bd547bSAdrian Chadd     int32_t              freq_array[OSPREY_NUM_5G_20_TARGET_POWERS];
69076bd547bSAdrian Chadd     u_int8_t             *p_freq_bin;
69176bd547bSAdrian Chadd     ar9300_eeprom_t      *eep = &AH9300(ah)->ah_eeprom;
69276bd547bSAdrian Chadd     CAL_TARGET_POWER_LEG *p_eeprom_target_pwr;
69376bd547bSAdrian Chadd 
69476bd547bSAdrian Chadd     if (is_2ghz) {
69576bd547bSAdrian Chadd         num_piers = OSPREY_NUM_2G_20_TARGET_POWERS;
69676bd547bSAdrian Chadd         p_eeprom_target_pwr = eep->cal_target_power_2g;
69776bd547bSAdrian Chadd         p_freq_bin = eep->cal_target_freqbin_2g;
69876bd547bSAdrian Chadd     } else {
69976bd547bSAdrian Chadd         num_piers = OSPREY_NUM_5G_20_TARGET_POWERS;
70076bd547bSAdrian Chadd         p_eeprom_target_pwr = eep->cal_target_power_5g;
70176bd547bSAdrian Chadd         p_freq_bin = eep->cal_target_freqbin_5g;
70276bd547bSAdrian Chadd    }
70376bd547bSAdrian Chadd 
70476bd547bSAdrian Chadd     /*
70576bd547bSAdrian Chadd      * create array of channels and targetpower from
70676bd547bSAdrian Chadd      * targetpower piers stored on eeprom
70776bd547bSAdrian Chadd      */
70876bd547bSAdrian Chadd     for (i = 0; i < num_piers; i++) {
70976bd547bSAdrian Chadd         freq_array[i] = FBIN2FREQ(p_freq_bin[i], is_2ghz);
71076bd547bSAdrian Chadd         target_power_array[i] = p_eeprom_target_pwr[i].t_pow2x[rate_index];
71176bd547bSAdrian Chadd     }
71276bd547bSAdrian Chadd 
71376bd547bSAdrian Chadd     /* interpolate to get target power for given frequency */
71476bd547bSAdrian Chadd     return
71576bd547bSAdrian Chadd         ((u_int8_t)interpolate(
71676bd547bSAdrian Chadd             (int32_t)freq, freq_array, target_power_array, num_piers));
71776bd547bSAdrian Chadd }
71876bd547bSAdrian Chadd 
71976bd547bSAdrian Chadd u_int8_t
ar9300_eeprom_get_ht20_trgt_pwr(struct ath_hal * ah,u_int16_t rate_index,u_int16_t freq,HAL_BOOL is_2ghz)72076bd547bSAdrian Chadd ar9300_eeprom_get_ht20_trgt_pwr(struct ath_hal *ah, u_int16_t rate_index,
72176bd547bSAdrian Chadd     u_int16_t freq, HAL_BOOL is_2ghz)
72276bd547bSAdrian Chadd {
72376bd547bSAdrian Chadd     u_int16_t               num_piers, i;
72476bd547bSAdrian Chadd     int32_t                 target_power_array[OSPREY_NUM_5G_20_TARGET_POWERS];
72576bd547bSAdrian Chadd     int32_t                 freq_array[OSPREY_NUM_5G_20_TARGET_POWERS];
72676bd547bSAdrian Chadd     u_int8_t                *p_freq_bin;
72776bd547bSAdrian Chadd     ar9300_eeprom_t         *eep = &AH9300(ah)->ah_eeprom;
72876bd547bSAdrian Chadd     OSP_CAL_TARGET_POWER_HT *p_eeprom_target_pwr;
72976bd547bSAdrian Chadd 
73076bd547bSAdrian Chadd     if (is_2ghz) {
73176bd547bSAdrian Chadd         num_piers = OSPREY_NUM_2G_20_TARGET_POWERS;
73276bd547bSAdrian Chadd         p_eeprom_target_pwr = eep->cal_target_power_2g_ht20;
73376bd547bSAdrian Chadd         p_freq_bin = eep->cal_target_freqbin_2g_ht20;
73476bd547bSAdrian Chadd     } else {
73576bd547bSAdrian Chadd         num_piers = OSPREY_NUM_5G_20_TARGET_POWERS;
73676bd547bSAdrian Chadd         p_eeprom_target_pwr = eep->cal_target_power_5g_ht20;
73776bd547bSAdrian Chadd         p_freq_bin = eep->cal_target_freqbin_5g_ht20;
73876bd547bSAdrian Chadd     }
73976bd547bSAdrian Chadd 
74076bd547bSAdrian Chadd     /*
74176bd547bSAdrian Chadd      * create array of channels and targetpower from
74276bd547bSAdrian Chadd      * targetpower piers stored on eeprom
74376bd547bSAdrian Chadd      */
74476bd547bSAdrian Chadd     for (i = 0; i < num_piers; i++) {
74576bd547bSAdrian Chadd         freq_array[i] = FBIN2FREQ(p_freq_bin[i], is_2ghz);
74676bd547bSAdrian Chadd         target_power_array[i] = p_eeprom_target_pwr[i].t_pow2x[rate_index];
74776bd547bSAdrian Chadd     }
74876bd547bSAdrian Chadd 
74976bd547bSAdrian Chadd     /* interpolate to get target power for given frequency */
75076bd547bSAdrian Chadd     return
75176bd547bSAdrian Chadd         ((u_int8_t)interpolate(
75276bd547bSAdrian Chadd             (int32_t)freq, freq_array, target_power_array, num_piers));
75376bd547bSAdrian Chadd }
75476bd547bSAdrian Chadd 
75576bd547bSAdrian Chadd u_int8_t
ar9300_eeprom_get_ht40_trgt_pwr(struct ath_hal * ah,u_int16_t rate_index,u_int16_t freq,HAL_BOOL is_2ghz)75676bd547bSAdrian Chadd ar9300_eeprom_get_ht40_trgt_pwr(struct ath_hal *ah, u_int16_t rate_index,
75776bd547bSAdrian Chadd     u_int16_t freq, HAL_BOOL is_2ghz)
75876bd547bSAdrian Chadd {
75976bd547bSAdrian Chadd     u_int16_t               num_piers, i;
76076bd547bSAdrian Chadd     int32_t                 target_power_array[OSPREY_NUM_5G_40_TARGET_POWERS];
76176bd547bSAdrian Chadd     int32_t                 freq_array[OSPREY_NUM_5G_40_TARGET_POWERS];
76276bd547bSAdrian Chadd     u_int8_t                *p_freq_bin;
76376bd547bSAdrian Chadd     ar9300_eeprom_t         *eep = &AH9300(ah)->ah_eeprom;
76476bd547bSAdrian Chadd     OSP_CAL_TARGET_POWER_HT *p_eeprom_target_pwr;
76576bd547bSAdrian Chadd 
76676bd547bSAdrian Chadd     if (is_2ghz) {
76776bd547bSAdrian Chadd         num_piers = OSPREY_NUM_2G_40_TARGET_POWERS;
76876bd547bSAdrian Chadd         p_eeprom_target_pwr = eep->cal_target_power_2g_ht40;
76976bd547bSAdrian Chadd         p_freq_bin = eep->cal_target_freqbin_2g_ht40;
77076bd547bSAdrian Chadd     } else {
77176bd547bSAdrian Chadd         num_piers = OSPREY_NUM_5G_40_TARGET_POWERS;
77276bd547bSAdrian Chadd         p_eeprom_target_pwr = eep->cal_target_power_5g_ht40;
77376bd547bSAdrian Chadd         p_freq_bin = eep->cal_target_freqbin_5g_ht40;
77476bd547bSAdrian Chadd     }
77576bd547bSAdrian Chadd 
77676bd547bSAdrian Chadd     /*
77776bd547bSAdrian Chadd      * create array of channels and targetpower from
77876bd547bSAdrian Chadd      * targetpower piers stored on eeprom
77976bd547bSAdrian Chadd      */
78076bd547bSAdrian Chadd     for (i = 0; i < num_piers; i++) {
78176bd547bSAdrian Chadd         freq_array[i] = FBIN2FREQ(p_freq_bin[i], is_2ghz);
78276bd547bSAdrian Chadd         target_power_array[i] = p_eeprom_target_pwr[i].t_pow2x[rate_index];
78376bd547bSAdrian Chadd     }
78476bd547bSAdrian Chadd 
78576bd547bSAdrian Chadd     /* interpolate to get target power for given frequency */
78676bd547bSAdrian Chadd     return
78776bd547bSAdrian Chadd         ((u_int8_t)interpolate(
78876bd547bSAdrian Chadd             (int32_t)freq, freq_array, target_power_array, num_piers));
78976bd547bSAdrian Chadd }
79076bd547bSAdrian Chadd 
79176bd547bSAdrian Chadd u_int8_t
ar9300_eeprom_get_cck_trgt_pwr(struct ath_hal * ah,u_int16_t rate_index,u_int16_t freq)79276bd547bSAdrian Chadd ar9300_eeprom_get_cck_trgt_pwr(struct ath_hal *ah, u_int16_t rate_index,
79376bd547bSAdrian Chadd     u_int16_t freq)
79476bd547bSAdrian Chadd {
79576bd547bSAdrian Chadd     u_int16_t            num_piers = OSPREY_NUM_2G_CCK_TARGET_POWERS, i;
79676bd547bSAdrian Chadd     int32_t              target_power_array[OSPREY_NUM_2G_CCK_TARGET_POWERS];
79776bd547bSAdrian Chadd     int32_t              freq_array[OSPREY_NUM_2G_CCK_TARGET_POWERS];
79876bd547bSAdrian Chadd     ar9300_eeprom_t      *eep = &AH9300(ah)->ah_eeprom;
79976bd547bSAdrian Chadd     u_int8_t             *p_freq_bin = eep->cal_target_freqbin_cck;
80076bd547bSAdrian Chadd     CAL_TARGET_POWER_LEG *p_eeprom_target_pwr = eep->cal_target_power_cck;
80176bd547bSAdrian Chadd 
80276bd547bSAdrian Chadd     /*
80376bd547bSAdrian Chadd      * create array of channels and targetpower from
80476bd547bSAdrian Chadd      * targetpower piers stored on eeprom
80576bd547bSAdrian Chadd      */
80676bd547bSAdrian Chadd     for (i = 0; i < num_piers; i++) {
80776bd547bSAdrian Chadd         freq_array[i] = FBIN2FREQ(p_freq_bin[i], 1);
80876bd547bSAdrian Chadd         target_power_array[i] = p_eeprom_target_pwr[i].t_pow2x[rate_index];
80976bd547bSAdrian Chadd     }
81076bd547bSAdrian Chadd 
81176bd547bSAdrian Chadd     /* interpolate to get target power for given frequency */
81276bd547bSAdrian Chadd     return
81376bd547bSAdrian Chadd         ((u_int8_t)interpolate(
81476bd547bSAdrian Chadd             (int32_t)freq, freq_array, target_power_array, num_piers));
81576bd547bSAdrian Chadd }
81676bd547bSAdrian Chadd 
81776bd547bSAdrian Chadd /*
81876bd547bSAdrian Chadd  * Set tx power registers to array of values passed in
81976bd547bSAdrian Chadd  */
82076bd547bSAdrian Chadd int
ar9300_transmit_power_reg_write(struct ath_hal * ah,u_int8_t * p_pwr_array)82176bd547bSAdrian Chadd ar9300_transmit_power_reg_write(struct ath_hal *ah, u_int8_t *p_pwr_array)
82276bd547bSAdrian Chadd {
82376bd547bSAdrian Chadd #define POW_SM(_r, _s)     (((_r) & 0x3f) << (_s))
82476bd547bSAdrian Chadd     /* make sure forced gain is not set */
82576bd547bSAdrian Chadd #if 0
82676bd547bSAdrian Chadd     field_write("force_dac_gain", 0);
82776bd547bSAdrian Chadd     OS_REG_WRITE(ah, 0xa3f8, 0);
82876bd547bSAdrian Chadd     field_write("force_tx_gain", 0);
82976bd547bSAdrian Chadd #endif
83076bd547bSAdrian Chadd 
83176bd547bSAdrian Chadd     OS_REG_WRITE(ah, 0xa458, 0);
83276bd547bSAdrian Chadd 
83376bd547bSAdrian Chadd     /* Write the OFDM power per rate set */
83476bd547bSAdrian Chadd     /* 6 (LSB), 9, 12, 18 (MSB) */
83576bd547bSAdrian Chadd     OS_REG_WRITE(ah, 0xa3c0,
83676bd547bSAdrian Chadd         POW_SM(p_pwr_array[ALL_TARGET_LEGACY_6_24], 24)
83776bd547bSAdrian Chadd           | POW_SM(p_pwr_array[ALL_TARGET_LEGACY_6_24], 16)
83876bd547bSAdrian Chadd           | POW_SM(p_pwr_array[ALL_TARGET_LEGACY_6_24],  8)
83976bd547bSAdrian Chadd           | POW_SM(p_pwr_array[ALL_TARGET_LEGACY_6_24],  0)
84076bd547bSAdrian Chadd     );
84176bd547bSAdrian Chadd     /* 24 (LSB), 36, 48, 54 (MSB) */
84276bd547bSAdrian Chadd     OS_REG_WRITE(ah, 0xa3c4,
84376bd547bSAdrian Chadd         POW_SM(p_pwr_array[ALL_TARGET_LEGACY_54], 24)
84476bd547bSAdrian Chadd           | POW_SM(p_pwr_array[ALL_TARGET_LEGACY_48], 16)
84576bd547bSAdrian Chadd           | POW_SM(p_pwr_array[ALL_TARGET_LEGACY_36],  8)
84676bd547bSAdrian Chadd           | POW_SM(p_pwr_array[ALL_TARGET_LEGACY_6_24],  0)
84776bd547bSAdrian Chadd     );
84876bd547bSAdrian Chadd 
84976bd547bSAdrian Chadd     /* Write the CCK power per rate set */
85076bd547bSAdrian Chadd     /* 1L (LSB), reserved, 2L, 2S (MSB) */
85176bd547bSAdrian Chadd     OS_REG_WRITE(ah, 0xa3c8,
85276bd547bSAdrian Chadd         POW_SM(p_pwr_array[ALL_TARGET_LEGACY_1L_5L], 24)
85376bd547bSAdrian Chadd           | POW_SM(p_pwr_array[ALL_TARGET_LEGACY_1L_5L],  16)
85476bd547bSAdrian Chadd /*          | POW_SM(tx_power_times2,  8)*/ /* this is reserved for Osprey */
85576bd547bSAdrian Chadd           | POW_SM(p_pwr_array[ALL_TARGET_LEGACY_1L_5L],   0)
85676bd547bSAdrian Chadd     );
85776bd547bSAdrian Chadd     /* 5.5L (LSB), 5.5S, 11L, 11S (MSB) */
85876bd547bSAdrian Chadd     OS_REG_WRITE(ah, 0xa3cc,
85976bd547bSAdrian Chadd         POW_SM(p_pwr_array[ALL_TARGET_LEGACY_11S], 24)
86076bd547bSAdrian Chadd           | POW_SM(p_pwr_array[ALL_TARGET_LEGACY_11L], 16)
86176bd547bSAdrian Chadd           | POW_SM(p_pwr_array[ALL_TARGET_LEGACY_5S],  8)
86276bd547bSAdrian Chadd           | POW_SM(p_pwr_array[ALL_TARGET_LEGACY_1L_5L],  0)
86376bd547bSAdrian Chadd     );
86476bd547bSAdrian Chadd 
86576bd547bSAdrian Chadd 	/* write the power for duplicated frames - HT40 */
86676bd547bSAdrian Chadd 	/* dup40_cck (LSB), dup40_ofdm, ext20_cck, ext20_ofdm  (MSB) */
86776bd547bSAdrian Chadd     OS_REG_WRITE(ah, 0xa3e0,
86876bd547bSAdrian Chadd         POW_SM(p_pwr_array[ALL_TARGET_LEGACY_6_24], 24)
86976bd547bSAdrian Chadd           | POW_SM(p_pwr_array[ALL_TARGET_LEGACY_1L_5L], 16)
87076bd547bSAdrian Chadd           | POW_SM(p_pwr_array[ALL_TARGET_LEGACY_6_24],  8)
87176bd547bSAdrian Chadd           | POW_SM(p_pwr_array[ALL_TARGET_LEGACY_1L_5L],  0)
87276bd547bSAdrian Chadd     );
87376bd547bSAdrian Chadd 
87476bd547bSAdrian Chadd     /* Write the HT20 power per rate set */
87576bd547bSAdrian Chadd     /* 0/8/16 (LSB), 1-3/9-11/17-19, 4, 5 (MSB) */
87676bd547bSAdrian Chadd     OS_REG_WRITE(ah, 0xa3d0,
87776bd547bSAdrian Chadd         POW_SM(p_pwr_array[ALL_TARGET_HT20_5], 24)
87876bd547bSAdrian Chadd           | POW_SM(p_pwr_array[ALL_TARGET_HT20_4],  16)
87976bd547bSAdrian Chadd           | POW_SM(p_pwr_array[ALL_TARGET_HT20_1_3_9_11_17_19],  8)
88076bd547bSAdrian Chadd           | POW_SM(p_pwr_array[ALL_TARGET_HT20_0_8_16],   0)
88176bd547bSAdrian Chadd     );
88276bd547bSAdrian Chadd 
88376bd547bSAdrian Chadd     /* 6 (LSB), 7, 12, 13 (MSB) */
88476bd547bSAdrian Chadd     OS_REG_WRITE(ah, 0xa3d4,
88576bd547bSAdrian Chadd         POW_SM(p_pwr_array[ALL_TARGET_HT20_13], 24)
88676bd547bSAdrian Chadd           | POW_SM(p_pwr_array[ALL_TARGET_HT20_12],  16)
88776bd547bSAdrian Chadd           | POW_SM(p_pwr_array[ALL_TARGET_HT20_7],  8)
88876bd547bSAdrian Chadd           | POW_SM(p_pwr_array[ALL_TARGET_HT20_6],   0)
88976bd547bSAdrian Chadd     );
89076bd547bSAdrian Chadd 
89176bd547bSAdrian Chadd     /* 14 (LSB), 15, 20, 21 */
89276bd547bSAdrian Chadd     OS_REG_WRITE(ah, 0xa3e4,
89376bd547bSAdrian Chadd         POW_SM(p_pwr_array[ALL_TARGET_HT20_21], 24)
89476bd547bSAdrian Chadd           | POW_SM(p_pwr_array[ALL_TARGET_HT20_20],  16)
89576bd547bSAdrian Chadd           | POW_SM(p_pwr_array[ALL_TARGET_HT20_15],  8)
89676bd547bSAdrian Chadd           | POW_SM(p_pwr_array[ALL_TARGET_HT20_14],   0)
89776bd547bSAdrian Chadd     );
89876bd547bSAdrian Chadd 
89976bd547bSAdrian Chadd     /* Mixed HT20 and HT40 rates */
90076bd547bSAdrian Chadd     /* HT20 22 (LSB), HT20 23, HT40 22, HT40 23 (MSB) */
90176bd547bSAdrian Chadd     OS_REG_WRITE(ah, 0xa3e8,
90276bd547bSAdrian Chadd         POW_SM(p_pwr_array[ALL_TARGET_HT40_23], 24)
90376bd547bSAdrian Chadd           | POW_SM(p_pwr_array[ALL_TARGET_HT40_22],  16)
90476bd547bSAdrian Chadd           | POW_SM(p_pwr_array[ALL_TARGET_HT20_23],  8)
90576bd547bSAdrian Chadd           | POW_SM(p_pwr_array[ALL_TARGET_HT20_22],   0)
90676bd547bSAdrian Chadd     );
90776bd547bSAdrian Chadd 
90876bd547bSAdrian Chadd     /* Write the HT40 power per rate set */
90976bd547bSAdrian Chadd     /* correct PAR difference between HT40 and HT20/LEGACY */
91076bd547bSAdrian Chadd     /* 0/8/16 (LSB), 1-3/9-11/17-19, 4, 5 (MSB) */
91176bd547bSAdrian Chadd     OS_REG_WRITE(ah, 0xa3d8,
91276bd547bSAdrian Chadd         POW_SM(p_pwr_array[ALL_TARGET_HT40_5], 24)
91376bd547bSAdrian Chadd           | POW_SM(p_pwr_array[ALL_TARGET_HT40_4],  16)
91476bd547bSAdrian Chadd           | POW_SM(p_pwr_array[ALL_TARGET_HT40_1_3_9_11_17_19],  8)
91576bd547bSAdrian Chadd           | POW_SM(p_pwr_array[ALL_TARGET_HT40_0_8_16],   0)
91676bd547bSAdrian Chadd     );
91776bd547bSAdrian Chadd 
91876bd547bSAdrian Chadd     /* 6 (LSB), 7, 12, 13 (MSB) */
91976bd547bSAdrian Chadd     OS_REG_WRITE(ah, 0xa3dc,
92076bd547bSAdrian Chadd         POW_SM(p_pwr_array[ALL_TARGET_HT40_13], 24)
92176bd547bSAdrian Chadd           | POW_SM(p_pwr_array[ALL_TARGET_HT40_12],  16)
92276bd547bSAdrian Chadd           | POW_SM(p_pwr_array[ALL_TARGET_HT40_7], 8)
92376bd547bSAdrian Chadd           | POW_SM(p_pwr_array[ALL_TARGET_HT40_6], 0)
92476bd547bSAdrian Chadd     );
92576bd547bSAdrian Chadd 
92676bd547bSAdrian Chadd     /* 14 (LSB), 15, 20, 21 */
92776bd547bSAdrian Chadd     OS_REG_WRITE(ah, 0xa3ec,
92876bd547bSAdrian Chadd         POW_SM(p_pwr_array[ALL_TARGET_HT40_21], 24)
92976bd547bSAdrian Chadd           | POW_SM(p_pwr_array[ALL_TARGET_HT40_20],  16)
93076bd547bSAdrian Chadd           | POW_SM(p_pwr_array[ALL_TARGET_HT40_15],  8)
93176bd547bSAdrian Chadd           | POW_SM(p_pwr_array[ALL_TARGET_HT40_14],   0)
93276bd547bSAdrian Chadd     );
93376bd547bSAdrian Chadd 
93476bd547bSAdrian Chadd     return 0;
93576bd547bSAdrian Chadd #undef POW_SM
93676bd547bSAdrian Chadd }
93776bd547bSAdrian Chadd 
93876bd547bSAdrian Chadd static void
ar9300_selfgen_tpc_reg_write(struct ath_hal * ah,const struct ieee80211_channel * chan,u_int8_t * p_pwr_array)939e113789bSAdrian Chadd ar9300_selfgen_tpc_reg_write(struct ath_hal *ah, const struct ieee80211_channel *chan,
94076bd547bSAdrian Chadd                              u_int8_t *p_pwr_array)
94176bd547bSAdrian Chadd {
94276bd547bSAdrian Chadd     u_int32_t tpc_reg_val;
94376bd547bSAdrian Chadd 
94476bd547bSAdrian Chadd     /* Set the target power values for self generated frames (ACK,RTS/CTS) to
94576bd547bSAdrian Chadd      * be within limits. This is just a safety measure.With per packet TPC mode
94676bd547bSAdrian Chadd      * enabled the target power value used with self generated frames will be
94776bd547bSAdrian Chadd      * MIN( TPC reg, BB_powertx_rate register)
94876bd547bSAdrian Chadd      */
94976bd547bSAdrian Chadd 
950e113789bSAdrian Chadd     if (IEEE80211_IS_CHAN_2GHZ(chan)) {
95176bd547bSAdrian Chadd         tpc_reg_val = (SM(p_pwr_array[ALL_TARGET_LEGACY_1L_5L], AR_TPC_ACK) |
95276bd547bSAdrian Chadd                        SM(p_pwr_array[ALL_TARGET_LEGACY_1L_5L], AR_TPC_CTS) |
95376bd547bSAdrian Chadd                        SM(0x3f, AR_TPC_CHIRP) |
95476bd547bSAdrian Chadd                        SM(0x3f, AR_TPC_RPT));
95576bd547bSAdrian Chadd     } else {
95676bd547bSAdrian Chadd         tpc_reg_val = (SM(p_pwr_array[ALL_TARGET_LEGACY_6_24], AR_TPC_ACK) |
95776bd547bSAdrian Chadd                        SM(p_pwr_array[ALL_TARGET_LEGACY_6_24], AR_TPC_CTS) |
95876bd547bSAdrian Chadd                        SM(0x3f, AR_TPC_CHIRP) |
95976bd547bSAdrian Chadd                        SM(0x3f, AR_TPC_RPT));
96076bd547bSAdrian Chadd     }
96176bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_TPC, tpc_reg_val);
96276bd547bSAdrian Chadd }
96376bd547bSAdrian Chadd 
96476bd547bSAdrian Chadd void
ar9300_set_target_power_from_eeprom(struct ath_hal * ah,u_int16_t freq,u_int8_t * target_power_val_t2)96576bd547bSAdrian Chadd ar9300_set_target_power_from_eeprom(struct ath_hal *ah, u_int16_t freq,
96676bd547bSAdrian Chadd     u_int8_t *target_power_val_t2)
96776bd547bSAdrian Chadd {
96876bd547bSAdrian Chadd     /* hard code for now, need to get from eeprom struct */
96976bd547bSAdrian Chadd     u_int8_t ht40_power_inc_for_pdadc = 0;
97076bd547bSAdrian Chadd     HAL_BOOL  is_2ghz = 0;
97176bd547bSAdrian Chadd 
97276bd547bSAdrian Chadd     if (freq < 4000) {
97376bd547bSAdrian Chadd         is_2ghz = 1;
97476bd547bSAdrian Chadd     }
97576bd547bSAdrian Chadd 
97676bd547bSAdrian Chadd     target_power_val_t2[ALL_TARGET_LEGACY_6_24] =
97776bd547bSAdrian Chadd         ar9300_eeprom_get_legacy_trgt_pwr(
97876bd547bSAdrian Chadd             ah, LEGACY_TARGET_RATE_6_24, freq, is_2ghz);
97976bd547bSAdrian Chadd     target_power_val_t2[ALL_TARGET_LEGACY_36] =
98076bd547bSAdrian Chadd         ar9300_eeprom_get_legacy_trgt_pwr(
98176bd547bSAdrian Chadd             ah, LEGACY_TARGET_RATE_36, freq, is_2ghz);
98276bd547bSAdrian Chadd     target_power_val_t2[ALL_TARGET_LEGACY_48] =
98376bd547bSAdrian Chadd         ar9300_eeprom_get_legacy_trgt_pwr(
98476bd547bSAdrian Chadd             ah, LEGACY_TARGET_RATE_48, freq, is_2ghz);
98576bd547bSAdrian Chadd     target_power_val_t2[ALL_TARGET_LEGACY_54] =
98676bd547bSAdrian Chadd         ar9300_eeprom_get_legacy_trgt_pwr(
98776bd547bSAdrian Chadd             ah, LEGACY_TARGET_RATE_54, freq, is_2ghz);
98876bd547bSAdrian Chadd     target_power_val_t2[ALL_TARGET_LEGACY_1L_5L] =
98976bd547bSAdrian Chadd         ar9300_eeprom_get_cck_trgt_pwr(
99076bd547bSAdrian Chadd             ah, LEGACY_TARGET_RATE_1L_5L, freq);
99176bd547bSAdrian Chadd     target_power_val_t2[ALL_TARGET_LEGACY_5S] =
99276bd547bSAdrian Chadd         ar9300_eeprom_get_cck_trgt_pwr(
99376bd547bSAdrian Chadd             ah, LEGACY_TARGET_RATE_5S, freq);
99476bd547bSAdrian Chadd     target_power_val_t2[ALL_TARGET_LEGACY_11L] =
99576bd547bSAdrian Chadd         ar9300_eeprom_get_cck_trgt_pwr(
99676bd547bSAdrian Chadd             ah, LEGACY_TARGET_RATE_11L, freq);
99776bd547bSAdrian Chadd     target_power_val_t2[ALL_TARGET_LEGACY_11S] =
99876bd547bSAdrian Chadd         ar9300_eeprom_get_cck_trgt_pwr(
99976bd547bSAdrian Chadd             ah, LEGACY_TARGET_RATE_11S, freq);
100076bd547bSAdrian Chadd     target_power_val_t2[ALL_TARGET_HT20_0_8_16] =
100176bd547bSAdrian Chadd         ar9300_eeprom_get_ht20_trgt_pwr(
100276bd547bSAdrian Chadd             ah, HT_TARGET_RATE_0_8_16, freq, is_2ghz);
100376bd547bSAdrian Chadd     target_power_val_t2[ALL_TARGET_HT20_1_3_9_11_17_19] =
100476bd547bSAdrian Chadd         ar9300_eeprom_get_ht20_trgt_pwr(
100576bd547bSAdrian Chadd             ah, HT_TARGET_RATE_1_3_9_11_17_19, freq, is_2ghz);
100676bd547bSAdrian Chadd     target_power_val_t2[ALL_TARGET_HT20_4] =
100776bd547bSAdrian Chadd         ar9300_eeprom_get_ht20_trgt_pwr(
100876bd547bSAdrian Chadd             ah, HT_TARGET_RATE_4, freq, is_2ghz);
100976bd547bSAdrian Chadd     target_power_val_t2[ALL_TARGET_HT20_5] =
101076bd547bSAdrian Chadd         ar9300_eeprom_get_ht20_trgt_pwr(
101176bd547bSAdrian Chadd             ah, HT_TARGET_RATE_5, freq, is_2ghz);
101276bd547bSAdrian Chadd     target_power_val_t2[ALL_TARGET_HT20_6] =
101376bd547bSAdrian Chadd         ar9300_eeprom_get_ht20_trgt_pwr(
101476bd547bSAdrian Chadd             ah, HT_TARGET_RATE_6, freq, is_2ghz);
101576bd547bSAdrian Chadd     target_power_val_t2[ALL_TARGET_HT20_7] =
101676bd547bSAdrian Chadd         ar9300_eeprom_get_ht20_trgt_pwr(
101776bd547bSAdrian Chadd             ah, HT_TARGET_RATE_7, freq, is_2ghz);
101876bd547bSAdrian Chadd     target_power_val_t2[ALL_TARGET_HT20_12] =
101976bd547bSAdrian Chadd         ar9300_eeprom_get_ht20_trgt_pwr(
102076bd547bSAdrian Chadd             ah, HT_TARGET_RATE_12, freq, is_2ghz);
102176bd547bSAdrian Chadd     target_power_val_t2[ALL_TARGET_HT20_13] =
102276bd547bSAdrian Chadd         ar9300_eeprom_get_ht20_trgt_pwr(
102376bd547bSAdrian Chadd             ah, HT_TARGET_RATE_13, freq, is_2ghz);
102476bd547bSAdrian Chadd     target_power_val_t2[ALL_TARGET_HT20_14] =
102576bd547bSAdrian Chadd         ar9300_eeprom_get_ht20_trgt_pwr(
102676bd547bSAdrian Chadd             ah, HT_TARGET_RATE_14, freq, is_2ghz);
102776bd547bSAdrian Chadd     target_power_val_t2[ALL_TARGET_HT20_15] =
102876bd547bSAdrian Chadd         ar9300_eeprom_get_ht20_trgt_pwr(
102976bd547bSAdrian Chadd             ah, HT_TARGET_RATE_15, freq, is_2ghz);
103076bd547bSAdrian Chadd     target_power_val_t2[ALL_TARGET_HT20_20] =
103176bd547bSAdrian Chadd         ar9300_eeprom_get_ht20_trgt_pwr(
103276bd547bSAdrian Chadd             ah, HT_TARGET_RATE_20, freq, is_2ghz);
103376bd547bSAdrian Chadd     target_power_val_t2[ALL_TARGET_HT20_21] =
103476bd547bSAdrian Chadd         ar9300_eeprom_get_ht20_trgt_pwr(
103576bd547bSAdrian Chadd             ah, HT_TARGET_RATE_21, freq, is_2ghz);
103676bd547bSAdrian Chadd     target_power_val_t2[ALL_TARGET_HT20_22] =
103776bd547bSAdrian Chadd         ar9300_eeprom_get_ht20_trgt_pwr(
103876bd547bSAdrian Chadd             ah, HT_TARGET_RATE_22, freq, is_2ghz);
103976bd547bSAdrian Chadd     target_power_val_t2[ALL_TARGET_HT20_23] =
104076bd547bSAdrian Chadd         ar9300_eeprom_get_ht20_trgt_pwr(
104176bd547bSAdrian Chadd             ah, HT_TARGET_RATE_23, freq, is_2ghz);
104276bd547bSAdrian Chadd     target_power_val_t2[ALL_TARGET_HT40_0_8_16] =
104376bd547bSAdrian Chadd         ar9300_eeprom_get_ht40_trgt_pwr(
104476bd547bSAdrian Chadd             ah, HT_TARGET_RATE_0_8_16, freq, is_2ghz) +
104576bd547bSAdrian Chadd         ht40_power_inc_for_pdadc;
104676bd547bSAdrian Chadd     target_power_val_t2[ALL_TARGET_HT40_1_3_9_11_17_19] =
104776bd547bSAdrian Chadd         ar9300_eeprom_get_ht40_trgt_pwr(
104876bd547bSAdrian Chadd             ah, HT_TARGET_RATE_1_3_9_11_17_19, freq, is_2ghz) +
104976bd547bSAdrian Chadd         ht40_power_inc_for_pdadc;
105076bd547bSAdrian Chadd     target_power_val_t2[ALL_TARGET_HT40_4] =
105176bd547bSAdrian Chadd         ar9300_eeprom_get_ht40_trgt_pwr(
105276bd547bSAdrian Chadd             ah, HT_TARGET_RATE_4, freq, is_2ghz) + ht40_power_inc_for_pdadc;
105376bd547bSAdrian Chadd     target_power_val_t2[ALL_TARGET_HT40_5] =
105476bd547bSAdrian Chadd         ar9300_eeprom_get_ht40_trgt_pwr(
105576bd547bSAdrian Chadd             ah, HT_TARGET_RATE_5, freq, is_2ghz) + ht40_power_inc_for_pdadc;
105676bd547bSAdrian Chadd     target_power_val_t2[ALL_TARGET_HT40_6] =
105776bd547bSAdrian Chadd         ar9300_eeprom_get_ht40_trgt_pwr(
105876bd547bSAdrian Chadd             ah, HT_TARGET_RATE_6, freq, is_2ghz) + ht40_power_inc_for_pdadc;
105976bd547bSAdrian Chadd     target_power_val_t2[ALL_TARGET_HT40_7] =
106076bd547bSAdrian Chadd         ar9300_eeprom_get_ht40_trgt_pwr(
106176bd547bSAdrian Chadd             ah, HT_TARGET_RATE_7, freq, is_2ghz) + ht40_power_inc_for_pdadc;
106276bd547bSAdrian Chadd     target_power_val_t2[ALL_TARGET_HT40_12] =
106376bd547bSAdrian Chadd         ar9300_eeprom_get_ht40_trgt_pwr(
106476bd547bSAdrian Chadd             ah, HT_TARGET_RATE_12, freq, is_2ghz) + ht40_power_inc_for_pdadc;
106576bd547bSAdrian Chadd     target_power_val_t2[ALL_TARGET_HT40_13] =
106676bd547bSAdrian Chadd         ar9300_eeprom_get_ht40_trgt_pwr(
106776bd547bSAdrian Chadd             ah, HT_TARGET_RATE_13, freq, is_2ghz) + ht40_power_inc_for_pdadc;
106876bd547bSAdrian Chadd     target_power_val_t2[ALL_TARGET_HT40_14] =
106976bd547bSAdrian Chadd         ar9300_eeprom_get_ht40_trgt_pwr(
107076bd547bSAdrian Chadd             ah, HT_TARGET_RATE_14, freq, is_2ghz) + ht40_power_inc_for_pdadc;
107176bd547bSAdrian Chadd     target_power_val_t2[ALL_TARGET_HT40_15] =
107276bd547bSAdrian Chadd         ar9300_eeprom_get_ht40_trgt_pwr(
107376bd547bSAdrian Chadd             ah, HT_TARGET_RATE_15, freq, is_2ghz) + ht40_power_inc_for_pdadc;
107476bd547bSAdrian Chadd     target_power_val_t2[ALL_TARGET_HT40_20] =
107576bd547bSAdrian Chadd         ar9300_eeprom_get_ht40_trgt_pwr(
107676bd547bSAdrian Chadd             ah, HT_TARGET_RATE_20, freq, is_2ghz) + ht40_power_inc_for_pdadc;
107776bd547bSAdrian Chadd     target_power_val_t2[ALL_TARGET_HT40_21] =
107876bd547bSAdrian Chadd         ar9300_eeprom_get_ht40_trgt_pwr(
107976bd547bSAdrian Chadd             ah, HT_TARGET_RATE_21, freq, is_2ghz) + ht40_power_inc_for_pdadc;
108076bd547bSAdrian Chadd     target_power_val_t2[ALL_TARGET_HT40_22] =
108176bd547bSAdrian Chadd         ar9300_eeprom_get_ht40_trgt_pwr(
108276bd547bSAdrian Chadd             ah, HT_TARGET_RATE_22, freq, is_2ghz) + ht40_power_inc_for_pdadc;
108376bd547bSAdrian Chadd     target_power_val_t2[ALL_TARGET_HT40_23] =
108476bd547bSAdrian Chadd         ar9300_eeprom_get_ht40_trgt_pwr(
108576bd547bSAdrian Chadd             ah, HT_TARGET_RATE_23, freq, is_2ghz) + ht40_power_inc_for_pdadc;
108676bd547bSAdrian Chadd 
108776bd547bSAdrian Chadd #ifdef AH_DEBUG
108876bd547bSAdrian Chadd     {
108976bd547bSAdrian Chadd         int  i = 0;
109076bd547bSAdrian Chadd 
109176bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_EEPROM, "%s: APPLYING TARGET POWERS\n", __func__);
109276bd547bSAdrian Chadd         while (i < ar9300_rate_size) {
109376bd547bSAdrian Chadd             HALDEBUG(ah, HAL_DEBUG_EEPROM, "%s: TPC[%02d] 0x%08x ",
109476bd547bSAdrian Chadd                      __func__, i, target_power_val_t2[i]);
109576bd547bSAdrian Chadd             i++;
109676bd547bSAdrian Chadd 			if (i == ar9300_rate_size) {
109776bd547bSAdrian Chadd                 break;
109876bd547bSAdrian Chadd 			}
109976bd547bSAdrian Chadd             HALDEBUG(ah, HAL_DEBUG_EEPROM, "%s: TPC[%02d] 0x%08x ",
110076bd547bSAdrian Chadd                      __func__, i, target_power_val_t2[i]);
110176bd547bSAdrian Chadd             i++;
110276bd547bSAdrian Chadd 			if (i == ar9300_rate_size) {
110376bd547bSAdrian Chadd                 break;
110476bd547bSAdrian Chadd 			}
110576bd547bSAdrian Chadd             HALDEBUG(ah, HAL_DEBUG_EEPROM, "%s: TPC[%02d] 0x%08x ",
110676bd547bSAdrian Chadd                      __func__, i, target_power_val_t2[i]);
110776bd547bSAdrian Chadd             i++;
110876bd547bSAdrian Chadd 			if (i == ar9300_rate_size) {
110976bd547bSAdrian Chadd                 break;
111076bd547bSAdrian Chadd 			}
111176bd547bSAdrian Chadd             HALDEBUG(ah, HAL_DEBUG_EEPROM, "%s: TPC[%02d] 0x%08x \n",
111276bd547bSAdrian Chadd                      __func__, i, target_power_val_t2[i]);
111376bd547bSAdrian Chadd             i++;
111476bd547bSAdrian Chadd         }
111576bd547bSAdrian Chadd     }
111676bd547bSAdrian Chadd #endif
111776bd547bSAdrian Chadd }
111876bd547bSAdrian Chadd 
ar9300_regulatory_domain_get(struct ath_hal * ah)111976bd547bSAdrian Chadd u_int16_t *ar9300_regulatory_domain_get(struct ath_hal *ah)
112076bd547bSAdrian Chadd {
112176bd547bSAdrian Chadd     ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom;
112276bd547bSAdrian Chadd     return eep->base_eep_header.reg_dmn;
112376bd547bSAdrian Chadd }
112476bd547bSAdrian Chadd 
112576bd547bSAdrian Chadd 
112676bd547bSAdrian Chadd int32_t
ar9300_eeprom_write_enable_gpio_get(struct ath_hal * ah)112776bd547bSAdrian Chadd ar9300_eeprom_write_enable_gpio_get(struct ath_hal *ah)
112876bd547bSAdrian Chadd {
112976bd547bSAdrian Chadd     ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom;
113076bd547bSAdrian Chadd     return eep->base_eep_header.eeprom_write_enable_gpio;
113176bd547bSAdrian Chadd }
113276bd547bSAdrian Chadd 
113376bd547bSAdrian Chadd int32_t
ar9300_wlan_disable_gpio_get(struct ath_hal * ah)113476bd547bSAdrian Chadd ar9300_wlan_disable_gpio_get(struct ath_hal *ah)
113576bd547bSAdrian Chadd {
113676bd547bSAdrian Chadd     ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom;
113776bd547bSAdrian Chadd     return eep->base_eep_header.wlan_disable_gpio;
113876bd547bSAdrian Chadd }
113976bd547bSAdrian Chadd 
114076bd547bSAdrian Chadd int32_t
ar9300_wlan_led_gpio_get(struct ath_hal * ah)114176bd547bSAdrian Chadd ar9300_wlan_led_gpio_get(struct ath_hal *ah)
114276bd547bSAdrian Chadd {
114376bd547bSAdrian Chadd     ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom;
114476bd547bSAdrian Chadd     return eep->base_eep_header.wlan_led_gpio;
114576bd547bSAdrian Chadd }
114676bd547bSAdrian Chadd 
114776bd547bSAdrian Chadd int32_t
ar9300_rx_band_select_gpio_get(struct ath_hal * ah)114876bd547bSAdrian Chadd ar9300_rx_band_select_gpio_get(struct ath_hal *ah)
114976bd547bSAdrian Chadd {
115076bd547bSAdrian Chadd     ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom;
115176bd547bSAdrian Chadd     return eep->base_eep_header.rx_band_select_gpio;
115276bd547bSAdrian Chadd }
115376bd547bSAdrian Chadd 
115476bd547bSAdrian Chadd /*
115576bd547bSAdrian Chadd  * since valid noise floor values are negative, returns 1 on error
115676bd547bSAdrian Chadd  */
115776bd547bSAdrian Chadd int32_t
ar9300_noise_floor_cal_or_power_get(struct ath_hal * ah,int32_t frequency,int32_t ichain,HAL_BOOL use_cal)115876bd547bSAdrian Chadd ar9300_noise_floor_cal_or_power_get(struct ath_hal *ah, int32_t frequency,
115976bd547bSAdrian Chadd     int32_t ichain, HAL_BOOL use_cal)
116076bd547bSAdrian Chadd {
116176bd547bSAdrian Chadd     int     nf_use = 1; /* start with an error return value */
116276bd547bSAdrian Chadd     int32_t fx[OSPREY_NUM_5G_CAL_PIERS + OSPREY_NUM_2G_CAL_PIERS];
116376bd547bSAdrian Chadd     int32_t nf[OSPREY_NUM_5G_CAL_PIERS + OSPREY_NUM_2G_CAL_PIERS];
116476bd547bSAdrian Chadd     int     nnf;
116576bd547bSAdrian Chadd     int     is_2ghz;
116676bd547bSAdrian Chadd     int     ipier, npier;
116776bd547bSAdrian Chadd     ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom;
116876bd547bSAdrian Chadd     u_int8_t        *p_cal_pier;
116976bd547bSAdrian Chadd     OSP_CAL_DATA_PER_FREQ_OP_LOOP *p_cal_pier_struct;
117076bd547bSAdrian Chadd 
117176bd547bSAdrian Chadd     /*
117276bd547bSAdrian Chadd      * check chain value
117376bd547bSAdrian Chadd      */
117476bd547bSAdrian Chadd     if (ichain < 0 || ichain >= OSPREY_MAX_CHAINS) {
117576bd547bSAdrian Chadd         return 1;
117676bd547bSAdrian Chadd     }
117776bd547bSAdrian Chadd 
117876bd547bSAdrian Chadd     /* figure out which band we're using */
117976bd547bSAdrian Chadd     is_2ghz = (frequency < 4000);
118076bd547bSAdrian Chadd     if (is_2ghz) {
118176bd547bSAdrian Chadd         npier = OSPREY_NUM_2G_CAL_PIERS;
118276bd547bSAdrian Chadd         p_cal_pier = eep->cal_freq_pier_2g;
118376bd547bSAdrian Chadd         p_cal_pier_struct = eep->cal_pier_data_2g[ichain];
118476bd547bSAdrian Chadd     } else {
118576bd547bSAdrian Chadd         npier = OSPREY_NUM_5G_CAL_PIERS;
118676bd547bSAdrian Chadd         p_cal_pier = eep->cal_freq_pier_5g;
118776bd547bSAdrian Chadd         p_cal_pier_struct = eep->cal_pier_data_5g[ichain];
118876bd547bSAdrian Chadd     }
118976bd547bSAdrian Chadd     /* look for valid noise floor values */
119076bd547bSAdrian Chadd     nnf = 0;
119176bd547bSAdrian Chadd     for (ipier = 0; ipier < npier; ipier++) {
119276bd547bSAdrian Chadd         fx[nnf] = FBIN2FREQ(p_cal_pier[ipier], is_2ghz);
119376bd547bSAdrian Chadd         nf[nnf] = use_cal ?
119476bd547bSAdrian Chadd             p_cal_pier_struct[ipier].rx_noisefloor_cal :
119576bd547bSAdrian Chadd             p_cal_pier_struct[ipier].rx_noisefloor_power;
119676bd547bSAdrian Chadd         if (nf[nnf] < 0) {
119776bd547bSAdrian Chadd             nnf++;
119876bd547bSAdrian Chadd         }
119976bd547bSAdrian Chadd     }
120076bd547bSAdrian Chadd     /*
120176bd547bSAdrian Chadd      * If we have some valid values, interpolate to find the value
120276bd547bSAdrian Chadd      * at the desired frequency.
120376bd547bSAdrian Chadd      */
120476bd547bSAdrian Chadd     if (nnf > 0) {
120576bd547bSAdrian Chadd         nf_use = interpolate(frequency, fx, nf, nnf);
120676bd547bSAdrian Chadd     }
120776bd547bSAdrian Chadd 
120876bd547bSAdrian Chadd     return nf_use;
120976bd547bSAdrian Chadd }
121076bd547bSAdrian Chadd 
1211899d1cacSAdrian Chadd /*
1212899d1cacSAdrian Chadd  * Return the Rx NF offset for specific channel.
1213899d1cacSAdrian Chadd  * The values saved in EEPROM/OTP/Flash is converted through the following way:
1214899d1cacSAdrian Chadd  *     ((_p) - NOISE_PWR_DATA_OFFSET) << 2
1215899d1cacSAdrian Chadd  * So we need to convert back to the original values.
1216899d1cacSAdrian Chadd  */
ar9300_get_rx_nf_offset(struct ath_hal * ah,struct ieee80211_channel * chan,int8_t * nf_pwr,int8_t * nf_cal)1217899d1cacSAdrian Chadd int ar9300_get_rx_nf_offset(struct ath_hal *ah, struct ieee80211_channel *chan, int8_t *nf_pwr, int8_t *nf_cal) {
1218899d1cacSAdrian Chadd     HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan);
1219899d1cacSAdrian Chadd     int8_t rx_nf_pwr, rx_nf_cal;
1220899d1cacSAdrian Chadd     int i;
1221899d1cacSAdrian Chadd     //HALASSERT(ichan);
1222899d1cacSAdrian Chadd 
1223899d1cacSAdrian Chadd     /* Fill 0 if valid internal channel is not found */
1224899d1cacSAdrian Chadd     if (ichan == AH_NULL) {
1225899d1cacSAdrian Chadd         OS_MEMZERO(nf_pwr, sizeof(nf_pwr[0])*OSPREY_MAX_CHAINS);
1226899d1cacSAdrian Chadd         OS_MEMZERO(nf_cal, sizeof(nf_cal[0])*OSPREY_MAX_CHAINS);
1227899d1cacSAdrian Chadd         return -1;
1228899d1cacSAdrian Chadd     }
1229899d1cacSAdrian Chadd 
1230899d1cacSAdrian Chadd     for (i = 0; i < OSPREY_MAX_CHAINS; i++) {
1231899d1cacSAdrian Chadd 	    if ((rx_nf_pwr = ar9300_noise_floor_cal_or_power_get(ah, ichan->channel, i, 0)) == 1) {
1232899d1cacSAdrian Chadd 	        nf_pwr[i] = 0;
1233899d1cacSAdrian Chadd 	    } else {
1234899d1cacSAdrian Chadd 	        //printk("%s: raw nf_pwr[%d] = %d\n", __func__, i, rx_nf_pwr);
1235899d1cacSAdrian Chadd             nf_pwr[i] = NOISE_PWR_DBM_2_INT(rx_nf_pwr);
1236899d1cacSAdrian Chadd 	    }
1237899d1cacSAdrian Chadd 
1238899d1cacSAdrian Chadd 	    if ((rx_nf_cal = ar9300_noise_floor_cal_or_power_get(ah, ichan->channel, i, 1)) == 1) {
1239899d1cacSAdrian Chadd 	        nf_cal[i] = 0;
1240899d1cacSAdrian Chadd 	    } else {
1241899d1cacSAdrian Chadd 	        //printk("%s: raw nf_cal[%d] = %d\n", __func__, i, rx_nf_cal);
1242899d1cacSAdrian Chadd             nf_cal[i] = NOISE_PWR_DBM_2_INT(rx_nf_cal);
1243899d1cacSAdrian Chadd 	    }
1244899d1cacSAdrian Chadd     }
1245899d1cacSAdrian Chadd 
1246899d1cacSAdrian Chadd     return 0;
1247899d1cacSAdrian Chadd }
1248899d1cacSAdrian Chadd 
ar9300_rx_gain_index_get(struct ath_hal * ah)124976bd547bSAdrian Chadd int32_t ar9300_rx_gain_index_get(struct ath_hal *ah)
125076bd547bSAdrian Chadd {
125176bd547bSAdrian Chadd     ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom;
125276bd547bSAdrian Chadd 
125376bd547bSAdrian Chadd     return (eep->base_eep_header.txrxgain) & 0xf;        /* bits 3:0 */
125476bd547bSAdrian Chadd }
125576bd547bSAdrian Chadd 
125676bd547bSAdrian Chadd 
ar9300_tx_gain_index_get(struct ath_hal * ah)125776bd547bSAdrian Chadd int32_t ar9300_tx_gain_index_get(struct ath_hal *ah)
125876bd547bSAdrian Chadd {
125976bd547bSAdrian Chadd     ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom;
126076bd547bSAdrian Chadd 
126176bd547bSAdrian Chadd     return (eep->base_eep_header.txrxgain >> 4) & 0xf;    /* bits 7:4 */
126276bd547bSAdrian Chadd }
126376bd547bSAdrian Chadd 
ar9300_internal_regulator_apply(struct ath_hal * ah)126476bd547bSAdrian Chadd HAL_BOOL ar9300_internal_regulator_apply(struct ath_hal *ah)
126576bd547bSAdrian Chadd {
126676bd547bSAdrian Chadd     struct ath_hal_9300 *ahp = AH9300(ah);
126776bd547bSAdrian Chadd     int internal_regulator = ar9300_eeprom_get(ahp, EEP_INTERNAL_REGULATOR);
126876bd547bSAdrian Chadd     int reg_pmu1, reg_pmu2, reg_pmu1_set, reg_pmu2_set;
126976bd547bSAdrian Chadd     u_int32_t reg_PMU1, reg_PMU2;
127076bd547bSAdrian Chadd     unsigned long eep_addr;
127176bd547bSAdrian Chadd     u_int32_t reg_val, reg_usb = 0, reg_pmu = 0;
127276bd547bSAdrian Chadd     int usb_valid = 0, pmu_valid = 0;
127376bd547bSAdrian Chadd     unsigned char pmu_refv;
127476bd547bSAdrian Chadd 
127576bd547bSAdrian Chadd     if (AR_SREV_JUPITER(ah) || AR_SREV_APHRODITE(ah)) {
127676bd547bSAdrian Chadd         reg_PMU1 = AR_PHY_PMU1_JUPITER;
127776bd547bSAdrian Chadd         reg_PMU2 = AR_PHY_PMU2_JUPITER;
127876bd547bSAdrian Chadd     }
127976bd547bSAdrian Chadd     else {
128076bd547bSAdrian Chadd         reg_PMU1 = AR_PHY_PMU1;
128176bd547bSAdrian Chadd         reg_PMU2 = AR_PHY_PMU2;
128276bd547bSAdrian Chadd     }
128376bd547bSAdrian Chadd 
128476bd547bSAdrian Chadd     if (internal_regulator) {
128576bd547bSAdrian Chadd         if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah)) {
128676bd547bSAdrian Chadd             if (AR_SREV_HORNET(ah)) {
128776bd547bSAdrian Chadd                 /* Read OTP first */
128876bd547bSAdrian Chadd                 for (eep_addr = 0x14; ; eep_addr -= 0x10) {
128976bd547bSAdrian Chadd 
129076bd547bSAdrian Chadd                     ar9300_otp_read(ah, eep_addr / 4, &reg_val, 1);
129176bd547bSAdrian Chadd 
129276bd547bSAdrian Chadd                     if ((reg_val & 0x80) == 0x80){
129376bd547bSAdrian Chadd                         usb_valid = 1;
129476bd547bSAdrian Chadd                         reg_usb = reg_val & 0x000000ff;
129576bd547bSAdrian Chadd                     }
129676bd547bSAdrian Chadd 
129776bd547bSAdrian Chadd                     if ((reg_val & 0x80000000) == 0x80000000){
129876bd547bSAdrian Chadd                         pmu_valid = 1;
129976bd547bSAdrian Chadd                         reg_pmu = (reg_val & 0xff000000) >> 24;
130076bd547bSAdrian Chadd                     }
130176bd547bSAdrian Chadd 
130276bd547bSAdrian Chadd                     if (eep_addr == 0x4) {
130376bd547bSAdrian Chadd                         break;
130476bd547bSAdrian Chadd                     }
130576bd547bSAdrian Chadd                 }
130676bd547bSAdrian Chadd 
130776bd547bSAdrian Chadd                 if (pmu_valid) {
130876bd547bSAdrian Chadd                     pmu_refv = reg_pmu & 0xf;
130976bd547bSAdrian Chadd                 } else {
131076bd547bSAdrian Chadd                     pmu_refv = 0x8;
131176bd547bSAdrian Chadd                 }
131276bd547bSAdrian Chadd 
131376bd547bSAdrian Chadd                 /*
131476bd547bSAdrian Chadd                  * If (valid) {
131576bd547bSAdrian Chadd                  *   Usb_phy_ctrl2_tx_cal_en -> 0
131676bd547bSAdrian Chadd                  *   Usb_phy_ctrl2_tx_cal_sel -> 0
131776bd547bSAdrian Chadd                  *   Usb_phy_ctrl2_tx_man_cal -> 0, 1, 3, 7 or 15 from OTP
131876bd547bSAdrian Chadd                  * }
131976bd547bSAdrian Chadd                  */
132076bd547bSAdrian Chadd                 if (usb_valid) {
132176bd547bSAdrian Chadd                     OS_REG_RMW_FIELD(ah, 0x16c88, AR_PHY_CTRL2_TX_CAL_EN, 0x0);
132276bd547bSAdrian Chadd                     OS_REG_RMW_FIELD(ah, 0x16c88, AR_PHY_CTRL2_TX_CAL_SEL, 0x0);
132376bd547bSAdrian Chadd                     OS_REG_RMW_FIELD(ah, 0x16c88,
132476bd547bSAdrian Chadd                         AR_PHY_CTRL2_TX_MAN_CAL, (reg_usb & 0xf));
132576bd547bSAdrian Chadd                 }
132676bd547bSAdrian Chadd 
132776bd547bSAdrian Chadd             } else {
132876bd547bSAdrian Chadd                 pmu_refv = 0x8;
132976bd547bSAdrian Chadd             }
133076bd547bSAdrian Chadd             /*#ifndef USE_HIF*/
133176bd547bSAdrian Chadd             /* Follow the MDK settings for Hornet PMU.
133276bd547bSAdrian Chadd              * my $pwd               = 0x0;
133376bd547bSAdrian Chadd              * my $Nfdiv             = 0x3;  # xtal_freq = 25MHz
133476bd547bSAdrian Chadd              * my $Nfdiv             = 0x4;  # xtal_freq = 40MHz
133576bd547bSAdrian Chadd              * my $Refv              = 0x7;  # 0x5:1.22V; 0x8:1.29V
133676bd547bSAdrian Chadd              * my $Gm1               = 0x3;  #Poseidon $Gm1=1
133776bd547bSAdrian Chadd              * my $classb            = 0x0;
133876bd547bSAdrian Chadd              * my $Cc                = 0x1;  #Poseidon $Cc=7
133976bd547bSAdrian Chadd              * my $Rc                = 0x6;
134076bd547bSAdrian Chadd              * my $ramp_slope        = 0x1;
134176bd547bSAdrian Chadd              * my $Segm              = 0x3;
134276bd547bSAdrian Chadd              * my $use_local_osc     = 0x0;
134376bd547bSAdrian Chadd              * my $force_xosc_stable = 0x0;
134476bd547bSAdrian Chadd              * my $Selfb             = 0x0;  #Poseidon $Selfb=1
134576bd547bSAdrian Chadd              * my $Filterfb          = 0x3;  #Poseidon $Filterfb=0
134676bd547bSAdrian Chadd              * my $Filtervc          = 0x0;
134776bd547bSAdrian Chadd              * my $disc              = 0x0;
134876bd547bSAdrian Chadd              * my $discdel           = 0x4;
134976bd547bSAdrian Chadd              * my $spare             = 0x0;
135076bd547bSAdrian Chadd              * $reg_PMU1 =
135176bd547bSAdrian Chadd              *     $pwd | ($Nfdiv<<1) | ($Refv<<4) | ($Gm1<<8) |
135276bd547bSAdrian Chadd              *     ($classb<<11) | ($Cc<<14) | ($Rc<<17) | ($ramp_slope<<20) |
135376bd547bSAdrian Chadd              *     ($Segm<<24) | ($use_local_osc<<26) |
135476bd547bSAdrian Chadd              *     ($force_xosc_stable<<27) | ($Selfb<<28) | ($Filterfb<<29);
135576bd547bSAdrian Chadd              * $reg_PMU2 = $handle->reg_rd("ch0_PMU2");
135676bd547bSAdrian Chadd              * $reg_PMU2 = ($reg_PMU2 & 0xfe3fffff) | ($Filtervc<<22);
135776bd547bSAdrian Chadd              * $reg_PMU2 = ($reg_PMU2 & 0xe3ffffff) | ($discdel<<26);
135876bd547bSAdrian Chadd              * $reg_PMU2 = ($reg_PMU2 & 0x1fffffff) | ($spare<<29);
135976bd547bSAdrian Chadd              */
136076bd547bSAdrian Chadd             if (ahp->clk_25mhz) {
136176bd547bSAdrian Chadd                 reg_pmu1_set = 0 |
136276bd547bSAdrian Chadd                     (3 <<  1) | (pmu_refv << 4) | (3 <<  8) | (0 << 11) |
136376bd547bSAdrian Chadd                     (1 << 14) | (6 << 17) | (1 << 20) | (3 << 24) |
136476bd547bSAdrian Chadd                     (0 << 26) | (0 << 27) | (0 << 28) | (0 << 29);
136576bd547bSAdrian Chadd             } else {
136676bd547bSAdrian Chadd                 if (AR_SREV_POSEIDON(ah)) {
136776bd547bSAdrian Chadd                     reg_pmu1_set = 0 |
136876bd547bSAdrian Chadd                         (5 <<  1) | (7 <<  4) | (2 <<  8) | (0 << 11) |
136976bd547bSAdrian Chadd                         (2 << 14) | (6 << 17) | (1 << 20) | (3 << 24) |
137076bd547bSAdrian Chadd                         (0 << 26) | (0 << 27) | (1 << 28) | (0 << 29) ;
137176bd547bSAdrian Chadd                 } else {
137276bd547bSAdrian Chadd                     reg_pmu1_set = 0 |
137376bd547bSAdrian Chadd                         (4 <<  1) | (7 <<  4) | (3 <<  8) | (0 << 11) |
137476bd547bSAdrian Chadd                         (1 << 14) | (6 << 17) | (1 << 20) | (3 << 24) |
137576bd547bSAdrian Chadd                         (0 << 26) | (0 << 27) | (0 << 28) | (0 << 29) ;
137676bd547bSAdrian Chadd                 }
137776bd547bSAdrian Chadd             }
137876bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah, reg_PMU2, AR_PHY_PMU2_PGM, 0x0);
137976bd547bSAdrian Chadd 
138076bd547bSAdrian Chadd             OS_REG_WRITE(ah, reg_PMU1, reg_pmu1_set);   /* 0x638c8376 */
138176bd547bSAdrian Chadd             reg_pmu1 = OS_REG_READ(ah, reg_PMU1);
138276bd547bSAdrian Chadd             while (reg_pmu1 != reg_pmu1_set) {
138376bd547bSAdrian Chadd                 OS_REG_WRITE(ah, reg_PMU1, reg_pmu1_set);  /* 0x638c8376 */
138476bd547bSAdrian Chadd                 OS_DELAY(10);
138576bd547bSAdrian Chadd                 reg_pmu1 = OS_REG_READ(ah, reg_PMU1);
138676bd547bSAdrian Chadd             }
138776bd547bSAdrian Chadd 
138876bd547bSAdrian Chadd             reg_pmu2_set =
138976bd547bSAdrian Chadd                  (OS_REG_READ(ah, reg_PMU2) & (~0xFFC00000)) | (4 << 26);
139076bd547bSAdrian Chadd             OS_REG_WRITE(ah, reg_PMU2, reg_pmu2_set);
139176bd547bSAdrian Chadd             reg_pmu2 = OS_REG_READ(ah, reg_PMU2);
139276bd547bSAdrian Chadd             while (reg_pmu2 != reg_pmu2_set) {
139376bd547bSAdrian Chadd                 OS_REG_WRITE(ah, reg_PMU2, reg_pmu2_set);
139476bd547bSAdrian Chadd                 OS_DELAY(10);
139576bd547bSAdrian Chadd                 reg_pmu2 = OS_REG_READ(ah, reg_PMU2);
139676bd547bSAdrian Chadd             }
139776bd547bSAdrian Chadd             reg_pmu2_set =
139876bd547bSAdrian Chadd                  (OS_REG_READ(ah, reg_PMU2) & (~0x00200000)) | (1 << 21);
139976bd547bSAdrian Chadd             OS_REG_WRITE(ah, reg_PMU2, reg_pmu2_set);
140076bd547bSAdrian Chadd             reg_pmu2 = OS_REG_READ(ah, reg_PMU2);
140176bd547bSAdrian Chadd             while (reg_pmu2 != reg_pmu2_set) {
140276bd547bSAdrian Chadd                 OS_REG_WRITE(ah, reg_PMU2, reg_pmu2_set);
140376bd547bSAdrian Chadd                 OS_DELAY(10);
140476bd547bSAdrian Chadd                 reg_pmu2 = OS_REG_READ(ah, reg_PMU2);
140576bd547bSAdrian Chadd             }
140676bd547bSAdrian Chadd             /*#endif*/
140776bd547bSAdrian Chadd         } else if (AR_SREV_JUPITER(ah) || AR_SREV_APHRODITE(ah)) {
140876bd547bSAdrian Chadd             /* Internal regulator is ON. Write swreg register. */
140976bd547bSAdrian Chadd             int swreg = ar9300_eeprom_get(ahp, EEP_SWREG);
141076bd547bSAdrian Chadd             OS_REG_WRITE(ah, reg_PMU1, swreg);
141176bd547bSAdrian Chadd         } else {
141276bd547bSAdrian Chadd             /* Internal regulator is ON. Write swreg register. */
141376bd547bSAdrian Chadd             int swreg = ar9300_eeprom_get(ahp, EEP_SWREG);
141476bd547bSAdrian Chadd             OS_REG_WRITE(ah, AR_RTC_REG_CONTROL1,
141576bd547bSAdrian Chadd                          OS_REG_READ(ah, AR_RTC_REG_CONTROL1) &
141676bd547bSAdrian Chadd                          (~AR_RTC_REG_CONTROL1_SWREG_PROGRAM));
141776bd547bSAdrian Chadd             OS_REG_WRITE(ah, AR_RTC_REG_CONTROL0, swreg);
141876bd547bSAdrian Chadd             /* Set REG_CONTROL1.SWREG_PROGRAM */
141976bd547bSAdrian Chadd             OS_REG_WRITE(ah, AR_RTC_REG_CONTROL1,
142076bd547bSAdrian Chadd                 OS_REG_READ(ah, AR_RTC_REG_CONTROL1) |
142176bd547bSAdrian Chadd                 AR_RTC_REG_CONTROL1_SWREG_PROGRAM);
142276bd547bSAdrian Chadd         }
142376bd547bSAdrian Chadd     } else {
142476bd547bSAdrian Chadd         if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah)) {
142576bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah, reg_PMU2, AR_PHY_PMU2_PGM, 0x0);
142676bd547bSAdrian Chadd             reg_pmu2 = OS_REG_READ_FIELD(ah, reg_PMU2, AR_PHY_PMU2_PGM);
142776bd547bSAdrian Chadd             while (reg_pmu2) {
142876bd547bSAdrian Chadd                 OS_DELAY(10);
142976bd547bSAdrian Chadd                 reg_pmu2 = OS_REG_READ_FIELD(ah, reg_PMU2, AR_PHY_PMU2_PGM);
143076bd547bSAdrian Chadd             }
143176bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah, reg_PMU1, AR_PHY_PMU1_PWD, 0x1);
143276bd547bSAdrian Chadd             reg_pmu1 = OS_REG_READ_FIELD(ah, reg_PMU1, AR_PHY_PMU1_PWD);
143376bd547bSAdrian Chadd             while (!reg_pmu1) {
143476bd547bSAdrian Chadd                 OS_DELAY(10);
143576bd547bSAdrian Chadd                 reg_pmu1 = OS_REG_READ_FIELD(ah, reg_PMU1, AR_PHY_PMU1_PWD);
143676bd547bSAdrian Chadd             }
143776bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah, reg_PMU2, AR_PHY_PMU2_PGM, 0x1);
143876bd547bSAdrian Chadd             reg_pmu2 = OS_REG_READ_FIELD(ah, reg_PMU2, AR_PHY_PMU2_PGM);
143976bd547bSAdrian Chadd             while (!reg_pmu2) {
144076bd547bSAdrian Chadd                 OS_DELAY(10);
144176bd547bSAdrian Chadd                 reg_pmu2 = OS_REG_READ_FIELD(ah, reg_PMU2, AR_PHY_PMU2_PGM);
144276bd547bSAdrian Chadd             }
144376bd547bSAdrian Chadd         } else if (AR_SREV_JUPITER(ah) || AR_SREV_APHRODITE(ah)) {
144476bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah, reg_PMU1, AR_PHY_PMU1_PWD, 0x1);
144576bd547bSAdrian Chadd         } else {
144676bd547bSAdrian Chadd             OS_REG_WRITE(ah, AR_RTC_SLEEP_CLK,
144776bd547bSAdrian Chadd                 (OS_REG_READ(ah, AR_RTC_SLEEP_CLK) |
144876bd547bSAdrian Chadd                 AR_RTC_FORCE_SWREG_PRD | AR_RTC_PCIE_RST_PWDN_EN));
144976bd547bSAdrian Chadd         }
145076bd547bSAdrian Chadd     }
145176bd547bSAdrian Chadd 
145276bd547bSAdrian Chadd     return 0;
145376bd547bSAdrian Chadd }
145476bd547bSAdrian Chadd 
ar9300_drive_strength_apply(struct ath_hal * ah)145576bd547bSAdrian Chadd HAL_BOOL ar9300_drive_strength_apply(struct ath_hal *ah)
145676bd547bSAdrian Chadd {
145776bd547bSAdrian Chadd     struct ath_hal_9300 *ahp = AH9300(ah);
145876bd547bSAdrian Chadd     int drive_strength;
145976bd547bSAdrian Chadd     unsigned long reg;
146076bd547bSAdrian Chadd 
146176bd547bSAdrian Chadd     drive_strength = ar9300_eeprom_get(ahp, EEP_DRIVE_STRENGTH);
146276bd547bSAdrian Chadd     if (drive_strength) {
146376bd547bSAdrian Chadd         reg = OS_REG_READ(ah, AR_PHY_65NM_CH0_BIAS1);
146476bd547bSAdrian Chadd         reg &= ~0x00ffffc0;
146576bd547bSAdrian Chadd         reg |= 0x5 << 21;
146676bd547bSAdrian Chadd         reg |= 0x5 << 18;
146776bd547bSAdrian Chadd         reg |= 0x5 << 15;
146876bd547bSAdrian Chadd         reg |= 0x5 << 12;
146976bd547bSAdrian Chadd         reg |= 0x5 << 9;
147076bd547bSAdrian Chadd         reg |= 0x5 << 6;
147176bd547bSAdrian Chadd         OS_REG_WRITE(ah, AR_PHY_65NM_CH0_BIAS1, reg);
147276bd547bSAdrian Chadd 
147376bd547bSAdrian Chadd         reg = OS_REG_READ(ah, AR_PHY_65NM_CH0_BIAS2);
147476bd547bSAdrian Chadd         reg &= ~0xffffffe0;
147576bd547bSAdrian Chadd         reg |= 0x5 << 29;
147676bd547bSAdrian Chadd         reg |= 0x5 << 26;
147776bd547bSAdrian Chadd         reg |= 0x5 << 23;
147876bd547bSAdrian Chadd         reg |= 0x5 << 20;
147976bd547bSAdrian Chadd         reg |= 0x5 << 17;
148076bd547bSAdrian Chadd         reg |= 0x5 << 14;
148176bd547bSAdrian Chadd         reg |= 0x5 << 11;
148276bd547bSAdrian Chadd         reg |= 0x5 << 8;
148376bd547bSAdrian Chadd         reg |= 0x5 << 5;
148476bd547bSAdrian Chadd         OS_REG_WRITE(ah, AR_PHY_65NM_CH0_BIAS2, reg);
148576bd547bSAdrian Chadd 
148676bd547bSAdrian Chadd         reg = OS_REG_READ(ah, AR_PHY_65NM_CH0_BIAS4);
148776bd547bSAdrian Chadd         reg &= ~0xff800000;
148876bd547bSAdrian Chadd         reg |= 0x5 << 29;
148976bd547bSAdrian Chadd         reg |= 0x5 << 26;
149076bd547bSAdrian Chadd         reg |= 0x5 << 23;
149176bd547bSAdrian Chadd         OS_REG_WRITE(ah, AR_PHY_65NM_CH0_BIAS4, reg);
149276bd547bSAdrian Chadd     }
149376bd547bSAdrian Chadd     return 0;
149476bd547bSAdrian Chadd }
149576bd547bSAdrian Chadd 
ar9300_xpa_bias_level_get(struct ath_hal * ah,HAL_BOOL is_2ghz)149676bd547bSAdrian Chadd int32_t ar9300_xpa_bias_level_get(struct ath_hal *ah, HAL_BOOL is_2ghz)
149776bd547bSAdrian Chadd {
149876bd547bSAdrian Chadd     ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom;
149976bd547bSAdrian Chadd     if (is_2ghz) {
150076bd547bSAdrian Chadd         return eep->modal_header_2g.xpa_bias_lvl;
150176bd547bSAdrian Chadd     } else {
150276bd547bSAdrian Chadd         return eep->modal_header_5g.xpa_bias_lvl;
150376bd547bSAdrian Chadd     }
150476bd547bSAdrian Chadd }
150576bd547bSAdrian Chadd 
ar9300_xpa_bias_level_apply(struct ath_hal * ah,HAL_BOOL is_2ghz)150676bd547bSAdrian Chadd HAL_BOOL ar9300_xpa_bias_level_apply(struct ath_hal *ah, HAL_BOOL is_2ghz)
150776bd547bSAdrian Chadd {
150876bd547bSAdrian Chadd     /*
150976bd547bSAdrian Chadd      * In ar9330 emu, we can't access radio registers,
151076bd547bSAdrian Chadd      * merlin is used for radio part.
151176bd547bSAdrian Chadd      */
151276bd547bSAdrian Chadd     int bias;
151376bd547bSAdrian Chadd     bias = ar9300_xpa_bias_level_get(ah, is_2ghz);
151476bd547bSAdrian Chadd 
151576bd547bSAdrian Chadd     if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah) || AR_SREV_WASP(ah)) {
151676bd547bSAdrian Chadd         OS_REG_RMW_FIELD(ah,
151776bd547bSAdrian Chadd             AR_HORNET_CH0_TOP2, AR_HORNET_CH0_TOP2_XPABIASLVL, bias);
151876bd547bSAdrian Chadd     } else if (AR_SREV_SCORPION(ah)) {
151976bd547bSAdrian Chadd         OS_REG_RMW_FIELD(ah,
152076bd547bSAdrian Chadd             AR_SCORPION_CH0_TOP, AR_SCORPION_CH0_TOP_XPABIASLVL, bias);
152176bd547bSAdrian Chadd     } else if (AR_SREV_JUPITER(ah) || AR_SREV_APHRODITE(ah)) {
152276bd547bSAdrian Chadd         OS_REG_RMW_FIELD(ah,
152376bd547bSAdrian Chadd             AR_PHY_65NM_CH0_TOP_JUPITER, AR_PHY_65NM_CH0_TOP_XPABIASLVL, bias);
152476bd547bSAdrian Chadd     } else {
152576bd547bSAdrian Chadd         OS_REG_RMW_FIELD(ah,
152676bd547bSAdrian Chadd             AR_PHY_65NM_CH0_TOP, AR_PHY_65NM_CH0_TOP_XPABIASLVL, bias);
152776bd547bSAdrian Chadd         OS_REG_RMW_FIELD(ah,
152876bd547bSAdrian Chadd             AR_PHY_65NM_CH0_THERM, AR_PHY_65NM_CH0_THERM_XPABIASLVL_MSB,
152976bd547bSAdrian Chadd             bias >> 2);
153076bd547bSAdrian Chadd         OS_REG_RMW_FIELD(ah,
153176bd547bSAdrian Chadd             AR_PHY_65NM_CH0_THERM, AR_PHY_65NM_CH0_THERM_XPASHORT2GND, 1);
153276bd547bSAdrian Chadd     }
153376bd547bSAdrian Chadd     return 0;
153476bd547bSAdrian Chadd }
153576bd547bSAdrian Chadd 
ar9300_ant_ctrl_common_get(struct ath_hal * ah,HAL_BOOL is_2ghz)153676bd547bSAdrian Chadd u_int32_t ar9300_ant_ctrl_common_get(struct ath_hal *ah, HAL_BOOL is_2ghz)
153776bd547bSAdrian Chadd {
153876bd547bSAdrian Chadd     ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom;
153976bd547bSAdrian Chadd     if (is_2ghz) {
154076bd547bSAdrian Chadd         return eep->modal_header_2g.ant_ctrl_common;
154176bd547bSAdrian Chadd     } else {
154276bd547bSAdrian Chadd         return eep->modal_header_5g.ant_ctrl_common;
154376bd547bSAdrian Chadd     }
154476bd547bSAdrian Chadd }
154576bd547bSAdrian Chadd static u_int16_t
ar9300_switch_com_spdt_get(struct ath_hal * ah,HAL_BOOL is_2ghz)154676bd547bSAdrian Chadd ar9300_switch_com_spdt_get(struct ath_hal *ah, HAL_BOOL is_2ghz)
154776bd547bSAdrian Chadd {
154876bd547bSAdrian Chadd     ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom;
154976bd547bSAdrian Chadd     if (is_2ghz) {
155076bd547bSAdrian Chadd         return eep->modal_header_2g.switchcomspdt;
155176bd547bSAdrian Chadd     } else {
155276bd547bSAdrian Chadd         return eep->modal_header_5g.switchcomspdt;
155376bd547bSAdrian Chadd     }
155476bd547bSAdrian Chadd }
ar9300_ant_ctrl_common2_get(struct ath_hal * ah,HAL_BOOL is_2ghz)155576bd547bSAdrian Chadd u_int32_t ar9300_ant_ctrl_common2_get(struct ath_hal *ah, HAL_BOOL is_2ghz)
155676bd547bSAdrian Chadd {
155776bd547bSAdrian Chadd     ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom;
155876bd547bSAdrian Chadd     if (is_2ghz) {
155976bd547bSAdrian Chadd         return eep->modal_header_2g.ant_ctrl_common2;
156076bd547bSAdrian Chadd     } else {
156176bd547bSAdrian Chadd         return eep->modal_header_5g.ant_ctrl_common2;
156276bd547bSAdrian Chadd     }
156376bd547bSAdrian Chadd }
156476bd547bSAdrian Chadd 
ar9300_ant_ctrl_chain_get(struct ath_hal * ah,int chain,HAL_BOOL is_2ghz)156576bd547bSAdrian Chadd u_int16_t ar9300_ant_ctrl_chain_get(struct ath_hal *ah, int chain,
156676bd547bSAdrian Chadd     HAL_BOOL is_2ghz)
156776bd547bSAdrian Chadd {
156876bd547bSAdrian Chadd     ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom;
156976bd547bSAdrian Chadd     if (chain >= 0 && chain < OSPREY_MAX_CHAINS) {
157076bd547bSAdrian Chadd         if (is_2ghz) {
157176bd547bSAdrian Chadd             return eep->modal_header_2g.ant_ctrl_chain[chain];
157276bd547bSAdrian Chadd         } else {
157376bd547bSAdrian Chadd             return eep->modal_header_5g.ant_ctrl_chain[chain];
157476bd547bSAdrian Chadd         }
157576bd547bSAdrian Chadd     }
157676bd547bSAdrian Chadd     return 0;
157776bd547bSAdrian Chadd }
157876bd547bSAdrian Chadd 
1579899d1cacSAdrian Chadd /*
1580899d1cacSAdrian Chadd  * Select the usage of antenna via the RF switch.
1581899d1cacSAdrian Chadd  * Default values are loaded from eeprom.
1582899d1cacSAdrian Chadd  */
ar9300_ant_swcom_sel(struct ath_hal * ah,u_int8_t ops,u_int32_t * common_tbl1,u_int32_t * common_tbl2)1583899d1cacSAdrian Chadd HAL_BOOL ar9300_ant_swcom_sel(struct ath_hal *ah, u_int8_t ops,
1584899d1cacSAdrian Chadd                         u_int32_t *common_tbl1, u_int32_t *common_tbl2)
1585899d1cacSAdrian Chadd {
1586899d1cacSAdrian Chadd     ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom;
1587899d1cacSAdrian Chadd     struct ath_hal_private  *ap  = AH_PRIVATE(ah);
1588899d1cacSAdrian Chadd     const struct ieee80211_channel *curchan = ap->ah_curchan;
1589899d1cacSAdrian Chadd     enum {
1590899d1cacSAdrian Chadd         ANT_SELECT_OPS_GET,
1591899d1cacSAdrian Chadd         ANT_SELECT_OPS_SET,
1592899d1cacSAdrian Chadd     };
1593899d1cacSAdrian Chadd 
1594899d1cacSAdrian Chadd     if (AR_SREV_JUPITER(ah) || AR_SREV_SCORPION(ah))
1595899d1cacSAdrian Chadd         return AH_FALSE;
1596899d1cacSAdrian Chadd 
1597899d1cacSAdrian Chadd     if (!curchan)
1598899d1cacSAdrian Chadd         return AH_FALSE;
1599899d1cacSAdrian Chadd 
1600899d1cacSAdrian Chadd #define AR_SWITCH_TABLE_COM_ALL (0xffff)
1601899d1cacSAdrian Chadd #define AR_SWITCH_TABLE_COM_ALL_S (0)
1602899d1cacSAdrian Chadd #define AR_SWITCH_TABLE_COM2_ALL (0xffffff)
1603899d1cacSAdrian Chadd #define AR_SWITCH_TABLE_COM2_ALL_S (0)
1604899d1cacSAdrian Chadd     switch (ops) {
1605899d1cacSAdrian Chadd     case ANT_SELECT_OPS_GET:
1606899d1cacSAdrian Chadd         *common_tbl1 = OS_REG_READ_FIELD(ah, AR_PHY_SWITCH_COM,
1607899d1cacSAdrian Chadd                             AR_SWITCH_TABLE_COM_ALL);
1608899d1cacSAdrian Chadd         *common_tbl2 = OS_REG_READ_FIELD(ah, AR_PHY_SWITCH_COM_2,
1609899d1cacSAdrian Chadd                             AR_SWITCH_TABLE_COM2_ALL);
1610899d1cacSAdrian Chadd         break;
1611899d1cacSAdrian Chadd     case ANT_SELECT_OPS_SET:
1612899d1cacSAdrian Chadd         OS_REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM,
1613899d1cacSAdrian Chadd             AR_SWITCH_TABLE_COM_ALL, *common_tbl1);
1614899d1cacSAdrian Chadd         OS_REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM_2,
1615899d1cacSAdrian Chadd             AR_SWITCH_TABLE_COM2_ALL, *common_tbl2);
1616899d1cacSAdrian Chadd 
1617899d1cacSAdrian Chadd         /* write back to eeprom */
1618899d1cacSAdrian Chadd         if (IEEE80211_IS_CHAN_2GHZ(curchan)) {
1619899d1cacSAdrian Chadd             eep->modal_header_2g.ant_ctrl_common = *common_tbl1;
1620899d1cacSAdrian Chadd             eep->modal_header_2g.ant_ctrl_common2 = *common_tbl2;
1621899d1cacSAdrian Chadd         } else {
1622899d1cacSAdrian Chadd             eep->modal_header_5g.ant_ctrl_common = *common_tbl1;
1623899d1cacSAdrian Chadd             eep->modal_header_5g.ant_ctrl_common2 = *common_tbl2;
1624899d1cacSAdrian Chadd         }
1625899d1cacSAdrian Chadd 
1626899d1cacSAdrian Chadd         break;
1627899d1cacSAdrian Chadd     default:
1628899d1cacSAdrian Chadd         break;
1629899d1cacSAdrian Chadd     }
1630899d1cacSAdrian Chadd 
1631899d1cacSAdrian Chadd     return AH_TRUE;
1632899d1cacSAdrian Chadd }
1633899d1cacSAdrian Chadd 
ar9300_ant_ctrl_apply(struct ath_hal * ah,HAL_BOOL is_2ghz)163476bd547bSAdrian Chadd HAL_BOOL ar9300_ant_ctrl_apply(struct ath_hal *ah, HAL_BOOL is_2ghz)
163576bd547bSAdrian Chadd {
163676bd547bSAdrian Chadd     u_int32_t value;
163776bd547bSAdrian Chadd     struct ath_hal_9300 *ahp = AH9300(ah);
163876bd547bSAdrian Chadd     u_int32_t regval;
163976bd547bSAdrian Chadd     struct ath_hal_private *ahpriv = AH_PRIVATE(ah);
164076bd547bSAdrian Chadd #if ATH_ANT_DIV_COMB
164176bd547bSAdrian Chadd     HAL_CAPABILITIES *pcap = &ahpriv->ah_caps;
164276bd547bSAdrian Chadd #endif  /* ATH_ANT_DIV_COMB */
164376bd547bSAdrian Chadd     u_int32_t xlan_gpio_cfg;
164476bd547bSAdrian Chadd     u_int8_t  i;
164576bd547bSAdrian Chadd 
1646eb800a94SAdrian Chadd     HALDEBUG(ah, HAL_DEBUG_BT_COEX, "%s: use_bt_ant_enable=%d\n",
1647eb800a94SAdrian Chadd       __func__, ahp->ah_lna_div_use_bt_ant_enable);
1648eb800a94SAdrian Chadd 
1649eb800a94SAdrian Chadd     /* XXX TODO: only if rx_gain_idx == 0 */
165076bd547bSAdrian Chadd     if (AR_SREV_POSEIDON(ah)) {
1651e113789bSAdrian Chadd         xlan_gpio_cfg = ah->ah_config.ath_hal_ext_lna_ctl_gpio;
165276bd547bSAdrian Chadd         if (xlan_gpio_cfg) {
165376bd547bSAdrian Chadd             for (i = 0; i < 32; i++) {
165476bd547bSAdrian Chadd                 if (xlan_gpio_cfg & (1 << i)) {
1655e113789bSAdrian Chadd                     ath_hal_gpioCfgOutput(ah, i,
1656e113789bSAdrian Chadd                         HAL_GPIO_OUTPUT_MUX_PCIE_ATTENTION_LED);
165776bd547bSAdrian Chadd                 }
165876bd547bSAdrian Chadd             }
165976bd547bSAdrian Chadd         }
166076bd547bSAdrian Chadd     }
166176bd547bSAdrian Chadd #define AR_SWITCH_TABLE_COM_ALL (0xffff)
166276bd547bSAdrian Chadd #define AR_SWITCH_TABLE_COM_ALL_S (0)
166376bd547bSAdrian Chadd #define AR_SWITCH_TABLE_COM_JUPITER_ALL (0xffffff)
166476bd547bSAdrian Chadd #define AR_SWITCH_TABLE_COM_JUPITER_ALL_S (0)
166576bd547bSAdrian Chadd #define AR_SWITCH_TABLE_COM_SCORPION_ALL (0xffffff)
166676bd547bSAdrian Chadd #define AR_SWITCH_TABLE_COM_SCORPION_ALL_S (0)
166727e2ad46SAdrian Chadd #define AR_SWITCH_TABLE_COM_HONEYBEE_ALL (0xffffff)
166827e2ad46SAdrian Chadd #define AR_SWITCH_TABLE_COM_HONEYBEE_ALL_S (0)
166976bd547bSAdrian Chadd #define AR_SWITCH_TABLE_COM_SPDT (0x00f00000)
167076bd547bSAdrian Chadd     value = ar9300_ant_ctrl_common_get(ah, is_2ghz);
167176bd547bSAdrian Chadd     if (AR_SREV_JUPITER(ah) || AR_SREV_APHRODITE(ah)) {
167276bd547bSAdrian Chadd         if (AR_SREV_JUPITER_10(ah)) {
167376bd547bSAdrian Chadd             /* Force SPDT setting for Jupiter 1.0 chips. */
167476bd547bSAdrian Chadd             value &= ~AR_SWITCH_TABLE_COM_SPDT;
167576bd547bSAdrian Chadd             value |= 0x00100000;
167676bd547bSAdrian Chadd         }
167776bd547bSAdrian Chadd         OS_REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM,
167876bd547bSAdrian Chadd             AR_SWITCH_TABLE_COM_JUPITER_ALL, value);
167976bd547bSAdrian Chadd     }
168076bd547bSAdrian Chadd     else if (AR_SREV_SCORPION(ah)) {
168176bd547bSAdrian Chadd         OS_REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM,
168276bd547bSAdrian Chadd             AR_SWITCH_TABLE_COM_SCORPION_ALL, value);
168376bd547bSAdrian Chadd     }
168427e2ad46SAdrian Chadd     else if (AR_SREV_HONEYBEE(ah)) {
168527e2ad46SAdrian Chadd         OS_REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM,
168627e2ad46SAdrian Chadd             AR_SWITCH_TABLE_COM_HONEYBEE_ALL, value);
168727e2ad46SAdrian Chadd     }
168876bd547bSAdrian Chadd     else {
168976bd547bSAdrian Chadd         OS_REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM,
169076bd547bSAdrian Chadd             AR_SWITCH_TABLE_COM_ALL, value);
169176bd547bSAdrian Chadd     }
169276bd547bSAdrian Chadd /*
169376bd547bSAdrian Chadd *   Jupiter2.0 defines new switch table for BT/WLAN,
169476bd547bSAdrian Chadd *	here's new field name in WB222.ref for both 2G and 5G.
169576bd547bSAdrian Chadd *   Register: [GLB_CONTROL] GLB_CONTROL (@0x20044)
169676bd547bSAdrian Chadd *   15:12	R/W	SWITCH_TABLE_COM_SPDT_WLAN_RX	SWITCH_TABLE_COM_SPDT_WLAN_RX
169776bd547bSAdrian Chadd *   11:8	R/W	SWITCH_TABLE_COM_SPDT_WLAN_TX	SWITCH_TABLE_COM_SPDT_WLAN_TX
169876bd547bSAdrian Chadd *   7:4	R/W	SWITCH_TABLE_COM_SPDT_WLAN_IDLE	SWITCH_TABLE_COM_SPDT_WLAN_IDLE
169976bd547bSAdrian Chadd */
170076bd547bSAdrian Chadd #define AR_SWITCH_TABLE_COM_SPDT_ALL (0x0000fff0)
170176bd547bSAdrian Chadd #define AR_SWITCH_TABLE_COM_SPDT_ALL_S (4)
170276bd547bSAdrian Chadd     if (AR_SREV_JUPITER_20_OR_LATER(ah) || AR_SREV_APHRODITE(ah)) {
170376bd547bSAdrian Chadd         value = ar9300_switch_com_spdt_get(ah, is_2ghz);
170476bd547bSAdrian Chadd         OS_REG_RMW_FIELD(ah, AR_GLB_CONTROL,
170576bd547bSAdrian Chadd             AR_SWITCH_TABLE_COM_SPDT_ALL, value);
170676bd547bSAdrian Chadd 
170776bd547bSAdrian Chadd         OS_REG_SET_BIT(ah, AR_GLB_CONTROL,
170876bd547bSAdrian Chadd             AR_BTCOEX_CTRL_SPDT_ENABLE);
170976bd547bSAdrian Chadd         //OS_REG_SET_BIT(ah, AR_GLB_CONTROL,
171076bd547bSAdrian Chadd         //    AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL);
171176bd547bSAdrian Chadd     }
171276bd547bSAdrian Chadd 
171376bd547bSAdrian Chadd #define AR_SWITCH_TABLE_COM2_ALL (0xffffff)
171476bd547bSAdrian Chadd #define AR_SWITCH_TABLE_COM2_ALL_S (0)
171576bd547bSAdrian Chadd     value = ar9300_ant_ctrl_common2_get(ah, is_2ghz);
171676bd547bSAdrian Chadd #if ATH_ANT_DIV_COMB
171776bd547bSAdrian Chadd     if ( AR_SREV_POSEIDON(ah) && (ahp->ah_lna_div_use_bt_ant_enable == TRUE) ) {
171876bd547bSAdrian Chadd         value &= ~AR_SWITCH_TABLE_COM2_ALL;
1719e113789bSAdrian Chadd         value |= ah->ah_config.ath_hal_ant_ctrl_comm2g_switch_enable;
17209389d5a9SAdrian Chadd 	HALDEBUG(ah, HAL_DEBUG_RESET, "%s: com2=0x%08x\n", __func__, value)
172176bd547bSAdrian Chadd     }
172276bd547bSAdrian Chadd #endif  /* ATH_ANT_DIV_COMB */
172376bd547bSAdrian Chadd     OS_REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM_2, AR_SWITCH_TABLE_COM2_ALL, value);
172476bd547bSAdrian Chadd 
172576bd547bSAdrian Chadd #define AR_SWITCH_TABLE_ALL (0xfff)
172676bd547bSAdrian Chadd #define AR_SWITCH_TABLE_ALL_S (0)
172776bd547bSAdrian Chadd     value = ar9300_ant_ctrl_chain_get(ah, 0, is_2ghz);
172876bd547bSAdrian Chadd     OS_REG_RMW_FIELD(ah, AR_PHY_SWITCH_CHAIN_0, AR_SWITCH_TABLE_ALL, value);
172976bd547bSAdrian Chadd 
173076bd547bSAdrian Chadd     if (!AR_SREV_HORNET(ah) && !AR_SREV_POSEIDON(ah) && !AR_SREV_APHRODITE(ah)) {
173176bd547bSAdrian Chadd         value = ar9300_ant_ctrl_chain_get(ah, 1, is_2ghz);
173276bd547bSAdrian Chadd         OS_REG_RMW_FIELD(ah, AR_PHY_SWITCH_CHAIN_1, AR_SWITCH_TABLE_ALL, value);
173376bd547bSAdrian Chadd 
173427e2ad46SAdrian Chadd         if (!AR_SREV_WASP(ah) && !AR_SREV_JUPITER(ah) && !AR_SREV_HONEYBEE(ah)) {
173576bd547bSAdrian Chadd             value = ar9300_ant_ctrl_chain_get(ah, 2, is_2ghz);
173676bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah,
173776bd547bSAdrian Chadd                 AR_PHY_SWITCH_CHAIN_2, AR_SWITCH_TABLE_ALL, value);
173876bd547bSAdrian Chadd         }
173976bd547bSAdrian Chadd     }
1740eb800a94SAdrian Chadd     if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah) || AR_SREV_APHRODITE(ah)) {
174176bd547bSAdrian Chadd         value = ar9300_eeprom_get(ahp, EEP_ANTDIV_control);
174276bd547bSAdrian Chadd         /* main_lnaconf, alt_lnaconf, main_tb, alt_tb */
174376bd547bSAdrian Chadd         regval = OS_REG_READ(ah, AR_PHY_MC_GAIN_CTRL);
174476bd547bSAdrian Chadd         regval &= (~ANT_DIV_CONTROL_ALL); /* clear bit 25~30 */
174576bd547bSAdrian Chadd         regval |= (value & 0x3f) << ANT_DIV_CONTROL_ALL_S;
174676bd547bSAdrian Chadd         /* enable_lnadiv */
174776bd547bSAdrian Chadd         regval &= (~MULTICHAIN_GAIN_CTRL__ENABLE_ANT_DIV_LNADIV__MASK);
174876bd547bSAdrian Chadd         regval |= ((value >> 6) & 0x1) <<
174976bd547bSAdrian Chadd                   MULTICHAIN_GAIN_CTRL__ENABLE_ANT_DIV_LNADIV__SHIFT;
175076bd547bSAdrian Chadd #if ATH_ANT_DIV_COMB
175176bd547bSAdrian Chadd         if ( AR_SREV_POSEIDON(ah) && (ahp->ah_lna_div_use_bt_ant_enable == TRUE) ) {
175276bd547bSAdrian Chadd             regval |= ANT_DIV_ENABLE;
175376bd547bSAdrian Chadd         }
1754eb800a94SAdrian Chadd         if (AR_SREV_APHRODITE(ah)) {
1755eb800a94SAdrian Chadd                 if (ahp->ah_lna_div_use_bt_ant_enable) {
1756eb800a94SAdrian Chadd                         regval |= (1 << MULTICHAIN_GAIN_CTRL__ENABLE_ANT_SW_RX_PROT__SHIFT);
1757eb800a94SAdrian Chadd 
1758eb800a94SAdrian Chadd                         OS_REG_SET_BIT(ah, AR_PHY_RESTART,
1759eb800a94SAdrian Chadd                                     RESTART__ENABLE_ANT_FAST_DIV_M2FLAG__MASK);
1760eb800a94SAdrian Chadd 
1761eb800a94SAdrian Chadd                         /* Force WLAN LNA diversity ON */
1762eb800a94SAdrian Chadd                         OS_REG_SET_BIT(ah, AR_BTCOEX_WL_LNADIV,
1763eb800a94SAdrian Chadd                                     AR_BTCOEX_WL_LNADIV_FORCE_ON);
1764eb800a94SAdrian Chadd                 } else {
1765eb800a94SAdrian Chadd                         regval &= ~(1 << MULTICHAIN_GAIN_CTRL__ENABLE_ANT_DIV_LNADIV__SHIFT);
1766eb800a94SAdrian Chadd                         regval &= ~(1 << MULTICHAIN_GAIN_CTRL__ENABLE_ANT_SW_RX_PROT__SHIFT);
1767eb800a94SAdrian Chadd 
1768eb800a94SAdrian Chadd                         OS_REG_CLR_BIT(ah, AR_PHY_MC_GAIN_CTRL,
1769eb800a94SAdrian Chadd                                     (1 << MULTICHAIN_GAIN_CTRL__ENABLE_ANT_SW_RX_PROT__SHIFT));
1770eb800a94SAdrian Chadd 
1771eb800a94SAdrian Chadd                         /* Force WLAN LNA diversity OFF */
1772eb800a94SAdrian Chadd                         OS_REG_CLR_BIT(ah, AR_BTCOEX_WL_LNADIV,
1773eb800a94SAdrian Chadd                                     AR_BTCOEX_WL_LNADIV_FORCE_ON);
1774eb800a94SAdrian Chadd                 }
1775eb800a94SAdrian Chadd         }
1776eb800a94SAdrian Chadd 
177776bd547bSAdrian Chadd #endif  /* ATH_ANT_DIV_COMB */
177876bd547bSAdrian Chadd         OS_REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval);
177976bd547bSAdrian Chadd 
178076bd547bSAdrian Chadd         /* enable fast_div */
178176bd547bSAdrian Chadd         regval = OS_REG_READ(ah, AR_PHY_CCK_DETECT);
178276bd547bSAdrian Chadd         regval &= (~BBB_SIG_DETECT__ENABLE_ANT_FAST_DIV__MASK);
178376bd547bSAdrian Chadd         regval |= ((value >> 7) & 0x1) <<
178476bd547bSAdrian Chadd                   BBB_SIG_DETECT__ENABLE_ANT_FAST_DIV__SHIFT;
178576bd547bSAdrian Chadd #if ATH_ANT_DIV_COMB
1786eb800a94SAdrian Chadd         if ((AR_SREV_POSEIDON(ah) || AR_SREV_APHRODITE(ah))
1787eb800a94SAdrian Chadd           && (ahp->ah_lna_div_use_bt_ant_enable == TRUE) ) {
178876bd547bSAdrian Chadd             regval |= FAST_DIV_ENABLE;
178976bd547bSAdrian Chadd         }
179076bd547bSAdrian Chadd #endif  /* ATH_ANT_DIV_COMB */
179176bd547bSAdrian Chadd         OS_REG_WRITE(ah, AR_PHY_CCK_DETECT, regval);
179276bd547bSAdrian Chadd     }
179376bd547bSAdrian Chadd 
179476bd547bSAdrian Chadd #if ATH_ANT_DIV_COMB
179576bd547bSAdrian Chadd     if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON_11_OR_LATER(ah)) {
1796e113789bSAdrian Chadd         if (pcap->halAntDivCombSupport) {
179776bd547bSAdrian Chadd             /* If support DivComb, set MAIN to LNA1, ALT to LNA2 at beginning */
179876bd547bSAdrian Chadd             regval = OS_REG_READ(ah, AR_PHY_MC_GAIN_CTRL);
179976bd547bSAdrian Chadd             /* clear bit 25~30 main_lnaconf, alt_lnaconf, main_tb, alt_tb */
180076bd547bSAdrian Chadd             regval &= (~(MULTICHAIN_GAIN_CTRL__ANT_DIV_MAIN_LNACONF__MASK |
180176bd547bSAdrian Chadd                          MULTICHAIN_GAIN_CTRL__ANT_DIV_ALT_LNACONF__MASK |
180276bd547bSAdrian Chadd                          MULTICHAIN_GAIN_CTRL__ANT_DIV_ALT_GAINTB__MASK |
180376bd547bSAdrian Chadd                          MULTICHAIN_GAIN_CTRL__ANT_DIV_MAIN_GAINTB__MASK));
180476bd547bSAdrian Chadd             regval |= (HAL_ANT_DIV_COMB_LNA1 <<
180576bd547bSAdrian Chadd                        MULTICHAIN_GAIN_CTRL__ANT_DIV_MAIN_LNACONF__SHIFT);
180676bd547bSAdrian Chadd             regval |= (HAL_ANT_DIV_COMB_LNA2 <<
180776bd547bSAdrian Chadd                        MULTICHAIN_GAIN_CTRL__ANT_DIV_ALT_LNACONF__SHIFT);
180876bd547bSAdrian Chadd             OS_REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval);
180976bd547bSAdrian Chadd         }
181076bd547bSAdrian Chadd 
181176bd547bSAdrian Chadd     }
181276bd547bSAdrian Chadd #endif /* ATH_ANT_DIV_COMB */
181376bd547bSAdrian Chadd     if (AR_SREV_POSEIDON(ah) && ( ahp->ah_diversity_control == HAL_ANT_FIXED_A
181476bd547bSAdrian Chadd 	     || ahp->ah_diversity_control == HAL_ANT_FIXED_B))
181576bd547bSAdrian Chadd     {
181676bd547bSAdrian Chadd         u_int32_t reg_val = OS_REG_READ(ah, AR_PHY_MC_GAIN_CTRL);
181776bd547bSAdrian Chadd         reg_val &=  ~(MULTICHAIN_GAIN_CTRL__ANT_DIV_MAIN_LNACONF__MASK |
181876bd547bSAdrian Chadd                     MULTICHAIN_GAIN_CTRL__ANT_DIV_ALT_LNACONF__MASK |
181976bd547bSAdrian Chadd                     MULTICHAIN_GAIN_CTRL__ANT_FAST_DIV_BIAS__MASK |
182076bd547bSAdrian Chadd     		        MULTICHAIN_GAIN_CTRL__ANT_DIV_MAIN_GAINTB__MASK |
182176bd547bSAdrian Chadd     		        MULTICHAIN_GAIN_CTRL__ANT_DIV_ALT_GAINTB__MASK );
182276bd547bSAdrian Chadd 
182376bd547bSAdrian Chadd         switch (ahp->ah_diversity_control) {
182476bd547bSAdrian Chadd         case HAL_ANT_FIXED_A:
182576bd547bSAdrian Chadd             /* Enable first antenna only */
182676bd547bSAdrian Chadd             reg_val |= (HAL_ANT_DIV_COMB_LNA1 <<
182776bd547bSAdrian Chadd                        MULTICHAIN_GAIN_CTRL__ANT_DIV_MAIN_LNACONF__SHIFT);
182876bd547bSAdrian Chadd             reg_val |= (HAL_ANT_DIV_COMB_LNA2 <<
182976bd547bSAdrian Chadd                        MULTICHAIN_GAIN_CTRL__ANT_DIV_ALT_LNACONF__SHIFT);
183076bd547bSAdrian Chadd             /* main/alt gain table and Fast Div Bias all set to 0 */
183176bd547bSAdrian Chadd             OS_REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, reg_val);
183276bd547bSAdrian Chadd             regval = OS_REG_READ(ah, AR_PHY_CCK_DETECT);
183376bd547bSAdrian Chadd             regval &= (~BBB_SIG_DETECT__ENABLE_ANT_FAST_DIV__MASK);
183476bd547bSAdrian Chadd             OS_REG_WRITE(ah, AR_PHY_CCK_DETECT, regval);
183576bd547bSAdrian Chadd             break;
183676bd547bSAdrian Chadd         case HAL_ANT_FIXED_B:
183776bd547bSAdrian Chadd             /* Enable second antenna only, after checking capability */
183876bd547bSAdrian Chadd             reg_val |= (HAL_ANT_DIV_COMB_LNA2 <<
183976bd547bSAdrian Chadd                        MULTICHAIN_GAIN_CTRL__ANT_DIV_MAIN_LNACONF__SHIFT);
184076bd547bSAdrian Chadd             reg_val |= (HAL_ANT_DIV_COMB_LNA1 <<
184176bd547bSAdrian Chadd                        MULTICHAIN_GAIN_CTRL__ANT_DIV_ALT_LNACONF__SHIFT);
184276bd547bSAdrian Chadd             /* main/alt gain table and Fast Div all set to 0 */
184376bd547bSAdrian Chadd             OS_REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, reg_val);
184476bd547bSAdrian Chadd             regval = OS_REG_READ(ah, AR_PHY_CCK_DETECT);
184576bd547bSAdrian Chadd             regval &= (~BBB_SIG_DETECT__ENABLE_ANT_FAST_DIV__MASK);
184676bd547bSAdrian Chadd             OS_REG_WRITE(ah, AR_PHY_CCK_DETECT, regval);
184776bd547bSAdrian Chadd             /* For WB225, need to swith ANT2 from BT to Wifi
184876bd547bSAdrian Chadd              * This will not affect HB125 LNA diversity feature.
184976bd547bSAdrian Chadd              */
18509389d5a9SAdrian Chadd 	     HALDEBUG(ah, HAL_DEBUG_RESET, "%s: com2=0x%08x\n", __func__,
18519389d5a9SAdrian Chadd 	         ah->ah_config.ath_hal_ant_ctrl_comm2g_switch_enable)
185276bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM_2, AR_SWITCH_TABLE_COM2_ALL,
1853e113789bSAdrian Chadd                 ah->ah_config.ath_hal_ant_ctrl_comm2g_switch_enable);
185476bd547bSAdrian Chadd             break;
185576bd547bSAdrian Chadd         default:
185676bd547bSAdrian Chadd             break;
185776bd547bSAdrian Chadd         }
185876bd547bSAdrian Chadd     }
185976bd547bSAdrian Chadd     return 0;
186076bd547bSAdrian Chadd }
186176bd547bSAdrian Chadd 
186276bd547bSAdrian Chadd static u_int16_t
ar9300_attenuation_chain_get(struct ath_hal * ah,int chain,u_int16_t channel)186376bd547bSAdrian Chadd ar9300_attenuation_chain_get(struct ath_hal *ah, int chain, u_int16_t channel)
186476bd547bSAdrian Chadd {
186576bd547bSAdrian Chadd     int32_t f[3], t[3];
186676bd547bSAdrian Chadd     u_int16_t value;
186776bd547bSAdrian Chadd     ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom;
186876bd547bSAdrian Chadd     if (chain >= 0 && chain < OSPREY_MAX_CHAINS) {
186976bd547bSAdrian Chadd         if (channel < 4000) {
187076bd547bSAdrian Chadd             return eep->modal_header_2g.xatten1_db[chain];
187176bd547bSAdrian Chadd         } else {
187276bd547bSAdrian Chadd             if (eep->base_ext2.xatten1_db_low[chain] != 0) {
187376bd547bSAdrian Chadd                 t[0] = eep->base_ext2.xatten1_db_low[chain];
187476bd547bSAdrian Chadd                 f[0] = 5180;
187576bd547bSAdrian Chadd                 t[1] = eep->modal_header_5g.xatten1_db[chain];
187676bd547bSAdrian Chadd                 f[1] = 5500;
187776bd547bSAdrian Chadd                 t[2] = eep->base_ext2.xatten1_db_high[chain];
187876bd547bSAdrian Chadd                 f[2] = 5785;
187976bd547bSAdrian Chadd                 value = interpolate(channel, f, t, 3);
188076bd547bSAdrian Chadd                 return value;
188176bd547bSAdrian Chadd             } else {
188276bd547bSAdrian Chadd                 return eep->modal_header_5g.xatten1_db[chain];
188376bd547bSAdrian Chadd             }
188476bd547bSAdrian Chadd         }
188576bd547bSAdrian Chadd     }
188676bd547bSAdrian Chadd     return 0;
188776bd547bSAdrian Chadd }
188876bd547bSAdrian Chadd 
188976bd547bSAdrian Chadd static u_int16_t
ar9300_attenuation_margin_chain_get(struct ath_hal * ah,int chain,u_int16_t channel)189076bd547bSAdrian Chadd ar9300_attenuation_margin_chain_get(struct ath_hal *ah, int chain,
189176bd547bSAdrian Chadd     u_int16_t channel)
189276bd547bSAdrian Chadd {
189376bd547bSAdrian Chadd     int32_t f[3], t[3];
189476bd547bSAdrian Chadd     u_int16_t value;
189576bd547bSAdrian Chadd     ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom;
189676bd547bSAdrian Chadd     if (chain >= 0 && chain < OSPREY_MAX_CHAINS) {
189776bd547bSAdrian Chadd         if (channel < 4000) {
189876bd547bSAdrian Chadd             return eep->modal_header_2g.xatten1_margin[chain];
189976bd547bSAdrian Chadd         } else {
190076bd547bSAdrian Chadd             if (eep->base_ext2.xatten1_margin_low[chain] != 0) {
190176bd547bSAdrian Chadd                 t[0] = eep->base_ext2.xatten1_margin_low[chain];
190276bd547bSAdrian Chadd                 f[0] = 5180;
190376bd547bSAdrian Chadd                 t[1] = eep->modal_header_5g.xatten1_margin[chain];
190476bd547bSAdrian Chadd                 f[1] = 5500;
190576bd547bSAdrian Chadd                 t[2] = eep->base_ext2.xatten1_margin_high[chain];
190676bd547bSAdrian Chadd                 f[2] = 5785;
190776bd547bSAdrian Chadd                 value = interpolate(channel, f, t, 3);
190876bd547bSAdrian Chadd                 return value;
190976bd547bSAdrian Chadd             } else {
191076bd547bSAdrian Chadd                 return eep->modal_header_5g.xatten1_margin[chain];
191176bd547bSAdrian Chadd             }
191276bd547bSAdrian Chadd         }
191376bd547bSAdrian Chadd     }
191476bd547bSAdrian Chadd     return 0;
191576bd547bSAdrian Chadd }
191676bd547bSAdrian Chadd 
19179389d5a9SAdrian Chadd #if 0
191876bd547bSAdrian Chadd HAL_BOOL ar9300_attenuation_apply(struct ath_hal *ah, u_int16_t channel)
191976bd547bSAdrian Chadd {
192076bd547bSAdrian Chadd     u_int32_t value;
1921e113789bSAdrian Chadd //    struct ath_hal_private *ahpriv = AH_PRIVATE(ah);
192276bd547bSAdrian Chadd 
192376bd547bSAdrian Chadd     /* Test value. if 0 then attenuation is unused. Don't load anything. */
192476bd547bSAdrian Chadd     value = ar9300_attenuation_chain_get(ah, 0, channel);
192576bd547bSAdrian Chadd     OS_REG_RMW_FIELD(ah,
192676bd547bSAdrian Chadd         AR_PHY_EXT_ATTEN_CTL_0, AR_PHY_EXT_ATTEN_CTL_XATTEN1_DB, value);
192776bd547bSAdrian Chadd     value = ar9300_attenuation_margin_chain_get(ah, 0, channel);
192876bd547bSAdrian Chadd     if (ar9300_rx_gain_index_get(ah) == 0
1929e113789bSAdrian Chadd         && ah->ah_config.ath_hal_ext_atten_margin_cfg)
193076bd547bSAdrian Chadd     {
193176bd547bSAdrian Chadd         value = 5;
193276bd547bSAdrian Chadd     }
193376bd547bSAdrian Chadd     OS_REG_RMW_FIELD(ah,
193476bd547bSAdrian Chadd         AR_PHY_EXT_ATTEN_CTL_0, AR_PHY_EXT_ATTEN_CTL_XATTEN1_MARGIN, value);
193576bd547bSAdrian Chadd 
193676bd547bSAdrian Chadd     if (!AR_SREV_HORNET(ah) && !AR_SREV_POSEIDON(ah)) {
193776bd547bSAdrian Chadd         value = ar9300_attenuation_chain_get(ah, 1, channel);
193876bd547bSAdrian Chadd         OS_REG_RMW_FIELD(ah,
193976bd547bSAdrian Chadd             AR_PHY_EXT_ATTEN_CTL_1, AR_PHY_EXT_ATTEN_CTL_XATTEN1_DB, value);
194076bd547bSAdrian Chadd         value = ar9300_attenuation_margin_chain_get(ah, 1, channel);
194176bd547bSAdrian Chadd         OS_REG_RMW_FIELD(ah,
194276bd547bSAdrian Chadd             AR_PHY_EXT_ATTEN_CTL_1, AR_PHY_EXT_ATTEN_CTL_XATTEN1_MARGIN,
194376bd547bSAdrian Chadd             value);
194427e2ad46SAdrian Chadd         if (!AR_SREV_WASP(ah) && !AR_SREV_JUPITER(ah)&& !AR_SREV_HONEYBEE(ah) ) {
194576bd547bSAdrian Chadd             value = ar9300_attenuation_chain_get(ah, 2, channel);
194676bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah,
194776bd547bSAdrian Chadd                 AR_PHY_EXT_ATTEN_CTL_2, AR_PHY_EXT_ATTEN_CTL_XATTEN1_DB, value);
194876bd547bSAdrian Chadd             value = ar9300_attenuation_margin_chain_get(ah, 2, channel);
194976bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah,
195076bd547bSAdrian Chadd                 AR_PHY_EXT_ATTEN_CTL_2, AR_PHY_EXT_ATTEN_CTL_XATTEN1_MARGIN,
195176bd547bSAdrian Chadd                 value);
195276bd547bSAdrian Chadd         }
195376bd547bSAdrian Chadd     }
195476bd547bSAdrian Chadd     return 0;
195576bd547bSAdrian Chadd }
19569389d5a9SAdrian Chadd #endif
19579389d5a9SAdrian Chadd HAL_BOOL
ar9300_attenuation_apply(struct ath_hal * ah,u_int16_t channel)19589389d5a9SAdrian Chadd ar9300_attenuation_apply(struct ath_hal *ah, u_int16_t channel)
19599389d5a9SAdrian Chadd {
19609389d5a9SAdrian Chadd 	int i;
19619389d5a9SAdrian Chadd 	uint32_t value;
19629389d5a9SAdrian Chadd 	uint32_t ext_atten_reg[3] = {
19639389d5a9SAdrian Chadd 	    AR_PHY_EXT_ATTEN_CTL_0,
19649389d5a9SAdrian Chadd 	    AR_PHY_EXT_ATTEN_CTL_1,
19659389d5a9SAdrian Chadd 	    AR_PHY_EXT_ATTEN_CTL_2
19669389d5a9SAdrian Chadd 	};
19679389d5a9SAdrian Chadd 
19689389d5a9SAdrian Chadd 	/*
19699389d5a9SAdrian Chadd 	 * If it's an AR9462 and we're receiving on the second
19709389d5a9SAdrian Chadd 	 * chain only, set the chain 0 details from chain 1
19719389d5a9SAdrian Chadd 	 * calibration.
19729389d5a9SAdrian Chadd 	 *
19739389d5a9SAdrian Chadd 	 * This is from ath9k.
19749389d5a9SAdrian Chadd 	 */
19759389d5a9SAdrian Chadd 	if (AR_SREV_JUPITER(ah) && (AH9300(ah)->ah_rx_chainmask == 0x2)) {
19769389d5a9SAdrian Chadd 		value = ar9300_attenuation_chain_get(ah, 1, channel);
19779389d5a9SAdrian Chadd 		OS_REG_RMW_FIELD(ah, ext_atten_reg[0],
19789389d5a9SAdrian Chadd 		    AR_PHY_EXT_ATTEN_CTL_XATTEN1_DB, value);
19799389d5a9SAdrian Chadd 		value = ar9300_attenuation_margin_chain_get(ah, 1, channel);
19809389d5a9SAdrian Chadd 		OS_REG_RMW_FIELD(ah, ext_atten_reg[0],
19819389d5a9SAdrian Chadd 		    AR_PHY_EXT_ATTEN_CTL_XATTEN1_MARGIN, value);
19829389d5a9SAdrian Chadd 	}
19839389d5a9SAdrian Chadd 
19849389d5a9SAdrian Chadd 	/*
19859389d5a9SAdrian Chadd 	 * Now, loop over the configured transmit chains and
19869389d5a9SAdrian Chadd 	 * load in the attenuation/margin settings as appropriate.
19879389d5a9SAdrian Chadd 	 */
19889389d5a9SAdrian Chadd 	for (i = 0; i < 3; i++) {
19899389d5a9SAdrian Chadd 		if ((AH9300(ah)->ah_tx_chainmask & (1 << i)) == 0)
19909389d5a9SAdrian Chadd 			continue;
19919389d5a9SAdrian Chadd 
19929389d5a9SAdrian Chadd 		value = ar9300_attenuation_chain_get(ah, i, channel);
19939389d5a9SAdrian Chadd 		OS_REG_RMW_FIELD(ah, ext_atten_reg[i],
19949389d5a9SAdrian Chadd 		    AR_PHY_EXT_ATTEN_CTL_XATTEN1_DB,
19959389d5a9SAdrian Chadd 		    value);
19969389d5a9SAdrian Chadd 
19979389d5a9SAdrian Chadd 		if (AR_SREV_POSEIDON(ah) &&
19989389d5a9SAdrian Chadd 		    (ar9300_rx_gain_index_get(ah) == 0) &&
19999389d5a9SAdrian Chadd 		    ah->ah_config.ath_hal_ext_atten_margin_cfg) {
20009389d5a9SAdrian Chadd 			value = 5;
20019389d5a9SAdrian Chadd 		} else {
20029389d5a9SAdrian Chadd 			value = ar9300_attenuation_margin_chain_get(ah, 0,
20039389d5a9SAdrian Chadd 			    channel);
20049389d5a9SAdrian Chadd 		}
20059389d5a9SAdrian Chadd 
20069389d5a9SAdrian Chadd 		/*
20079389d5a9SAdrian Chadd 		 * I'm not sure why it's loading in this setting into
20089389d5a9SAdrian Chadd 		 * the chain 0 margin regardless of the current chain.
20099389d5a9SAdrian Chadd 		 */
20109389d5a9SAdrian Chadd 		if (ah->ah_config.ath_hal_min_gainidx)
20119389d5a9SAdrian Chadd 			OS_REG_RMW_FIELD(ah,
20129389d5a9SAdrian Chadd 			    AR_PHY_EXT_ATTEN_CTL_0,
20139389d5a9SAdrian Chadd 			    AR_PHY_EXT_ATTEN_CTL_XATTEN1_MARGIN,
20149389d5a9SAdrian Chadd 			    value);
20159389d5a9SAdrian Chadd 
20169389d5a9SAdrian Chadd 		OS_REG_RMW_FIELD(ah,
20179389d5a9SAdrian Chadd 		    ext_atten_reg[i],
20189389d5a9SAdrian Chadd 		    AR_PHY_EXT_ATTEN_CTL_XATTEN1_MARGIN,
20199389d5a9SAdrian Chadd 		    value);
20209389d5a9SAdrian Chadd 	}
20219389d5a9SAdrian Chadd 
20229389d5a9SAdrian Chadd 	return (0);
20239389d5a9SAdrian Chadd }
20249389d5a9SAdrian Chadd 
202576bd547bSAdrian Chadd 
ar9300_quick_drop_get(struct ath_hal * ah,int chain,u_int16_t channel)202676bd547bSAdrian Chadd static u_int16_t ar9300_quick_drop_get(struct ath_hal *ah,
202776bd547bSAdrian Chadd 								int chain, u_int16_t channel)
202876bd547bSAdrian Chadd {
202976bd547bSAdrian Chadd     int32_t f[3], t[3];
203076bd547bSAdrian Chadd     u_int16_t value;
203176bd547bSAdrian Chadd     ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom;
203276bd547bSAdrian Chadd 
203376bd547bSAdrian Chadd     if (channel < 4000) {
203476bd547bSAdrian Chadd         return eep->modal_header_2g.quick_drop;
203576bd547bSAdrian Chadd     } else {
203676bd547bSAdrian Chadd         t[0] = eep->base_ext1.quick_drop_low;
203776bd547bSAdrian Chadd         f[0] = 5180;
203876bd547bSAdrian Chadd         t[1] = eep->modal_header_5g.quick_drop;
203976bd547bSAdrian Chadd         f[1] = 5500;
204076bd547bSAdrian Chadd         t[2] = eep->base_ext1.quick_drop_high;
204176bd547bSAdrian Chadd         f[2] = 5785;
204276bd547bSAdrian Chadd         value = interpolate(channel, f, t, 3);
204376bd547bSAdrian Chadd         return value;
204476bd547bSAdrian Chadd     }
204576bd547bSAdrian Chadd }
204676bd547bSAdrian Chadd 
204776bd547bSAdrian Chadd 
ar9300_quick_drop_apply(struct ath_hal * ah,u_int16_t channel)204876bd547bSAdrian Chadd static HAL_BOOL ar9300_quick_drop_apply(struct ath_hal *ah, u_int16_t channel)
204976bd547bSAdrian Chadd {
205076bd547bSAdrian Chadd     ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom;
205176bd547bSAdrian Chadd     u_int32_t value;
205276bd547bSAdrian Chadd     //
205376bd547bSAdrian Chadd     // Test value. if 0 then quickDrop is unused. Don't load anything.
205476bd547bSAdrian Chadd     //
205576bd547bSAdrian Chadd     if (eep->base_eep_header.misc_configuration & 0x10)
205676bd547bSAdrian Chadd 	{
205776bd547bSAdrian Chadd         if (AR_SREV_OSPREY(ah) || AR_SREV_AR9580(ah) || AR_SREV_WASP(ah))
205876bd547bSAdrian Chadd         {
205976bd547bSAdrian Chadd             value = ar9300_quick_drop_get(ah, 0, channel);
206076bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah, AR_PHY_AGC, AR_PHY_AGC_QUICK_DROP, value);
206176bd547bSAdrian Chadd         }
206276bd547bSAdrian Chadd     }
206376bd547bSAdrian Chadd     return 0;
206476bd547bSAdrian Chadd }
206576bd547bSAdrian Chadd 
ar9300_tx_end_to_xpa_off_get(struct ath_hal * ah,u_int16_t channel)206676bd547bSAdrian Chadd static u_int16_t ar9300_tx_end_to_xpa_off_get(struct ath_hal *ah, u_int16_t channel)
206776bd547bSAdrian Chadd {
206876bd547bSAdrian Chadd     ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom;
206976bd547bSAdrian Chadd 
207076bd547bSAdrian Chadd     if (channel < 4000) {
207176bd547bSAdrian Chadd         return eep->modal_header_2g.tx_end_to_xpa_off;
207276bd547bSAdrian Chadd     } else {
207376bd547bSAdrian Chadd         return eep->modal_header_5g.tx_end_to_xpa_off;
207476bd547bSAdrian Chadd     }
207576bd547bSAdrian Chadd }
207676bd547bSAdrian Chadd 
ar9300_tx_end_to_xpab_off_apply(struct ath_hal * ah,u_int16_t channel)207776bd547bSAdrian Chadd static HAL_BOOL ar9300_tx_end_to_xpab_off_apply(struct ath_hal *ah, u_int16_t channel)
207876bd547bSAdrian Chadd {
207976bd547bSAdrian Chadd     u_int32_t value;
208076bd547bSAdrian Chadd 
208176bd547bSAdrian Chadd     value = ar9300_tx_end_to_xpa_off_get(ah, channel);
208276bd547bSAdrian Chadd     /* Apply to both xpaa and xpab */
208376bd547bSAdrian Chadd     if (AR_SREV_OSPREY(ah) || AR_SREV_AR9580(ah) || AR_SREV_WASP(ah))
208476bd547bSAdrian Chadd     {
208576bd547bSAdrian Chadd         OS_REG_RMW_FIELD(ah, AR_PHY_XPA_TIMING_CTL,
208676bd547bSAdrian Chadd             AR_PHY_XPA_TIMING_CTL_TX_END_XPAB_OFF, value);
208776bd547bSAdrian Chadd         OS_REG_RMW_FIELD(ah, AR_PHY_XPA_TIMING_CTL,
208876bd547bSAdrian Chadd             AR_PHY_XPA_TIMING_CTL_TX_END_XPAA_OFF, value);
208976bd547bSAdrian Chadd     }
209076bd547bSAdrian Chadd     return 0;
209176bd547bSAdrian Chadd }
209276bd547bSAdrian Chadd 
209376bd547bSAdrian Chadd static int
ar9300_eeprom_cal_pier_get(struct ath_hal * ah,int mode,int ipier,int ichain,int * pfrequency,int * pcorrection,int * ptemperature,int * pvoltage)209476bd547bSAdrian Chadd ar9300_eeprom_cal_pier_get(struct ath_hal *ah, int mode, int ipier, int ichain,
209576bd547bSAdrian Chadd     int *pfrequency, int *pcorrection, int *ptemperature, int *pvoltage)
209676bd547bSAdrian Chadd {
209776bd547bSAdrian Chadd     u_int8_t *p_cal_pier;
209876bd547bSAdrian Chadd     OSP_CAL_DATA_PER_FREQ_OP_LOOP *p_cal_pier_struct;
209976bd547bSAdrian Chadd     int is_2ghz;
210076bd547bSAdrian Chadd     ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom;
210176bd547bSAdrian Chadd 
210276bd547bSAdrian Chadd     if (ichain >= OSPREY_MAX_CHAINS) {
210376bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_EEPROM,
210476bd547bSAdrian Chadd             "%s: Invalid chain index, must be less than %d\n",
210576bd547bSAdrian Chadd             __func__, OSPREY_MAX_CHAINS);
210676bd547bSAdrian Chadd         return -1;
210776bd547bSAdrian Chadd     }
210876bd547bSAdrian Chadd 
210976bd547bSAdrian Chadd     if (mode) {/* 5GHz */
211076bd547bSAdrian Chadd         if (ipier >= OSPREY_NUM_5G_CAL_PIERS){
211176bd547bSAdrian Chadd             HALDEBUG(ah, HAL_DEBUG_EEPROM,
211276bd547bSAdrian Chadd                 "%s: Invalid 5GHz cal pier index, must be less than %d\n",
211376bd547bSAdrian Chadd                 __func__, OSPREY_NUM_5G_CAL_PIERS);
211476bd547bSAdrian Chadd             return -1;
211576bd547bSAdrian Chadd         }
211676bd547bSAdrian Chadd         p_cal_pier = &(eep->cal_freq_pier_5g[ipier]);
211776bd547bSAdrian Chadd         p_cal_pier_struct = &(eep->cal_pier_data_5g[ichain][ipier]);
211876bd547bSAdrian Chadd         is_2ghz = 0;
211976bd547bSAdrian Chadd     } else {
212076bd547bSAdrian Chadd         if (ipier >= OSPREY_NUM_2G_CAL_PIERS){
212176bd547bSAdrian Chadd             HALDEBUG(ah, HAL_DEBUG_EEPROM,
212276bd547bSAdrian Chadd                 "%s: Invalid 2GHz cal pier index, must be less than %d\n",
212376bd547bSAdrian Chadd                 __func__, OSPREY_NUM_2G_CAL_PIERS);
212476bd547bSAdrian Chadd             return -1;
212576bd547bSAdrian Chadd         }
212676bd547bSAdrian Chadd 
212776bd547bSAdrian Chadd         p_cal_pier = &(eep->cal_freq_pier_2g[ipier]);
212876bd547bSAdrian Chadd         p_cal_pier_struct = &(eep->cal_pier_data_2g[ichain][ipier]);
212976bd547bSAdrian Chadd         is_2ghz = 1;
213076bd547bSAdrian Chadd     }
213176bd547bSAdrian Chadd     *pfrequency = FBIN2FREQ(*p_cal_pier, is_2ghz);
213276bd547bSAdrian Chadd     *pcorrection = p_cal_pier_struct->ref_power;
213376bd547bSAdrian Chadd     *ptemperature = p_cal_pier_struct->temp_meas;
213476bd547bSAdrian Chadd     *pvoltage = p_cal_pier_struct->volt_meas;
213576bd547bSAdrian Chadd     return 0;
213676bd547bSAdrian Chadd }
213776bd547bSAdrian Chadd 
213876bd547bSAdrian Chadd /*
213976bd547bSAdrian Chadd  * Apply the recorded correction values.
214076bd547bSAdrian Chadd  */
214176bd547bSAdrian Chadd static int
ar9300_calibration_apply(struct ath_hal * ah,int frequency)214276bd547bSAdrian Chadd ar9300_calibration_apply(struct ath_hal *ah, int frequency)
214376bd547bSAdrian Chadd {
2144e113789bSAdrian Chadd     struct ath_hal_9300 *ahp = AH9300(ah);
2145e113789bSAdrian Chadd 
214676bd547bSAdrian Chadd     int ichain, ipier, npier;
214776bd547bSAdrian Chadd     int mode;
214876bd547bSAdrian Chadd     int fdiff;
214976bd547bSAdrian Chadd     int pfrequency, pcorrection, ptemperature, pvoltage;
215076bd547bSAdrian Chadd     int bf, factor, plus;
215176bd547bSAdrian Chadd 
215276bd547bSAdrian Chadd     int lfrequency[AR9300_MAX_CHAINS];
215376bd547bSAdrian Chadd     int hfrequency[AR9300_MAX_CHAINS];
215476bd547bSAdrian Chadd 
215576bd547bSAdrian Chadd     int lcorrection[AR9300_MAX_CHAINS];
215676bd547bSAdrian Chadd     int hcorrection[AR9300_MAX_CHAINS];
215776bd547bSAdrian Chadd     int correction[AR9300_MAX_CHAINS];
215876bd547bSAdrian Chadd 
215976bd547bSAdrian Chadd     int ltemperature[AR9300_MAX_CHAINS];
216076bd547bSAdrian Chadd     int htemperature[AR9300_MAX_CHAINS];
216176bd547bSAdrian Chadd     int temperature[AR9300_MAX_CHAINS];
216276bd547bSAdrian Chadd 
216376bd547bSAdrian Chadd     int lvoltage[AR9300_MAX_CHAINS];
216476bd547bSAdrian Chadd     int hvoltage[AR9300_MAX_CHAINS];
216576bd547bSAdrian Chadd     int voltage[AR9300_MAX_CHAINS];
216676bd547bSAdrian Chadd 
216776bd547bSAdrian Chadd     mode = (frequency >= 4000);
216876bd547bSAdrian Chadd     npier = (mode) ?  OSPREY_NUM_5G_CAL_PIERS : OSPREY_NUM_2G_CAL_PIERS;
216976bd547bSAdrian Chadd 
217076bd547bSAdrian Chadd     for (ichain = 0; ichain < AR9300_MAX_CHAINS; ichain++) {
217176bd547bSAdrian Chadd         lfrequency[ichain] = 0;
217276bd547bSAdrian Chadd         hfrequency[ichain] = 100000;
217376bd547bSAdrian Chadd     }
217476bd547bSAdrian Chadd     /*
217576bd547bSAdrian Chadd      * identify best lower and higher frequency calibration measurement
217676bd547bSAdrian Chadd      */
217776bd547bSAdrian Chadd     for (ichain = 0; ichain < AR9300_MAX_CHAINS; ichain++) {
217876bd547bSAdrian Chadd         for (ipier = 0; ipier < npier; ipier++) {
217976bd547bSAdrian Chadd             if (ar9300_eeprom_cal_pier_get(
218076bd547bSAdrian Chadd                     ah, mode, ipier, ichain,
218176bd547bSAdrian Chadd                     &pfrequency, &pcorrection, &ptemperature, &pvoltage) == 0)
218276bd547bSAdrian Chadd             {
218376bd547bSAdrian Chadd                 fdiff = frequency - pfrequency;
218476bd547bSAdrian Chadd                 /*
218576bd547bSAdrian Chadd                  * this measurement is higher than our desired frequency
218676bd547bSAdrian Chadd                  */
218776bd547bSAdrian Chadd                 if (fdiff <= 0) {
218876bd547bSAdrian Chadd                     if (hfrequency[ichain] <= 0 ||
218976bd547bSAdrian Chadd                         hfrequency[ichain] >= 100000 ||
219076bd547bSAdrian Chadd                         fdiff > (frequency - hfrequency[ichain]))
219176bd547bSAdrian Chadd                     {
219276bd547bSAdrian Chadd                         /*
219376bd547bSAdrian Chadd                          * new best higher frequency measurement
219476bd547bSAdrian Chadd                          */
219576bd547bSAdrian Chadd                         hfrequency[ichain] = pfrequency;
219676bd547bSAdrian Chadd                         hcorrection[ichain] = pcorrection;
219776bd547bSAdrian Chadd                         htemperature[ichain] = ptemperature;
219876bd547bSAdrian Chadd                         hvoltage[ichain] = pvoltage;
219976bd547bSAdrian Chadd                     }
220076bd547bSAdrian Chadd                 }
220176bd547bSAdrian Chadd                 if (fdiff >= 0) {
220276bd547bSAdrian Chadd                     if (lfrequency[ichain] <= 0 ||
220376bd547bSAdrian Chadd                         fdiff < (frequency - lfrequency[ichain]))
220476bd547bSAdrian Chadd                     {
220576bd547bSAdrian Chadd                         /*
220676bd547bSAdrian Chadd                          * new best lower frequency measurement
220776bd547bSAdrian Chadd                          */
220876bd547bSAdrian Chadd                         lfrequency[ichain] = pfrequency;
220976bd547bSAdrian Chadd                         lcorrection[ichain] = pcorrection;
221076bd547bSAdrian Chadd                         ltemperature[ichain] = ptemperature;
221176bd547bSAdrian Chadd                         lvoltage[ichain] = pvoltage;
221276bd547bSAdrian Chadd                     }
221376bd547bSAdrian Chadd                 }
221476bd547bSAdrian Chadd             }
221576bd547bSAdrian Chadd         }
221676bd547bSAdrian Chadd     }
221776bd547bSAdrian Chadd     /* interpolate */
221876bd547bSAdrian Chadd     for (ichain = 0; ichain < AR9300_MAX_CHAINS; ichain++) {
221976bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_EEPROM,
222076bd547bSAdrian Chadd             "%s: ch=%d f=%d low=%d %d h=%d %d\n",
222176bd547bSAdrian Chadd             __func__, ichain, frequency,
222276bd547bSAdrian Chadd             lfrequency[ichain], lcorrection[ichain],
222376bd547bSAdrian Chadd             hfrequency[ichain], hcorrection[ichain]);
222476bd547bSAdrian Chadd         /*
222576bd547bSAdrian Chadd          * they're the same, so just pick one
222676bd547bSAdrian Chadd          */
222776bd547bSAdrian Chadd         if (hfrequency[ichain] == lfrequency[ichain]) {
222876bd547bSAdrian Chadd             correction[ichain] = lcorrection[ichain];
222976bd547bSAdrian Chadd             voltage[ichain] = lvoltage[ichain];
223076bd547bSAdrian Chadd             temperature[ichain] = ltemperature[ichain];
223176bd547bSAdrian Chadd         } else if (frequency - lfrequency[ichain] < 1000) {
223276bd547bSAdrian Chadd             /* the low frequency is good */
223376bd547bSAdrian Chadd             if (hfrequency[ichain] - frequency < 1000) {
223476bd547bSAdrian Chadd                 /*
223576bd547bSAdrian Chadd                  * The high frequency is good too -
223676bd547bSAdrian Chadd                  * interpolate with round off.
223776bd547bSAdrian Chadd                  */
223876bd547bSAdrian Chadd                 int mult, div, diff;
223976bd547bSAdrian Chadd                 mult = frequency - lfrequency[ichain];
224076bd547bSAdrian Chadd                 div = hfrequency[ichain] - lfrequency[ichain];
224176bd547bSAdrian Chadd 
224276bd547bSAdrian Chadd                 diff = hcorrection[ichain] - lcorrection[ichain];
224376bd547bSAdrian Chadd                 bf = 2 * diff * mult / div;
224476bd547bSAdrian Chadd                 plus = (bf % 2);
224576bd547bSAdrian Chadd                 factor = bf / 2;
224676bd547bSAdrian Chadd                 correction[ichain] = lcorrection[ichain] + factor + plus;
224776bd547bSAdrian Chadd 
224876bd547bSAdrian Chadd                 diff = htemperature[ichain] - ltemperature[ichain];
224976bd547bSAdrian Chadd                 bf = 2 * diff * mult / div;
225076bd547bSAdrian Chadd                 plus = (bf % 2);
225176bd547bSAdrian Chadd                 factor = bf / 2;
225276bd547bSAdrian Chadd                 temperature[ichain] = ltemperature[ichain] + factor + plus;
225376bd547bSAdrian Chadd 
225476bd547bSAdrian Chadd                 diff = hvoltage[ichain] - lvoltage[ichain];
225576bd547bSAdrian Chadd                 bf = 2 * diff * mult / div;
225676bd547bSAdrian Chadd                 plus = (bf % 2);
225776bd547bSAdrian Chadd                 factor = bf / 2;
225876bd547bSAdrian Chadd                 voltage[ichain] = lvoltage[ichain] + factor + plus;
225976bd547bSAdrian Chadd             } else {
226076bd547bSAdrian Chadd                 /* only low is good, use it */
226176bd547bSAdrian Chadd                 correction[ichain] = lcorrection[ichain];
226276bd547bSAdrian Chadd                 temperature[ichain] = ltemperature[ichain];
226376bd547bSAdrian Chadd                 voltage[ichain] = lvoltage[ichain];
226476bd547bSAdrian Chadd             }
226576bd547bSAdrian Chadd         } else if (hfrequency[ichain] - frequency < 1000) {
226676bd547bSAdrian Chadd             /* only high is good, use it */
226776bd547bSAdrian Chadd             correction[ichain] = hcorrection[ichain];
226876bd547bSAdrian Chadd             temperature[ichain] = htemperature[ichain];
226976bd547bSAdrian Chadd             voltage[ichain] = hvoltage[ichain];
227076bd547bSAdrian Chadd         } else {
227176bd547bSAdrian Chadd             /* nothing is good, presume 0???? */
227276bd547bSAdrian Chadd             correction[ichain] = 0;
227376bd547bSAdrian Chadd             temperature[ichain] = 0;
227476bd547bSAdrian Chadd             voltage[ichain] = 0;
227576bd547bSAdrian Chadd         }
227676bd547bSAdrian Chadd     }
227776bd547bSAdrian Chadd 
2278e113789bSAdrian Chadd     /* GreenTx isn't currently supported */
227976bd547bSAdrian Chadd     /* GreenTx */
2280e113789bSAdrian Chadd     if (ah->ah_config.ath_hal_sta_update_tx_pwr_enable) {
228176bd547bSAdrian Chadd         if (AR_SREV_POSEIDON(ah)) {
228276bd547bSAdrian Chadd             /* Get calibrated OLPC gain delta value for GreenTx */
2283e113789bSAdrian Chadd             ahp->ah_db2[POSEIDON_STORED_REG_G2_OLPC_OFFSET] =
228476bd547bSAdrian Chadd                 (u_int32_t) correction[0];
228576bd547bSAdrian Chadd         }
228676bd547bSAdrian Chadd     }
228776bd547bSAdrian Chadd 
228876bd547bSAdrian Chadd     ar9300_power_control_override(
228976bd547bSAdrian Chadd         ah, frequency, correction, voltage, temperature);
229076bd547bSAdrian Chadd     HALDEBUG(ah, HAL_DEBUG_EEPROM,
229176bd547bSAdrian Chadd         "%s: for frequency=%d, calibration correction = %d %d %d\n",
229276bd547bSAdrian Chadd          __func__, frequency, correction[0], correction[1], correction[2]);
229376bd547bSAdrian Chadd 
229476bd547bSAdrian Chadd     return 0;
229576bd547bSAdrian Chadd }
229676bd547bSAdrian Chadd 
229776bd547bSAdrian Chadd int
ar9300_power_control_override(struct ath_hal * ah,int frequency,int * correction,int * voltage,int * temperature)229876bd547bSAdrian Chadd ar9300_power_control_override(struct ath_hal *ah, int frequency,
229976bd547bSAdrian Chadd     int *correction, int *voltage, int *temperature)
230076bd547bSAdrian Chadd {
230176bd547bSAdrian Chadd     int temp_slope = 0;
230276bd547bSAdrian Chadd     int temp_slope_1 = 0;
230376bd547bSAdrian Chadd     int temp_slope_2 = 0;
230476bd547bSAdrian Chadd     ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom;
230576bd547bSAdrian Chadd     int32_t f[8], t[8],t1[3], t2[3];
230676bd547bSAdrian Chadd 	int i;
230776bd547bSAdrian Chadd 
230876bd547bSAdrian Chadd     OS_REG_RMW(ah, AR_PHY_TPC_11_B0,
230976bd547bSAdrian Chadd         (correction[0] << AR_PHY_TPC_OLPC_GAIN_DELTA_S),
231076bd547bSAdrian Chadd         AR_PHY_TPC_OLPC_GAIN_DELTA);
231176bd547bSAdrian Chadd     if (!AR_SREV_POSEIDON(ah)) {
231276bd547bSAdrian Chadd         OS_REG_RMW(ah, AR_PHY_TPC_11_B1,
231376bd547bSAdrian Chadd             (correction[1] << AR_PHY_TPC_OLPC_GAIN_DELTA_S),
231476bd547bSAdrian Chadd             AR_PHY_TPC_OLPC_GAIN_DELTA);
231527e2ad46SAdrian Chadd         if (!AR_SREV_WASP(ah) && !AR_SREV_JUPITER(ah) && !AR_SREV_HONEYBEE(ah) ) {
231676bd547bSAdrian Chadd             OS_REG_RMW(ah, AR_PHY_TPC_11_B2,
231776bd547bSAdrian Chadd                 (correction[2] << AR_PHY_TPC_OLPC_GAIN_DELTA_S),
231876bd547bSAdrian Chadd                 AR_PHY_TPC_OLPC_GAIN_DELTA);
231976bd547bSAdrian Chadd         }
232076bd547bSAdrian Chadd     }
232176bd547bSAdrian Chadd     /*
232276bd547bSAdrian Chadd      * enable open loop power control on chip
232376bd547bSAdrian Chadd      */
232476bd547bSAdrian Chadd     OS_REG_RMW(ah, AR_PHY_TPC_6_B0,
232576bd547bSAdrian Chadd         (3 << AR_PHY_TPC_6_ERROR_EST_MODE_S), AR_PHY_TPC_6_ERROR_EST_MODE);
232676bd547bSAdrian Chadd     if (!AR_SREV_POSEIDON(ah)) {
232776bd547bSAdrian Chadd         OS_REG_RMW(ah, AR_PHY_TPC_6_B1,
232876bd547bSAdrian Chadd             (3 << AR_PHY_TPC_6_ERROR_EST_MODE_S), AR_PHY_TPC_6_ERROR_EST_MODE);
232927e2ad46SAdrian Chadd         if (!AR_SREV_WASP(ah) && !AR_SREV_JUPITER(ah) && !AR_SREV_HONEYBEE(ah)  ) {
233076bd547bSAdrian Chadd             OS_REG_RMW(ah, AR_PHY_TPC_6_B2,
233176bd547bSAdrian Chadd                 (3 << AR_PHY_TPC_6_ERROR_EST_MODE_S),
233276bd547bSAdrian Chadd                 AR_PHY_TPC_6_ERROR_EST_MODE);
233376bd547bSAdrian Chadd         }
233476bd547bSAdrian Chadd     }
233576bd547bSAdrian Chadd 
233676bd547bSAdrian Chadd     /*
233776bd547bSAdrian Chadd      * Enable temperature compensation
233876bd547bSAdrian Chadd      * Need to use register names
233976bd547bSAdrian Chadd      */
234076bd547bSAdrian Chadd     if (frequency < 4000) {
234176bd547bSAdrian Chadd         temp_slope = eep->modal_header_2g.temp_slope;
234276bd547bSAdrian Chadd     } else {
234376bd547bSAdrian Chadd 		if ((eep->base_eep_header.misc_configuration & 0x20) != 0)
234476bd547bSAdrian Chadd 		{
234576bd547bSAdrian Chadd 				for(i=0;i<8;i++)
234676bd547bSAdrian Chadd 				{
234776bd547bSAdrian Chadd 					t[i]=eep->base_ext1.tempslopextension[i];
234876bd547bSAdrian Chadd 					f[i]=FBIN2FREQ(eep->cal_freq_pier_5g[i], 0);
234976bd547bSAdrian Chadd 				}
235076bd547bSAdrian Chadd 				temp_slope=interpolate(frequency,f,t,8);
235176bd547bSAdrian Chadd 		}
235276bd547bSAdrian Chadd 		else
235376bd547bSAdrian Chadd 		{
235476bd547bSAdrian Chadd         if(!AR_SREV_SCORPION(ah)) {
235576bd547bSAdrian Chadd           if (eep->base_ext2.temp_slope_low != 0) {
235676bd547bSAdrian Chadd              t[0] = eep->base_ext2.temp_slope_low;
235776bd547bSAdrian Chadd              f[0] = 5180;
235876bd547bSAdrian Chadd              t[1] = eep->modal_header_5g.temp_slope;
235976bd547bSAdrian Chadd              f[1] = 5500;
236076bd547bSAdrian Chadd              t[2] = eep->base_ext2.temp_slope_high;
236176bd547bSAdrian Chadd              f[2] = 5785;
236276bd547bSAdrian Chadd              temp_slope = interpolate(frequency, f, t, 3);
236376bd547bSAdrian Chadd            } else {
236476bd547bSAdrian Chadd              temp_slope = eep->modal_header_5g.temp_slope;
236576bd547bSAdrian Chadd            }
236676bd547bSAdrian Chadd          } else {
236776bd547bSAdrian Chadd             /*
236876bd547bSAdrian Chadd              * Scorpion has individual chain tempslope values
236976bd547bSAdrian Chadd              */
237076bd547bSAdrian Chadd              t[0] = eep->base_ext1.tempslopextension[2];
237176bd547bSAdrian Chadd              t1[0]= eep->base_ext1.tempslopextension[3];
237276bd547bSAdrian Chadd              t2[0]= eep->base_ext1.tempslopextension[4];
237376bd547bSAdrian Chadd              f[0] = 5180;
237476bd547bSAdrian Chadd              t[1] = eep->modal_header_5g.temp_slope;
237576bd547bSAdrian Chadd              t1[1]= eep->base_ext1.tempslopextension[0];
237676bd547bSAdrian Chadd              t2[1]= eep->base_ext1.tempslopextension[1];
237776bd547bSAdrian Chadd              f[1] = 5500;
237876bd547bSAdrian Chadd              t[2] = eep->base_ext1.tempslopextension[5];
237976bd547bSAdrian Chadd              t1[2]= eep->base_ext1.tempslopextension[6];
238076bd547bSAdrian Chadd              t2[2]= eep->base_ext1.tempslopextension[7];
238176bd547bSAdrian Chadd              f[2] = 5785;
238276bd547bSAdrian Chadd              temp_slope = interpolate(frequency, f, t, 3);
238376bd547bSAdrian Chadd              temp_slope_1=interpolate(frequency, f, t1,3);
238476bd547bSAdrian Chadd              temp_slope_2=interpolate(frequency, f, t2,3);
238576bd547bSAdrian Chadd        }
238676bd547bSAdrian Chadd 	 }
238776bd547bSAdrian Chadd   }
238876bd547bSAdrian Chadd 
238927e2ad46SAdrian Chadd     if (!AR_SREV_SCORPION(ah) && !AR_SREV_HONEYBEE(ah)) {
239076bd547bSAdrian Chadd         OS_REG_RMW_FIELD(ah,
239176bd547bSAdrian Chadd             AR_PHY_TPC_19, AR_PHY_TPC_19_ALPHA_THERM, temp_slope);
239276bd547bSAdrian Chadd     } else {
239327e2ad46SAdrian Chadd         /*Scorpion and Honeybee has tempSlope register for each chain*/
239476bd547bSAdrian Chadd         /*Check whether temp_compensation feature is enabled or not*/
239576bd547bSAdrian Chadd         if (eep->base_eep_header.feature_enable & 0x1){
239676bd547bSAdrian Chadd 	    if(frequency < 4000) {
239727e2ad46SAdrian Chadd 		if (((eep->base_eep_header.txrx_mask & 0xf0) >> 4) & 0x1) {
239876bd547bSAdrian Chadd 		    OS_REG_RMW_FIELD(ah,
239976bd547bSAdrian Chadd 				    AR_PHY_TPC_19, AR_PHY_TPC_19_ALPHA_THERM,
240076bd547bSAdrian Chadd 				    eep->base_ext2.temp_slope_low);
240127e2ad46SAdrian Chadd 		    }
240227e2ad46SAdrian Chadd 		if (((eep->base_eep_header.txrx_mask & 0xf0) >> 4) & 0x2) {
240376bd547bSAdrian Chadd 		    OS_REG_RMW_FIELD(ah,
240476bd547bSAdrian Chadd 				    AR_SCORPION_PHY_TPC_19_B1, AR_PHY_TPC_19_ALPHA_THERM,
240576bd547bSAdrian Chadd 				    temp_slope);
240627e2ad46SAdrian Chadd 		    }
240727e2ad46SAdrian Chadd 		if (((eep->base_eep_header.txrx_mask & 0xf0) >> 4) & 0x4) {
240876bd547bSAdrian Chadd 		    OS_REG_RMW_FIELD(ah,
240976bd547bSAdrian Chadd 				    AR_SCORPION_PHY_TPC_19_B2, AR_PHY_TPC_19_ALPHA_THERM,
241076bd547bSAdrian Chadd 				    eep->base_ext2.temp_slope_high);
241127e2ad46SAdrian Chadd 		     }
241276bd547bSAdrian Chadd 	    } else {
241327e2ad46SAdrian Chadd 		if (((eep->base_eep_header.txrx_mask & 0xf0) >> 4) & 0x1) {
241476bd547bSAdrian Chadd 		    OS_REG_RMW_FIELD(ah,
241576bd547bSAdrian Chadd 				    AR_PHY_TPC_19, AR_PHY_TPC_19_ALPHA_THERM,
241676bd547bSAdrian Chadd 				    temp_slope);
241727e2ad46SAdrian Chadd 			}
241827e2ad46SAdrian Chadd 		if (((eep->base_eep_header.txrx_mask & 0xf0) >> 4) & 0x2) {
241976bd547bSAdrian Chadd 		    OS_REG_RMW_FIELD(ah,
242076bd547bSAdrian Chadd 				    AR_SCORPION_PHY_TPC_19_B1, AR_PHY_TPC_19_ALPHA_THERM,
242176bd547bSAdrian Chadd 				    temp_slope_1);
242227e2ad46SAdrian Chadd 		}
242327e2ad46SAdrian Chadd 		if (((eep->base_eep_header.txrx_mask & 0xf0) >> 4) & 0x4) {
242476bd547bSAdrian Chadd 		    OS_REG_RMW_FIELD(ah,
242576bd547bSAdrian Chadd 				    AR_SCORPION_PHY_TPC_19_B2, AR_PHY_TPC_19_ALPHA_THERM,
242676bd547bSAdrian Chadd 				    temp_slope_2);
242776bd547bSAdrian Chadd 			}
242827e2ad46SAdrian Chadd 	    }
242976bd547bSAdrian Chadd         }else {
243076bd547bSAdrian Chadd         	/* If temp compensation is not enabled, set all registers to 0*/
243127e2ad46SAdrian Chadd 		if (((eep->base_eep_header.txrx_mask & 0xf0) >> 4) & 0x1) {
243276bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah,
243376bd547bSAdrian Chadd                 AR_PHY_TPC_19, AR_PHY_TPC_19_ALPHA_THERM, 0);
243427e2ad46SAdrian Chadd 		    }
243527e2ad46SAdrian Chadd 		if (((eep->base_eep_header.txrx_mask & 0xf0) >> 4) & 0x2) {
243676bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah,
243776bd547bSAdrian Chadd                 AR_SCORPION_PHY_TPC_19_B1, AR_PHY_TPC_19_ALPHA_THERM, 0);
243827e2ad46SAdrian Chadd 		    }
243927e2ad46SAdrian Chadd 		if (((eep->base_eep_header.txrx_mask & 0xf0) >> 4) & 0x4) {
244076bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah,
244176bd547bSAdrian Chadd                 AR_SCORPION_PHY_TPC_19_B2, AR_PHY_TPC_19_ALPHA_THERM, 0);
244276bd547bSAdrian Chadd 		}
244376bd547bSAdrian Chadd         }
244427e2ad46SAdrian Chadd     }
244576bd547bSAdrian Chadd     OS_REG_RMW_FIELD(ah,
244676bd547bSAdrian Chadd         AR_PHY_TPC_18, AR_PHY_TPC_18_THERM_CAL_VALUE, temperature[0]);
244776bd547bSAdrian Chadd 
244876bd547bSAdrian Chadd     return 0;
244976bd547bSAdrian Chadd }
245076bd547bSAdrian Chadd 
245176bd547bSAdrian Chadd /**************************************************************
245276bd547bSAdrian Chadd  * ar9300_eep_def_get_max_edge_power
245376bd547bSAdrian Chadd  *
245476bd547bSAdrian Chadd  * Find the maximum conformance test limit for the given channel and CTL info
245576bd547bSAdrian Chadd  */
245676bd547bSAdrian Chadd static inline u_int16_t
ar9300_eep_def_get_max_edge_power(ar9300_eeprom_t * p_eep_data,u_int16_t freq,int idx,HAL_BOOL is_2ghz)245776bd547bSAdrian Chadd ar9300_eep_def_get_max_edge_power(ar9300_eeprom_t *p_eep_data, u_int16_t freq,
245876bd547bSAdrian Chadd     int idx, HAL_BOOL is_2ghz)
245976bd547bSAdrian Chadd {
246076bd547bSAdrian Chadd     u_int16_t twice_max_edge_power = AR9300_MAX_RATE_POWER;
246176bd547bSAdrian Chadd     u_int8_t *ctl_freqbin = is_2ghz ?
246276bd547bSAdrian Chadd         &p_eep_data->ctl_freqbin_2G[idx][0] :
246376bd547bSAdrian Chadd         &p_eep_data->ctl_freqbin_5G[idx][0];
246476bd547bSAdrian Chadd     u_int16_t num_edges = is_2ghz ?
246576bd547bSAdrian Chadd         OSPREY_NUM_BAND_EDGES_2G : OSPREY_NUM_BAND_EDGES_5G;
246676bd547bSAdrian Chadd     int i;
246776bd547bSAdrian Chadd 
246876bd547bSAdrian Chadd     /* Get the edge power */
246976bd547bSAdrian Chadd     for (i = 0; (i < num_edges) && (ctl_freqbin[i] != AR9300_BCHAN_UNUSED); i++)
247076bd547bSAdrian Chadd     {
247176bd547bSAdrian Chadd         /*
247276bd547bSAdrian Chadd          * If there's an exact channel match or an inband flag set
247376bd547bSAdrian Chadd          * on the lower channel use the given rd_edge_power
247476bd547bSAdrian Chadd          */
247576bd547bSAdrian Chadd         if (freq == fbin2freq(ctl_freqbin[i], is_2ghz)) {
247676bd547bSAdrian Chadd             if (is_2ghz) {
247776bd547bSAdrian Chadd                 twice_max_edge_power =
247876bd547bSAdrian Chadd                     p_eep_data->ctl_power_data_2g[idx].ctl_edges[i].t_power;
247976bd547bSAdrian Chadd             } else {
248076bd547bSAdrian Chadd                 twice_max_edge_power =
248176bd547bSAdrian Chadd                     p_eep_data->ctl_power_data_5g[idx].ctl_edges[i].t_power;
248276bd547bSAdrian Chadd             }
248376bd547bSAdrian Chadd             break;
248476bd547bSAdrian Chadd         } else if ((i > 0) && (freq < fbin2freq(ctl_freqbin[i], is_2ghz))) {
248576bd547bSAdrian Chadd             if (is_2ghz) {
248676bd547bSAdrian Chadd                 if (fbin2freq(ctl_freqbin[i - 1], 1) < freq &&
248776bd547bSAdrian Chadd                     p_eep_data->ctl_power_data_2g[idx].ctl_edges[i - 1].flag)
248876bd547bSAdrian Chadd                 {
248976bd547bSAdrian Chadd                     twice_max_edge_power =
249076bd547bSAdrian Chadd                         p_eep_data->ctl_power_data_2g[idx].
249176bd547bSAdrian Chadd                             ctl_edges[i - 1].t_power;
249276bd547bSAdrian Chadd                 }
249376bd547bSAdrian Chadd             } else {
249476bd547bSAdrian Chadd                 if (fbin2freq(ctl_freqbin[i - 1], 0) < freq &&
249576bd547bSAdrian Chadd                     p_eep_data->ctl_power_data_5g[idx].ctl_edges[i - 1].flag)
249676bd547bSAdrian Chadd                 {
249776bd547bSAdrian Chadd                     twice_max_edge_power =
249876bd547bSAdrian Chadd                         p_eep_data->ctl_power_data_5g[idx].
249976bd547bSAdrian Chadd                             ctl_edges[i - 1].t_power;
250076bd547bSAdrian Chadd                 }
250176bd547bSAdrian Chadd             }
250276bd547bSAdrian Chadd             /*
250376bd547bSAdrian Chadd              * Leave loop - no more affecting edges possible
250476bd547bSAdrian Chadd              * in this monotonic increasing list
250576bd547bSAdrian Chadd              */
250676bd547bSAdrian Chadd             break;
250776bd547bSAdrian Chadd         }
250876bd547bSAdrian Chadd     }
250976bd547bSAdrian Chadd     /*
251076bd547bSAdrian Chadd      * EV89475: EEPROM might contain 0 txpower in CTL table for certain
251176bd547bSAdrian Chadd      * 2.4GHz channels. We workaround it by overwriting 60 (30 dBm) here.
251276bd547bSAdrian Chadd      */
251376bd547bSAdrian Chadd     if (is_2ghz && (twice_max_edge_power == 0)) {
251476bd547bSAdrian Chadd         twice_max_edge_power = 60;
251576bd547bSAdrian Chadd     }
251676bd547bSAdrian Chadd 
251776bd547bSAdrian Chadd     HALASSERT(twice_max_edge_power > 0);
251876bd547bSAdrian Chadd     return twice_max_edge_power;
251976bd547bSAdrian Chadd }
252076bd547bSAdrian Chadd 
252176bd547bSAdrian Chadd HAL_BOOL
ar9300_eeprom_set_power_per_rate_table(struct ath_hal * ah,ar9300_eeprom_t * p_eep_data,const struct ieee80211_channel * chan,u_int8_t * p_pwr_array,u_int16_t cfg_ctl,u_int16_t antenna_reduction,u_int16_t twice_max_regulatory_power,u_int16_t power_limit,u_int8_t chainmask)252276bd547bSAdrian Chadd ar9300_eeprom_set_power_per_rate_table(
252376bd547bSAdrian Chadd     struct ath_hal *ah,
252476bd547bSAdrian Chadd     ar9300_eeprom_t *p_eep_data,
2525e113789bSAdrian Chadd     const struct ieee80211_channel *chan,
252676bd547bSAdrian Chadd     u_int8_t *p_pwr_array,
252776bd547bSAdrian Chadd     u_int16_t cfg_ctl,
252876bd547bSAdrian Chadd     u_int16_t antenna_reduction,
252976bd547bSAdrian Chadd     u_int16_t twice_max_regulatory_power,
253076bd547bSAdrian Chadd     u_int16_t power_limit,
253176bd547bSAdrian Chadd     u_int8_t chainmask)
253276bd547bSAdrian Chadd {
253376bd547bSAdrian Chadd     /* Local defines to distinguish between extension and control CTL's */
253476bd547bSAdrian Chadd #define EXT_ADDITIVE (0x8000)
253576bd547bSAdrian Chadd #define CTL_11A_EXT (CTL_11A | EXT_ADDITIVE)
253676bd547bSAdrian Chadd #define CTL_11G_EXT (CTL_11G | EXT_ADDITIVE)
253776bd547bSAdrian Chadd #define CTL_11B_EXT (CTL_11B | EXT_ADDITIVE)
253876bd547bSAdrian Chadd #define REDUCE_SCALED_POWER_BY_TWO_CHAIN     6  /* 10*log10(2)*2 */
253976bd547bSAdrian Chadd #define REDUCE_SCALED_POWER_BY_THREE_CHAIN  10  /* 10*log10(3)*2 */
254076bd547bSAdrian Chadd #define PWRINCR_3_TO_1_CHAIN      9             /* 10*log(3)*2 */
254176bd547bSAdrian Chadd #define PWRINCR_3_TO_2_CHAIN      3             /* floor(10*log(3/2)*2) */
254276bd547bSAdrian Chadd #define PWRINCR_2_TO_1_CHAIN      6             /* 10*log(2)*2 */
254376bd547bSAdrian Chadd 
254476bd547bSAdrian Chadd     static const u_int16_t tp_scale_reduction_table[5] =
254576bd547bSAdrian Chadd         { 0, 3, 6, 9, AR9300_MAX_RATE_POWER };
254676bd547bSAdrian Chadd     int i;
254776bd547bSAdrian Chadd     int16_t twice_largest_antenna;
254876bd547bSAdrian Chadd     u_int16_t twice_antenna_reduction = 2*antenna_reduction ;
254976bd547bSAdrian Chadd     int16_t scaled_power = 0, min_ctl_power, max_reg_allowed_power;
255076bd547bSAdrian Chadd #define SUB_NUM_CTL_MODES_AT_5G_40 2    /* excluding HT40, EXT-OFDM */
255176bd547bSAdrian Chadd #define SUB_NUM_CTL_MODES_AT_2G_40 3    /* excluding HT40, EXT-OFDM, EXT-CCK */
255276bd547bSAdrian Chadd     u_int16_t ctl_modes_for11a[] =
255376bd547bSAdrian Chadd         {CTL_11A, CTL_5GHT20, CTL_11A_EXT, CTL_5GHT40};
255476bd547bSAdrian Chadd     u_int16_t ctl_modes_for11g[] =
255576bd547bSAdrian Chadd         {CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT, CTL_2GHT40};
255676bd547bSAdrian Chadd     u_int16_t num_ctl_modes, *p_ctl_mode, ctl_mode, freq;
255776bd547bSAdrian Chadd     CHAN_CENTERS centers;
255876bd547bSAdrian Chadd     int tx_chainmask;
255976bd547bSAdrian Chadd     struct ath_hal_9300 *ahp = AH9300(ah);
256076bd547bSAdrian Chadd     u_int8_t *ctl_index;
256176bd547bSAdrian Chadd     u_int8_t ctl_num;
256276bd547bSAdrian Chadd     u_int16_t twice_min_edge_power;
256376bd547bSAdrian Chadd     u_int16_t twice_max_edge_power = AR9300_MAX_RATE_POWER;
2564e113789bSAdrian Chadd #ifdef	AH_DEBUG
2565e113789bSAdrian Chadd     HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan);
2566e113789bSAdrian Chadd #endif
256776bd547bSAdrian Chadd 
2568899d1cacSAdrian Chadd     if (chainmask)
2569899d1cacSAdrian Chadd         tx_chainmask = chainmask;
2570899d1cacSAdrian Chadd     else
2571899d1cacSAdrian Chadd         tx_chainmask = ahp->ah_tx_chainmaskopt ?
2572899d1cacSAdrian Chadd                             ahp->ah_tx_chainmaskopt :ahp->ah_tx_chainmask;
257376bd547bSAdrian Chadd 
257476bd547bSAdrian Chadd     ar9300_get_channel_centers(ah, chan, &centers);
257576bd547bSAdrian Chadd 
2576899d1cacSAdrian Chadd #if 1
2577e113789bSAdrian Chadd     if (IEEE80211_IS_CHAN_2GHZ(chan)) {
257876bd547bSAdrian Chadd         ahp->twice_antenna_gain = p_eep_data->modal_header_2g.antenna_gain;
257976bd547bSAdrian Chadd     } else {
258076bd547bSAdrian Chadd         ahp->twice_antenna_gain = p_eep_data->modal_header_5g.antenna_gain;
258176bd547bSAdrian Chadd     }
258276bd547bSAdrian Chadd 
2583899d1cacSAdrian Chadd #else
2584899d1cacSAdrian Chadd     if (IEEE80211_IS_CHAN_2GHZ(chan)) {
2585899d1cacSAdrian Chadd         ahp->twice_antenna_gain = AH_MAX(p_eep_data->modal_header_2g.antenna_gain,
2586899d1cacSAdrian Chadd                                          AH_PRIVATE(ah)->ah_antenna_gain_2g);
2587899d1cacSAdrian Chadd     } else {
2588899d1cacSAdrian Chadd         ahp->twice_antenna_gain = AH_MAX(p_eep_data->modal_header_5g.antenna_gain,
2589899d1cacSAdrian Chadd                                          AH_PRIVATE(ah)->ah_antenna_gain_5g);
2590899d1cacSAdrian Chadd     }
2591899d1cacSAdrian Chadd #endif
2592899d1cacSAdrian Chadd 
259376bd547bSAdrian Chadd     /* Save max allowed antenna gain to ease future lookups */
259476bd547bSAdrian Chadd     ahp->twice_antenna_reduction = twice_antenna_reduction;
259576bd547bSAdrian Chadd 
259676bd547bSAdrian Chadd     /*  Deduct antenna gain from  EIRP to get the upper limit */
259776bd547bSAdrian Chadd     twice_largest_antenna = (int16_t)AH_MIN((twice_antenna_reduction -
259876bd547bSAdrian Chadd                                        ahp->twice_antenna_gain), 0);
259976bd547bSAdrian Chadd     max_reg_allowed_power = twice_max_regulatory_power + twice_largest_antenna;
260076bd547bSAdrian Chadd 
260176bd547bSAdrian Chadd     /* Use ah_tp_scale - see bug 30070. */
2602e113789bSAdrian Chadd     if (AH_PRIVATE(ah)->ah_tpScale != HAL_TP_SCALE_MAX) {
260376bd547bSAdrian Chadd         max_reg_allowed_power -=
2604e113789bSAdrian Chadd             (tp_scale_reduction_table[(AH_PRIVATE(ah)->ah_tpScale)] * 2);
260576bd547bSAdrian Chadd     }
260676bd547bSAdrian Chadd 
260776bd547bSAdrian Chadd     scaled_power = AH_MIN(power_limit, max_reg_allowed_power);
260876bd547bSAdrian Chadd 
260976bd547bSAdrian Chadd     /*
261076bd547bSAdrian Chadd      * Reduce scaled Power by number of chains active to get to
261176bd547bSAdrian Chadd      * per chain tx power level
261276bd547bSAdrian Chadd      */
261376bd547bSAdrian Chadd     /* TODO: better value than these? */
261476bd547bSAdrian Chadd     switch (ar9300_get_ntxchains(tx_chainmask)) {
261576bd547bSAdrian Chadd     case 1:
261676bd547bSAdrian Chadd         ahp->upper_limit[0] = AH_MAX(0, scaled_power);
261776bd547bSAdrian Chadd         break;
261876bd547bSAdrian Chadd     case 2:
261976bd547bSAdrian Chadd         scaled_power -= REDUCE_SCALED_POWER_BY_TWO_CHAIN;
262076bd547bSAdrian Chadd         ahp->upper_limit[1] = AH_MAX(0, scaled_power);
262176bd547bSAdrian Chadd         break;
262276bd547bSAdrian Chadd     case 3:
262376bd547bSAdrian Chadd         scaled_power -= REDUCE_SCALED_POWER_BY_THREE_CHAIN;
262476bd547bSAdrian Chadd         ahp->upper_limit[2] = AH_MAX(0, scaled_power);
262576bd547bSAdrian Chadd         break;
262676bd547bSAdrian Chadd     default:
262776bd547bSAdrian Chadd         HALASSERT(0); /* Unsupported number of chains */
262876bd547bSAdrian Chadd     }
262976bd547bSAdrian Chadd 
263076bd547bSAdrian Chadd     scaled_power = AH_MAX(0, scaled_power);
263176bd547bSAdrian Chadd 
263276bd547bSAdrian Chadd     /* Get target powers from EEPROM - our baseline for TX Power */
2633e113789bSAdrian Chadd     if (IEEE80211_IS_CHAN_2GHZ(chan)) {
263476bd547bSAdrian Chadd         /* Setup for CTL modes */
263576bd547bSAdrian Chadd         /* CTL_11B, CTL_11G, CTL_2GHT20 */
263676bd547bSAdrian Chadd         num_ctl_modes =
263776bd547bSAdrian Chadd             ARRAY_LENGTH(ctl_modes_for11g) - SUB_NUM_CTL_MODES_AT_2G_40;
263876bd547bSAdrian Chadd         p_ctl_mode = ctl_modes_for11g;
263976bd547bSAdrian Chadd 
2640e113789bSAdrian Chadd         if (IEEE80211_IS_CHAN_HT40(chan)) {
264176bd547bSAdrian Chadd             num_ctl_modes = ARRAY_LENGTH(ctl_modes_for11g); /* All 2G CTL's */
264276bd547bSAdrian Chadd         }
264376bd547bSAdrian Chadd     } else {
264476bd547bSAdrian Chadd         /* Setup for CTL modes */
264576bd547bSAdrian Chadd         /* CTL_11A, CTL_5GHT20 */
264676bd547bSAdrian Chadd         num_ctl_modes =
264776bd547bSAdrian Chadd             ARRAY_LENGTH(ctl_modes_for11a) - SUB_NUM_CTL_MODES_AT_5G_40;
264876bd547bSAdrian Chadd         p_ctl_mode = ctl_modes_for11a;
264976bd547bSAdrian Chadd 
2650e113789bSAdrian Chadd         if (IEEE80211_IS_CHAN_HT40(chan)) {
265176bd547bSAdrian Chadd             num_ctl_modes = ARRAY_LENGTH(ctl_modes_for11a); /* All 5G CTL's */
265276bd547bSAdrian Chadd         }
265376bd547bSAdrian Chadd     }
265476bd547bSAdrian Chadd 
265576bd547bSAdrian Chadd     /*
265676bd547bSAdrian Chadd      * For MIMO, need to apply regulatory caps individually across dynamically
265776bd547bSAdrian Chadd      * running modes: CCK, OFDM, HT20, HT40
265876bd547bSAdrian Chadd      *
265976bd547bSAdrian Chadd      * The outer loop walks through each possible applicable runtime mode.
266076bd547bSAdrian Chadd      * The inner loop walks through each ctl_index entry in EEPROM.
266176bd547bSAdrian Chadd      * The ctl value is encoded as [7:4] == test group, [3:0] == test mode.
266276bd547bSAdrian Chadd      *
266376bd547bSAdrian Chadd      */
266476bd547bSAdrian Chadd     for (ctl_mode = 0; ctl_mode < num_ctl_modes; ctl_mode++) {
266576bd547bSAdrian Chadd         HAL_BOOL is_ht40_ctl_mode =
266676bd547bSAdrian Chadd             (p_ctl_mode[ctl_mode] == CTL_5GHT40) ||
266776bd547bSAdrian Chadd             (p_ctl_mode[ctl_mode] == CTL_2GHT40);
266876bd547bSAdrian Chadd         if (is_ht40_ctl_mode) {
266976bd547bSAdrian Chadd             freq = centers.synth_center;
267076bd547bSAdrian Chadd         } else if (p_ctl_mode[ctl_mode] & EXT_ADDITIVE) {
267176bd547bSAdrian Chadd             freq = centers.ext_center;
267276bd547bSAdrian Chadd         } else {
267376bd547bSAdrian Chadd             freq = centers.ctl_center;
267476bd547bSAdrian Chadd         }
267576bd547bSAdrian Chadd 
267676bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_POWER_MGMT,
267776bd547bSAdrian Chadd             "LOOP-Mode ctl_mode %d < %d, "
267876bd547bSAdrian Chadd             "is_ht40_ctl_mode %d, EXT_ADDITIVE %d\n",
267976bd547bSAdrian Chadd             ctl_mode, num_ctl_modes, is_ht40_ctl_mode,
268076bd547bSAdrian Chadd             (p_ctl_mode[ctl_mode] & EXT_ADDITIVE));
268176bd547bSAdrian Chadd         /* walk through each CTL index stored in EEPROM */
2682e113789bSAdrian Chadd         if (IEEE80211_IS_CHAN_2GHZ(chan)) {
268376bd547bSAdrian Chadd             ctl_index = p_eep_data->ctl_index_2g;
268476bd547bSAdrian Chadd             ctl_num = OSPREY_NUM_CTLS_2G;
268576bd547bSAdrian Chadd         } else {
268676bd547bSAdrian Chadd             ctl_index = p_eep_data->ctl_index_5g;
268776bd547bSAdrian Chadd             ctl_num = OSPREY_NUM_CTLS_5G;
268876bd547bSAdrian Chadd         }
268976bd547bSAdrian Chadd 
269076bd547bSAdrian Chadd         for (i = 0; (i < ctl_num) && ctl_index[i]; i++) {
269176bd547bSAdrian Chadd             HALDEBUG(ah, HAL_DEBUG_POWER_MGMT,
269276bd547bSAdrian Chadd                 "  LOOP-Ctlidx %d: cfg_ctl 0x%2.2x p_ctl_mode 0x%2.2x "
269376bd547bSAdrian Chadd                 "ctl_index 0x%2.2x chan %d chanctl 0x%x\n",
269476bd547bSAdrian Chadd                 i, cfg_ctl, p_ctl_mode[ctl_mode], ctl_index[i],
2695e113789bSAdrian Chadd                 ichan->channel, ath_hal_getctl(ah, chan));
2696e113789bSAdrian Chadd 
269776bd547bSAdrian Chadd 
269876bd547bSAdrian Chadd             /*
269976bd547bSAdrian Chadd              * compare test group from regulatory channel list
270076bd547bSAdrian Chadd              * with test mode from p_ctl_mode list
270176bd547bSAdrian Chadd              */
270276bd547bSAdrian Chadd             if ((((cfg_ctl & ~CTL_MODE_M) |
270376bd547bSAdrian Chadd                   (p_ctl_mode[ctl_mode] & CTL_MODE_M)) == ctl_index[i]) ||
270476bd547bSAdrian Chadd                 (((cfg_ctl & ~CTL_MODE_M) |
270576bd547bSAdrian Chadd                   (p_ctl_mode[ctl_mode] & CTL_MODE_M)) ==
270676bd547bSAdrian Chadd                  ((ctl_index[i] & CTL_MODE_M) | SD_NO_CTL)))
270776bd547bSAdrian Chadd             {
270876bd547bSAdrian Chadd                 twice_min_edge_power =
270976bd547bSAdrian Chadd                     ar9300_eep_def_get_max_edge_power(
2710e113789bSAdrian Chadd                         p_eep_data, freq, i, IEEE80211_IS_CHAN_2GHZ(chan));
271176bd547bSAdrian Chadd 
271276bd547bSAdrian Chadd                 HALDEBUG(ah, HAL_DEBUG_POWER_MGMT,
271376bd547bSAdrian Chadd                     "    MATCH-EE_IDX %d: ch %d is2 %d "
271476bd547bSAdrian Chadd                     "2xMinEdge %d chainmask %d chains %d\n",
2715e113789bSAdrian Chadd                     i, freq, IEEE80211_IS_CHAN_2GHZ(chan),
271676bd547bSAdrian Chadd                     twice_min_edge_power, tx_chainmask,
271776bd547bSAdrian Chadd                     ar9300_get_ntxchains(tx_chainmask));
271876bd547bSAdrian Chadd 
271976bd547bSAdrian Chadd                 if ((cfg_ctl & ~CTL_MODE_M) == SD_NO_CTL) {
272076bd547bSAdrian Chadd                     /*
272176bd547bSAdrian Chadd                      * Find the minimum of all CTL edge powers
272276bd547bSAdrian Chadd                      * that apply to this channel
272376bd547bSAdrian Chadd                      */
272476bd547bSAdrian Chadd                     twice_max_edge_power =
272576bd547bSAdrian Chadd                         AH_MIN(twice_max_edge_power, twice_min_edge_power);
272676bd547bSAdrian Chadd                 } else {
272776bd547bSAdrian Chadd                     /* specific */
272876bd547bSAdrian Chadd                     twice_max_edge_power = twice_min_edge_power;
272976bd547bSAdrian Chadd                     break;
273076bd547bSAdrian Chadd                 }
273176bd547bSAdrian Chadd             }
273276bd547bSAdrian Chadd         }
273376bd547bSAdrian Chadd 
273476bd547bSAdrian Chadd         min_ctl_power = (u_int8_t)AH_MIN(twice_max_edge_power, scaled_power);
273576bd547bSAdrian Chadd 
273676bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_POWER_MGMT,
273776bd547bSAdrian Chadd             "    SEL-Min ctl_mode %d p_ctl_mode %d "
273876bd547bSAdrian Chadd             "2xMaxEdge %d sP %d min_ctl_pwr %d\n",
273976bd547bSAdrian Chadd             ctl_mode, p_ctl_mode[ctl_mode],
274076bd547bSAdrian Chadd             twice_max_edge_power, scaled_power, min_ctl_power);
274176bd547bSAdrian Chadd 
274276bd547bSAdrian Chadd         /* Apply ctl mode to correct target power set */
274376bd547bSAdrian Chadd         switch (p_ctl_mode[ctl_mode]) {
274476bd547bSAdrian Chadd         case CTL_11B:
274576bd547bSAdrian Chadd             for (i = ALL_TARGET_LEGACY_1L_5L; i <= ALL_TARGET_LEGACY_11S; i++) {
274676bd547bSAdrian Chadd                 p_pwr_array[i] =
274776bd547bSAdrian Chadd                     (u_int8_t)AH_MIN(p_pwr_array[i], min_ctl_power);
274876bd547bSAdrian Chadd             }
274976bd547bSAdrian Chadd             break;
275076bd547bSAdrian Chadd         case CTL_11A:
275176bd547bSAdrian Chadd         case CTL_11G:
275276bd547bSAdrian Chadd             for (i = ALL_TARGET_LEGACY_6_24; i <= ALL_TARGET_LEGACY_54; i++) {
275376bd547bSAdrian Chadd                 p_pwr_array[i] =
275476bd547bSAdrian Chadd                     (u_int8_t)AH_MIN(p_pwr_array[i], min_ctl_power);
275576bd547bSAdrian Chadd #ifdef ATH_BT_COEX
275676bd547bSAdrian Chadd                 if ((ahp->ah_bt_coex_config_type == HAL_BT_COEX_CFG_3WIRE) ||
275776bd547bSAdrian Chadd                     (ahp->ah_bt_coex_config_type == HAL_BT_COEX_CFG_MCI))
275876bd547bSAdrian Chadd                 {
275976bd547bSAdrian Chadd                     if ((ahp->ah_bt_coex_flag & HAL_BT_COEX_FLAG_LOWER_TX_PWR)
276076bd547bSAdrian Chadd                         && (ahp->ah_bt_wlan_isolation
276176bd547bSAdrian Chadd                          < HAL_BT_COEX_ISOLATION_FOR_NO_COEX))
276276bd547bSAdrian Chadd                     {
276376bd547bSAdrian Chadd 
276476bd547bSAdrian Chadd                         u_int8_t reduce_pow;
276576bd547bSAdrian Chadd 
276676bd547bSAdrian Chadd                         reduce_pow = (HAL_BT_COEX_ISOLATION_FOR_NO_COEX
276776bd547bSAdrian Chadd                                      - ahp->ah_bt_wlan_isolation) << 1;
276876bd547bSAdrian Chadd 
276976bd547bSAdrian Chadd                         if (reduce_pow <= p_pwr_array[i]) {
277076bd547bSAdrian Chadd                             p_pwr_array[i] -= reduce_pow;
277176bd547bSAdrian Chadd                         }
277276bd547bSAdrian Chadd                     }
277376bd547bSAdrian Chadd                     if ((ahp->ah_bt_coex_flag &
277476bd547bSAdrian Chadd                           HAL_BT_COEX_FLAG_LOW_ACK_PWR) &&
277576bd547bSAdrian Chadd                           (i != ALL_TARGET_LEGACY_36) &&
277676bd547bSAdrian Chadd                           (i != ALL_TARGET_LEGACY_48) &&
277776bd547bSAdrian Chadd                           (i != ALL_TARGET_LEGACY_54) &&
277876bd547bSAdrian Chadd                           (p_ctl_mode[ctl_mode] == CTL_11G))
277976bd547bSAdrian Chadd                     {
278076bd547bSAdrian Chadd                         p_pwr_array[i] = 0;
278176bd547bSAdrian Chadd                     }
278276bd547bSAdrian Chadd                 }
278376bd547bSAdrian Chadd #endif
278476bd547bSAdrian Chadd             }
278576bd547bSAdrian Chadd             break;
278676bd547bSAdrian Chadd         case CTL_5GHT20:
278776bd547bSAdrian Chadd         case CTL_2GHT20:
278876bd547bSAdrian Chadd             for (i = ALL_TARGET_HT20_0_8_16; i <= ALL_TARGET_HT20_23; i++) {
278976bd547bSAdrian Chadd                 p_pwr_array[i] =
279076bd547bSAdrian Chadd                     (u_int8_t)AH_MIN(p_pwr_array[i], min_ctl_power);
279176bd547bSAdrian Chadd #ifdef ATH_BT_COEX
279276bd547bSAdrian Chadd                 if (((ahp->ah_bt_coex_config_type == HAL_BT_COEX_CFG_3WIRE) ||
279376bd547bSAdrian Chadd                      (ahp->ah_bt_coex_config_type == HAL_BT_COEX_CFG_MCI)) &&
279476bd547bSAdrian Chadd                     (ahp->ah_bt_coex_flag & HAL_BT_COEX_FLAG_LOWER_TX_PWR) &&
279576bd547bSAdrian Chadd                     (ahp->ah_bt_wlan_isolation
279676bd547bSAdrian Chadd                         < HAL_BT_COEX_ISOLATION_FOR_NO_COEX)) {
279776bd547bSAdrian Chadd 
279876bd547bSAdrian Chadd                     u_int8_t reduce_pow = (HAL_BT_COEX_ISOLATION_FOR_NO_COEX
279976bd547bSAdrian Chadd                                            - ahp->ah_bt_wlan_isolation) << 1;
280076bd547bSAdrian Chadd 
280176bd547bSAdrian Chadd                     if (reduce_pow <= p_pwr_array[i]) {
280276bd547bSAdrian Chadd                         p_pwr_array[i] -= reduce_pow;
280376bd547bSAdrian Chadd                     }
280476bd547bSAdrian Chadd                 }
280576bd547bSAdrian Chadd #if ATH_SUPPORT_MCI
280676bd547bSAdrian Chadd                 else if ((ahp->ah_bt_coex_flag &
280776bd547bSAdrian Chadd                           HAL_BT_COEX_FLAG_MCI_MAX_TX_PWR) &&
280876bd547bSAdrian Chadd                          (p_ctl_mode[ctl_mode] == CTL_2GHT20) &&
280976bd547bSAdrian Chadd                          (ahp->ah_bt_coex_config_type == HAL_BT_COEX_CFG_MCI))
281076bd547bSAdrian Chadd                 {
281176bd547bSAdrian Chadd                     u_int8_t max_pwr;
281276bd547bSAdrian Chadd 
281376bd547bSAdrian Chadd                     max_pwr = MS(mci_concur_tx_max_pwr[2][1],
281476bd547bSAdrian Chadd                                  ATH_MCI_CONCUR_TX_LOWEST_PWR_MASK);
281576bd547bSAdrian Chadd                     if (p_pwr_array[i] > max_pwr) {
281676bd547bSAdrian Chadd                         p_pwr_array[i] = max_pwr;
281776bd547bSAdrian Chadd                     }
281876bd547bSAdrian Chadd                 }
281976bd547bSAdrian Chadd #endif
282076bd547bSAdrian Chadd #endif
282176bd547bSAdrian Chadd             }
282276bd547bSAdrian Chadd             break;
282376bd547bSAdrian Chadd         case CTL_11B_EXT:
282476bd547bSAdrian Chadd #ifdef NOT_YET
282576bd547bSAdrian Chadd             target_power_cck_ext.t_pow2x[0] = (u_int8_t)
282676bd547bSAdrian Chadd                 AH_MIN(target_power_cck_ext.t_pow2x[0], min_ctl_power);
282776bd547bSAdrian Chadd #endif /* NOT_YET */
282876bd547bSAdrian Chadd             break;
282976bd547bSAdrian Chadd         case CTL_11A_EXT:
283076bd547bSAdrian Chadd         case CTL_11G_EXT:
283176bd547bSAdrian Chadd #ifdef NOT_YET
283276bd547bSAdrian Chadd             target_power_ofdm_ext.t_pow2x[0] = (u_int8_t)
283376bd547bSAdrian Chadd                 AH_MIN(target_power_ofdm_ext.t_pow2x[0], min_ctl_power);
283476bd547bSAdrian Chadd #endif /* NOT_YET */
283576bd547bSAdrian Chadd             break;
283676bd547bSAdrian Chadd         case CTL_5GHT40:
283776bd547bSAdrian Chadd         case CTL_2GHT40:
283876bd547bSAdrian Chadd             for (i = ALL_TARGET_HT40_0_8_16; i <= ALL_TARGET_HT40_23; i++) {
283976bd547bSAdrian Chadd                 p_pwr_array[i] = (u_int8_t)
284076bd547bSAdrian Chadd                     AH_MIN(p_pwr_array[i], min_ctl_power);
284176bd547bSAdrian Chadd #ifdef ATH_BT_COEX
284276bd547bSAdrian Chadd                 if (((ahp->ah_bt_coex_config_type == HAL_BT_COEX_CFG_3WIRE) ||
284376bd547bSAdrian Chadd                      (ahp->ah_bt_coex_config_type == HAL_BT_COEX_CFG_MCI)) &&
284476bd547bSAdrian Chadd                     (ahp->ah_bt_coex_flag & HAL_BT_COEX_FLAG_LOWER_TX_PWR) &&
284576bd547bSAdrian Chadd                     (ahp->ah_bt_wlan_isolation
284676bd547bSAdrian Chadd                         < HAL_BT_COEX_ISOLATION_FOR_NO_COEX)) {
284776bd547bSAdrian Chadd 
284876bd547bSAdrian Chadd                     u_int8_t reduce_pow = (HAL_BT_COEX_ISOLATION_FOR_NO_COEX
284976bd547bSAdrian Chadd                                               - ahp->ah_bt_wlan_isolation) << 1;
285076bd547bSAdrian Chadd 
285176bd547bSAdrian Chadd                     if (reduce_pow <= p_pwr_array[i]) {
285276bd547bSAdrian Chadd                         p_pwr_array[i] -= reduce_pow;
285376bd547bSAdrian Chadd                     }
285476bd547bSAdrian Chadd                 }
285576bd547bSAdrian Chadd #if ATH_SUPPORT_MCI
285676bd547bSAdrian Chadd                 else if ((ahp->ah_bt_coex_flag &
285776bd547bSAdrian Chadd                           HAL_BT_COEX_FLAG_MCI_MAX_TX_PWR) &&
285876bd547bSAdrian Chadd                          (p_ctl_mode[ctl_mode] == CTL_2GHT40) &&
285976bd547bSAdrian Chadd                          (ahp->ah_bt_coex_config_type == HAL_BT_COEX_CFG_MCI))
286076bd547bSAdrian Chadd                 {
286176bd547bSAdrian Chadd                     u_int8_t max_pwr;
286276bd547bSAdrian Chadd 
286376bd547bSAdrian Chadd                     max_pwr = MS(mci_concur_tx_max_pwr[3][1],
286476bd547bSAdrian Chadd                                  ATH_MCI_CONCUR_TX_LOWEST_PWR_MASK);
286576bd547bSAdrian Chadd                     if (p_pwr_array[i] > max_pwr) {
286676bd547bSAdrian Chadd                         p_pwr_array[i] = max_pwr;
286776bd547bSAdrian Chadd                     }
286876bd547bSAdrian Chadd                 }
286976bd547bSAdrian Chadd #endif
287076bd547bSAdrian Chadd #endif
287176bd547bSAdrian Chadd             }
287276bd547bSAdrian Chadd             break;
287376bd547bSAdrian Chadd         default:
287476bd547bSAdrian Chadd             HALASSERT(0);
287576bd547bSAdrian Chadd             break;
287676bd547bSAdrian Chadd         }
287776bd547bSAdrian Chadd     } /* end ctl mode checking */
287876bd547bSAdrian Chadd 
287976bd547bSAdrian Chadd     return AH_TRUE;
288076bd547bSAdrian Chadd #undef EXT_ADDITIVE
288176bd547bSAdrian Chadd #undef CTL_11A_EXT
288276bd547bSAdrian Chadd #undef CTL_11G_EXT
288376bd547bSAdrian Chadd #undef CTL_11B_EXT
288476bd547bSAdrian Chadd #undef REDUCE_SCALED_POWER_BY_TWO_CHAIN
288576bd547bSAdrian Chadd #undef REDUCE_SCALED_POWER_BY_THREE_CHAIN
288676bd547bSAdrian Chadd }
288776bd547bSAdrian Chadd 
288876bd547bSAdrian Chadd /**************************************************************
288976bd547bSAdrian Chadd  * ar9300_eeprom_set_transmit_power
289076bd547bSAdrian Chadd  *
289176bd547bSAdrian Chadd  * Set the transmit power in the baseband for the given
289276bd547bSAdrian Chadd  * operating channel and mode.
289376bd547bSAdrian Chadd  */
289476bd547bSAdrian Chadd HAL_STATUS
ar9300_eeprom_set_transmit_power(struct ath_hal * ah,ar9300_eeprom_t * p_eep_data,const struct ieee80211_channel * chan,u_int16_t cfg_ctl,u_int16_t antenna_reduction,u_int16_t twice_max_regulatory_power,u_int16_t power_limit)289576bd547bSAdrian Chadd ar9300_eeprom_set_transmit_power(struct ath_hal *ah,
2896e113789bSAdrian Chadd     ar9300_eeprom_t *p_eep_data, const struct ieee80211_channel *chan, u_int16_t cfg_ctl,
289776bd547bSAdrian Chadd     u_int16_t antenna_reduction, u_int16_t twice_max_regulatory_power,
289876bd547bSAdrian Chadd     u_int16_t power_limit)
289976bd547bSAdrian Chadd {
290076bd547bSAdrian Chadd #define ABS(_x, _y) ((int)_x > (int)_y ? (int)_x - (int)_y : (int)_y - (int)_x)
290176bd547bSAdrian Chadd #define INCREASE_MAXPOW_BY_TWO_CHAIN     6  /* 10*log10(2)*2 */
290276bd547bSAdrian Chadd #define INCREASE_MAXPOW_BY_THREE_CHAIN   10 /* 10*log10(3)*2 */
290376bd547bSAdrian Chadd     u_int8_t target_power_val_t2[ar9300_rate_size];
290476bd547bSAdrian Chadd     u_int8_t target_power_val_t2_eep[ar9300_rate_size];
290576bd547bSAdrian Chadd     int16_t twice_array_gain = 0, max_power_level = 0;
290676bd547bSAdrian Chadd     struct ath_hal_9300 *ahp = AH9300(ah);
290776bd547bSAdrian Chadd     int  i = 0;
290876bd547bSAdrian Chadd     u_int32_t tmp_paprd_rate_mask = 0, *tmp_ptr = NULL;
290976bd547bSAdrian Chadd     int      paprd_scale_factor = 5;
2910e113789bSAdrian Chadd     HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan);
291176bd547bSAdrian Chadd 
291276bd547bSAdrian Chadd     u_int8_t *ptr_mcs_rate2power_table_index;
291376bd547bSAdrian Chadd     u_int8_t mcs_rate2power_table_index_ht20[24] =
291476bd547bSAdrian Chadd     {
291576bd547bSAdrian Chadd         ALL_TARGET_HT20_0_8_16,
291676bd547bSAdrian Chadd         ALL_TARGET_HT20_1_3_9_11_17_19,
291776bd547bSAdrian Chadd         ALL_TARGET_HT20_1_3_9_11_17_19,
291876bd547bSAdrian Chadd         ALL_TARGET_HT20_1_3_9_11_17_19,
291976bd547bSAdrian Chadd         ALL_TARGET_HT20_4,
292076bd547bSAdrian Chadd         ALL_TARGET_HT20_5,
292176bd547bSAdrian Chadd         ALL_TARGET_HT20_6,
292276bd547bSAdrian Chadd         ALL_TARGET_HT20_7,
292376bd547bSAdrian Chadd         ALL_TARGET_HT20_0_8_16,
292476bd547bSAdrian Chadd         ALL_TARGET_HT20_1_3_9_11_17_19,
292576bd547bSAdrian Chadd         ALL_TARGET_HT20_1_3_9_11_17_19,
292676bd547bSAdrian Chadd         ALL_TARGET_HT20_1_3_9_11_17_19,
292776bd547bSAdrian Chadd         ALL_TARGET_HT20_12,
292876bd547bSAdrian Chadd         ALL_TARGET_HT20_13,
292976bd547bSAdrian Chadd         ALL_TARGET_HT20_14,
293076bd547bSAdrian Chadd         ALL_TARGET_HT20_15,
293176bd547bSAdrian Chadd         ALL_TARGET_HT20_0_8_16,
293276bd547bSAdrian Chadd         ALL_TARGET_HT20_1_3_9_11_17_19,
293376bd547bSAdrian Chadd         ALL_TARGET_HT20_1_3_9_11_17_19,
293476bd547bSAdrian Chadd         ALL_TARGET_HT20_1_3_9_11_17_19,
293576bd547bSAdrian Chadd         ALL_TARGET_HT20_20,
293676bd547bSAdrian Chadd         ALL_TARGET_HT20_21,
293776bd547bSAdrian Chadd         ALL_TARGET_HT20_22,
293876bd547bSAdrian Chadd         ALL_TARGET_HT20_23
293976bd547bSAdrian Chadd     };
294076bd547bSAdrian Chadd 
294176bd547bSAdrian Chadd     u_int8_t mcs_rate2power_table_index_ht40[24] =
294276bd547bSAdrian Chadd     {
294376bd547bSAdrian Chadd         ALL_TARGET_HT40_0_8_16,
294476bd547bSAdrian Chadd         ALL_TARGET_HT40_1_3_9_11_17_19,
294576bd547bSAdrian Chadd         ALL_TARGET_HT40_1_3_9_11_17_19,
294676bd547bSAdrian Chadd         ALL_TARGET_HT40_1_3_9_11_17_19,
294776bd547bSAdrian Chadd         ALL_TARGET_HT40_4,
294876bd547bSAdrian Chadd         ALL_TARGET_HT40_5,
294976bd547bSAdrian Chadd         ALL_TARGET_HT40_6,
295076bd547bSAdrian Chadd         ALL_TARGET_HT40_7,
295176bd547bSAdrian Chadd         ALL_TARGET_HT40_0_8_16,
295276bd547bSAdrian Chadd         ALL_TARGET_HT40_1_3_9_11_17_19,
295376bd547bSAdrian Chadd         ALL_TARGET_HT40_1_3_9_11_17_19,
295476bd547bSAdrian Chadd         ALL_TARGET_HT40_1_3_9_11_17_19,
295576bd547bSAdrian Chadd         ALL_TARGET_HT40_12,
295676bd547bSAdrian Chadd         ALL_TARGET_HT40_13,
295776bd547bSAdrian Chadd         ALL_TARGET_HT40_14,
295876bd547bSAdrian Chadd         ALL_TARGET_HT40_15,
295976bd547bSAdrian Chadd         ALL_TARGET_HT40_0_8_16,
296076bd547bSAdrian Chadd         ALL_TARGET_HT40_1_3_9_11_17_19,
296176bd547bSAdrian Chadd         ALL_TARGET_HT40_1_3_9_11_17_19,
296276bd547bSAdrian Chadd         ALL_TARGET_HT40_1_3_9_11_17_19,
296376bd547bSAdrian Chadd         ALL_TARGET_HT40_20,
296476bd547bSAdrian Chadd         ALL_TARGET_HT40_21,
296576bd547bSAdrian Chadd         ALL_TARGET_HT40_22,
296676bd547bSAdrian Chadd         ALL_TARGET_HT40_23,
296776bd547bSAdrian Chadd     };
296876bd547bSAdrian Chadd 
296976bd547bSAdrian Chadd     HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
297076bd547bSAdrian Chadd         "%s[%d] +++chan %d,cfgctl 0x%04x  "
297176bd547bSAdrian Chadd         "antenna_reduction 0x%04x, twice_max_regulatory_power 0x%04x "
297276bd547bSAdrian Chadd         "power_limit 0x%04x\n",
2973e113789bSAdrian Chadd         __func__, __LINE__, ichan->channel, cfg_ctl,
297476bd547bSAdrian Chadd         antenna_reduction, twice_max_regulatory_power, power_limit);
2975e113789bSAdrian Chadd     ar9300_set_target_power_from_eeprom(ah, ichan->channel, target_power_val_t2);
297676bd547bSAdrian Chadd 
297776bd547bSAdrian Chadd     if (ar9300_eeprom_get(ahp, EEP_PAPRD_ENABLED)) {
2978e113789bSAdrian Chadd         if (IEEE80211_IS_CHAN_2GHZ(chan)) {
2979e113789bSAdrian Chadd             if (IEEE80211_IS_CHAN_HT40(chan)) {
298076bd547bSAdrian Chadd                 tmp_paprd_rate_mask =
298176bd547bSAdrian Chadd                     p_eep_data->modal_header_2g.paprd_rate_mask_ht40;
298276bd547bSAdrian Chadd                 tmp_ptr = &AH9300(ah)->ah_2g_paprd_rate_mask_ht40;
298376bd547bSAdrian Chadd             } else {
298476bd547bSAdrian Chadd                 tmp_paprd_rate_mask =
298576bd547bSAdrian Chadd                     p_eep_data->modal_header_2g.paprd_rate_mask_ht20;
298676bd547bSAdrian Chadd                 tmp_ptr = &AH9300(ah)->ah_2g_paprd_rate_mask_ht20;
298776bd547bSAdrian Chadd             }
298876bd547bSAdrian Chadd         } else {
2989e113789bSAdrian Chadd             if (IEEE80211_IS_CHAN_HT40(chan)) {
299076bd547bSAdrian Chadd                 tmp_paprd_rate_mask =
299176bd547bSAdrian Chadd                     p_eep_data->modal_header_5g.paprd_rate_mask_ht40;
299276bd547bSAdrian Chadd                 tmp_ptr = &AH9300(ah)->ah_5g_paprd_rate_mask_ht40;
299376bd547bSAdrian Chadd             } else {
299476bd547bSAdrian Chadd                 tmp_paprd_rate_mask =
299576bd547bSAdrian Chadd                     p_eep_data->modal_header_5g.paprd_rate_mask_ht20;
299676bd547bSAdrian Chadd                 tmp_ptr = &AH9300(ah)->ah_5g_paprd_rate_mask_ht20;
299776bd547bSAdrian Chadd             }
299876bd547bSAdrian Chadd         }
299976bd547bSAdrian Chadd         AH_PAPRD_GET_SCALE_FACTOR(
3000e113789bSAdrian Chadd             paprd_scale_factor, p_eep_data, IEEE80211_IS_CHAN_2GHZ(chan), ichan->channel);
300176bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s[%d] paprd_scale_factor %d\n",
300276bd547bSAdrian Chadd             __func__, __LINE__, paprd_scale_factor);
300376bd547bSAdrian Chadd         /* PAPRD is not done yet, Scale down the EEP power */
3004e113789bSAdrian Chadd         if (IEEE80211_IS_CHAN_HT40(chan)) {
300576bd547bSAdrian Chadd             ptr_mcs_rate2power_table_index =
300676bd547bSAdrian Chadd                 &mcs_rate2power_table_index_ht40[0];
300776bd547bSAdrian Chadd         } else {
300876bd547bSAdrian Chadd             ptr_mcs_rate2power_table_index =
300976bd547bSAdrian Chadd                 &mcs_rate2power_table_index_ht20[0];
301076bd547bSAdrian Chadd         }
3011e113789bSAdrian Chadd         if (! ichan->paprd_table_write_done) {
301276bd547bSAdrian Chadd             for (i = 0;  i < 24; i++) {
301376bd547bSAdrian Chadd                 /* PAPRD is done yet, so Scale down Power for PAPRD Rates*/
301476bd547bSAdrian Chadd                 if (tmp_paprd_rate_mask & (1 << i)) {
301576bd547bSAdrian Chadd                     target_power_val_t2[ptr_mcs_rate2power_table_index[i]] -=
301676bd547bSAdrian Chadd                         paprd_scale_factor;
301776bd547bSAdrian Chadd                     HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
301876bd547bSAdrian Chadd                         "%s[%d]: Chan %d "
301976bd547bSAdrian Chadd                         "Scale down target_power_val_t2[%d] = 0x%04x\n",
302076bd547bSAdrian Chadd                         __func__, __LINE__,
3021e113789bSAdrian Chadd                         ichan->channel, i, target_power_val_t2[i]);
302276bd547bSAdrian Chadd                 }
302376bd547bSAdrian Chadd             }
302476bd547bSAdrian Chadd         } else {
302576bd547bSAdrian Chadd             HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
302676bd547bSAdrian Chadd                 "%s[%d]: PAPRD Done No TGT PWR Scaling\n", __func__, __LINE__);
302776bd547bSAdrian Chadd         }
302876bd547bSAdrian Chadd     }
302976bd547bSAdrian Chadd 
303076bd547bSAdrian Chadd     /* Save the Target power for future use */
303176bd547bSAdrian Chadd     OS_MEMCPY(target_power_val_t2_eep, target_power_val_t2,
303276bd547bSAdrian Chadd                                    sizeof(target_power_val_t2));
303376bd547bSAdrian Chadd     ar9300_eeprom_set_power_per_rate_table(ah, p_eep_data, chan,
303476bd547bSAdrian Chadd                                      target_power_val_t2, cfg_ctl,
303576bd547bSAdrian Chadd                                      antenna_reduction,
303676bd547bSAdrian Chadd                                      twice_max_regulatory_power,
303776bd547bSAdrian Chadd                                      power_limit, 0);
303876bd547bSAdrian Chadd 
303976bd547bSAdrian Chadd     /* Save this for quick lookup */
3040e113789bSAdrian Chadd     ahp->reg_dmn = ath_hal_getctl(ah, chan);
304176bd547bSAdrian Chadd 
304276bd547bSAdrian Chadd     /*
30436851341aSAdrian Chadd      * After reading FCC/OET 13TR1003 (Directional Gain of IEEE 802.11
30446851341aSAdrian Chadd      * MIMO devices employing cyclic delay diversity) and looking at what
30456851341aSAdrian Chadd      * ath9k does, let's disable the CDD check until it's clearer exactly
30466851341aSAdrian Chadd      * how the maximum cap should be applied here.
30476851341aSAdrian Chadd      *
30486851341aSAdrian Chadd      * Right now the CDD check is simply unconditionally reducing the
30496851341aSAdrian Chadd      * gain of legacy and 1/2 stream rates depending upon the chainmask.
30506851341aSAdrian Chadd      * (CDD is used when transmitting rates that don't already use up the
30516851341aSAdrian Chadd      * full set of streams - eg OFDM or MCS0-7 on a 2 or 3 chain TX path.)
30526851341aSAdrian Chadd      *
30536851341aSAdrian Chadd      * It's dropping the 2-chain TX by 3dB and 3-chain by 5dB to "meet"
30546851341aSAdrian Chadd      * power spectral density requirements but it's not currently taking
30556851341aSAdrian Chadd      * into account how close to the regulatory limit the hardware/antenna
30566851341aSAdrian Chadd      * system is already at.  It doesn't help that the conductive testing
30576851341aSAdrian Chadd      * limits have the array gain at 0dB for all AR9300/derivative
30586851341aSAdrian Chadd      * configurations.
30596851341aSAdrian Chadd      *
30606851341aSAdrian Chadd      * It also doesn't let us do single chain transmit at the full allowed
30616851341aSAdrian Chadd      * power for the regulatory/CTL limits as it subtracts it from what's
30626851341aSAdrian Chadd      * programmed into the hardware.
30636851341aSAdrian Chadd      *
30646851341aSAdrian Chadd      * ath9k doesn't factor any of the CDD stuff into account, so I'm going
30656851341aSAdrian Chadd      * to disable it here and in the TPC path until I get a better idea
30666851341aSAdrian Chadd      * of what to really do here.
30676851341aSAdrian Chadd      */
30686851341aSAdrian Chadd #if 0
30696851341aSAdrian Chadd     /*
307076bd547bSAdrian Chadd      * Always use CDD/direct per rate power table for register based approach.
307176bd547bSAdrian Chadd      * For FCC, CDD calculations should factor in the array gain, hence
307276bd547bSAdrian Chadd      * this adjust call. ETSI and MKK does not have this requirement.
307376bd547bSAdrian Chadd      */
307476bd547bSAdrian Chadd     if (is_reg_dmn_fcc(ahp->reg_dmn)) {
3075e113789bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
3076e113789bSAdrian Chadd             "%s: FCC regdomain, calling reg_txpower_cdd\n",
3077e113789bSAdrian Chadd             __func__);
307876bd547bSAdrian Chadd         ar9300_adjust_reg_txpower_cdd(ah, target_power_val_t2);
307976bd547bSAdrian Chadd     }
30806851341aSAdrian Chadd #endif
308176bd547bSAdrian Chadd 
308276bd547bSAdrian Chadd     if (ar9300_eeprom_get(ahp, EEP_PAPRD_ENABLED)) {
308376bd547bSAdrian Chadd         for (i = 0;  i < ar9300_rate_size; i++) {
308476bd547bSAdrian Chadd             /*
308576bd547bSAdrian Chadd              * EEPROM TGT PWR is not same as current TGT PWR,
308676bd547bSAdrian Chadd              * so Disable PAPRD for this rate.
308776bd547bSAdrian Chadd              * Some of APs might ask to reduce Target Power,
308876bd547bSAdrian Chadd              * if target power drops significantly,
308976bd547bSAdrian Chadd              * disable PAPRD for that rate.
309076bd547bSAdrian Chadd              */
309176bd547bSAdrian Chadd             if (tmp_paprd_rate_mask & (1 << i)) {
309276bd547bSAdrian Chadd                 if (ABS(target_power_val_t2_eep[i], target_power_val_t2[i]) >
309376bd547bSAdrian Chadd                     paprd_scale_factor)
309476bd547bSAdrian Chadd                 {
309576bd547bSAdrian Chadd                     tmp_paprd_rate_mask &= ~(1 << i);
309676bd547bSAdrian Chadd                     HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
309776bd547bSAdrian Chadd                         "%s: EEP TPC[%02d] 0x%08x "
309876bd547bSAdrian Chadd                         "Curr TPC[%02d] 0x%08x mask = 0x%08x\n",
309976bd547bSAdrian Chadd                         __func__, i, target_power_val_t2_eep[i], i,
310076bd547bSAdrian Chadd                         target_power_val_t2[i], tmp_paprd_rate_mask);
310176bd547bSAdrian Chadd                 }
310276bd547bSAdrian Chadd             }
310376bd547bSAdrian Chadd 
310476bd547bSAdrian Chadd         }
310576bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
310676bd547bSAdrian Chadd             "%s: Chan %d After tmp_paprd_rate_mask = 0x%08x\n",
3107e113789bSAdrian Chadd             __func__, ichan->channel, tmp_paprd_rate_mask);
310876bd547bSAdrian Chadd         if (tmp_ptr) {
310976bd547bSAdrian Chadd             *tmp_ptr = tmp_paprd_rate_mask;
311076bd547bSAdrian Chadd         }
311176bd547bSAdrian Chadd     }
311276bd547bSAdrian Chadd 
311376bd547bSAdrian Chadd     /* Write target power array to registers */
311476bd547bSAdrian Chadd     ar9300_transmit_power_reg_write(ah, target_power_val_t2);
311576bd547bSAdrian Chadd 
311676bd547bSAdrian Chadd     /* Write target power for self generated frames to the TPC register */
311776bd547bSAdrian Chadd     ar9300_selfgen_tpc_reg_write(ah, chan, target_power_val_t2);
311876bd547bSAdrian Chadd 
311976bd547bSAdrian Chadd     /* GreenTx or Paprd */
3120e113789bSAdrian Chadd     if (ah->ah_config.ath_hal_sta_update_tx_pwr_enable ||
3121e113789bSAdrian Chadd         AH_PRIVATE(ah)->ah_caps.halPaprdEnabled)
312276bd547bSAdrian Chadd     {
312376bd547bSAdrian Chadd         if (AR_SREV_POSEIDON(ah)) {
312476bd547bSAdrian Chadd             /*For HAL_RSSI_TX_POWER_NONE array*/
312576bd547bSAdrian Chadd             OS_MEMCPY(ahp->ah_default_tx_power,
312676bd547bSAdrian Chadd                 target_power_val_t2,
312776bd547bSAdrian Chadd                 sizeof(target_power_val_t2));
312876bd547bSAdrian Chadd             /* Get defautl tx related register setting for GreenTx */
312976bd547bSAdrian Chadd             /* Record OB/DB */
3130e113789bSAdrian Chadd             ahp->ah_ob_db1[POSEIDON_STORED_REG_OBDB] =
313176bd547bSAdrian Chadd                 OS_REG_READ(ah, AR_PHY_65NM_CH0_TXRF2);
313276bd547bSAdrian Chadd             /* Record TPC settting */
3133e113789bSAdrian Chadd             ahp->ah_ob_db1[POSEIDON_STORED_REG_TPC] =
313476bd547bSAdrian Chadd                 OS_REG_READ(ah, AR_TPC);
313576bd547bSAdrian Chadd             /* Record BB_powertx_rate9 setting */
3136e113789bSAdrian Chadd             ahp->ah_ob_db1[POSEIDON_STORED_REG_BB_PWRTX_RATE9] =
313776bd547bSAdrian Chadd                 OS_REG_READ(ah, AR_PHY_BB_POWERTX_RATE9);
313876bd547bSAdrian Chadd         }
313976bd547bSAdrian Chadd     }
314076bd547bSAdrian Chadd 
314176bd547bSAdrian Chadd     /*
314276bd547bSAdrian Chadd      * Return tx power used to iwconfig.
314376bd547bSAdrian Chadd      * Since power is rate dependent, use one of the indices from the
314476bd547bSAdrian Chadd      * AR9300_Rates enum to select an entry from target_power_val_t2[]
314576bd547bSAdrian Chadd      * to report.
314676bd547bSAdrian Chadd      * Currently returns the power for HT40 MCS 0, HT20 MCS 0, or OFDM 6 Mbps
314776bd547bSAdrian Chadd      * as CCK power is less interesting (?).
314876bd547bSAdrian Chadd      */
314976bd547bSAdrian Chadd     i = ALL_TARGET_LEGACY_6_24;         /* legacy */
3150e113789bSAdrian Chadd     if (IEEE80211_IS_CHAN_HT40(chan)) {
315176bd547bSAdrian Chadd         i = ALL_TARGET_HT40_0_8_16;     /* ht40 */
3152e113789bSAdrian Chadd     } else if (IEEE80211_IS_CHAN_HT20(chan)) {
315376bd547bSAdrian Chadd         i = ALL_TARGET_HT20_0_8_16;     /* ht20 */
315476bd547bSAdrian Chadd     }
315576bd547bSAdrian Chadd     max_power_level = target_power_val_t2[i];
315676bd547bSAdrian Chadd     /* Adjusting the ah_max_power_level based on chains and antennaGain*/
3157899d1cacSAdrian Chadd     switch (ar9300_get_ntxchains(((ahp->ah_tx_chainmaskopt > 0) ?
3158899d1cacSAdrian Chadd                                     ahp->ah_tx_chainmaskopt : ahp->ah_tx_chainmask)))
315976bd547bSAdrian Chadd     {
316076bd547bSAdrian Chadd         case 1:
316176bd547bSAdrian Chadd             break;
316276bd547bSAdrian Chadd         case 2:
316376bd547bSAdrian Chadd             twice_array_gain = (ahp->twice_antenna_gain >= ahp->twice_antenna_reduction)? 0:
316476bd547bSAdrian Chadd                                ((int16_t)AH_MIN((ahp->twice_antenna_reduction -
316576bd547bSAdrian Chadd                                    (ahp->twice_antenna_gain + INCREASE_MAXPOW_BY_TWO_CHAIN)), 0));
316676bd547bSAdrian Chadd             /* Adjusting maxpower with antennaGain */
316776bd547bSAdrian Chadd             max_power_level -= twice_array_gain;
316876bd547bSAdrian Chadd             /* Adjusting maxpower based on chain */
316976bd547bSAdrian Chadd             max_power_level += INCREASE_MAXPOW_BY_TWO_CHAIN;
317076bd547bSAdrian Chadd             break;
317176bd547bSAdrian Chadd         case 3:
317276bd547bSAdrian Chadd             twice_array_gain = (ahp->twice_antenna_gain >= ahp->twice_antenna_reduction)? 0:
317376bd547bSAdrian Chadd                                ((int16_t)AH_MIN((ahp->twice_antenna_reduction -
317476bd547bSAdrian Chadd                                    (ahp->twice_antenna_gain + INCREASE_MAXPOW_BY_THREE_CHAIN)), 0));
317576bd547bSAdrian Chadd 
317676bd547bSAdrian Chadd             /* Adjusting maxpower with antennaGain */
317776bd547bSAdrian Chadd             max_power_level -= twice_array_gain;
317876bd547bSAdrian Chadd             /* Adjusting maxpower based on chain */
317976bd547bSAdrian Chadd             max_power_level += INCREASE_MAXPOW_BY_THREE_CHAIN;
318076bd547bSAdrian Chadd             break;
318176bd547bSAdrian Chadd         default:
318276bd547bSAdrian Chadd             HALASSERT(0); /* Unsupported number of chains */
318376bd547bSAdrian Chadd     }
3184e113789bSAdrian Chadd     AH_PRIVATE(ah)->ah_maxPowerLevel = (int8_t)max_power_level;
318576bd547bSAdrian Chadd 
3186e113789bSAdrian Chadd     ar9300_calibration_apply(ah, ichan->channel);
318776bd547bSAdrian Chadd #undef ABS
318876bd547bSAdrian Chadd 
318976bd547bSAdrian Chadd     /* Handle per packet TPC initializations */
3190e113789bSAdrian Chadd     if (ah->ah_config.ath_hal_desc_tpc) {
319176bd547bSAdrian Chadd         /* Transmit Power per-rate per-chain  are  computed here. A separate
319276bd547bSAdrian Chadd          * power table is maintained for different MIMO modes (i.e. TXBF ON,
319376bd547bSAdrian Chadd          * STBC) to enable easy lookup during packet transmit.
319476bd547bSAdrian Chadd          * The reason for maintaing each of these tables per chain is that
319576bd547bSAdrian Chadd          * the transmit power used for different number of chains is different
319676bd547bSAdrian Chadd          * depending on whether the power has been limited by the target power,
319776bd547bSAdrian Chadd          * the regulatory domain  or the CTL limits.
319876bd547bSAdrian Chadd          */
319976bd547bSAdrian Chadd         u_int mode = ath_hal_get_curmode(ah, chan);
320076bd547bSAdrian Chadd         u_int32_t val = 0;
320176bd547bSAdrian Chadd         u_int8_t chainmasks[AR9300_MAX_CHAINS] =
320276bd547bSAdrian Chadd             {OSPREY_1_CHAINMASK, OSPREY_2LOHI_CHAINMASK, OSPREY_3_CHAINMASK};
320376bd547bSAdrian Chadd         for (i = 0; i < AR9300_MAX_CHAINS; i++) {
320476bd547bSAdrian Chadd             OS_MEMCPY(target_power_val_t2, target_power_val_t2_eep,
320576bd547bSAdrian Chadd                                    sizeof(target_power_val_t2_eep));
320676bd547bSAdrian Chadd             ar9300_eeprom_set_power_per_rate_table(ah, p_eep_data, chan,
320776bd547bSAdrian Chadd                                      target_power_val_t2, cfg_ctl,
320876bd547bSAdrian Chadd                                      antenna_reduction,
320976bd547bSAdrian Chadd                                      twice_max_regulatory_power,
321076bd547bSAdrian Chadd                                      power_limit, chainmasks[i]);
321176bd547bSAdrian Chadd             HALDEBUG(ah, HAL_DEBUG_POWER_MGMT,
321276bd547bSAdrian Chadd                  " Channel = %d Chainmask = %d, Upper Limit = [%2d.%1d dBm]\n",
3213e113789bSAdrian Chadd                                        ichan->channel, i, ahp->upper_limit[i]/2,
321476bd547bSAdrian Chadd                                        ahp->upper_limit[i]%2 * 5);
321576bd547bSAdrian Chadd             ar9300_init_rate_txpower(ah, mode, chan, target_power_val_t2,
321676bd547bSAdrian Chadd                                                            chainmasks[i]);
321776bd547bSAdrian Chadd 
321876bd547bSAdrian Chadd         }
321976bd547bSAdrian Chadd 
322076bd547bSAdrian Chadd         /* Enable TPC */
322176bd547bSAdrian Chadd         OS_REG_WRITE(ah, AR_PHY_PWRTX_MAX, AR_PHY_PWRTX_MAX_TPC_ENABLE);
322276bd547bSAdrian Chadd         /*
322376bd547bSAdrian Chadd          * Disable per chain power reduction since we are already
322476bd547bSAdrian Chadd          * accounting for this in our calculations
322576bd547bSAdrian Chadd          */
322676bd547bSAdrian Chadd         val = OS_REG_READ(ah, AR_PHY_POWER_TX_SUB);
322776bd547bSAdrian Chadd         if (AR_SREV_WASP(ah)) {
322876bd547bSAdrian Chadd             OS_REG_WRITE(ah, AR_PHY_POWER_TX_SUB,
322976bd547bSAdrian Chadd                        val & AR_PHY_POWER_TX_SUB_2_DISABLE);
323076bd547bSAdrian Chadd         } else {
323176bd547bSAdrian Chadd             OS_REG_WRITE(ah, AR_PHY_POWER_TX_SUB,
323276bd547bSAdrian Chadd                        val & AR_PHY_POWER_TX_SUB_3_DISABLE);
323376bd547bSAdrian Chadd         }
323476bd547bSAdrian Chadd     }
323576bd547bSAdrian Chadd 
323676bd547bSAdrian Chadd     return HAL_OK;
323776bd547bSAdrian Chadd }
323876bd547bSAdrian Chadd 
323976bd547bSAdrian Chadd /**************************************************************
324076bd547bSAdrian Chadd  * ar9300_eeprom_set_addac
324176bd547bSAdrian Chadd  *
324276bd547bSAdrian Chadd  * Set the ADDAC from eeprom.
324376bd547bSAdrian Chadd  */
324476bd547bSAdrian Chadd void
ar9300_eeprom_set_addac(struct ath_hal * ah,struct ieee80211_channel * chan)3245e113789bSAdrian Chadd ar9300_eeprom_set_addac(struct ath_hal *ah, struct ieee80211_channel *chan)
324676bd547bSAdrian Chadd {
324776bd547bSAdrian Chadd 
324876bd547bSAdrian Chadd     HALDEBUG(AH_NULL, HAL_DEBUG_UNMASKABLE,
324976bd547bSAdrian Chadd                  "FIXME: ar9300_eeprom_def_set_addac called\n");
325076bd547bSAdrian Chadd #if 0
325176bd547bSAdrian Chadd     MODAL_EEPDEF_HEADER *p_modal;
325276bd547bSAdrian Chadd     struct ath_hal_9300 *ahp = AH9300(ah);
325376bd547bSAdrian Chadd     ar9300_eeprom_t *eep = &ahp->ah_eeprom.def;
325476bd547bSAdrian Chadd     u_int8_t biaslevel;
325576bd547bSAdrian Chadd 
325676bd547bSAdrian Chadd     if (AH_PRIVATE(ah)->ah_macVersion != AR_SREV_VERSION_SOWL) {
325776bd547bSAdrian Chadd         return;
325876bd547bSAdrian Chadd     }
325976bd547bSAdrian Chadd 
326076bd547bSAdrian Chadd     HALASSERT(owl_get_eepdef_ver(ahp) == AR9300_EEP_VER);
326176bd547bSAdrian Chadd 
326276bd547bSAdrian Chadd     /* Xpa bias levels in eeprom are valid from rev 14.7 */
326376bd547bSAdrian Chadd     if (owl_get_eepdef_rev(ahp) < AR9300_EEP_MINOR_VER_7) {
326476bd547bSAdrian Chadd         return;
326576bd547bSAdrian Chadd     }
326676bd547bSAdrian Chadd 
326776bd547bSAdrian Chadd     if (ahp->ah_emu_eeprom) {
326876bd547bSAdrian Chadd         return;
326976bd547bSAdrian Chadd     }
327076bd547bSAdrian Chadd 
3271e113789bSAdrian Chadd     p_modal = &(eep->modal_header[IEEE80211_IS_CHAN_2GHZ(chan)]);
327276bd547bSAdrian Chadd 
327376bd547bSAdrian Chadd     if (p_modal->xpa_bias_lvl != 0xff) {
327476bd547bSAdrian Chadd         biaslevel = p_modal->xpa_bias_lvl;
327576bd547bSAdrian Chadd     } else {
327676bd547bSAdrian Chadd         /* Use freqeuncy specific xpa bias level */
327776bd547bSAdrian Chadd         u_int16_t reset_freq_bin, freq_bin, freq_count = 0;
327876bd547bSAdrian Chadd         CHAN_CENTERS centers;
327976bd547bSAdrian Chadd 
328076bd547bSAdrian Chadd         ar9300_get_channel_centers(ah, chan, &centers);
328176bd547bSAdrian Chadd 
3282e113789bSAdrian Chadd         reset_freq_bin = FREQ2FBIN(centers.synth_center, IEEE80211_IS_CHAN_2GHZ(chan));
328376bd547bSAdrian Chadd         freq_bin = p_modal->xpa_bias_lvl_freq[0] & 0xff;
328476bd547bSAdrian Chadd         biaslevel = (u_int8_t)(p_modal->xpa_bias_lvl_freq[0] >> 14);
328576bd547bSAdrian Chadd 
328676bd547bSAdrian Chadd         freq_count++;
328776bd547bSAdrian Chadd 
328876bd547bSAdrian Chadd         while (freq_count < 3) {
328976bd547bSAdrian Chadd             if (p_modal->xpa_bias_lvl_freq[freq_count] == 0x0) {
329076bd547bSAdrian Chadd                 break;
329176bd547bSAdrian Chadd             }
329276bd547bSAdrian Chadd 
329376bd547bSAdrian Chadd             freq_bin = p_modal->xpa_bias_lvl_freq[freq_count] & 0xff;
329476bd547bSAdrian Chadd             if (reset_freq_bin >= freq_bin) {
329576bd547bSAdrian Chadd                 biaslevel =
329676bd547bSAdrian Chadd                     (u_int8_t)(p_modal->xpa_bias_lvl_freq[freq_count] >> 14);
329776bd547bSAdrian Chadd             } else {
329876bd547bSAdrian Chadd                 break;
329976bd547bSAdrian Chadd             }
330076bd547bSAdrian Chadd             freq_count++;
330176bd547bSAdrian Chadd         }
330276bd547bSAdrian Chadd     }
330376bd547bSAdrian Chadd 
330476bd547bSAdrian Chadd     /* Apply bias level to the ADDAC values in the INI array */
3305e113789bSAdrian Chadd     if (IEEE80211_IS_CHAN_2GHZ(chan)) {
330676bd547bSAdrian Chadd         INI_RA(&ahp->ah_ini_addac, 7, 1) =
330776bd547bSAdrian Chadd             (INI_RA(&ahp->ah_ini_addac, 7, 1) & (~0x18)) | biaslevel << 3;
330876bd547bSAdrian Chadd     } else {
330976bd547bSAdrian Chadd         INI_RA(&ahp->ah_ini_addac, 6, 1) =
331076bd547bSAdrian Chadd             (INI_RA(&ahp->ah_ini_addac, 6, 1) & (~0xc0)) | biaslevel << 6;
331176bd547bSAdrian Chadd     }
331276bd547bSAdrian Chadd #endif
331376bd547bSAdrian Chadd }
331476bd547bSAdrian Chadd 
331576bd547bSAdrian Chadd u_int
ar9300_eeprom_dump_support(struct ath_hal * ah,void ** pp_e)331676bd547bSAdrian Chadd ar9300_eeprom_dump_support(struct ath_hal *ah, void **pp_e)
331776bd547bSAdrian Chadd {
331876bd547bSAdrian Chadd     *pp_e = &(AH9300(ah)->ah_eeprom);
331976bd547bSAdrian Chadd     return sizeof(ar9300_eeprom_t);
332076bd547bSAdrian Chadd }
332176bd547bSAdrian Chadd 
332276bd547bSAdrian Chadd u_int8_t
ar9300_eeprom_get_num_ant_config(struct ath_hal_9300 * ahp,HAL_FREQ_BAND freq_band)332376bd547bSAdrian Chadd ar9300_eeprom_get_num_ant_config(struct ath_hal_9300 *ahp,
332476bd547bSAdrian Chadd     HAL_FREQ_BAND freq_band)
332576bd547bSAdrian Chadd {
332676bd547bSAdrian Chadd #if 0
332776bd547bSAdrian Chadd     ar9300_eeprom_t  *eep = &ahp->ah_eeprom.def;
332876bd547bSAdrian Chadd     MODAL_EEPDEF_HEADER *p_modal =
332976bd547bSAdrian Chadd         &(eep->modal_header[HAL_FREQ_BAND_2GHZ == freq_band]);
333076bd547bSAdrian Chadd     BASE_EEPDEF_HEADER  *p_base  = &eep->base_eep_header;
333176bd547bSAdrian Chadd     u_int8_t         num_ant_config;
333276bd547bSAdrian Chadd 
333376bd547bSAdrian Chadd     num_ant_config = 1; /* default antenna configuration */
333476bd547bSAdrian Chadd 
333576bd547bSAdrian Chadd     if (p_base->version >= 0x0E0D) {
333676bd547bSAdrian Chadd         if (p_modal->use_ant1) {
333776bd547bSAdrian Chadd             num_ant_config += 1;
333876bd547bSAdrian Chadd         }
333976bd547bSAdrian Chadd     }
334076bd547bSAdrian Chadd 
334176bd547bSAdrian Chadd     return num_ant_config;
334276bd547bSAdrian Chadd #else
334376bd547bSAdrian Chadd     return 1;
334476bd547bSAdrian Chadd #endif
334576bd547bSAdrian Chadd }
334676bd547bSAdrian Chadd 
334776bd547bSAdrian Chadd HAL_STATUS
ar9300_eeprom_get_ant_cfg(struct ath_hal_9300 * ahp,const struct ieee80211_channel * chan,u_int8_t index,u_int16_t * config)3348e113789bSAdrian Chadd ar9300_eeprom_get_ant_cfg(struct ath_hal_9300 *ahp,
3349e113789bSAdrian Chadd   const struct ieee80211_channel *chan,
335076bd547bSAdrian Chadd   u_int8_t index, u_int16_t *config)
335176bd547bSAdrian Chadd {
335276bd547bSAdrian Chadd #if 0
335376bd547bSAdrian Chadd     ar9300_eeprom_t  *eep = &ahp->ah_eeprom.def;
3354e113789bSAdrian Chadd     MODAL_EEPDEF_HEADER *p_modal = &(eep->modal_header[IEEE80211_IS_CHAN_2GHZ(chan)]);
335576bd547bSAdrian Chadd     BASE_EEPDEF_HEADER  *p_base  = &eep->base_eep_header;
335676bd547bSAdrian Chadd 
335776bd547bSAdrian Chadd     switch (index) {
335876bd547bSAdrian Chadd     case 0:
335976bd547bSAdrian Chadd         *config = p_modal->ant_ctrl_common & 0xFFFF;
336076bd547bSAdrian Chadd         return HAL_OK;
336176bd547bSAdrian Chadd     case 1:
336276bd547bSAdrian Chadd         if (p_base->version >= 0x0E0D) {
336376bd547bSAdrian Chadd             if (p_modal->use_ant1) {
336476bd547bSAdrian Chadd                 *config = ((p_modal->ant_ctrl_common & 0xFFFF0000) >> 16);
336576bd547bSAdrian Chadd                 return HAL_OK;
336676bd547bSAdrian Chadd             }
336776bd547bSAdrian Chadd         }
336876bd547bSAdrian Chadd         break;
336976bd547bSAdrian Chadd     default:
337076bd547bSAdrian Chadd         break;
337176bd547bSAdrian Chadd     }
337276bd547bSAdrian Chadd #endif
337376bd547bSAdrian Chadd     return HAL_EINVAL;
337476bd547bSAdrian Chadd }
337576bd547bSAdrian Chadd 
337676bd547bSAdrian Chadd u_int8_t*
ar9300_eeprom_get_cust_data(struct ath_hal_9300 * ahp)337776bd547bSAdrian Chadd ar9300_eeprom_get_cust_data(struct ath_hal_9300 *ahp)
337876bd547bSAdrian Chadd {
337976bd547bSAdrian Chadd     return (u_int8_t *)ahp;
338076bd547bSAdrian Chadd }
338176bd547bSAdrian Chadd 
338276bd547bSAdrian Chadd #ifdef UNUSED
338376bd547bSAdrian Chadd static inline HAL_STATUS
ar9300_check_eeprom(struct ath_hal * ah)338476bd547bSAdrian Chadd ar9300_check_eeprom(struct ath_hal *ah)
338576bd547bSAdrian Chadd {
338676bd547bSAdrian Chadd #if 0
338776bd547bSAdrian Chadd     u_int32_t sum = 0, el;
338876bd547bSAdrian Chadd     u_int16_t *eepdata;
338976bd547bSAdrian Chadd     int i;
339076bd547bSAdrian Chadd     struct ath_hal_9300 *ahp = AH9300(ah);
339176bd547bSAdrian Chadd     HAL_BOOL need_swap = AH_FALSE;
339276bd547bSAdrian Chadd     ar9300_eeprom_t *eep = (ar9300_eeprom_t *)&ahp->ah_eeprom.def;
339376bd547bSAdrian Chadd     u_int16_t magic, magic2;
339476bd547bSAdrian Chadd     int addr;
339576bd547bSAdrian Chadd     u_int16_t temp;
339676bd547bSAdrian Chadd 
339776bd547bSAdrian Chadd     /*
339876bd547bSAdrian Chadd     ** We need to check the EEPROM data regardless of if it's in flash or
339976bd547bSAdrian Chadd     ** in EEPROM.
340076bd547bSAdrian Chadd     */
340176bd547bSAdrian Chadd 
340276bd547bSAdrian Chadd     if (!ahp->ah_priv.priv.ah_eeprom_read(
340376bd547bSAdrian Chadd             ah, AR9300_EEPROM_MAGIC_OFFSET, &magic))
340476bd547bSAdrian Chadd     {
340576bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_EEPROM, "%s: Reading Magic # failed\n", __func__);
340676bd547bSAdrian Chadd         return AH_FALSE;
340776bd547bSAdrian Chadd     }
340876bd547bSAdrian Chadd 
340976bd547bSAdrian Chadd     HALDEBUG(ah, HAL_DEBUG_EEPROM, "%s: Read Magic = 0x%04X\n", __func__, magic);
341076bd547bSAdrian Chadd 
341176bd547bSAdrian Chadd     if (!ar9300_eep_data_in_flash(ah)) {
341276bd547bSAdrian Chadd 
341376bd547bSAdrian Chadd         if (magic != AR9300_EEPROM_MAGIC) {
341476bd547bSAdrian Chadd             magic2 = SWAP16(magic);
341576bd547bSAdrian Chadd 
341676bd547bSAdrian Chadd             if (magic2 == AR9300_EEPROM_MAGIC) {
341776bd547bSAdrian Chadd                 need_swap = AH_TRUE;
341876bd547bSAdrian Chadd                 eepdata = (u_int16_t *)(&ahp->ah_eeprom);
341976bd547bSAdrian Chadd 
342076bd547bSAdrian Chadd                 for (addr = 0;
342176bd547bSAdrian Chadd                      addr < sizeof(ar9300_eeprom_t) / sizeof(u_int16_t);
342276bd547bSAdrian Chadd                      addr++)
342376bd547bSAdrian Chadd                 {
342476bd547bSAdrian Chadd                     temp = SWAP16(*eepdata);
342576bd547bSAdrian Chadd                     *eepdata = temp;
342676bd547bSAdrian Chadd                     eepdata++;
342776bd547bSAdrian Chadd 
342876bd547bSAdrian Chadd                     HALDEBUG(ah, HAL_DEBUG_EEPROM_DUMP, "0x%04X  ", *eepdata);
342976bd547bSAdrian Chadd                     if (((addr + 1) % 6) == 0) {
343076bd547bSAdrian Chadd                         HALDEBUG(ah, HAL_DEBUG_EEPROM_DUMP, "\n");
343176bd547bSAdrian Chadd                     }
343276bd547bSAdrian Chadd                 }
343376bd547bSAdrian Chadd             } else {
343476bd547bSAdrian Chadd                 HALDEBUG(ah, HAL_DEBUG_EEPROM,
343576bd547bSAdrian Chadd                     "Invalid EEPROM Magic. endianness missmatch.\n");
343676bd547bSAdrian Chadd                 return HAL_EEBADSUM;
343776bd547bSAdrian Chadd             }
343876bd547bSAdrian Chadd         }
343976bd547bSAdrian Chadd     } else {
344076bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_EEPROM,
344176bd547bSAdrian Chadd                  "EEPROM being read from flash @0x%p\n", AH_PRIVATE(ah)->ah_st);
344276bd547bSAdrian Chadd     }
344376bd547bSAdrian Chadd 
344476bd547bSAdrian Chadd     HALDEBUG(ah, HAL_DEBUG_EEPROM, "need_swap = %s.\n", need_swap?"True":"False");
344576bd547bSAdrian Chadd 
344676bd547bSAdrian Chadd     if (need_swap) {
344776bd547bSAdrian Chadd         el = SWAP16(ahp->ah_eeprom.def.base_eep_header.length);
344876bd547bSAdrian Chadd     } else {
344976bd547bSAdrian Chadd         el = ahp->ah_eeprom.def.base_eep_header.length;
345076bd547bSAdrian Chadd     }
345176bd547bSAdrian Chadd 
345276bd547bSAdrian Chadd     eepdata = (u_int16_t *)(&ahp->ah_eeprom.def);
345376bd547bSAdrian Chadd     for (i = 0;
345476bd547bSAdrian Chadd          i < AH_MIN(el, sizeof(ar9300_eeprom_t)) / sizeof(u_int16_t);
345576bd547bSAdrian Chadd          i++) {
345676bd547bSAdrian Chadd         sum ^= *eepdata++;
345776bd547bSAdrian Chadd     }
345876bd547bSAdrian Chadd 
345976bd547bSAdrian Chadd     if (need_swap) {
346076bd547bSAdrian Chadd         /*
346176bd547bSAdrian Chadd         *  preddy: EEPROM endianness does not match. So change it
346276bd547bSAdrian Chadd         *  8bit values in eeprom data structure does not need to be swapped
346376bd547bSAdrian Chadd         *  Only >8bits (16 & 32) values need to be swapped
346476bd547bSAdrian Chadd         *  If a new 16 or 32 bit field is added to the EEPROM contents,
346576bd547bSAdrian Chadd         *  please make sure to swap the field here
346676bd547bSAdrian Chadd         */
346776bd547bSAdrian Chadd         u_int32_t integer, j;
346876bd547bSAdrian Chadd         u_int16_t word;
346976bd547bSAdrian Chadd 
347076bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_EEPROM,
347176bd547bSAdrian Chadd             "EEPROM Endianness is not native.. Changing \n");
347276bd547bSAdrian Chadd 
347376bd547bSAdrian Chadd         /* convert Base Eep header */
347476bd547bSAdrian Chadd         word = SWAP16(eep->base_eep_header.length);
347576bd547bSAdrian Chadd         eep->base_eep_header.length = word;
347676bd547bSAdrian Chadd 
347776bd547bSAdrian Chadd         word = SWAP16(eep->base_eep_header.checksum);
347876bd547bSAdrian Chadd         eep->base_eep_header.checksum = word;
347976bd547bSAdrian Chadd 
348076bd547bSAdrian Chadd         word = SWAP16(eep->base_eep_header.version);
348176bd547bSAdrian Chadd         eep->base_eep_header.version = word;
348276bd547bSAdrian Chadd 
348376bd547bSAdrian Chadd         word = SWAP16(eep->base_eep_header.reg_dmn[0]);
348476bd547bSAdrian Chadd         eep->base_eep_header.reg_dmn[0] = word;
348576bd547bSAdrian Chadd 
348676bd547bSAdrian Chadd         word = SWAP16(eep->base_eep_header.reg_dmn[1]);
348776bd547bSAdrian Chadd         eep->base_eep_header.reg_dmn[1] = word;
348876bd547bSAdrian Chadd 
348976bd547bSAdrian Chadd         word = SWAP16(eep->base_eep_header.rf_silent);
349076bd547bSAdrian Chadd         eep->base_eep_header.rf_silent = word;
349176bd547bSAdrian Chadd 
349276bd547bSAdrian Chadd         word = SWAP16(eep->base_eep_header.blue_tooth_options);
349376bd547bSAdrian Chadd         eep->base_eep_header.blue_tooth_options = word;
349476bd547bSAdrian Chadd 
349576bd547bSAdrian Chadd         word = SWAP16(eep->base_eep_header.device_cap);
349676bd547bSAdrian Chadd         eep->base_eep_header.device_cap = word;
349776bd547bSAdrian Chadd 
349876bd547bSAdrian Chadd         /* convert Modal Eep header */
349976bd547bSAdrian Chadd         for (j = 0; j < ARRAY_LENGTH(eep->modal_header); j++) {
350076bd547bSAdrian Chadd             MODAL_EEPDEF_HEADER *p_modal = &eep->modal_header[j];
350176bd547bSAdrian Chadd             integer = SWAP32(p_modal->ant_ctrl_common);
350276bd547bSAdrian Chadd             p_modal->ant_ctrl_common = integer;
350376bd547bSAdrian Chadd 
350476bd547bSAdrian Chadd             for (i = 0; i < AR9300_MAX_CHAINS; i++) {
350576bd547bSAdrian Chadd                 integer = SWAP32(p_modal->ant_ctrl_chain[i]);
350676bd547bSAdrian Chadd                 p_modal->ant_ctrl_chain[i] = integer;
350776bd547bSAdrian Chadd             }
350876bd547bSAdrian Chadd 
350976bd547bSAdrian Chadd             for (i = 0; i < AR9300_EEPROM_MODAL_SPURS; i++) {
351076bd547bSAdrian Chadd                 word = SWAP16(p_modal->spur_chans[i].spur_chan);
351176bd547bSAdrian Chadd                 p_modal->spur_chans[i].spur_chan = word;
351276bd547bSAdrian Chadd             }
351376bd547bSAdrian Chadd         }
351476bd547bSAdrian Chadd     }
351576bd547bSAdrian Chadd 
351676bd547bSAdrian Chadd     /* Check CRC - Attach should fail on a bad checksum */
351776bd547bSAdrian Chadd     if (sum != 0xffff || owl_get_eepdef_ver(ahp) != AR9300_EEP_VER ||
351876bd547bSAdrian Chadd         owl_get_eepdef_rev(ahp) < AR9300_EEP_NO_BACK_VER) {
351976bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_EEPROM,
352076bd547bSAdrian Chadd             "Bad EEPROM checksum 0x%x or revision 0x%04x\n",
352176bd547bSAdrian Chadd             sum, owl_get_eepdef_ver(ahp));
352276bd547bSAdrian Chadd         return HAL_EEBADSUM;
352376bd547bSAdrian Chadd     }
352476bd547bSAdrian Chadd #ifdef EEPROM_DUMP
352576bd547bSAdrian Chadd     ar9300_eeprom_def_dump(ah, eep);
352676bd547bSAdrian Chadd #endif
352776bd547bSAdrian Chadd 
352876bd547bSAdrian Chadd #if 0
352976bd547bSAdrian Chadd #ifdef AH_AR9300_OVRD_TGT_PWR
353076bd547bSAdrian Chadd 
353176bd547bSAdrian Chadd     /*
353276bd547bSAdrian Chadd      * 14.4 EEPROM contains low target powers.
353376bd547bSAdrian Chadd      * Hardcode until EEPROM > 14.4
353476bd547bSAdrian Chadd      */
353576bd547bSAdrian Chadd     if (owl_get_eepdef_ver(ahp) == 14 && owl_get_eepdef_rev(ahp) <= 4) {
353676bd547bSAdrian Chadd         MODAL_EEPDEF_HEADER *p_modal;
353776bd547bSAdrian Chadd 
353876bd547bSAdrian Chadd #ifdef EEPROM_DUMP
353976bd547bSAdrian Chadd         HALDEBUG(ah,  HAL_DEBUG_POWER_OVERRIDE, "Original Target Powers\n");
354076bd547bSAdrian Chadd         ar9300_eep_def_dump_tgt_power(ah, eep);
354176bd547bSAdrian Chadd #endif
354276bd547bSAdrian Chadd         HALDEBUG(ah,  HAL_DEBUG_POWER_OVERRIDE,
354376bd547bSAdrian Chadd                 "Override Target Powers. EEPROM Version is %d.%d, "
354476bd547bSAdrian Chadd                 "Device Type %d\n",
354576bd547bSAdrian Chadd                 owl_get_eepdef_ver(ahp),
354676bd547bSAdrian Chadd                 owl_get_eepdef_rev(ahp),
354776bd547bSAdrian Chadd                 eep->base_eep_header.device_type);
354876bd547bSAdrian Chadd 
354976bd547bSAdrian Chadd 
355076bd547bSAdrian Chadd         ar9300_eep_def_override_tgt_power(ah, eep);
355176bd547bSAdrian Chadd 
355276bd547bSAdrian Chadd         if (eep->base_eep_header.device_type == 5) {
355376bd547bSAdrian Chadd             /* for xb72 only: improve transmit EVM for interop */
355476bd547bSAdrian Chadd             p_modal = &eep->modal_header[1];
355576bd547bSAdrian Chadd             p_modal->tx_frame_to_data_start = 0x23;
355676bd547bSAdrian Chadd             p_modal->tx_frame_to_xpa_on = 0x23;
355776bd547bSAdrian Chadd             p_modal->tx_frame_to_pa_on = 0x23;
355876bd547bSAdrian Chadd     }
355976bd547bSAdrian Chadd 
356076bd547bSAdrian Chadd #ifdef EEPROM_DUMP
356176bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_POWER_OVERRIDE, "Modified Target Powers\n");
356276bd547bSAdrian Chadd         ar9300_eep_def_dump_tgt_power(ah, eep);
356376bd547bSAdrian Chadd #endif
356476bd547bSAdrian Chadd         }
356576bd547bSAdrian Chadd #endif /* AH_AR9300_OVRD_TGT_PWR */
356676bd547bSAdrian Chadd #endif
356776bd547bSAdrian Chadd #endif
356876bd547bSAdrian Chadd     return HAL_OK;
356976bd547bSAdrian Chadd }
357076bd547bSAdrian Chadd #endif
357176bd547bSAdrian Chadd 
357276bd547bSAdrian Chadd static u_int16_t
ar9300_eeprom_get_spur_chan(struct ath_hal * ah,int i,HAL_BOOL is_2ghz)3573e113789bSAdrian Chadd ar9300_eeprom_get_spur_chan(struct ath_hal *ah, int i, HAL_BOOL is_2ghz)
357476bd547bSAdrian Chadd {
357576bd547bSAdrian Chadd     u_int16_t   spur_val = AR_NO_SPUR;
357676bd547bSAdrian Chadd #if 0
357776bd547bSAdrian Chadd     struct ath_hal_9300 *ahp = AH9300(ah);
357876bd547bSAdrian Chadd     ar9300_eeprom_t *eep = (ar9300_eeprom_t *)&ahp->ah_eeprom;
357976bd547bSAdrian Chadd 
358076bd547bSAdrian Chadd     HALASSERT(i <  AR_EEPROM_MODAL_SPURS );
358176bd547bSAdrian Chadd 
358276bd547bSAdrian Chadd     HALDEBUG(ah, HAL_DEBUG_ANI,
358376bd547bSAdrian Chadd              "Getting spur idx %d is2Ghz. %d val %x\n",
358476bd547bSAdrian Chadd              i, is_2ghz,
358576bd547bSAdrian Chadd              AH_PRIVATE(ah)->ah_config.ath_hal_spur_chans[i][is_2ghz]);
358676bd547bSAdrian Chadd 
358776bd547bSAdrian Chadd     switch (AH_PRIVATE(ah)->ah_config.ath_hal_spur_mode) {
358876bd547bSAdrian Chadd     case SPUR_DISABLE:
358976bd547bSAdrian Chadd         /* returns AR_NO_SPUR */
359076bd547bSAdrian Chadd         break;
359176bd547bSAdrian Chadd     case SPUR_ENABLE_IOCTL:
359276bd547bSAdrian Chadd         spur_val = AH_PRIVATE(ah)->ah_config.ath_hal_spur_chans[i][is_2ghz];
359376bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_ANI,
359476bd547bSAdrian Chadd             "Getting spur val from new loc. %d\n", spur_val);
359576bd547bSAdrian Chadd         break;
359676bd547bSAdrian Chadd     case SPUR_ENABLE_EEPROM:
359776bd547bSAdrian Chadd         spur_val = eep->modal_header[is_2ghz].spur_chans[i].spur_chan;
359876bd547bSAdrian Chadd         break;
359976bd547bSAdrian Chadd 
360076bd547bSAdrian Chadd     }
360176bd547bSAdrian Chadd #endif
360276bd547bSAdrian Chadd     return spur_val;
360376bd547bSAdrian Chadd }
360476bd547bSAdrian Chadd 
360576bd547bSAdrian Chadd #ifdef UNUSED
360676bd547bSAdrian Chadd static inline HAL_BOOL
ar9300_fill_eeprom(struct ath_hal * ah)360776bd547bSAdrian Chadd ar9300_fill_eeprom(struct ath_hal *ah)
360876bd547bSAdrian Chadd {
360976bd547bSAdrian Chadd     return ar9300_eeprom_restore(ah);
361076bd547bSAdrian Chadd }
361176bd547bSAdrian Chadd #endif
361276bd547bSAdrian Chadd 
361376bd547bSAdrian Chadd u_int16_t
ar9300_eeprom_struct_size(void)361476bd547bSAdrian Chadd ar9300_eeprom_struct_size(void)
361576bd547bSAdrian Chadd {
361676bd547bSAdrian Chadd     return sizeof(ar9300_eeprom_t);
361776bd547bSAdrian Chadd }
361876bd547bSAdrian Chadd 
ar9300_eeprom_struct_default_many(void)361976bd547bSAdrian Chadd int ar9300_eeprom_struct_default_many(void)
362076bd547bSAdrian Chadd {
362176bd547bSAdrian Chadd     return ARRAY_LENGTH(default9300);
362276bd547bSAdrian Chadd }
362376bd547bSAdrian Chadd 
362476bd547bSAdrian Chadd 
362576bd547bSAdrian Chadd ar9300_eeprom_t *
ar9300_eeprom_struct_default(int default_index)362676bd547bSAdrian Chadd ar9300_eeprom_struct_default(int default_index)
362776bd547bSAdrian Chadd {
362876bd547bSAdrian Chadd     if (default_index >= 0 &&
362976bd547bSAdrian Chadd         default_index < ARRAY_LENGTH(default9300))
363076bd547bSAdrian Chadd     {
363176bd547bSAdrian Chadd         return default9300[default_index];
363276bd547bSAdrian Chadd     } else {
363376bd547bSAdrian Chadd         return 0;
363476bd547bSAdrian Chadd     }
363576bd547bSAdrian Chadd }
363676bd547bSAdrian Chadd 
363776bd547bSAdrian Chadd ar9300_eeprom_t *
ar9300_eeprom_struct_default_find_by_id(int id)363876bd547bSAdrian Chadd ar9300_eeprom_struct_default_find_by_id(int id)
363976bd547bSAdrian Chadd {
364076bd547bSAdrian Chadd     int it;
364176bd547bSAdrian Chadd 
364276bd547bSAdrian Chadd     for (it = 0; it < ARRAY_LENGTH(default9300); it++) {
364376bd547bSAdrian Chadd         if (default9300[it] != 0 && default9300[it]->template_version == id) {
364476bd547bSAdrian Chadd             return default9300[it];
364576bd547bSAdrian Chadd         }
364676bd547bSAdrian Chadd     }
364776bd547bSAdrian Chadd     return 0;
364876bd547bSAdrian Chadd }
364976bd547bSAdrian Chadd 
365076bd547bSAdrian Chadd 
365176bd547bSAdrian Chadd HAL_BOOL
ar9300_calibration_data_read_flash(struct ath_hal * ah,long address,u_int8_t * buffer,int many)365276bd547bSAdrian Chadd ar9300_calibration_data_read_flash(struct ath_hal *ah, long address,
365376bd547bSAdrian Chadd     u_int8_t *buffer, int many)
365476bd547bSAdrian Chadd {
365576bd547bSAdrian Chadd 
365676bd547bSAdrian Chadd     if (((address) < 0) || ((address + many) > AR9300_EEPROM_SIZE - 1)) {
365776bd547bSAdrian Chadd         return AH_FALSE;
365876bd547bSAdrian Chadd     }
365976bd547bSAdrian Chadd     return AH_FALSE;
366076bd547bSAdrian Chadd }
366176bd547bSAdrian Chadd 
366276bd547bSAdrian Chadd HAL_BOOL
ar9300_calibration_data_read_eeprom(struct ath_hal * ah,long address,u_int8_t * buffer,int many)366376bd547bSAdrian Chadd ar9300_calibration_data_read_eeprom(struct ath_hal *ah, long address,
366476bd547bSAdrian Chadd     u_int8_t *buffer, int many)
366576bd547bSAdrian Chadd {
366676bd547bSAdrian Chadd     int i;
366776bd547bSAdrian Chadd     u_int8_t value[2];
366876bd547bSAdrian Chadd     unsigned long eep_addr;
366976bd547bSAdrian Chadd     unsigned long byte_addr;
367076bd547bSAdrian Chadd     u_int16_t *svalue;
367176bd547bSAdrian Chadd 
367276bd547bSAdrian Chadd     if (((address) < 0) || ((address + many) > AR9300_EEPROM_SIZE)) {
367376bd547bSAdrian Chadd         return AH_FALSE;
367476bd547bSAdrian Chadd     }
367576bd547bSAdrian Chadd 
367676bd547bSAdrian Chadd     for (i = 0; i < many; i++) {
367776bd547bSAdrian Chadd         eep_addr = (u_int16_t) (address + i) / 2;
367876bd547bSAdrian Chadd         byte_addr = (u_int16_t) (address + i) % 2;
367976bd547bSAdrian Chadd         svalue = (u_int16_t *) value;
3680e113789bSAdrian Chadd         if (! ath_hal_eepromRead(ah, eep_addr, svalue)) {
368176bd547bSAdrian Chadd             HALDEBUG(ah, HAL_DEBUG_EEPROM,
368276bd547bSAdrian Chadd                 "%s: Unable to read eeprom region \n", __func__);
368376bd547bSAdrian Chadd             return AH_FALSE;
368476bd547bSAdrian Chadd         }
368576bd547bSAdrian Chadd         buffer[i] = (*svalue >> (8 * byte_addr)) & 0xff;
368676bd547bSAdrian Chadd     }
368776bd547bSAdrian Chadd     return AH_TRUE;
368876bd547bSAdrian Chadd }
368976bd547bSAdrian Chadd 
369076bd547bSAdrian Chadd HAL_BOOL
ar9300_calibration_data_read_otp(struct ath_hal * ah,long address,u_int8_t * buffer,int many,HAL_BOOL is_wifi)369176bd547bSAdrian Chadd ar9300_calibration_data_read_otp(struct ath_hal *ah, long address,
369276bd547bSAdrian Chadd     u_int8_t *buffer, int many, HAL_BOOL is_wifi)
369376bd547bSAdrian Chadd {
369476bd547bSAdrian Chadd     int i;
369576bd547bSAdrian Chadd     unsigned long eep_addr;
369676bd547bSAdrian Chadd     unsigned long byte_addr;
369776bd547bSAdrian Chadd     u_int32_t svalue;
369876bd547bSAdrian Chadd 
369976bd547bSAdrian Chadd     if (((address) < 0) || ((address + many) > 0x400)) {
370076bd547bSAdrian Chadd         return AH_FALSE;
370176bd547bSAdrian Chadd     }
370276bd547bSAdrian Chadd 
370376bd547bSAdrian Chadd     for (i = 0; i < many; i++) {
370476bd547bSAdrian Chadd         eep_addr = (u_int16_t) (address + i) / 4; /* otp is 4 bytes long???? */
370576bd547bSAdrian Chadd         byte_addr = (u_int16_t) (address + i) % 4;
370676bd547bSAdrian Chadd         if (!ar9300_otp_read(ah, eep_addr, &svalue, is_wifi)) {
370776bd547bSAdrian Chadd             HALDEBUG(ah, HAL_DEBUG_EEPROM,
370876bd547bSAdrian Chadd                 "%s: Unable to read otp region \n", __func__);
370976bd547bSAdrian Chadd             return AH_FALSE;
371076bd547bSAdrian Chadd         }
371176bd547bSAdrian Chadd         buffer[i] = (svalue >> (8 * byte_addr)) & 0xff;
371276bd547bSAdrian Chadd     }
371376bd547bSAdrian Chadd     return AH_TRUE;
371476bd547bSAdrian Chadd }
371576bd547bSAdrian Chadd 
371676bd547bSAdrian Chadd #ifdef ATH_CAL_NAND_FLASH
371776bd547bSAdrian Chadd HAL_BOOL
ar9300_calibration_data_read_nand(struct ath_hal * ah,long address,u_int8_t * buffer,int many)371876bd547bSAdrian Chadd ar9300_calibration_data_read_nand(struct ath_hal *ah, long address,
371976bd547bSAdrian Chadd     u_int8_t *buffer, int many)
372076bd547bSAdrian Chadd {
372176bd547bSAdrian Chadd     int ret_len;
372276bd547bSAdrian Chadd     int ret_val = 1;
372376bd547bSAdrian Chadd 
372476bd547bSAdrian Chadd       /* Calling OS based API to read NAND */
372576bd547bSAdrian Chadd     ret_val = OS_NAND_FLASH_READ(ATH_CAL_NAND_PARTITION, address, many, &ret_len, buffer);
372676bd547bSAdrian Chadd 
372776bd547bSAdrian Chadd     return (ret_val ? AH_FALSE: AH_TRUE);
372876bd547bSAdrian Chadd }
372976bd547bSAdrian Chadd #endif
373076bd547bSAdrian Chadd 
373176bd547bSAdrian Chadd HAL_BOOL
ar9300_calibration_data_read(struct ath_hal * ah,long address,u_int8_t * buffer,int many)373276bd547bSAdrian Chadd ar9300_calibration_data_read(struct ath_hal *ah, long address,
373376bd547bSAdrian Chadd     u_int8_t *buffer, int many)
373476bd547bSAdrian Chadd {
373576bd547bSAdrian Chadd     switch (AH9300(ah)->calibration_data_source) {
373676bd547bSAdrian Chadd     case calibration_data_flash:
373776bd547bSAdrian Chadd         return ar9300_calibration_data_read_flash(ah, address, buffer, many);
373876bd547bSAdrian Chadd     case calibration_data_eeprom:
373976bd547bSAdrian Chadd         return ar9300_calibration_data_read_eeprom(ah, address, buffer, many);
374076bd547bSAdrian Chadd     case calibration_data_otp:
374176bd547bSAdrian Chadd         return ar9300_calibration_data_read_otp(ah, address, buffer, many, 1);
374276bd547bSAdrian Chadd #ifdef ATH_CAL_NAND_FLASH
374376bd547bSAdrian Chadd     case calibration_data_nand:
374476bd547bSAdrian Chadd         return ar9300_calibration_data_read_nand(ah,address,buffer,many);
374576bd547bSAdrian Chadd #endif
374676bd547bSAdrian Chadd 
374776bd547bSAdrian Chadd     }
374876bd547bSAdrian Chadd     return AH_FALSE;
374976bd547bSAdrian Chadd }
375076bd547bSAdrian Chadd 
375176bd547bSAdrian Chadd 
375276bd547bSAdrian Chadd HAL_BOOL
ar9300_calibration_data_read_array(struct ath_hal * ah,int address,u_int8_t * buffer,int many)375376bd547bSAdrian Chadd ar9300_calibration_data_read_array(struct ath_hal *ah, int address,
375476bd547bSAdrian Chadd     u_int8_t *buffer, int many)
375576bd547bSAdrian Chadd {
375676bd547bSAdrian Chadd     int it;
375776bd547bSAdrian Chadd 
375876bd547bSAdrian Chadd     for (it = 0; it < many; it++) {
375976bd547bSAdrian Chadd         (void)ar9300_calibration_data_read(ah, address - it, buffer + it, 1);
376076bd547bSAdrian Chadd     }
376176bd547bSAdrian Chadd     return AH_TRUE;
376276bd547bSAdrian Chadd }
376376bd547bSAdrian Chadd 
376476bd547bSAdrian Chadd 
376576bd547bSAdrian Chadd /*
376676bd547bSAdrian Chadd  * the address where the first configuration block is written
376776bd547bSAdrian Chadd  */
376876bd547bSAdrian Chadd static const int base_address = 0x3ff;                /* 1KB */
376976bd547bSAdrian Chadd static const int base_address_512 = 0x1ff;            /* 512Bytes */
377076bd547bSAdrian Chadd 
377176bd547bSAdrian Chadd /*
377276bd547bSAdrian Chadd  * the address where the NAND first configuration block is written
377376bd547bSAdrian Chadd  */
377476bd547bSAdrian Chadd #ifdef ATH_CAL_NAND_FLASH
377576bd547bSAdrian Chadd static const int base_address_nand = AR9300_FLASH_CAL_START_OFFSET;
377676bd547bSAdrian Chadd #endif
377776bd547bSAdrian Chadd 
377876bd547bSAdrian Chadd 
377976bd547bSAdrian Chadd /*
378076bd547bSAdrian Chadd  * the lower limit on configuration data
378176bd547bSAdrian Chadd  */
378276bd547bSAdrian Chadd static const int low_limit = 0x040;
378376bd547bSAdrian Chadd 
378476bd547bSAdrian Chadd /*
378576bd547bSAdrian Chadd  * returns size of the physical eeprom in bytes.
378676bd547bSAdrian Chadd  * 1024 and 2048 are normal sizes.
378776bd547bSAdrian Chadd  * 0 means there is no eeprom.
378876bd547bSAdrian Chadd  */
378976bd547bSAdrian Chadd int32_t
ar9300_eeprom_size(struct ath_hal * ah)379076bd547bSAdrian Chadd ar9300_eeprom_size(struct ath_hal *ah)
379176bd547bSAdrian Chadd {
379276bd547bSAdrian Chadd     u_int16_t data;
379376bd547bSAdrian Chadd     /*
379476bd547bSAdrian Chadd      * first we'll try for 4096 bytes eeprom
379576bd547bSAdrian Chadd      */
379676bd547bSAdrian Chadd     if (ar9300_eeprom_read_word(ah, 2047, &data)) {
379776bd547bSAdrian Chadd         if (data != 0) {
379876bd547bSAdrian Chadd             return 4096;
379976bd547bSAdrian Chadd         }
380076bd547bSAdrian Chadd     }
380176bd547bSAdrian Chadd     /*
380276bd547bSAdrian Chadd      * then we'll try for 2048 bytes eeprom
380376bd547bSAdrian Chadd      */
380476bd547bSAdrian Chadd     if (ar9300_eeprom_read_word(ah, 1023, &data)) {
380576bd547bSAdrian Chadd         if (data != 0) {
380676bd547bSAdrian Chadd             return 2048;
380776bd547bSAdrian Chadd         }
380876bd547bSAdrian Chadd     }
380976bd547bSAdrian Chadd     /*
381076bd547bSAdrian Chadd      * then we'll try for 1024 bytes eeprom
381176bd547bSAdrian Chadd      */
381276bd547bSAdrian Chadd     if (ar9300_eeprom_read_word(ah, 511, &data)) {
381376bd547bSAdrian Chadd         if (data != 0) {
381476bd547bSAdrian Chadd             return 1024;
381576bd547bSAdrian Chadd         }
381676bd547bSAdrian Chadd     }
381776bd547bSAdrian Chadd     return 0;
381876bd547bSAdrian Chadd }
381976bd547bSAdrian Chadd 
382076bd547bSAdrian Chadd /*
382176bd547bSAdrian Chadd  * returns size of the physical otp in bytes.
382276bd547bSAdrian Chadd  * 1024 and 2048 are normal sizes.
382376bd547bSAdrian Chadd  * 0 means there is no eeprom.
382476bd547bSAdrian Chadd  */
382576bd547bSAdrian Chadd int32_t
ar9300_otp_size(struct ath_hal * ah)382676bd547bSAdrian Chadd ar9300_otp_size(struct ath_hal *ah)
382776bd547bSAdrian Chadd {
382876bd547bSAdrian Chadd     if (AR_SREV_POSEIDON(ah) || AR_SREV_HORNET(ah)) {
382976bd547bSAdrian Chadd         return base_address_512+1;
383076bd547bSAdrian Chadd     } else {
383176bd547bSAdrian Chadd         return base_address+1;
383276bd547bSAdrian Chadd     }
383376bd547bSAdrian Chadd }
383476bd547bSAdrian Chadd 
383576bd547bSAdrian Chadd 
383676bd547bSAdrian Chadd /*
383776bd547bSAdrian Chadd  * find top of memory
383876bd547bSAdrian Chadd  */
383976bd547bSAdrian Chadd int
ar9300_eeprom_base_address(struct ath_hal * ah)384076bd547bSAdrian Chadd ar9300_eeprom_base_address(struct ath_hal *ah)
384176bd547bSAdrian Chadd {
384276bd547bSAdrian Chadd     int size;
384376bd547bSAdrian Chadd 
384476bd547bSAdrian Chadd     if (AH9300(ah)->calibration_data_source == calibration_data_otp) {
384576bd547bSAdrian Chadd 		return ar9300_otp_size(ah)-1;
384676bd547bSAdrian Chadd 	}
384776bd547bSAdrian Chadd 	else
384876bd547bSAdrian Chadd 	{
384976bd547bSAdrian Chadd 		size = ar9300_eeprom_size(ah);
385076bd547bSAdrian Chadd 		if (size > 0) {
385176bd547bSAdrian Chadd 			return size - 1;
385276bd547bSAdrian Chadd 		} else {
385376bd547bSAdrian Chadd 			return ar9300_otp_size(ah)-1;
385476bd547bSAdrian Chadd 		}
385576bd547bSAdrian Chadd 	}
385676bd547bSAdrian Chadd }
385776bd547bSAdrian Chadd 
385876bd547bSAdrian Chadd int
ar9300_eeprom_volatile(struct ath_hal * ah)385976bd547bSAdrian Chadd ar9300_eeprom_volatile(struct ath_hal *ah)
386076bd547bSAdrian Chadd {
386176bd547bSAdrian Chadd     if (AH9300(ah)->calibration_data_source == calibration_data_otp) {
386276bd547bSAdrian Chadd         return 0;        /* no eeprom, use otp */
386376bd547bSAdrian Chadd     } else {
386476bd547bSAdrian Chadd         return 1;        /* board has eeprom or flash */
386576bd547bSAdrian Chadd     }
386676bd547bSAdrian Chadd }
386776bd547bSAdrian Chadd 
386876bd547bSAdrian Chadd /*
386976bd547bSAdrian Chadd  * need to change this to look for the pcie data in the low parts of memory
387076bd547bSAdrian Chadd  * cal data needs to stop a few locations above
387176bd547bSAdrian Chadd  */
387276bd547bSAdrian Chadd int
ar9300_eeprom_low_limit(struct ath_hal * ah)387376bd547bSAdrian Chadd ar9300_eeprom_low_limit(struct ath_hal *ah)
387476bd547bSAdrian Chadd {
387576bd547bSAdrian Chadd     return low_limit;
387676bd547bSAdrian Chadd }
387776bd547bSAdrian Chadd 
387876bd547bSAdrian Chadd u_int16_t
ar9300_compression_checksum(u_int8_t * data,int dsize)387976bd547bSAdrian Chadd ar9300_compression_checksum(u_int8_t *data, int dsize)
388076bd547bSAdrian Chadd {
388176bd547bSAdrian Chadd     int it;
388276bd547bSAdrian Chadd     int checksum = 0;
388376bd547bSAdrian Chadd 
388476bd547bSAdrian Chadd     for (it = 0; it < dsize; it++) {
388576bd547bSAdrian Chadd         checksum += data[it];
388676bd547bSAdrian Chadd         checksum &= 0xffff;
388776bd547bSAdrian Chadd     }
388876bd547bSAdrian Chadd 
388976bd547bSAdrian Chadd     return checksum;
389076bd547bSAdrian Chadd }
389176bd547bSAdrian Chadd 
389276bd547bSAdrian Chadd int
ar9300_compression_header_unpack(u_int8_t * best,int * code,int * reference,int * length,int * major,int * minor)389376bd547bSAdrian Chadd ar9300_compression_header_unpack(u_int8_t *best, int *code, int *reference,
389476bd547bSAdrian Chadd     int *length, int *major, int *minor)
389576bd547bSAdrian Chadd {
389676bd547bSAdrian Chadd     unsigned long value[4];
389776bd547bSAdrian Chadd 
389876bd547bSAdrian Chadd     value[0] = best[0];
389976bd547bSAdrian Chadd     value[1] = best[1];
390076bd547bSAdrian Chadd     value[2] = best[2];
390176bd547bSAdrian Chadd     value[3] = best[3];
390276bd547bSAdrian Chadd     *code = ((value[0] >> 5) & 0x0007);
390376bd547bSAdrian Chadd     *reference = (value[0] & 0x001f) | ((value[1] >> 2) & 0x0020);
390476bd547bSAdrian Chadd     *length = ((value[1] << 4) & 0x07f0) | ((value[2] >> 4) & 0x000f);
390576bd547bSAdrian Chadd     *major = (value[2] & 0x000f);
390676bd547bSAdrian Chadd     *minor = (value[3] & 0x00ff);
390776bd547bSAdrian Chadd 
390876bd547bSAdrian Chadd     return 4;
390976bd547bSAdrian Chadd }
391076bd547bSAdrian Chadd 
391176bd547bSAdrian Chadd 
391276bd547bSAdrian Chadd static HAL_BOOL
ar9300_uncompress_block(struct ath_hal * ah,u_int8_t * mptr,int mdata_size,u_int8_t * block,int size)391376bd547bSAdrian Chadd ar9300_uncompress_block(struct ath_hal *ah, u_int8_t *mptr, int mdata_size,
391476bd547bSAdrian Chadd     u_int8_t *block, int size)
391576bd547bSAdrian Chadd {
391676bd547bSAdrian Chadd     int it;
391776bd547bSAdrian Chadd     int spot;
391876bd547bSAdrian Chadd     int offset;
391976bd547bSAdrian Chadd     int length;
392076bd547bSAdrian Chadd 
392176bd547bSAdrian Chadd     spot = 0;
392276bd547bSAdrian Chadd     for (it = 0; it < size; it += (length + 2)) {
392376bd547bSAdrian Chadd         offset = block[it];
392476bd547bSAdrian Chadd         offset &= 0xff;
392576bd547bSAdrian Chadd         spot += offset;
392676bd547bSAdrian Chadd         length = block[it + 1];
392776bd547bSAdrian Chadd         length &= 0xff;
392876bd547bSAdrian Chadd         if (length > 0 && spot >= 0 && spot + length <= mdata_size) {
392976bd547bSAdrian Chadd             HALDEBUG(ah, HAL_DEBUG_EEPROM,
393076bd547bSAdrian Chadd                 "%s: Restore at %d: spot=%d offset=%d length=%d\n",
393176bd547bSAdrian Chadd                 __func__, it, spot, offset, length);
393276bd547bSAdrian Chadd             OS_MEMCPY(&mptr[spot], &block[it + 2], length);
393376bd547bSAdrian Chadd             spot += length;
393476bd547bSAdrian Chadd         } else if (length > 0) {
393576bd547bSAdrian Chadd             HALDEBUG(ah, HAL_DEBUG_EEPROM,
393676bd547bSAdrian Chadd                 "%s: Bad restore at %d: spot=%d offset=%d length=%d\n",
393776bd547bSAdrian Chadd                 __func__, it, spot, offset, length);
393876bd547bSAdrian Chadd             return AH_FALSE;
393976bd547bSAdrian Chadd         }
394076bd547bSAdrian Chadd     }
394176bd547bSAdrian Chadd     return AH_TRUE;
394276bd547bSAdrian Chadd }
394376bd547bSAdrian Chadd 
394476bd547bSAdrian Chadd static int
ar9300_eeprom_restore_internal_address(struct ath_hal * ah,ar9300_eeprom_t * mptr,int mdata_size,int cptr,u_int8_t blank)394576bd547bSAdrian Chadd ar9300_eeprom_restore_internal_address(struct ath_hal *ah,
394676bd547bSAdrian Chadd     ar9300_eeprom_t *mptr, int mdata_size, int cptr, u_int8_t blank)
394776bd547bSAdrian Chadd {
394876bd547bSAdrian Chadd     u_int8_t word[MOUTPUT];
394976bd547bSAdrian Chadd     ar9300_eeprom_t *dptr; /* was uint8 */
395076bd547bSAdrian Chadd     int code;
395176bd547bSAdrian Chadd     int reference, length, major, minor;
395276bd547bSAdrian Chadd     int osize;
395376bd547bSAdrian Chadd     int it;
395476bd547bSAdrian Chadd     int restored;
395576bd547bSAdrian Chadd     u_int16_t checksum, mchecksum;
395676bd547bSAdrian Chadd 
395776bd547bSAdrian Chadd     restored = 0;
395876bd547bSAdrian Chadd     for (it = 0; it < MSTATE; it++) {
395976bd547bSAdrian Chadd         (void) ar9300_calibration_data_read_array(
396076bd547bSAdrian Chadd             ah, cptr, word, compression_header_length);
396176bd547bSAdrian Chadd         if (word[0] == blank && word[1] == blank && word[2] == blank && word[3] == blank)
396276bd547bSAdrian Chadd         {
396376bd547bSAdrian Chadd             break;
396476bd547bSAdrian Chadd         }
396576bd547bSAdrian Chadd         ar9300_compression_header_unpack(
396676bd547bSAdrian Chadd             word, &code, &reference, &length, &major, &minor);
396776bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_EEPROM,
396876bd547bSAdrian Chadd             "%s: Found block at %x: "
396976bd547bSAdrian Chadd             "code=%d ref=%d length=%d major=%d minor=%d\n",
397076bd547bSAdrian Chadd             __func__, cptr, code, reference, length, major, minor);
397176bd547bSAdrian Chadd #ifdef DONTUSE
397276bd547bSAdrian Chadd         if (length >= 1024) {
397376bd547bSAdrian Chadd             HALDEBUG(ah, HAL_DEBUG_EEPROM, "%s: Skipping bad header\n", __func__);
397476bd547bSAdrian Chadd             cptr -= compression_header_length;
397576bd547bSAdrian Chadd             continue;
397676bd547bSAdrian Chadd         }
397776bd547bSAdrian Chadd #endif
397876bd547bSAdrian Chadd         osize = length;
397976bd547bSAdrian Chadd         (void) ar9300_calibration_data_read_array(
398076bd547bSAdrian Chadd             ah, cptr, word,
398176bd547bSAdrian Chadd             compression_header_length + osize + compression_checksum_length);
398276bd547bSAdrian Chadd         checksum = ar9300_compression_checksum(
398376bd547bSAdrian Chadd             &word[compression_header_length], length);
398476bd547bSAdrian Chadd         mchecksum =
398576bd547bSAdrian Chadd             word[compression_header_length + osize] |
398676bd547bSAdrian Chadd             (word[compression_header_length + osize + 1] << 8);
398776bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_EEPROM,
398876bd547bSAdrian Chadd             "%s: checksum %x %x\n", __func__, checksum, mchecksum);
398976bd547bSAdrian Chadd         if (checksum == mchecksum) {
399076bd547bSAdrian Chadd             switch (code) {
399176bd547bSAdrian Chadd             case _compress_none:
399276bd547bSAdrian Chadd                 if (length != mdata_size) {
399376bd547bSAdrian Chadd                     HALDEBUG(ah, HAL_DEBUG_EEPROM,
399476bd547bSAdrian Chadd                         "%s: EEPROM structure size mismatch "
399576bd547bSAdrian Chadd                         "memory=%d eeprom=%d\n", __func__, mdata_size, length);
399676bd547bSAdrian Chadd                     return -1;
399776bd547bSAdrian Chadd                 }
399876bd547bSAdrian Chadd                 OS_MEMCPY((u_int8_t *)mptr,
399976bd547bSAdrian Chadd                     (u_int8_t *)(word + compression_header_length), length);
400076bd547bSAdrian Chadd                 HALDEBUG(ah, HAL_DEBUG_EEPROM,
400176bd547bSAdrian Chadd                     "%s: restored eeprom %d: uncompressed, length %d\n",
400276bd547bSAdrian Chadd                     __func__, it, length);
400376bd547bSAdrian Chadd                 restored = 1;
400476bd547bSAdrian Chadd                 break;
400576bd547bSAdrian Chadd #ifdef UNUSED
400676bd547bSAdrian Chadd             case _compress_lzma:
400776bd547bSAdrian Chadd                 if (reference == reference_current) {
400876bd547bSAdrian Chadd                     dptr = mptr;
400976bd547bSAdrian Chadd                 } else {
401076bd547bSAdrian Chadd                     dptr = (u_int8_t *)ar9300_eeprom_struct_default_find_by_id(
401176bd547bSAdrian Chadd                         reference);
401276bd547bSAdrian Chadd                     if (dptr == 0) {
401376bd547bSAdrian Chadd                         HALDEBUG(ah, HAL_DEBUG_EEPROM,
401476bd547bSAdrian Chadd                             "%s: Can't find reference eeprom struct %d\n",
401576bd547bSAdrian Chadd                             __func__, reference);
401676bd547bSAdrian Chadd                         goto done;
401776bd547bSAdrian Chadd                     }
401876bd547bSAdrian Chadd                 }
401976bd547bSAdrian Chadd                 usize = -1;
402076bd547bSAdrian Chadd                 if (usize != mdata_size) {
402176bd547bSAdrian Chadd                     HALDEBUG(ah, HAL_DEBUG_EEPROM,
402276bd547bSAdrian Chadd                         "%s: uncompressed data is wrong size %d %d\n",
402376bd547bSAdrian Chadd                         __func__, usize, mdata_size);
402476bd547bSAdrian Chadd                     goto done;
402576bd547bSAdrian Chadd                 }
402676bd547bSAdrian Chadd 
402776bd547bSAdrian Chadd                 for (ib = 0; ib < mdata_size; ib++) {
402876bd547bSAdrian Chadd                     mptr[ib] = dptr[ib] ^ word[ib + overhead];
402976bd547bSAdrian Chadd                 }
403076bd547bSAdrian Chadd                 HALDEBUG(ah, HAL_DEBUG_EEPROM,
403176bd547bSAdrian Chadd                     "%s: restored eeprom %d: compressed, "
403276bd547bSAdrian Chadd                     "reference %d, length %d\n",
403376bd547bSAdrian Chadd                     __func__, it, reference, length);
403476bd547bSAdrian Chadd                 break;
403576bd547bSAdrian Chadd             case _compress_pairs:
403676bd547bSAdrian Chadd                 if (reference == reference_current) {
403776bd547bSAdrian Chadd                     dptr = mptr;
403876bd547bSAdrian Chadd                 } else {
403976bd547bSAdrian Chadd                     dptr = (u_int8_t *)ar9300_eeprom_struct_default_find_by_id(
404076bd547bSAdrian Chadd                         reference);
404176bd547bSAdrian Chadd                     if (dptr == 0) {
404276bd547bSAdrian Chadd                         HALDEBUG(ah, HAL_DEBUG_EEPROM,
404376bd547bSAdrian Chadd                             "%s: Can't find the reference "
404476bd547bSAdrian Chadd                             "eeprom structure %d\n",
404576bd547bSAdrian Chadd                             __func__, reference);
404676bd547bSAdrian Chadd                         goto done;
404776bd547bSAdrian Chadd                     }
404876bd547bSAdrian Chadd                 }
404976bd547bSAdrian Chadd                 HALDEBUG(ah, HAL_DEBUG_EEPROM,
405076bd547bSAdrian Chadd                     "%s: restored eeprom %d: "
405176bd547bSAdrian Chadd                     "pairs, reference %d, length %d,\n",
405276bd547bSAdrian Chadd                     __func__, it, reference, length);
405376bd547bSAdrian Chadd                 break;
405476bd547bSAdrian Chadd #endif
405576bd547bSAdrian Chadd             case _compress_block:
405676bd547bSAdrian Chadd                 if (reference == reference_current) {
405776bd547bSAdrian Chadd                     dptr = mptr;
405876bd547bSAdrian Chadd                 } else {
405976bd547bSAdrian Chadd                     dptr = ar9300_eeprom_struct_default_find_by_id(reference);
406076bd547bSAdrian Chadd                     if (dptr == 0) {
406176bd547bSAdrian Chadd                         HALDEBUG(ah, HAL_DEBUG_EEPROM,
406276bd547bSAdrian Chadd                             "%s: cant find reference eeprom struct %d\n",
406376bd547bSAdrian Chadd                             __func__, reference);
406476bd547bSAdrian Chadd                         break;
406576bd547bSAdrian Chadd                     }
406676bd547bSAdrian Chadd                     OS_MEMCPY(mptr, dptr, mdata_size);
406776bd547bSAdrian Chadd                 }
406876bd547bSAdrian Chadd 
406976bd547bSAdrian Chadd                 HALDEBUG(ah, HAL_DEBUG_EEPROM,
407076bd547bSAdrian Chadd                     "%s: restore eeprom %d: block, reference %d, length %d\n",
407176bd547bSAdrian Chadd                     __func__, it, reference, length);
407276bd547bSAdrian Chadd                 (void) ar9300_uncompress_block(ah,
407376bd547bSAdrian Chadd                     (u_int8_t *) mptr, mdata_size,
407476bd547bSAdrian Chadd                     (u_int8_t *) (word + compression_header_length), length);
407576bd547bSAdrian Chadd                 restored = 1;
407676bd547bSAdrian Chadd                 break;
407776bd547bSAdrian Chadd             default:
407876bd547bSAdrian Chadd                 HALDEBUG(ah, HAL_DEBUG_EEPROM,
407976bd547bSAdrian Chadd                     "%s: unknown compression code %d\n", __func__, code);
408076bd547bSAdrian Chadd                 break;
408176bd547bSAdrian Chadd             }
408276bd547bSAdrian Chadd         } else {
408376bd547bSAdrian Chadd             HALDEBUG(ah, HAL_DEBUG_EEPROM,
408476bd547bSAdrian Chadd                 "%s: skipping block with bad checksum\n", __func__);
408576bd547bSAdrian Chadd         }
408676bd547bSAdrian Chadd         cptr -= compression_header_length + osize + compression_checksum_length;
408776bd547bSAdrian Chadd     }
408876bd547bSAdrian Chadd 
408976bd547bSAdrian Chadd     if (!restored) {
409076bd547bSAdrian Chadd         cptr = -1;
409176bd547bSAdrian Chadd     }
409276bd547bSAdrian Chadd     return cptr;
409376bd547bSAdrian Chadd }
409476bd547bSAdrian Chadd 
409576bd547bSAdrian Chadd static int
ar9300_eeprom_restore_from_dram(struct ath_hal * ah,ar9300_eeprom_t * mptr,int mdata_size)409676bd547bSAdrian Chadd ar9300_eeprom_restore_from_dram(struct ath_hal *ah, ar9300_eeprom_t *mptr,
409776bd547bSAdrian Chadd     int mdata_size)
409876bd547bSAdrian Chadd {
409976bd547bSAdrian Chadd     struct ath_hal_9300 *ahp = AH9300(ah);
410076bd547bSAdrian Chadd #if !defined(USE_PLATFORM_FRAMEWORK)
410176bd547bSAdrian Chadd     char *cal_ptr;
410276bd547bSAdrian Chadd #endif
410376bd547bSAdrian Chadd 
410476bd547bSAdrian Chadd     HALASSERT(mdata_size > 0);
410576bd547bSAdrian Chadd 
410676bd547bSAdrian Chadd     /* if cal_in_flash is AH_TRUE, the address sent by LMAC to HAL
410776bd547bSAdrian Chadd        (i.e. ah->ah_st) is corresponding to Flash. so return from
410876bd547bSAdrian Chadd        here if ar9300_eep_data_in_flash(ah) returns AH_TRUE */
410976bd547bSAdrian Chadd     if(ar9300_eep_data_in_flash(ah))
411076bd547bSAdrian Chadd         return -1;
411176bd547bSAdrian Chadd 
4112e113789bSAdrian Chadd #if 0
411376bd547bSAdrian Chadd     /* check if LMAC sent DRAM address is valid */
411476bd547bSAdrian Chadd     if (!(uintptr_t)(AH_PRIVATE(ah)->ah_st)) {
411576bd547bSAdrian Chadd         return -1;
411676bd547bSAdrian Chadd     }
4117e113789bSAdrian Chadd #endif
411876bd547bSAdrian Chadd 
411976bd547bSAdrian Chadd     /* When calibration data is from host, Host will copy the
412076bd547bSAdrian Chadd        compressed data to the predefined DRAM location saved at ah->ah_st */
4121e113789bSAdrian Chadd #if 0
412276bd547bSAdrian Chadd     ath_hal_printf(ah, "Restoring Cal data from DRAM\n");
412376bd547bSAdrian Chadd     ahp->ah_cal_mem = OS_REMAP((uintptr_t)(AH_PRIVATE(ah)->ah_st),
412476bd547bSAdrian Chadd 							HOST_CALDATA_SIZE);
4125e113789bSAdrian Chadd #endif
412676bd547bSAdrian Chadd     if (!ahp->ah_cal_mem)
412776bd547bSAdrian Chadd     {
412876bd547bSAdrian Chadd        HALDEBUG(ah, HAL_DEBUG_EEPROM,"%s: can't remap dram region\n", __func__);
412976bd547bSAdrian Chadd        return -1;
413076bd547bSAdrian Chadd     }
413176bd547bSAdrian Chadd #if !defined(USE_PLATFORM_FRAMEWORK)
413276bd547bSAdrian Chadd     cal_ptr = &((char *)(ahp->ah_cal_mem))[AR9300_FLASH_CAL_START_OFFSET];
413376bd547bSAdrian Chadd     OS_MEMCPY(mptr, cal_ptr, mdata_size);
413476bd547bSAdrian Chadd #else
413576bd547bSAdrian Chadd     OS_MEMCPY(mptr, ahp->ah_cal_mem, mdata_size);
413676bd547bSAdrian Chadd #endif
413776bd547bSAdrian Chadd 
413876bd547bSAdrian Chadd     if (mptr->eeprom_version   == 0xff ||
413976bd547bSAdrian Chadd         mptr->template_version == 0xff ||
414076bd547bSAdrian Chadd         mptr->eeprom_version   == 0    ||
414176bd547bSAdrian Chadd         mptr->template_version == 0)
414276bd547bSAdrian Chadd     {
414376bd547bSAdrian Chadd         /* The board is uncalibrated */
414476bd547bSAdrian Chadd         return -1;
414576bd547bSAdrian Chadd     }
414676bd547bSAdrian Chadd     if (mptr->eeprom_version != 0x2)
414776bd547bSAdrian Chadd     {
414876bd547bSAdrian Chadd         return -1;
414976bd547bSAdrian Chadd     }
415076bd547bSAdrian Chadd 
415176bd547bSAdrian Chadd     return mdata_size;
415276bd547bSAdrian Chadd 
415376bd547bSAdrian Chadd }
415476bd547bSAdrian Chadd 
415576bd547bSAdrian Chadd static int
ar9300_eeprom_restore_from_flash(struct ath_hal * ah,ar9300_eeprom_t * mptr,int mdata_size)415676bd547bSAdrian Chadd ar9300_eeprom_restore_from_flash(struct ath_hal *ah, ar9300_eeprom_t *mptr,
415776bd547bSAdrian Chadd     int mdata_size)
415876bd547bSAdrian Chadd {
415976bd547bSAdrian Chadd     struct ath_hal_9300 *ahp = AH9300(ah);
416076bd547bSAdrian Chadd     char *cal_ptr;
416176bd547bSAdrian Chadd 
416276bd547bSAdrian Chadd     HALASSERT(mdata_size > 0);
416376bd547bSAdrian Chadd 
416476bd547bSAdrian Chadd     if (!ahp->ah_cal_mem) {
416576bd547bSAdrian Chadd         return -1;
416676bd547bSAdrian Chadd     }
416776bd547bSAdrian Chadd 
416876bd547bSAdrian Chadd     ath_hal_printf(ah, "Restoring Cal data from Flash\n");
416976bd547bSAdrian Chadd     /*
417076bd547bSAdrian Chadd      * When calibration data is saved in flash, read
417176bd547bSAdrian Chadd      * uncompressed eeprom structure from flash and return
417276bd547bSAdrian Chadd      */
417376bd547bSAdrian Chadd     cal_ptr = &((char *)(ahp->ah_cal_mem))[AR9300_FLASH_CAL_START_OFFSET];
417476bd547bSAdrian Chadd     OS_MEMCPY(mptr, cal_ptr, mdata_size);
417576bd547bSAdrian Chadd #if 0
417676bd547bSAdrian Chadd     ar9300_swap_eeprom((ar9300_eeprom_t *)mptr); DONE IN ar9300_restore()
417776bd547bSAdrian Chadd #endif
417876bd547bSAdrian Chadd     if (mptr->eeprom_version   == 0xff ||
417976bd547bSAdrian Chadd         mptr->template_version == 0xff ||
418076bd547bSAdrian Chadd         mptr->eeprom_version   == 0    ||
418176bd547bSAdrian Chadd         mptr->template_version == 0)
418276bd547bSAdrian Chadd     {
418376bd547bSAdrian Chadd         /* The board is uncalibrated */
418476bd547bSAdrian Chadd         return -1;
418576bd547bSAdrian Chadd     }
418676bd547bSAdrian Chadd     if (mptr->eeprom_version != 0x2)
418776bd547bSAdrian Chadd     {
418876bd547bSAdrian Chadd         return -1;
418976bd547bSAdrian Chadd     }
419076bd547bSAdrian Chadd     return mdata_size;
419176bd547bSAdrian Chadd }
419276bd547bSAdrian Chadd 
419376bd547bSAdrian Chadd /*
419476bd547bSAdrian Chadd  * Read the configuration data from the storage. We try the order with:
419576bd547bSAdrian Chadd  * EEPROM, Flash, OTP. If all of above failed, use the default template.
419676bd547bSAdrian Chadd  * The data can be put in any specified memory buffer.
419776bd547bSAdrian Chadd  *
419876bd547bSAdrian Chadd  * Returns -1 on error.
419976bd547bSAdrian Chadd  * Returns address of next memory location on success.
420076bd547bSAdrian Chadd  */
420176bd547bSAdrian Chadd int
ar9300_eeprom_restore_internal(struct ath_hal * ah,ar9300_eeprom_t * mptr,int mdata_size)420276bd547bSAdrian Chadd ar9300_eeprom_restore_internal(struct ath_hal *ah, ar9300_eeprom_t *mptr,
420376bd547bSAdrian Chadd     int mdata_size)
420476bd547bSAdrian Chadd {
420576bd547bSAdrian Chadd     int nptr;
420676bd547bSAdrian Chadd 
420776bd547bSAdrian Chadd     nptr = -1;
420876bd547bSAdrian Chadd 
420976bd547bSAdrian Chadd     if ((AH9300(ah)->calibration_data_try == calibration_data_none ||
421076bd547bSAdrian Chadd          AH9300(ah)->calibration_data_try == calibration_data_dram) &&
421176bd547bSAdrian Chadd          AH9300(ah)->try_dram && nptr < 0)
421276bd547bSAdrian Chadd     {
4213e113789bSAdrian Chadd         ath_hal_printf(ah, "Restoring Cal data from DRAM\n");
421476bd547bSAdrian Chadd         AH9300(ah)->calibration_data_source = calibration_data_dram;
421576bd547bSAdrian Chadd         AH9300(ah)->calibration_data_source_address = 0;
421676bd547bSAdrian Chadd         nptr = ar9300_eeprom_restore_from_dram(ah, mptr, mdata_size);
421776bd547bSAdrian Chadd         if (nptr < 0) {
421876bd547bSAdrian Chadd             AH9300(ah)->calibration_data_source = calibration_data_none;
421976bd547bSAdrian Chadd             AH9300(ah)->calibration_data_source_address = 0;
422076bd547bSAdrian Chadd         }
422176bd547bSAdrian Chadd     }
422276bd547bSAdrian Chadd 
422376bd547bSAdrian Chadd     if ((AH9300(ah)->calibration_data_try == calibration_data_none ||
422476bd547bSAdrian Chadd          AH9300(ah)->calibration_data_try == calibration_data_eeprom) &&
422576bd547bSAdrian Chadd         AH9300(ah)->try_eeprom && nptr < 0)
422676bd547bSAdrian Chadd     {
422776bd547bSAdrian Chadd         /*
422876bd547bSAdrian Chadd          * need to look at highest eeprom address as well as at
422976bd547bSAdrian Chadd          * base_address=0x3ff where we used to write the data
423076bd547bSAdrian Chadd          */
4231e113789bSAdrian Chadd         ath_hal_printf(ah, "Restoring Cal data from EEPROM\n");
423276bd547bSAdrian Chadd         AH9300(ah)->calibration_data_source = calibration_data_eeprom;
423376bd547bSAdrian Chadd         if (AH9300(ah)->calibration_data_try_address != 0) {
423476bd547bSAdrian Chadd             AH9300(ah)->calibration_data_source_address =
423576bd547bSAdrian Chadd                 AH9300(ah)->calibration_data_try_address;
423676bd547bSAdrian Chadd             nptr = ar9300_eeprom_restore_internal_address(
423776bd547bSAdrian Chadd                 ah, mptr, mdata_size,
423876bd547bSAdrian Chadd                 AH9300(ah)->calibration_data_source_address, 0xff);
423976bd547bSAdrian Chadd         } else {
424076bd547bSAdrian Chadd             AH9300(ah)->calibration_data_source_address =
424176bd547bSAdrian Chadd                 ar9300_eeprom_base_address(ah);
424276bd547bSAdrian Chadd             nptr = ar9300_eeprom_restore_internal_address(
424376bd547bSAdrian Chadd                 ah, mptr, mdata_size,
424476bd547bSAdrian Chadd                 AH9300(ah)->calibration_data_source_address, 0xff);
424576bd547bSAdrian Chadd             if (nptr < 0 &&
424676bd547bSAdrian Chadd                 AH9300(ah)->calibration_data_source_address != base_address)
424776bd547bSAdrian Chadd             {
424876bd547bSAdrian Chadd                 AH9300(ah)->calibration_data_source_address = base_address;
424976bd547bSAdrian Chadd                 nptr = ar9300_eeprom_restore_internal_address(
425076bd547bSAdrian Chadd                     ah, mptr, mdata_size,
425176bd547bSAdrian Chadd                     AH9300(ah)->calibration_data_source_address, 0xff);
425276bd547bSAdrian Chadd             }
425376bd547bSAdrian Chadd         }
425476bd547bSAdrian Chadd         if (nptr < 0) {
425576bd547bSAdrian Chadd             AH9300(ah)->calibration_data_source = calibration_data_none;
425676bd547bSAdrian Chadd             AH9300(ah)->calibration_data_source_address = 0;
425776bd547bSAdrian Chadd         }
425876bd547bSAdrian Chadd     }
425976bd547bSAdrian Chadd 
426076bd547bSAdrian Chadd     /*
426176bd547bSAdrian Chadd      * ##### should be an ifdef test for any AP usage,
426276bd547bSAdrian Chadd      * either in driver or in nart
426376bd547bSAdrian Chadd      */
426476bd547bSAdrian Chadd     if ((AH9300(ah)->calibration_data_try == calibration_data_none ||
426576bd547bSAdrian Chadd          AH9300(ah)->calibration_data_try == calibration_data_flash) &&
426676bd547bSAdrian Chadd         AH9300(ah)->try_flash && nptr < 0)
426776bd547bSAdrian Chadd     {
4268e113789bSAdrian Chadd         ath_hal_printf(ah, "Restoring Cal data from Flash\n");
426976bd547bSAdrian Chadd         AH9300(ah)->calibration_data_source = calibration_data_flash;
427076bd547bSAdrian Chadd         /* how are we supposed to set this for flash? */
427176bd547bSAdrian Chadd         AH9300(ah)->calibration_data_source_address = 0;
427276bd547bSAdrian Chadd         nptr = ar9300_eeprom_restore_from_flash(ah, mptr, mdata_size);
427376bd547bSAdrian Chadd         if (nptr < 0) {
427476bd547bSAdrian Chadd             AH9300(ah)->calibration_data_source = calibration_data_none;
427576bd547bSAdrian Chadd             AH9300(ah)->calibration_data_source_address = 0;
427676bd547bSAdrian Chadd         }
427776bd547bSAdrian Chadd     }
427876bd547bSAdrian Chadd 
427976bd547bSAdrian Chadd     if ((AH9300(ah)->calibration_data_try == calibration_data_none ||
428076bd547bSAdrian Chadd          AH9300(ah)->calibration_data_try == calibration_data_otp) &&
428176bd547bSAdrian Chadd         AH9300(ah)->try_otp && nptr < 0)
428276bd547bSAdrian Chadd     {
4283e113789bSAdrian Chadd         ath_hal_printf(ah, "Restoring Cal data from OTP\n");
428476bd547bSAdrian Chadd         AH9300(ah)->calibration_data_source = calibration_data_otp;
428576bd547bSAdrian Chadd         if (AH9300(ah)->calibration_data_try_address != 0) {
428676bd547bSAdrian Chadd             AH9300(ah)->calibration_data_source_address =
428776bd547bSAdrian Chadd                 AH9300(ah)->calibration_data_try_address;
428876bd547bSAdrian Chadd 		} else {
428976bd547bSAdrian Chadd             AH9300(ah)->calibration_data_source_address =
429076bd547bSAdrian Chadd                 ar9300_eeprom_base_address(ah);
429176bd547bSAdrian Chadd 		}
429276bd547bSAdrian Chadd         nptr = ar9300_eeprom_restore_internal_address(
429376bd547bSAdrian Chadd             ah, mptr, mdata_size, AH9300(ah)->calibration_data_source_address, 0);
429476bd547bSAdrian Chadd         if (nptr < 0) {
429576bd547bSAdrian Chadd             AH9300(ah)->calibration_data_source = calibration_data_none;
429676bd547bSAdrian Chadd             AH9300(ah)->calibration_data_source_address = 0;
429776bd547bSAdrian Chadd         }
429876bd547bSAdrian Chadd     }
429976bd547bSAdrian Chadd 
430076bd547bSAdrian Chadd #ifdef ATH_CAL_NAND_FLASH
430176bd547bSAdrian Chadd     if ((AH9300(ah)->calibration_data_try == calibration_data_none ||
430276bd547bSAdrian Chadd          AH9300(ah)->calibration_data_try == calibration_data_nand) &&
430376bd547bSAdrian Chadd         AH9300(ah)->try_nand && nptr < 0)
430476bd547bSAdrian Chadd     {
430576bd547bSAdrian Chadd         AH9300(ah)->calibration_data_source = calibration_data_nand;
430676bd547bSAdrian Chadd         AH9300(ah)->calibration_data_source_address = ((unsigned int)(AH_PRIVATE(ah)->ah_st)) + base_address_nand;
430776bd547bSAdrian Chadd         if(ar9300_calibration_data_read(
430876bd547bSAdrian Chadd             ah, AH9300(ah)->calibration_data_source_address,
430976bd547bSAdrian Chadd             (u_int8_t *)mptr, mdata_size) == AH_TRUE)
431076bd547bSAdrian Chadd         {
431176bd547bSAdrian Chadd             nptr = mdata_size;
431276bd547bSAdrian Chadd         }
431376bd547bSAdrian Chadd         /*nptr=ar9300EepromRestoreInternalAddress(ah, mptr, mdataSize, CalibrationDataSourceAddress);*/
431476bd547bSAdrian Chadd         if(nptr < 0)
431576bd547bSAdrian Chadd         {
431676bd547bSAdrian Chadd             AH9300(ah)->calibration_data_source = calibration_data_none;
431776bd547bSAdrian Chadd             AH9300(ah)->calibration_data_source_address = 0;
431876bd547bSAdrian Chadd         }
431976bd547bSAdrian Chadd     }
432076bd547bSAdrian Chadd #endif
432176bd547bSAdrian Chadd     if (nptr < 0) {
4322f254aad3SBjoern A. Zeeb         ath_hal_printf(ah, "%s[%d] No valid CAL, calling default template\n",
432376bd547bSAdrian Chadd             __func__, __LINE__);
432476bd547bSAdrian Chadd         nptr = ar9300_eeprom_restore_something(ah, mptr, mdata_size);
432576bd547bSAdrian Chadd     }
432676bd547bSAdrian Chadd 
432776bd547bSAdrian Chadd     return nptr;
432876bd547bSAdrian Chadd }
432976bd547bSAdrian Chadd 
433076bd547bSAdrian Chadd /******************************************************************************/
433176bd547bSAdrian Chadd /*!
433276bd547bSAdrian Chadd **  \brief Eeprom Swapping Function
433376bd547bSAdrian Chadd **
433476bd547bSAdrian Chadd **  This function will swap the contents of the "longer" EEPROM data items
433576bd547bSAdrian Chadd **  to ensure they are consistent with the endian requirements for the platform
433676bd547bSAdrian Chadd **  they are being compiled for
433776bd547bSAdrian Chadd **
433876bd547bSAdrian Chadd **  \param eh    Pointer to the EEPROM data structure
433976bd547bSAdrian Chadd **  \return N/A
434076bd547bSAdrian Chadd */
434176bd547bSAdrian Chadd #if AH_BYTE_ORDER == AH_BIG_ENDIAN
434276bd547bSAdrian Chadd void
ar9300_swap_eeprom(ar9300_eeprom_t * eep)434376bd547bSAdrian Chadd ar9300_swap_eeprom(ar9300_eeprom_t *eep)
434476bd547bSAdrian Chadd {
434576bd547bSAdrian Chadd     u_int32_t dword;
434676bd547bSAdrian Chadd     u_int16_t word;
434776bd547bSAdrian Chadd     int          i;
434876bd547bSAdrian Chadd 
434976bd547bSAdrian Chadd     word = __bswap16(eep->base_eep_header.reg_dmn[0]);
435076bd547bSAdrian Chadd     eep->base_eep_header.reg_dmn[0] = word;
435176bd547bSAdrian Chadd 
435276bd547bSAdrian Chadd     word = __bswap16(eep->base_eep_header.reg_dmn[1]);
435376bd547bSAdrian Chadd     eep->base_eep_header.reg_dmn[1] = word;
435476bd547bSAdrian Chadd 
435576bd547bSAdrian Chadd     dword = __bswap32(eep->base_eep_header.swreg);
435676bd547bSAdrian Chadd     eep->base_eep_header.swreg = dword;
435776bd547bSAdrian Chadd 
435876bd547bSAdrian Chadd     dword = __bswap32(eep->modal_header_2g.ant_ctrl_common);
435976bd547bSAdrian Chadd     eep->modal_header_2g.ant_ctrl_common = dword;
436076bd547bSAdrian Chadd 
436176bd547bSAdrian Chadd     dword = __bswap32(eep->modal_header_2g.ant_ctrl_common2);
436276bd547bSAdrian Chadd     eep->modal_header_2g.ant_ctrl_common2 = dword;
436376bd547bSAdrian Chadd 
436476bd547bSAdrian Chadd     dword = __bswap32(eep->modal_header_2g.paprd_rate_mask_ht20);
436576bd547bSAdrian Chadd     eep->modal_header_2g.paprd_rate_mask_ht20 = dword;
436676bd547bSAdrian Chadd 
436776bd547bSAdrian Chadd     dword = __bswap32(eep->modal_header_2g.paprd_rate_mask_ht40);
436876bd547bSAdrian Chadd     eep->modal_header_2g.paprd_rate_mask_ht40 = dword;
436976bd547bSAdrian Chadd 
437076bd547bSAdrian Chadd     dword = __bswap32(eep->modal_header_5g.ant_ctrl_common);
437176bd547bSAdrian Chadd     eep->modal_header_5g.ant_ctrl_common = dword;
437276bd547bSAdrian Chadd 
437376bd547bSAdrian Chadd     dword = __bswap32(eep->modal_header_5g.ant_ctrl_common2);
437476bd547bSAdrian Chadd     eep->modal_header_5g.ant_ctrl_common2 = dword;
437576bd547bSAdrian Chadd 
437676bd547bSAdrian Chadd     dword = __bswap32(eep->modal_header_5g.paprd_rate_mask_ht20);
437776bd547bSAdrian Chadd     eep->modal_header_5g.paprd_rate_mask_ht20 = dword;
437876bd547bSAdrian Chadd 
437976bd547bSAdrian Chadd     dword = __bswap32(eep->modal_header_5g.paprd_rate_mask_ht40);
438076bd547bSAdrian Chadd     eep->modal_header_5g.paprd_rate_mask_ht40 = dword;
438176bd547bSAdrian Chadd 
438276bd547bSAdrian Chadd     for (i = 0; i < OSPREY_MAX_CHAINS; i++) {
438376bd547bSAdrian Chadd         word = __bswap16(eep->modal_header_2g.ant_ctrl_chain[i]);
438476bd547bSAdrian Chadd         eep->modal_header_2g.ant_ctrl_chain[i] = word;
438576bd547bSAdrian Chadd 
438676bd547bSAdrian Chadd         word = __bswap16(eep->modal_header_5g.ant_ctrl_chain[i]);
438776bd547bSAdrian Chadd         eep->modal_header_5g.ant_ctrl_chain[i] = word;
438876bd547bSAdrian Chadd     }
438976bd547bSAdrian Chadd }
439076bd547bSAdrian Chadd 
ar9300_eeprom_template_swap(void)439176bd547bSAdrian Chadd void ar9300_eeprom_template_swap(void)
439276bd547bSAdrian Chadd {
439376bd547bSAdrian Chadd     int it;
439476bd547bSAdrian Chadd     ar9300_eeprom_t *dptr;
439576bd547bSAdrian Chadd 
439676bd547bSAdrian Chadd     for (it = 0; it < ARRAY_LENGTH(default9300); it++) {
439776bd547bSAdrian Chadd         dptr = ar9300_eeprom_struct_default(it);
439876bd547bSAdrian Chadd         if (dptr != 0) {
439976bd547bSAdrian Chadd             ar9300_swap_eeprom(dptr);
440076bd547bSAdrian Chadd         }
440176bd547bSAdrian Chadd     }
440276bd547bSAdrian Chadd }
440376bd547bSAdrian Chadd #endif
440476bd547bSAdrian Chadd 
440576bd547bSAdrian Chadd 
440676bd547bSAdrian Chadd /*
440776bd547bSAdrian Chadd  * Restore the configuration structure by reading the eeprom.
440876bd547bSAdrian Chadd  * This function destroys any existing in-memory structure content.
440976bd547bSAdrian Chadd  */
441076bd547bSAdrian Chadd HAL_BOOL
ar9300_eeprom_restore(struct ath_hal * ah)441176bd547bSAdrian Chadd ar9300_eeprom_restore(struct ath_hal *ah)
441276bd547bSAdrian Chadd {
441376bd547bSAdrian Chadd     struct ath_hal_9300 *ahp = AH9300(ah);
441476bd547bSAdrian Chadd     ar9300_eeprom_t *mptr;
441576bd547bSAdrian Chadd     int mdata_size;
441676bd547bSAdrian Chadd     HAL_BOOL status = AH_FALSE;
441776bd547bSAdrian Chadd 
441876bd547bSAdrian Chadd     mptr = &ahp->ah_eeprom;
441976bd547bSAdrian Chadd     mdata_size = ar9300_eeprom_struct_size();
442076bd547bSAdrian Chadd 
442176bd547bSAdrian Chadd     if (mptr != 0 && mdata_size > 0) {
442276bd547bSAdrian Chadd #if AH_BYTE_ORDER == AH_BIG_ENDIAN
442376bd547bSAdrian Chadd         ar9300_eeprom_template_swap();
442476bd547bSAdrian Chadd         ar9300_swap_eeprom(mptr);
442576bd547bSAdrian Chadd #endif
442676bd547bSAdrian Chadd         /*
442776bd547bSAdrian Chadd          * At this point, mptr points to the eeprom data structure
442828323addSBryan Drewery          * in its "default" state.  If this is big endian, swap the
442976bd547bSAdrian Chadd          * data structures back to "little endian" form.
443076bd547bSAdrian Chadd          */
443176bd547bSAdrian Chadd         if (ar9300_eeprom_restore_internal(ah, mptr, mdata_size) >= 0) {
443276bd547bSAdrian Chadd             status = AH_TRUE;
443376bd547bSAdrian Chadd         }
443476bd547bSAdrian Chadd 
443576bd547bSAdrian Chadd #if AH_BYTE_ORDER == AH_BIG_ENDIAN
443676bd547bSAdrian Chadd         /* Second Swap, back to Big Endian */
443776bd547bSAdrian Chadd         ar9300_eeprom_template_swap();
443876bd547bSAdrian Chadd         ar9300_swap_eeprom(mptr);
443976bd547bSAdrian Chadd #endif
444076bd547bSAdrian Chadd 
444176bd547bSAdrian Chadd     }
444276bd547bSAdrian Chadd     ahp->ah_2g_paprd_rate_mask_ht40 =
444376bd547bSAdrian Chadd         mptr->modal_header_2g.paprd_rate_mask_ht40;
444476bd547bSAdrian Chadd     ahp->ah_2g_paprd_rate_mask_ht20 =
444576bd547bSAdrian Chadd         mptr->modal_header_2g.paprd_rate_mask_ht20;
444676bd547bSAdrian Chadd     ahp->ah_5g_paprd_rate_mask_ht40 =
444776bd547bSAdrian Chadd         mptr->modal_header_5g.paprd_rate_mask_ht40;
444876bd547bSAdrian Chadd     ahp->ah_5g_paprd_rate_mask_ht20 =
444976bd547bSAdrian Chadd         mptr->modal_header_5g.paprd_rate_mask_ht20;
445076bd547bSAdrian Chadd     return status;
445176bd547bSAdrian Chadd }
445276bd547bSAdrian Chadd 
ar9300_thermometer_get(struct ath_hal * ah)445376bd547bSAdrian Chadd int32_t ar9300_thermometer_get(struct ath_hal *ah)
445476bd547bSAdrian Chadd {
445576bd547bSAdrian Chadd     struct ath_hal_9300 *ahp = AH9300(ah);
445676bd547bSAdrian Chadd     int thermometer;
445776bd547bSAdrian Chadd     thermometer =
445876bd547bSAdrian Chadd         (ahp->ah_eeprom.base_eep_header.misc_configuration >> 1) & 0x3;
445976bd547bSAdrian Chadd     thermometer--;
446076bd547bSAdrian Chadd     return thermometer;
446176bd547bSAdrian Chadd }
446276bd547bSAdrian Chadd 
ar9300_thermometer_apply(struct ath_hal * ah)446376bd547bSAdrian Chadd HAL_BOOL ar9300_thermometer_apply(struct ath_hal *ah)
446476bd547bSAdrian Chadd {
446576bd547bSAdrian Chadd     int thermometer = ar9300_thermometer_get(ah);
446676bd547bSAdrian Chadd 
446776bd547bSAdrian Chadd /* ch0_RXTX4 */
446876bd547bSAdrian Chadd /*#define AR_PHY_65NM_CH0_RXTX4       AR_PHY_65NM(ch0_RXTX4)*/
446976bd547bSAdrian Chadd #define AR_PHY_65NM_CH1_RXTX4       AR_PHY_65NM(ch1_RXTX4)
447076bd547bSAdrian Chadd #define AR_PHY_65NM_CH2_RXTX4       AR_PHY_65NM(ch2_RXTX4)
447176bd547bSAdrian Chadd /*#define AR_PHY_65NM_CH0_RXTX4_THERM_ON          0x10000000*/
447276bd547bSAdrian Chadd /*#define AR_PHY_65NM_CH0_RXTX4_THERM_ON_S        28*/
447376bd547bSAdrian Chadd #define AR_PHY_65NM_CH0_RXTX4_THERM_ON_OVR_S      29
447476bd547bSAdrian Chadd #define AR_PHY_65NM_CH0_RXTX4_THERM_ON_OVR        \
447576bd547bSAdrian Chadd     (0x1<<AR_PHY_65NM_CH0_RXTX4_THERM_ON_OVR_S)
447676bd547bSAdrian Chadd 
447776bd547bSAdrian Chadd     if (thermometer < 0) {
447876bd547bSAdrian Chadd         OS_REG_RMW_FIELD(ah,
447976bd547bSAdrian Chadd             AR_PHY_65NM_CH0_RXTX4, AR_PHY_65NM_CH0_RXTX4_THERM_ON_OVR, 0);
448076bd547bSAdrian Chadd         if (!AR_SREV_HORNET(ah) && !AR_SREV_POSEIDON(ah)) {
448176bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah,
448276bd547bSAdrian Chadd                 AR_PHY_65NM_CH1_RXTX4, AR_PHY_65NM_CH0_RXTX4_THERM_ON_OVR, 0);
448327e2ad46SAdrian Chadd             if (!AR_SREV_WASP(ah) && !AR_SREV_JUPITER(ah) && !AR_SREV_HONEYBEE(ah)  ) {
448476bd547bSAdrian Chadd                 OS_REG_RMW_FIELD(ah, AR_PHY_65NM_CH2_RXTX4,
448576bd547bSAdrian Chadd                     AR_PHY_65NM_CH0_RXTX4_THERM_ON_OVR, 0);
448676bd547bSAdrian Chadd             }
448776bd547bSAdrian Chadd         }
448876bd547bSAdrian Chadd         OS_REG_RMW_FIELD(ah,
448976bd547bSAdrian Chadd             AR_PHY_65NM_CH0_RXTX4, AR_PHY_65NM_CH0_RXTX4_THERM_ON, 0);
449076bd547bSAdrian Chadd         if (!AR_SREV_HORNET(ah) && !AR_SREV_POSEIDON(ah)) {
449176bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah,
449276bd547bSAdrian Chadd                 AR_PHY_65NM_CH1_RXTX4, AR_PHY_65NM_CH0_RXTX4_THERM_ON, 0);
449327e2ad46SAdrian Chadd             if (!AR_SREV_WASP(ah) && !AR_SREV_JUPITER(ah) && !AR_SREV_HONEYBEE(ah) ) {
449476bd547bSAdrian Chadd                 OS_REG_RMW_FIELD(ah,
449576bd547bSAdrian Chadd                     AR_PHY_65NM_CH2_RXTX4, AR_PHY_65NM_CH0_RXTX4_THERM_ON, 0);
449676bd547bSAdrian Chadd             }
449776bd547bSAdrian Chadd         }
449876bd547bSAdrian Chadd     } else {
449976bd547bSAdrian Chadd         OS_REG_RMW_FIELD(ah,
450076bd547bSAdrian Chadd             AR_PHY_65NM_CH0_RXTX4, AR_PHY_65NM_CH0_RXTX4_THERM_ON_OVR, 1);
450176bd547bSAdrian Chadd         if (!AR_SREV_HORNET(ah) && !AR_SREV_POSEIDON(ah)) {
450276bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah,
450376bd547bSAdrian Chadd                 AR_PHY_65NM_CH1_RXTX4, AR_PHY_65NM_CH0_RXTX4_THERM_ON_OVR, 1);
450427e2ad46SAdrian Chadd             if (!AR_SREV_WASP(ah) && !AR_SREV_JUPITER(ah) && !AR_SREV_HONEYBEE(ah)  ) {
450576bd547bSAdrian Chadd                 OS_REG_RMW_FIELD(ah, AR_PHY_65NM_CH2_RXTX4,
450676bd547bSAdrian Chadd                     AR_PHY_65NM_CH0_RXTX4_THERM_ON_OVR, 1);
450776bd547bSAdrian Chadd             }
450876bd547bSAdrian Chadd         }
450976bd547bSAdrian Chadd         if (thermometer == 0) {
451076bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah,
451176bd547bSAdrian Chadd                 AR_PHY_65NM_CH0_RXTX4, AR_PHY_65NM_CH0_RXTX4_THERM_ON, 1);
451276bd547bSAdrian Chadd             if (!AR_SREV_HORNET(ah) && !AR_SREV_POSEIDON(ah)) {
451376bd547bSAdrian Chadd                 OS_REG_RMW_FIELD(ah,
451476bd547bSAdrian Chadd                     AR_PHY_65NM_CH1_RXTX4, AR_PHY_65NM_CH0_RXTX4_THERM_ON, 0);
451527e2ad46SAdrian Chadd                 if (!AR_SREV_WASP(ah) && !AR_SREV_JUPITER(ah) && !AR_SREV_HONEYBEE(ah) ) {
451676bd547bSAdrian Chadd                     OS_REG_RMW_FIELD(ah, AR_PHY_65NM_CH2_RXTX4,
451776bd547bSAdrian Chadd                         AR_PHY_65NM_CH0_RXTX4_THERM_ON, 0);
451876bd547bSAdrian Chadd                 }
451976bd547bSAdrian Chadd             }
452076bd547bSAdrian Chadd         } else if (thermometer == 1) {
452176bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah,
452276bd547bSAdrian Chadd                 AR_PHY_65NM_CH0_RXTX4, AR_PHY_65NM_CH0_RXTX4_THERM_ON, 0);
452376bd547bSAdrian Chadd             if (!AR_SREV_HORNET(ah) && !AR_SREV_POSEIDON(ah)) {
452476bd547bSAdrian Chadd                 OS_REG_RMW_FIELD(ah,
452576bd547bSAdrian Chadd                     AR_PHY_65NM_CH1_RXTX4, AR_PHY_65NM_CH0_RXTX4_THERM_ON, 1);
452627e2ad46SAdrian Chadd                 if (!AR_SREV_WASP(ah) && !AR_SREV_JUPITER(ah) && !AR_SREV_HONEYBEE(ah) ) {
452776bd547bSAdrian Chadd                     OS_REG_RMW_FIELD(ah, AR_PHY_65NM_CH2_RXTX4,
452876bd547bSAdrian Chadd                         AR_PHY_65NM_CH0_RXTX4_THERM_ON, 0);
452976bd547bSAdrian Chadd                 }
453076bd547bSAdrian Chadd             }
453176bd547bSAdrian Chadd         } else if (thermometer == 2) {
453276bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah,
453376bd547bSAdrian Chadd                 AR_PHY_65NM_CH0_RXTX4, AR_PHY_65NM_CH0_RXTX4_THERM_ON, 0);
453476bd547bSAdrian Chadd             if (!AR_SREV_HORNET(ah) && !AR_SREV_POSEIDON(ah)) {
453576bd547bSAdrian Chadd                 OS_REG_RMW_FIELD(ah,
453676bd547bSAdrian Chadd                     AR_PHY_65NM_CH1_RXTX4, AR_PHY_65NM_CH0_RXTX4_THERM_ON, 0);
453727e2ad46SAdrian Chadd                 if (!AR_SREV_WASP(ah) && !AR_SREV_JUPITER(ah) && !AR_SREV_HONEYBEE(ah) ) {
453876bd547bSAdrian Chadd                     OS_REG_RMW_FIELD(ah, AR_PHY_65NM_CH2_RXTX4,
453976bd547bSAdrian Chadd                         AR_PHY_65NM_CH0_RXTX4_THERM_ON, 1);
454076bd547bSAdrian Chadd                 }
454176bd547bSAdrian Chadd             }
454276bd547bSAdrian Chadd         }
454376bd547bSAdrian Chadd     }
454476bd547bSAdrian Chadd     return AH_TRUE;
454576bd547bSAdrian Chadd }
454676bd547bSAdrian Chadd 
ar9300_tuning_caps_params_get(struct ath_hal * ah)454776bd547bSAdrian Chadd static int32_t ar9300_tuning_caps_params_get(struct ath_hal *ah)
454876bd547bSAdrian Chadd {
454976bd547bSAdrian Chadd     int tuning_caps_params;
455076bd547bSAdrian Chadd     ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom;
455176bd547bSAdrian Chadd     tuning_caps_params = eep->base_eep_header.params_for_tuning_caps[0];
455276bd547bSAdrian Chadd     return tuning_caps_params;
455376bd547bSAdrian Chadd }
455476bd547bSAdrian Chadd 
455576bd547bSAdrian Chadd /*
455676bd547bSAdrian Chadd  * Read the tuning caps params from eeprom and set to correct register.
455776bd547bSAdrian Chadd  * To regulation the frequency accuracy.
455876bd547bSAdrian Chadd  */
ar9300_tuning_caps_apply(struct ath_hal * ah)455976bd547bSAdrian Chadd HAL_BOOL ar9300_tuning_caps_apply(struct ath_hal *ah)
456076bd547bSAdrian Chadd {
456176bd547bSAdrian Chadd     int tuning_caps_params;
456276bd547bSAdrian Chadd     ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom;
456376bd547bSAdrian Chadd     tuning_caps_params = ar9300_tuning_caps_params_get(ah);
456476bd547bSAdrian Chadd     if ((eep->base_eep_header.feature_enable & 0x40) >> 6) {
456576bd547bSAdrian Chadd         tuning_caps_params &= 0x7f;
456676bd547bSAdrian Chadd 
456727e2ad46SAdrian Chadd         if (AR_SREV_POSEIDON(ah) || AR_SREV_WASP(ah) || AR_SREV_HONEYBEE(ah)) {
456827e2ad46SAdrian Chadd             return true;
4569967e8d37SAdrian Chadd         } else if (AR_SREV_HORNET(ah)) {
4570967e8d37SAdrian Chadd             OS_REG_RMW_FIELD(ah,
4571967e8d37SAdrian Chadd                 AR_HORNET_CH0_XTAL, AR_OSPREY_CHO_XTAL_CAPINDAC,
4572967e8d37SAdrian Chadd                 tuning_caps_params);
4573967e8d37SAdrian Chadd             OS_REG_RMW_FIELD(ah,
4574967e8d37SAdrian Chadd                 AR_HORNET_CH0_XTAL, AR_OSPREY_CHO_XTAL_CAPOUTDAC,
4575967e8d37SAdrian Chadd                 tuning_caps_params);
457676bd547bSAdrian Chadd         } else if (AR_SREV_SCORPION(ah)) {
457776bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah,
457876bd547bSAdrian Chadd                 AR_SCORPION_CH0_XTAL, AR_OSPREY_CHO_XTAL_CAPINDAC,
457976bd547bSAdrian Chadd                 tuning_caps_params);
458076bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah,
458176bd547bSAdrian Chadd                 AR_SCORPION_CH0_XTAL, AR_OSPREY_CHO_XTAL_CAPOUTDAC,
458276bd547bSAdrian Chadd                 tuning_caps_params);
458376bd547bSAdrian Chadd         } else {
458476bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah,
458576bd547bSAdrian Chadd                 AR_OSPREY_CH0_XTAL, AR_OSPREY_CHO_XTAL_CAPINDAC,
458676bd547bSAdrian Chadd                 tuning_caps_params);
458776bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah,
458876bd547bSAdrian Chadd                 AR_OSPREY_CH0_XTAL, AR_OSPREY_CHO_XTAL_CAPOUTDAC,
458976bd547bSAdrian Chadd                 tuning_caps_params);
459076bd547bSAdrian Chadd         }
459176bd547bSAdrian Chadd 
459276bd547bSAdrian Chadd     }
459376bd547bSAdrian Chadd     return AH_TRUE;
459476bd547bSAdrian Chadd }
459576bd547bSAdrian Chadd 
459676bd547bSAdrian Chadd /*
459776bd547bSAdrian Chadd  * Read the tx_frame_to_xpa_on param from eeprom and apply the value to
459876bd547bSAdrian Chadd  * correct register.
459976bd547bSAdrian Chadd  */
ar9300_xpa_timing_control_apply(struct ath_hal * ah,HAL_BOOL is_2ghz)460076bd547bSAdrian Chadd HAL_BOOL ar9300_xpa_timing_control_apply(struct ath_hal *ah, HAL_BOOL is_2ghz)
460176bd547bSAdrian Chadd {
460276bd547bSAdrian Chadd     u_int8_t xpa_timing_control;
460376bd547bSAdrian Chadd     ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom;
460476bd547bSAdrian Chadd     if ((eep->base_eep_header.feature_enable & 0x80) >> 7) {
460527e2ad46SAdrian Chadd 		if (AR_SREV_OSPREY(ah) || AR_SREV_AR9580(ah) || AR_SREV_WASP(ah) || AR_SREV_HONEYBEE(ah)) {
460676bd547bSAdrian Chadd 			if (is_2ghz) {
460776bd547bSAdrian Chadd                 xpa_timing_control = eep->modal_header_2g.tx_frame_to_xpa_on;
460876bd547bSAdrian Chadd                 OS_REG_RMW_FIELD(ah,
460976bd547bSAdrian Chadd 						AR_PHY_XPA_TIMING_CTL, AR_PHY_XPA_TIMING_CTL_FRAME_XPAB_ON,
461076bd547bSAdrian Chadd 						xpa_timing_control);
461176bd547bSAdrian Chadd 			} else {
461276bd547bSAdrian Chadd                 xpa_timing_control = eep->modal_header_5g.tx_frame_to_xpa_on;
461376bd547bSAdrian Chadd                 OS_REG_RMW_FIELD(ah,
461476bd547bSAdrian Chadd 						AR_PHY_XPA_TIMING_CTL, AR_PHY_XPA_TIMING_CTL_FRAME_XPAA_ON,
461576bd547bSAdrian Chadd 						xpa_timing_control);
461676bd547bSAdrian Chadd 			}
461776bd547bSAdrian Chadd 		}
461876bd547bSAdrian Chadd 	}
461976bd547bSAdrian Chadd     return AH_TRUE;
462076bd547bSAdrian Chadd }
462176bd547bSAdrian Chadd 
462276bd547bSAdrian Chadd 
462376bd547bSAdrian Chadd /*
462476bd547bSAdrian Chadd  * Read the xLNA_bias_strength param from eeprom and apply the value to
462576bd547bSAdrian Chadd  * correct register.
462676bd547bSAdrian Chadd  */
ar9300_x_lNA_bias_strength_apply(struct ath_hal * ah,HAL_BOOL is_2ghz)462776bd547bSAdrian Chadd HAL_BOOL ar9300_x_lNA_bias_strength_apply(struct ath_hal *ah, HAL_BOOL is_2ghz)
462876bd547bSAdrian Chadd {
462976bd547bSAdrian Chadd     u_int8_t x_lNABias;
463076bd547bSAdrian Chadd     u_int32_t value = 0;
463176bd547bSAdrian Chadd     ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom;
463276bd547bSAdrian Chadd 
463376bd547bSAdrian Chadd     if ((eep->base_eep_header.misc_configuration & 0x40) >> 6) {
463476bd547bSAdrian Chadd         if (AR_SREV_OSPREY(ah)) {
463576bd547bSAdrian Chadd             if (is_2ghz) {
463676bd547bSAdrian Chadd                 x_lNABias = eep->modal_header_2g.xLNA_bias_strength;
463776bd547bSAdrian Chadd             } else {
463876bd547bSAdrian Chadd                 x_lNABias = eep->modal_header_5g.xLNA_bias_strength;
463976bd547bSAdrian Chadd             }
464076bd547bSAdrian Chadd             value = x_lNABias & ( 0x03 );	// bit0,1 for chain0
464176bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah,
464276bd547bSAdrian Chadd 					AR_PHY_65NM_CH0_RXTX4, AR_PHY_65NM_RXTX4_XLNA_BIAS, value);
464376bd547bSAdrian Chadd             value = (x_lNABias >> 2) & ( 0x03 );	// bit2,3 for chain1
464476bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah,
464576bd547bSAdrian Chadd 					AR_PHY_65NM_CH1_RXTX4, AR_PHY_65NM_RXTX4_XLNA_BIAS, value);
464676bd547bSAdrian Chadd             value = (x_lNABias >> 4) & ( 0x03 );	// bit4,5 for chain2
464776bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah,
464876bd547bSAdrian Chadd 					AR_PHY_65NM_CH2_RXTX4, AR_PHY_65NM_RXTX4_XLNA_BIAS, value);
464976bd547bSAdrian Chadd         }
465076bd547bSAdrian Chadd     }
465176bd547bSAdrian Chadd     return AH_TRUE;
465276bd547bSAdrian Chadd }
465376bd547bSAdrian Chadd 
465476bd547bSAdrian Chadd 
465576bd547bSAdrian Chadd /*
465676bd547bSAdrian Chadd  * Read EEPROM header info and program the device for correct operation
465776bd547bSAdrian Chadd  * given the channel value.
465876bd547bSAdrian Chadd  */
465976bd547bSAdrian Chadd HAL_BOOL
ar9300_eeprom_set_board_values(struct ath_hal * ah,const struct ieee80211_channel * chan)4660e113789bSAdrian Chadd ar9300_eeprom_set_board_values(struct ath_hal *ah, const struct ieee80211_channel *chan)
466176bd547bSAdrian Chadd {
4662e113789bSAdrian Chadd     HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan);
466376bd547bSAdrian Chadd 
4664e113789bSAdrian Chadd     ar9300_xpa_bias_level_apply(ah, IEEE80211_IS_CHAN_2GHZ(chan));
466576bd547bSAdrian Chadd 
4666e113789bSAdrian Chadd     ar9300_xpa_timing_control_apply(ah, IEEE80211_IS_CHAN_2GHZ(chan));
4667e113789bSAdrian Chadd 
4668e113789bSAdrian Chadd     ar9300_ant_ctrl_apply(ah, IEEE80211_IS_CHAN_2GHZ(chan));
466976bd547bSAdrian Chadd     ar9300_drive_strength_apply(ah);
467076bd547bSAdrian Chadd 
4671e113789bSAdrian Chadd     ar9300_x_lNA_bias_strength_apply(ah, IEEE80211_IS_CHAN_2GHZ(chan));
467276bd547bSAdrian Chadd 
467376bd547bSAdrian Chadd 	/* wait for Poseidon internal regular turnning */
467476bd547bSAdrian Chadd     /* for Hornet we move it before initPLL to avoid an access issue */
467576bd547bSAdrian Chadd     /* Function not used when EMULATION. */
467627e2ad46SAdrian Chadd     if (!AR_SREV_HORNET(ah) && !AR_SREV_WASP(ah) && !AR_SREV_HONEYBEE(ah)) {
467776bd547bSAdrian Chadd         ar9300_internal_regulator_apply(ah);
467876bd547bSAdrian Chadd     }
467976bd547bSAdrian Chadd 
4680e113789bSAdrian Chadd     ar9300_attenuation_apply(ah, ichan->channel);
4681e113789bSAdrian Chadd     ar9300_quick_drop_apply(ah, ichan->channel);
468276bd547bSAdrian Chadd     ar9300_thermometer_apply(ah);
468376bd547bSAdrian Chadd     if(!AR_SREV_WASP(ah))
468476bd547bSAdrian Chadd     {
468576bd547bSAdrian Chadd         ar9300_tuning_caps_apply(ah);
468676bd547bSAdrian Chadd     }
468776bd547bSAdrian Chadd 
4688e113789bSAdrian Chadd     ar9300_tx_end_to_xpab_off_apply(ah, ichan->channel);
468976bd547bSAdrian Chadd 
469076bd547bSAdrian Chadd     return AH_TRUE;
469176bd547bSAdrian Chadd }
469276bd547bSAdrian Chadd 
469376bd547bSAdrian Chadd u_int8_t *
ar9300_eeprom_get_spur_chans_ptr(struct ath_hal * ah,HAL_BOOL is_2ghz)469476bd547bSAdrian Chadd ar9300_eeprom_get_spur_chans_ptr(struct ath_hal *ah, HAL_BOOL is_2ghz)
469576bd547bSAdrian Chadd {
469676bd547bSAdrian Chadd     ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom;
469776bd547bSAdrian Chadd 
469876bd547bSAdrian Chadd     if (is_2ghz) {
469976bd547bSAdrian Chadd         return &(eep->modal_header_2g.spur_chans[0]);
470076bd547bSAdrian Chadd     } else {
470176bd547bSAdrian Chadd         return &(eep->modal_header_5g.spur_chans[0]);
470276bd547bSAdrian Chadd     }
470376bd547bSAdrian Chadd }
470476bd547bSAdrian Chadd 
ar9300_eeprom_get_tx_gain_table_number_max(struct ath_hal * ah)470576bd547bSAdrian Chadd static u_int8_t ar9300_eeprom_get_tx_gain_table_number_max(struct ath_hal *ah)
470676bd547bSAdrian Chadd {
470776bd547bSAdrian Chadd     unsigned long tx_gain_table_max;
470876bd547bSAdrian Chadd     tx_gain_table_max = OS_REG_READ_FIELD(ah,
470976bd547bSAdrian Chadd         AR_PHY_TPC_7, AR_PHY_TPC_7_TX_GAIN_TABLE_MAX);
471076bd547bSAdrian Chadd     return tx_gain_table_max;
471176bd547bSAdrian Chadd }
471276bd547bSAdrian Chadd 
ar9300_eeprom_tx_gain_table_index_max_apply(struct ath_hal * ah,u_int16_t channel)471376bd547bSAdrian Chadd u_int8_t ar9300_eeprom_tx_gain_table_index_max_apply(struct ath_hal *ah, u_int16_t channel)
471476bd547bSAdrian Chadd {
471576bd547bSAdrian Chadd     unsigned int index;
471676bd547bSAdrian Chadd     ar9300_eeprom_t *ahp_Eeprom;
471776bd547bSAdrian Chadd     struct ath_hal_9300 *ahp = AH9300(ah);
471876bd547bSAdrian Chadd 
471976bd547bSAdrian Chadd     ahp_Eeprom = &ahp->ah_eeprom;
472076bd547bSAdrian Chadd 
472176bd547bSAdrian Chadd     if (ahp_Eeprom->base_ext1.misc_enable == 0)
472276bd547bSAdrian Chadd         return AH_FALSE;
472376bd547bSAdrian Chadd 
472476bd547bSAdrian Chadd     if (channel < 4000)
472576bd547bSAdrian Chadd     {
472676bd547bSAdrian Chadd         index = ahp_Eeprom->modal_header_2g.tx_gain_cap;
472776bd547bSAdrian Chadd     }
472876bd547bSAdrian Chadd     else
472976bd547bSAdrian Chadd     {
473076bd547bSAdrian Chadd         index = ahp_Eeprom->modal_header_5g.tx_gain_cap;
473176bd547bSAdrian Chadd     }
473276bd547bSAdrian Chadd 
473376bd547bSAdrian Chadd     OS_REG_RMW_FIELD(ah,
473476bd547bSAdrian Chadd         AR_PHY_TPC_7, AR_PHY_TPC_7_TX_GAIN_TABLE_MAX, index);
473576bd547bSAdrian Chadd     return AH_TRUE;
473676bd547bSAdrian Chadd }
473776bd547bSAdrian Chadd 
ar9300_eeprom_get_pcdac_tx_gain_table_i(struct ath_hal * ah,int i,u_int8_t * pcdac)473876bd547bSAdrian Chadd static u_int8_t ar9300_eeprom_get_pcdac_tx_gain_table_i(struct ath_hal *ah,
473976bd547bSAdrian Chadd                                                int i, u_int8_t *pcdac)
474076bd547bSAdrian Chadd {
474176bd547bSAdrian Chadd     unsigned long tx_gain;
474276bd547bSAdrian Chadd     u_int8_t tx_gain_table_max;
474376bd547bSAdrian Chadd     tx_gain_table_max = ar9300_eeprom_get_tx_gain_table_number_max(ah);
474476bd547bSAdrian Chadd     if (i <= 0 || i > tx_gain_table_max) {
474576bd547bSAdrian Chadd         *pcdac = 0;
474676bd547bSAdrian Chadd         return AH_FALSE;
474776bd547bSAdrian Chadd     }
474876bd547bSAdrian Chadd 
474976bd547bSAdrian Chadd     tx_gain = OS_REG_READ(ah, AR_PHY_TXGAIN_TAB(1) + i * 4);
475076bd547bSAdrian Chadd     *pcdac = ((tx_gain >> 24) & 0xff);
475176bd547bSAdrian Chadd     return AH_TRUE;
475276bd547bSAdrian Chadd }
475376bd547bSAdrian Chadd 
ar9300_eeprom_set_tx_gain_cap(struct ath_hal * ah,int * tx_gain_max)475476bd547bSAdrian Chadd u_int8_t ar9300_eeprom_set_tx_gain_cap(struct ath_hal *ah,
475576bd547bSAdrian Chadd                                                int *tx_gain_max)
475676bd547bSAdrian Chadd // pcdac read back from reg, read back value depends on reset 2GHz/5GHz ini
475776bd547bSAdrian Chadd // tx_gain_table, this function will be called twice after each
475876bd547bSAdrian Chadd // band's calibration.
475976bd547bSAdrian Chadd // after 2GHz cal, tx_gain_max[0] has 2GHz, calibration max txgain,
476076bd547bSAdrian Chadd // tx_gain_max[1]=-100
476176bd547bSAdrian Chadd // after 5GHz cal, tx_gain_max[0],tx_gain_max[1] have calibration
476276bd547bSAdrian Chadd // value for both band
476376bd547bSAdrian Chadd // reset is on 5GHz, reg reading from tx_gain_table is for 5GHz,
476476bd547bSAdrian Chadd // so program can't recalculate 2g.tx_gain_cap at this point.
476576bd547bSAdrian Chadd {
476676bd547bSAdrian Chadd     int i = 0, ig, im = 0;
476776bd547bSAdrian Chadd     u_int8_t pcdac = 0;
476876bd547bSAdrian Chadd     u_int8_t tx_gain_table_max;
476976bd547bSAdrian Chadd     ar9300_eeprom_t *ahp_Eeprom;
477076bd547bSAdrian Chadd     struct ath_hal_9300 *ahp = AH9300(ah);
477176bd547bSAdrian Chadd 
477276bd547bSAdrian Chadd     ahp_Eeprom = &ahp->ah_eeprom;
477376bd547bSAdrian Chadd 
477476bd547bSAdrian Chadd     if (ahp_Eeprom->base_ext1.misc_enable == 0)
477576bd547bSAdrian Chadd         return AH_FALSE;
477676bd547bSAdrian Chadd 
477776bd547bSAdrian Chadd     tx_gain_table_max = ar9300_eeprom_get_tx_gain_table_number_max(ah);
477876bd547bSAdrian Chadd 
477976bd547bSAdrian Chadd     for (i = 0; i < 2; i++) {
478076bd547bSAdrian Chadd         if (tx_gain_max[i]>-100) {	// -100 didn't cal that band.
478176bd547bSAdrian Chadd             if ( i== 0) {
478276bd547bSAdrian Chadd                 if (tx_gain_max[1]>-100) {
478376bd547bSAdrian Chadd                     continue;
478476bd547bSAdrian Chadd                     // both band are calibrated, skip 2GHz 2g.tx_gain_cap reset
478576bd547bSAdrian Chadd                 }
478676bd547bSAdrian Chadd             }
478776bd547bSAdrian Chadd             for (ig = 1; ig <= tx_gain_table_max; ig++) {
478876bd547bSAdrian Chadd                 if (ah != 0 && ah->ah_reset != 0)
478976bd547bSAdrian Chadd                 {
479076bd547bSAdrian Chadd                     ar9300_eeprom_get_pcdac_tx_gain_table_i(ah, ig, &pcdac);
479176bd547bSAdrian Chadd                     if (pcdac >= tx_gain_max[i])
479276bd547bSAdrian Chadd                         break;
479376bd547bSAdrian Chadd                 }
479476bd547bSAdrian Chadd             }
479576bd547bSAdrian Chadd             if (ig+1 <= tx_gain_table_max) {
479676bd547bSAdrian Chadd                 if (pcdac == tx_gain_max[i])
479776bd547bSAdrian Chadd                     im = ig;
479876bd547bSAdrian Chadd                 else
479976bd547bSAdrian Chadd                     im = ig + 1;
480076bd547bSAdrian Chadd                 if (i == 0) {
480176bd547bSAdrian Chadd                     ahp_Eeprom->modal_header_2g.tx_gain_cap = im;
480276bd547bSAdrian Chadd                 } else {
480376bd547bSAdrian Chadd                     ahp_Eeprom->modal_header_5g.tx_gain_cap = im;
480476bd547bSAdrian Chadd                 }
480576bd547bSAdrian Chadd             } else {
480676bd547bSAdrian Chadd                 if (i == 0) {
480776bd547bSAdrian Chadd                     ahp_Eeprom->modal_header_2g.tx_gain_cap = ig;
480876bd547bSAdrian Chadd                 } else {
480976bd547bSAdrian Chadd                     ahp_Eeprom->modal_header_5g.tx_gain_cap = ig;
481076bd547bSAdrian Chadd                 }
481176bd547bSAdrian Chadd             }
481276bd547bSAdrian Chadd         }
481376bd547bSAdrian Chadd     }
481476bd547bSAdrian Chadd     return AH_TRUE;
481576bd547bSAdrian Chadd }
4816