1b7d5e03cSMatthew Dillon /*
2b7d5e03cSMatthew Dillon * Copyright (c) 2013 Qualcomm Atheros, Inc.
3b7d5e03cSMatthew Dillon *
4b7d5e03cSMatthew Dillon * Permission to use, copy, modify, and/or distribute this software for any
5b7d5e03cSMatthew Dillon * purpose with or without fee is hereby granted, provided that the above
6b7d5e03cSMatthew Dillon * copyright notice and this permission notice appear in all copies.
7b7d5e03cSMatthew Dillon *
8b7d5e03cSMatthew Dillon * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
9b7d5e03cSMatthew Dillon * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10b7d5e03cSMatthew Dillon * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
11b7d5e03cSMatthew Dillon * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12b7d5e03cSMatthew Dillon * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
13b7d5e03cSMatthew Dillon * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14b7d5e03cSMatthew Dillon * PERFORMANCE OF THIS SOFTWARE.
15b7d5e03cSMatthew Dillon */
16b7d5e03cSMatthew Dillon
17b7d5e03cSMatthew Dillon #include "opt_ah.h"
18b7d5e03cSMatthew Dillon
19b7d5e03cSMatthew Dillon #include "ah.h"
20b7d5e03cSMatthew Dillon #include "ah_internal.h"
21b7d5e03cSMatthew Dillon #include "ah_devid.h"
22b7d5e03cSMatthew Dillon #ifdef AH_DEBUG
23b7d5e03cSMatthew Dillon #include "ah_desc.h" /* NB: for HAL_PHYERR* */
24b7d5e03cSMatthew Dillon #endif
25b7d5e03cSMatthew Dillon #include "ar9300/ar9300.h"
26b7d5e03cSMatthew Dillon #include "ar9300/ar9300eep.h"
27b7d5e03cSMatthew Dillon #include "ar9300/ar9300template_generic.h"
28b7d5e03cSMatthew Dillon #include "ar9300/ar9300template_xb112.h"
29b7d5e03cSMatthew Dillon #include "ar9300/ar9300template_hb116.h"
30b7d5e03cSMatthew Dillon #include "ar9300/ar9300template_xb113.h"
31b7d5e03cSMatthew Dillon #include "ar9300/ar9300template_hb112.h"
32b7d5e03cSMatthew Dillon #include "ar9300/ar9300template_ap121.h"
33b7d5e03cSMatthew Dillon #include "ar9300/ar9300template_osprey_k31.h"
34b7d5e03cSMatthew Dillon #include "ar9300/ar9300template_wasp_2.h"
35b7d5e03cSMatthew Dillon #include "ar9300/ar9300template_wasp_k31.h"
36b7d5e03cSMatthew Dillon #include "ar9300/ar9300template_aphrodite.h"
37b7d5e03cSMatthew Dillon #include "ar9300/ar9300reg.h"
38b7d5e03cSMatthew Dillon #include "ar9300/ar9300phy.h"
39b7d5e03cSMatthew Dillon
40b7d5e03cSMatthew Dillon
41b7d5e03cSMatthew Dillon
42b7d5e03cSMatthew Dillon #if AH_BYTE_ORDER == AH_BIG_ENDIAN
43b7d5e03cSMatthew Dillon void ar9300_swap_eeprom(ar9300_eeprom_t *eep);
44b7d5e03cSMatthew Dillon void ar9300_eeprom_template_swap(void);
45b7d5e03cSMatthew Dillon #endif
46b7d5e03cSMatthew Dillon
47b7d5e03cSMatthew Dillon static u_int16_t ar9300_eeprom_get_spur_chan(struct ath_hal *ah,
48b7d5e03cSMatthew Dillon int spur_chan, HAL_BOOL is_2ghz);
49b7d5e03cSMatthew Dillon #ifdef UNUSED
50b7d5e03cSMatthew Dillon static inline HAL_BOOL ar9300_fill_eeprom(struct ath_hal *ah);
51b7d5e03cSMatthew Dillon static inline HAL_STATUS ar9300_check_eeprom(struct ath_hal *ah);
52b7d5e03cSMatthew Dillon #endif
53b7d5e03cSMatthew Dillon
54b7d5e03cSMatthew Dillon static ar9300_eeprom_t *default9300[] =
55b7d5e03cSMatthew Dillon {
56b7d5e03cSMatthew Dillon &ar9300_template_generic,
57b7d5e03cSMatthew Dillon &ar9300_template_xb112,
58b7d5e03cSMatthew Dillon &ar9300_template_hb116,
59b7d5e03cSMatthew Dillon &ar9300_template_hb112,
60b7d5e03cSMatthew Dillon &ar9300_template_xb113,
61b7d5e03cSMatthew Dillon &ar9300_template_ap121,
62b7d5e03cSMatthew Dillon &ar9300_template_wasp_2,
63b7d5e03cSMatthew Dillon &ar9300_template_wasp_k31,
64b7d5e03cSMatthew Dillon &ar9300_template_osprey_k31,
65b7d5e03cSMatthew Dillon &ar9300_template_aphrodite,
66b7d5e03cSMatthew Dillon };
67b7d5e03cSMatthew Dillon
68b7d5e03cSMatthew Dillon /*
69b7d5e03cSMatthew Dillon * Different types of memory where the calibration data might be stored.
70b7d5e03cSMatthew Dillon * All types are searched in ar9300_eeprom_restore()
71b7d5e03cSMatthew Dillon * in the order flash, eeprom, otp.
72b7d5e03cSMatthew Dillon * To disable searching a type, set its parameter to 0.
73b7d5e03cSMatthew Dillon */
74b7d5e03cSMatthew Dillon
75b7d5e03cSMatthew Dillon /*
76b7d5e03cSMatthew Dillon * This is where we look for the calibration data.
77b7d5e03cSMatthew Dillon * must be set before ath_attach() is called
78b7d5e03cSMatthew Dillon */
79b7d5e03cSMatthew Dillon static int calibration_data_try = calibration_data_none;
80b7d5e03cSMatthew Dillon static int calibration_data_try_address = 0;
81b7d5e03cSMatthew Dillon
82b7d5e03cSMatthew Dillon /*
83b7d5e03cSMatthew Dillon * Set the type of memory used to store calibration data.
84b7d5e03cSMatthew Dillon * Used by nart to force reading/writing of a specific type.
85b7d5e03cSMatthew Dillon * The driver can normally allow autodetection
86b7d5e03cSMatthew Dillon * by setting source to calibration_data_none=0.
87b7d5e03cSMatthew Dillon */
ar9300_calibration_data_set(struct ath_hal * ah,int32_t source)88b7d5e03cSMatthew Dillon void ar9300_calibration_data_set(struct ath_hal *ah, int32_t source)
89b7d5e03cSMatthew Dillon {
90b7d5e03cSMatthew Dillon if (ah != 0) {
91b7d5e03cSMatthew Dillon AH9300(ah)->calibration_data_source = source;
92b7d5e03cSMatthew Dillon } else {
93b7d5e03cSMatthew Dillon calibration_data_try = source;
94b7d5e03cSMatthew Dillon }
95b7d5e03cSMatthew Dillon }
96b7d5e03cSMatthew Dillon
ar9300_calibration_data_get(struct ath_hal * ah)97b7d5e03cSMatthew Dillon int32_t ar9300_calibration_data_get(struct ath_hal *ah)
98b7d5e03cSMatthew Dillon {
99b7d5e03cSMatthew Dillon if (ah != 0) {
100b7d5e03cSMatthew Dillon return AH9300(ah)->calibration_data_source;
101b7d5e03cSMatthew Dillon } else {
102b7d5e03cSMatthew Dillon return calibration_data_try;
103b7d5e03cSMatthew Dillon }
104b7d5e03cSMatthew Dillon }
105b7d5e03cSMatthew Dillon
106b7d5e03cSMatthew Dillon /*
107b7d5e03cSMatthew Dillon * Set the address of first byte used to store calibration data.
108b7d5e03cSMatthew Dillon * Used by nart to force reading/writing at a specific address.
109b7d5e03cSMatthew Dillon * The driver can normally allow autodetection by setting size=0.
110b7d5e03cSMatthew Dillon */
ar9300_calibration_data_address_set(struct ath_hal * ah,int32_t size)111b7d5e03cSMatthew Dillon void ar9300_calibration_data_address_set(struct ath_hal *ah, int32_t size)
112b7d5e03cSMatthew Dillon {
113b7d5e03cSMatthew Dillon if (ah != 0) {
114b7d5e03cSMatthew Dillon AH9300(ah)->calibration_data_source_address = size;
115b7d5e03cSMatthew Dillon } else {
116b7d5e03cSMatthew Dillon calibration_data_try_address = size;
117b7d5e03cSMatthew Dillon }
118b7d5e03cSMatthew Dillon }
119b7d5e03cSMatthew Dillon
ar9300_calibration_data_address_get(struct ath_hal * ah)120b7d5e03cSMatthew Dillon int32_t ar9300_calibration_data_address_get(struct ath_hal *ah)
121b7d5e03cSMatthew Dillon {
122b7d5e03cSMatthew Dillon if (ah != 0) {
123b7d5e03cSMatthew Dillon return AH9300(ah)->calibration_data_source_address;
124b7d5e03cSMatthew Dillon } else {
125b7d5e03cSMatthew Dillon return calibration_data_try_address;
126b7d5e03cSMatthew Dillon }
127b7d5e03cSMatthew Dillon }
128b7d5e03cSMatthew Dillon
129b7d5e03cSMatthew Dillon /*
130b7d5e03cSMatthew Dillon * This is the template that is loaded if ar9300_eeprom_restore()
131b7d5e03cSMatthew Dillon * can't find valid data in the memory.
132b7d5e03cSMatthew Dillon */
133b7d5e03cSMatthew Dillon static int Ar9300_eeprom_template_preference = ar9300_eeprom_template_generic;
134b7d5e03cSMatthew Dillon
ar9300_eeprom_template_preference(int32_t value)135b7d5e03cSMatthew Dillon void ar9300_eeprom_template_preference(int32_t value)
136b7d5e03cSMatthew Dillon {
137b7d5e03cSMatthew Dillon Ar9300_eeprom_template_preference = value;
138b7d5e03cSMatthew Dillon }
139b7d5e03cSMatthew Dillon
140b7d5e03cSMatthew Dillon /*
141b7d5e03cSMatthew Dillon * Install the specified default template.
142b7d5e03cSMatthew Dillon * Overwrites any existing calibration and configuration information in memory.
143b7d5e03cSMatthew Dillon */
ar9300_eeprom_template_install(struct ath_hal * ah,int32_t value)144b7d5e03cSMatthew Dillon int32_t ar9300_eeprom_template_install(struct ath_hal *ah, int32_t value)
145b7d5e03cSMatthew Dillon {
146b7d5e03cSMatthew Dillon struct ath_hal_9300 *ahp = AH9300(ah);
147b7d5e03cSMatthew Dillon ar9300_eeprom_t *mptr, *dptr;
148b7d5e03cSMatthew Dillon int mdata_size;
149b7d5e03cSMatthew Dillon
150b7d5e03cSMatthew Dillon mptr = &ahp->ah_eeprom;
151b7d5e03cSMatthew Dillon mdata_size = ar9300_eeprom_struct_size();
152b7d5e03cSMatthew Dillon if (mptr != 0) {
153b7d5e03cSMatthew Dillon #if 0
154b7d5e03cSMatthew Dillon calibration_data_source = calibration_data_none;
155b7d5e03cSMatthew Dillon calibration_data_source_address = 0;
156b7d5e03cSMatthew Dillon #endif
157b7d5e03cSMatthew Dillon dptr = ar9300_eeprom_struct_default_find_by_id(value);
158b7d5e03cSMatthew Dillon if (dptr != 0) {
159b7d5e03cSMatthew Dillon OS_MEMCPY(mptr, dptr, mdata_size);
160b7d5e03cSMatthew Dillon return 0;
161b7d5e03cSMatthew Dillon }
162b7d5e03cSMatthew Dillon }
163b7d5e03cSMatthew Dillon return -1;
164b7d5e03cSMatthew Dillon }
165b7d5e03cSMatthew Dillon
166b7d5e03cSMatthew Dillon static int
ar9300_eeprom_restore_something(struct ath_hal * ah,ar9300_eeprom_t * mptr,int mdata_size)167b7d5e03cSMatthew Dillon ar9300_eeprom_restore_something(struct ath_hal *ah, ar9300_eeprom_t *mptr,
168b7d5e03cSMatthew Dillon int mdata_size)
169b7d5e03cSMatthew Dillon {
170b7d5e03cSMatthew Dillon int it;
171b7d5e03cSMatthew Dillon ar9300_eeprom_t *dptr;
172b7d5e03cSMatthew Dillon int nptr;
173b7d5e03cSMatthew Dillon
174b7d5e03cSMatthew Dillon nptr = -1;
175b7d5e03cSMatthew Dillon /*
176b7d5e03cSMatthew Dillon * if we didn't find any blocks in the memory,
177b7d5e03cSMatthew Dillon * put the prefered template in place
178b7d5e03cSMatthew Dillon */
179b7d5e03cSMatthew Dillon if (nptr < 0) {
180b7d5e03cSMatthew Dillon AH9300(ah)->calibration_data_source = calibration_data_none;
181b7d5e03cSMatthew Dillon AH9300(ah)->calibration_data_source_address = 0;
182b7d5e03cSMatthew Dillon dptr = ar9300_eeprom_struct_default_find_by_id(
183b7d5e03cSMatthew Dillon Ar9300_eeprom_template_preference);
184b7d5e03cSMatthew Dillon if (dptr != 0) {
185b7d5e03cSMatthew Dillon OS_MEMCPY(mptr, dptr, mdata_size);
186b7d5e03cSMatthew Dillon nptr = 0;
187b7d5e03cSMatthew Dillon }
188b7d5e03cSMatthew Dillon }
189b7d5e03cSMatthew Dillon /*
190b7d5e03cSMatthew Dillon * if we didn't find the prefered one,
191b7d5e03cSMatthew Dillon * put the normal default template in place
192b7d5e03cSMatthew Dillon */
193b7d5e03cSMatthew Dillon if (nptr < 0) {
194b7d5e03cSMatthew Dillon AH9300(ah)->calibration_data_source = calibration_data_none;
195b7d5e03cSMatthew Dillon AH9300(ah)->calibration_data_source_address = 0;
196b7d5e03cSMatthew Dillon dptr = ar9300_eeprom_struct_default_find_by_id(
197b7d5e03cSMatthew Dillon ar9300_eeprom_template_default);
198b7d5e03cSMatthew Dillon if (dptr != 0) {
199b7d5e03cSMatthew Dillon OS_MEMCPY(mptr, dptr, mdata_size);
200b7d5e03cSMatthew Dillon nptr = 0;
201b7d5e03cSMatthew Dillon }
202b7d5e03cSMatthew Dillon }
203b7d5e03cSMatthew Dillon /*
204b7d5e03cSMatthew Dillon * if we can't find the best template, put any old template in place
205b7d5e03cSMatthew Dillon * presume that newer ones are better, so search backwards
206b7d5e03cSMatthew Dillon */
207b7d5e03cSMatthew Dillon if (nptr < 0) {
208b7d5e03cSMatthew Dillon AH9300(ah)->calibration_data_source = calibration_data_none;
209b7d5e03cSMatthew Dillon AH9300(ah)->calibration_data_source_address = 0;
210b7d5e03cSMatthew Dillon for (it = ar9300_eeprom_struct_default_many() - 1; it >= 0; it--) {
211b7d5e03cSMatthew Dillon dptr = ar9300_eeprom_struct_default(it);
212b7d5e03cSMatthew Dillon if (dptr != 0) {
213b7d5e03cSMatthew Dillon OS_MEMCPY(mptr, dptr, mdata_size);
214b7d5e03cSMatthew Dillon nptr = 0;
215b7d5e03cSMatthew Dillon break;
216b7d5e03cSMatthew Dillon }
217b7d5e03cSMatthew Dillon }
218b7d5e03cSMatthew Dillon }
219b7d5e03cSMatthew Dillon return nptr;
220b7d5e03cSMatthew Dillon }
221b7d5e03cSMatthew Dillon
222b7d5e03cSMatthew Dillon /*
223b7d5e03cSMatthew Dillon * Read 16 bits of data from offset into *data
224b7d5e03cSMatthew Dillon */
225b7d5e03cSMatthew Dillon HAL_BOOL
ar9300_eeprom_read_word(struct ath_hal * ah,u_int off,u_int16_t * data)226b7d5e03cSMatthew Dillon ar9300_eeprom_read_word(struct ath_hal *ah, u_int off, u_int16_t *data)
227b7d5e03cSMatthew Dillon {
228b7d5e03cSMatthew Dillon if (AR_SREV_OSPREY(ah) || AR_SREV_POSEIDON(ah))
229b7d5e03cSMatthew Dillon {
230b7d5e03cSMatthew Dillon (void) OS_REG_READ(ah, AR9300_EEPROM_OFFSET + (off << AR9300_EEPROM_S));
231b7d5e03cSMatthew Dillon if (!ath_hal_wait(ah,
232b7d5e03cSMatthew Dillon AR_HOSTIF_REG(ah, AR_EEPROM_STATUS_DATA),
233b7d5e03cSMatthew Dillon AR_EEPROM_STATUS_DATA_BUSY | AR_EEPROM_STATUS_DATA_PROT_ACCESS,
234b7d5e03cSMatthew Dillon 0))
235b7d5e03cSMatthew Dillon {
236b7d5e03cSMatthew Dillon return AH_FALSE;
237b7d5e03cSMatthew Dillon }
238b7d5e03cSMatthew Dillon *data = MS(OS_REG_READ(ah,
239b7d5e03cSMatthew Dillon AR_HOSTIF_REG(ah, AR_EEPROM_STATUS_DATA)), AR_EEPROM_STATUS_DATA_VAL);
240b7d5e03cSMatthew Dillon return AH_TRUE;
241b7d5e03cSMatthew Dillon }
242b7d5e03cSMatthew Dillon else
243b7d5e03cSMatthew Dillon {
244b7d5e03cSMatthew Dillon *data = 0;
245b7d5e03cSMatthew Dillon return AH_FALSE;
246b7d5e03cSMatthew Dillon }
247b7d5e03cSMatthew Dillon }
248b7d5e03cSMatthew Dillon
249b7d5e03cSMatthew Dillon
250b7d5e03cSMatthew Dillon HAL_BOOL
ar9300_otp_read(struct ath_hal * ah,u_int off,u_int32_t * data,HAL_BOOL is_wifi)251b7d5e03cSMatthew Dillon ar9300_otp_read(struct ath_hal *ah, u_int off, u_int32_t *data, HAL_BOOL is_wifi)
252b7d5e03cSMatthew Dillon {
253b7d5e03cSMatthew Dillon int time_out = 1000;
254b7d5e03cSMatthew Dillon int status = 0;
255b7d5e03cSMatthew Dillon u_int32_t addr;
256b7d5e03cSMatthew Dillon
257a20e5e51SMatthew Dillon if (AR_SREV_HONEYBEE(ah)){ /* no OTP for Honeybee */
258a20e5e51SMatthew Dillon return false;
259a20e5e51SMatthew Dillon }
260b7d5e03cSMatthew Dillon addr = (AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah))?
261b7d5e03cSMatthew Dillon OTP_MEM_START_ADDRESS_WASP : OTP_MEM_START_ADDRESS;
262b7d5e03cSMatthew Dillon if (!is_wifi) {
263b7d5e03cSMatthew Dillon addr = BTOTP_MEM_START_ADDRESS;
264b7d5e03cSMatthew Dillon }
265b7d5e03cSMatthew Dillon addr += off * 4; /* OTP is 32 bit addressable */
266b7d5e03cSMatthew Dillon (void) OS_REG_READ(ah, addr);
267b7d5e03cSMatthew Dillon
268b7d5e03cSMatthew Dillon addr = (AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) ?
269b7d5e03cSMatthew Dillon OTP_STATUS0_OTP_SM_BUSY_WASP : OTP_STATUS0_OTP_SM_BUSY;
270b7d5e03cSMatthew Dillon if (!is_wifi) {
271b7d5e03cSMatthew Dillon addr = BTOTP_STATUS0_OTP_SM_BUSY;
272b7d5e03cSMatthew Dillon }
273b7d5e03cSMatthew Dillon while ((time_out > 0) && (!status)) { /* wait for access complete */
274b7d5e03cSMatthew Dillon /* Read data valid, access not busy, sm not busy */
275b7d5e03cSMatthew Dillon status = ((OS_REG_READ(ah, addr) & 0x7) == 0x4) ? 1 : 0;
276b7d5e03cSMatthew Dillon time_out--;
277b7d5e03cSMatthew Dillon }
278b7d5e03cSMatthew Dillon if (time_out == 0) {
279b7d5e03cSMatthew Dillon HALDEBUG(ah, HAL_DEBUG_EEPROM,
280b7d5e03cSMatthew Dillon "%s: Timed out during OTP Status0 validation\n", __func__);
281b7d5e03cSMatthew Dillon return AH_FALSE;
282b7d5e03cSMatthew Dillon }
283b7d5e03cSMatthew Dillon
284b7d5e03cSMatthew Dillon addr = (AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) ?
285b7d5e03cSMatthew Dillon OTP_STATUS1_EFUSE_READ_DATA_WASP : OTP_STATUS1_EFUSE_READ_DATA;
286b7d5e03cSMatthew Dillon if (!is_wifi) {
287b7d5e03cSMatthew Dillon addr = BTOTP_STATUS1_EFUSE_READ_DATA;
288b7d5e03cSMatthew Dillon }
289b7d5e03cSMatthew Dillon *data = OS_REG_READ(ah, addr);
290b7d5e03cSMatthew Dillon return AH_TRUE;
291b7d5e03cSMatthew Dillon }
292b7d5e03cSMatthew Dillon
293b7d5e03cSMatthew Dillon
294b7d5e03cSMatthew Dillon
295b7d5e03cSMatthew Dillon
296b7d5e03cSMatthew Dillon static HAL_STATUS
ar9300_flash_map(struct ath_hal * ah)297b7d5e03cSMatthew Dillon ar9300_flash_map(struct ath_hal *ah)
298b7d5e03cSMatthew Dillon {
299b7d5e03cSMatthew Dillon /* XXX disable flash remapping for now (ie, SoC support) */
300b7d5e03cSMatthew Dillon ath_hal_printf(ah, "%s: unimplemented for now\n", __func__);
301b7d5e03cSMatthew Dillon #if 0
302b7d5e03cSMatthew Dillon struct ath_hal_9300 *ahp = AH9300(ah);
303b7d5e03cSMatthew Dillon #if defined(AR9100) || defined(__NetBSD__)
304b7d5e03cSMatthew Dillon ahp->ah_cal_mem = OS_REMAP(ah, AR9300_EEPROM_START_ADDR, AR9300_EEPROM_MAX);
305b7d5e03cSMatthew Dillon #else
306b7d5e03cSMatthew Dillon ahp->ah_cal_mem = OS_REMAP((uintptr_t)(AH_PRIVATE(ah)->ah_st),
307b7d5e03cSMatthew Dillon (AR9300_EEPROM_MAX + AR9300_FLASH_CAL_START_OFFSET));
308b7d5e03cSMatthew Dillon #endif
309b7d5e03cSMatthew Dillon if (!ahp->ah_cal_mem) {
310b7d5e03cSMatthew Dillon HALDEBUG(ah, HAL_DEBUG_EEPROM,
311b7d5e03cSMatthew Dillon "%s: cannot remap eeprom region \n", __func__);
312b7d5e03cSMatthew Dillon return HAL_EIO;
313b7d5e03cSMatthew Dillon }
314b7d5e03cSMatthew Dillon #endif
315b7d5e03cSMatthew Dillon return HAL_OK;
316b7d5e03cSMatthew Dillon }
317b7d5e03cSMatthew Dillon
318b7d5e03cSMatthew Dillon HAL_BOOL
ar9300_flash_read(struct ath_hal * ah,u_int off,u_int16_t * data)319b7d5e03cSMatthew Dillon ar9300_flash_read(struct ath_hal *ah, u_int off, u_int16_t *data)
320b7d5e03cSMatthew Dillon {
321b7d5e03cSMatthew Dillon struct ath_hal_9300 *ahp = AH9300(ah);
322b7d5e03cSMatthew Dillon
323b7d5e03cSMatthew Dillon *data = ((u_int16_t *)ahp->ah_cal_mem)[off];
324b7d5e03cSMatthew Dillon return AH_TRUE;
325b7d5e03cSMatthew Dillon }
326b7d5e03cSMatthew Dillon
327b7d5e03cSMatthew Dillon HAL_BOOL
ar9300_flash_write(struct ath_hal * ah,u_int off,u_int16_t data)328b7d5e03cSMatthew Dillon ar9300_flash_write(struct ath_hal *ah, u_int off, u_int16_t data)
329b7d5e03cSMatthew Dillon {
330b7d5e03cSMatthew Dillon struct ath_hal_9300 *ahp = AH9300(ah);
331b7d5e03cSMatthew Dillon
332b7d5e03cSMatthew Dillon ((u_int16_t *)ahp->ah_cal_mem)[off] = data;
333b7d5e03cSMatthew Dillon return AH_TRUE;
334b7d5e03cSMatthew Dillon }
335b7d5e03cSMatthew Dillon
336b7d5e03cSMatthew Dillon HAL_STATUS
ar9300_eeprom_attach(struct ath_hal * ah)337b7d5e03cSMatthew Dillon ar9300_eeprom_attach(struct ath_hal *ah)
338b7d5e03cSMatthew Dillon {
339b7d5e03cSMatthew Dillon struct ath_hal_9300 *ahp = AH9300(ah);
340b7d5e03cSMatthew Dillon ahp->try_dram = 1;
341b7d5e03cSMatthew Dillon ahp->try_eeprom = 1;
342b7d5e03cSMatthew Dillon ahp->try_otp = 1;
343b7d5e03cSMatthew Dillon #ifdef ATH_CAL_NAND_FLASH
344b7d5e03cSMatthew Dillon ahp->try_nand = 1;
345b7d5e03cSMatthew Dillon #else
346b7d5e03cSMatthew Dillon ahp->try_flash = 1;
347b7d5e03cSMatthew Dillon #endif
348b7d5e03cSMatthew Dillon ahp->calibration_data_source = calibration_data_none;
349b7d5e03cSMatthew Dillon ahp->calibration_data_source_address = 0;
350b7d5e03cSMatthew Dillon ahp->calibration_data_try = calibration_data_try;
351b7d5e03cSMatthew Dillon ahp->calibration_data_try_address = 0;
352b7d5e03cSMatthew Dillon
353b7d5e03cSMatthew Dillon /*
354b7d5e03cSMatthew Dillon * In case flash will be used for EEPROM. Otherwise ahp->ah_cal_mem
355b7d5e03cSMatthew Dillon * must be set to NULL or the real EEPROM address.
356b7d5e03cSMatthew Dillon */
357b7d5e03cSMatthew Dillon ar9300_flash_map(ah);
358b7d5e03cSMatthew Dillon /*
359b7d5e03cSMatthew Dillon * ###### This function always return NO SPUR.
360a20e5e51SMatthew Dillon * This is not true for many board designs.
361b7d5e03cSMatthew Dillon * Does anyone use this?
362b7d5e03cSMatthew Dillon */
363b7d5e03cSMatthew Dillon AH_PRIVATE(ah)->ah_getSpurChan = ar9300_eeprom_get_spur_chan;
364b7d5e03cSMatthew Dillon
365b7d5e03cSMatthew Dillon #ifdef OLDCODE
366b7d5e03cSMatthew Dillon /* XXX Needs to be moved for dynamic selection */
367b7d5e03cSMatthew Dillon ahp->ah_eeprom = *(default9300[ar9300_eeprom_template_default]);
368b7d5e03cSMatthew Dillon
369b7d5e03cSMatthew Dillon
370b7d5e03cSMatthew Dillon if (AR_SREV_HORNET(ah)) {
371b7d5e03cSMatthew Dillon /* Set default values for Hornet. */
372b7d5e03cSMatthew Dillon ahp->ah_eeprom.base_eep_header.op_cap_flags.op_flags =
373b7d5e03cSMatthew Dillon AR9300_OPFLAGS_11G;
374b7d5e03cSMatthew Dillon ahp->ah_eeprom.base_eep_header.txrx_mask = 0x11;
375b7d5e03cSMatthew Dillon } else if (AR_SREV_POSEIDON(ah)) {
376b7d5e03cSMatthew Dillon /* Set default values for Poseidon. */
377b7d5e03cSMatthew Dillon ahp->ah_eeprom.base_eep_header.op_cap_flags.op_flags =
378b7d5e03cSMatthew Dillon AR9300_OPFLAGS_11G;
379b7d5e03cSMatthew Dillon ahp->ah_eeprom.base_eep_header.txrx_mask = 0x11;
380b7d5e03cSMatthew Dillon }
381b7d5e03cSMatthew Dillon
382b7d5e03cSMatthew Dillon if (AH_PRIVATE(ah)->ah_config.ath_hal_skip_eeprom_read) {
383b7d5e03cSMatthew Dillon ahp->ah_emu_eeprom = 1;
384b7d5e03cSMatthew Dillon return HAL_OK;
385b7d5e03cSMatthew Dillon }
386b7d5e03cSMatthew Dillon
387b7d5e03cSMatthew Dillon ahp->ah_emu_eeprom = 1;
388b7d5e03cSMatthew Dillon
389b7d5e03cSMatthew Dillon #ifdef UNUSED
390b7d5e03cSMatthew Dillon #endif
391b7d5e03cSMatthew Dillon
392b7d5e03cSMatthew Dillon if (!ar9300_fill_eeprom(ah)) {
393b7d5e03cSMatthew Dillon return HAL_EIO;
394b7d5e03cSMatthew Dillon }
395b7d5e03cSMatthew Dillon
396b7d5e03cSMatthew Dillon return HAL_OK;
397b7d5e03cSMatthew Dillon /* return ar9300_check_eeprom(ah); */
398b7d5e03cSMatthew Dillon #else
399b7d5e03cSMatthew Dillon ahp->ah_emu_eeprom = 1;
400b7d5e03cSMatthew Dillon
401b7d5e03cSMatthew Dillon #if 0
402b7d5e03cSMatthew Dillon /*#ifdef MDK_AP*/ /* MDK_AP is defined only in NART AP build */
403b7d5e03cSMatthew Dillon u_int8_t buffer[10];
404b7d5e03cSMatthew Dillon int caldata_check = 0;
405b7d5e03cSMatthew Dillon
406b7d5e03cSMatthew Dillon ar9300_calibration_data_read_flash(
407b7d5e03cSMatthew Dillon ah, FLASH_BASE_CALDATA_OFFSET, buffer, 4);
408b7d5e03cSMatthew Dillon printf("flash caldata:: %x\n", buffer[0]);
409b7d5e03cSMatthew Dillon if (buffer[0] != 0xff) {
410b7d5e03cSMatthew Dillon caldata_check = 1;
411b7d5e03cSMatthew Dillon }
412b7d5e03cSMatthew Dillon if (!caldata_check) {
413b7d5e03cSMatthew Dillon ar9300_eeprom_t *mptr;
414b7d5e03cSMatthew Dillon int mdata_size;
415b7d5e03cSMatthew Dillon if (AR_SREV_HORNET(ah)) {
416b7d5e03cSMatthew Dillon /* XXX: For initial testing */
417b7d5e03cSMatthew Dillon mptr = &ahp->ah_eeprom;
418b7d5e03cSMatthew Dillon mdata_size = ar9300_eeprom_struct_size();
419b7d5e03cSMatthew Dillon ahp->ah_eeprom = ar9300_template_ap121;
420b7d5e03cSMatthew Dillon ahp->ah_emu_eeprom = 1;
421b7d5e03cSMatthew Dillon /* need it to let art save in to flash ????? */
422b7d5e03cSMatthew Dillon calibration_data_source = calibration_data_flash;
423b7d5e03cSMatthew Dillon } else if (AR_SREV_WASP(ah)) {
424b7d5e03cSMatthew Dillon /* XXX: For initial testing */
425b7d5e03cSMatthew Dillon ath_hal_printf(ah, " wasp eep attach\n");
426b7d5e03cSMatthew Dillon mptr = &ahp->ah_eeprom;
427b7d5e03cSMatthew Dillon mdata_size = ar9300_eeprom_struct_size();
428b7d5e03cSMatthew Dillon ahp->ah_eeprom = ar9300_template_generic;
429b7d5e03cSMatthew Dillon ahp->ah_eeprom.mac_addr[0] = 0x00;
430b7d5e03cSMatthew Dillon ahp->ah_eeprom.mac_addr[1] = 0x03;
431b7d5e03cSMatthew Dillon ahp->ah_eeprom.mac_addr[2] = 0x7F;
432b7d5e03cSMatthew Dillon ahp->ah_eeprom.mac_addr[3] = 0xBA;
433b7d5e03cSMatthew Dillon ahp->ah_eeprom.mac_addr[4] = 0xD0;
434b7d5e03cSMatthew Dillon ahp->ah_eeprom.mac_addr[5] = 0x00;
435b7d5e03cSMatthew Dillon ahp->ah_emu_eeprom = 1;
436b7d5e03cSMatthew Dillon ahp->ah_eeprom.base_eep_header.txrx_mask = 0x33;
437b7d5e03cSMatthew Dillon ahp->ah_eeprom.base_eep_header.txrxgain = 0x10;
438b7d5e03cSMatthew Dillon /* need it to let art save in to flash ????? */
439b7d5e03cSMatthew Dillon calibration_data_source = calibration_data_flash;
440b7d5e03cSMatthew Dillon }
441b7d5e03cSMatthew Dillon return HAL_OK;
442b7d5e03cSMatthew Dillon }
443b7d5e03cSMatthew Dillon #endif
444a20e5e51SMatthew Dillon if (AR_SREV_HORNET(ah) || AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)
445a20e5e51SMatthew Dillon || AR_SREV_HONEYBEE(ah)) {
446b7d5e03cSMatthew Dillon ahp->try_eeprom = 0;
447b7d5e03cSMatthew Dillon }
448b7d5e03cSMatthew Dillon
449a20e5e51SMatthew Dillon if (AR_SREV_HONEYBEE(ah)) {
450a20e5e51SMatthew Dillon ahp->try_otp = 0;
451a20e5e51SMatthew Dillon }
452a20e5e51SMatthew Dillon
453b7d5e03cSMatthew Dillon if (!ar9300_eeprom_restore(ah)) {
454b7d5e03cSMatthew Dillon return HAL_EIO;
455b7d5e03cSMatthew Dillon }
456b7d5e03cSMatthew Dillon return HAL_OK;
457b7d5e03cSMatthew Dillon #endif
458b7d5e03cSMatthew Dillon }
459b7d5e03cSMatthew Dillon
460b7d5e03cSMatthew Dillon u_int32_t
ar9300_eeprom_get(struct ath_hal_9300 * ahp,EEPROM_PARAM param)461b7d5e03cSMatthew Dillon ar9300_eeprom_get(struct ath_hal_9300 *ahp, EEPROM_PARAM param)
462b7d5e03cSMatthew Dillon {
463b7d5e03cSMatthew Dillon ar9300_eeprom_t *eep = &ahp->ah_eeprom;
464b7d5e03cSMatthew Dillon OSPREY_BASE_EEP_HEADER *p_base = &eep->base_eep_header;
465b7d5e03cSMatthew Dillon OSPREY_BASE_EXTENSION_1 *base_ext1 = &eep->base_ext1;
466b7d5e03cSMatthew Dillon
467b7d5e03cSMatthew Dillon switch (param) {
468b7d5e03cSMatthew Dillon #ifdef NOTYET
469b7d5e03cSMatthew Dillon case EEP_NFTHRESH_5:
470b7d5e03cSMatthew Dillon return p_modal[0].noise_floor_thresh_ch[0];
471b7d5e03cSMatthew Dillon case EEP_NFTHRESH_2:
472b7d5e03cSMatthew Dillon return p_modal[1].noise_floor_thresh_ch[0];
473b7d5e03cSMatthew Dillon #endif
474b7d5e03cSMatthew Dillon case EEP_MAC_LSW:
475b7d5e03cSMatthew Dillon return eep->mac_addr[0] << 8 | eep->mac_addr[1];
476b7d5e03cSMatthew Dillon case EEP_MAC_MID:
477b7d5e03cSMatthew Dillon return eep->mac_addr[2] << 8 | eep->mac_addr[3];
478b7d5e03cSMatthew Dillon case EEP_MAC_MSW:
479b7d5e03cSMatthew Dillon return eep->mac_addr[4] << 8 | eep->mac_addr[5];
480b7d5e03cSMatthew Dillon case EEP_REG_0:
481b7d5e03cSMatthew Dillon return p_base->reg_dmn[0];
482b7d5e03cSMatthew Dillon case EEP_REG_1:
483b7d5e03cSMatthew Dillon return p_base->reg_dmn[1];
484b7d5e03cSMatthew Dillon case EEP_OP_CAP:
485b7d5e03cSMatthew Dillon return p_base->device_cap;
486b7d5e03cSMatthew Dillon case EEP_OP_MODE:
487b7d5e03cSMatthew Dillon return p_base->op_cap_flags.op_flags;
488b7d5e03cSMatthew Dillon case EEP_RF_SILENT:
489b7d5e03cSMatthew Dillon return p_base->rf_silent;
490b7d5e03cSMatthew Dillon #ifdef NOTYET
491b7d5e03cSMatthew Dillon case EEP_OB_5:
492b7d5e03cSMatthew Dillon return p_modal[0].ob;
493b7d5e03cSMatthew Dillon case EEP_DB_5:
494b7d5e03cSMatthew Dillon return p_modal[0].db;
495b7d5e03cSMatthew Dillon case EEP_OB_2:
496b7d5e03cSMatthew Dillon return p_modal[1].ob;
497b7d5e03cSMatthew Dillon case EEP_DB_2:
498b7d5e03cSMatthew Dillon return p_modal[1].db;
499b7d5e03cSMatthew Dillon case EEP_MINOR_REV:
500b7d5e03cSMatthew Dillon return p_base->eeprom_version & AR9300_EEP_VER_MINOR_MASK;
501b7d5e03cSMatthew Dillon #endif
502b7d5e03cSMatthew Dillon case EEP_TX_MASK:
503b7d5e03cSMatthew Dillon return (p_base->txrx_mask >> 4) & 0xf;
504b7d5e03cSMatthew Dillon case EEP_RX_MASK:
505b7d5e03cSMatthew Dillon return p_base->txrx_mask & 0xf;
506b7d5e03cSMatthew Dillon #ifdef NOTYET
507b7d5e03cSMatthew Dillon case EEP_FSTCLK_5G:
508b7d5e03cSMatthew Dillon return p_base->fast_clk5g;
509b7d5e03cSMatthew Dillon case EEP_RXGAIN_TYPE:
510b7d5e03cSMatthew Dillon return p_base->rx_gain_type;
511b7d5e03cSMatthew Dillon #endif
512b7d5e03cSMatthew Dillon case EEP_DRIVE_STRENGTH:
513b7d5e03cSMatthew Dillon #define AR9300_EEP_BASE_DRIVE_STRENGTH 0x1
514b7d5e03cSMatthew Dillon return p_base->misc_configuration & AR9300_EEP_BASE_DRIVE_STRENGTH;
515b7d5e03cSMatthew Dillon case EEP_INTERNAL_REGULATOR:
516b7d5e03cSMatthew Dillon /* Bit 4 is internal regulator flag */
517b7d5e03cSMatthew Dillon return ((p_base->feature_enable & 0x10) >> 4);
518b7d5e03cSMatthew Dillon case EEP_SWREG:
519b7d5e03cSMatthew Dillon return (p_base->swreg);
520b7d5e03cSMatthew Dillon case EEP_PAPRD_ENABLED:
521b7d5e03cSMatthew Dillon /* Bit 5 is paprd flag */
522b7d5e03cSMatthew Dillon return ((p_base->feature_enable & 0x20) >> 5);
523b7d5e03cSMatthew Dillon case EEP_ANTDIV_control:
524b7d5e03cSMatthew Dillon return (u_int32_t)(base_ext1->ant_div_control);
525b7d5e03cSMatthew Dillon case EEP_CHAIN_MASK_REDUCE:
526b7d5e03cSMatthew Dillon return ((p_base->misc_configuration >> 3) & 0x1);
527b7d5e03cSMatthew Dillon case EEP_OL_PWRCTRL:
528b7d5e03cSMatthew Dillon return 0;
529b7d5e03cSMatthew Dillon case EEP_DEV_TYPE:
530b7d5e03cSMatthew Dillon return p_base->device_type;
531b7d5e03cSMatthew Dillon default:
532b7d5e03cSMatthew Dillon HALASSERT(0);
533b7d5e03cSMatthew Dillon return 0;
534b7d5e03cSMatthew Dillon }
535b7d5e03cSMatthew Dillon }
536b7d5e03cSMatthew Dillon
537b7d5e03cSMatthew Dillon
538b7d5e03cSMatthew Dillon
539b7d5e03cSMatthew Dillon /******************************************************************************/
540b7d5e03cSMatthew Dillon /*!
541b7d5e03cSMatthew Dillon ** \brief EEPROM fixup code for INI values
542b7d5e03cSMatthew Dillon **
543b7d5e03cSMatthew Dillon ** This routine provides a place to insert "fixup" code for specific devices
544b7d5e03cSMatthew Dillon ** that need to modify INI values based on EEPROM values, BEFORE the INI values
545b7d5e03cSMatthew Dillon ** are written.
546b7d5e03cSMatthew Dillon ** Certain registers in the INI file can only be written once without
547b7d5e03cSMatthew Dillon ** undesired side effects, and this provides a place for EEPROM overrides
548b7d5e03cSMatthew Dillon ** in these cases.
549b7d5e03cSMatthew Dillon **
550b7d5e03cSMatthew Dillon ** This is called at attach time once. It should not affect run time
551b7d5e03cSMatthew Dillon ** performance at all
552b7d5e03cSMatthew Dillon **
553b7d5e03cSMatthew Dillon ** \param ah Pointer to HAL object (this)
554b7d5e03cSMatthew Dillon ** \param p_eep_data Pointer to (filled in) eeprom data structure
555b7d5e03cSMatthew Dillon ** \param reg register being inspected on this call
556b7d5e03cSMatthew Dillon ** \param value value in INI file
557b7d5e03cSMatthew Dillon **
558b7d5e03cSMatthew Dillon ** \return Updated value for INI file.
559b7d5e03cSMatthew Dillon */
560b7d5e03cSMatthew Dillon u_int32_t
ar9300_ini_fixup(struct ath_hal * ah,ar9300_eeprom_t * p_eep_data,u_int32_t reg,u_int32_t value)561b7d5e03cSMatthew Dillon ar9300_ini_fixup(struct ath_hal *ah, ar9300_eeprom_t *p_eep_data,
562b7d5e03cSMatthew Dillon u_int32_t reg, u_int32_t value)
563b7d5e03cSMatthew Dillon {
564b7d5e03cSMatthew Dillon HALDEBUG(AH_NULL, HAL_DEBUG_UNMASKABLE,
565b7d5e03cSMatthew Dillon "ar9300_eeprom_def_ini_fixup: FIXME\n");
566b7d5e03cSMatthew Dillon #if 0
567b7d5e03cSMatthew Dillon BASE_EEPDEF_HEADER *p_base = &(p_eep_data->base_eep_header);
568b7d5e03cSMatthew Dillon
569b7d5e03cSMatthew Dillon switch (AH_PRIVATE(ah)->ah_devid)
570b7d5e03cSMatthew Dillon {
571b7d5e03cSMatthew Dillon case AR9300_DEVID_AR9300_PCI:
572b7d5e03cSMatthew Dillon /*
573b7d5e03cSMatthew Dillon ** Need to set the external/internal regulator bit to the proper value.
574b7d5e03cSMatthew Dillon ** Can only write this ONCE.
575b7d5e03cSMatthew Dillon */
576b7d5e03cSMatthew Dillon
577b7d5e03cSMatthew Dillon if ( reg == 0x7894 )
578b7d5e03cSMatthew Dillon {
579b7d5e03cSMatthew Dillon /*
580b7d5e03cSMatthew Dillon ** Check for an EEPROM data structure of "0x0b" or better
581b7d5e03cSMatthew Dillon */
582b7d5e03cSMatthew Dillon
583b7d5e03cSMatthew Dillon HALDEBUG(ah, HAL_DEBUG_EEPROM, "ini VAL: %x EEPROM: %x\n",
584b7d5e03cSMatthew Dillon value, (p_base->version & 0xff));
585b7d5e03cSMatthew Dillon
586b7d5e03cSMatthew Dillon if ( (p_base->version & 0xff) > 0x0a) {
587b7d5e03cSMatthew Dillon HALDEBUG(ah, HAL_DEBUG_EEPROM,
588b7d5e03cSMatthew Dillon "PWDCLKIND: %d\n", p_base->pwdclkind);
589b7d5e03cSMatthew Dillon value &= ~AR_AN_TOP2_PWDCLKIND;
590b7d5e03cSMatthew Dillon value |=
591b7d5e03cSMatthew Dillon AR_AN_TOP2_PWDCLKIND &
592b7d5e03cSMatthew Dillon (p_base->pwdclkind << AR_AN_TOP2_PWDCLKIND_S);
593b7d5e03cSMatthew Dillon } else {
594b7d5e03cSMatthew Dillon HALDEBUG(ah, HAL_DEBUG_EEPROM, "PWDCLKIND Earlier Rev\n");
595b7d5e03cSMatthew Dillon }
596b7d5e03cSMatthew Dillon
597b7d5e03cSMatthew Dillon HALDEBUG(ah, HAL_DEBUG_EEPROM, "final ini VAL: %x\n", value);
598b7d5e03cSMatthew Dillon }
599b7d5e03cSMatthew Dillon break;
600b7d5e03cSMatthew Dillon
601b7d5e03cSMatthew Dillon }
602b7d5e03cSMatthew Dillon
603b7d5e03cSMatthew Dillon return (value);
604b7d5e03cSMatthew Dillon #else
605b7d5e03cSMatthew Dillon return 0;
606b7d5e03cSMatthew Dillon #endif
607b7d5e03cSMatthew Dillon }
608b7d5e03cSMatthew Dillon
609b7d5e03cSMatthew Dillon /*
610b7d5e03cSMatthew Dillon * Returns the interpolated y value corresponding to the specified x value
611b7d5e03cSMatthew Dillon * from the np ordered pairs of data (px,py).
612b7d5e03cSMatthew Dillon * The pairs do not have to be in any order.
613b7d5e03cSMatthew Dillon * If the specified x value is less than any of the px,
614b7d5e03cSMatthew Dillon * the returned y value is equal to the py for the lowest px.
615b7d5e03cSMatthew Dillon * If the specified x value is greater than any of the px,
616b7d5e03cSMatthew Dillon * the returned y value is equal to the py for the highest px.
617b7d5e03cSMatthew Dillon */
618b7d5e03cSMatthew Dillon static int
interpolate(int32_t x,int32_t * px,int32_t * py,u_int16_t np)619b7d5e03cSMatthew Dillon interpolate(int32_t x, int32_t *px, int32_t *py, u_int16_t np)
620b7d5e03cSMatthew Dillon {
621b7d5e03cSMatthew Dillon int ip = 0;
622b7d5e03cSMatthew Dillon int lx = 0, ly = 0, lhave = 0;
623b7d5e03cSMatthew Dillon int hx = 0, hy = 0, hhave = 0;
624b7d5e03cSMatthew Dillon int dx = 0;
625b7d5e03cSMatthew Dillon int y = 0;
626b7d5e03cSMatthew Dillon int bf, factor, plus;
627b7d5e03cSMatthew Dillon
628b7d5e03cSMatthew Dillon lhave = 0;
629b7d5e03cSMatthew Dillon hhave = 0;
630b7d5e03cSMatthew Dillon /*
631b7d5e03cSMatthew Dillon * identify best lower and higher x calibration measurement
632b7d5e03cSMatthew Dillon */
633b7d5e03cSMatthew Dillon for (ip = 0; ip < np; ip++) {
634b7d5e03cSMatthew Dillon dx = x - px[ip];
635b7d5e03cSMatthew Dillon /* this measurement is higher than our desired x */
636b7d5e03cSMatthew Dillon if (dx <= 0) {
637b7d5e03cSMatthew Dillon if (!hhave || dx > (x - hx)) {
638b7d5e03cSMatthew Dillon /* new best higher x measurement */
639b7d5e03cSMatthew Dillon hx = px[ip];
640b7d5e03cSMatthew Dillon hy = py[ip];
641b7d5e03cSMatthew Dillon hhave = 1;
642b7d5e03cSMatthew Dillon }
643b7d5e03cSMatthew Dillon }
644b7d5e03cSMatthew Dillon /* this measurement is lower than our desired x */
645b7d5e03cSMatthew Dillon if (dx >= 0) {
646b7d5e03cSMatthew Dillon if (!lhave || dx < (x - lx)) {
647b7d5e03cSMatthew Dillon /* new best lower x measurement */
648b7d5e03cSMatthew Dillon lx = px[ip];
649b7d5e03cSMatthew Dillon ly = py[ip];
650b7d5e03cSMatthew Dillon lhave = 1;
651b7d5e03cSMatthew Dillon }
652b7d5e03cSMatthew Dillon }
653b7d5e03cSMatthew Dillon }
654b7d5e03cSMatthew Dillon /* the low x is good */
655b7d5e03cSMatthew Dillon if (lhave) {
656b7d5e03cSMatthew Dillon /* so is the high x */
657b7d5e03cSMatthew Dillon if (hhave) {
658b7d5e03cSMatthew Dillon /* they're the same, so just pick one */
659b7d5e03cSMatthew Dillon if (hx == lx) {
660b7d5e03cSMatthew Dillon y = ly;
661b7d5e03cSMatthew Dillon } else {
662b7d5e03cSMatthew Dillon /* interpolate with round off */
663b7d5e03cSMatthew Dillon bf = (2 * (hy - ly) * (x - lx)) / (hx - lx);
664b7d5e03cSMatthew Dillon plus = (bf % 2);
665b7d5e03cSMatthew Dillon factor = bf / 2;
666b7d5e03cSMatthew Dillon y = ly + factor + plus;
667b7d5e03cSMatthew Dillon }
668b7d5e03cSMatthew Dillon } else {
669b7d5e03cSMatthew Dillon /* only low is good, use it */
670b7d5e03cSMatthew Dillon y = ly;
671b7d5e03cSMatthew Dillon }
672b7d5e03cSMatthew Dillon } else if (hhave) {
673b7d5e03cSMatthew Dillon /* only high is good, use it */
674b7d5e03cSMatthew Dillon y = hy;
675b7d5e03cSMatthew Dillon } else {
676b7d5e03cSMatthew Dillon /* nothing is good,this should never happen unless np=0, ???? */
677b7d5e03cSMatthew Dillon y = -(1 << 30);
678b7d5e03cSMatthew Dillon }
679b7d5e03cSMatthew Dillon
680b7d5e03cSMatthew Dillon return y;
681b7d5e03cSMatthew Dillon }
682b7d5e03cSMatthew Dillon
683b7d5e03cSMatthew Dillon 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)684b7d5e03cSMatthew Dillon ar9300_eeprom_get_legacy_trgt_pwr(struct ath_hal *ah, u_int16_t rate_index,
685b7d5e03cSMatthew Dillon u_int16_t freq, HAL_BOOL is_2ghz)
686b7d5e03cSMatthew Dillon {
687b7d5e03cSMatthew Dillon u_int16_t num_piers, i;
688b7d5e03cSMatthew Dillon int32_t target_power_array[OSPREY_NUM_5G_20_TARGET_POWERS];
689b7d5e03cSMatthew Dillon int32_t freq_array[OSPREY_NUM_5G_20_TARGET_POWERS];
690b7d5e03cSMatthew Dillon u_int8_t *p_freq_bin;
691b7d5e03cSMatthew Dillon ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom;
692b7d5e03cSMatthew Dillon CAL_TARGET_POWER_LEG *p_eeprom_target_pwr;
693b7d5e03cSMatthew Dillon
694b7d5e03cSMatthew Dillon if (is_2ghz) {
695b7d5e03cSMatthew Dillon num_piers = OSPREY_NUM_2G_20_TARGET_POWERS;
696b7d5e03cSMatthew Dillon p_eeprom_target_pwr = eep->cal_target_power_2g;
697b7d5e03cSMatthew Dillon p_freq_bin = eep->cal_target_freqbin_2g;
698b7d5e03cSMatthew Dillon } else {
699b7d5e03cSMatthew Dillon num_piers = OSPREY_NUM_5G_20_TARGET_POWERS;
700b7d5e03cSMatthew Dillon p_eeprom_target_pwr = eep->cal_target_power_5g;
701b7d5e03cSMatthew Dillon p_freq_bin = eep->cal_target_freqbin_5g;
702b7d5e03cSMatthew Dillon }
703b7d5e03cSMatthew Dillon
704b7d5e03cSMatthew Dillon /*
705b7d5e03cSMatthew Dillon * create array of channels and targetpower from
706b7d5e03cSMatthew Dillon * targetpower piers stored on eeprom
707b7d5e03cSMatthew Dillon */
708b7d5e03cSMatthew Dillon for (i = 0; i < num_piers; i++) {
709b7d5e03cSMatthew Dillon freq_array[i] = FBIN2FREQ(p_freq_bin[i], is_2ghz);
710b7d5e03cSMatthew Dillon target_power_array[i] = p_eeprom_target_pwr[i].t_pow2x[rate_index];
711b7d5e03cSMatthew Dillon }
712b7d5e03cSMatthew Dillon
713b7d5e03cSMatthew Dillon /* interpolate to get target power for given frequency */
714b7d5e03cSMatthew Dillon return
715b7d5e03cSMatthew Dillon ((u_int8_t)interpolate(
716b7d5e03cSMatthew Dillon (int32_t)freq, freq_array, target_power_array, num_piers));
717b7d5e03cSMatthew Dillon }
718b7d5e03cSMatthew Dillon
719b7d5e03cSMatthew Dillon 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)720b7d5e03cSMatthew Dillon ar9300_eeprom_get_ht20_trgt_pwr(struct ath_hal *ah, u_int16_t rate_index,
721b7d5e03cSMatthew Dillon u_int16_t freq, HAL_BOOL is_2ghz)
722b7d5e03cSMatthew Dillon {
723b7d5e03cSMatthew Dillon u_int16_t num_piers, i;
724b7d5e03cSMatthew Dillon int32_t target_power_array[OSPREY_NUM_5G_20_TARGET_POWERS];
725b7d5e03cSMatthew Dillon int32_t freq_array[OSPREY_NUM_5G_20_TARGET_POWERS];
726b7d5e03cSMatthew Dillon u_int8_t *p_freq_bin;
727b7d5e03cSMatthew Dillon ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom;
728b7d5e03cSMatthew Dillon OSP_CAL_TARGET_POWER_HT *p_eeprom_target_pwr;
729b7d5e03cSMatthew Dillon
730b7d5e03cSMatthew Dillon if (is_2ghz) {
731b7d5e03cSMatthew Dillon num_piers = OSPREY_NUM_2G_20_TARGET_POWERS;
732b7d5e03cSMatthew Dillon p_eeprom_target_pwr = eep->cal_target_power_2g_ht20;
733b7d5e03cSMatthew Dillon p_freq_bin = eep->cal_target_freqbin_2g_ht20;
734b7d5e03cSMatthew Dillon } else {
735b7d5e03cSMatthew Dillon num_piers = OSPREY_NUM_5G_20_TARGET_POWERS;
736b7d5e03cSMatthew Dillon p_eeprom_target_pwr = eep->cal_target_power_5g_ht20;
737b7d5e03cSMatthew Dillon p_freq_bin = eep->cal_target_freqbin_5g_ht20;
738b7d5e03cSMatthew Dillon }
739b7d5e03cSMatthew Dillon
740b7d5e03cSMatthew Dillon /*
741b7d5e03cSMatthew Dillon * create array of channels and targetpower from
742b7d5e03cSMatthew Dillon * targetpower piers stored on eeprom
743b7d5e03cSMatthew Dillon */
744b7d5e03cSMatthew Dillon for (i = 0; i < num_piers; i++) {
745b7d5e03cSMatthew Dillon freq_array[i] = FBIN2FREQ(p_freq_bin[i], is_2ghz);
746b7d5e03cSMatthew Dillon target_power_array[i] = p_eeprom_target_pwr[i].t_pow2x[rate_index];
747b7d5e03cSMatthew Dillon }
748b7d5e03cSMatthew Dillon
749b7d5e03cSMatthew Dillon /* interpolate to get target power for given frequency */
750b7d5e03cSMatthew Dillon return
751b7d5e03cSMatthew Dillon ((u_int8_t)interpolate(
752b7d5e03cSMatthew Dillon (int32_t)freq, freq_array, target_power_array, num_piers));
753b7d5e03cSMatthew Dillon }
754b7d5e03cSMatthew Dillon
755b7d5e03cSMatthew Dillon 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)756b7d5e03cSMatthew Dillon ar9300_eeprom_get_ht40_trgt_pwr(struct ath_hal *ah, u_int16_t rate_index,
757b7d5e03cSMatthew Dillon u_int16_t freq, HAL_BOOL is_2ghz)
758b7d5e03cSMatthew Dillon {
759b7d5e03cSMatthew Dillon u_int16_t num_piers, i;
760b7d5e03cSMatthew Dillon int32_t target_power_array[OSPREY_NUM_5G_40_TARGET_POWERS];
761b7d5e03cSMatthew Dillon int32_t freq_array[OSPREY_NUM_5G_40_TARGET_POWERS];
762b7d5e03cSMatthew Dillon u_int8_t *p_freq_bin;
763b7d5e03cSMatthew Dillon ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom;
764b7d5e03cSMatthew Dillon OSP_CAL_TARGET_POWER_HT *p_eeprom_target_pwr;
765b7d5e03cSMatthew Dillon
766b7d5e03cSMatthew Dillon if (is_2ghz) {
767b7d5e03cSMatthew Dillon num_piers = OSPREY_NUM_2G_40_TARGET_POWERS;
768b7d5e03cSMatthew Dillon p_eeprom_target_pwr = eep->cal_target_power_2g_ht40;
769b7d5e03cSMatthew Dillon p_freq_bin = eep->cal_target_freqbin_2g_ht40;
770b7d5e03cSMatthew Dillon } else {
771b7d5e03cSMatthew Dillon num_piers = OSPREY_NUM_5G_40_TARGET_POWERS;
772b7d5e03cSMatthew Dillon p_eeprom_target_pwr = eep->cal_target_power_5g_ht40;
773b7d5e03cSMatthew Dillon p_freq_bin = eep->cal_target_freqbin_5g_ht40;
774b7d5e03cSMatthew Dillon }
775b7d5e03cSMatthew Dillon
776b7d5e03cSMatthew Dillon /*
777b7d5e03cSMatthew Dillon * create array of channels and targetpower from
778b7d5e03cSMatthew Dillon * targetpower piers stored on eeprom
779b7d5e03cSMatthew Dillon */
780b7d5e03cSMatthew Dillon for (i = 0; i < num_piers; i++) {
781b7d5e03cSMatthew Dillon freq_array[i] = FBIN2FREQ(p_freq_bin[i], is_2ghz);
782b7d5e03cSMatthew Dillon target_power_array[i] = p_eeprom_target_pwr[i].t_pow2x[rate_index];
783b7d5e03cSMatthew Dillon }
784b7d5e03cSMatthew Dillon
785b7d5e03cSMatthew Dillon /* interpolate to get target power for given frequency */
786b7d5e03cSMatthew Dillon return
787b7d5e03cSMatthew Dillon ((u_int8_t)interpolate(
788b7d5e03cSMatthew Dillon (int32_t)freq, freq_array, target_power_array, num_piers));
789b7d5e03cSMatthew Dillon }
790b7d5e03cSMatthew Dillon
791b7d5e03cSMatthew Dillon u_int8_t
ar9300_eeprom_get_cck_trgt_pwr(struct ath_hal * ah,u_int16_t rate_index,u_int16_t freq)792b7d5e03cSMatthew Dillon ar9300_eeprom_get_cck_trgt_pwr(struct ath_hal *ah, u_int16_t rate_index,
793b7d5e03cSMatthew Dillon u_int16_t freq)
794b7d5e03cSMatthew Dillon {
795b7d5e03cSMatthew Dillon u_int16_t num_piers = OSPREY_NUM_2G_CCK_TARGET_POWERS, i;
796b7d5e03cSMatthew Dillon int32_t target_power_array[OSPREY_NUM_2G_CCK_TARGET_POWERS];
797b7d5e03cSMatthew Dillon int32_t freq_array[OSPREY_NUM_2G_CCK_TARGET_POWERS];
798b7d5e03cSMatthew Dillon ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom;
799b7d5e03cSMatthew Dillon u_int8_t *p_freq_bin = eep->cal_target_freqbin_cck;
800b7d5e03cSMatthew Dillon CAL_TARGET_POWER_LEG *p_eeprom_target_pwr = eep->cal_target_power_cck;
801b7d5e03cSMatthew Dillon
802b7d5e03cSMatthew Dillon /*
803b7d5e03cSMatthew Dillon * create array of channels and targetpower from
804b7d5e03cSMatthew Dillon * targetpower piers stored on eeprom
805b7d5e03cSMatthew Dillon */
806b7d5e03cSMatthew Dillon for (i = 0; i < num_piers; i++) {
807b7d5e03cSMatthew Dillon freq_array[i] = FBIN2FREQ(p_freq_bin[i], 1);
808b7d5e03cSMatthew Dillon target_power_array[i] = p_eeprom_target_pwr[i].t_pow2x[rate_index];
809b7d5e03cSMatthew Dillon }
810b7d5e03cSMatthew Dillon
811b7d5e03cSMatthew Dillon /* interpolate to get target power for given frequency */
812b7d5e03cSMatthew Dillon return
813b7d5e03cSMatthew Dillon ((u_int8_t)interpolate(
814b7d5e03cSMatthew Dillon (int32_t)freq, freq_array, target_power_array, num_piers));
815b7d5e03cSMatthew Dillon }
816b7d5e03cSMatthew Dillon
817b7d5e03cSMatthew Dillon /*
818b7d5e03cSMatthew Dillon * Set tx power registers to array of values passed in
819b7d5e03cSMatthew Dillon */
820b7d5e03cSMatthew Dillon int
ar9300_transmit_power_reg_write(struct ath_hal * ah,u_int8_t * p_pwr_array)821b7d5e03cSMatthew Dillon ar9300_transmit_power_reg_write(struct ath_hal *ah, u_int8_t *p_pwr_array)
822b7d5e03cSMatthew Dillon {
823b7d5e03cSMatthew Dillon #define POW_SM(_r, _s) (((_r) & 0x3f) << (_s))
824b7d5e03cSMatthew Dillon /* make sure forced gain is not set */
825b7d5e03cSMatthew Dillon #if 0
826b7d5e03cSMatthew Dillon field_write("force_dac_gain", 0);
827b7d5e03cSMatthew Dillon OS_REG_WRITE(ah, 0xa3f8, 0);
828b7d5e03cSMatthew Dillon field_write("force_tx_gain", 0);
829b7d5e03cSMatthew Dillon #endif
830b7d5e03cSMatthew Dillon
831b7d5e03cSMatthew Dillon OS_REG_WRITE(ah, 0xa458, 0);
832b7d5e03cSMatthew Dillon
833b7d5e03cSMatthew Dillon /* Write the OFDM power per rate set */
834b7d5e03cSMatthew Dillon /* 6 (LSB), 9, 12, 18 (MSB) */
835b7d5e03cSMatthew Dillon OS_REG_WRITE(ah, 0xa3c0,
836b7d5e03cSMatthew Dillon POW_SM(p_pwr_array[ALL_TARGET_LEGACY_6_24], 24)
837b7d5e03cSMatthew Dillon | POW_SM(p_pwr_array[ALL_TARGET_LEGACY_6_24], 16)
838b7d5e03cSMatthew Dillon | POW_SM(p_pwr_array[ALL_TARGET_LEGACY_6_24], 8)
839b7d5e03cSMatthew Dillon | POW_SM(p_pwr_array[ALL_TARGET_LEGACY_6_24], 0)
840b7d5e03cSMatthew Dillon );
841b7d5e03cSMatthew Dillon /* 24 (LSB), 36, 48, 54 (MSB) */
842b7d5e03cSMatthew Dillon OS_REG_WRITE(ah, 0xa3c4,
843b7d5e03cSMatthew Dillon POW_SM(p_pwr_array[ALL_TARGET_LEGACY_54], 24)
844b7d5e03cSMatthew Dillon | POW_SM(p_pwr_array[ALL_TARGET_LEGACY_48], 16)
845b7d5e03cSMatthew Dillon | POW_SM(p_pwr_array[ALL_TARGET_LEGACY_36], 8)
846b7d5e03cSMatthew Dillon | POW_SM(p_pwr_array[ALL_TARGET_LEGACY_6_24], 0)
847b7d5e03cSMatthew Dillon );
848b7d5e03cSMatthew Dillon
849b7d5e03cSMatthew Dillon /* Write the CCK power per rate set */
850b7d5e03cSMatthew Dillon /* 1L (LSB), reserved, 2L, 2S (MSB) */
851b7d5e03cSMatthew Dillon OS_REG_WRITE(ah, 0xa3c8,
852b7d5e03cSMatthew Dillon POW_SM(p_pwr_array[ALL_TARGET_LEGACY_1L_5L], 24)
853b7d5e03cSMatthew Dillon | POW_SM(p_pwr_array[ALL_TARGET_LEGACY_1L_5L], 16)
854b7d5e03cSMatthew Dillon /* | POW_SM(tx_power_times2, 8)*/ /* this is reserved for Osprey */
855b7d5e03cSMatthew Dillon | POW_SM(p_pwr_array[ALL_TARGET_LEGACY_1L_5L], 0)
856b7d5e03cSMatthew Dillon );
857b7d5e03cSMatthew Dillon /* 5.5L (LSB), 5.5S, 11L, 11S (MSB) */
858b7d5e03cSMatthew Dillon OS_REG_WRITE(ah, 0xa3cc,
859b7d5e03cSMatthew Dillon POW_SM(p_pwr_array[ALL_TARGET_LEGACY_11S], 24)
860b7d5e03cSMatthew Dillon | POW_SM(p_pwr_array[ALL_TARGET_LEGACY_11L], 16)
861b7d5e03cSMatthew Dillon | POW_SM(p_pwr_array[ALL_TARGET_LEGACY_5S], 8)
862b7d5e03cSMatthew Dillon | POW_SM(p_pwr_array[ALL_TARGET_LEGACY_1L_5L], 0)
863b7d5e03cSMatthew Dillon );
864b7d5e03cSMatthew Dillon
865b7d5e03cSMatthew Dillon /* write the power for duplicated frames - HT40 */
866b7d5e03cSMatthew Dillon /* dup40_cck (LSB), dup40_ofdm, ext20_cck, ext20_ofdm (MSB) */
867b7d5e03cSMatthew Dillon OS_REG_WRITE(ah, 0xa3e0,
868b7d5e03cSMatthew Dillon POW_SM(p_pwr_array[ALL_TARGET_LEGACY_6_24], 24)
869b7d5e03cSMatthew Dillon | POW_SM(p_pwr_array[ALL_TARGET_LEGACY_1L_5L], 16)
870b7d5e03cSMatthew Dillon | POW_SM(p_pwr_array[ALL_TARGET_LEGACY_6_24], 8)
871b7d5e03cSMatthew Dillon | POW_SM(p_pwr_array[ALL_TARGET_LEGACY_1L_5L], 0)
872b7d5e03cSMatthew Dillon );
873b7d5e03cSMatthew Dillon
874b7d5e03cSMatthew Dillon /* Write the HT20 power per rate set */
875b7d5e03cSMatthew Dillon /* 0/8/16 (LSB), 1-3/9-11/17-19, 4, 5 (MSB) */
876b7d5e03cSMatthew Dillon OS_REG_WRITE(ah, 0xa3d0,
877b7d5e03cSMatthew Dillon POW_SM(p_pwr_array[ALL_TARGET_HT20_5], 24)
878b7d5e03cSMatthew Dillon | POW_SM(p_pwr_array[ALL_TARGET_HT20_4], 16)
879b7d5e03cSMatthew Dillon | POW_SM(p_pwr_array[ALL_TARGET_HT20_1_3_9_11_17_19], 8)
880b7d5e03cSMatthew Dillon | POW_SM(p_pwr_array[ALL_TARGET_HT20_0_8_16], 0)
881b7d5e03cSMatthew Dillon );
882b7d5e03cSMatthew Dillon
883b7d5e03cSMatthew Dillon /* 6 (LSB), 7, 12, 13 (MSB) */
884b7d5e03cSMatthew Dillon OS_REG_WRITE(ah, 0xa3d4,
885b7d5e03cSMatthew Dillon POW_SM(p_pwr_array[ALL_TARGET_HT20_13], 24)
886b7d5e03cSMatthew Dillon | POW_SM(p_pwr_array[ALL_TARGET_HT20_12], 16)
887b7d5e03cSMatthew Dillon | POW_SM(p_pwr_array[ALL_TARGET_HT20_7], 8)
888b7d5e03cSMatthew Dillon | POW_SM(p_pwr_array[ALL_TARGET_HT20_6], 0)
889b7d5e03cSMatthew Dillon );
890b7d5e03cSMatthew Dillon
891b7d5e03cSMatthew Dillon /* 14 (LSB), 15, 20, 21 */
892b7d5e03cSMatthew Dillon OS_REG_WRITE(ah, 0xa3e4,
893b7d5e03cSMatthew Dillon POW_SM(p_pwr_array[ALL_TARGET_HT20_21], 24)
894b7d5e03cSMatthew Dillon | POW_SM(p_pwr_array[ALL_TARGET_HT20_20], 16)
895b7d5e03cSMatthew Dillon | POW_SM(p_pwr_array[ALL_TARGET_HT20_15], 8)
896b7d5e03cSMatthew Dillon | POW_SM(p_pwr_array[ALL_TARGET_HT20_14], 0)
897b7d5e03cSMatthew Dillon );
898b7d5e03cSMatthew Dillon
899b7d5e03cSMatthew Dillon /* Mixed HT20 and HT40 rates */
900b7d5e03cSMatthew Dillon /* HT20 22 (LSB), HT20 23, HT40 22, HT40 23 (MSB) */
901b7d5e03cSMatthew Dillon OS_REG_WRITE(ah, 0xa3e8,
902b7d5e03cSMatthew Dillon POW_SM(p_pwr_array[ALL_TARGET_HT40_23], 24)
903b7d5e03cSMatthew Dillon | POW_SM(p_pwr_array[ALL_TARGET_HT40_22], 16)
904b7d5e03cSMatthew Dillon | POW_SM(p_pwr_array[ALL_TARGET_HT20_23], 8)
905b7d5e03cSMatthew Dillon | POW_SM(p_pwr_array[ALL_TARGET_HT20_22], 0)
906b7d5e03cSMatthew Dillon );
907b7d5e03cSMatthew Dillon
908b7d5e03cSMatthew Dillon /* Write the HT40 power per rate set */
909b7d5e03cSMatthew Dillon /* correct PAR difference between HT40 and HT20/LEGACY */
910b7d5e03cSMatthew Dillon /* 0/8/16 (LSB), 1-3/9-11/17-19, 4, 5 (MSB) */
911b7d5e03cSMatthew Dillon OS_REG_WRITE(ah, 0xa3d8,
912b7d5e03cSMatthew Dillon POW_SM(p_pwr_array[ALL_TARGET_HT40_5], 24)
913b7d5e03cSMatthew Dillon | POW_SM(p_pwr_array[ALL_TARGET_HT40_4], 16)
914b7d5e03cSMatthew Dillon | POW_SM(p_pwr_array[ALL_TARGET_HT40_1_3_9_11_17_19], 8)
915b7d5e03cSMatthew Dillon | POW_SM(p_pwr_array[ALL_TARGET_HT40_0_8_16], 0)
916b7d5e03cSMatthew Dillon );
917b7d5e03cSMatthew Dillon
918b7d5e03cSMatthew Dillon /* 6 (LSB), 7, 12, 13 (MSB) */
919b7d5e03cSMatthew Dillon OS_REG_WRITE(ah, 0xa3dc,
920b7d5e03cSMatthew Dillon POW_SM(p_pwr_array[ALL_TARGET_HT40_13], 24)
921b7d5e03cSMatthew Dillon | POW_SM(p_pwr_array[ALL_TARGET_HT40_12], 16)
922b7d5e03cSMatthew Dillon | POW_SM(p_pwr_array[ALL_TARGET_HT40_7], 8)
923b7d5e03cSMatthew Dillon | POW_SM(p_pwr_array[ALL_TARGET_HT40_6], 0)
924b7d5e03cSMatthew Dillon );
925b7d5e03cSMatthew Dillon
926b7d5e03cSMatthew Dillon /* 14 (LSB), 15, 20, 21 */
927b7d5e03cSMatthew Dillon OS_REG_WRITE(ah, 0xa3ec,
928b7d5e03cSMatthew Dillon POW_SM(p_pwr_array[ALL_TARGET_HT40_21], 24)
929b7d5e03cSMatthew Dillon | POW_SM(p_pwr_array[ALL_TARGET_HT40_20], 16)
930b7d5e03cSMatthew Dillon | POW_SM(p_pwr_array[ALL_TARGET_HT40_15], 8)
931b7d5e03cSMatthew Dillon | POW_SM(p_pwr_array[ALL_TARGET_HT40_14], 0)
932b7d5e03cSMatthew Dillon );
933b7d5e03cSMatthew Dillon
934b7d5e03cSMatthew Dillon return 0;
935b7d5e03cSMatthew Dillon #undef POW_SM
936b7d5e03cSMatthew Dillon }
937b7d5e03cSMatthew Dillon
938b7d5e03cSMatthew Dillon static void
ar9300_selfgen_tpc_reg_write(struct ath_hal * ah,const struct ieee80211_channel * chan,u_int8_t * p_pwr_array)939b7d5e03cSMatthew Dillon ar9300_selfgen_tpc_reg_write(struct ath_hal *ah, const struct ieee80211_channel *chan,
940b7d5e03cSMatthew Dillon u_int8_t *p_pwr_array)
941b7d5e03cSMatthew Dillon {
942b7d5e03cSMatthew Dillon u_int32_t tpc_reg_val;
943b7d5e03cSMatthew Dillon
944b7d5e03cSMatthew Dillon /* Set the target power values for self generated frames (ACK,RTS/CTS) to
945b7d5e03cSMatthew Dillon * be within limits. This is just a safety measure.With per packet TPC mode
946b7d5e03cSMatthew Dillon * enabled the target power value used with self generated frames will be
947b7d5e03cSMatthew Dillon * MIN( TPC reg, BB_powertx_rate register)
948b7d5e03cSMatthew Dillon */
949b7d5e03cSMatthew Dillon
950b7d5e03cSMatthew Dillon if (IEEE80211_IS_CHAN_2GHZ(chan)) {
951b7d5e03cSMatthew Dillon tpc_reg_val = (SM(p_pwr_array[ALL_TARGET_LEGACY_1L_5L], AR_TPC_ACK) |
952b7d5e03cSMatthew Dillon SM(p_pwr_array[ALL_TARGET_LEGACY_1L_5L], AR_TPC_CTS) |
953b7d5e03cSMatthew Dillon SM(0x3f, AR_TPC_CHIRP) |
954b7d5e03cSMatthew Dillon SM(0x3f, AR_TPC_RPT));
955b7d5e03cSMatthew Dillon } else {
956b7d5e03cSMatthew Dillon tpc_reg_val = (SM(p_pwr_array[ALL_TARGET_LEGACY_6_24], AR_TPC_ACK) |
957b7d5e03cSMatthew Dillon SM(p_pwr_array[ALL_TARGET_LEGACY_6_24], AR_TPC_CTS) |
958b7d5e03cSMatthew Dillon SM(0x3f, AR_TPC_CHIRP) |
959b7d5e03cSMatthew Dillon SM(0x3f, AR_TPC_RPT));
960b7d5e03cSMatthew Dillon }
961b7d5e03cSMatthew Dillon OS_REG_WRITE(ah, AR_TPC, tpc_reg_val);
962b7d5e03cSMatthew Dillon }
963b7d5e03cSMatthew Dillon
964b7d5e03cSMatthew Dillon void
ar9300_set_target_power_from_eeprom(struct ath_hal * ah,u_int16_t freq,u_int8_t * target_power_val_t2)965b7d5e03cSMatthew Dillon ar9300_set_target_power_from_eeprom(struct ath_hal *ah, u_int16_t freq,
966b7d5e03cSMatthew Dillon u_int8_t *target_power_val_t2)
967b7d5e03cSMatthew Dillon {
968b7d5e03cSMatthew Dillon /* hard code for now, need to get from eeprom struct */
969b7d5e03cSMatthew Dillon u_int8_t ht40_power_inc_for_pdadc = 0;
970b7d5e03cSMatthew Dillon HAL_BOOL is_2ghz = 0;
971b7d5e03cSMatthew Dillon
972b7d5e03cSMatthew Dillon if (freq < 4000) {
973b7d5e03cSMatthew Dillon is_2ghz = 1;
974b7d5e03cSMatthew Dillon }
975b7d5e03cSMatthew Dillon
976b7d5e03cSMatthew Dillon target_power_val_t2[ALL_TARGET_LEGACY_6_24] =
977b7d5e03cSMatthew Dillon ar9300_eeprom_get_legacy_trgt_pwr(
978b7d5e03cSMatthew Dillon ah, LEGACY_TARGET_RATE_6_24, freq, is_2ghz);
979b7d5e03cSMatthew Dillon target_power_val_t2[ALL_TARGET_LEGACY_36] =
980b7d5e03cSMatthew Dillon ar9300_eeprom_get_legacy_trgt_pwr(
981b7d5e03cSMatthew Dillon ah, LEGACY_TARGET_RATE_36, freq, is_2ghz);
982b7d5e03cSMatthew Dillon target_power_val_t2[ALL_TARGET_LEGACY_48] =
983b7d5e03cSMatthew Dillon ar9300_eeprom_get_legacy_trgt_pwr(
984b7d5e03cSMatthew Dillon ah, LEGACY_TARGET_RATE_48, freq, is_2ghz);
985b7d5e03cSMatthew Dillon target_power_val_t2[ALL_TARGET_LEGACY_54] =
986b7d5e03cSMatthew Dillon ar9300_eeprom_get_legacy_trgt_pwr(
987b7d5e03cSMatthew Dillon ah, LEGACY_TARGET_RATE_54, freq, is_2ghz);
988b7d5e03cSMatthew Dillon target_power_val_t2[ALL_TARGET_LEGACY_1L_5L] =
989b7d5e03cSMatthew Dillon ar9300_eeprom_get_cck_trgt_pwr(
990b7d5e03cSMatthew Dillon ah, LEGACY_TARGET_RATE_1L_5L, freq);
991b7d5e03cSMatthew Dillon target_power_val_t2[ALL_TARGET_LEGACY_5S] =
992b7d5e03cSMatthew Dillon ar9300_eeprom_get_cck_trgt_pwr(
993b7d5e03cSMatthew Dillon ah, LEGACY_TARGET_RATE_5S, freq);
994b7d5e03cSMatthew Dillon target_power_val_t2[ALL_TARGET_LEGACY_11L] =
995b7d5e03cSMatthew Dillon ar9300_eeprom_get_cck_trgt_pwr(
996b7d5e03cSMatthew Dillon ah, LEGACY_TARGET_RATE_11L, freq);
997b7d5e03cSMatthew Dillon target_power_val_t2[ALL_TARGET_LEGACY_11S] =
998b7d5e03cSMatthew Dillon ar9300_eeprom_get_cck_trgt_pwr(
999b7d5e03cSMatthew Dillon ah, LEGACY_TARGET_RATE_11S, freq);
1000b7d5e03cSMatthew Dillon target_power_val_t2[ALL_TARGET_HT20_0_8_16] =
1001b7d5e03cSMatthew Dillon ar9300_eeprom_get_ht20_trgt_pwr(
1002b7d5e03cSMatthew Dillon ah, HT_TARGET_RATE_0_8_16, freq, is_2ghz);
1003b7d5e03cSMatthew Dillon target_power_val_t2[ALL_TARGET_HT20_1_3_9_11_17_19] =
1004b7d5e03cSMatthew Dillon ar9300_eeprom_get_ht20_trgt_pwr(
1005b7d5e03cSMatthew Dillon ah, HT_TARGET_RATE_1_3_9_11_17_19, freq, is_2ghz);
1006b7d5e03cSMatthew Dillon target_power_val_t2[ALL_TARGET_HT20_4] =
1007b7d5e03cSMatthew Dillon ar9300_eeprom_get_ht20_trgt_pwr(
1008b7d5e03cSMatthew Dillon ah, HT_TARGET_RATE_4, freq, is_2ghz);
1009b7d5e03cSMatthew Dillon target_power_val_t2[ALL_TARGET_HT20_5] =
1010b7d5e03cSMatthew Dillon ar9300_eeprom_get_ht20_trgt_pwr(
1011b7d5e03cSMatthew Dillon ah, HT_TARGET_RATE_5, freq, is_2ghz);
1012b7d5e03cSMatthew Dillon target_power_val_t2[ALL_TARGET_HT20_6] =
1013b7d5e03cSMatthew Dillon ar9300_eeprom_get_ht20_trgt_pwr(
1014b7d5e03cSMatthew Dillon ah, HT_TARGET_RATE_6, freq, is_2ghz);
1015b7d5e03cSMatthew Dillon target_power_val_t2[ALL_TARGET_HT20_7] =
1016b7d5e03cSMatthew Dillon ar9300_eeprom_get_ht20_trgt_pwr(
1017b7d5e03cSMatthew Dillon ah, HT_TARGET_RATE_7, freq, is_2ghz);
1018b7d5e03cSMatthew Dillon target_power_val_t2[ALL_TARGET_HT20_12] =
1019b7d5e03cSMatthew Dillon ar9300_eeprom_get_ht20_trgt_pwr(
1020b7d5e03cSMatthew Dillon ah, HT_TARGET_RATE_12, freq, is_2ghz);
1021b7d5e03cSMatthew Dillon target_power_val_t2[ALL_TARGET_HT20_13] =
1022b7d5e03cSMatthew Dillon ar9300_eeprom_get_ht20_trgt_pwr(
1023b7d5e03cSMatthew Dillon ah, HT_TARGET_RATE_13, freq, is_2ghz);
1024b7d5e03cSMatthew Dillon target_power_val_t2[ALL_TARGET_HT20_14] =
1025b7d5e03cSMatthew Dillon ar9300_eeprom_get_ht20_trgt_pwr(
1026b7d5e03cSMatthew Dillon ah, HT_TARGET_RATE_14, freq, is_2ghz);
1027b7d5e03cSMatthew Dillon target_power_val_t2[ALL_TARGET_HT20_15] =
1028b7d5e03cSMatthew Dillon ar9300_eeprom_get_ht20_trgt_pwr(
1029b7d5e03cSMatthew Dillon ah, HT_TARGET_RATE_15, freq, is_2ghz);
1030b7d5e03cSMatthew Dillon target_power_val_t2[ALL_TARGET_HT20_20] =
1031b7d5e03cSMatthew Dillon ar9300_eeprom_get_ht20_trgt_pwr(
1032b7d5e03cSMatthew Dillon ah, HT_TARGET_RATE_20, freq, is_2ghz);
1033b7d5e03cSMatthew Dillon target_power_val_t2[ALL_TARGET_HT20_21] =
1034b7d5e03cSMatthew Dillon ar9300_eeprom_get_ht20_trgt_pwr(
1035b7d5e03cSMatthew Dillon ah, HT_TARGET_RATE_21, freq, is_2ghz);
1036b7d5e03cSMatthew Dillon target_power_val_t2[ALL_TARGET_HT20_22] =
1037b7d5e03cSMatthew Dillon ar9300_eeprom_get_ht20_trgt_pwr(
1038b7d5e03cSMatthew Dillon ah, HT_TARGET_RATE_22, freq, is_2ghz);
1039b7d5e03cSMatthew Dillon target_power_val_t2[ALL_TARGET_HT20_23] =
1040b7d5e03cSMatthew Dillon ar9300_eeprom_get_ht20_trgt_pwr(
1041b7d5e03cSMatthew Dillon ah, HT_TARGET_RATE_23, freq, is_2ghz);
1042b7d5e03cSMatthew Dillon target_power_val_t2[ALL_TARGET_HT40_0_8_16] =
1043b7d5e03cSMatthew Dillon ar9300_eeprom_get_ht40_trgt_pwr(
1044b7d5e03cSMatthew Dillon ah, HT_TARGET_RATE_0_8_16, freq, is_2ghz) +
1045b7d5e03cSMatthew Dillon ht40_power_inc_for_pdadc;
1046b7d5e03cSMatthew Dillon target_power_val_t2[ALL_TARGET_HT40_1_3_9_11_17_19] =
1047b7d5e03cSMatthew Dillon ar9300_eeprom_get_ht40_trgt_pwr(
1048b7d5e03cSMatthew Dillon ah, HT_TARGET_RATE_1_3_9_11_17_19, freq, is_2ghz) +
1049b7d5e03cSMatthew Dillon ht40_power_inc_for_pdadc;
1050b7d5e03cSMatthew Dillon target_power_val_t2[ALL_TARGET_HT40_4] =
1051b7d5e03cSMatthew Dillon ar9300_eeprom_get_ht40_trgt_pwr(
1052b7d5e03cSMatthew Dillon ah, HT_TARGET_RATE_4, freq, is_2ghz) + ht40_power_inc_for_pdadc;
1053b7d5e03cSMatthew Dillon target_power_val_t2[ALL_TARGET_HT40_5] =
1054b7d5e03cSMatthew Dillon ar9300_eeprom_get_ht40_trgt_pwr(
1055b7d5e03cSMatthew Dillon ah, HT_TARGET_RATE_5, freq, is_2ghz) + ht40_power_inc_for_pdadc;
1056b7d5e03cSMatthew Dillon target_power_val_t2[ALL_TARGET_HT40_6] =
1057b7d5e03cSMatthew Dillon ar9300_eeprom_get_ht40_trgt_pwr(
1058b7d5e03cSMatthew Dillon ah, HT_TARGET_RATE_6, freq, is_2ghz) + ht40_power_inc_for_pdadc;
1059b7d5e03cSMatthew Dillon target_power_val_t2[ALL_TARGET_HT40_7] =
1060b7d5e03cSMatthew Dillon ar9300_eeprom_get_ht40_trgt_pwr(
1061b7d5e03cSMatthew Dillon ah, HT_TARGET_RATE_7, freq, is_2ghz) + ht40_power_inc_for_pdadc;
1062b7d5e03cSMatthew Dillon target_power_val_t2[ALL_TARGET_HT40_12] =
1063b7d5e03cSMatthew Dillon ar9300_eeprom_get_ht40_trgt_pwr(
1064b7d5e03cSMatthew Dillon ah, HT_TARGET_RATE_12, freq, is_2ghz) + ht40_power_inc_for_pdadc;
1065b7d5e03cSMatthew Dillon target_power_val_t2[ALL_TARGET_HT40_13] =
1066b7d5e03cSMatthew Dillon ar9300_eeprom_get_ht40_trgt_pwr(
1067b7d5e03cSMatthew Dillon ah, HT_TARGET_RATE_13, freq, is_2ghz) + ht40_power_inc_for_pdadc;
1068b7d5e03cSMatthew Dillon target_power_val_t2[ALL_TARGET_HT40_14] =
1069b7d5e03cSMatthew Dillon ar9300_eeprom_get_ht40_trgt_pwr(
1070b7d5e03cSMatthew Dillon ah, HT_TARGET_RATE_14, freq, is_2ghz) + ht40_power_inc_for_pdadc;
1071b7d5e03cSMatthew Dillon target_power_val_t2[ALL_TARGET_HT40_15] =
1072b7d5e03cSMatthew Dillon ar9300_eeprom_get_ht40_trgt_pwr(
1073b7d5e03cSMatthew Dillon ah, HT_TARGET_RATE_15, freq, is_2ghz) + ht40_power_inc_for_pdadc;
1074b7d5e03cSMatthew Dillon target_power_val_t2[ALL_TARGET_HT40_20] =
1075b7d5e03cSMatthew Dillon ar9300_eeprom_get_ht40_trgt_pwr(
1076b7d5e03cSMatthew Dillon ah, HT_TARGET_RATE_20, freq, is_2ghz) + ht40_power_inc_for_pdadc;
1077b7d5e03cSMatthew Dillon target_power_val_t2[ALL_TARGET_HT40_21] =
1078b7d5e03cSMatthew Dillon ar9300_eeprom_get_ht40_trgt_pwr(
1079b7d5e03cSMatthew Dillon ah, HT_TARGET_RATE_21, freq, is_2ghz) + ht40_power_inc_for_pdadc;
1080b7d5e03cSMatthew Dillon target_power_val_t2[ALL_TARGET_HT40_22] =
1081b7d5e03cSMatthew Dillon ar9300_eeprom_get_ht40_trgt_pwr(
1082b7d5e03cSMatthew Dillon ah, HT_TARGET_RATE_22, freq, is_2ghz) + ht40_power_inc_for_pdadc;
1083b7d5e03cSMatthew Dillon target_power_val_t2[ALL_TARGET_HT40_23] =
1084b7d5e03cSMatthew Dillon ar9300_eeprom_get_ht40_trgt_pwr(
1085b7d5e03cSMatthew Dillon ah, HT_TARGET_RATE_23, freq, is_2ghz) + ht40_power_inc_for_pdadc;
1086b7d5e03cSMatthew Dillon
1087b7d5e03cSMatthew Dillon #ifdef AH_DEBUG
1088b7d5e03cSMatthew Dillon {
1089b7d5e03cSMatthew Dillon int i = 0;
1090b7d5e03cSMatthew Dillon
1091b7d5e03cSMatthew Dillon HALDEBUG(ah, HAL_DEBUG_EEPROM, "%s: APPLYING TARGET POWERS\n", __func__);
1092b7d5e03cSMatthew Dillon while (i < ar9300_rate_size) {
1093b7d5e03cSMatthew Dillon HALDEBUG(ah, HAL_DEBUG_EEPROM, "%s: TPC[%02d] 0x%08x ",
1094b7d5e03cSMatthew Dillon __func__, i, target_power_val_t2[i]);
1095b7d5e03cSMatthew Dillon i++;
1096b7d5e03cSMatthew Dillon if (i == ar9300_rate_size) {
1097b7d5e03cSMatthew Dillon break;
1098b7d5e03cSMatthew Dillon }
1099b7d5e03cSMatthew Dillon HALDEBUG(ah, HAL_DEBUG_EEPROM, "%s: TPC[%02d] 0x%08x ",
1100b7d5e03cSMatthew Dillon __func__, i, target_power_val_t2[i]);
1101b7d5e03cSMatthew Dillon i++;
1102b7d5e03cSMatthew Dillon if (i == ar9300_rate_size) {
1103b7d5e03cSMatthew Dillon break;
1104b7d5e03cSMatthew Dillon }
1105b7d5e03cSMatthew Dillon HALDEBUG(ah, HAL_DEBUG_EEPROM, "%s: TPC[%02d] 0x%08x ",
1106b7d5e03cSMatthew Dillon __func__, i, target_power_val_t2[i]);
1107b7d5e03cSMatthew Dillon i++;
1108b7d5e03cSMatthew Dillon if (i == ar9300_rate_size) {
1109b7d5e03cSMatthew Dillon break;
1110b7d5e03cSMatthew Dillon }
1111b7d5e03cSMatthew Dillon HALDEBUG(ah, HAL_DEBUG_EEPROM, "%s: TPC[%02d] 0x%08x \n",
1112b7d5e03cSMatthew Dillon __func__, i, target_power_val_t2[i]);
1113b7d5e03cSMatthew Dillon i++;
1114b7d5e03cSMatthew Dillon }
1115b7d5e03cSMatthew Dillon }
1116b7d5e03cSMatthew Dillon #endif
1117b7d5e03cSMatthew Dillon }
1118b7d5e03cSMatthew Dillon
ar9300_regulatory_domain_get(struct ath_hal * ah)1119b7d5e03cSMatthew Dillon u_int16_t *ar9300_regulatory_domain_get(struct ath_hal *ah)
1120b7d5e03cSMatthew Dillon {
1121b7d5e03cSMatthew Dillon ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom;
1122b7d5e03cSMatthew Dillon return eep->base_eep_header.reg_dmn;
1123b7d5e03cSMatthew Dillon }
1124b7d5e03cSMatthew Dillon
1125b7d5e03cSMatthew Dillon
1126b7d5e03cSMatthew Dillon int32_t
ar9300_eeprom_write_enable_gpio_get(struct ath_hal * ah)1127b7d5e03cSMatthew Dillon ar9300_eeprom_write_enable_gpio_get(struct ath_hal *ah)
1128b7d5e03cSMatthew Dillon {
1129b7d5e03cSMatthew Dillon ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom;
1130b7d5e03cSMatthew Dillon return eep->base_eep_header.eeprom_write_enable_gpio;
1131b7d5e03cSMatthew Dillon }
1132b7d5e03cSMatthew Dillon
1133b7d5e03cSMatthew Dillon int32_t
ar9300_wlan_disable_gpio_get(struct ath_hal * ah)1134b7d5e03cSMatthew Dillon ar9300_wlan_disable_gpio_get(struct ath_hal *ah)
1135b7d5e03cSMatthew Dillon {
1136b7d5e03cSMatthew Dillon ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom;
1137b7d5e03cSMatthew Dillon return eep->base_eep_header.wlan_disable_gpio;
1138b7d5e03cSMatthew Dillon }
1139b7d5e03cSMatthew Dillon
1140b7d5e03cSMatthew Dillon int32_t
ar9300_wlan_led_gpio_get(struct ath_hal * ah)1141b7d5e03cSMatthew Dillon ar9300_wlan_led_gpio_get(struct ath_hal *ah)
1142b7d5e03cSMatthew Dillon {
1143b7d5e03cSMatthew Dillon ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom;
1144b7d5e03cSMatthew Dillon return eep->base_eep_header.wlan_led_gpio;
1145b7d5e03cSMatthew Dillon }
1146b7d5e03cSMatthew Dillon
1147b7d5e03cSMatthew Dillon int32_t
ar9300_rx_band_select_gpio_get(struct ath_hal * ah)1148b7d5e03cSMatthew Dillon ar9300_rx_band_select_gpio_get(struct ath_hal *ah)
1149b7d5e03cSMatthew Dillon {
1150b7d5e03cSMatthew Dillon ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom;
1151b7d5e03cSMatthew Dillon return eep->base_eep_header.rx_band_select_gpio;
1152b7d5e03cSMatthew Dillon }
1153b7d5e03cSMatthew Dillon
1154b7d5e03cSMatthew Dillon /*
1155b7d5e03cSMatthew Dillon * since valid noise floor values are negative, returns 1 on error
1156b7d5e03cSMatthew Dillon */
1157b7d5e03cSMatthew Dillon int32_t
ar9300_noise_floor_cal_or_power_get(struct ath_hal * ah,int32_t frequency,int32_t ichain,HAL_BOOL use_cal)1158b7d5e03cSMatthew Dillon ar9300_noise_floor_cal_or_power_get(struct ath_hal *ah, int32_t frequency,
1159b7d5e03cSMatthew Dillon int32_t ichain, HAL_BOOL use_cal)
1160b7d5e03cSMatthew Dillon {
1161b7d5e03cSMatthew Dillon int nf_use = 1; /* start with an error return value */
1162b7d5e03cSMatthew Dillon int32_t fx[OSPREY_NUM_5G_CAL_PIERS + OSPREY_NUM_2G_CAL_PIERS];
1163b7d5e03cSMatthew Dillon int32_t nf[OSPREY_NUM_5G_CAL_PIERS + OSPREY_NUM_2G_CAL_PIERS];
1164b7d5e03cSMatthew Dillon int nnf;
1165b7d5e03cSMatthew Dillon int is_2ghz;
1166b7d5e03cSMatthew Dillon int ipier, npier;
1167b7d5e03cSMatthew Dillon ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom;
1168b7d5e03cSMatthew Dillon u_int8_t *p_cal_pier;
1169b7d5e03cSMatthew Dillon OSP_CAL_DATA_PER_FREQ_OP_LOOP *p_cal_pier_struct;
1170b7d5e03cSMatthew Dillon
1171b7d5e03cSMatthew Dillon /*
1172b7d5e03cSMatthew Dillon * check chain value
1173b7d5e03cSMatthew Dillon */
1174b7d5e03cSMatthew Dillon if (ichain < 0 || ichain >= OSPREY_MAX_CHAINS) {
1175b7d5e03cSMatthew Dillon return 1;
1176b7d5e03cSMatthew Dillon }
1177b7d5e03cSMatthew Dillon
1178b7d5e03cSMatthew Dillon /* figure out which band we're using */
1179b7d5e03cSMatthew Dillon is_2ghz = (frequency < 4000);
1180b7d5e03cSMatthew Dillon if (is_2ghz) {
1181b7d5e03cSMatthew Dillon npier = OSPREY_NUM_2G_CAL_PIERS;
1182b7d5e03cSMatthew Dillon p_cal_pier = eep->cal_freq_pier_2g;
1183b7d5e03cSMatthew Dillon p_cal_pier_struct = eep->cal_pier_data_2g[ichain];
1184b7d5e03cSMatthew Dillon } else {
1185b7d5e03cSMatthew Dillon npier = OSPREY_NUM_5G_CAL_PIERS;
1186b7d5e03cSMatthew Dillon p_cal_pier = eep->cal_freq_pier_5g;
1187b7d5e03cSMatthew Dillon p_cal_pier_struct = eep->cal_pier_data_5g[ichain];
1188b7d5e03cSMatthew Dillon }
1189b7d5e03cSMatthew Dillon /* look for valid noise floor values */
1190b7d5e03cSMatthew Dillon nnf = 0;
1191b7d5e03cSMatthew Dillon for (ipier = 0; ipier < npier; ipier++) {
1192b7d5e03cSMatthew Dillon fx[nnf] = FBIN2FREQ(p_cal_pier[ipier], is_2ghz);
1193b7d5e03cSMatthew Dillon nf[nnf] = use_cal ?
1194b7d5e03cSMatthew Dillon p_cal_pier_struct[ipier].rx_noisefloor_cal :
1195b7d5e03cSMatthew Dillon p_cal_pier_struct[ipier].rx_noisefloor_power;
1196b7d5e03cSMatthew Dillon if (nf[nnf] < 0) {
1197b7d5e03cSMatthew Dillon nnf++;
1198b7d5e03cSMatthew Dillon }
1199b7d5e03cSMatthew Dillon }
1200b7d5e03cSMatthew Dillon /*
1201b7d5e03cSMatthew Dillon * If we have some valid values, interpolate to find the value
1202b7d5e03cSMatthew Dillon * at the desired frequency.
1203b7d5e03cSMatthew Dillon */
1204b7d5e03cSMatthew Dillon if (nnf > 0) {
1205b7d5e03cSMatthew Dillon nf_use = interpolate(frequency, fx, nf, nnf);
1206b7d5e03cSMatthew Dillon }
1207b7d5e03cSMatthew Dillon
1208b7d5e03cSMatthew Dillon return nf_use;
1209b7d5e03cSMatthew Dillon }
1210b7d5e03cSMatthew Dillon
1211a20e5e51SMatthew Dillon /*
1212a20e5e51SMatthew Dillon * Return the Rx NF offset for specific channel.
1213a20e5e51SMatthew Dillon * The values saved in EEPROM/OTP/Flash is converted through the following way:
1214a20e5e51SMatthew Dillon * ((_p) - NOISE_PWR_DATA_OFFSET) << 2
1215a20e5e51SMatthew Dillon * So we need to convert back to the original values.
1216a20e5e51SMatthew Dillon */
ar9300_get_rx_nf_offset(struct ath_hal * ah,struct ieee80211_channel * chan,int8_t * nf_pwr,int8_t * nf_cal)1217a20e5e51SMatthew Dillon int ar9300_get_rx_nf_offset(struct ath_hal *ah, struct ieee80211_channel *chan, int8_t *nf_pwr, int8_t *nf_cal) {
1218a20e5e51SMatthew Dillon HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan);
1219a20e5e51SMatthew Dillon int8_t rx_nf_pwr, rx_nf_cal;
1220a20e5e51SMatthew Dillon int i;
1221a20e5e51SMatthew Dillon //HALASSERT(ichan);
1222a20e5e51SMatthew Dillon
1223a20e5e51SMatthew Dillon /* Fill 0 if valid internal channel is not found */
1224a20e5e51SMatthew Dillon if (ichan == AH_NULL) {
1225a20e5e51SMatthew Dillon OS_MEMZERO(nf_pwr, sizeof(nf_pwr[0])*OSPREY_MAX_CHAINS);
1226a20e5e51SMatthew Dillon OS_MEMZERO(nf_cal, sizeof(nf_cal[0])*OSPREY_MAX_CHAINS);
1227a20e5e51SMatthew Dillon return -1;
1228a20e5e51SMatthew Dillon }
1229a20e5e51SMatthew Dillon
1230a20e5e51SMatthew Dillon for (i = 0; i < OSPREY_MAX_CHAINS; i++) {
1231a20e5e51SMatthew Dillon if ((rx_nf_pwr = ar9300_noise_floor_cal_or_power_get(ah, ichan->channel, i, 0)) == 1) {
1232a20e5e51SMatthew Dillon nf_pwr[i] = 0;
1233a20e5e51SMatthew Dillon } else {
1234a20e5e51SMatthew Dillon //printk("%s: raw nf_pwr[%d] = %d\n", __func__, i, rx_nf_pwr);
1235a20e5e51SMatthew Dillon nf_pwr[i] = NOISE_PWR_DBM_2_INT(rx_nf_pwr);
1236a20e5e51SMatthew Dillon }
1237a20e5e51SMatthew Dillon
1238a20e5e51SMatthew Dillon if ((rx_nf_cal = ar9300_noise_floor_cal_or_power_get(ah, ichan->channel, i, 1)) == 1) {
1239a20e5e51SMatthew Dillon nf_cal[i] = 0;
1240a20e5e51SMatthew Dillon } else {
1241a20e5e51SMatthew Dillon //printk("%s: raw nf_cal[%d] = %d\n", __func__, i, rx_nf_cal);
1242a20e5e51SMatthew Dillon nf_cal[i] = NOISE_PWR_DBM_2_INT(rx_nf_cal);
1243a20e5e51SMatthew Dillon }
1244a20e5e51SMatthew Dillon }
1245a20e5e51SMatthew Dillon
1246a20e5e51SMatthew Dillon return 0;
1247a20e5e51SMatthew Dillon }
1248a20e5e51SMatthew Dillon
ar9300_rx_gain_index_get(struct ath_hal * ah)1249b7d5e03cSMatthew Dillon int32_t ar9300_rx_gain_index_get(struct ath_hal *ah)
1250b7d5e03cSMatthew Dillon {
1251b7d5e03cSMatthew Dillon ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom;
1252b7d5e03cSMatthew Dillon
1253b7d5e03cSMatthew Dillon return (eep->base_eep_header.txrxgain) & 0xf; /* bits 3:0 */
1254b7d5e03cSMatthew Dillon }
1255b7d5e03cSMatthew Dillon
1256b7d5e03cSMatthew Dillon
ar9300_tx_gain_index_get(struct ath_hal * ah)1257b7d5e03cSMatthew Dillon int32_t ar9300_tx_gain_index_get(struct ath_hal *ah)
1258b7d5e03cSMatthew Dillon {
1259b7d5e03cSMatthew Dillon ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom;
1260b7d5e03cSMatthew Dillon
1261b7d5e03cSMatthew Dillon return (eep->base_eep_header.txrxgain >> 4) & 0xf; /* bits 7:4 */
1262b7d5e03cSMatthew Dillon }
1263b7d5e03cSMatthew Dillon
ar9300_internal_regulator_apply(struct ath_hal * ah)1264b7d5e03cSMatthew Dillon HAL_BOOL ar9300_internal_regulator_apply(struct ath_hal *ah)
1265b7d5e03cSMatthew Dillon {
1266b7d5e03cSMatthew Dillon struct ath_hal_9300 *ahp = AH9300(ah);
1267b7d5e03cSMatthew Dillon int internal_regulator = ar9300_eeprom_get(ahp, EEP_INTERNAL_REGULATOR);
1268b7d5e03cSMatthew Dillon int reg_pmu1, reg_pmu2, reg_pmu1_set, reg_pmu2_set;
1269b7d5e03cSMatthew Dillon u_int32_t reg_PMU1, reg_PMU2;
1270b7d5e03cSMatthew Dillon unsigned long eep_addr;
1271b7d5e03cSMatthew Dillon u_int32_t reg_val, reg_usb = 0, reg_pmu = 0;
1272b7d5e03cSMatthew Dillon int usb_valid = 0, pmu_valid = 0;
1273b7d5e03cSMatthew Dillon unsigned char pmu_refv;
1274b7d5e03cSMatthew Dillon
1275b7d5e03cSMatthew Dillon if (AR_SREV_JUPITER(ah) || AR_SREV_APHRODITE(ah)) {
1276b7d5e03cSMatthew Dillon reg_PMU1 = AR_PHY_PMU1_JUPITER;
1277b7d5e03cSMatthew Dillon reg_PMU2 = AR_PHY_PMU2_JUPITER;
1278b7d5e03cSMatthew Dillon }
1279b7d5e03cSMatthew Dillon else {
1280b7d5e03cSMatthew Dillon reg_PMU1 = AR_PHY_PMU1;
1281b7d5e03cSMatthew Dillon reg_PMU2 = AR_PHY_PMU2;
1282b7d5e03cSMatthew Dillon }
1283b7d5e03cSMatthew Dillon
1284b7d5e03cSMatthew Dillon if (internal_regulator) {
1285b7d5e03cSMatthew Dillon if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah)) {
1286b7d5e03cSMatthew Dillon if (AR_SREV_HORNET(ah)) {
1287b7d5e03cSMatthew Dillon /* Read OTP first */
1288b7d5e03cSMatthew Dillon for (eep_addr = 0x14; ; eep_addr -= 0x10) {
1289b7d5e03cSMatthew Dillon
1290b7d5e03cSMatthew Dillon ar9300_otp_read(ah, eep_addr / 4, ®_val, 1);
1291b7d5e03cSMatthew Dillon
1292b7d5e03cSMatthew Dillon if ((reg_val & 0x80) == 0x80){
1293b7d5e03cSMatthew Dillon usb_valid = 1;
1294b7d5e03cSMatthew Dillon reg_usb = reg_val & 0x000000ff;
1295b7d5e03cSMatthew Dillon }
1296b7d5e03cSMatthew Dillon
1297b7d5e03cSMatthew Dillon if ((reg_val & 0x80000000) == 0x80000000){
1298b7d5e03cSMatthew Dillon pmu_valid = 1;
1299b7d5e03cSMatthew Dillon reg_pmu = (reg_val & 0xff000000) >> 24;
1300b7d5e03cSMatthew Dillon }
1301b7d5e03cSMatthew Dillon
1302b7d5e03cSMatthew Dillon if (eep_addr == 0x4) {
1303b7d5e03cSMatthew Dillon break;
1304b7d5e03cSMatthew Dillon }
1305b7d5e03cSMatthew Dillon }
1306b7d5e03cSMatthew Dillon
1307b7d5e03cSMatthew Dillon if (pmu_valid) {
1308b7d5e03cSMatthew Dillon pmu_refv = reg_pmu & 0xf;
1309b7d5e03cSMatthew Dillon } else {
1310b7d5e03cSMatthew Dillon pmu_refv = 0x8;
1311b7d5e03cSMatthew Dillon }
1312b7d5e03cSMatthew Dillon
1313b7d5e03cSMatthew Dillon /*
1314b7d5e03cSMatthew Dillon * If (valid) {
1315b7d5e03cSMatthew Dillon * Usb_phy_ctrl2_tx_cal_en -> 0
1316b7d5e03cSMatthew Dillon * Usb_phy_ctrl2_tx_cal_sel -> 0
1317b7d5e03cSMatthew Dillon * Usb_phy_ctrl2_tx_man_cal -> 0, 1, 3, 7 or 15 from OTP
1318b7d5e03cSMatthew Dillon * }
1319b7d5e03cSMatthew Dillon */
1320b7d5e03cSMatthew Dillon if (usb_valid) {
1321b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah, 0x16c88, AR_PHY_CTRL2_TX_CAL_EN, 0x0);
1322b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah, 0x16c88, AR_PHY_CTRL2_TX_CAL_SEL, 0x0);
1323b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah, 0x16c88,
1324b7d5e03cSMatthew Dillon AR_PHY_CTRL2_TX_MAN_CAL, (reg_usb & 0xf));
1325b7d5e03cSMatthew Dillon }
1326b7d5e03cSMatthew Dillon
1327b7d5e03cSMatthew Dillon } else {
1328b7d5e03cSMatthew Dillon pmu_refv = 0x8;
1329b7d5e03cSMatthew Dillon }
1330b7d5e03cSMatthew Dillon /*#ifndef USE_HIF*/
1331b7d5e03cSMatthew Dillon /* Follow the MDK settings for Hornet PMU.
1332b7d5e03cSMatthew Dillon * my $pwd = 0x0;
1333b7d5e03cSMatthew Dillon * my $Nfdiv = 0x3; # xtal_freq = 25MHz
1334b7d5e03cSMatthew Dillon * my $Nfdiv = 0x4; # xtal_freq = 40MHz
1335b7d5e03cSMatthew Dillon * my $Refv = 0x7; # 0x5:1.22V; 0x8:1.29V
1336b7d5e03cSMatthew Dillon * my $Gm1 = 0x3; #Poseidon $Gm1=1
1337b7d5e03cSMatthew Dillon * my $classb = 0x0;
1338b7d5e03cSMatthew Dillon * my $Cc = 0x1; #Poseidon $Cc=7
1339b7d5e03cSMatthew Dillon * my $Rc = 0x6;
1340b7d5e03cSMatthew Dillon * my $ramp_slope = 0x1;
1341b7d5e03cSMatthew Dillon * my $Segm = 0x3;
1342b7d5e03cSMatthew Dillon * my $use_local_osc = 0x0;
1343b7d5e03cSMatthew Dillon * my $force_xosc_stable = 0x0;
1344b7d5e03cSMatthew Dillon * my $Selfb = 0x0; #Poseidon $Selfb=1
1345b7d5e03cSMatthew Dillon * my $Filterfb = 0x3; #Poseidon $Filterfb=0
1346b7d5e03cSMatthew Dillon * my $Filtervc = 0x0;
1347b7d5e03cSMatthew Dillon * my $disc = 0x0;
1348b7d5e03cSMatthew Dillon * my $discdel = 0x4;
1349b7d5e03cSMatthew Dillon * my $spare = 0x0;
1350b7d5e03cSMatthew Dillon * $reg_PMU1 =
1351b7d5e03cSMatthew Dillon * $pwd | ($Nfdiv<<1) | ($Refv<<4) | ($Gm1<<8) |
1352b7d5e03cSMatthew Dillon * ($classb<<11) | ($Cc<<14) | ($Rc<<17) | ($ramp_slope<<20) |
1353b7d5e03cSMatthew Dillon * ($Segm<<24) | ($use_local_osc<<26) |
1354b7d5e03cSMatthew Dillon * ($force_xosc_stable<<27) | ($Selfb<<28) | ($Filterfb<<29);
1355b7d5e03cSMatthew Dillon * $reg_PMU2 = $handle->reg_rd("ch0_PMU2");
1356b7d5e03cSMatthew Dillon * $reg_PMU2 = ($reg_PMU2 & 0xfe3fffff) | ($Filtervc<<22);
1357b7d5e03cSMatthew Dillon * $reg_PMU2 = ($reg_PMU2 & 0xe3ffffff) | ($discdel<<26);
1358b7d5e03cSMatthew Dillon * $reg_PMU2 = ($reg_PMU2 & 0x1fffffff) | ($spare<<29);
1359b7d5e03cSMatthew Dillon */
1360b7d5e03cSMatthew Dillon if (ahp->clk_25mhz) {
1361b7d5e03cSMatthew Dillon reg_pmu1_set = 0 |
1362b7d5e03cSMatthew Dillon (3 << 1) | (pmu_refv << 4) | (3 << 8) | (0 << 11) |
1363b7d5e03cSMatthew Dillon (1 << 14) | (6 << 17) | (1 << 20) | (3 << 24) |
1364b7d5e03cSMatthew Dillon (0 << 26) | (0 << 27) | (0 << 28) | (0 << 29);
1365b7d5e03cSMatthew Dillon } else {
1366b7d5e03cSMatthew Dillon if (AR_SREV_POSEIDON(ah)) {
1367b7d5e03cSMatthew Dillon reg_pmu1_set = 0 |
1368b7d5e03cSMatthew Dillon (5 << 1) | (7 << 4) | (2 << 8) | (0 << 11) |
1369b7d5e03cSMatthew Dillon (2 << 14) | (6 << 17) | (1 << 20) | (3 << 24) |
1370b7d5e03cSMatthew Dillon (0 << 26) | (0 << 27) | (1 << 28) | (0 << 29) ;
1371b7d5e03cSMatthew Dillon } else {
1372b7d5e03cSMatthew Dillon reg_pmu1_set = 0 |
1373b7d5e03cSMatthew Dillon (4 << 1) | (7 << 4) | (3 << 8) | (0 << 11) |
1374b7d5e03cSMatthew Dillon (1 << 14) | (6 << 17) | (1 << 20) | (3 << 24) |
1375b7d5e03cSMatthew Dillon (0 << 26) | (0 << 27) | (0 << 28) | (0 << 29) ;
1376b7d5e03cSMatthew Dillon }
1377b7d5e03cSMatthew Dillon }
1378b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah, reg_PMU2, AR_PHY_PMU2_PGM, 0x0);
1379b7d5e03cSMatthew Dillon
1380b7d5e03cSMatthew Dillon OS_REG_WRITE(ah, reg_PMU1, reg_pmu1_set); /* 0x638c8376 */
1381b7d5e03cSMatthew Dillon reg_pmu1 = OS_REG_READ(ah, reg_PMU1);
1382b7d5e03cSMatthew Dillon while (reg_pmu1 != reg_pmu1_set) {
1383b7d5e03cSMatthew Dillon OS_REG_WRITE(ah, reg_PMU1, reg_pmu1_set); /* 0x638c8376 */
1384b7d5e03cSMatthew Dillon OS_DELAY(10);
1385b7d5e03cSMatthew Dillon reg_pmu1 = OS_REG_READ(ah, reg_PMU1);
1386b7d5e03cSMatthew Dillon }
1387b7d5e03cSMatthew Dillon
1388b7d5e03cSMatthew Dillon reg_pmu2_set =
1389b7d5e03cSMatthew Dillon (OS_REG_READ(ah, reg_PMU2) & (~0xFFC00000)) | (4 << 26);
1390b7d5e03cSMatthew Dillon OS_REG_WRITE(ah, reg_PMU2, reg_pmu2_set);
1391b7d5e03cSMatthew Dillon reg_pmu2 = OS_REG_READ(ah, reg_PMU2);
1392b7d5e03cSMatthew Dillon while (reg_pmu2 != reg_pmu2_set) {
1393b7d5e03cSMatthew Dillon OS_REG_WRITE(ah, reg_PMU2, reg_pmu2_set);
1394b7d5e03cSMatthew Dillon OS_DELAY(10);
1395b7d5e03cSMatthew Dillon reg_pmu2 = OS_REG_READ(ah, reg_PMU2);
1396b7d5e03cSMatthew Dillon }
1397b7d5e03cSMatthew Dillon reg_pmu2_set =
1398b7d5e03cSMatthew Dillon (OS_REG_READ(ah, reg_PMU2) & (~0x00200000)) | (1 << 21);
1399b7d5e03cSMatthew Dillon OS_REG_WRITE(ah, reg_PMU2, reg_pmu2_set);
1400b7d5e03cSMatthew Dillon reg_pmu2 = OS_REG_READ(ah, reg_PMU2);
1401b7d5e03cSMatthew Dillon while (reg_pmu2 != reg_pmu2_set) {
1402b7d5e03cSMatthew Dillon OS_REG_WRITE(ah, reg_PMU2, reg_pmu2_set);
1403b7d5e03cSMatthew Dillon OS_DELAY(10);
1404b7d5e03cSMatthew Dillon reg_pmu2 = OS_REG_READ(ah, reg_PMU2);
1405b7d5e03cSMatthew Dillon }
1406b7d5e03cSMatthew Dillon /*#endif*/
1407b7d5e03cSMatthew Dillon } else if (AR_SREV_JUPITER(ah) || AR_SREV_APHRODITE(ah)) {
1408b7d5e03cSMatthew Dillon /* Internal regulator is ON. Write swreg register. */
1409b7d5e03cSMatthew Dillon int swreg = ar9300_eeprom_get(ahp, EEP_SWREG);
1410b7d5e03cSMatthew Dillon OS_REG_WRITE(ah, reg_PMU1, swreg);
1411b7d5e03cSMatthew Dillon } else {
1412b7d5e03cSMatthew Dillon /* Internal regulator is ON. Write swreg register. */
1413b7d5e03cSMatthew Dillon int swreg = ar9300_eeprom_get(ahp, EEP_SWREG);
1414b7d5e03cSMatthew Dillon OS_REG_WRITE(ah, AR_RTC_REG_CONTROL1,
1415b7d5e03cSMatthew Dillon OS_REG_READ(ah, AR_RTC_REG_CONTROL1) &
1416b7d5e03cSMatthew Dillon (~AR_RTC_REG_CONTROL1_SWREG_PROGRAM));
1417b7d5e03cSMatthew Dillon OS_REG_WRITE(ah, AR_RTC_REG_CONTROL0, swreg);
1418b7d5e03cSMatthew Dillon /* Set REG_CONTROL1.SWREG_PROGRAM */
1419b7d5e03cSMatthew Dillon OS_REG_WRITE(ah, AR_RTC_REG_CONTROL1,
1420b7d5e03cSMatthew Dillon OS_REG_READ(ah, AR_RTC_REG_CONTROL1) |
1421b7d5e03cSMatthew Dillon AR_RTC_REG_CONTROL1_SWREG_PROGRAM);
1422b7d5e03cSMatthew Dillon }
1423b7d5e03cSMatthew Dillon } else {
1424b7d5e03cSMatthew Dillon if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah)) {
1425b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah, reg_PMU2, AR_PHY_PMU2_PGM, 0x0);
1426b7d5e03cSMatthew Dillon reg_pmu2 = OS_REG_READ_FIELD(ah, reg_PMU2, AR_PHY_PMU2_PGM);
1427b7d5e03cSMatthew Dillon while (reg_pmu2) {
1428b7d5e03cSMatthew Dillon OS_DELAY(10);
1429b7d5e03cSMatthew Dillon reg_pmu2 = OS_REG_READ_FIELD(ah, reg_PMU2, AR_PHY_PMU2_PGM);
1430b7d5e03cSMatthew Dillon }
1431b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah, reg_PMU1, AR_PHY_PMU1_PWD, 0x1);
1432b7d5e03cSMatthew Dillon reg_pmu1 = OS_REG_READ_FIELD(ah, reg_PMU1, AR_PHY_PMU1_PWD);
1433b7d5e03cSMatthew Dillon while (!reg_pmu1) {
1434b7d5e03cSMatthew Dillon OS_DELAY(10);
1435b7d5e03cSMatthew Dillon reg_pmu1 = OS_REG_READ_FIELD(ah, reg_PMU1, AR_PHY_PMU1_PWD);
1436b7d5e03cSMatthew Dillon }
1437b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah, reg_PMU2, AR_PHY_PMU2_PGM, 0x1);
1438b7d5e03cSMatthew Dillon reg_pmu2 = OS_REG_READ_FIELD(ah, reg_PMU2, AR_PHY_PMU2_PGM);
1439b7d5e03cSMatthew Dillon while (!reg_pmu2) {
1440b7d5e03cSMatthew Dillon OS_DELAY(10);
1441b7d5e03cSMatthew Dillon reg_pmu2 = OS_REG_READ_FIELD(ah, reg_PMU2, AR_PHY_PMU2_PGM);
1442b7d5e03cSMatthew Dillon }
1443b7d5e03cSMatthew Dillon } else if (AR_SREV_JUPITER(ah) || AR_SREV_APHRODITE(ah)) {
1444b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah, reg_PMU1, AR_PHY_PMU1_PWD, 0x1);
1445b7d5e03cSMatthew Dillon } else {
1446b7d5e03cSMatthew Dillon OS_REG_WRITE(ah, AR_RTC_SLEEP_CLK,
1447b7d5e03cSMatthew Dillon (OS_REG_READ(ah, AR_RTC_SLEEP_CLK) |
1448b7d5e03cSMatthew Dillon AR_RTC_FORCE_SWREG_PRD | AR_RTC_PCIE_RST_PWDN_EN));
1449b7d5e03cSMatthew Dillon }
1450b7d5e03cSMatthew Dillon }
1451b7d5e03cSMatthew Dillon
1452b7d5e03cSMatthew Dillon return 0;
1453b7d5e03cSMatthew Dillon }
1454b7d5e03cSMatthew Dillon
ar9300_drive_strength_apply(struct ath_hal * ah)1455b7d5e03cSMatthew Dillon HAL_BOOL ar9300_drive_strength_apply(struct ath_hal *ah)
1456b7d5e03cSMatthew Dillon {
1457b7d5e03cSMatthew Dillon struct ath_hal_9300 *ahp = AH9300(ah);
1458b7d5e03cSMatthew Dillon int drive_strength;
1459b7d5e03cSMatthew Dillon unsigned long reg;
1460b7d5e03cSMatthew Dillon
1461b7d5e03cSMatthew Dillon drive_strength = ar9300_eeprom_get(ahp, EEP_DRIVE_STRENGTH);
1462b7d5e03cSMatthew Dillon if (drive_strength) {
1463b7d5e03cSMatthew Dillon reg = OS_REG_READ(ah, AR_PHY_65NM_CH0_BIAS1);
1464b7d5e03cSMatthew Dillon reg &= ~0x00ffffc0;
1465b7d5e03cSMatthew Dillon reg |= 0x5 << 21;
1466b7d5e03cSMatthew Dillon reg |= 0x5 << 18;
1467b7d5e03cSMatthew Dillon reg |= 0x5 << 15;
1468b7d5e03cSMatthew Dillon reg |= 0x5 << 12;
1469b7d5e03cSMatthew Dillon reg |= 0x5 << 9;
1470b7d5e03cSMatthew Dillon reg |= 0x5 << 6;
1471b7d5e03cSMatthew Dillon OS_REG_WRITE(ah, AR_PHY_65NM_CH0_BIAS1, reg);
1472b7d5e03cSMatthew Dillon
1473b7d5e03cSMatthew Dillon reg = OS_REG_READ(ah, AR_PHY_65NM_CH0_BIAS2);
1474b7d5e03cSMatthew Dillon reg &= ~0xffffffe0;
1475b7d5e03cSMatthew Dillon reg |= 0x5 << 29;
1476b7d5e03cSMatthew Dillon reg |= 0x5 << 26;
1477b7d5e03cSMatthew Dillon reg |= 0x5 << 23;
1478b7d5e03cSMatthew Dillon reg |= 0x5 << 20;
1479b7d5e03cSMatthew Dillon reg |= 0x5 << 17;
1480b7d5e03cSMatthew Dillon reg |= 0x5 << 14;
1481b7d5e03cSMatthew Dillon reg |= 0x5 << 11;
1482b7d5e03cSMatthew Dillon reg |= 0x5 << 8;
1483b7d5e03cSMatthew Dillon reg |= 0x5 << 5;
1484b7d5e03cSMatthew Dillon OS_REG_WRITE(ah, AR_PHY_65NM_CH0_BIAS2, reg);
1485b7d5e03cSMatthew Dillon
1486b7d5e03cSMatthew Dillon reg = OS_REG_READ(ah, AR_PHY_65NM_CH0_BIAS4);
1487b7d5e03cSMatthew Dillon reg &= ~0xff800000;
1488b7d5e03cSMatthew Dillon reg |= 0x5 << 29;
1489b7d5e03cSMatthew Dillon reg |= 0x5 << 26;
1490b7d5e03cSMatthew Dillon reg |= 0x5 << 23;
1491b7d5e03cSMatthew Dillon OS_REG_WRITE(ah, AR_PHY_65NM_CH0_BIAS4, reg);
1492b7d5e03cSMatthew Dillon }
1493b7d5e03cSMatthew Dillon return 0;
1494b7d5e03cSMatthew Dillon }
1495b7d5e03cSMatthew Dillon
ar9300_xpa_bias_level_get(struct ath_hal * ah,HAL_BOOL is_2ghz)1496b7d5e03cSMatthew Dillon int32_t ar9300_xpa_bias_level_get(struct ath_hal *ah, HAL_BOOL is_2ghz)
1497b7d5e03cSMatthew Dillon {
1498b7d5e03cSMatthew Dillon ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom;
1499b7d5e03cSMatthew Dillon if (is_2ghz) {
1500b7d5e03cSMatthew Dillon return eep->modal_header_2g.xpa_bias_lvl;
1501b7d5e03cSMatthew Dillon } else {
1502b7d5e03cSMatthew Dillon return eep->modal_header_5g.xpa_bias_lvl;
1503b7d5e03cSMatthew Dillon }
1504b7d5e03cSMatthew Dillon }
1505b7d5e03cSMatthew Dillon
ar9300_xpa_bias_level_apply(struct ath_hal * ah,HAL_BOOL is_2ghz)1506b7d5e03cSMatthew Dillon HAL_BOOL ar9300_xpa_bias_level_apply(struct ath_hal *ah, HAL_BOOL is_2ghz)
1507b7d5e03cSMatthew Dillon {
1508b7d5e03cSMatthew Dillon /*
1509b7d5e03cSMatthew Dillon * In ar9330 emu, we can't access radio registers,
1510b7d5e03cSMatthew Dillon * merlin is used for radio part.
1511b7d5e03cSMatthew Dillon */
1512b7d5e03cSMatthew Dillon int bias;
1513b7d5e03cSMatthew Dillon bias = ar9300_xpa_bias_level_get(ah, is_2ghz);
1514b7d5e03cSMatthew Dillon
1515b7d5e03cSMatthew Dillon if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah) || AR_SREV_WASP(ah)) {
1516b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah,
1517b7d5e03cSMatthew Dillon AR_HORNET_CH0_TOP2, AR_HORNET_CH0_TOP2_XPABIASLVL, bias);
1518b7d5e03cSMatthew Dillon } else if (AR_SREV_SCORPION(ah)) {
1519b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah,
1520b7d5e03cSMatthew Dillon AR_SCORPION_CH0_TOP, AR_SCORPION_CH0_TOP_XPABIASLVL, bias);
1521b7d5e03cSMatthew Dillon } else if (AR_SREV_JUPITER(ah) || AR_SREV_APHRODITE(ah)) {
1522b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah,
1523b7d5e03cSMatthew Dillon AR_PHY_65NM_CH0_TOP_JUPITER, AR_PHY_65NM_CH0_TOP_XPABIASLVL, bias);
1524b7d5e03cSMatthew Dillon } else {
1525b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah,
1526b7d5e03cSMatthew Dillon AR_PHY_65NM_CH0_TOP, AR_PHY_65NM_CH0_TOP_XPABIASLVL, bias);
1527b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah,
1528b7d5e03cSMatthew Dillon AR_PHY_65NM_CH0_THERM, AR_PHY_65NM_CH0_THERM_XPABIASLVL_MSB,
1529b7d5e03cSMatthew Dillon bias >> 2);
1530b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah,
1531b7d5e03cSMatthew Dillon AR_PHY_65NM_CH0_THERM, AR_PHY_65NM_CH0_THERM_XPASHORT2GND, 1);
1532b7d5e03cSMatthew Dillon }
1533b7d5e03cSMatthew Dillon return 0;
1534b7d5e03cSMatthew Dillon }
1535b7d5e03cSMatthew Dillon
ar9300_ant_ctrl_common_get(struct ath_hal * ah,HAL_BOOL is_2ghz)1536b7d5e03cSMatthew Dillon u_int32_t ar9300_ant_ctrl_common_get(struct ath_hal *ah, HAL_BOOL is_2ghz)
1537b7d5e03cSMatthew Dillon {
1538b7d5e03cSMatthew Dillon ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom;
1539b7d5e03cSMatthew Dillon if (is_2ghz) {
1540b7d5e03cSMatthew Dillon return eep->modal_header_2g.ant_ctrl_common;
1541b7d5e03cSMatthew Dillon } else {
1542b7d5e03cSMatthew Dillon return eep->modal_header_5g.ant_ctrl_common;
1543b7d5e03cSMatthew Dillon }
1544b7d5e03cSMatthew Dillon }
1545b7d5e03cSMatthew Dillon static u_int16_t
ar9300_switch_com_spdt_get(struct ath_hal * ah,HAL_BOOL is_2ghz)1546b7d5e03cSMatthew Dillon ar9300_switch_com_spdt_get(struct ath_hal *ah, HAL_BOOL is_2ghz)
1547b7d5e03cSMatthew Dillon {
1548b7d5e03cSMatthew Dillon ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom;
1549b7d5e03cSMatthew Dillon if (is_2ghz) {
1550b7d5e03cSMatthew Dillon return eep->modal_header_2g.switchcomspdt;
1551b7d5e03cSMatthew Dillon } else {
1552b7d5e03cSMatthew Dillon return eep->modal_header_5g.switchcomspdt;
1553b7d5e03cSMatthew Dillon }
1554b7d5e03cSMatthew Dillon }
ar9300_ant_ctrl_common2_get(struct ath_hal * ah,HAL_BOOL is_2ghz)1555b7d5e03cSMatthew Dillon u_int32_t ar9300_ant_ctrl_common2_get(struct ath_hal *ah, HAL_BOOL is_2ghz)
1556b7d5e03cSMatthew Dillon {
1557b7d5e03cSMatthew Dillon ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom;
1558b7d5e03cSMatthew Dillon if (is_2ghz) {
1559b7d5e03cSMatthew Dillon return eep->modal_header_2g.ant_ctrl_common2;
1560b7d5e03cSMatthew Dillon } else {
1561b7d5e03cSMatthew Dillon return eep->modal_header_5g.ant_ctrl_common2;
1562b7d5e03cSMatthew Dillon }
1563b7d5e03cSMatthew Dillon }
1564b7d5e03cSMatthew Dillon
ar9300_ant_ctrl_chain_get(struct ath_hal * ah,int chain,HAL_BOOL is_2ghz)1565b7d5e03cSMatthew Dillon u_int16_t ar9300_ant_ctrl_chain_get(struct ath_hal *ah, int chain,
1566b7d5e03cSMatthew Dillon HAL_BOOL is_2ghz)
1567b7d5e03cSMatthew Dillon {
1568b7d5e03cSMatthew Dillon ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom;
1569b7d5e03cSMatthew Dillon if (chain >= 0 && chain < OSPREY_MAX_CHAINS) {
1570b7d5e03cSMatthew Dillon if (is_2ghz) {
1571b7d5e03cSMatthew Dillon return eep->modal_header_2g.ant_ctrl_chain[chain];
1572b7d5e03cSMatthew Dillon } else {
1573b7d5e03cSMatthew Dillon return eep->modal_header_5g.ant_ctrl_chain[chain];
1574b7d5e03cSMatthew Dillon }
1575b7d5e03cSMatthew Dillon }
1576b7d5e03cSMatthew Dillon return 0;
1577b7d5e03cSMatthew Dillon }
1578b7d5e03cSMatthew Dillon
1579a20e5e51SMatthew Dillon /*
1580a20e5e51SMatthew Dillon * Select the usage of antenna via the RF switch.
1581a20e5e51SMatthew Dillon * Default values are loaded from eeprom.
1582a20e5e51SMatthew Dillon */
ar9300_ant_swcom_sel(struct ath_hal * ah,u_int8_t ops,u_int32_t * common_tbl1,u_int32_t * common_tbl2)1583a20e5e51SMatthew Dillon HAL_BOOL ar9300_ant_swcom_sel(struct ath_hal *ah, u_int8_t ops,
1584a20e5e51SMatthew Dillon u_int32_t *common_tbl1, u_int32_t *common_tbl2)
1585a20e5e51SMatthew Dillon {
1586a20e5e51SMatthew Dillon ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom;
1587a20e5e51SMatthew Dillon struct ath_hal_private *ap = AH_PRIVATE(ah);
1588a20e5e51SMatthew Dillon const struct ieee80211_channel *curchan = ap->ah_curchan;
1589a20e5e51SMatthew Dillon enum {
1590a20e5e51SMatthew Dillon ANT_SELECT_OPS_GET,
1591a20e5e51SMatthew Dillon ANT_SELECT_OPS_SET,
1592a20e5e51SMatthew Dillon };
1593a20e5e51SMatthew Dillon
1594a20e5e51SMatthew Dillon if (AR_SREV_JUPITER(ah) || AR_SREV_SCORPION(ah))
1595a20e5e51SMatthew Dillon return AH_FALSE;
1596a20e5e51SMatthew Dillon
1597a20e5e51SMatthew Dillon if (!curchan)
1598a20e5e51SMatthew Dillon return AH_FALSE;
1599a20e5e51SMatthew Dillon
1600a20e5e51SMatthew Dillon #define AR_SWITCH_TABLE_COM_ALL (0xffff)
1601a20e5e51SMatthew Dillon #define AR_SWITCH_TABLE_COM_ALL_S (0)
1602a20e5e51SMatthew Dillon #define AR_SWITCH_TABLE_COM2_ALL (0xffffff)
1603a20e5e51SMatthew Dillon #define AR_SWITCH_TABLE_COM2_ALL_S (0)
1604a20e5e51SMatthew Dillon switch (ops) {
1605a20e5e51SMatthew Dillon case ANT_SELECT_OPS_GET:
1606a20e5e51SMatthew Dillon *common_tbl1 = OS_REG_READ_FIELD(ah, AR_PHY_SWITCH_COM,
1607a20e5e51SMatthew Dillon AR_SWITCH_TABLE_COM_ALL);
1608a20e5e51SMatthew Dillon *common_tbl2 = OS_REG_READ_FIELD(ah, AR_PHY_SWITCH_COM_2,
1609a20e5e51SMatthew Dillon AR_SWITCH_TABLE_COM2_ALL);
1610a20e5e51SMatthew Dillon break;
1611a20e5e51SMatthew Dillon case ANT_SELECT_OPS_SET:
1612a20e5e51SMatthew Dillon OS_REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM,
1613a20e5e51SMatthew Dillon AR_SWITCH_TABLE_COM_ALL, *common_tbl1);
1614a20e5e51SMatthew Dillon OS_REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM_2,
1615a20e5e51SMatthew Dillon AR_SWITCH_TABLE_COM2_ALL, *common_tbl2);
1616a20e5e51SMatthew Dillon
1617a20e5e51SMatthew Dillon /* write back to eeprom */
1618a20e5e51SMatthew Dillon if (IEEE80211_IS_CHAN_2GHZ(curchan)) {
1619a20e5e51SMatthew Dillon eep->modal_header_2g.ant_ctrl_common = *common_tbl1;
1620a20e5e51SMatthew Dillon eep->modal_header_2g.ant_ctrl_common2 = *common_tbl2;
1621a20e5e51SMatthew Dillon } else {
1622a20e5e51SMatthew Dillon eep->modal_header_5g.ant_ctrl_common = *common_tbl1;
1623a20e5e51SMatthew Dillon eep->modal_header_5g.ant_ctrl_common2 = *common_tbl2;
1624a20e5e51SMatthew Dillon }
1625a20e5e51SMatthew Dillon
1626a20e5e51SMatthew Dillon break;
1627a20e5e51SMatthew Dillon default:
1628a20e5e51SMatthew Dillon break;
1629a20e5e51SMatthew Dillon }
1630a20e5e51SMatthew Dillon
1631a20e5e51SMatthew Dillon return AH_TRUE;
1632a20e5e51SMatthew Dillon }
1633a20e5e51SMatthew Dillon
ar9300_ant_ctrl_apply(struct ath_hal * ah,HAL_BOOL is_2ghz)1634b7d5e03cSMatthew Dillon HAL_BOOL ar9300_ant_ctrl_apply(struct ath_hal *ah, HAL_BOOL is_2ghz)
1635b7d5e03cSMatthew Dillon {
1636b7d5e03cSMatthew Dillon u_int32_t value;
1637b7d5e03cSMatthew Dillon struct ath_hal_9300 *ahp = AH9300(ah);
1638b7d5e03cSMatthew Dillon u_int32_t regval;
1639b7d5e03cSMatthew Dillon struct ath_hal_private *ahpriv = AH_PRIVATE(ah);
1640b7d5e03cSMatthew Dillon #if ATH_ANT_DIV_COMB
1641b7d5e03cSMatthew Dillon HAL_CAPABILITIES *pcap = &ahpriv->ah_caps;
1642b7d5e03cSMatthew Dillon #endif /* ATH_ANT_DIV_COMB */
1643b7d5e03cSMatthew Dillon u_int32_t xlan_gpio_cfg;
1644b7d5e03cSMatthew Dillon u_int8_t i;
1645b7d5e03cSMatthew Dillon
1646b7d5e03cSMatthew Dillon if (AR_SREV_POSEIDON(ah)) {
1647b7d5e03cSMatthew Dillon xlan_gpio_cfg = ah->ah_config.ath_hal_ext_lna_ctl_gpio;
1648b7d5e03cSMatthew Dillon if (xlan_gpio_cfg) {
1649b7d5e03cSMatthew Dillon for (i = 0; i < 32; i++) {
1650b7d5e03cSMatthew Dillon if (xlan_gpio_cfg & (1 << i)) {
1651b7d5e03cSMatthew Dillon ath_hal_gpioCfgOutput(ah, i,
1652b7d5e03cSMatthew Dillon HAL_GPIO_OUTPUT_MUX_PCIE_ATTENTION_LED);
1653b7d5e03cSMatthew Dillon }
1654b7d5e03cSMatthew Dillon }
1655b7d5e03cSMatthew Dillon }
1656b7d5e03cSMatthew Dillon }
1657b7d5e03cSMatthew Dillon #define AR_SWITCH_TABLE_COM_ALL (0xffff)
1658b7d5e03cSMatthew Dillon #define AR_SWITCH_TABLE_COM_ALL_S (0)
1659b7d5e03cSMatthew Dillon #define AR_SWITCH_TABLE_COM_JUPITER_ALL (0xffffff)
1660b7d5e03cSMatthew Dillon #define AR_SWITCH_TABLE_COM_JUPITER_ALL_S (0)
1661b7d5e03cSMatthew Dillon #define AR_SWITCH_TABLE_COM_SCORPION_ALL (0xffffff)
1662b7d5e03cSMatthew Dillon #define AR_SWITCH_TABLE_COM_SCORPION_ALL_S (0)
1663a20e5e51SMatthew Dillon #define AR_SWITCH_TABLE_COM_HONEYBEE_ALL (0xffffff)
1664a20e5e51SMatthew Dillon #define AR_SWITCH_TABLE_COM_HONEYBEE_ALL_S (0)
1665b7d5e03cSMatthew Dillon #define AR_SWITCH_TABLE_COM_SPDT (0x00f00000)
1666b7d5e03cSMatthew Dillon value = ar9300_ant_ctrl_common_get(ah, is_2ghz);
1667b7d5e03cSMatthew Dillon if (AR_SREV_JUPITER(ah) || AR_SREV_APHRODITE(ah)) {
1668b7d5e03cSMatthew Dillon if (AR_SREV_JUPITER_10(ah)) {
1669b7d5e03cSMatthew Dillon /* Force SPDT setting for Jupiter 1.0 chips. */
1670b7d5e03cSMatthew Dillon value &= ~AR_SWITCH_TABLE_COM_SPDT;
1671b7d5e03cSMatthew Dillon value |= 0x00100000;
1672b7d5e03cSMatthew Dillon }
1673b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM,
1674b7d5e03cSMatthew Dillon AR_SWITCH_TABLE_COM_JUPITER_ALL, value);
1675b7d5e03cSMatthew Dillon }
1676b7d5e03cSMatthew Dillon else if (AR_SREV_SCORPION(ah)) {
1677b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM,
1678b7d5e03cSMatthew Dillon AR_SWITCH_TABLE_COM_SCORPION_ALL, value);
1679b7d5e03cSMatthew Dillon }
1680a20e5e51SMatthew Dillon else if (AR_SREV_HONEYBEE(ah)) {
1681a20e5e51SMatthew Dillon OS_REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM,
1682a20e5e51SMatthew Dillon AR_SWITCH_TABLE_COM_HONEYBEE_ALL, value);
1683a20e5e51SMatthew Dillon }
1684b7d5e03cSMatthew Dillon else {
1685b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM,
1686b7d5e03cSMatthew Dillon AR_SWITCH_TABLE_COM_ALL, value);
1687b7d5e03cSMatthew Dillon }
1688b7d5e03cSMatthew Dillon /*
1689b7d5e03cSMatthew Dillon * Jupiter2.0 defines new switch table for BT/WLAN,
1690b7d5e03cSMatthew Dillon * here's new field name in WB222.ref for both 2G and 5G.
1691b7d5e03cSMatthew Dillon * Register: [GLB_CONTROL] GLB_CONTROL (@0x20044)
1692b7d5e03cSMatthew Dillon * 15:12 R/W SWITCH_TABLE_COM_SPDT_WLAN_RX SWITCH_TABLE_COM_SPDT_WLAN_RX
1693b7d5e03cSMatthew Dillon * 11:8 R/W SWITCH_TABLE_COM_SPDT_WLAN_TX SWITCH_TABLE_COM_SPDT_WLAN_TX
1694b7d5e03cSMatthew Dillon * 7:4 R/W SWITCH_TABLE_COM_SPDT_WLAN_IDLE SWITCH_TABLE_COM_SPDT_WLAN_IDLE
1695b7d5e03cSMatthew Dillon */
1696b7d5e03cSMatthew Dillon #define AR_SWITCH_TABLE_COM_SPDT_ALL (0x0000fff0)
1697b7d5e03cSMatthew Dillon #define AR_SWITCH_TABLE_COM_SPDT_ALL_S (4)
1698b7d5e03cSMatthew Dillon if (AR_SREV_JUPITER_20_OR_LATER(ah) || AR_SREV_APHRODITE(ah)) {
1699b7d5e03cSMatthew Dillon value = ar9300_switch_com_spdt_get(ah, is_2ghz);
1700b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah, AR_GLB_CONTROL,
1701b7d5e03cSMatthew Dillon AR_SWITCH_TABLE_COM_SPDT_ALL, value);
1702b7d5e03cSMatthew Dillon
1703b7d5e03cSMatthew Dillon OS_REG_SET_BIT(ah, AR_GLB_CONTROL,
1704b7d5e03cSMatthew Dillon AR_BTCOEX_CTRL_SPDT_ENABLE);
1705b7d5e03cSMatthew Dillon //OS_REG_SET_BIT(ah, AR_GLB_CONTROL,
1706b7d5e03cSMatthew Dillon // AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL);
1707b7d5e03cSMatthew Dillon }
1708b7d5e03cSMatthew Dillon
1709b7d5e03cSMatthew Dillon #define AR_SWITCH_TABLE_COM2_ALL (0xffffff)
1710b7d5e03cSMatthew Dillon #define AR_SWITCH_TABLE_COM2_ALL_S (0)
1711b7d5e03cSMatthew Dillon value = ar9300_ant_ctrl_common2_get(ah, is_2ghz);
1712b7d5e03cSMatthew Dillon #if ATH_ANT_DIV_COMB
1713b7d5e03cSMatthew Dillon if ( AR_SREV_POSEIDON(ah) && (ahp->ah_lna_div_use_bt_ant_enable == TRUE) ) {
1714b7d5e03cSMatthew Dillon value &= ~AR_SWITCH_TABLE_COM2_ALL;
1715b7d5e03cSMatthew Dillon value |= ah->ah_config.ath_hal_ant_ctrl_comm2g_switch_enable;
1716*6e17739dSzrj HALDEBUG(ah, HAL_DEBUG_RESET, "%s: com2=0x%08x\n", __func__, value);
1717b7d5e03cSMatthew Dillon }
1718b7d5e03cSMatthew Dillon #endif /* ATH_ANT_DIV_COMB */
1719b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM_2, AR_SWITCH_TABLE_COM2_ALL, value);
1720b7d5e03cSMatthew Dillon
1721b7d5e03cSMatthew Dillon #define AR_SWITCH_TABLE_ALL (0xfff)
1722b7d5e03cSMatthew Dillon #define AR_SWITCH_TABLE_ALL_S (0)
1723b7d5e03cSMatthew Dillon value = ar9300_ant_ctrl_chain_get(ah, 0, is_2ghz);
1724b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah, AR_PHY_SWITCH_CHAIN_0, AR_SWITCH_TABLE_ALL, value);
1725b7d5e03cSMatthew Dillon
1726b7d5e03cSMatthew Dillon if (!AR_SREV_HORNET(ah) && !AR_SREV_POSEIDON(ah) && !AR_SREV_APHRODITE(ah)) {
1727b7d5e03cSMatthew Dillon value = ar9300_ant_ctrl_chain_get(ah, 1, is_2ghz);
1728b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah, AR_PHY_SWITCH_CHAIN_1, AR_SWITCH_TABLE_ALL, value);
1729b7d5e03cSMatthew Dillon
1730a20e5e51SMatthew Dillon if (!AR_SREV_WASP(ah) && !AR_SREV_JUPITER(ah) && !AR_SREV_HONEYBEE(ah)) {
1731b7d5e03cSMatthew Dillon value = ar9300_ant_ctrl_chain_get(ah, 2, is_2ghz);
1732b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah,
1733b7d5e03cSMatthew Dillon AR_PHY_SWITCH_CHAIN_2, AR_SWITCH_TABLE_ALL, value);
1734b7d5e03cSMatthew Dillon }
1735b7d5e03cSMatthew Dillon }
1736b7d5e03cSMatthew Dillon if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah)) {
1737b7d5e03cSMatthew Dillon value = ar9300_eeprom_get(ahp, EEP_ANTDIV_control);
1738b7d5e03cSMatthew Dillon /* main_lnaconf, alt_lnaconf, main_tb, alt_tb */
1739b7d5e03cSMatthew Dillon regval = OS_REG_READ(ah, AR_PHY_MC_GAIN_CTRL);
1740b7d5e03cSMatthew Dillon regval &= (~ANT_DIV_CONTROL_ALL); /* clear bit 25~30 */
1741b7d5e03cSMatthew Dillon regval |= (value & 0x3f) << ANT_DIV_CONTROL_ALL_S;
1742b7d5e03cSMatthew Dillon /* enable_lnadiv */
1743b7d5e03cSMatthew Dillon regval &= (~MULTICHAIN_GAIN_CTRL__ENABLE_ANT_DIV_LNADIV__MASK);
1744b7d5e03cSMatthew Dillon regval |= ((value >> 6) & 0x1) <<
1745b7d5e03cSMatthew Dillon MULTICHAIN_GAIN_CTRL__ENABLE_ANT_DIV_LNADIV__SHIFT;
1746b7d5e03cSMatthew Dillon #if ATH_ANT_DIV_COMB
1747b7d5e03cSMatthew Dillon if ( AR_SREV_POSEIDON(ah) && (ahp->ah_lna_div_use_bt_ant_enable == TRUE) ) {
1748b7d5e03cSMatthew Dillon regval |= ANT_DIV_ENABLE;
1749b7d5e03cSMatthew Dillon }
1750b7d5e03cSMatthew Dillon #endif /* ATH_ANT_DIV_COMB */
1751b7d5e03cSMatthew Dillon OS_REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval);
1752b7d5e03cSMatthew Dillon
1753b7d5e03cSMatthew Dillon /* enable fast_div */
1754b7d5e03cSMatthew Dillon regval = OS_REG_READ(ah, AR_PHY_CCK_DETECT);
1755b7d5e03cSMatthew Dillon regval &= (~BBB_SIG_DETECT__ENABLE_ANT_FAST_DIV__MASK);
1756b7d5e03cSMatthew Dillon regval |= ((value >> 7) & 0x1) <<
1757b7d5e03cSMatthew Dillon BBB_SIG_DETECT__ENABLE_ANT_FAST_DIV__SHIFT;
1758b7d5e03cSMatthew Dillon #if ATH_ANT_DIV_COMB
1759b7d5e03cSMatthew Dillon if ( AR_SREV_POSEIDON(ah) && (ahp->ah_lna_div_use_bt_ant_enable == TRUE) ) {
1760b7d5e03cSMatthew Dillon regval |= FAST_DIV_ENABLE;
1761b7d5e03cSMatthew Dillon }
1762b7d5e03cSMatthew Dillon #endif /* ATH_ANT_DIV_COMB */
1763b7d5e03cSMatthew Dillon OS_REG_WRITE(ah, AR_PHY_CCK_DETECT, regval);
1764b7d5e03cSMatthew Dillon }
1765b7d5e03cSMatthew Dillon
1766b7d5e03cSMatthew Dillon #if ATH_ANT_DIV_COMB
1767b7d5e03cSMatthew Dillon if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON_11_OR_LATER(ah)) {
1768b7d5e03cSMatthew Dillon if (pcap->halAntDivCombSupport) {
1769b7d5e03cSMatthew Dillon /* If support DivComb, set MAIN to LNA1, ALT to LNA2 at beginning */
1770b7d5e03cSMatthew Dillon regval = OS_REG_READ(ah, AR_PHY_MC_GAIN_CTRL);
1771b7d5e03cSMatthew Dillon /* clear bit 25~30 main_lnaconf, alt_lnaconf, main_tb, alt_tb */
1772b7d5e03cSMatthew Dillon regval &= (~(MULTICHAIN_GAIN_CTRL__ANT_DIV_MAIN_LNACONF__MASK |
1773b7d5e03cSMatthew Dillon MULTICHAIN_GAIN_CTRL__ANT_DIV_ALT_LNACONF__MASK |
1774b7d5e03cSMatthew Dillon MULTICHAIN_GAIN_CTRL__ANT_DIV_ALT_GAINTB__MASK |
1775b7d5e03cSMatthew Dillon MULTICHAIN_GAIN_CTRL__ANT_DIV_MAIN_GAINTB__MASK));
1776b7d5e03cSMatthew Dillon regval |= (HAL_ANT_DIV_COMB_LNA1 <<
1777b7d5e03cSMatthew Dillon MULTICHAIN_GAIN_CTRL__ANT_DIV_MAIN_LNACONF__SHIFT);
1778b7d5e03cSMatthew Dillon regval |= (HAL_ANT_DIV_COMB_LNA2 <<
1779b7d5e03cSMatthew Dillon MULTICHAIN_GAIN_CTRL__ANT_DIV_ALT_LNACONF__SHIFT);
1780b7d5e03cSMatthew Dillon OS_REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval);
1781b7d5e03cSMatthew Dillon }
1782b7d5e03cSMatthew Dillon
1783b7d5e03cSMatthew Dillon }
1784b7d5e03cSMatthew Dillon #endif /* ATH_ANT_DIV_COMB */
1785b7d5e03cSMatthew Dillon if (AR_SREV_POSEIDON(ah) && ( ahp->ah_diversity_control == HAL_ANT_FIXED_A
1786b7d5e03cSMatthew Dillon || ahp->ah_diversity_control == HAL_ANT_FIXED_B))
1787b7d5e03cSMatthew Dillon {
1788b7d5e03cSMatthew Dillon u_int32_t reg_val = OS_REG_READ(ah, AR_PHY_MC_GAIN_CTRL);
1789b7d5e03cSMatthew Dillon reg_val &= ~(MULTICHAIN_GAIN_CTRL__ANT_DIV_MAIN_LNACONF__MASK |
1790b7d5e03cSMatthew Dillon MULTICHAIN_GAIN_CTRL__ANT_DIV_ALT_LNACONF__MASK |
1791b7d5e03cSMatthew Dillon MULTICHAIN_GAIN_CTRL__ANT_FAST_DIV_BIAS__MASK |
1792b7d5e03cSMatthew Dillon MULTICHAIN_GAIN_CTRL__ANT_DIV_MAIN_GAINTB__MASK |
1793b7d5e03cSMatthew Dillon MULTICHAIN_GAIN_CTRL__ANT_DIV_ALT_GAINTB__MASK );
1794b7d5e03cSMatthew Dillon
1795b7d5e03cSMatthew Dillon switch (ahp->ah_diversity_control) {
1796b7d5e03cSMatthew Dillon case HAL_ANT_FIXED_A:
1797b7d5e03cSMatthew Dillon /* Enable first antenna only */
1798b7d5e03cSMatthew Dillon reg_val |= (HAL_ANT_DIV_COMB_LNA1 <<
1799b7d5e03cSMatthew Dillon MULTICHAIN_GAIN_CTRL__ANT_DIV_MAIN_LNACONF__SHIFT);
1800b7d5e03cSMatthew Dillon reg_val |= (HAL_ANT_DIV_COMB_LNA2 <<
1801b7d5e03cSMatthew Dillon MULTICHAIN_GAIN_CTRL__ANT_DIV_ALT_LNACONF__SHIFT);
1802b7d5e03cSMatthew Dillon /* main/alt gain table and Fast Div Bias all set to 0 */
1803b7d5e03cSMatthew Dillon OS_REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, reg_val);
1804b7d5e03cSMatthew Dillon regval = OS_REG_READ(ah, AR_PHY_CCK_DETECT);
1805b7d5e03cSMatthew Dillon regval &= (~BBB_SIG_DETECT__ENABLE_ANT_FAST_DIV__MASK);
1806b7d5e03cSMatthew Dillon OS_REG_WRITE(ah, AR_PHY_CCK_DETECT, regval);
1807b7d5e03cSMatthew Dillon break;
1808b7d5e03cSMatthew Dillon case HAL_ANT_FIXED_B:
1809b7d5e03cSMatthew Dillon /* Enable second antenna only, after checking capability */
1810b7d5e03cSMatthew Dillon reg_val |= (HAL_ANT_DIV_COMB_LNA2 <<
1811b7d5e03cSMatthew Dillon MULTICHAIN_GAIN_CTRL__ANT_DIV_MAIN_LNACONF__SHIFT);
1812b7d5e03cSMatthew Dillon reg_val |= (HAL_ANT_DIV_COMB_LNA1 <<
1813b7d5e03cSMatthew Dillon MULTICHAIN_GAIN_CTRL__ANT_DIV_ALT_LNACONF__SHIFT);
1814b7d5e03cSMatthew Dillon /* main/alt gain table and Fast Div all set to 0 */
1815b7d5e03cSMatthew Dillon OS_REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, reg_val);
1816b7d5e03cSMatthew Dillon regval = OS_REG_READ(ah, AR_PHY_CCK_DETECT);
1817b7d5e03cSMatthew Dillon regval &= (~BBB_SIG_DETECT__ENABLE_ANT_FAST_DIV__MASK);
1818b7d5e03cSMatthew Dillon OS_REG_WRITE(ah, AR_PHY_CCK_DETECT, regval);
1819b7d5e03cSMatthew Dillon /* For WB225, need to swith ANT2 from BT to Wifi
1820b7d5e03cSMatthew Dillon * This will not affect HB125 LNA diversity feature.
1821b7d5e03cSMatthew Dillon */
1822848b370cSMatthew Dillon HALDEBUG(ah, HAL_DEBUG_RESET, "%s: com2=0x%08x\n", __func__,
1823*6e17739dSzrj ah->ah_config.ath_hal_ant_ctrl_comm2g_switch_enable);
1824b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM_2, AR_SWITCH_TABLE_COM2_ALL,
1825b7d5e03cSMatthew Dillon ah->ah_config.ath_hal_ant_ctrl_comm2g_switch_enable);
1826b7d5e03cSMatthew Dillon break;
1827b7d5e03cSMatthew Dillon default:
1828b7d5e03cSMatthew Dillon break;
1829b7d5e03cSMatthew Dillon }
1830b7d5e03cSMatthew Dillon }
1831b7d5e03cSMatthew Dillon return 0;
1832b7d5e03cSMatthew Dillon }
1833b7d5e03cSMatthew Dillon
1834b7d5e03cSMatthew Dillon static u_int16_t
ar9300_attenuation_chain_get(struct ath_hal * ah,int chain,u_int16_t channel)1835b7d5e03cSMatthew Dillon ar9300_attenuation_chain_get(struct ath_hal *ah, int chain, u_int16_t channel)
1836b7d5e03cSMatthew Dillon {
1837b7d5e03cSMatthew Dillon int32_t f[3], t[3];
1838b7d5e03cSMatthew Dillon u_int16_t value;
1839b7d5e03cSMatthew Dillon ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom;
1840b7d5e03cSMatthew Dillon if (chain >= 0 && chain < OSPREY_MAX_CHAINS) {
1841b7d5e03cSMatthew Dillon if (channel < 4000) {
1842b7d5e03cSMatthew Dillon return eep->modal_header_2g.xatten1_db[chain];
1843b7d5e03cSMatthew Dillon } else {
1844b7d5e03cSMatthew Dillon if (eep->base_ext2.xatten1_db_low[chain] != 0) {
1845b7d5e03cSMatthew Dillon t[0] = eep->base_ext2.xatten1_db_low[chain];
1846b7d5e03cSMatthew Dillon f[0] = 5180;
1847b7d5e03cSMatthew Dillon t[1] = eep->modal_header_5g.xatten1_db[chain];
1848b7d5e03cSMatthew Dillon f[1] = 5500;
1849b7d5e03cSMatthew Dillon t[2] = eep->base_ext2.xatten1_db_high[chain];
1850b7d5e03cSMatthew Dillon f[2] = 5785;
1851b7d5e03cSMatthew Dillon value = interpolate(channel, f, t, 3);
1852b7d5e03cSMatthew Dillon return value;
1853b7d5e03cSMatthew Dillon } else {
1854b7d5e03cSMatthew Dillon return eep->modal_header_5g.xatten1_db[chain];
1855b7d5e03cSMatthew Dillon }
1856b7d5e03cSMatthew Dillon }
1857b7d5e03cSMatthew Dillon }
1858b7d5e03cSMatthew Dillon return 0;
1859b7d5e03cSMatthew Dillon }
1860b7d5e03cSMatthew Dillon
1861b7d5e03cSMatthew Dillon static u_int16_t
ar9300_attenuation_margin_chain_get(struct ath_hal * ah,int chain,u_int16_t channel)1862b7d5e03cSMatthew Dillon ar9300_attenuation_margin_chain_get(struct ath_hal *ah, int chain,
1863b7d5e03cSMatthew Dillon u_int16_t channel)
1864b7d5e03cSMatthew Dillon {
1865b7d5e03cSMatthew Dillon int32_t f[3], t[3];
1866b7d5e03cSMatthew Dillon u_int16_t value;
1867b7d5e03cSMatthew Dillon ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom;
1868b7d5e03cSMatthew Dillon if (chain >= 0 && chain < OSPREY_MAX_CHAINS) {
1869b7d5e03cSMatthew Dillon if (channel < 4000) {
1870b7d5e03cSMatthew Dillon return eep->modal_header_2g.xatten1_margin[chain];
1871b7d5e03cSMatthew Dillon } else {
1872b7d5e03cSMatthew Dillon if (eep->base_ext2.xatten1_margin_low[chain] != 0) {
1873b7d5e03cSMatthew Dillon t[0] = eep->base_ext2.xatten1_margin_low[chain];
1874b7d5e03cSMatthew Dillon f[0] = 5180;
1875b7d5e03cSMatthew Dillon t[1] = eep->modal_header_5g.xatten1_margin[chain];
1876b7d5e03cSMatthew Dillon f[1] = 5500;
1877b7d5e03cSMatthew Dillon t[2] = eep->base_ext2.xatten1_margin_high[chain];
1878b7d5e03cSMatthew Dillon f[2] = 5785;
1879b7d5e03cSMatthew Dillon value = interpolate(channel, f, t, 3);
1880b7d5e03cSMatthew Dillon return value;
1881b7d5e03cSMatthew Dillon } else {
1882b7d5e03cSMatthew Dillon return eep->modal_header_5g.xatten1_margin[chain];
1883b7d5e03cSMatthew Dillon }
1884b7d5e03cSMatthew Dillon }
1885b7d5e03cSMatthew Dillon }
1886b7d5e03cSMatthew Dillon return 0;
1887b7d5e03cSMatthew Dillon }
1888b7d5e03cSMatthew Dillon
1889848b370cSMatthew Dillon #if 0
1890b7d5e03cSMatthew Dillon HAL_BOOL ar9300_attenuation_apply(struct ath_hal *ah, u_int16_t channel)
1891b7d5e03cSMatthew Dillon {
1892b7d5e03cSMatthew Dillon u_int32_t value;
1893b7d5e03cSMatthew Dillon // struct ath_hal_private *ahpriv = AH_PRIVATE(ah);
1894b7d5e03cSMatthew Dillon
1895b7d5e03cSMatthew Dillon /* Test value. if 0 then attenuation is unused. Don't load anything. */
1896b7d5e03cSMatthew Dillon value = ar9300_attenuation_chain_get(ah, 0, channel);
1897b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah,
1898b7d5e03cSMatthew Dillon AR_PHY_EXT_ATTEN_CTL_0, AR_PHY_EXT_ATTEN_CTL_XATTEN1_DB, value);
1899b7d5e03cSMatthew Dillon value = ar9300_attenuation_margin_chain_get(ah, 0, channel);
1900b7d5e03cSMatthew Dillon if (ar9300_rx_gain_index_get(ah) == 0
1901b7d5e03cSMatthew Dillon && ah->ah_config.ath_hal_ext_atten_margin_cfg)
1902b7d5e03cSMatthew Dillon {
1903b7d5e03cSMatthew Dillon value = 5;
1904b7d5e03cSMatthew Dillon }
1905b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah,
1906b7d5e03cSMatthew Dillon AR_PHY_EXT_ATTEN_CTL_0, AR_PHY_EXT_ATTEN_CTL_XATTEN1_MARGIN, value);
1907b7d5e03cSMatthew Dillon
1908b7d5e03cSMatthew Dillon if (!AR_SREV_HORNET(ah) && !AR_SREV_POSEIDON(ah)) {
1909b7d5e03cSMatthew Dillon value = ar9300_attenuation_chain_get(ah, 1, channel);
1910b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah,
1911b7d5e03cSMatthew Dillon AR_PHY_EXT_ATTEN_CTL_1, AR_PHY_EXT_ATTEN_CTL_XATTEN1_DB, value);
1912b7d5e03cSMatthew Dillon value = ar9300_attenuation_margin_chain_get(ah, 1, channel);
1913b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah,
1914b7d5e03cSMatthew Dillon AR_PHY_EXT_ATTEN_CTL_1, AR_PHY_EXT_ATTEN_CTL_XATTEN1_MARGIN,
1915b7d5e03cSMatthew Dillon value);
1916a20e5e51SMatthew Dillon if (!AR_SREV_WASP(ah) && !AR_SREV_JUPITER(ah)&& !AR_SREV_HONEYBEE(ah) ) {
1917b7d5e03cSMatthew Dillon value = ar9300_attenuation_chain_get(ah, 2, channel);
1918b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah,
1919b7d5e03cSMatthew Dillon AR_PHY_EXT_ATTEN_CTL_2, AR_PHY_EXT_ATTEN_CTL_XATTEN1_DB, value);
1920b7d5e03cSMatthew Dillon value = ar9300_attenuation_margin_chain_get(ah, 2, channel);
1921b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah,
1922b7d5e03cSMatthew Dillon AR_PHY_EXT_ATTEN_CTL_2, AR_PHY_EXT_ATTEN_CTL_XATTEN1_MARGIN,
1923b7d5e03cSMatthew Dillon value);
1924b7d5e03cSMatthew Dillon }
1925b7d5e03cSMatthew Dillon }
1926b7d5e03cSMatthew Dillon return 0;
1927b7d5e03cSMatthew Dillon }
1928848b370cSMatthew Dillon #endif
1929848b370cSMatthew Dillon HAL_BOOL
ar9300_attenuation_apply(struct ath_hal * ah,u_int16_t channel)1930848b370cSMatthew Dillon ar9300_attenuation_apply(struct ath_hal *ah, u_int16_t channel)
1931848b370cSMatthew Dillon {
1932848b370cSMatthew Dillon int i;
1933848b370cSMatthew Dillon uint32_t value;
1934848b370cSMatthew Dillon uint32_t ext_atten_reg[3] = {
1935848b370cSMatthew Dillon AR_PHY_EXT_ATTEN_CTL_0,
1936848b370cSMatthew Dillon AR_PHY_EXT_ATTEN_CTL_1,
1937848b370cSMatthew Dillon AR_PHY_EXT_ATTEN_CTL_2
1938848b370cSMatthew Dillon };
1939848b370cSMatthew Dillon
1940848b370cSMatthew Dillon /*
1941848b370cSMatthew Dillon * If it's an AR9462 and we're receiving on the second
1942848b370cSMatthew Dillon * chain only, set the chain 0 details from chain 1
1943848b370cSMatthew Dillon * calibration.
1944848b370cSMatthew Dillon *
1945848b370cSMatthew Dillon * This is from ath9k.
1946848b370cSMatthew Dillon */
1947848b370cSMatthew Dillon if (AR_SREV_JUPITER(ah) && (AH9300(ah)->ah_rx_chainmask == 0x2)) {
1948848b370cSMatthew Dillon value = ar9300_attenuation_chain_get(ah, 1, channel);
1949848b370cSMatthew Dillon OS_REG_RMW_FIELD(ah, ext_atten_reg[0],
1950848b370cSMatthew Dillon AR_PHY_EXT_ATTEN_CTL_XATTEN1_DB, value);
1951848b370cSMatthew Dillon value = ar9300_attenuation_margin_chain_get(ah, 1, channel);
1952848b370cSMatthew Dillon OS_REG_RMW_FIELD(ah, ext_atten_reg[0],
1953848b370cSMatthew Dillon AR_PHY_EXT_ATTEN_CTL_XATTEN1_MARGIN, value);
1954848b370cSMatthew Dillon }
1955848b370cSMatthew Dillon
1956848b370cSMatthew Dillon /*
1957848b370cSMatthew Dillon * Now, loop over the configured transmit chains and
1958848b370cSMatthew Dillon * load in the attenuation/margin settings as appropriate.
1959848b370cSMatthew Dillon */
1960848b370cSMatthew Dillon for (i = 0; i < 3; i++) {
1961848b370cSMatthew Dillon if ((AH9300(ah)->ah_tx_chainmask & (1 << i)) == 0)
1962848b370cSMatthew Dillon continue;
1963848b370cSMatthew Dillon
1964848b370cSMatthew Dillon value = ar9300_attenuation_chain_get(ah, i, channel);
1965848b370cSMatthew Dillon OS_REG_RMW_FIELD(ah, ext_atten_reg[i],
1966848b370cSMatthew Dillon AR_PHY_EXT_ATTEN_CTL_XATTEN1_DB,
1967848b370cSMatthew Dillon value);
1968848b370cSMatthew Dillon
1969848b370cSMatthew Dillon if (AR_SREV_POSEIDON(ah) &&
1970848b370cSMatthew Dillon (ar9300_rx_gain_index_get(ah) == 0) &&
1971848b370cSMatthew Dillon ah->ah_config.ath_hal_ext_atten_margin_cfg) {
1972848b370cSMatthew Dillon value = 5;
1973848b370cSMatthew Dillon } else {
1974848b370cSMatthew Dillon value = ar9300_attenuation_margin_chain_get(ah, 0,
1975848b370cSMatthew Dillon channel);
1976848b370cSMatthew Dillon }
1977848b370cSMatthew Dillon
1978848b370cSMatthew Dillon /*
1979848b370cSMatthew Dillon * I'm not sure why it's loading in this setting into
1980848b370cSMatthew Dillon * the chain 0 margin regardless of the current chain.
1981848b370cSMatthew Dillon */
1982848b370cSMatthew Dillon if (ah->ah_config.ath_hal_min_gainidx)
1983848b370cSMatthew Dillon OS_REG_RMW_FIELD(ah,
1984848b370cSMatthew Dillon AR_PHY_EXT_ATTEN_CTL_0,
1985848b370cSMatthew Dillon AR_PHY_EXT_ATTEN_CTL_XATTEN1_MARGIN,
1986848b370cSMatthew Dillon value);
1987848b370cSMatthew Dillon
1988848b370cSMatthew Dillon OS_REG_RMW_FIELD(ah,
1989848b370cSMatthew Dillon ext_atten_reg[i],
1990848b370cSMatthew Dillon AR_PHY_EXT_ATTEN_CTL_XATTEN1_MARGIN,
1991848b370cSMatthew Dillon value);
1992848b370cSMatthew Dillon }
1993848b370cSMatthew Dillon
1994848b370cSMatthew Dillon return (0);
1995848b370cSMatthew Dillon }
1996848b370cSMatthew Dillon
1997b7d5e03cSMatthew Dillon
ar9300_quick_drop_get(struct ath_hal * ah,int chain,u_int16_t channel)1998b7d5e03cSMatthew Dillon static u_int16_t ar9300_quick_drop_get(struct ath_hal *ah,
1999b7d5e03cSMatthew Dillon int chain, u_int16_t channel)
2000b7d5e03cSMatthew Dillon {
2001b7d5e03cSMatthew Dillon int32_t f[3], t[3];
2002b7d5e03cSMatthew Dillon u_int16_t value;
2003b7d5e03cSMatthew Dillon ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom;
2004b7d5e03cSMatthew Dillon
2005b7d5e03cSMatthew Dillon if (channel < 4000) {
2006b7d5e03cSMatthew Dillon return eep->modal_header_2g.quick_drop;
2007b7d5e03cSMatthew Dillon } else {
2008b7d5e03cSMatthew Dillon t[0] = eep->base_ext1.quick_drop_low;
2009b7d5e03cSMatthew Dillon f[0] = 5180;
2010b7d5e03cSMatthew Dillon t[1] = eep->modal_header_5g.quick_drop;
2011b7d5e03cSMatthew Dillon f[1] = 5500;
2012b7d5e03cSMatthew Dillon t[2] = eep->base_ext1.quick_drop_high;
2013b7d5e03cSMatthew Dillon f[2] = 5785;
2014b7d5e03cSMatthew Dillon value = interpolate(channel, f, t, 3);
2015b7d5e03cSMatthew Dillon return value;
2016b7d5e03cSMatthew Dillon }
2017b7d5e03cSMatthew Dillon }
2018b7d5e03cSMatthew Dillon
2019b7d5e03cSMatthew Dillon
ar9300_quick_drop_apply(struct ath_hal * ah,u_int16_t channel)2020b7d5e03cSMatthew Dillon static HAL_BOOL ar9300_quick_drop_apply(struct ath_hal *ah, u_int16_t channel)
2021b7d5e03cSMatthew Dillon {
2022b7d5e03cSMatthew Dillon ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom;
2023b7d5e03cSMatthew Dillon u_int32_t value;
2024b7d5e03cSMatthew Dillon //
2025b7d5e03cSMatthew Dillon // Test value. if 0 then quickDrop is unused. Don't load anything.
2026b7d5e03cSMatthew Dillon //
2027b7d5e03cSMatthew Dillon if (eep->base_eep_header.misc_configuration & 0x10)
2028b7d5e03cSMatthew Dillon {
2029b7d5e03cSMatthew Dillon if (AR_SREV_OSPREY(ah) || AR_SREV_AR9580(ah) || AR_SREV_WASP(ah))
2030b7d5e03cSMatthew Dillon {
2031b7d5e03cSMatthew Dillon value = ar9300_quick_drop_get(ah, 0, channel);
2032b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah, AR_PHY_AGC, AR_PHY_AGC_QUICK_DROP, value);
2033b7d5e03cSMatthew Dillon }
2034b7d5e03cSMatthew Dillon }
2035b7d5e03cSMatthew Dillon return 0;
2036b7d5e03cSMatthew Dillon }
2037b7d5e03cSMatthew Dillon
ar9300_tx_end_to_xpa_off_get(struct ath_hal * ah,u_int16_t channel)2038b7d5e03cSMatthew Dillon static u_int16_t ar9300_tx_end_to_xpa_off_get(struct ath_hal *ah, u_int16_t channel)
2039b7d5e03cSMatthew Dillon {
2040b7d5e03cSMatthew Dillon ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom;
2041b7d5e03cSMatthew Dillon
2042b7d5e03cSMatthew Dillon if (channel < 4000) {
2043b7d5e03cSMatthew Dillon return eep->modal_header_2g.tx_end_to_xpa_off;
2044b7d5e03cSMatthew Dillon } else {
2045b7d5e03cSMatthew Dillon return eep->modal_header_5g.tx_end_to_xpa_off;
2046b7d5e03cSMatthew Dillon }
2047b7d5e03cSMatthew Dillon }
2048b7d5e03cSMatthew Dillon
ar9300_tx_end_to_xpab_off_apply(struct ath_hal * ah,u_int16_t channel)2049b7d5e03cSMatthew Dillon static HAL_BOOL ar9300_tx_end_to_xpab_off_apply(struct ath_hal *ah, u_int16_t channel)
2050b7d5e03cSMatthew Dillon {
2051b7d5e03cSMatthew Dillon u_int32_t value;
2052b7d5e03cSMatthew Dillon
2053b7d5e03cSMatthew Dillon value = ar9300_tx_end_to_xpa_off_get(ah, channel);
2054b7d5e03cSMatthew Dillon /* Apply to both xpaa and xpab */
2055b7d5e03cSMatthew Dillon if (AR_SREV_OSPREY(ah) || AR_SREV_AR9580(ah) || AR_SREV_WASP(ah))
2056b7d5e03cSMatthew Dillon {
2057b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah, AR_PHY_XPA_TIMING_CTL,
2058b7d5e03cSMatthew Dillon AR_PHY_XPA_TIMING_CTL_TX_END_XPAB_OFF, value);
2059b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah, AR_PHY_XPA_TIMING_CTL,
2060b7d5e03cSMatthew Dillon AR_PHY_XPA_TIMING_CTL_TX_END_XPAA_OFF, value);
2061b7d5e03cSMatthew Dillon }
2062b7d5e03cSMatthew Dillon return 0;
2063b7d5e03cSMatthew Dillon }
2064b7d5e03cSMatthew Dillon
2065b7d5e03cSMatthew Dillon 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)2066b7d5e03cSMatthew Dillon ar9300_eeprom_cal_pier_get(struct ath_hal *ah, int mode, int ipier, int ichain,
2067b7d5e03cSMatthew Dillon int *pfrequency, int *pcorrection, int *ptemperature, int *pvoltage)
2068b7d5e03cSMatthew Dillon {
2069b7d5e03cSMatthew Dillon u_int8_t *p_cal_pier;
2070b7d5e03cSMatthew Dillon OSP_CAL_DATA_PER_FREQ_OP_LOOP *p_cal_pier_struct;
2071b7d5e03cSMatthew Dillon int is_2ghz;
2072b7d5e03cSMatthew Dillon ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom;
2073b7d5e03cSMatthew Dillon
2074b7d5e03cSMatthew Dillon if (ichain >= OSPREY_MAX_CHAINS) {
2075b7d5e03cSMatthew Dillon HALDEBUG(ah, HAL_DEBUG_EEPROM,
2076b7d5e03cSMatthew Dillon "%s: Invalid chain index, must be less than %d\n",
2077b7d5e03cSMatthew Dillon __func__, OSPREY_MAX_CHAINS);
2078b7d5e03cSMatthew Dillon return -1;
2079b7d5e03cSMatthew Dillon }
2080b7d5e03cSMatthew Dillon
2081b7d5e03cSMatthew Dillon if (mode) {/* 5GHz */
2082b7d5e03cSMatthew Dillon if (ipier >= OSPREY_NUM_5G_CAL_PIERS){
2083b7d5e03cSMatthew Dillon HALDEBUG(ah, HAL_DEBUG_EEPROM,
2084b7d5e03cSMatthew Dillon "%s: Invalid 5GHz cal pier index, must be less than %d\n",
2085b7d5e03cSMatthew Dillon __func__, OSPREY_NUM_5G_CAL_PIERS);
2086b7d5e03cSMatthew Dillon return -1;
2087b7d5e03cSMatthew Dillon }
2088b7d5e03cSMatthew Dillon p_cal_pier = &(eep->cal_freq_pier_5g[ipier]);
2089b7d5e03cSMatthew Dillon p_cal_pier_struct = &(eep->cal_pier_data_5g[ichain][ipier]);
2090b7d5e03cSMatthew Dillon is_2ghz = 0;
2091b7d5e03cSMatthew Dillon } else {
2092b7d5e03cSMatthew Dillon if (ipier >= OSPREY_NUM_2G_CAL_PIERS){
2093b7d5e03cSMatthew Dillon HALDEBUG(ah, HAL_DEBUG_EEPROM,
2094b7d5e03cSMatthew Dillon "%s: Invalid 2GHz cal pier index, must be less than %d\n",
2095b7d5e03cSMatthew Dillon __func__, OSPREY_NUM_2G_CAL_PIERS);
2096b7d5e03cSMatthew Dillon return -1;
2097b7d5e03cSMatthew Dillon }
2098b7d5e03cSMatthew Dillon
2099b7d5e03cSMatthew Dillon p_cal_pier = &(eep->cal_freq_pier_2g[ipier]);
2100b7d5e03cSMatthew Dillon p_cal_pier_struct = &(eep->cal_pier_data_2g[ichain][ipier]);
2101b7d5e03cSMatthew Dillon is_2ghz = 1;
2102b7d5e03cSMatthew Dillon }
2103b7d5e03cSMatthew Dillon *pfrequency = FBIN2FREQ(*p_cal_pier, is_2ghz);
2104b7d5e03cSMatthew Dillon *pcorrection = p_cal_pier_struct->ref_power;
2105b7d5e03cSMatthew Dillon *ptemperature = p_cal_pier_struct->temp_meas;
2106b7d5e03cSMatthew Dillon *pvoltage = p_cal_pier_struct->volt_meas;
2107b7d5e03cSMatthew Dillon return 0;
2108b7d5e03cSMatthew Dillon }
2109b7d5e03cSMatthew Dillon
2110b7d5e03cSMatthew Dillon /*
2111b7d5e03cSMatthew Dillon * Apply the recorded correction values.
2112b7d5e03cSMatthew Dillon */
2113b7d5e03cSMatthew Dillon static int
ar9300_calibration_apply(struct ath_hal * ah,int frequency)2114b7d5e03cSMatthew Dillon ar9300_calibration_apply(struct ath_hal *ah, int frequency)
2115b7d5e03cSMatthew Dillon {
2116b7d5e03cSMatthew Dillon struct ath_hal_9300 *ahp = AH9300(ah);
2117b7d5e03cSMatthew Dillon
2118b7d5e03cSMatthew Dillon int ichain, ipier, npier;
2119b7d5e03cSMatthew Dillon int mode;
2120b7d5e03cSMatthew Dillon int fdiff;
2121b7d5e03cSMatthew Dillon int pfrequency, pcorrection, ptemperature, pvoltage;
2122b7d5e03cSMatthew Dillon int bf, factor, plus;
2123b7d5e03cSMatthew Dillon
2124b7d5e03cSMatthew Dillon int lfrequency[AR9300_MAX_CHAINS];
2125b7d5e03cSMatthew Dillon int hfrequency[AR9300_MAX_CHAINS];
2126b7d5e03cSMatthew Dillon
2127b7d5e03cSMatthew Dillon int lcorrection[AR9300_MAX_CHAINS];
2128b7d5e03cSMatthew Dillon int hcorrection[AR9300_MAX_CHAINS];
2129b7d5e03cSMatthew Dillon int correction[AR9300_MAX_CHAINS];
2130b7d5e03cSMatthew Dillon
2131b7d5e03cSMatthew Dillon int ltemperature[AR9300_MAX_CHAINS];
2132b7d5e03cSMatthew Dillon int htemperature[AR9300_MAX_CHAINS];
2133b7d5e03cSMatthew Dillon int temperature[AR9300_MAX_CHAINS];
2134b7d5e03cSMatthew Dillon
2135b7d5e03cSMatthew Dillon int lvoltage[AR9300_MAX_CHAINS];
2136b7d5e03cSMatthew Dillon int hvoltage[AR9300_MAX_CHAINS];
2137b7d5e03cSMatthew Dillon int voltage[AR9300_MAX_CHAINS];
2138b7d5e03cSMatthew Dillon
2139b7d5e03cSMatthew Dillon mode = (frequency >= 4000);
2140b7d5e03cSMatthew Dillon npier = (mode) ? OSPREY_NUM_5G_CAL_PIERS : OSPREY_NUM_2G_CAL_PIERS;
2141b7d5e03cSMatthew Dillon
2142b7d5e03cSMatthew Dillon for (ichain = 0; ichain < AR9300_MAX_CHAINS; ichain++) {
2143b7d5e03cSMatthew Dillon lfrequency[ichain] = 0;
2144b7d5e03cSMatthew Dillon hfrequency[ichain] = 100000;
2145b7d5e03cSMatthew Dillon }
2146b7d5e03cSMatthew Dillon /*
2147b7d5e03cSMatthew Dillon * identify best lower and higher frequency calibration measurement
2148b7d5e03cSMatthew Dillon */
2149b7d5e03cSMatthew Dillon for (ichain = 0; ichain < AR9300_MAX_CHAINS; ichain++) {
2150b7d5e03cSMatthew Dillon for (ipier = 0; ipier < npier; ipier++) {
2151b7d5e03cSMatthew Dillon if (ar9300_eeprom_cal_pier_get(
2152b7d5e03cSMatthew Dillon ah, mode, ipier, ichain,
2153b7d5e03cSMatthew Dillon &pfrequency, &pcorrection, &ptemperature, &pvoltage) == 0)
2154b7d5e03cSMatthew Dillon {
2155b7d5e03cSMatthew Dillon fdiff = frequency - pfrequency;
2156b7d5e03cSMatthew Dillon /*
2157b7d5e03cSMatthew Dillon * this measurement is higher than our desired frequency
2158b7d5e03cSMatthew Dillon */
2159b7d5e03cSMatthew Dillon if (fdiff <= 0) {
2160b7d5e03cSMatthew Dillon if (hfrequency[ichain] <= 0 ||
2161b7d5e03cSMatthew Dillon hfrequency[ichain] >= 100000 ||
2162b7d5e03cSMatthew Dillon fdiff > (frequency - hfrequency[ichain]))
2163b7d5e03cSMatthew Dillon {
2164b7d5e03cSMatthew Dillon /*
2165b7d5e03cSMatthew Dillon * new best higher frequency measurement
2166b7d5e03cSMatthew Dillon */
2167b7d5e03cSMatthew Dillon hfrequency[ichain] = pfrequency;
2168b7d5e03cSMatthew Dillon hcorrection[ichain] = pcorrection;
2169b7d5e03cSMatthew Dillon htemperature[ichain] = ptemperature;
2170b7d5e03cSMatthew Dillon hvoltage[ichain] = pvoltage;
2171b7d5e03cSMatthew Dillon }
2172b7d5e03cSMatthew Dillon }
2173b7d5e03cSMatthew Dillon if (fdiff >= 0) {
2174b7d5e03cSMatthew Dillon if (lfrequency[ichain] <= 0 ||
2175b7d5e03cSMatthew Dillon fdiff < (frequency - lfrequency[ichain]))
2176b7d5e03cSMatthew Dillon {
2177b7d5e03cSMatthew Dillon /*
2178b7d5e03cSMatthew Dillon * new best lower frequency measurement
2179b7d5e03cSMatthew Dillon */
2180b7d5e03cSMatthew Dillon lfrequency[ichain] = pfrequency;
2181b7d5e03cSMatthew Dillon lcorrection[ichain] = pcorrection;
2182b7d5e03cSMatthew Dillon ltemperature[ichain] = ptemperature;
2183b7d5e03cSMatthew Dillon lvoltage[ichain] = pvoltage;
2184b7d5e03cSMatthew Dillon }
2185b7d5e03cSMatthew Dillon }
2186b7d5e03cSMatthew Dillon }
2187b7d5e03cSMatthew Dillon }
2188b7d5e03cSMatthew Dillon }
2189b7d5e03cSMatthew Dillon /* interpolate */
2190b7d5e03cSMatthew Dillon for (ichain = 0; ichain < AR9300_MAX_CHAINS; ichain++) {
2191b7d5e03cSMatthew Dillon HALDEBUG(ah, HAL_DEBUG_EEPROM,
2192b7d5e03cSMatthew Dillon "%s: ch=%d f=%d low=%d %d h=%d %d\n",
2193b7d5e03cSMatthew Dillon __func__, ichain, frequency,
2194b7d5e03cSMatthew Dillon lfrequency[ichain], lcorrection[ichain],
2195b7d5e03cSMatthew Dillon hfrequency[ichain], hcorrection[ichain]);
2196b7d5e03cSMatthew Dillon /*
2197b7d5e03cSMatthew Dillon * they're the same, so just pick one
2198b7d5e03cSMatthew Dillon */
2199b7d5e03cSMatthew Dillon if (hfrequency[ichain] == lfrequency[ichain]) {
2200b7d5e03cSMatthew Dillon correction[ichain] = lcorrection[ichain];
2201b7d5e03cSMatthew Dillon voltage[ichain] = lvoltage[ichain];
2202b7d5e03cSMatthew Dillon temperature[ichain] = ltemperature[ichain];
2203b7d5e03cSMatthew Dillon } else if (frequency - lfrequency[ichain] < 1000) {
2204b7d5e03cSMatthew Dillon /* the low frequency is good */
2205b7d5e03cSMatthew Dillon if (hfrequency[ichain] - frequency < 1000) {
2206b7d5e03cSMatthew Dillon /*
2207b7d5e03cSMatthew Dillon * The high frequency is good too -
2208b7d5e03cSMatthew Dillon * interpolate with round off.
2209b7d5e03cSMatthew Dillon */
2210b7d5e03cSMatthew Dillon int mult, div, diff;
2211b7d5e03cSMatthew Dillon mult = frequency - lfrequency[ichain];
2212b7d5e03cSMatthew Dillon div = hfrequency[ichain] - lfrequency[ichain];
2213b7d5e03cSMatthew Dillon
2214b7d5e03cSMatthew Dillon diff = hcorrection[ichain] - lcorrection[ichain];
2215b7d5e03cSMatthew Dillon bf = 2 * diff * mult / div;
2216b7d5e03cSMatthew Dillon plus = (bf % 2);
2217b7d5e03cSMatthew Dillon factor = bf / 2;
2218b7d5e03cSMatthew Dillon correction[ichain] = lcorrection[ichain] + factor + plus;
2219b7d5e03cSMatthew Dillon
2220b7d5e03cSMatthew Dillon diff = htemperature[ichain] - ltemperature[ichain];
2221b7d5e03cSMatthew Dillon bf = 2 * diff * mult / div;
2222b7d5e03cSMatthew Dillon plus = (bf % 2);
2223b7d5e03cSMatthew Dillon factor = bf / 2;
2224b7d5e03cSMatthew Dillon temperature[ichain] = ltemperature[ichain] + factor + plus;
2225b7d5e03cSMatthew Dillon
2226b7d5e03cSMatthew Dillon diff = hvoltage[ichain] - lvoltage[ichain];
2227b7d5e03cSMatthew Dillon bf = 2 * diff * mult / div;
2228b7d5e03cSMatthew Dillon plus = (bf % 2);
2229b7d5e03cSMatthew Dillon factor = bf / 2;
2230b7d5e03cSMatthew Dillon voltage[ichain] = lvoltage[ichain] + factor + plus;
2231b7d5e03cSMatthew Dillon } else {
2232b7d5e03cSMatthew Dillon /* only low is good, use it */
2233b7d5e03cSMatthew Dillon correction[ichain] = lcorrection[ichain];
2234b7d5e03cSMatthew Dillon temperature[ichain] = ltemperature[ichain];
2235b7d5e03cSMatthew Dillon voltage[ichain] = lvoltage[ichain];
2236b7d5e03cSMatthew Dillon }
2237b7d5e03cSMatthew Dillon } else if (hfrequency[ichain] - frequency < 1000) {
2238b7d5e03cSMatthew Dillon /* only high is good, use it */
2239b7d5e03cSMatthew Dillon correction[ichain] = hcorrection[ichain];
2240b7d5e03cSMatthew Dillon temperature[ichain] = htemperature[ichain];
2241b7d5e03cSMatthew Dillon voltage[ichain] = hvoltage[ichain];
2242b7d5e03cSMatthew Dillon } else {
2243b7d5e03cSMatthew Dillon /* nothing is good, presume 0???? */
2244b7d5e03cSMatthew Dillon correction[ichain] = 0;
2245b7d5e03cSMatthew Dillon temperature[ichain] = 0;
2246b7d5e03cSMatthew Dillon voltage[ichain] = 0;
2247b7d5e03cSMatthew Dillon }
2248b7d5e03cSMatthew Dillon }
2249b7d5e03cSMatthew Dillon
2250b7d5e03cSMatthew Dillon /* GreenTx isn't currently supported */
2251b7d5e03cSMatthew Dillon /* GreenTx */
2252b7d5e03cSMatthew Dillon if (ah->ah_config.ath_hal_sta_update_tx_pwr_enable) {
2253b7d5e03cSMatthew Dillon if (AR_SREV_POSEIDON(ah)) {
2254b7d5e03cSMatthew Dillon /* Get calibrated OLPC gain delta value for GreenTx */
2255b7d5e03cSMatthew Dillon ahp->ah_db2[POSEIDON_STORED_REG_G2_OLPC_OFFSET] =
2256b7d5e03cSMatthew Dillon (u_int32_t) correction[0];
2257b7d5e03cSMatthew Dillon }
2258b7d5e03cSMatthew Dillon }
2259b7d5e03cSMatthew Dillon
2260b7d5e03cSMatthew Dillon ar9300_power_control_override(
2261b7d5e03cSMatthew Dillon ah, frequency, correction, voltage, temperature);
2262b7d5e03cSMatthew Dillon HALDEBUG(ah, HAL_DEBUG_EEPROM,
2263b7d5e03cSMatthew Dillon "%s: for frequency=%d, calibration correction = %d %d %d\n",
2264b7d5e03cSMatthew Dillon __func__, frequency, correction[0], correction[1], correction[2]);
2265b7d5e03cSMatthew Dillon
2266b7d5e03cSMatthew Dillon return 0;
2267b7d5e03cSMatthew Dillon }
2268b7d5e03cSMatthew Dillon
2269b7d5e03cSMatthew Dillon int
ar9300_power_control_override(struct ath_hal * ah,int frequency,int * correction,int * voltage,int * temperature)2270b7d5e03cSMatthew Dillon ar9300_power_control_override(struct ath_hal *ah, int frequency,
2271b7d5e03cSMatthew Dillon int *correction, int *voltage, int *temperature)
2272b7d5e03cSMatthew Dillon {
2273b7d5e03cSMatthew Dillon int temp_slope = 0;
2274b7d5e03cSMatthew Dillon int temp_slope_1 = 0;
2275b7d5e03cSMatthew Dillon int temp_slope_2 = 0;
2276b7d5e03cSMatthew Dillon ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom;
2277b7d5e03cSMatthew Dillon int32_t f[8], t[8],t1[3], t2[3];
2278b7d5e03cSMatthew Dillon int i;
2279b7d5e03cSMatthew Dillon
2280b7d5e03cSMatthew Dillon OS_REG_RMW(ah, AR_PHY_TPC_11_B0,
2281b7d5e03cSMatthew Dillon (correction[0] << AR_PHY_TPC_OLPC_GAIN_DELTA_S),
2282b7d5e03cSMatthew Dillon AR_PHY_TPC_OLPC_GAIN_DELTA);
2283b7d5e03cSMatthew Dillon if (!AR_SREV_POSEIDON(ah)) {
2284b7d5e03cSMatthew Dillon OS_REG_RMW(ah, AR_PHY_TPC_11_B1,
2285b7d5e03cSMatthew Dillon (correction[1] << AR_PHY_TPC_OLPC_GAIN_DELTA_S),
2286b7d5e03cSMatthew Dillon AR_PHY_TPC_OLPC_GAIN_DELTA);
2287a20e5e51SMatthew Dillon if (!AR_SREV_WASP(ah) && !AR_SREV_JUPITER(ah) && !AR_SREV_HONEYBEE(ah) ) {
2288b7d5e03cSMatthew Dillon OS_REG_RMW(ah, AR_PHY_TPC_11_B2,
2289b7d5e03cSMatthew Dillon (correction[2] << AR_PHY_TPC_OLPC_GAIN_DELTA_S),
2290b7d5e03cSMatthew Dillon AR_PHY_TPC_OLPC_GAIN_DELTA);
2291b7d5e03cSMatthew Dillon }
2292b7d5e03cSMatthew Dillon }
2293b7d5e03cSMatthew Dillon /*
2294b7d5e03cSMatthew Dillon * enable open loop power control on chip
2295b7d5e03cSMatthew Dillon */
2296b7d5e03cSMatthew Dillon OS_REG_RMW(ah, AR_PHY_TPC_6_B0,
2297b7d5e03cSMatthew Dillon (3 << AR_PHY_TPC_6_ERROR_EST_MODE_S), AR_PHY_TPC_6_ERROR_EST_MODE);
2298b7d5e03cSMatthew Dillon if (!AR_SREV_POSEIDON(ah)) {
2299b7d5e03cSMatthew Dillon OS_REG_RMW(ah, AR_PHY_TPC_6_B1,
2300b7d5e03cSMatthew Dillon (3 << AR_PHY_TPC_6_ERROR_EST_MODE_S), AR_PHY_TPC_6_ERROR_EST_MODE);
2301a20e5e51SMatthew Dillon if (!AR_SREV_WASP(ah) && !AR_SREV_JUPITER(ah) && !AR_SREV_HONEYBEE(ah) ) {
2302b7d5e03cSMatthew Dillon OS_REG_RMW(ah, AR_PHY_TPC_6_B2,
2303b7d5e03cSMatthew Dillon (3 << AR_PHY_TPC_6_ERROR_EST_MODE_S),
2304b7d5e03cSMatthew Dillon AR_PHY_TPC_6_ERROR_EST_MODE);
2305b7d5e03cSMatthew Dillon }
2306b7d5e03cSMatthew Dillon }
2307b7d5e03cSMatthew Dillon
2308b7d5e03cSMatthew Dillon /*
2309b7d5e03cSMatthew Dillon * Enable temperature compensation
2310b7d5e03cSMatthew Dillon * Need to use register names
2311b7d5e03cSMatthew Dillon */
2312b7d5e03cSMatthew Dillon if (frequency < 4000) {
2313b7d5e03cSMatthew Dillon temp_slope = eep->modal_header_2g.temp_slope;
2314b7d5e03cSMatthew Dillon } else {
2315b7d5e03cSMatthew Dillon if ((eep->base_eep_header.misc_configuration & 0x20) != 0)
2316b7d5e03cSMatthew Dillon {
2317b7d5e03cSMatthew Dillon for(i=0;i<8;i++)
2318b7d5e03cSMatthew Dillon {
2319b7d5e03cSMatthew Dillon t[i]=eep->base_ext1.tempslopextension[i];
2320b7d5e03cSMatthew Dillon f[i]=FBIN2FREQ(eep->cal_freq_pier_5g[i], 0);
2321b7d5e03cSMatthew Dillon }
2322b7d5e03cSMatthew Dillon temp_slope=interpolate(frequency,f,t,8);
2323b7d5e03cSMatthew Dillon }
2324b7d5e03cSMatthew Dillon else
2325b7d5e03cSMatthew Dillon {
2326b7d5e03cSMatthew Dillon if(!AR_SREV_SCORPION(ah)) {
2327b7d5e03cSMatthew Dillon if (eep->base_ext2.temp_slope_low != 0) {
2328b7d5e03cSMatthew Dillon t[0] = eep->base_ext2.temp_slope_low;
2329b7d5e03cSMatthew Dillon f[0] = 5180;
2330b7d5e03cSMatthew Dillon t[1] = eep->modal_header_5g.temp_slope;
2331b7d5e03cSMatthew Dillon f[1] = 5500;
2332b7d5e03cSMatthew Dillon t[2] = eep->base_ext2.temp_slope_high;
2333b7d5e03cSMatthew Dillon f[2] = 5785;
2334b7d5e03cSMatthew Dillon temp_slope = interpolate(frequency, f, t, 3);
2335b7d5e03cSMatthew Dillon } else {
2336b7d5e03cSMatthew Dillon temp_slope = eep->modal_header_5g.temp_slope;
2337b7d5e03cSMatthew Dillon }
2338b7d5e03cSMatthew Dillon } else {
2339b7d5e03cSMatthew Dillon /*
2340b7d5e03cSMatthew Dillon * Scorpion has individual chain tempslope values
2341b7d5e03cSMatthew Dillon */
2342b7d5e03cSMatthew Dillon t[0] = eep->base_ext1.tempslopextension[2];
2343b7d5e03cSMatthew Dillon t1[0]= eep->base_ext1.tempslopextension[3];
2344b7d5e03cSMatthew Dillon t2[0]= eep->base_ext1.tempslopextension[4];
2345b7d5e03cSMatthew Dillon f[0] = 5180;
2346b7d5e03cSMatthew Dillon t[1] = eep->modal_header_5g.temp_slope;
2347b7d5e03cSMatthew Dillon t1[1]= eep->base_ext1.tempslopextension[0];
2348b7d5e03cSMatthew Dillon t2[1]= eep->base_ext1.tempslopextension[1];
2349b7d5e03cSMatthew Dillon f[1] = 5500;
2350b7d5e03cSMatthew Dillon t[2] = eep->base_ext1.tempslopextension[5];
2351b7d5e03cSMatthew Dillon t1[2]= eep->base_ext1.tempslopextension[6];
2352b7d5e03cSMatthew Dillon t2[2]= eep->base_ext1.tempslopextension[7];
2353b7d5e03cSMatthew Dillon f[2] = 5785;
2354b7d5e03cSMatthew Dillon temp_slope = interpolate(frequency, f, t, 3);
2355b7d5e03cSMatthew Dillon temp_slope_1=interpolate(frequency, f, t1,3);
2356b7d5e03cSMatthew Dillon temp_slope_2=interpolate(frequency, f, t2,3);
2357b7d5e03cSMatthew Dillon }
2358b7d5e03cSMatthew Dillon }
2359b7d5e03cSMatthew Dillon }
2360b7d5e03cSMatthew Dillon
2361a20e5e51SMatthew Dillon if (!AR_SREV_SCORPION(ah) && !AR_SREV_HONEYBEE(ah)) {
2362b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah,
2363b7d5e03cSMatthew Dillon AR_PHY_TPC_19, AR_PHY_TPC_19_ALPHA_THERM, temp_slope);
2364b7d5e03cSMatthew Dillon } else {
2365a20e5e51SMatthew Dillon /*Scorpion and Honeybee has tempSlope register for each chain*/
2366b7d5e03cSMatthew Dillon /*Check whether temp_compensation feature is enabled or not*/
2367b7d5e03cSMatthew Dillon if (eep->base_eep_header.feature_enable & 0x1){
2368b7d5e03cSMatthew Dillon if(frequency < 4000) {
2369a20e5e51SMatthew Dillon if (((eep->base_eep_header.txrx_mask & 0xf0) >> 4) & 0x1) {
2370b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah,
2371b7d5e03cSMatthew Dillon AR_PHY_TPC_19, AR_PHY_TPC_19_ALPHA_THERM,
2372b7d5e03cSMatthew Dillon eep->base_ext2.temp_slope_low);
2373a20e5e51SMatthew Dillon }
2374a20e5e51SMatthew Dillon if (((eep->base_eep_header.txrx_mask & 0xf0) >> 4) & 0x2) {
2375b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah,
2376b7d5e03cSMatthew Dillon AR_SCORPION_PHY_TPC_19_B1, AR_PHY_TPC_19_ALPHA_THERM,
2377b7d5e03cSMatthew Dillon temp_slope);
2378a20e5e51SMatthew Dillon }
2379a20e5e51SMatthew Dillon if (((eep->base_eep_header.txrx_mask & 0xf0) >> 4) & 0x4) {
2380b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah,
2381b7d5e03cSMatthew Dillon AR_SCORPION_PHY_TPC_19_B2, AR_PHY_TPC_19_ALPHA_THERM,
2382b7d5e03cSMatthew Dillon eep->base_ext2.temp_slope_high);
2383a20e5e51SMatthew Dillon }
2384b7d5e03cSMatthew Dillon } else {
2385a20e5e51SMatthew Dillon if (((eep->base_eep_header.txrx_mask & 0xf0) >> 4) & 0x1) {
2386b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah,
2387b7d5e03cSMatthew Dillon AR_PHY_TPC_19, AR_PHY_TPC_19_ALPHA_THERM,
2388b7d5e03cSMatthew Dillon temp_slope);
2389a20e5e51SMatthew Dillon }
2390a20e5e51SMatthew Dillon if (((eep->base_eep_header.txrx_mask & 0xf0) >> 4) & 0x2) {
2391b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah,
2392b7d5e03cSMatthew Dillon AR_SCORPION_PHY_TPC_19_B1, AR_PHY_TPC_19_ALPHA_THERM,
2393b7d5e03cSMatthew Dillon temp_slope_1);
2394a20e5e51SMatthew Dillon }
2395a20e5e51SMatthew Dillon if (((eep->base_eep_header.txrx_mask & 0xf0) >> 4) & 0x4) {
2396b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah,
2397b7d5e03cSMatthew Dillon AR_SCORPION_PHY_TPC_19_B2, AR_PHY_TPC_19_ALPHA_THERM,
2398b7d5e03cSMatthew Dillon temp_slope_2);
2399b7d5e03cSMatthew Dillon }
2400a20e5e51SMatthew Dillon }
2401b7d5e03cSMatthew Dillon }else {
2402b7d5e03cSMatthew Dillon /* If temp compensation is not enabled, set all registers to 0*/
2403a20e5e51SMatthew Dillon if (((eep->base_eep_header.txrx_mask & 0xf0) >> 4) & 0x1) {
2404b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah,
2405b7d5e03cSMatthew Dillon AR_PHY_TPC_19, AR_PHY_TPC_19_ALPHA_THERM, 0);
2406a20e5e51SMatthew Dillon }
2407a20e5e51SMatthew Dillon if (((eep->base_eep_header.txrx_mask & 0xf0) >> 4) & 0x2) {
2408b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah,
2409b7d5e03cSMatthew Dillon AR_SCORPION_PHY_TPC_19_B1, AR_PHY_TPC_19_ALPHA_THERM, 0);
2410a20e5e51SMatthew Dillon }
2411a20e5e51SMatthew Dillon if (((eep->base_eep_header.txrx_mask & 0xf0) >> 4) & 0x4) {
2412b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah,
2413b7d5e03cSMatthew Dillon AR_SCORPION_PHY_TPC_19_B2, AR_PHY_TPC_19_ALPHA_THERM, 0);
2414b7d5e03cSMatthew Dillon }
2415b7d5e03cSMatthew Dillon }
2416a20e5e51SMatthew Dillon }
2417b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah,
2418b7d5e03cSMatthew Dillon AR_PHY_TPC_18, AR_PHY_TPC_18_THERM_CAL_VALUE, temperature[0]);
2419b7d5e03cSMatthew Dillon
2420b7d5e03cSMatthew Dillon return 0;
2421b7d5e03cSMatthew Dillon }
2422b7d5e03cSMatthew Dillon
2423b7d5e03cSMatthew Dillon /**************************************************************
2424b7d5e03cSMatthew Dillon * ar9300_eep_def_get_max_edge_power
2425b7d5e03cSMatthew Dillon *
2426b7d5e03cSMatthew Dillon * Find the maximum conformance test limit for the given channel and CTL info
2427b7d5e03cSMatthew Dillon */
2428b7d5e03cSMatthew Dillon 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)2429b7d5e03cSMatthew Dillon ar9300_eep_def_get_max_edge_power(ar9300_eeprom_t *p_eep_data, u_int16_t freq,
2430b7d5e03cSMatthew Dillon int idx, HAL_BOOL is_2ghz)
2431b7d5e03cSMatthew Dillon {
2432b7d5e03cSMatthew Dillon u_int16_t twice_max_edge_power = AR9300_MAX_RATE_POWER;
2433b7d5e03cSMatthew Dillon u_int8_t *ctl_freqbin = is_2ghz ?
2434b7d5e03cSMatthew Dillon &p_eep_data->ctl_freqbin_2G[idx][0] :
2435b7d5e03cSMatthew Dillon &p_eep_data->ctl_freqbin_5G[idx][0];
2436b7d5e03cSMatthew Dillon u_int16_t num_edges = is_2ghz ?
2437b7d5e03cSMatthew Dillon OSPREY_NUM_BAND_EDGES_2G : OSPREY_NUM_BAND_EDGES_5G;
2438b7d5e03cSMatthew Dillon int i;
2439b7d5e03cSMatthew Dillon
2440b7d5e03cSMatthew Dillon /* Get the edge power */
2441b7d5e03cSMatthew Dillon for (i = 0; (i < num_edges) && (ctl_freqbin[i] != AR9300_BCHAN_UNUSED); i++)
2442b7d5e03cSMatthew Dillon {
2443b7d5e03cSMatthew Dillon /*
2444b7d5e03cSMatthew Dillon * If there's an exact channel match or an inband flag set
2445b7d5e03cSMatthew Dillon * on the lower channel use the given rd_edge_power
2446b7d5e03cSMatthew Dillon */
2447b7d5e03cSMatthew Dillon if (freq == fbin2freq(ctl_freqbin[i], is_2ghz)) {
2448b7d5e03cSMatthew Dillon if (is_2ghz) {
2449b7d5e03cSMatthew Dillon twice_max_edge_power =
2450b7d5e03cSMatthew Dillon p_eep_data->ctl_power_data_2g[idx].ctl_edges[i].t_power;
2451b7d5e03cSMatthew Dillon } else {
2452b7d5e03cSMatthew Dillon twice_max_edge_power =
2453b7d5e03cSMatthew Dillon p_eep_data->ctl_power_data_5g[idx].ctl_edges[i].t_power;
2454b7d5e03cSMatthew Dillon }
2455b7d5e03cSMatthew Dillon break;
2456b7d5e03cSMatthew Dillon } else if ((i > 0) && (freq < fbin2freq(ctl_freqbin[i], is_2ghz))) {
2457b7d5e03cSMatthew Dillon if (is_2ghz) {
2458b7d5e03cSMatthew Dillon if (fbin2freq(ctl_freqbin[i - 1], 1) < freq &&
2459b7d5e03cSMatthew Dillon p_eep_data->ctl_power_data_2g[idx].ctl_edges[i - 1].flag)
2460b7d5e03cSMatthew Dillon {
2461b7d5e03cSMatthew Dillon twice_max_edge_power =
2462b7d5e03cSMatthew Dillon p_eep_data->ctl_power_data_2g[idx].
2463b7d5e03cSMatthew Dillon ctl_edges[i - 1].t_power;
2464b7d5e03cSMatthew Dillon }
2465b7d5e03cSMatthew Dillon } else {
2466b7d5e03cSMatthew Dillon if (fbin2freq(ctl_freqbin[i - 1], 0) < freq &&
2467b7d5e03cSMatthew Dillon p_eep_data->ctl_power_data_5g[idx].ctl_edges[i - 1].flag)
2468b7d5e03cSMatthew Dillon {
2469b7d5e03cSMatthew Dillon twice_max_edge_power =
2470b7d5e03cSMatthew Dillon p_eep_data->ctl_power_data_5g[idx].
2471b7d5e03cSMatthew Dillon ctl_edges[i - 1].t_power;
2472b7d5e03cSMatthew Dillon }
2473b7d5e03cSMatthew Dillon }
2474b7d5e03cSMatthew Dillon /*
2475b7d5e03cSMatthew Dillon * Leave loop - no more affecting edges possible
2476b7d5e03cSMatthew Dillon * in this monotonic increasing list
2477b7d5e03cSMatthew Dillon */
2478b7d5e03cSMatthew Dillon break;
2479b7d5e03cSMatthew Dillon }
2480b7d5e03cSMatthew Dillon }
2481b7d5e03cSMatthew Dillon /*
2482b7d5e03cSMatthew Dillon * EV89475: EEPROM might contain 0 txpower in CTL table for certain
2483b7d5e03cSMatthew Dillon * 2.4GHz channels. We workaround it by overwriting 60 (30 dBm) here.
2484b7d5e03cSMatthew Dillon */
2485b7d5e03cSMatthew Dillon if (is_2ghz && (twice_max_edge_power == 0)) {
2486b7d5e03cSMatthew Dillon twice_max_edge_power = 60;
2487b7d5e03cSMatthew Dillon }
2488b7d5e03cSMatthew Dillon
2489b7d5e03cSMatthew Dillon HALASSERT(twice_max_edge_power > 0);
2490b7d5e03cSMatthew Dillon return twice_max_edge_power;
2491b7d5e03cSMatthew Dillon }
2492b7d5e03cSMatthew Dillon
2493b7d5e03cSMatthew Dillon 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)2494b7d5e03cSMatthew Dillon ar9300_eeprom_set_power_per_rate_table(
2495b7d5e03cSMatthew Dillon struct ath_hal *ah,
2496b7d5e03cSMatthew Dillon ar9300_eeprom_t *p_eep_data,
2497b7d5e03cSMatthew Dillon const struct ieee80211_channel *chan,
2498b7d5e03cSMatthew Dillon u_int8_t *p_pwr_array,
2499b7d5e03cSMatthew Dillon u_int16_t cfg_ctl,
2500b7d5e03cSMatthew Dillon u_int16_t antenna_reduction,
2501b7d5e03cSMatthew Dillon u_int16_t twice_max_regulatory_power,
2502b7d5e03cSMatthew Dillon u_int16_t power_limit,
2503b7d5e03cSMatthew Dillon u_int8_t chainmask)
2504b7d5e03cSMatthew Dillon {
2505b7d5e03cSMatthew Dillon /* Local defines to distinguish between extension and control CTL's */
2506b7d5e03cSMatthew Dillon #define EXT_ADDITIVE (0x8000)
2507b7d5e03cSMatthew Dillon #define CTL_11A_EXT (CTL_11A | EXT_ADDITIVE)
2508b7d5e03cSMatthew Dillon #define CTL_11G_EXT (CTL_11G | EXT_ADDITIVE)
2509b7d5e03cSMatthew Dillon #define CTL_11B_EXT (CTL_11B | EXT_ADDITIVE)
2510b7d5e03cSMatthew Dillon #define REDUCE_SCALED_POWER_BY_TWO_CHAIN 6 /* 10*log10(2)*2 */
2511b7d5e03cSMatthew Dillon #define REDUCE_SCALED_POWER_BY_THREE_CHAIN 10 /* 10*log10(3)*2 */
2512b7d5e03cSMatthew Dillon #define PWRINCR_3_TO_1_CHAIN 9 /* 10*log(3)*2 */
2513b7d5e03cSMatthew Dillon #define PWRINCR_3_TO_2_CHAIN 3 /* floor(10*log(3/2)*2) */
2514b7d5e03cSMatthew Dillon #define PWRINCR_2_TO_1_CHAIN 6 /* 10*log(2)*2 */
2515b7d5e03cSMatthew Dillon
2516b7d5e03cSMatthew Dillon static const u_int16_t tp_scale_reduction_table[5] =
2517b7d5e03cSMatthew Dillon { 0, 3, 6, 9, AR9300_MAX_RATE_POWER };
2518b7d5e03cSMatthew Dillon int i;
2519b7d5e03cSMatthew Dillon int16_t twice_largest_antenna;
2520b7d5e03cSMatthew Dillon u_int16_t twice_antenna_reduction = 2*antenna_reduction ;
2521b7d5e03cSMatthew Dillon int16_t scaled_power = 0, min_ctl_power, max_reg_allowed_power;
2522b7d5e03cSMatthew Dillon #define SUB_NUM_CTL_MODES_AT_5G_40 2 /* excluding HT40, EXT-OFDM */
2523b7d5e03cSMatthew Dillon #define SUB_NUM_CTL_MODES_AT_2G_40 3 /* excluding HT40, EXT-OFDM, EXT-CCK */
2524b7d5e03cSMatthew Dillon u_int16_t ctl_modes_for11a[] =
2525b7d5e03cSMatthew Dillon {CTL_11A, CTL_5GHT20, CTL_11A_EXT, CTL_5GHT40};
2526b7d5e03cSMatthew Dillon u_int16_t ctl_modes_for11g[] =
2527b7d5e03cSMatthew Dillon {CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT, CTL_2GHT40};
2528b7d5e03cSMatthew Dillon u_int16_t num_ctl_modes, *p_ctl_mode, ctl_mode, freq;
2529b7d5e03cSMatthew Dillon CHAN_CENTERS centers;
2530b7d5e03cSMatthew Dillon int tx_chainmask;
2531b7d5e03cSMatthew Dillon struct ath_hal_9300 *ahp = AH9300(ah);
2532b7d5e03cSMatthew Dillon u_int8_t *ctl_index;
2533b7d5e03cSMatthew Dillon u_int8_t ctl_num;
2534b7d5e03cSMatthew Dillon u_int16_t twice_min_edge_power;
2535b7d5e03cSMatthew Dillon u_int16_t twice_max_edge_power = AR9300_MAX_RATE_POWER;
2536b7d5e03cSMatthew Dillon #ifdef AH_DEBUG
2537b7d5e03cSMatthew Dillon HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan);
2538b7d5e03cSMatthew Dillon #endif
2539b7d5e03cSMatthew Dillon
2540a20e5e51SMatthew Dillon if (chainmask)
2541a20e5e51SMatthew Dillon tx_chainmask = chainmask;
2542a20e5e51SMatthew Dillon else
2543a20e5e51SMatthew Dillon tx_chainmask = ahp->ah_tx_chainmaskopt ?
2544a20e5e51SMatthew Dillon ahp->ah_tx_chainmaskopt :ahp->ah_tx_chainmask;
2545b7d5e03cSMatthew Dillon
2546b7d5e03cSMatthew Dillon ar9300_get_channel_centers(ah, chan, ¢ers);
2547b7d5e03cSMatthew Dillon
2548a20e5e51SMatthew Dillon #if 1
2549b7d5e03cSMatthew Dillon if (IEEE80211_IS_CHAN_2GHZ(chan)) {
2550b7d5e03cSMatthew Dillon ahp->twice_antenna_gain = p_eep_data->modal_header_2g.antenna_gain;
2551b7d5e03cSMatthew Dillon } else {
2552b7d5e03cSMatthew Dillon ahp->twice_antenna_gain = p_eep_data->modal_header_5g.antenna_gain;
2553b7d5e03cSMatthew Dillon }
2554b7d5e03cSMatthew Dillon
2555a20e5e51SMatthew Dillon #else
2556a20e5e51SMatthew Dillon if (IEEE80211_IS_CHAN_2GHZ(chan)) {
2557a20e5e51SMatthew Dillon ahp->twice_antenna_gain = AH_MAX(p_eep_data->modal_header_2g.antenna_gain,
2558a20e5e51SMatthew Dillon AH_PRIVATE(ah)->ah_antenna_gain_2g);
2559a20e5e51SMatthew Dillon } else {
2560a20e5e51SMatthew Dillon ahp->twice_antenna_gain = AH_MAX(p_eep_data->modal_header_5g.antenna_gain,
2561a20e5e51SMatthew Dillon AH_PRIVATE(ah)->ah_antenna_gain_5g);
2562a20e5e51SMatthew Dillon }
2563a20e5e51SMatthew Dillon #endif
2564a20e5e51SMatthew Dillon
2565b7d5e03cSMatthew Dillon /* Save max allowed antenna gain to ease future lookups */
2566b7d5e03cSMatthew Dillon ahp->twice_antenna_reduction = twice_antenna_reduction;
2567b7d5e03cSMatthew Dillon
2568b7d5e03cSMatthew Dillon /* Deduct antenna gain from EIRP to get the upper limit */
2569b7d5e03cSMatthew Dillon twice_largest_antenna = (int16_t)AH_MIN((twice_antenna_reduction -
2570b7d5e03cSMatthew Dillon ahp->twice_antenna_gain), 0);
2571b7d5e03cSMatthew Dillon max_reg_allowed_power = twice_max_regulatory_power + twice_largest_antenna;
2572b7d5e03cSMatthew Dillon
2573b7d5e03cSMatthew Dillon /* Use ah_tp_scale - see bug 30070. */
2574b7d5e03cSMatthew Dillon if (AH_PRIVATE(ah)->ah_tpScale != HAL_TP_SCALE_MAX) {
2575b7d5e03cSMatthew Dillon max_reg_allowed_power -=
2576b7d5e03cSMatthew Dillon (tp_scale_reduction_table[(AH_PRIVATE(ah)->ah_tpScale)] * 2);
2577b7d5e03cSMatthew Dillon }
2578b7d5e03cSMatthew Dillon
2579b7d5e03cSMatthew Dillon scaled_power = AH_MIN(power_limit, max_reg_allowed_power);
2580b7d5e03cSMatthew Dillon
2581b7d5e03cSMatthew Dillon /*
2582b7d5e03cSMatthew Dillon * Reduce scaled Power by number of chains active to get to
2583b7d5e03cSMatthew Dillon * per chain tx power level
2584b7d5e03cSMatthew Dillon */
2585b7d5e03cSMatthew Dillon /* TODO: better value than these? */
2586b7d5e03cSMatthew Dillon switch (ar9300_get_ntxchains(tx_chainmask)) {
2587b7d5e03cSMatthew Dillon case 1:
2588b7d5e03cSMatthew Dillon ahp->upper_limit[0] = AH_MAX(0, scaled_power);
2589b7d5e03cSMatthew Dillon break;
2590b7d5e03cSMatthew Dillon case 2:
2591b7d5e03cSMatthew Dillon scaled_power -= REDUCE_SCALED_POWER_BY_TWO_CHAIN;
2592b7d5e03cSMatthew Dillon ahp->upper_limit[1] = AH_MAX(0, scaled_power);
2593b7d5e03cSMatthew Dillon break;
2594b7d5e03cSMatthew Dillon case 3:
2595b7d5e03cSMatthew Dillon scaled_power -= REDUCE_SCALED_POWER_BY_THREE_CHAIN;
2596b7d5e03cSMatthew Dillon ahp->upper_limit[2] = AH_MAX(0, scaled_power);
2597b7d5e03cSMatthew Dillon break;
2598b7d5e03cSMatthew Dillon default:
2599b7d5e03cSMatthew Dillon HALASSERT(0); /* Unsupported number of chains */
2600b7d5e03cSMatthew Dillon }
2601b7d5e03cSMatthew Dillon
2602b7d5e03cSMatthew Dillon scaled_power = AH_MAX(0, scaled_power);
2603b7d5e03cSMatthew Dillon
2604b7d5e03cSMatthew Dillon /* Get target powers from EEPROM - our baseline for TX Power */
2605b7d5e03cSMatthew Dillon if (IEEE80211_IS_CHAN_2GHZ(chan)) {
2606b7d5e03cSMatthew Dillon /* Setup for CTL modes */
2607b7d5e03cSMatthew Dillon /* CTL_11B, CTL_11G, CTL_2GHT20 */
2608b7d5e03cSMatthew Dillon num_ctl_modes =
2609b7d5e03cSMatthew Dillon ARRAY_LENGTH(ctl_modes_for11g) - SUB_NUM_CTL_MODES_AT_2G_40;
2610b7d5e03cSMatthew Dillon p_ctl_mode = ctl_modes_for11g;
2611b7d5e03cSMatthew Dillon
2612b7d5e03cSMatthew Dillon if (IEEE80211_IS_CHAN_HT40(chan)) {
2613b7d5e03cSMatthew Dillon num_ctl_modes = ARRAY_LENGTH(ctl_modes_for11g); /* All 2G CTL's */
2614b7d5e03cSMatthew Dillon }
2615b7d5e03cSMatthew Dillon } else {
2616b7d5e03cSMatthew Dillon /* Setup for CTL modes */
2617b7d5e03cSMatthew Dillon /* CTL_11A, CTL_5GHT20 */
2618b7d5e03cSMatthew Dillon num_ctl_modes =
2619b7d5e03cSMatthew Dillon ARRAY_LENGTH(ctl_modes_for11a) - SUB_NUM_CTL_MODES_AT_5G_40;
2620b7d5e03cSMatthew Dillon p_ctl_mode = ctl_modes_for11a;
2621b7d5e03cSMatthew Dillon
2622b7d5e03cSMatthew Dillon if (IEEE80211_IS_CHAN_HT40(chan)) {
2623b7d5e03cSMatthew Dillon num_ctl_modes = ARRAY_LENGTH(ctl_modes_for11a); /* All 5G CTL's */
2624b7d5e03cSMatthew Dillon }
2625b7d5e03cSMatthew Dillon }
2626b7d5e03cSMatthew Dillon
2627b7d5e03cSMatthew Dillon /*
2628b7d5e03cSMatthew Dillon * For MIMO, need to apply regulatory caps individually across dynamically
2629b7d5e03cSMatthew Dillon * running modes: CCK, OFDM, HT20, HT40
2630b7d5e03cSMatthew Dillon *
2631b7d5e03cSMatthew Dillon * The outer loop walks through each possible applicable runtime mode.
2632b7d5e03cSMatthew Dillon * The inner loop walks through each ctl_index entry in EEPROM.
2633b7d5e03cSMatthew Dillon * The ctl value is encoded as [7:4] == test group, [3:0] == test mode.
2634b7d5e03cSMatthew Dillon *
2635b7d5e03cSMatthew Dillon */
2636b7d5e03cSMatthew Dillon for (ctl_mode = 0; ctl_mode < num_ctl_modes; ctl_mode++) {
2637b7d5e03cSMatthew Dillon HAL_BOOL is_ht40_ctl_mode =
2638b7d5e03cSMatthew Dillon (p_ctl_mode[ctl_mode] == CTL_5GHT40) ||
2639b7d5e03cSMatthew Dillon (p_ctl_mode[ctl_mode] == CTL_2GHT40);
2640b7d5e03cSMatthew Dillon if (is_ht40_ctl_mode) {
2641b7d5e03cSMatthew Dillon freq = centers.synth_center;
2642b7d5e03cSMatthew Dillon } else if (p_ctl_mode[ctl_mode] & EXT_ADDITIVE) {
2643b7d5e03cSMatthew Dillon freq = centers.ext_center;
2644b7d5e03cSMatthew Dillon } else {
2645b7d5e03cSMatthew Dillon freq = centers.ctl_center;
2646b7d5e03cSMatthew Dillon }
2647b7d5e03cSMatthew Dillon
2648b7d5e03cSMatthew Dillon HALDEBUG(ah, HAL_DEBUG_POWER_MGMT,
2649b7d5e03cSMatthew Dillon "LOOP-Mode ctl_mode %d < %d, "
2650b7d5e03cSMatthew Dillon "is_ht40_ctl_mode %d, EXT_ADDITIVE %d\n",
2651b7d5e03cSMatthew Dillon ctl_mode, num_ctl_modes, is_ht40_ctl_mode,
2652b7d5e03cSMatthew Dillon (p_ctl_mode[ctl_mode] & EXT_ADDITIVE));
2653b7d5e03cSMatthew Dillon /* walk through each CTL index stored in EEPROM */
2654b7d5e03cSMatthew Dillon if (IEEE80211_IS_CHAN_2GHZ(chan)) {
2655b7d5e03cSMatthew Dillon ctl_index = p_eep_data->ctl_index_2g;
2656b7d5e03cSMatthew Dillon ctl_num = OSPREY_NUM_CTLS_2G;
2657b7d5e03cSMatthew Dillon } else {
2658b7d5e03cSMatthew Dillon ctl_index = p_eep_data->ctl_index_5g;
2659b7d5e03cSMatthew Dillon ctl_num = OSPREY_NUM_CTLS_5G;
2660b7d5e03cSMatthew Dillon }
2661b7d5e03cSMatthew Dillon
2662b7d5e03cSMatthew Dillon for (i = 0; (i < ctl_num) && ctl_index[i]; i++) {
2663b7d5e03cSMatthew Dillon HALDEBUG(ah, HAL_DEBUG_POWER_MGMT,
2664b7d5e03cSMatthew Dillon " LOOP-Ctlidx %d: cfg_ctl 0x%2.2x p_ctl_mode 0x%2.2x "
2665b7d5e03cSMatthew Dillon "ctl_index 0x%2.2x chan %d chanctl 0x%x\n",
2666b7d5e03cSMatthew Dillon i, cfg_ctl, p_ctl_mode[ctl_mode], ctl_index[i],
2667b7d5e03cSMatthew Dillon ichan->channel, ath_hal_getctl(ah, chan));
2668b7d5e03cSMatthew Dillon
2669b7d5e03cSMatthew Dillon
2670b7d5e03cSMatthew Dillon /*
2671b7d5e03cSMatthew Dillon * compare test group from regulatory channel list
2672b7d5e03cSMatthew Dillon * with test mode from p_ctl_mode list
2673b7d5e03cSMatthew Dillon */
2674b7d5e03cSMatthew Dillon if ((((cfg_ctl & ~CTL_MODE_M) |
2675b7d5e03cSMatthew Dillon (p_ctl_mode[ctl_mode] & CTL_MODE_M)) == ctl_index[i]) ||
2676b7d5e03cSMatthew Dillon (((cfg_ctl & ~CTL_MODE_M) |
2677b7d5e03cSMatthew Dillon (p_ctl_mode[ctl_mode] & CTL_MODE_M)) ==
2678b7d5e03cSMatthew Dillon ((ctl_index[i] & CTL_MODE_M) | SD_NO_CTL)))
2679b7d5e03cSMatthew Dillon {
2680b7d5e03cSMatthew Dillon twice_min_edge_power =
2681b7d5e03cSMatthew Dillon ar9300_eep_def_get_max_edge_power(
2682b7d5e03cSMatthew Dillon p_eep_data, freq, i, IEEE80211_IS_CHAN_2GHZ(chan));
2683b7d5e03cSMatthew Dillon
2684b7d5e03cSMatthew Dillon HALDEBUG(ah, HAL_DEBUG_POWER_MGMT,
2685b7d5e03cSMatthew Dillon " MATCH-EE_IDX %d: ch %d is2 %d "
2686b7d5e03cSMatthew Dillon "2xMinEdge %d chainmask %d chains %d\n",
2687b7d5e03cSMatthew Dillon i, freq, IEEE80211_IS_CHAN_2GHZ(chan),
2688b7d5e03cSMatthew Dillon twice_min_edge_power, tx_chainmask,
2689b7d5e03cSMatthew Dillon ar9300_get_ntxchains(tx_chainmask));
2690b7d5e03cSMatthew Dillon
2691b7d5e03cSMatthew Dillon if ((cfg_ctl & ~CTL_MODE_M) == SD_NO_CTL) {
2692b7d5e03cSMatthew Dillon /*
2693b7d5e03cSMatthew Dillon * Find the minimum of all CTL edge powers
2694b7d5e03cSMatthew Dillon * that apply to this channel
2695b7d5e03cSMatthew Dillon */
2696b7d5e03cSMatthew Dillon twice_max_edge_power =
2697b7d5e03cSMatthew Dillon AH_MIN(twice_max_edge_power, twice_min_edge_power);
2698b7d5e03cSMatthew Dillon } else {
2699b7d5e03cSMatthew Dillon /* specific */
2700b7d5e03cSMatthew Dillon twice_max_edge_power = twice_min_edge_power;
2701b7d5e03cSMatthew Dillon break;
2702b7d5e03cSMatthew Dillon }
2703b7d5e03cSMatthew Dillon }
2704b7d5e03cSMatthew Dillon }
2705b7d5e03cSMatthew Dillon
2706b7d5e03cSMatthew Dillon min_ctl_power = (u_int8_t)AH_MIN(twice_max_edge_power, scaled_power);
2707b7d5e03cSMatthew Dillon
2708b7d5e03cSMatthew Dillon HALDEBUG(ah, HAL_DEBUG_POWER_MGMT,
2709b7d5e03cSMatthew Dillon " SEL-Min ctl_mode %d p_ctl_mode %d "
2710b7d5e03cSMatthew Dillon "2xMaxEdge %d sP %d min_ctl_pwr %d\n",
2711b7d5e03cSMatthew Dillon ctl_mode, p_ctl_mode[ctl_mode],
2712b7d5e03cSMatthew Dillon twice_max_edge_power, scaled_power, min_ctl_power);
2713b7d5e03cSMatthew Dillon
2714b7d5e03cSMatthew Dillon /* Apply ctl mode to correct target power set */
2715b7d5e03cSMatthew Dillon switch (p_ctl_mode[ctl_mode]) {
2716b7d5e03cSMatthew Dillon case CTL_11B:
2717b7d5e03cSMatthew Dillon for (i = ALL_TARGET_LEGACY_1L_5L; i <= ALL_TARGET_LEGACY_11S; i++) {
2718b7d5e03cSMatthew Dillon p_pwr_array[i] =
2719b7d5e03cSMatthew Dillon (u_int8_t)AH_MIN(p_pwr_array[i], min_ctl_power);
2720b7d5e03cSMatthew Dillon }
2721b7d5e03cSMatthew Dillon break;
2722b7d5e03cSMatthew Dillon case CTL_11A:
2723b7d5e03cSMatthew Dillon case CTL_11G:
2724b7d5e03cSMatthew Dillon for (i = ALL_TARGET_LEGACY_6_24; i <= ALL_TARGET_LEGACY_54; i++) {
2725b7d5e03cSMatthew Dillon p_pwr_array[i] =
2726b7d5e03cSMatthew Dillon (u_int8_t)AH_MIN(p_pwr_array[i], min_ctl_power);
2727b7d5e03cSMatthew Dillon #ifdef ATH_BT_COEX
2728b7d5e03cSMatthew Dillon if ((ahp->ah_bt_coex_config_type == HAL_BT_COEX_CFG_3WIRE) ||
2729b7d5e03cSMatthew Dillon (ahp->ah_bt_coex_config_type == HAL_BT_COEX_CFG_MCI))
2730b7d5e03cSMatthew Dillon {
2731b7d5e03cSMatthew Dillon if ((ahp->ah_bt_coex_flag & HAL_BT_COEX_FLAG_LOWER_TX_PWR)
2732b7d5e03cSMatthew Dillon && (ahp->ah_bt_wlan_isolation
2733b7d5e03cSMatthew Dillon < HAL_BT_COEX_ISOLATION_FOR_NO_COEX))
2734b7d5e03cSMatthew Dillon {
2735b7d5e03cSMatthew Dillon
2736b7d5e03cSMatthew Dillon u_int8_t reduce_pow;
2737b7d5e03cSMatthew Dillon
2738b7d5e03cSMatthew Dillon reduce_pow = (HAL_BT_COEX_ISOLATION_FOR_NO_COEX
2739b7d5e03cSMatthew Dillon - ahp->ah_bt_wlan_isolation) << 1;
2740b7d5e03cSMatthew Dillon
2741b7d5e03cSMatthew Dillon if (reduce_pow <= p_pwr_array[i]) {
2742b7d5e03cSMatthew Dillon p_pwr_array[i] -= reduce_pow;
2743b7d5e03cSMatthew Dillon }
2744b7d5e03cSMatthew Dillon }
2745b7d5e03cSMatthew Dillon if ((ahp->ah_bt_coex_flag &
2746b7d5e03cSMatthew Dillon HAL_BT_COEX_FLAG_LOW_ACK_PWR) &&
2747b7d5e03cSMatthew Dillon (i != ALL_TARGET_LEGACY_36) &&
2748b7d5e03cSMatthew Dillon (i != ALL_TARGET_LEGACY_48) &&
2749b7d5e03cSMatthew Dillon (i != ALL_TARGET_LEGACY_54) &&
2750b7d5e03cSMatthew Dillon (p_ctl_mode[ctl_mode] == CTL_11G))
2751b7d5e03cSMatthew Dillon {
2752b7d5e03cSMatthew Dillon p_pwr_array[i] = 0;
2753b7d5e03cSMatthew Dillon }
2754b7d5e03cSMatthew Dillon }
2755b7d5e03cSMatthew Dillon #endif
2756b7d5e03cSMatthew Dillon }
2757b7d5e03cSMatthew Dillon break;
2758b7d5e03cSMatthew Dillon case CTL_5GHT20:
2759b7d5e03cSMatthew Dillon case CTL_2GHT20:
2760b7d5e03cSMatthew Dillon for (i = ALL_TARGET_HT20_0_8_16; i <= ALL_TARGET_HT20_23; i++) {
2761b7d5e03cSMatthew Dillon p_pwr_array[i] =
2762b7d5e03cSMatthew Dillon (u_int8_t)AH_MIN(p_pwr_array[i], min_ctl_power);
2763b7d5e03cSMatthew Dillon #ifdef ATH_BT_COEX
2764b7d5e03cSMatthew Dillon if (((ahp->ah_bt_coex_config_type == HAL_BT_COEX_CFG_3WIRE) ||
2765b7d5e03cSMatthew Dillon (ahp->ah_bt_coex_config_type == HAL_BT_COEX_CFG_MCI)) &&
2766b7d5e03cSMatthew Dillon (ahp->ah_bt_coex_flag & HAL_BT_COEX_FLAG_LOWER_TX_PWR) &&
2767b7d5e03cSMatthew Dillon (ahp->ah_bt_wlan_isolation
2768b7d5e03cSMatthew Dillon < HAL_BT_COEX_ISOLATION_FOR_NO_COEX)) {
2769b7d5e03cSMatthew Dillon
2770b7d5e03cSMatthew Dillon u_int8_t reduce_pow = (HAL_BT_COEX_ISOLATION_FOR_NO_COEX
2771b7d5e03cSMatthew Dillon - ahp->ah_bt_wlan_isolation) << 1;
2772b7d5e03cSMatthew Dillon
2773b7d5e03cSMatthew Dillon if (reduce_pow <= p_pwr_array[i]) {
2774b7d5e03cSMatthew Dillon p_pwr_array[i] -= reduce_pow;
2775b7d5e03cSMatthew Dillon }
2776b7d5e03cSMatthew Dillon }
2777b7d5e03cSMatthew Dillon #if ATH_SUPPORT_MCI
2778b7d5e03cSMatthew Dillon else if ((ahp->ah_bt_coex_flag &
2779b7d5e03cSMatthew Dillon HAL_BT_COEX_FLAG_MCI_MAX_TX_PWR) &&
2780b7d5e03cSMatthew Dillon (p_ctl_mode[ctl_mode] == CTL_2GHT20) &&
2781b7d5e03cSMatthew Dillon (ahp->ah_bt_coex_config_type == HAL_BT_COEX_CFG_MCI))
2782b7d5e03cSMatthew Dillon {
2783b7d5e03cSMatthew Dillon u_int8_t max_pwr;
2784b7d5e03cSMatthew Dillon
2785b7d5e03cSMatthew Dillon max_pwr = MS(mci_concur_tx_max_pwr[2][1],
2786b7d5e03cSMatthew Dillon ATH_MCI_CONCUR_TX_LOWEST_PWR_MASK);
2787b7d5e03cSMatthew Dillon if (p_pwr_array[i] > max_pwr) {
2788b7d5e03cSMatthew Dillon p_pwr_array[i] = max_pwr;
2789b7d5e03cSMatthew Dillon }
2790b7d5e03cSMatthew Dillon }
2791b7d5e03cSMatthew Dillon #endif
2792b7d5e03cSMatthew Dillon #endif
2793b7d5e03cSMatthew Dillon }
2794b7d5e03cSMatthew Dillon break;
2795b7d5e03cSMatthew Dillon case CTL_11B_EXT:
2796b7d5e03cSMatthew Dillon #ifdef NOT_YET
2797b7d5e03cSMatthew Dillon target_power_cck_ext.t_pow2x[0] = (u_int8_t)
2798b7d5e03cSMatthew Dillon AH_MIN(target_power_cck_ext.t_pow2x[0], min_ctl_power);
2799b7d5e03cSMatthew Dillon #endif /* NOT_YET */
2800b7d5e03cSMatthew Dillon break;
2801b7d5e03cSMatthew Dillon case CTL_11A_EXT:
2802b7d5e03cSMatthew Dillon case CTL_11G_EXT:
2803b7d5e03cSMatthew Dillon #ifdef NOT_YET
2804b7d5e03cSMatthew Dillon target_power_ofdm_ext.t_pow2x[0] = (u_int8_t)
2805b7d5e03cSMatthew Dillon AH_MIN(target_power_ofdm_ext.t_pow2x[0], min_ctl_power);
2806b7d5e03cSMatthew Dillon #endif /* NOT_YET */
2807b7d5e03cSMatthew Dillon break;
2808b7d5e03cSMatthew Dillon case CTL_5GHT40:
2809b7d5e03cSMatthew Dillon case CTL_2GHT40:
2810b7d5e03cSMatthew Dillon for (i = ALL_TARGET_HT40_0_8_16; i <= ALL_TARGET_HT40_23; i++) {
2811b7d5e03cSMatthew Dillon p_pwr_array[i] = (u_int8_t)
2812b7d5e03cSMatthew Dillon AH_MIN(p_pwr_array[i], min_ctl_power);
2813b7d5e03cSMatthew Dillon #ifdef ATH_BT_COEX
2814b7d5e03cSMatthew Dillon if (((ahp->ah_bt_coex_config_type == HAL_BT_COEX_CFG_3WIRE) ||
2815b7d5e03cSMatthew Dillon (ahp->ah_bt_coex_config_type == HAL_BT_COEX_CFG_MCI)) &&
2816b7d5e03cSMatthew Dillon (ahp->ah_bt_coex_flag & HAL_BT_COEX_FLAG_LOWER_TX_PWR) &&
2817b7d5e03cSMatthew Dillon (ahp->ah_bt_wlan_isolation
2818b7d5e03cSMatthew Dillon < HAL_BT_COEX_ISOLATION_FOR_NO_COEX)) {
2819b7d5e03cSMatthew Dillon
2820b7d5e03cSMatthew Dillon u_int8_t reduce_pow = (HAL_BT_COEX_ISOLATION_FOR_NO_COEX
2821b7d5e03cSMatthew Dillon - ahp->ah_bt_wlan_isolation) << 1;
2822b7d5e03cSMatthew Dillon
2823b7d5e03cSMatthew Dillon if (reduce_pow <= p_pwr_array[i]) {
2824b7d5e03cSMatthew Dillon p_pwr_array[i] -= reduce_pow;
2825b7d5e03cSMatthew Dillon }
2826b7d5e03cSMatthew Dillon }
2827b7d5e03cSMatthew Dillon #if ATH_SUPPORT_MCI
2828b7d5e03cSMatthew Dillon else if ((ahp->ah_bt_coex_flag &
2829b7d5e03cSMatthew Dillon HAL_BT_COEX_FLAG_MCI_MAX_TX_PWR) &&
2830b7d5e03cSMatthew Dillon (p_ctl_mode[ctl_mode] == CTL_2GHT40) &&
2831b7d5e03cSMatthew Dillon (ahp->ah_bt_coex_config_type == HAL_BT_COEX_CFG_MCI))
2832b7d5e03cSMatthew Dillon {
2833b7d5e03cSMatthew Dillon u_int8_t max_pwr;
2834b7d5e03cSMatthew Dillon
2835b7d5e03cSMatthew Dillon max_pwr = MS(mci_concur_tx_max_pwr[3][1],
2836b7d5e03cSMatthew Dillon ATH_MCI_CONCUR_TX_LOWEST_PWR_MASK);
2837b7d5e03cSMatthew Dillon if (p_pwr_array[i] > max_pwr) {
2838b7d5e03cSMatthew Dillon p_pwr_array[i] = max_pwr;
2839b7d5e03cSMatthew Dillon }
2840b7d5e03cSMatthew Dillon }
2841b7d5e03cSMatthew Dillon #endif
2842b7d5e03cSMatthew Dillon #endif
2843b7d5e03cSMatthew Dillon }
2844b7d5e03cSMatthew Dillon break;
2845b7d5e03cSMatthew Dillon default:
2846b7d5e03cSMatthew Dillon HALASSERT(0);
2847b7d5e03cSMatthew Dillon break;
2848b7d5e03cSMatthew Dillon }
2849b7d5e03cSMatthew Dillon } /* end ctl mode checking */
2850b7d5e03cSMatthew Dillon
2851b7d5e03cSMatthew Dillon return AH_TRUE;
2852b7d5e03cSMatthew Dillon #undef EXT_ADDITIVE
2853b7d5e03cSMatthew Dillon #undef CTL_11A_EXT
2854b7d5e03cSMatthew Dillon #undef CTL_11G_EXT
2855b7d5e03cSMatthew Dillon #undef CTL_11B_EXT
2856b7d5e03cSMatthew Dillon #undef REDUCE_SCALED_POWER_BY_TWO_CHAIN
2857b7d5e03cSMatthew Dillon #undef REDUCE_SCALED_POWER_BY_THREE_CHAIN
2858b7d5e03cSMatthew Dillon }
2859b7d5e03cSMatthew Dillon
2860b7d5e03cSMatthew Dillon /**************************************************************
2861b7d5e03cSMatthew Dillon * ar9300_eeprom_set_transmit_power
2862b7d5e03cSMatthew Dillon *
2863b7d5e03cSMatthew Dillon * Set the transmit power in the baseband for the given
2864b7d5e03cSMatthew Dillon * operating channel and mode.
2865b7d5e03cSMatthew Dillon */
2866b7d5e03cSMatthew Dillon 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)2867b7d5e03cSMatthew Dillon ar9300_eeprom_set_transmit_power(struct ath_hal *ah,
2868b7d5e03cSMatthew Dillon ar9300_eeprom_t *p_eep_data, const struct ieee80211_channel *chan, u_int16_t cfg_ctl,
2869b7d5e03cSMatthew Dillon u_int16_t antenna_reduction, u_int16_t twice_max_regulatory_power,
2870b7d5e03cSMatthew Dillon u_int16_t power_limit)
2871b7d5e03cSMatthew Dillon {
2872b7d5e03cSMatthew Dillon #define ABS(_x, _y) ((int)_x > (int)_y ? (int)_x - (int)_y : (int)_y - (int)_x)
2873b7d5e03cSMatthew Dillon #define INCREASE_MAXPOW_BY_TWO_CHAIN 6 /* 10*log10(2)*2 */
2874b7d5e03cSMatthew Dillon #define INCREASE_MAXPOW_BY_THREE_CHAIN 10 /* 10*log10(3)*2 */
2875b7d5e03cSMatthew Dillon u_int8_t target_power_val_t2[ar9300_rate_size];
2876b7d5e03cSMatthew Dillon u_int8_t target_power_val_t2_eep[ar9300_rate_size];
2877b7d5e03cSMatthew Dillon int16_t twice_array_gain = 0, max_power_level = 0;
2878b7d5e03cSMatthew Dillon struct ath_hal_9300 *ahp = AH9300(ah);
2879b7d5e03cSMatthew Dillon int i = 0;
2880b7d5e03cSMatthew Dillon u_int32_t tmp_paprd_rate_mask = 0, *tmp_ptr = NULL;
2881b7d5e03cSMatthew Dillon int paprd_scale_factor = 5;
2882b7d5e03cSMatthew Dillon HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan);
2883b7d5e03cSMatthew Dillon
2884b7d5e03cSMatthew Dillon u_int8_t *ptr_mcs_rate2power_table_index;
2885b7d5e03cSMatthew Dillon u_int8_t mcs_rate2power_table_index_ht20[24] =
2886b7d5e03cSMatthew Dillon {
2887b7d5e03cSMatthew Dillon ALL_TARGET_HT20_0_8_16,
2888b7d5e03cSMatthew Dillon ALL_TARGET_HT20_1_3_9_11_17_19,
2889b7d5e03cSMatthew Dillon ALL_TARGET_HT20_1_3_9_11_17_19,
2890b7d5e03cSMatthew Dillon ALL_TARGET_HT20_1_3_9_11_17_19,
2891b7d5e03cSMatthew Dillon ALL_TARGET_HT20_4,
2892b7d5e03cSMatthew Dillon ALL_TARGET_HT20_5,
2893b7d5e03cSMatthew Dillon ALL_TARGET_HT20_6,
2894b7d5e03cSMatthew Dillon ALL_TARGET_HT20_7,
2895b7d5e03cSMatthew Dillon ALL_TARGET_HT20_0_8_16,
2896b7d5e03cSMatthew Dillon ALL_TARGET_HT20_1_3_9_11_17_19,
2897b7d5e03cSMatthew Dillon ALL_TARGET_HT20_1_3_9_11_17_19,
2898b7d5e03cSMatthew Dillon ALL_TARGET_HT20_1_3_9_11_17_19,
2899b7d5e03cSMatthew Dillon ALL_TARGET_HT20_12,
2900b7d5e03cSMatthew Dillon ALL_TARGET_HT20_13,
2901b7d5e03cSMatthew Dillon ALL_TARGET_HT20_14,
2902b7d5e03cSMatthew Dillon ALL_TARGET_HT20_15,
2903b7d5e03cSMatthew Dillon ALL_TARGET_HT20_0_8_16,
2904b7d5e03cSMatthew Dillon ALL_TARGET_HT20_1_3_9_11_17_19,
2905b7d5e03cSMatthew Dillon ALL_TARGET_HT20_1_3_9_11_17_19,
2906b7d5e03cSMatthew Dillon ALL_TARGET_HT20_1_3_9_11_17_19,
2907b7d5e03cSMatthew Dillon ALL_TARGET_HT20_20,
2908b7d5e03cSMatthew Dillon ALL_TARGET_HT20_21,
2909b7d5e03cSMatthew Dillon ALL_TARGET_HT20_22,
2910b7d5e03cSMatthew Dillon ALL_TARGET_HT20_23
2911b7d5e03cSMatthew Dillon };
2912b7d5e03cSMatthew Dillon
2913b7d5e03cSMatthew Dillon u_int8_t mcs_rate2power_table_index_ht40[24] =
2914b7d5e03cSMatthew Dillon {
2915b7d5e03cSMatthew Dillon ALL_TARGET_HT40_0_8_16,
2916b7d5e03cSMatthew Dillon ALL_TARGET_HT40_1_3_9_11_17_19,
2917b7d5e03cSMatthew Dillon ALL_TARGET_HT40_1_3_9_11_17_19,
2918b7d5e03cSMatthew Dillon ALL_TARGET_HT40_1_3_9_11_17_19,
2919b7d5e03cSMatthew Dillon ALL_TARGET_HT40_4,
2920b7d5e03cSMatthew Dillon ALL_TARGET_HT40_5,
2921b7d5e03cSMatthew Dillon ALL_TARGET_HT40_6,
2922b7d5e03cSMatthew Dillon ALL_TARGET_HT40_7,
2923b7d5e03cSMatthew Dillon ALL_TARGET_HT40_0_8_16,
2924b7d5e03cSMatthew Dillon ALL_TARGET_HT40_1_3_9_11_17_19,
2925b7d5e03cSMatthew Dillon ALL_TARGET_HT40_1_3_9_11_17_19,
2926b7d5e03cSMatthew Dillon ALL_TARGET_HT40_1_3_9_11_17_19,
2927b7d5e03cSMatthew Dillon ALL_TARGET_HT40_12,
2928b7d5e03cSMatthew Dillon ALL_TARGET_HT40_13,
2929b7d5e03cSMatthew Dillon ALL_TARGET_HT40_14,
2930b7d5e03cSMatthew Dillon ALL_TARGET_HT40_15,
2931b7d5e03cSMatthew Dillon ALL_TARGET_HT40_0_8_16,
2932b7d5e03cSMatthew Dillon ALL_TARGET_HT40_1_3_9_11_17_19,
2933b7d5e03cSMatthew Dillon ALL_TARGET_HT40_1_3_9_11_17_19,
2934b7d5e03cSMatthew Dillon ALL_TARGET_HT40_1_3_9_11_17_19,
2935b7d5e03cSMatthew Dillon ALL_TARGET_HT40_20,
2936b7d5e03cSMatthew Dillon ALL_TARGET_HT40_21,
2937b7d5e03cSMatthew Dillon ALL_TARGET_HT40_22,
2938b7d5e03cSMatthew Dillon ALL_TARGET_HT40_23,
2939b7d5e03cSMatthew Dillon };
2940b7d5e03cSMatthew Dillon
2941b7d5e03cSMatthew Dillon HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
2942b7d5e03cSMatthew Dillon "%s[%d] +++chan %d,cfgctl 0x%04x "
2943b7d5e03cSMatthew Dillon "antenna_reduction 0x%04x, twice_max_regulatory_power 0x%04x "
2944b7d5e03cSMatthew Dillon "power_limit 0x%04x\n",
2945b7d5e03cSMatthew Dillon __func__, __LINE__, ichan->channel, cfg_ctl,
2946b7d5e03cSMatthew Dillon antenna_reduction, twice_max_regulatory_power, power_limit);
2947b7d5e03cSMatthew Dillon ar9300_set_target_power_from_eeprom(ah, ichan->channel, target_power_val_t2);
2948b7d5e03cSMatthew Dillon
2949b7d5e03cSMatthew Dillon if (ar9300_eeprom_get(ahp, EEP_PAPRD_ENABLED)) {
2950b7d5e03cSMatthew Dillon if (IEEE80211_IS_CHAN_2GHZ(chan)) {
2951b7d5e03cSMatthew Dillon if (IEEE80211_IS_CHAN_HT40(chan)) {
2952b7d5e03cSMatthew Dillon tmp_paprd_rate_mask =
2953b7d5e03cSMatthew Dillon p_eep_data->modal_header_2g.paprd_rate_mask_ht40;
2954b7d5e03cSMatthew Dillon tmp_ptr = &AH9300(ah)->ah_2g_paprd_rate_mask_ht40;
2955b7d5e03cSMatthew Dillon } else {
2956b7d5e03cSMatthew Dillon tmp_paprd_rate_mask =
2957b7d5e03cSMatthew Dillon p_eep_data->modal_header_2g.paprd_rate_mask_ht20;
2958b7d5e03cSMatthew Dillon tmp_ptr = &AH9300(ah)->ah_2g_paprd_rate_mask_ht20;
2959b7d5e03cSMatthew Dillon }
2960b7d5e03cSMatthew Dillon } else {
2961b7d5e03cSMatthew Dillon if (IEEE80211_IS_CHAN_HT40(chan)) {
2962b7d5e03cSMatthew Dillon tmp_paprd_rate_mask =
2963b7d5e03cSMatthew Dillon p_eep_data->modal_header_5g.paprd_rate_mask_ht40;
2964b7d5e03cSMatthew Dillon tmp_ptr = &AH9300(ah)->ah_5g_paprd_rate_mask_ht40;
2965b7d5e03cSMatthew Dillon } else {
2966b7d5e03cSMatthew Dillon tmp_paprd_rate_mask =
2967b7d5e03cSMatthew Dillon p_eep_data->modal_header_5g.paprd_rate_mask_ht20;
2968b7d5e03cSMatthew Dillon tmp_ptr = &AH9300(ah)->ah_5g_paprd_rate_mask_ht20;
2969b7d5e03cSMatthew Dillon }
2970b7d5e03cSMatthew Dillon }
2971b7d5e03cSMatthew Dillon AH_PAPRD_GET_SCALE_FACTOR(
2972b7d5e03cSMatthew Dillon paprd_scale_factor, p_eep_data, IEEE80211_IS_CHAN_2GHZ(chan), ichan->channel);
2973b7d5e03cSMatthew Dillon HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s[%d] paprd_scale_factor %d\n",
2974b7d5e03cSMatthew Dillon __func__, __LINE__, paprd_scale_factor);
2975b7d5e03cSMatthew Dillon /* PAPRD is not done yet, Scale down the EEP power */
2976b7d5e03cSMatthew Dillon if (IEEE80211_IS_CHAN_HT40(chan)) {
2977b7d5e03cSMatthew Dillon ptr_mcs_rate2power_table_index =
2978b7d5e03cSMatthew Dillon &mcs_rate2power_table_index_ht40[0];
2979b7d5e03cSMatthew Dillon } else {
2980b7d5e03cSMatthew Dillon ptr_mcs_rate2power_table_index =
2981b7d5e03cSMatthew Dillon &mcs_rate2power_table_index_ht20[0];
2982b7d5e03cSMatthew Dillon }
2983b7d5e03cSMatthew Dillon if (! ichan->paprd_table_write_done) {
2984b7d5e03cSMatthew Dillon for (i = 0; i < 24; i++) {
2985b7d5e03cSMatthew Dillon /* PAPRD is done yet, so Scale down Power for PAPRD Rates*/
2986b7d5e03cSMatthew Dillon if (tmp_paprd_rate_mask & (1 << i)) {
2987b7d5e03cSMatthew Dillon target_power_val_t2[ptr_mcs_rate2power_table_index[i]] -=
2988b7d5e03cSMatthew Dillon paprd_scale_factor;
2989b7d5e03cSMatthew Dillon HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
2990b7d5e03cSMatthew Dillon "%s[%d]: Chan %d "
2991b7d5e03cSMatthew Dillon "Scale down target_power_val_t2[%d] = 0x%04x\n",
2992b7d5e03cSMatthew Dillon __func__, __LINE__,
2993b7d5e03cSMatthew Dillon ichan->channel, i, target_power_val_t2[i]);
2994b7d5e03cSMatthew Dillon }
2995b7d5e03cSMatthew Dillon }
2996b7d5e03cSMatthew Dillon } else {
2997b7d5e03cSMatthew Dillon HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
2998b7d5e03cSMatthew Dillon "%s[%d]: PAPRD Done No TGT PWR Scaling\n", __func__, __LINE__);
2999b7d5e03cSMatthew Dillon }
3000b7d5e03cSMatthew Dillon }
3001b7d5e03cSMatthew Dillon
3002b7d5e03cSMatthew Dillon /* Save the Target power for future use */
3003b7d5e03cSMatthew Dillon OS_MEMCPY(target_power_val_t2_eep, target_power_val_t2,
3004b7d5e03cSMatthew Dillon sizeof(target_power_val_t2));
3005b7d5e03cSMatthew Dillon ar9300_eeprom_set_power_per_rate_table(ah, p_eep_data, chan,
3006b7d5e03cSMatthew Dillon target_power_val_t2, cfg_ctl,
3007b7d5e03cSMatthew Dillon antenna_reduction,
3008b7d5e03cSMatthew Dillon twice_max_regulatory_power,
3009b7d5e03cSMatthew Dillon power_limit, 0);
3010b7d5e03cSMatthew Dillon
3011b7d5e03cSMatthew Dillon /* Save this for quick lookup */
3012b7d5e03cSMatthew Dillon ahp->reg_dmn = ath_hal_getctl(ah, chan);
3013b7d5e03cSMatthew Dillon
3014b7d5e03cSMatthew Dillon /*
3015b7d5e03cSMatthew Dillon * Always use CDD/direct per rate power table for register based approach.
3016b7d5e03cSMatthew Dillon * For FCC, CDD calculations should factor in the array gain, hence
3017b7d5e03cSMatthew Dillon * this adjust call. ETSI and MKK does not have this requirement.
3018b7d5e03cSMatthew Dillon */
3019b7d5e03cSMatthew Dillon if (is_reg_dmn_fcc(ahp->reg_dmn)) {
3020b7d5e03cSMatthew Dillon HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
3021b7d5e03cSMatthew Dillon "%s: FCC regdomain, calling reg_txpower_cdd\n",
3022b7d5e03cSMatthew Dillon __func__);
3023b7d5e03cSMatthew Dillon ar9300_adjust_reg_txpower_cdd(ah, target_power_val_t2);
3024b7d5e03cSMatthew Dillon }
3025b7d5e03cSMatthew Dillon
3026b7d5e03cSMatthew Dillon if (ar9300_eeprom_get(ahp, EEP_PAPRD_ENABLED)) {
3027b7d5e03cSMatthew Dillon for (i = 0; i < ar9300_rate_size; i++) {
3028b7d5e03cSMatthew Dillon /*
3029b7d5e03cSMatthew Dillon * EEPROM TGT PWR is not same as current TGT PWR,
3030b7d5e03cSMatthew Dillon * so Disable PAPRD for this rate.
3031b7d5e03cSMatthew Dillon * Some of APs might ask to reduce Target Power,
3032b7d5e03cSMatthew Dillon * if target power drops significantly,
3033b7d5e03cSMatthew Dillon * disable PAPRD for that rate.
3034b7d5e03cSMatthew Dillon */
3035b7d5e03cSMatthew Dillon if (tmp_paprd_rate_mask & (1 << i)) {
3036b7d5e03cSMatthew Dillon if (ABS(target_power_val_t2_eep[i], target_power_val_t2[i]) >
3037b7d5e03cSMatthew Dillon paprd_scale_factor)
3038b7d5e03cSMatthew Dillon {
3039b7d5e03cSMatthew Dillon tmp_paprd_rate_mask &= ~(1 << i);
3040b7d5e03cSMatthew Dillon HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
3041b7d5e03cSMatthew Dillon "%s: EEP TPC[%02d] 0x%08x "
3042b7d5e03cSMatthew Dillon "Curr TPC[%02d] 0x%08x mask = 0x%08x\n",
3043b7d5e03cSMatthew Dillon __func__, i, target_power_val_t2_eep[i], i,
3044b7d5e03cSMatthew Dillon target_power_val_t2[i], tmp_paprd_rate_mask);
3045b7d5e03cSMatthew Dillon }
3046b7d5e03cSMatthew Dillon }
3047b7d5e03cSMatthew Dillon
3048b7d5e03cSMatthew Dillon }
3049b7d5e03cSMatthew Dillon HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
3050b7d5e03cSMatthew Dillon "%s: Chan %d After tmp_paprd_rate_mask = 0x%08x\n",
3051b7d5e03cSMatthew Dillon __func__, ichan->channel, tmp_paprd_rate_mask);
3052b7d5e03cSMatthew Dillon if (tmp_ptr) {
3053b7d5e03cSMatthew Dillon *tmp_ptr = tmp_paprd_rate_mask;
3054b7d5e03cSMatthew Dillon }
3055b7d5e03cSMatthew Dillon }
3056b7d5e03cSMatthew Dillon
3057b7d5e03cSMatthew Dillon /* Write target power array to registers */
3058b7d5e03cSMatthew Dillon ar9300_transmit_power_reg_write(ah, target_power_val_t2);
3059b7d5e03cSMatthew Dillon
3060b7d5e03cSMatthew Dillon /* Write target power for self generated frames to the TPC register */
3061b7d5e03cSMatthew Dillon ar9300_selfgen_tpc_reg_write(ah, chan, target_power_val_t2);
3062b7d5e03cSMatthew Dillon
3063b7d5e03cSMatthew Dillon /* GreenTx or Paprd */
3064b7d5e03cSMatthew Dillon if (ah->ah_config.ath_hal_sta_update_tx_pwr_enable ||
3065b7d5e03cSMatthew Dillon AH_PRIVATE(ah)->ah_caps.halPaprdEnabled)
3066b7d5e03cSMatthew Dillon {
3067b7d5e03cSMatthew Dillon if (AR_SREV_POSEIDON(ah)) {
3068b7d5e03cSMatthew Dillon /*For HAL_RSSI_TX_POWER_NONE array*/
3069b7d5e03cSMatthew Dillon OS_MEMCPY(ahp->ah_default_tx_power,
3070b7d5e03cSMatthew Dillon target_power_val_t2,
3071b7d5e03cSMatthew Dillon sizeof(target_power_val_t2));
3072b7d5e03cSMatthew Dillon /* Get defautl tx related register setting for GreenTx */
3073b7d5e03cSMatthew Dillon /* Record OB/DB */
3074b7d5e03cSMatthew Dillon ahp->ah_ob_db1[POSEIDON_STORED_REG_OBDB] =
3075b7d5e03cSMatthew Dillon OS_REG_READ(ah, AR_PHY_65NM_CH0_TXRF2);
3076b7d5e03cSMatthew Dillon /* Record TPC settting */
3077b7d5e03cSMatthew Dillon ahp->ah_ob_db1[POSEIDON_STORED_REG_TPC] =
3078b7d5e03cSMatthew Dillon OS_REG_READ(ah, AR_TPC);
3079b7d5e03cSMatthew Dillon /* Record BB_powertx_rate9 setting */
3080b7d5e03cSMatthew Dillon ahp->ah_ob_db1[POSEIDON_STORED_REG_BB_PWRTX_RATE9] =
3081b7d5e03cSMatthew Dillon OS_REG_READ(ah, AR_PHY_BB_POWERTX_RATE9);
3082b7d5e03cSMatthew Dillon }
3083b7d5e03cSMatthew Dillon }
3084b7d5e03cSMatthew Dillon
3085b7d5e03cSMatthew Dillon /*
3086b7d5e03cSMatthew Dillon * Return tx power used to iwconfig.
3087b7d5e03cSMatthew Dillon * Since power is rate dependent, use one of the indices from the
3088b7d5e03cSMatthew Dillon * AR9300_Rates enum to select an entry from target_power_val_t2[]
3089b7d5e03cSMatthew Dillon * to report.
3090b7d5e03cSMatthew Dillon * Currently returns the power for HT40 MCS 0, HT20 MCS 0, or OFDM 6 Mbps
3091b7d5e03cSMatthew Dillon * as CCK power is less interesting (?).
3092b7d5e03cSMatthew Dillon */
3093b7d5e03cSMatthew Dillon i = ALL_TARGET_LEGACY_6_24; /* legacy */
3094b7d5e03cSMatthew Dillon if (IEEE80211_IS_CHAN_HT40(chan)) {
3095b7d5e03cSMatthew Dillon i = ALL_TARGET_HT40_0_8_16; /* ht40 */
3096b7d5e03cSMatthew Dillon } else if (IEEE80211_IS_CHAN_HT20(chan)) {
3097b7d5e03cSMatthew Dillon i = ALL_TARGET_HT20_0_8_16; /* ht20 */
3098b7d5e03cSMatthew Dillon }
3099b7d5e03cSMatthew Dillon max_power_level = target_power_val_t2[i];
3100b7d5e03cSMatthew Dillon /* Adjusting the ah_max_power_level based on chains and antennaGain*/
3101a20e5e51SMatthew Dillon switch (ar9300_get_ntxchains(((ahp->ah_tx_chainmaskopt > 0) ?
3102a20e5e51SMatthew Dillon ahp->ah_tx_chainmaskopt : ahp->ah_tx_chainmask)))
3103b7d5e03cSMatthew Dillon {
3104b7d5e03cSMatthew Dillon case 1:
3105b7d5e03cSMatthew Dillon break;
3106b7d5e03cSMatthew Dillon case 2:
3107b7d5e03cSMatthew Dillon twice_array_gain = (ahp->twice_antenna_gain >= ahp->twice_antenna_reduction)? 0:
3108b7d5e03cSMatthew Dillon ((int16_t)AH_MIN((ahp->twice_antenna_reduction -
3109b7d5e03cSMatthew Dillon (ahp->twice_antenna_gain + INCREASE_MAXPOW_BY_TWO_CHAIN)), 0));
3110b7d5e03cSMatthew Dillon /* Adjusting maxpower with antennaGain */
3111b7d5e03cSMatthew Dillon max_power_level -= twice_array_gain;
3112b7d5e03cSMatthew Dillon /* Adjusting maxpower based on chain */
3113b7d5e03cSMatthew Dillon max_power_level += INCREASE_MAXPOW_BY_TWO_CHAIN;
3114b7d5e03cSMatthew Dillon break;
3115b7d5e03cSMatthew Dillon case 3:
3116b7d5e03cSMatthew Dillon twice_array_gain = (ahp->twice_antenna_gain >= ahp->twice_antenna_reduction)? 0:
3117b7d5e03cSMatthew Dillon ((int16_t)AH_MIN((ahp->twice_antenna_reduction -
3118b7d5e03cSMatthew Dillon (ahp->twice_antenna_gain + INCREASE_MAXPOW_BY_THREE_CHAIN)), 0));
3119b7d5e03cSMatthew Dillon
3120b7d5e03cSMatthew Dillon /* Adjusting maxpower with antennaGain */
3121b7d5e03cSMatthew Dillon max_power_level -= twice_array_gain;
3122b7d5e03cSMatthew Dillon /* Adjusting maxpower based on chain */
3123b7d5e03cSMatthew Dillon max_power_level += INCREASE_MAXPOW_BY_THREE_CHAIN;
3124b7d5e03cSMatthew Dillon break;
3125b7d5e03cSMatthew Dillon default:
3126b7d5e03cSMatthew Dillon HALASSERT(0); /* Unsupported number of chains */
3127b7d5e03cSMatthew Dillon }
3128b7d5e03cSMatthew Dillon AH_PRIVATE(ah)->ah_maxPowerLevel = (int8_t)max_power_level;
3129b7d5e03cSMatthew Dillon
3130b7d5e03cSMatthew Dillon ar9300_calibration_apply(ah, ichan->channel);
3131b7d5e03cSMatthew Dillon #undef ABS
3132b7d5e03cSMatthew Dillon
3133b7d5e03cSMatthew Dillon /* Handle per packet TPC initializations */
3134b7d5e03cSMatthew Dillon if (ah->ah_config.ath_hal_desc_tpc) {
3135b7d5e03cSMatthew Dillon /* Transmit Power per-rate per-chain are computed here. A separate
3136b7d5e03cSMatthew Dillon * power table is maintained for different MIMO modes (i.e. TXBF ON,
3137b7d5e03cSMatthew Dillon * STBC) to enable easy lookup during packet transmit.
3138b7d5e03cSMatthew Dillon * The reason for maintaing each of these tables per chain is that
3139b7d5e03cSMatthew Dillon * the transmit power used for different number of chains is different
3140b7d5e03cSMatthew Dillon * depending on whether the power has been limited by the target power,
3141b7d5e03cSMatthew Dillon * the regulatory domain or the CTL limits.
3142b7d5e03cSMatthew Dillon */
3143b7d5e03cSMatthew Dillon u_int mode = ath_hal_get_curmode(ah, chan);
3144b7d5e03cSMatthew Dillon u_int32_t val = 0;
3145b7d5e03cSMatthew Dillon u_int8_t chainmasks[AR9300_MAX_CHAINS] =
3146b7d5e03cSMatthew Dillon {OSPREY_1_CHAINMASK, OSPREY_2LOHI_CHAINMASK, OSPREY_3_CHAINMASK};
3147b7d5e03cSMatthew Dillon for (i = 0; i < AR9300_MAX_CHAINS; i++) {
3148b7d5e03cSMatthew Dillon OS_MEMCPY(target_power_val_t2, target_power_val_t2_eep,
3149b7d5e03cSMatthew Dillon sizeof(target_power_val_t2_eep));
3150b7d5e03cSMatthew Dillon ar9300_eeprom_set_power_per_rate_table(ah, p_eep_data, chan,
3151b7d5e03cSMatthew Dillon target_power_val_t2, cfg_ctl,
3152b7d5e03cSMatthew Dillon antenna_reduction,
3153b7d5e03cSMatthew Dillon twice_max_regulatory_power,
3154b7d5e03cSMatthew Dillon power_limit, chainmasks[i]);
3155b7d5e03cSMatthew Dillon HALDEBUG(ah, HAL_DEBUG_POWER_MGMT,
3156b7d5e03cSMatthew Dillon " Channel = %d Chainmask = %d, Upper Limit = [%2d.%1d dBm]\n",
3157b7d5e03cSMatthew Dillon ichan->channel, i, ahp->upper_limit[i]/2,
3158b7d5e03cSMatthew Dillon ahp->upper_limit[i]%2 * 5);
3159b7d5e03cSMatthew Dillon ar9300_init_rate_txpower(ah, mode, chan, target_power_val_t2,
3160b7d5e03cSMatthew Dillon chainmasks[i]);
3161b7d5e03cSMatthew Dillon
3162b7d5e03cSMatthew Dillon }
3163b7d5e03cSMatthew Dillon
3164b7d5e03cSMatthew Dillon /* Enable TPC */
3165b7d5e03cSMatthew Dillon OS_REG_WRITE(ah, AR_PHY_PWRTX_MAX, AR_PHY_PWRTX_MAX_TPC_ENABLE);
3166b7d5e03cSMatthew Dillon /*
3167b7d5e03cSMatthew Dillon * Disable per chain power reduction since we are already
3168b7d5e03cSMatthew Dillon * accounting for this in our calculations
3169b7d5e03cSMatthew Dillon */
3170b7d5e03cSMatthew Dillon val = OS_REG_READ(ah, AR_PHY_POWER_TX_SUB);
3171b7d5e03cSMatthew Dillon if (AR_SREV_WASP(ah)) {
3172b7d5e03cSMatthew Dillon OS_REG_WRITE(ah, AR_PHY_POWER_TX_SUB,
3173b7d5e03cSMatthew Dillon val & AR_PHY_POWER_TX_SUB_2_DISABLE);
3174b7d5e03cSMatthew Dillon } else {
3175b7d5e03cSMatthew Dillon OS_REG_WRITE(ah, AR_PHY_POWER_TX_SUB,
3176b7d5e03cSMatthew Dillon val & AR_PHY_POWER_TX_SUB_3_DISABLE);
3177b7d5e03cSMatthew Dillon }
3178b7d5e03cSMatthew Dillon }
3179b7d5e03cSMatthew Dillon
3180b7d5e03cSMatthew Dillon return HAL_OK;
3181b7d5e03cSMatthew Dillon }
3182b7d5e03cSMatthew Dillon
3183b7d5e03cSMatthew Dillon /**************************************************************
3184b7d5e03cSMatthew Dillon * ar9300_eeprom_set_addac
3185b7d5e03cSMatthew Dillon *
3186b7d5e03cSMatthew Dillon * Set the ADDAC from eeprom.
3187b7d5e03cSMatthew Dillon */
3188b7d5e03cSMatthew Dillon void
ar9300_eeprom_set_addac(struct ath_hal * ah,struct ieee80211_channel * chan)3189b7d5e03cSMatthew Dillon ar9300_eeprom_set_addac(struct ath_hal *ah, struct ieee80211_channel *chan)
3190b7d5e03cSMatthew Dillon {
3191b7d5e03cSMatthew Dillon
3192b7d5e03cSMatthew Dillon HALDEBUG(AH_NULL, HAL_DEBUG_UNMASKABLE,
3193b7d5e03cSMatthew Dillon "FIXME: ar9300_eeprom_def_set_addac called\n");
3194b7d5e03cSMatthew Dillon #if 0
3195b7d5e03cSMatthew Dillon MODAL_EEPDEF_HEADER *p_modal;
3196b7d5e03cSMatthew Dillon struct ath_hal_9300 *ahp = AH9300(ah);
3197b7d5e03cSMatthew Dillon ar9300_eeprom_t *eep = &ahp->ah_eeprom.def;
3198b7d5e03cSMatthew Dillon u_int8_t biaslevel;
3199b7d5e03cSMatthew Dillon
3200b7d5e03cSMatthew Dillon if (AH_PRIVATE(ah)->ah_macVersion != AR_SREV_VERSION_SOWL) {
3201b7d5e03cSMatthew Dillon return;
3202b7d5e03cSMatthew Dillon }
3203b7d5e03cSMatthew Dillon
3204b7d5e03cSMatthew Dillon HALASSERT(owl_get_eepdef_ver(ahp) == AR9300_EEP_VER);
3205b7d5e03cSMatthew Dillon
3206b7d5e03cSMatthew Dillon /* Xpa bias levels in eeprom are valid from rev 14.7 */
3207b7d5e03cSMatthew Dillon if (owl_get_eepdef_rev(ahp) < AR9300_EEP_MINOR_VER_7) {
3208b7d5e03cSMatthew Dillon return;
3209b7d5e03cSMatthew Dillon }
3210b7d5e03cSMatthew Dillon
3211b7d5e03cSMatthew Dillon if (ahp->ah_emu_eeprom) {
3212b7d5e03cSMatthew Dillon return;
3213b7d5e03cSMatthew Dillon }
3214b7d5e03cSMatthew Dillon
3215b7d5e03cSMatthew Dillon p_modal = &(eep->modal_header[IEEE80211_IS_CHAN_2GHZ(chan)]);
3216b7d5e03cSMatthew Dillon
3217b7d5e03cSMatthew Dillon if (p_modal->xpa_bias_lvl != 0xff) {
3218b7d5e03cSMatthew Dillon biaslevel = p_modal->xpa_bias_lvl;
3219b7d5e03cSMatthew Dillon } else {
3220b7d5e03cSMatthew Dillon /* Use freqeuncy specific xpa bias level */
3221b7d5e03cSMatthew Dillon u_int16_t reset_freq_bin, freq_bin, freq_count = 0;
3222b7d5e03cSMatthew Dillon CHAN_CENTERS centers;
3223b7d5e03cSMatthew Dillon
3224b7d5e03cSMatthew Dillon ar9300_get_channel_centers(ah, chan, ¢ers);
3225b7d5e03cSMatthew Dillon
3226b7d5e03cSMatthew Dillon reset_freq_bin = FREQ2FBIN(centers.synth_center, IEEE80211_IS_CHAN_2GHZ(chan));
3227b7d5e03cSMatthew Dillon freq_bin = p_modal->xpa_bias_lvl_freq[0] & 0xff;
3228b7d5e03cSMatthew Dillon biaslevel = (u_int8_t)(p_modal->xpa_bias_lvl_freq[0] >> 14);
3229b7d5e03cSMatthew Dillon
3230b7d5e03cSMatthew Dillon freq_count++;
3231b7d5e03cSMatthew Dillon
3232b7d5e03cSMatthew Dillon while (freq_count < 3) {
3233b7d5e03cSMatthew Dillon if (p_modal->xpa_bias_lvl_freq[freq_count] == 0x0) {
3234b7d5e03cSMatthew Dillon break;
3235b7d5e03cSMatthew Dillon }
3236b7d5e03cSMatthew Dillon
3237b7d5e03cSMatthew Dillon freq_bin = p_modal->xpa_bias_lvl_freq[freq_count] & 0xff;
3238b7d5e03cSMatthew Dillon if (reset_freq_bin >= freq_bin) {
3239b7d5e03cSMatthew Dillon biaslevel =
3240b7d5e03cSMatthew Dillon (u_int8_t)(p_modal->xpa_bias_lvl_freq[freq_count] >> 14);
3241b7d5e03cSMatthew Dillon } else {
3242b7d5e03cSMatthew Dillon break;
3243b7d5e03cSMatthew Dillon }
3244b7d5e03cSMatthew Dillon freq_count++;
3245b7d5e03cSMatthew Dillon }
3246b7d5e03cSMatthew Dillon }
3247b7d5e03cSMatthew Dillon
3248b7d5e03cSMatthew Dillon /* Apply bias level to the ADDAC values in the INI array */
3249b7d5e03cSMatthew Dillon if (IEEE80211_IS_CHAN_2GHZ(chan)) {
3250b7d5e03cSMatthew Dillon INI_RA(&ahp->ah_ini_addac, 7, 1) =
3251b7d5e03cSMatthew Dillon (INI_RA(&ahp->ah_ini_addac, 7, 1) & (~0x18)) | biaslevel << 3;
3252b7d5e03cSMatthew Dillon } else {
3253b7d5e03cSMatthew Dillon INI_RA(&ahp->ah_ini_addac, 6, 1) =
3254b7d5e03cSMatthew Dillon (INI_RA(&ahp->ah_ini_addac, 6, 1) & (~0xc0)) | biaslevel << 6;
3255b7d5e03cSMatthew Dillon }
3256b7d5e03cSMatthew Dillon #endif
3257b7d5e03cSMatthew Dillon }
3258b7d5e03cSMatthew Dillon
3259b7d5e03cSMatthew Dillon u_int
ar9300_eeprom_dump_support(struct ath_hal * ah,void ** pp_e)3260b7d5e03cSMatthew Dillon ar9300_eeprom_dump_support(struct ath_hal *ah, void **pp_e)
3261b7d5e03cSMatthew Dillon {
3262b7d5e03cSMatthew Dillon *pp_e = &(AH9300(ah)->ah_eeprom);
3263b7d5e03cSMatthew Dillon return sizeof(ar9300_eeprom_t);
3264b7d5e03cSMatthew Dillon }
3265b7d5e03cSMatthew Dillon
3266b7d5e03cSMatthew Dillon u_int8_t
ar9300_eeprom_get_num_ant_config(struct ath_hal_9300 * ahp,HAL_FREQ_BAND freq_band)3267b7d5e03cSMatthew Dillon ar9300_eeprom_get_num_ant_config(struct ath_hal_9300 *ahp,
3268b7d5e03cSMatthew Dillon HAL_FREQ_BAND freq_band)
3269b7d5e03cSMatthew Dillon {
3270b7d5e03cSMatthew Dillon #if 0
3271b7d5e03cSMatthew Dillon ar9300_eeprom_t *eep = &ahp->ah_eeprom.def;
3272b7d5e03cSMatthew Dillon MODAL_EEPDEF_HEADER *p_modal =
3273b7d5e03cSMatthew Dillon &(eep->modal_header[HAL_FREQ_BAND_2GHZ == freq_band]);
3274b7d5e03cSMatthew Dillon BASE_EEPDEF_HEADER *p_base = &eep->base_eep_header;
3275b7d5e03cSMatthew Dillon u_int8_t num_ant_config;
3276b7d5e03cSMatthew Dillon
3277b7d5e03cSMatthew Dillon num_ant_config = 1; /* default antenna configuration */
3278b7d5e03cSMatthew Dillon
3279b7d5e03cSMatthew Dillon if (p_base->version >= 0x0E0D) {
3280b7d5e03cSMatthew Dillon if (p_modal->use_ant1) {
3281b7d5e03cSMatthew Dillon num_ant_config += 1;
3282b7d5e03cSMatthew Dillon }
3283b7d5e03cSMatthew Dillon }
3284b7d5e03cSMatthew Dillon
3285b7d5e03cSMatthew Dillon return num_ant_config;
3286b7d5e03cSMatthew Dillon #else
3287b7d5e03cSMatthew Dillon return 1;
3288b7d5e03cSMatthew Dillon #endif
3289b7d5e03cSMatthew Dillon }
3290b7d5e03cSMatthew Dillon
3291b7d5e03cSMatthew Dillon 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)3292b7d5e03cSMatthew Dillon ar9300_eeprom_get_ant_cfg(struct ath_hal_9300 *ahp,
3293b7d5e03cSMatthew Dillon const struct ieee80211_channel *chan,
3294b7d5e03cSMatthew Dillon u_int8_t index, u_int16_t *config)
3295b7d5e03cSMatthew Dillon {
3296b7d5e03cSMatthew Dillon #if 0
3297b7d5e03cSMatthew Dillon ar9300_eeprom_t *eep = &ahp->ah_eeprom.def;
3298b7d5e03cSMatthew Dillon MODAL_EEPDEF_HEADER *p_modal = &(eep->modal_header[IEEE80211_IS_CHAN_2GHZ(chan)]);
3299b7d5e03cSMatthew Dillon BASE_EEPDEF_HEADER *p_base = &eep->base_eep_header;
3300b7d5e03cSMatthew Dillon
3301b7d5e03cSMatthew Dillon switch (index) {
3302b7d5e03cSMatthew Dillon case 0:
3303b7d5e03cSMatthew Dillon *config = p_modal->ant_ctrl_common & 0xFFFF;
3304b7d5e03cSMatthew Dillon return HAL_OK;
3305b7d5e03cSMatthew Dillon case 1:
3306b7d5e03cSMatthew Dillon if (p_base->version >= 0x0E0D) {
3307b7d5e03cSMatthew Dillon if (p_modal->use_ant1) {
3308b7d5e03cSMatthew Dillon *config = ((p_modal->ant_ctrl_common & 0xFFFF0000) >> 16);
3309b7d5e03cSMatthew Dillon return HAL_OK;
3310b7d5e03cSMatthew Dillon }
3311b7d5e03cSMatthew Dillon }
3312b7d5e03cSMatthew Dillon break;
3313b7d5e03cSMatthew Dillon default:
3314b7d5e03cSMatthew Dillon break;
3315b7d5e03cSMatthew Dillon }
3316b7d5e03cSMatthew Dillon #endif
3317b7d5e03cSMatthew Dillon return HAL_EINVAL;
3318b7d5e03cSMatthew Dillon }
3319b7d5e03cSMatthew Dillon
3320b7d5e03cSMatthew Dillon u_int8_t*
ar9300_eeprom_get_cust_data(struct ath_hal_9300 * ahp)3321b7d5e03cSMatthew Dillon ar9300_eeprom_get_cust_data(struct ath_hal_9300 *ahp)
3322b7d5e03cSMatthew Dillon {
3323b7d5e03cSMatthew Dillon return (u_int8_t *)ahp;
3324b7d5e03cSMatthew Dillon }
3325b7d5e03cSMatthew Dillon
3326b7d5e03cSMatthew Dillon #ifdef UNUSED
3327b7d5e03cSMatthew Dillon static inline HAL_STATUS
ar9300_check_eeprom(struct ath_hal * ah)3328b7d5e03cSMatthew Dillon ar9300_check_eeprom(struct ath_hal *ah)
3329b7d5e03cSMatthew Dillon {
3330b7d5e03cSMatthew Dillon #if 0
3331b7d5e03cSMatthew Dillon u_int32_t sum = 0, el;
3332b7d5e03cSMatthew Dillon u_int16_t *eepdata;
3333b7d5e03cSMatthew Dillon int i;
3334b7d5e03cSMatthew Dillon struct ath_hal_9300 *ahp = AH9300(ah);
3335b7d5e03cSMatthew Dillon HAL_BOOL need_swap = AH_FALSE;
3336b7d5e03cSMatthew Dillon ar9300_eeprom_t *eep = (ar9300_eeprom_t *)&ahp->ah_eeprom.def;
3337b7d5e03cSMatthew Dillon u_int16_t magic, magic2;
3338b7d5e03cSMatthew Dillon int addr;
3339b7d5e03cSMatthew Dillon u_int16_t temp;
3340b7d5e03cSMatthew Dillon
3341b7d5e03cSMatthew Dillon /*
3342b7d5e03cSMatthew Dillon ** We need to check the EEPROM data regardless of if it's in flash or
3343b7d5e03cSMatthew Dillon ** in EEPROM.
3344b7d5e03cSMatthew Dillon */
3345b7d5e03cSMatthew Dillon
3346b7d5e03cSMatthew Dillon if (!ahp->ah_priv.priv.ah_eeprom_read(
3347b7d5e03cSMatthew Dillon ah, AR9300_EEPROM_MAGIC_OFFSET, &magic))
3348b7d5e03cSMatthew Dillon {
3349b7d5e03cSMatthew Dillon HALDEBUG(ah, HAL_DEBUG_EEPROM, "%s: Reading Magic # failed\n", __func__);
3350b7d5e03cSMatthew Dillon return AH_FALSE;
3351b7d5e03cSMatthew Dillon }
3352b7d5e03cSMatthew Dillon
3353b7d5e03cSMatthew Dillon HALDEBUG(ah, HAL_DEBUG_EEPROM, "%s: Read Magic = 0x%04X\n", __func__, magic);
3354b7d5e03cSMatthew Dillon
3355b7d5e03cSMatthew Dillon if (!ar9300_eep_data_in_flash(ah)) {
3356b7d5e03cSMatthew Dillon
3357b7d5e03cSMatthew Dillon if (magic != AR9300_EEPROM_MAGIC) {
3358b7d5e03cSMatthew Dillon magic2 = SWAP16(magic);
3359b7d5e03cSMatthew Dillon
3360b7d5e03cSMatthew Dillon if (magic2 == AR9300_EEPROM_MAGIC) {
3361b7d5e03cSMatthew Dillon need_swap = AH_TRUE;
3362b7d5e03cSMatthew Dillon eepdata = (u_int16_t *)(&ahp->ah_eeprom);
3363b7d5e03cSMatthew Dillon
3364b7d5e03cSMatthew Dillon for (addr = 0;
3365b7d5e03cSMatthew Dillon addr < sizeof(ar9300_eeprom_t) / sizeof(u_int16_t);
3366b7d5e03cSMatthew Dillon addr++)
3367b7d5e03cSMatthew Dillon {
3368b7d5e03cSMatthew Dillon temp = SWAP16(*eepdata);
3369b7d5e03cSMatthew Dillon *eepdata = temp;
3370b7d5e03cSMatthew Dillon eepdata++;
3371b7d5e03cSMatthew Dillon
3372b7d5e03cSMatthew Dillon HALDEBUG(ah, HAL_DEBUG_EEPROM_DUMP, "0x%04X ", *eepdata);
3373b7d5e03cSMatthew Dillon if (((addr + 1) % 6) == 0) {
3374b7d5e03cSMatthew Dillon HALDEBUG(ah, HAL_DEBUG_EEPROM_DUMP, "\n");
3375b7d5e03cSMatthew Dillon }
3376b7d5e03cSMatthew Dillon }
3377b7d5e03cSMatthew Dillon } else {
3378b7d5e03cSMatthew Dillon HALDEBUG(ah, HAL_DEBUG_EEPROM,
3379b7d5e03cSMatthew Dillon "Invalid EEPROM Magic. endianness missmatch.\n");
3380b7d5e03cSMatthew Dillon return HAL_EEBADSUM;
3381b7d5e03cSMatthew Dillon }
3382b7d5e03cSMatthew Dillon }
3383b7d5e03cSMatthew Dillon } else {
3384b7d5e03cSMatthew Dillon HALDEBUG(ah, HAL_DEBUG_EEPROM,
3385b7d5e03cSMatthew Dillon "EEPROM being read from flash @0x%p\n", AH_PRIVATE(ah)->ah_st);
3386b7d5e03cSMatthew Dillon }
3387b7d5e03cSMatthew Dillon
3388b7d5e03cSMatthew Dillon HALDEBUG(ah, HAL_DEBUG_EEPROM, "need_swap = %s.\n", need_swap?"True":"False");
3389b7d5e03cSMatthew Dillon
3390b7d5e03cSMatthew Dillon if (need_swap) {
3391b7d5e03cSMatthew Dillon el = SWAP16(ahp->ah_eeprom.def.base_eep_header.length);
3392b7d5e03cSMatthew Dillon } else {
3393b7d5e03cSMatthew Dillon el = ahp->ah_eeprom.def.base_eep_header.length;
3394b7d5e03cSMatthew Dillon }
3395b7d5e03cSMatthew Dillon
3396b7d5e03cSMatthew Dillon eepdata = (u_int16_t *)(&ahp->ah_eeprom.def);
3397b7d5e03cSMatthew Dillon for (i = 0;
3398b7d5e03cSMatthew Dillon i < AH_MIN(el, sizeof(ar9300_eeprom_t)) / sizeof(u_int16_t);
3399b7d5e03cSMatthew Dillon i++) {
3400b7d5e03cSMatthew Dillon sum ^= *eepdata++;
3401b7d5e03cSMatthew Dillon }
3402b7d5e03cSMatthew Dillon
3403b7d5e03cSMatthew Dillon if (need_swap) {
3404b7d5e03cSMatthew Dillon /*
3405b7d5e03cSMatthew Dillon * preddy: EEPROM endianness does not match. So change it
3406b7d5e03cSMatthew Dillon * 8bit values in eeprom data structure does not need to be swapped
3407b7d5e03cSMatthew Dillon * Only >8bits (16 & 32) values need to be swapped
3408b7d5e03cSMatthew Dillon * If a new 16 or 32 bit field is added to the EEPROM contents,
3409b7d5e03cSMatthew Dillon * please make sure to swap the field here
3410b7d5e03cSMatthew Dillon */
3411b7d5e03cSMatthew Dillon u_int32_t integer, j;
3412b7d5e03cSMatthew Dillon u_int16_t word;
3413b7d5e03cSMatthew Dillon
3414b7d5e03cSMatthew Dillon HALDEBUG(ah, HAL_DEBUG_EEPROM,
3415b7d5e03cSMatthew Dillon "EEPROM Endianness is not native.. Changing \n");
3416b7d5e03cSMatthew Dillon
3417b7d5e03cSMatthew Dillon /* convert Base Eep header */
3418b7d5e03cSMatthew Dillon word = SWAP16(eep->base_eep_header.length);
3419b7d5e03cSMatthew Dillon eep->base_eep_header.length = word;
3420b7d5e03cSMatthew Dillon
3421b7d5e03cSMatthew Dillon word = SWAP16(eep->base_eep_header.checksum);
3422b7d5e03cSMatthew Dillon eep->base_eep_header.checksum = word;
3423b7d5e03cSMatthew Dillon
3424b7d5e03cSMatthew Dillon word = SWAP16(eep->base_eep_header.version);
3425b7d5e03cSMatthew Dillon eep->base_eep_header.version = word;
3426b7d5e03cSMatthew Dillon
3427b7d5e03cSMatthew Dillon word = SWAP16(eep->base_eep_header.reg_dmn[0]);
3428b7d5e03cSMatthew Dillon eep->base_eep_header.reg_dmn[0] = word;
3429b7d5e03cSMatthew Dillon
3430b7d5e03cSMatthew Dillon word = SWAP16(eep->base_eep_header.reg_dmn[1]);
3431b7d5e03cSMatthew Dillon eep->base_eep_header.reg_dmn[1] = word;
3432b7d5e03cSMatthew Dillon
3433b7d5e03cSMatthew Dillon word = SWAP16(eep->base_eep_header.rf_silent);
3434b7d5e03cSMatthew Dillon eep->base_eep_header.rf_silent = word;
3435b7d5e03cSMatthew Dillon
3436b7d5e03cSMatthew Dillon word = SWAP16(eep->base_eep_header.blue_tooth_options);
3437b7d5e03cSMatthew Dillon eep->base_eep_header.blue_tooth_options = word;
3438b7d5e03cSMatthew Dillon
3439b7d5e03cSMatthew Dillon word = SWAP16(eep->base_eep_header.device_cap);
3440b7d5e03cSMatthew Dillon eep->base_eep_header.device_cap = word;
3441b7d5e03cSMatthew Dillon
3442b7d5e03cSMatthew Dillon /* convert Modal Eep header */
3443b7d5e03cSMatthew Dillon for (j = 0; j < ARRAY_LENGTH(eep->modal_header); j++) {
3444b7d5e03cSMatthew Dillon MODAL_EEPDEF_HEADER *p_modal = &eep->modal_header[j];
3445b7d5e03cSMatthew Dillon integer = SWAP32(p_modal->ant_ctrl_common);
3446b7d5e03cSMatthew Dillon p_modal->ant_ctrl_common = integer;
3447b7d5e03cSMatthew Dillon
3448b7d5e03cSMatthew Dillon for (i = 0; i < AR9300_MAX_CHAINS; i++) {
3449b7d5e03cSMatthew Dillon integer = SWAP32(p_modal->ant_ctrl_chain[i]);
3450b7d5e03cSMatthew Dillon p_modal->ant_ctrl_chain[i] = integer;
3451b7d5e03cSMatthew Dillon }
3452b7d5e03cSMatthew Dillon
3453b7d5e03cSMatthew Dillon for (i = 0; i < AR9300_EEPROM_MODAL_SPURS; i++) {
3454b7d5e03cSMatthew Dillon word = SWAP16(p_modal->spur_chans[i].spur_chan);
3455b7d5e03cSMatthew Dillon p_modal->spur_chans[i].spur_chan = word;
3456b7d5e03cSMatthew Dillon }
3457b7d5e03cSMatthew Dillon }
3458b7d5e03cSMatthew Dillon }
3459b7d5e03cSMatthew Dillon
3460b7d5e03cSMatthew Dillon /* Check CRC - Attach should fail on a bad checksum */
3461b7d5e03cSMatthew Dillon if (sum != 0xffff || owl_get_eepdef_ver(ahp) != AR9300_EEP_VER ||
3462b7d5e03cSMatthew Dillon owl_get_eepdef_rev(ahp) < AR9300_EEP_NO_BACK_VER) {
3463b7d5e03cSMatthew Dillon HALDEBUG(ah, HAL_DEBUG_EEPROM,
3464b7d5e03cSMatthew Dillon "Bad EEPROM checksum 0x%x or revision 0x%04x\n",
3465b7d5e03cSMatthew Dillon sum, owl_get_eepdef_ver(ahp));
3466b7d5e03cSMatthew Dillon return HAL_EEBADSUM;
3467b7d5e03cSMatthew Dillon }
3468b7d5e03cSMatthew Dillon #ifdef EEPROM_DUMP
3469b7d5e03cSMatthew Dillon ar9300_eeprom_def_dump(ah, eep);
3470b7d5e03cSMatthew Dillon #endif
3471b7d5e03cSMatthew Dillon
3472b7d5e03cSMatthew Dillon #if 0
3473b7d5e03cSMatthew Dillon #ifdef AH_AR9300_OVRD_TGT_PWR
3474b7d5e03cSMatthew Dillon
3475b7d5e03cSMatthew Dillon /*
3476b7d5e03cSMatthew Dillon * 14.4 EEPROM contains low target powers.
3477b7d5e03cSMatthew Dillon * Hardcode until EEPROM > 14.4
3478b7d5e03cSMatthew Dillon */
3479b7d5e03cSMatthew Dillon if (owl_get_eepdef_ver(ahp) == 14 && owl_get_eepdef_rev(ahp) <= 4) {
3480b7d5e03cSMatthew Dillon MODAL_EEPDEF_HEADER *p_modal;
3481b7d5e03cSMatthew Dillon
3482b7d5e03cSMatthew Dillon #ifdef EEPROM_DUMP
3483b7d5e03cSMatthew Dillon HALDEBUG(ah, HAL_DEBUG_POWER_OVERRIDE, "Original Target Powers\n");
3484b7d5e03cSMatthew Dillon ar9300_eep_def_dump_tgt_power(ah, eep);
3485b7d5e03cSMatthew Dillon #endif
3486b7d5e03cSMatthew Dillon HALDEBUG(ah, HAL_DEBUG_POWER_OVERRIDE,
3487b7d5e03cSMatthew Dillon "Override Target Powers. EEPROM Version is %d.%d, "
3488b7d5e03cSMatthew Dillon "Device Type %d\n",
3489b7d5e03cSMatthew Dillon owl_get_eepdef_ver(ahp),
3490b7d5e03cSMatthew Dillon owl_get_eepdef_rev(ahp),
3491b7d5e03cSMatthew Dillon eep->base_eep_header.device_type);
3492b7d5e03cSMatthew Dillon
3493b7d5e03cSMatthew Dillon
3494b7d5e03cSMatthew Dillon ar9300_eep_def_override_tgt_power(ah, eep);
3495b7d5e03cSMatthew Dillon
3496b7d5e03cSMatthew Dillon if (eep->base_eep_header.device_type == 5) {
3497b7d5e03cSMatthew Dillon /* for xb72 only: improve transmit EVM for interop */
3498b7d5e03cSMatthew Dillon p_modal = &eep->modal_header[1];
3499b7d5e03cSMatthew Dillon p_modal->tx_frame_to_data_start = 0x23;
3500b7d5e03cSMatthew Dillon p_modal->tx_frame_to_xpa_on = 0x23;
3501b7d5e03cSMatthew Dillon p_modal->tx_frame_to_pa_on = 0x23;
3502b7d5e03cSMatthew Dillon }
3503b7d5e03cSMatthew Dillon
3504b7d5e03cSMatthew Dillon #ifdef EEPROM_DUMP
3505b7d5e03cSMatthew Dillon HALDEBUG(ah, HAL_DEBUG_POWER_OVERRIDE, "Modified Target Powers\n");
3506b7d5e03cSMatthew Dillon ar9300_eep_def_dump_tgt_power(ah, eep);
3507b7d5e03cSMatthew Dillon #endif
3508b7d5e03cSMatthew Dillon }
3509b7d5e03cSMatthew Dillon #endif /* AH_AR9300_OVRD_TGT_PWR */
3510b7d5e03cSMatthew Dillon #endif
3511b7d5e03cSMatthew Dillon #endif
3512b7d5e03cSMatthew Dillon return HAL_OK;
3513b7d5e03cSMatthew Dillon }
3514b7d5e03cSMatthew Dillon #endif
3515b7d5e03cSMatthew Dillon
3516b7d5e03cSMatthew Dillon static u_int16_t
ar9300_eeprom_get_spur_chan(struct ath_hal * ah,int i,HAL_BOOL is_2ghz)3517b7d5e03cSMatthew Dillon ar9300_eeprom_get_spur_chan(struct ath_hal *ah, int i, HAL_BOOL is_2ghz)
3518b7d5e03cSMatthew Dillon {
3519b7d5e03cSMatthew Dillon u_int16_t spur_val = AR_NO_SPUR;
3520b7d5e03cSMatthew Dillon #if 0
3521b7d5e03cSMatthew Dillon struct ath_hal_9300 *ahp = AH9300(ah);
3522b7d5e03cSMatthew Dillon ar9300_eeprom_t *eep = (ar9300_eeprom_t *)&ahp->ah_eeprom;
3523b7d5e03cSMatthew Dillon
3524b7d5e03cSMatthew Dillon HALASSERT(i < AR_EEPROM_MODAL_SPURS );
3525b7d5e03cSMatthew Dillon
3526b7d5e03cSMatthew Dillon HALDEBUG(ah, HAL_DEBUG_ANI,
3527b7d5e03cSMatthew Dillon "Getting spur idx %d is2Ghz. %d val %x\n",
3528b7d5e03cSMatthew Dillon i, is_2ghz,
3529b7d5e03cSMatthew Dillon AH_PRIVATE(ah)->ah_config.ath_hal_spur_chans[i][is_2ghz]);
3530b7d5e03cSMatthew Dillon
3531b7d5e03cSMatthew Dillon switch (AH_PRIVATE(ah)->ah_config.ath_hal_spur_mode) {
3532b7d5e03cSMatthew Dillon case SPUR_DISABLE:
3533b7d5e03cSMatthew Dillon /* returns AR_NO_SPUR */
3534b7d5e03cSMatthew Dillon break;
3535b7d5e03cSMatthew Dillon case SPUR_ENABLE_IOCTL:
3536b7d5e03cSMatthew Dillon spur_val = AH_PRIVATE(ah)->ah_config.ath_hal_spur_chans[i][is_2ghz];
3537b7d5e03cSMatthew Dillon HALDEBUG(ah, HAL_DEBUG_ANI,
3538b7d5e03cSMatthew Dillon "Getting spur val from new loc. %d\n", spur_val);
3539b7d5e03cSMatthew Dillon break;
3540b7d5e03cSMatthew Dillon case SPUR_ENABLE_EEPROM:
3541b7d5e03cSMatthew Dillon spur_val = eep->modal_header[is_2ghz].spur_chans[i].spur_chan;
3542b7d5e03cSMatthew Dillon break;
3543b7d5e03cSMatthew Dillon
3544b7d5e03cSMatthew Dillon }
3545b7d5e03cSMatthew Dillon #endif
3546b7d5e03cSMatthew Dillon return spur_val;
3547b7d5e03cSMatthew Dillon }
3548b7d5e03cSMatthew Dillon
3549b7d5e03cSMatthew Dillon #ifdef UNUSED
3550b7d5e03cSMatthew Dillon static inline HAL_BOOL
ar9300_fill_eeprom(struct ath_hal * ah)3551b7d5e03cSMatthew Dillon ar9300_fill_eeprom(struct ath_hal *ah)
3552b7d5e03cSMatthew Dillon {
3553b7d5e03cSMatthew Dillon return ar9300_eeprom_restore(ah);
3554b7d5e03cSMatthew Dillon }
3555b7d5e03cSMatthew Dillon #endif
3556b7d5e03cSMatthew Dillon
3557b7d5e03cSMatthew Dillon u_int16_t
ar9300_eeprom_struct_size(void)3558b7d5e03cSMatthew Dillon ar9300_eeprom_struct_size(void)
3559b7d5e03cSMatthew Dillon {
3560b7d5e03cSMatthew Dillon return sizeof(ar9300_eeprom_t);
3561b7d5e03cSMatthew Dillon }
3562b7d5e03cSMatthew Dillon
ar9300_eeprom_struct_default_many(void)3563b7d5e03cSMatthew Dillon int ar9300_eeprom_struct_default_many(void)
3564b7d5e03cSMatthew Dillon {
3565b7d5e03cSMatthew Dillon return ARRAY_LENGTH(default9300);
3566b7d5e03cSMatthew Dillon }
3567b7d5e03cSMatthew Dillon
3568b7d5e03cSMatthew Dillon
3569b7d5e03cSMatthew Dillon ar9300_eeprom_t *
ar9300_eeprom_struct_default(int default_index)3570b7d5e03cSMatthew Dillon ar9300_eeprom_struct_default(int default_index)
3571b7d5e03cSMatthew Dillon {
3572b7d5e03cSMatthew Dillon if (default_index >= 0 &&
3573b7d5e03cSMatthew Dillon default_index < ARRAY_LENGTH(default9300))
3574b7d5e03cSMatthew Dillon {
3575b7d5e03cSMatthew Dillon return default9300[default_index];
3576b7d5e03cSMatthew Dillon } else {
3577b7d5e03cSMatthew Dillon return 0;
3578b7d5e03cSMatthew Dillon }
3579b7d5e03cSMatthew Dillon }
3580b7d5e03cSMatthew Dillon
3581b7d5e03cSMatthew Dillon ar9300_eeprom_t *
ar9300_eeprom_struct_default_find_by_id(int id)3582b7d5e03cSMatthew Dillon ar9300_eeprom_struct_default_find_by_id(int id)
3583b7d5e03cSMatthew Dillon {
3584b7d5e03cSMatthew Dillon int it;
3585b7d5e03cSMatthew Dillon
3586b7d5e03cSMatthew Dillon for (it = 0; it < ARRAY_LENGTH(default9300); it++) {
3587b7d5e03cSMatthew Dillon if (default9300[it] != 0 && default9300[it]->template_version == id) {
3588b7d5e03cSMatthew Dillon return default9300[it];
3589b7d5e03cSMatthew Dillon }
3590b7d5e03cSMatthew Dillon }
3591b7d5e03cSMatthew Dillon return 0;
3592b7d5e03cSMatthew Dillon }
3593b7d5e03cSMatthew Dillon
3594b7d5e03cSMatthew Dillon
3595b7d5e03cSMatthew Dillon HAL_BOOL
ar9300_calibration_data_read_flash(struct ath_hal * ah,long address,u_int8_t * buffer,int many)3596b7d5e03cSMatthew Dillon ar9300_calibration_data_read_flash(struct ath_hal *ah, long address,
3597b7d5e03cSMatthew Dillon u_int8_t *buffer, int many)
3598b7d5e03cSMatthew Dillon {
3599b7d5e03cSMatthew Dillon
3600b7d5e03cSMatthew Dillon if (((address) < 0) || ((address + many) > AR9300_EEPROM_SIZE - 1)) {
3601b7d5e03cSMatthew Dillon return AH_FALSE;
3602b7d5e03cSMatthew Dillon }
3603b7d5e03cSMatthew Dillon return AH_FALSE;
3604b7d5e03cSMatthew Dillon }
3605b7d5e03cSMatthew Dillon
3606b7d5e03cSMatthew Dillon HAL_BOOL
ar9300_calibration_data_read_eeprom(struct ath_hal * ah,long address,u_int8_t * buffer,int many)3607b7d5e03cSMatthew Dillon ar9300_calibration_data_read_eeprom(struct ath_hal *ah, long address,
3608b7d5e03cSMatthew Dillon u_int8_t *buffer, int many)
3609b7d5e03cSMatthew Dillon {
3610b7d5e03cSMatthew Dillon int i;
3611b7d5e03cSMatthew Dillon u_int8_t value[2];
3612b7d5e03cSMatthew Dillon unsigned long eep_addr;
3613b7d5e03cSMatthew Dillon unsigned long byte_addr;
3614b7d5e03cSMatthew Dillon u_int16_t *svalue;
3615b7d5e03cSMatthew Dillon
3616b7d5e03cSMatthew Dillon if (((address) < 0) || ((address + many) > AR9300_EEPROM_SIZE)) {
3617b7d5e03cSMatthew Dillon return AH_FALSE;
3618b7d5e03cSMatthew Dillon }
3619b7d5e03cSMatthew Dillon
3620b7d5e03cSMatthew Dillon for (i = 0; i < many; i++) {
3621b7d5e03cSMatthew Dillon eep_addr = (u_int16_t) (address + i) / 2;
3622b7d5e03cSMatthew Dillon byte_addr = (u_int16_t) (address + i) % 2;
3623b7d5e03cSMatthew Dillon svalue = (u_int16_t *) value;
3624b7d5e03cSMatthew Dillon if (! ath_hal_eepromRead(ah, eep_addr, svalue)) {
3625b7d5e03cSMatthew Dillon HALDEBUG(ah, HAL_DEBUG_EEPROM,
3626b7d5e03cSMatthew Dillon "%s: Unable to read eeprom region \n", __func__);
3627b7d5e03cSMatthew Dillon return AH_FALSE;
3628b7d5e03cSMatthew Dillon }
3629b7d5e03cSMatthew Dillon buffer[i] = (*svalue >> (8 * byte_addr)) & 0xff;
3630b7d5e03cSMatthew Dillon }
3631b7d5e03cSMatthew Dillon return AH_TRUE;
3632b7d5e03cSMatthew Dillon }
3633b7d5e03cSMatthew Dillon
3634b7d5e03cSMatthew Dillon HAL_BOOL
ar9300_calibration_data_read_otp(struct ath_hal * ah,long address,u_int8_t * buffer,int many,HAL_BOOL is_wifi)3635b7d5e03cSMatthew Dillon ar9300_calibration_data_read_otp(struct ath_hal *ah, long address,
3636b7d5e03cSMatthew Dillon u_int8_t *buffer, int many, HAL_BOOL is_wifi)
3637b7d5e03cSMatthew Dillon {
3638b7d5e03cSMatthew Dillon int i;
3639b7d5e03cSMatthew Dillon unsigned long eep_addr;
3640b7d5e03cSMatthew Dillon unsigned long byte_addr;
3641b7d5e03cSMatthew Dillon u_int32_t svalue;
3642b7d5e03cSMatthew Dillon
3643b7d5e03cSMatthew Dillon if (((address) < 0) || ((address + many) > 0x400)) {
3644b7d5e03cSMatthew Dillon return AH_FALSE;
3645b7d5e03cSMatthew Dillon }
3646b7d5e03cSMatthew Dillon
3647b7d5e03cSMatthew Dillon for (i = 0; i < many; i++) {
3648b7d5e03cSMatthew Dillon eep_addr = (u_int16_t) (address + i) / 4; /* otp is 4 bytes long???? */
3649b7d5e03cSMatthew Dillon byte_addr = (u_int16_t) (address + i) % 4;
3650b7d5e03cSMatthew Dillon if (!ar9300_otp_read(ah, eep_addr, &svalue, is_wifi)) {
3651b7d5e03cSMatthew Dillon HALDEBUG(ah, HAL_DEBUG_EEPROM,
3652b7d5e03cSMatthew Dillon "%s: Unable to read otp region \n", __func__);
3653b7d5e03cSMatthew Dillon return AH_FALSE;
3654b7d5e03cSMatthew Dillon }
3655b7d5e03cSMatthew Dillon buffer[i] = (svalue >> (8 * byte_addr)) & 0xff;
3656b7d5e03cSMatthew Dillon }
3657b7d5e03cSMatthew Dillon return AH_TRUE;
3658b7d5e03cSMatthew Dillon }
3659b7d5e03cSMatthew Dillon
3660b7d5e03cSMatthew Dillon #ifdef ATH_CAL_NAND_FLASH
3661b7d5e03cSMatthew Dillon HAL_BOOL
ar9300_calibration_data_read_nand(struct ath_hal * ah,long address,u_int8_t * buffer,int many)3662b7d5e03cSMatthew Dillon ar9300_calibration_data_read_nand(struct ath_hal *ah, long address,
3663b7d5e03cSMatthew Dillon u_int8_t *buffer, int many)
3664b7d5e03cSMatthew Dillon {
3665b7d5e03cSMatthew Dillon int ret_len;
3666b7d5e03cSMatthew Dillon int ret_val = 1;
3667b7d5e03cSMatthew Dillon
3668b7d5e03cSMatthew Dillon /* Calling OS based API to read NAND */
3669b7d5e03cSMatthew Dillon ret_val = OS_NAND_FLASH_READ(ATH_CAL_NAND_PARTITION, address, many, &ret_len, buffer);
3670b7d5e03cSMatthew Dillon
3671b7d5e03cSMatthew Dillon return (ret_val ? AH_FALSE: AH_TRUE);
3672b7d5e03cSMatthew Dillon }
3673b7d5e03cSMatthew Dillon #endif
3674b7d5e03cSMatthew Dillon
3675b7d5e03cSMatthew Dillon HAL_BOOL
ar9300_calibration_data_read(struct ath_hal * ah,long address,u_int8_t * buffer,int many)3676b7d5e03cSMatthew Dillon ar9300_calibration_data_read(struct ath_hal *ah, long address,
3677b7d5e03cSMatthew Dillon u_int8_t *buffer, int many)
3678b7d5e03cSMatthew Dillon {
3679b7d5e03cSMatthew Dillon switch (AH9300(ah)->calibration_data_source) {
3680b7d5e03cSMatthew Dillon case calibration_data_flash:
3681b7d5e03cSMatthew Dillon return ar9300_calibration_data_read_flash(ah, address, buffer, many);
3682b7d5e03cSMatthew Dillon case calibration_data_eeprom:
3683b7d5e03cSMatthew Dillon return ar9300_calibration_data_read_eeprom(ah, address, buffer, many);
3684b7d5e03cSMatthew Dillon case calibration_data_otp:
3685b7d5e03cSMatthew Dillon return ar9300_calibration_data_read_otp(ah, address, buffer, many, 1);
3686b7d5e03cSMatthew Dillon #ifdef ATH_CAL_NAND_FLASH
3687b7d5e03cSMatthew Dillon case calibration_data_nand:
3688b7d5e03cSMatthew Dillon return ar9300_calibration_data_read_nand(ah,address,buffer,many);
3689b7d5e03cSMatthew Dillon #endif
3690b7d5e03cSMatthew Dillon
3691b7d5e03cSMatthew Dillon }
3692b7d5e03cSMatthew Dillon return AH_FALSE;
3693b7d5e03cSMatthew Dillon }
3694b7d5e03cSMatthew Dillon
3695b7d5e03cSMatthew Dillon
3696b7d5e03cSMatthew Dillon HAL_BOOL
ar9300_calibration_data_read_array(struct ath_hal * ah,int address,u_int8_t * buffer,int many)3697b7d5e03cSMatthew Dillon ar9300_calibration_data_read_array(struct ath_hal *ah, int address,
3698b7d5e03cSMatthew Dillon u_int8_t *buffer, int many)
3699b7d5e03cSMatthew Dillon {
3700b7d5e03cSMatthew Dillon int it;
3701b7d5e03cSMatthew Dillon
3702b7d5e03cSMatthew Dillon for (it = 0; it < many; it++) {
3703b7d5e03cSMatthew Dillon (void)ar9300_calibration_data_read(ah, address - it, buffer + it, 1);
3704b7d5e03cSMatthew Dillon }
3705b7d5e03cSMatthew Dillon return AH_TRUE;
3706b7d5e03cSMatthew Dillon }
3707b7d5e03cSMatthew Dillon
3708b7d5e03cSMatthew Dillon
3709b7d5e03cSMatthew Dillon /*
3710b7d5e03cSMatthew Dillon * the address where the first configuration block is written
3711b7d5e03cSMatthew Dillon */
3712b7d5e03cSMatthew Dillon static const int base_address = 0x3ff; /* 1KB */
3713b7d5e03cSMatthew Dillon static const int base_address_512 = 0x1ff; /* 512Bytes */
3714b7d5e03cSMatthew Dillon
3715b7d5e03cSMatthew Dillon /*
3716b7d5e03cSMatthew Dillon * the address where the NAND first configuration block is written
3717b7d5e03cSMatthew Dillon */
3718b7d5e03cSMatthew Dillon #ifdef ATH_CAL_NAND_FLASH
3719b7d5e03cSMatthew Dillon static const int base_address_nand = AR9300_FLASH_CAL_START_OFFSET;
3720b7d5e03cSMatthew Dillon #endif
3721b7d5e03cSMatthew Dillon
3722b7d5e03cSMatthew Dillon
3723b7d5e03cSMatthew Dillon /*
3724b7d5e03cSMatthew Dillon * the lower limit on configuration data
3725b7d5e03cSMatthew Dillon */
3726b7d5e03cSMatthew Dillon static const int low_limit = 0x040;
3727b7d5e03cSMatthew Dillon
3728b7d5e03cSMatthew Dillon /*
3729b7d5e03cSMatthew Dillon * returns size of the physical eeprom in bytes.
3730b7d5e03cSMatthew Dillon * 1024 and 2048 are normal sizes.
3731b7d5e03cSMatthew Dillon * 0 means there is no eeprom.
3732b7d5e03cSMatthew Dillon */
3733b7d5e03cSMatthew Dillon int32_t
ar9300_eeprom_size(struct ath_hal * ah)3734b7d5e03cSMatthew Dillon ar9300_eeprom_size(struct ath_hal *ah)
3735b7d5e03cSMatthew Dillon {
3736b7d5e03cSMatthew Dillon u_int16_t data;
3737b7d5e03cSMatthew Dillon /*
3738b7d5e03cSMatthew Dillon * first we'll try for 4096 bytes eeprom
3739b7d5e03cSMatthew Dillon */
3740b7d5e03cSMatthew Dillon if (ar9300_eeprom_read_word(ah, 2047, &data)) {
3741b7d5e03cSMatthew Dillon if (data != 0) {
3742b7d5e03cSMatthew Dillon return 4096;
3743b7d5e03cSMatthew Dillon }
3744b7d5e03cSMatthew Dillon }
3745b7d5e03cSMatthew Dillon /*
3746b7d5e03cSMatthew Dillon * then we'll try for 2048 bytes eeprom
3747b7d5e03cSMatthew Dillon */
3748b7d5e03cSMatthew Dillon if (ar9300_eeprom_read_word(ah, 1023, &data)) {
3749b7d5e03cSMatthew Dillon if (data != 0) {
3750b7d5e03cSMatthew Dillon return 2048;
3751b7d5e03cSMatthew Dillon }
3752b7d5e03cSMatthew Dillon }
3753b7d5e03cSMatthew Dillon /*
3754b7d5e03cSMatthew Dillon * then we'll try for 1024 bytes eeprom
3755b7d5e03cSMatthew Dillon */
3756b7d5e03cSMatthew Dillon if (ar9300_eeprom_read_word(ah, 511, &data)) {
3757b7d5e03cSMatthew Dillon if (data != 0) {
3758b7d5e03cSMatthew Dillon return 1024;
3759b7d5e03cSMatthew Dillon }
3760b7d5e03cSMatthew Dillon }
3761b7d5e03cSMatthew Dillon return 0;
3762b7d5e03cSMatthew Dillon }
3763b7d5e03cSMatthew Dillon
3764b7d5e03cSMatthew Dillon /*
3765b7d5e03cSMatthew Dillon * returns size of the physical otp in bytes.
3766b7d5e03cSMatthew Dillon * 1024 and 2048 are normal sizes.
3767b7d5e03cSMatthew Dillon * 0 means there is no eeprom.
3768b7d5e03cSMatthew Dillon */
3769b7d5e03cSMatthew Dillon int32_t
ar9300_otp_size(struct ath_hal * ah)3770b7d5e03cSMatthew Dillon ar9300_otp_size(struct ath_hal *ah)
3771b7d5e03cSMatthew Dillon {
3772b7d5e03cSMatthew Dillon if (AR_SREV_POSEIDON(ah) || AR_SREV_HORNET(ah)) {
3773b7d5e03cSMatthew Dillon return base_address_512+1;
3774b7d5e03cSMatthew Dillon } else {
3775b7d5e03cSMatthew Dillon return base_address+1;
3776b7d5e03cSMatthew Dillon }
3777b7d5e03cSMatthew Dillon }
3778b7d5e03cSMatthew Dillon
3779b7d5e03cSMatthew Dillon
3780b7d5e03cSMatthew Dillon /*
3781b7d5e03cSMatthew Dillon * find top of memory
3782b7d5e03cSMatthew Dillon */
3783b7d5e03cSMatthew Dillon int
ar9300_eeprom_base_address(struct ath_hal * ah)3784b7d5e03cSMatthew Dillon ar9300_eeprom_base_address(struct ath_hal *ah)
3785b7d5e03cSMatthew Dillon {
3786b7d5e03cSMatthew Dillon int size;
3787b7d5e03cSMatthew Dillon
3788b7d5e03cSMatthew Dillon if (AH9300(ah)->calibration_data_source == calibration_data_otp) {
3789b7d5e03cSMatthew Dillon return ar9300_otp_size(ah)-1;
3790b7d5e03cSMatthew Dillon }
3791b7d5e03cSMatthew Dillon else
3792b7d5e03cSMatthew Dillon {
3793b7d5e03cSMatthew Dillon size = ar9300_eeprom_size(ah);
3794b7d5e03cSMatthew Dillon if (size > 0) {
3795b7d5e03cSMatthew Dillon return size - 1;
3796b7d5e03cSMatthew Dillon } else {
3797b7d5e03cSMatthew Dillon return ar9300_otp_size(ah)-1;
3798b7d5e03cSMatthew Dillon }
3799b7d5e03cSMatthew Dillon }
3800b7d5e03cSMatthew Dillon }
3801b7d5e03cSMatthew Dillon
3802b7d5e03cSMatthew Dillon int
ar9300_eeprom_volatile(struct ath_hal * ah)3803b7d5e03cSMatthew Dillon ar9300_eeprom_volatile(struct ath_hal *ah)
3804b7d5e03cSMatthew Dillon {
3805b7d5e03cSMatthew Dillon if (AH9300(ah)->calibration_data_source == calibration_data_otp) {
3806b7d5e03cSMatthew Dillon return 0; /* no eeprom, use otp */
3807b7d5e03cSMatthew Dillon } else {
3808b7d5e03cSMatthew Dillon return 1; /* board has eeprom or flash */
3809b7d5e03cSMatthew Dillon }
3810b7d5e03cSMatthew Dillon }
3811b7d5e03cSMatthew Dillon
3812b7d5e03cSMatthew Dillon /*
3813b7d5e03cSMatthew Dillon * need to change this to look for the pcie data in the low parts of memory
3814b7d5e03cSMatthew Dillon * cal data needs to stop a few locations above
3815b7d5e03cSMatthew Dillon */
3816b7d5e03cSMatthew Dillon int
ar9300_eeprom_low_limit(struct ath_hal * ah)3817b7d5e03cSMatthew Dillon ar9300_eeprom_low_limit(struct ath_hal *ah)
3818b7d5e03cSMatthew Dillon {
3819b7d5e03cSMatthew Dillon return low_limit;
3820b7d5e03cSMatthew Dillon }
3821b7d5e03cSMatthew Dillon
3822b7d5e03cSMatthew Dillon u_int16_t
ar9300_compression_checksum(u_int8_t * data,int dsize)3823b7d5e03cSMatthew Dillon ar9300_compression_checksum(u_int8_t *data, int dsize)
3824b7d5e03cSMatthew Dillon {
3825b7d5e03cSMatthew Dillon int it;
3826b7d5e03cSMatthew Dillon int checksum = 0;
3827b7d5e03cSMatthew Dillon
3828b7d5e03cSMatthew Dillon for (it = 0; it < dsize; it++) {
3829b7d5e03cSMatthew Dillon checksum += data[it];
3830b7d5e03cSMatthew Dillon checksum &= 0xffff;
3831b7d5e03cSMatthew Dillon }
3832b7d5e03cSMatthew Dillon
3833b7d5e03cSMatthew Dillon return checksum;
3834b7d5e03cSMatthew Dillon }
3835b7d5e03cSMatthew Dillon
3836b7d5e03cSMatthew Dillon int
ar9300_compression_header_unpack(u_int8_t * best,int * code,int * reference,int * length,int * major,int * minor)3837b7d5e03cSMatthew Dillon ar9300_compression_header_unpack(u_int8_t *best, int *code, int *reference,
3838b7d5e03cSMatthew Dillon int *length, int *major, int *minor)
3839b7d5e03cSMatthew Dillon {
3840b7d5e03cSMatthew Dillon unsigned long value[4];
3841b7d5e03cSMatthew Dillon
3842b7d5e03cSMatthew Dillon value[0] = best[0];
3843b7d5e03cSMatthew Dillon value[1] = best[1];
3844b7d5e03cSMatthew Dillon value[2] = best[2];
3845b7d5e03cSMatthew Dillon value[3] = best[3];
3846b7d5e03cSMatthew Dillon *code = ((value[0] >> 5) & 0x0007);
3847b7d5e03cSMatthew Dillon *reference = (value[0] & 0x001f) | ((value[1] >> 2) & 0x0020);
3848b7d5e03cSMatthew Dillon *length = ((value[1] << 4) & 0x07f0) | ((value[2] >> 4) & 0x000f);
3849b7d5e03cSMatthew Dillon *major = (value[2] & 0x000f);
3850b7d5e03cSMatthew Dillon *minor = (value[3] & 0x00ff);
3851b7d5e03cSMatthew Dillon
3852b7d5e03cSMatthew Dillon return 4;
3853b7d5e03cSMatthew Dillon }
3854b7d5e03cSMatthew Dillon
3855b7d5e03cSMatthew Dillon
3856b7d5e03cSMatthew Dillon static HAL_BOOL
ar9300_uncompress_block(struct ath_hal * ah,u_int8_t * mptr,int mdata_size,u_int8_t * block,int size)3857b7d5e03cSMatthew Dillon ar9300_uncompress_block(struct ath_hal *ah, u_int8_t *mptr, int mdata_size,
3858b7d5e03cSMatthew Dillon u_int8_t *block, int size)
3859b7d5e03cSMatthew Dillon {
3860b7d5e03cSMatthew Dillon int it;
3861b7d5e03cSMatthew Dillon int spot;
3862b7d5e03cSMatthew Dillon int offset;
3863b7d5e03cSMatthew Dillon int length;
3864b7d5e03cSMatthew Dillon
3865b7d5e03cSMatthew Dillon spot = 0;
3866b7d5e03cSMatthew Dillon for (it = 0; it < size; it += (length + 2)) {
3867b7d5e03cSMatthew Dillon offset = block[it];
3868b7d5e03cSMatthew Dillon offset &= 0xff;
3869b7d5e03cSMatthew Dillon spot += offset;
3870b7d5e03cSMatthew Dillon length = block[it + 1];
3871b7d5e03cSMatthew Dillon length &= 0xff;
3872b7d5e03cSMatthew Dillon if (length > 0 && spot >= 0 && spot + length <= mdata_size) {
3873b7d5e03cSMatthew Dillon HALDEBUG(ah, HAL_DEBUG_EEPROM,
3874b7d5e03cSMatthew Dillon "%s: Restore at %d: spot=%d offset=%d length=%d\n",
3875b7d5e03cSMatthew Dillon __func__, it, spot, offset, length);
3876b7d5e03cSMatthew Dillon OS_MEMCPY(&mptr[spot], &block[it + 2], length);
3877b7d5e03cSMatthew Dillon spot += length;
3878b7d5e03cSMatthew Dillon } else if (length > 0) {
3879b7d5e03cSMatthew Dillon HALDEBUG(ah, HAL_DEBUG_EEPROM,
3880b7d5e03cSMatthew Dillon "%s: Bad restore at %d: spot=%d offset=%d length=%d\n",
3881b7d5e03cSMatthew Dillon __func__, it, spot, offset, length);
3882b7d5e03cSMatthew Dillon return AH_FALSE;
3883b7d5e03cSMatthew Dillon }
3884b7d5e03cSMatthew Dillon }
3885b7d5e03cSMatthew Dillon return AH_TRUE;
3886b7d5e03cSMatthew Dillon }
3887b7d5e03cSMatthew Dillon
3888b7d5e03cSMatthew Dillon static int
ar9300_eeprom_restore_internal_address(struct ath_hal * ah,ar9300_eeprom_t * mptr,int mdata_size,int cptr,u_int8_t blank)3889b7d5e03cSMatthew Dillon ar9300_eeprom_restore_internal_address(struct ath_hal *ah,
3890b7d5e03cSMatthew Dillon ar9300_eeprom_t *mptr, int mdata_size, int cptr, u_int8_t blank)
3891b7d5e03cSMatthew Dillon {
3892b7d5e03cSMatthew Dillon u_int8_t word[MOUTPUT];
3893b7d5e03cSMatthew Dillon ar9300_eeprom_t *dptr; /* was uint8 */
3894b7d5e03cSMatthew Dillon int code;
3895b7d5e03cSMatthew Dillon int reference, length, major, minor;
3896b7d5e03cSMatthew Dillon int osize;
3897b7d5e03cSMatthew Dillon int it;
3898b7d5e03cSMatthew Dillon int restored;
3899b7d5e03cSMatthew Dillon u_int16_t checksum, mchecksum;
3900b7d5e03cSMatthew Dillon
3901b7d5e03cSMatthew Dillon restored = 0;
3902b7d5e03cSMatthew Dillon for (it = 0; it < MSTATE; it++) {
3903b7d5e03cSMatthew Dillon (void) ar9300_calibration_data_read_array(
3904b7d5e03cSMatthew Dillon ah, cptr, word, compression_header_length);
3905b7d5e03cSMatthew Dillon if (word[0] == blank && word[1] == blank && word[2] == blank && word[3] == blank)
3906b7d5e03cSMatthew Dillon {
3907b7d5e03cSMatthew Dillon break;
3908b7d5e03cSMatthew Dillon }
3909b7d5e03cSMatthew Dillon ar9300_compression_header_unpack(
3910b7d5e03cSMatthew Dillon word, &code, &reference, &length, &major, &minor);
3911b7d5e03cSMatthew Dillon HALDEBUG(ah, HAL_DEBUG_EEPROM,
3912b7d5e03cSMatthew Dillon "%s: Found block at %x: "
3913b7d5e03cSMatthew Dillon "code=%d ref=%d length=%d major=%d minor=%d\n",
3914b7d5e03cSMatthew Dillon __func__, cptr, code, reference, length, major, minor);
3915b7d5e03cSMatthew Dillon #ifdef DONTUSE
3916b7d5e03cSMatthew Dillon if (length >= 1024) {
3917b7d5e03cSMatthew Dillon HALDEBUG(ah, HAL_DEBUG_EEPROM, "%s: Skipping bad header\n", __func__);
3918b7d5e03cSMatthew Dillon cptr -= compression_header_length;
3919b7d5e03cSMatthew Dillon continue;
3920b7d5e03cSMatthew Dillon }
3921b7d5e03cSMatthew Dillon #endif
3922b7d5e03cSMatthew Dillon osize = length;
3923b7d5e03cSMatthew Dillon (void) ar9300_calibration_data_read_array(
3924b7d5e03cSMatthew Dillon ah, cptr, word,
3925b7d5e03cSMatthew Dillon compression_header_length + osize + compression_checksum_length);
3926b7d5e03cSMatthew Dillon checksum = ar9300_compression_checksum(
3927b7d5e03cSMatthew Dillon &word[compression_header_length], length);
3928b7d5e03cSMatthew Dillon mchecksum =
3929b7d5e03cSMatthew Dillon word[compression_header_length + osize] |
3930b7d5e03cSMatthew Dillon (word[compression_header_length + osize + 1] << 8);
3931b7d5e03cSMatthew Dillon HALDEBUG(ah, HAL_DEBUG_EEPROM,
3932b7d5e03cSMatthew Dillon "%s: checksum %x %x\n", __func__, checksum, mchecksum);
3933b7d5e03cSMatthew Dillon if (checksum == mchecksum) {
3934b7d5e03cSMatthew Dillon switch (code) {
3935b7d5e03cSMatthew Dillon case _compress_none:
3936b7d5e03cSMatthew Dillon if (length != mdata_size) {
3937b7d5e03cSMatthew Dillon HALDEBUG(ah, HAL_DEBUG_EEPROM,
3938b7d5e03cSMatthew Dillon "%s: EEPROM structure size mismatch "
3939b7d5e03cSMatthew Dillon "memory=%d eeprom=%d\n", __func__, mdata_size, length);
3940b7d5e03cSMatthew Dillon return -1;
3941b7d5e03cSMatthew Dillon }
3942b7d5e03cSMatthew Dillon OS_MEMCPY((u_int8_t *)mptr,
3943b7d5e03cSMatthew Dillon (u_int8_t *)(word + compression_header_length), length);
3944b7d5e03cSMatthew Dillon HALDEBUG(ah, HAL_DEBUG_EEPROM,
3945b7d5e03cSMatthew Dillon "%s: restored eeprom %d: uncompressed, length %d\n",
3946b7d5e03cSMatthew Dillon __func__, it, length);
3947b7d5e03cSMatthew Dillon restored = 1;
3948b7d5e03cSMatthew Dillon break;
3949b7d5e03cSMatthew Dillon #ifdef UNUSED
3950b7d5e03cSMatthew Dillon case _compress_lzma:
3951b7d5e03cSMatthew Dillon if (reference == reference_current) {
3952b7d5e03cSMatthew Dillon dptr = mptr;
3953b7d5e03cSMatthew Dillon } else {
3954b7d5e03cSMatthew Dillon dptr = (u_int8_t *)ar9300_eeprom_struct_default_find_by_id(
3955b7d5e03cSMatthew Dillon reference);
3956b7d5e03cSMatthew Dillon if (dptr == 0) {
3957b7d5e03cSMatthew Dillon HALDEBUG(ah, HAL_DEBUG_EEPROM,
3958b7d5e03cSMatthew Dillon "%s: Can't find reference eeprom struct %d\n",
3959b7d5e03cSMatthew Dillon __func__, reference);
3960b7d5e03cSMatthew Dillon goto done;
3961b7d5e03cSMatthew Dillon }
3962b7d5e03cSMatthew Dillon }
3963b7d5e03cSMatthew Dillon usize = -1;
3964b7d5e03cSMatthew Dillon if (usize != mdata_size) {
3965b7d5e03cSMatthew Dillon HALDEBUG(ah, HAL_DEBUG_EEPROM,
3966b7d5e03cSMatthew Dillon "%s: uncompressed data is wrong size %d %d\n",
3967b7d5e03cSMatthew Dillon __func__, usize, mdata_size);
3968b7d5e03cSMatthew Dillon goto done;
3969b7d5e03cSMatthew Dillon }
3970b7d5e03cSMatthew Dillon
3971b7d5e03cSMatthew Dillon for (ib = 0; ib < mdata_size; ib++) {
3972b7d5e03cSMatthew Dillon mptr[ib] = dptr[ib] ^ word[ib + overhead];
3973b7d5e03cSMatthew Dillon }
3974b7d5e03cSMatthew Dillon HALDEBUG(ah, HAL_DEBUG_EEPROM,
3975b7d5e03cSMatthew Dillon "%s: restored eeprom %d: compressed, "
3976b7d5e03cSMatthew Dillon "reference %d, length %d\n",
3977b7d5e03cSMatthew Dillon __func__, it, reference, length);
3978b7d5e03cSMatthew Dillon break;
3979b7d5e03cSMatthew Dillon case _compress_pairs:
3980b7d5e03cSMatthew Dillon if (reference == reference_current) {
3981b7d5e03cSMatthew Dillon dptr = mptr;
3982b7d5e03cSMatthew Dillon } else {
3983b7d5e03cSMatthew Dillon dptr = (u_int8_t *)ar9300_eeprom_struct_default_find_by_id(
3984b7d5e03cSMatthew Dillon reference);
3985b7d5e03cSMatthew Dillon if (dptr == 0) {
3986b7d5e03cSMatthew Dillon HALDEBUG(ah, HAL_DEBUG_EEPROM,
3987b7d5e03cSMatthew Dillon "%s: Can't find the reference "
3988b7d5e03cSMatthew Dillon "eeprom structure %d\n",
3989b7d5e03cSMatthew Dillon __func__, reference);
3990b7d5e03cSMatthew Dillon goto done;
3991b7d5e03cSMatthew Dillon }
3992b7d5e03cSMatthew Dillon }
3993b7d5e03cSMatthew Dillon HALDEBUG(ah, HAL_DEBUG_EEPROM,
3994b7d5e03cSMatthew Dillon "%s: restored eeprom %d: "
3995b7d5e03cSMatthew Dillon "pairs, reference %d, length %d,\n",
3996b7d5e03cSMatthew Dillon __func__, it, reference, length);
3997b7d5e03cSMatthew Dillon break;
3998b7d5e03cSMatthew Dillon #endif
3999b7d5e03cSMatthew Dillon case _compress_block:
4000b7d5e03cSMatthew Dillon if (reference == reference_current) {
4001b7d5e03cSMatthew Dillon dptr = mptr;
4002b7d5e03cSMatthew Dillon } else {
4003b7d5e03cSMatthew Dillon dptr = ar9300_eeprom_struct_default_find_by_id(reference);
4004b7d5e03cSMatthew Dillon if (dptr == 0) {
4005b7d5e03cSMatthew Dillon HALDEBUG(ah, HAL_DEBUG_EEPROM,
4006f12e2116SSascha Wildner "%s: can't find reference eeprom struct %d\n",
4007b7d5e03cSMatthew Dillon __func__, reference);
4008b7d5e03cSMatthew Dillon break;
4009b7d5e03cSMatthew Dillon }
4010b7d5e03cSMatthew Dillon OS_MEMCPY(mptr, dptr, mdata_size);
4011b7d5e03cSMatthew Dillon }
4012b7d5e03cSMatthew Dillon
4013b7d5e03cSMatthew Dillon HALDEBUG(ah, HAL_DEBUG_EEPROM,
4014b7d5e03cSMatthew Dillon "%s: restore eeprom %d: block, reference %d, length %d\n",
4015b7d5e03cSMatthew Dillon __func__, it, reference, length);
4016b7d5e03cSMatthew Dillon (void) ar9300_uncompress_block(ah,
4017b7d5e03cSMatthew Dillon (u_int8_t *) mptr, mdata_size,
4018b7d5e03cSMatthew Dillon (u_int8_t *) (word + compression_header_length), length);
4019b7d5e03cSMatthew Dillon restored = 1;
4020b7d5e03cSMatthew Dillon break;
4021b7d5e03cSMatthew Dillon default:
4022b7d5e03cSMatthew Dillon HALDEBUG(ah, HAL_DEBUG_EEPROM,
4023b7d5e03cSMatthew Dillon "%s: unknown compression code %d\n", __func__, code);
4024b7d5e03cSMatthew Dillon break;
4025b7d5e03cSMatthew Dillon }
4026b7d5e03cSMatthew Dillon } else {
4027b7d5e03cSMatthew Dillon HALDEBUG(ah, HAL_DEBUG_EEPROM,
4028b7d5e03cSMatthew Dillon "%s: skipping block with bad checksum\n", __func__);
4029b7d5e03cSMatthew Dillon }
4030b7d5e03cSMatthew Dillon cptr -= compression_header_length + osize + compression_checksum_length;
4031b7d5e03cSMatthew Dillon }
4032b7d5e03cSMatthew Dillon
4033b7d5e03cSMatthew Dillon if (!restored) {
4034b7d5e03cSMatthew Dillon cptr = -1;
4035b7d5e03cSMatthew Dillon }
4036b7d5e03cSMatthew Dillon return cptr;
4037b7d5e03cSMatthew Dillon }
4038b7d5e03cSMatthew Dillon
4039b7d5e03cSMatthew Dillon static int
ar9300_eeprom_restore_from_dram(struct ath_hal * ah,ar9300_eeprom_t * mptr,int mdata_size)4040b7d5e03cSMatthew Dillon ar9300_eeprom_restore_from_dram(struct ath_hal *ah, ar9300_eeprom_t *mptr,
4041b7d5e03cSMatthew Dillon int mdata_size)
4042b7d5e03cSMatthew Dillon {
4043b7d5e03cSMatthew Dillon struct ath_hal_9300 *ahp = AH9300(ah);
4044b7d5e03cSMatthew Dillon #if !defined(USE_PLATFORM_FRAMEWORK)
4045b7d5e03cSMatthew Dillon char *cal_ptr;
4046b7d5e03cSMatthew Dillon #endif
4047b7d5e03cSMatthew Dillon
4048b7d5e03cSMatthew Dillon HALASSERT(mdata_size > 0);
4049b7d5e03cSMatthew Dillon
4050b7d5e03cSMatthew Dillon /* if cal_in_flash is AH_TRUE, the address sent by LMAC to HAL
4051b7d5e03cSMatthew Dillon (i.e. ah->ah_st) is corresponding to Flash. so return from
4052b7d5e03cSMatthew Dillon here if ar9300_eep_data_in_flash(ah) returns AH_TRUE */
4053b7d5e03cSMatthew Dillon if(ar9300_eep_data_in_flash(ah))
4054b7d5e03cSMatthew Dillon return -1;
4055b7d5e03cSMatthew Dillon
4056b7d5e03cSMatthew Dillon #if 0
4057b7d5e03cSMatthew Dillon /* check if LMAC sent DRAM address is valid */
4058b7d5e03cSMatthew Dillon if (!(uintptr_t)(AH_PRIVATE(ah)->ah_st)) {
4059b7d5e03cSMatthew Dillon return -1;
4060b7d5e03cSMatthew Dillon }
4061b7d5e03cSMatthew Dillon #endif
4062b7d5e03cSMatthew Dillon
4063b7d5e03cSMatthew Dillon /* When calibration data is from host, Host will copy the
4064b7d5e03cSMatthew Dillon compressed data to the predefined DRAM location saved at ah->ah_st */
4065b7d5e03cSMatthew Dillon #if 0
4066b7d5e03cSMatthew Dillon ath_hal_printf(ah, "Restoring Cal data from DRAM\n");
4067b7d5e03cSMatthew Dillon ahp->ah_cal_mem = OS_REMAP((uintptr_t)(AH_PRIVATE(ah)->ah_st),
4068b7d5e03cSMatthew Dillon HOST_CALDATA_SIZE);
4069b7d5e03cSMatthew Dillon #endif
4070b7d5e03cSMatthew Dillon if (!ahp->ah_cal_mem)
4071b7d5e03cSMatthew Dillon {
4072b7d5e03cSMatthew Dillon HALDEBUG(ah, HAL_DEBUG_EEPROM,"%s: can't remap dram region\n", __func__);
4073b7d5e03cSMatthew Dillon return -1;
4074b7d5e03cSMatthew Dillon }
4075b7d5e03cSMatthew Dillon #if !defined(USE_PLATFORM_FRAMEWORK)
4076b7d5e03cSMatthew Dillon cal_ptr = &((char *)(ahp->ah_cal_mem))[AR9300_FLASH_CAL_START_OFFSET];
4077b7d5e03cSMatthew Dillon OS_MEMCPY(mptr, cal_ptr, mdata_size);
4078b7d5e03cSMatthew Dillon #else
4079b7d5e03cSMatthew Dillon OS_MEMCPY(mptr, ahp->ah_cal_mem, mdata_size);
4080b7d5e03cSMatthew Dillon #endif
4081b7d5e03cSMatthew Dillon
4082b7d5e03cSMatthew Dillon if (mptr->eeprom_version == 0xff ||
4083b7d5e03cSMatthew Dillon mptr->template_version == 0xff ||
4084b7d5e03cSMatthew Dillon mptr->eeprom_version == 0 ||
4085b7d5e03cSMatthew Dillon mptr->template_version == 0)
4086b7d5e03cSMatthew Dillon {
4087b7d5e03cSMatthew Dillon /* The board is uncalibrated */
4088b7d5e03cSMatthew Dillon return -1;
4089b7d5e03cSMatthew Dillon }
4090b7d5e03cSMatthew Dillon if (mptr->eeprom_version != 0x2)
4091b7d5e03cSMatthew Dillon {
4092b7d5e03cSMatthew Dillon return -1;
4093b7d5e03cSMatthew Dillon }
4094b7d5e03cSMatthew Dillon
4095b7d5e03cSMatthew Dillon return mdata_size;
4096b7d5e03cSMatthew Dillon
4097b7d5e03cSMatthew Dillon }
4098b7d5e03cSMatthew Dillon
4099b7d5e03cSMatthew Dillon static int
ar9300_eeprom_restore_from_flash(struct ath_hal * ah,ar9300_eeprom_t * mptr,int mdata_size)4100b7d5e03cSMatthew Dillon ar9300_eeprom_restore_from_flash(struct ath_hal *ah, ar9300_eeprom_t *mptr,
4101b7d5e03cSMatthew Dillon int mdata_size)
4102b7d5e03cSMatthew Dillon {
4103b7d5e03cSMatthew Dillon struct ath_hal_9300 *ahp = AH9300(ah);
4104b7d5e03cSMatthew Dillon char *cal_ptr;
4105b7d5e03cSMatthew Dillon
4106b7d5e03cSMatthew Dillon HALASSERT(mdata_size > 0);
4107b7d5e03cSMatthew Dillon
4108b7d5e03cSMatthew Dillon if (!ahp->ah_cal_mem) {
4109b7d5e03cSMatthew Dillon return -1;
4110b7d5e03cSMatthew Dillon }
4111b7d5e03cSMatthew Dillon
4112b7d5e03cSMatthew Dillon ath_hal_printf(ah, "Restoring Cal data from Flash\n");
4113b7d5e03cSMatthew Dillon /*
4114b7d5e03cSMatthew Dillon * When calibration data is saved in flash, read
4115b7d5e03cSMatthew Dillon * uncompressed eeprom structure from flash and return
4116b7d5e03cSMatthew Dillon */
4117b7d5e03cSMatthew Dillon cal_ptr = &((char *)(ahp->ah_cal_mem))[AR9300_FLASH_CAL_START_OFFSET];
4118b7d5e03cSMatthew Dillon OS_MEMCPY(mptr, cal_ptr, mdata_size);
4119b7d5e03cSMatthew Dillon #if 0
4120b7d5e03cSMatthew Dillon ar9300_swap_eeprom((ar9300_eeprom_t *)mptr); DONE IN ar9300_restore()
4121b7d5e03cSMatthew Dillon #endif
4122b7d5e03cSMatthew Dillon if (mptr->eeprom_version == 0xff ||
4123b7d5e03cSMatthew Dillon mptr->template_version == 0xff ||
4124b7d5e03cSMatthew Dillon mptr->eeprom_version == 0 ||
4125b7d5e03cSMatthew Dillon mptr->template_version == 0)
4126b7d5e03cSMatthew Dillon {
4127b7d5e03cSMatthew Dillon /* The board is uncalibrated */
4128b7d5e03cSMatthew Dillon return -1;
4129b7d5e03cSMatthew Dillon }
4130b7d5e03cSMatthew Dillon if (mptr->eeprom_version != 0x2)
4131b7d5e03cSMatthew Dillon {
4132b7d5e03cSMatthew Dillon return -1;
4133b7d5e03cSMatthew Dillon }
4134b7d5e03cSMatthew Dillon return mdata_size;
4135b7d5e03cSMatthew Dillon }
4136b7d5e03cSMatthew Dillon
4137b7d5e03cSMatthew Dillon /*
4138b7d5e03cSMatthew Dillon * Read the configuration data from the storage. We try the order with:
4139b7d5e03cSMatthew Dillon * EEPROM, Flash, OTP. If all of above failed, use the default template.
4140b7d5e03cSMatthew Dillon * The data can be put in any specified memory buffer.
4141b7d5e03cSMatthew Dillon *
4142b7d5e03cSMatthew Dillon * Returns -1 on error.
4143b7d5e03cSMatthew Dillon * Returns address of next memory location on success.
4144b7d5e03cSMatthew Dillon */
4145b7d5e03cSMatthew Dillon int
ar9300_eeprom_restore_internal(struct ath_hal * ah,ar9300_eeprom_t * mptr,int mdata_size)4146b7d5e03cSMatthew Dillon ar9300_eeprom_restore_internal(struct ath_hal *ah, ar9300_eeprom_t *mptr,
4147b7d5e03cSMatthew Dillon int mdata_size)
4148b7d5e03cSMatthew Dillon {
4149b7d5e03cSMatthew Dillon int nptr;
4150b7d5e03cSMatthew Dillon
4151b7d5e03cSMatthew Dillon nptr = -1;
4152b7d5e03cSMatthew Dillon
4153b7d5e03cSMatthew Dillon if ((AH9300(ah)->calibration_data_try == calibration_data_none ||
4154b7d5e03cSMatthew Dillon AH9300(ah)->calibration_data_try == calibration_data_dram) &&
4155b7d5e03cSMatthew Dillon AH9300(ah)->try_dram && nptr < 0)
4156b7d5e03cSMatthew Dillon {
4157b7d5e03cSMatthew Dillon ath_hal_printf(ah, "Restoring Cal data from DRAM\n");
4158b7d5e03cSMatthew Dillon AH9300(ah)->calibration_data_source = calibration_data_dram;
4159b7d5e03cSMatthew Dillon AH9300(ah)->calibration_data_source_address = 0;
4160b7d5e03cSMatthew Dillon nptr = ar9300_eeprom_restore_from_dram(ah, mptr, mdata_size);
4161b7d5e03cSMatthew Dillon if (nptr < 0) {
4162b7d5e03cSMatthew Dillon AH9300(ah)->calibration_data_source = calibration_data_none;
4163b7d5e03cSMatthew Dillon AH9300(ah)->calibration_data_source_address = 0;
4164b7d5e03cSMatthew Dillon }
4165b7d5e03cSMatthew Dillon }
4166b7d5e03cSMatthew Dillon
4167b7d5e03cSMatthew Dillon if ((AH9300(ah)->calibration_data_try == calibration_data_none ||
4168b7d5e03cSMatthew Dillon AH9300(ah)->calibration_data_try == calibration_data_eeprom) &&
4169b7d5e03cSMatthew Dillon AH9300(ah)->try_eeprom && nptr < 0)
4170b7d5e03cSMatthew Dillon {
4171b7d5e03cSMatthew Dillon /*
4172b7d5e03cSMatthew Dillon * need to look at highest eeprom address as well as at
4173b7d5e03cSMatthew Dillon * base_address=0x3ff where we used to write the data
4174b7d5e03cSMatthew Dillon */
4175b7d5e03cSMatthew Dillon ath_hal_printf(ah, "Restoring Cal data from EEPROM\n");
4176b7d5e03cSMatthew Dillon AH9300(ah)->calibration_data_source = calibration_data_eeprom;
4177b7d5e03cSMatthew Dillon if (AH9300(ah)->calibration_data_try_address != 0) {
4178b7d5e03cSMatthew Dillon AH9300(ah)->calibration_data_source_address =
4179b7d5e03cSMatthew Dillon AH9300(ah)->calibration_data_try_address;
4180b7d5e03cSMatthew Dillon nptr = ar9300_eeprom_restore_internal_address(
4181b7d5e03cSMatthew Dillon ah, mptr, mdata_size,
4182b7d5e03cSMatthew Dillon AH9300(ah)->calibration_data_source_address, 0xff);
4183b7d5e03cSMatthew Dillon } else {
4184b7d5e03cSMatthew Dillon AH9300(ah)->calibration_data_source_address =
4185b7d5e03cSMatthew Dillon ar9300_eeprom_base_address(ah);
4186b7d5e03cSMatthew Dillon nptr = ar9300_eeprom_restore_internal_address(
4187b7d5e03cSMatthew Dillon ah, mptr, mdata_size,
4188b7d5e03cSMatthew Dillon AH9300(ah)->calibration_data_source_address, 0xff);
4189b7d5e03cSMatthew Dillon if (nptr < 0 &&
4190b7d5e03cSMatthew Dillon AH9300(ah)->calibration_data_source_address != base_address)
4191b7d5e03cSMatthew Dillon {
4192b7d5e03cSMatthew Dillon AH9300(ah)->calibration_data_source_address = base_address;
4193b7d5e03cSMatthew Dillon nptr = ar9300_eeprom_restore_internal_address(
4194b7d5e03cSMatthew Dillon ah, mptr, mdata_size,
4195b7d5e03cSMatthew Dillon AH9300(ah)->calibration_data_source_address, 0xff);
4196b7d5e03cSMatthew Dillon }
4197b7d5e03cSMatthew Dillon }
4198b7d5e03cSMatthew Dillon if (nptr < 0) {
4199b7d5e03cSMatthew Dillon AH9300(ah)->calibration_data_source = calibration_data_none;
4200b7d5e03cSMatthew Dillon AH9300(ah)->calibration_data_source_address = 0;
4201b7d5e03cSMatthew Dillon }
4202b7d5e03cSMatthew Dillon }
4203b7d5e03cSMatthew Dillon
4204b7d5e03cSMatthew Dillon /*
4205b7d5e03cSMatthew Dillon * ##### should be an ifdef test for any AP usage,
4206b7d5e03cSMatthew Dillon * either in driver or in nart
4207b7d5e03cSMatthew Dillon */
4208b7d5e03cSMatthew Dillon if ((AH9300(ah)->calibration_data_try == calibration_data_none ||
4209b7d5e03cSMatthew Dillon AH9300(ah)->calibration_data_try == calibration_data_flash) &&
4210b7d5e03cSMatthew Dillon AH9300(ah)->try_flash && nptr < 0)
4211b7d5e03cSMatthew Dillon {
4212b7d5e03cSMatthew Dillon ath_hal_printf(ah, "Restoring Cal data from Flash\n");
4213b7d5e03cSMatthew Dillon AH9300(ah)->calibration_data_source = calibration_data_flash;
4214b7d5e03cSMatthew Dillon /* how are we supposed to set this for flash? */
4215b7d5e03cSMatthew Dillon AH9300(ah)->calibration_data_source_address = 0;
4216b7d5e03cSMatthew Dillon nptr = ar9300_eeprom_restore_from_flash(ah, mptr, mdata_size);
4217b7d5e03cSMatthew Dillon if (nptr < 0) {
4218b7d5e03cSMatthew Dillon AH9300(ah)->calibration_data_source = calibration_data_none;
4219b7d5e03cSMatthew Dillon AH9300(ah)->calibration_data_source_address = 0;
4220b7d5e03cSMatthew Dillon }
4221b7d5e03cSMatthew Dillon }
4222b7d5e03cSMatthew Dillon
4223b7d5e03cSMatthew Dillon if ((AH9300(ah)->calibration_data_try == calibration_data_none ||
4224b7d5e03cSMatthew Dillon AH9300(ah)->calibration_data_try == calibration_data_otp) &&
4225b7d5e03cSMatthew Dillon AH9300(ah)->try_otp && nptr < 0)
4226b7d5e03cSMatthew Dillon {
4227b7d5e03cSMatthew Dillon ath_hal_printf(ah, "Restoring Cal data from OTP\n");
4228b7d5e03cSMatthew Dillon AH9300(ah)->calibration_data_source = calibration_data_otp;
4229b7d5e03cSMatthew Dillon if (AH9300(ah)->calibration_data_try_address != 0) {
4230b7d5e03cSMatthew Dillon AH9300(ah)->calibration_data_source_address =
4231b7d5e03cSMatthew Dillon AH9300(ah)->calibration_data_try_address;
4232b7d5e03cSMatthew Dillon } else {
4233b7d5e03cSMatthew Dillon AH9300(ah)->calibration_data_source_address =
4234b7d5e03cSMatthew Dillon ar9300_eeprom_base_address(ah);
4235b7d5e03cSMatthew Dillon }
4236b7d5e03cSMatthew Dillon nptr = ar9300_eeprom_restore_internal_address(
4237b7d5e03cSMatthew Dillon ah, mptr, mdata_size, AH9300(ah)->calibration_data_source_address, 0);
4238b7d5e03cSMatthew Dillon if (nptr < 0) {
4239b7d5e03cSMatthew Dillon AH9300(ah)->calibration_data_source = calibration_data_none;
4240b7d5e03cSMatthew Dillon AH9300(ah)->calibration_data_source_address = 0;
4241b7d5e03cSMatthew Dillon }
4242b7d5e03cSMatthew Dillon }
4243b7d5e03cSMatthew Dillon
4244b7d5e03cSMatthew Dillon #ifdef ATH_CAL_NAND_FLASH
4245b7d5e03cSMatthew Dillon if ((AH9300(ah)->calibration_data_try == calibration_data_none ||
4246b7d5e03cSMatthew Dillon AH9300(ah)->calibration_data_try == calibration_data_nand) &&
4247b7d5e03cSMatthew Dillon AH9300(ah)->try_nand && nptr < 0)
4248b7d5e03cSMatthew Dillon {
4249b7d5e03cSMatthew Dillon AH9300(ah)->calibration_data_source = calibration_data_nand;
4250b7d5e03cSMatthew Dillon AH9300(ah)->calibration_data_source_address = ((unsigned int)(AH_PRIVATE(ah)->ah_st)) + base_address_nand;
4251b7d5e03cSMatthew Dillon if(ar9300_calibration_data_read(
4252b7d5e03cSMatthew Dillon ah, AH9300(ah)->calibration_data_source_address,
4253b7d5e03cSMatthew Dillon (u_int8_t *)mptr, mdata_size) == AH_TRUE)
4254b7d5e03cSMatthew Dillon {
4255b7d5e03cSMatthew Dillon nptr = mdata_size;
4256b7d5e03cSMatthew Dillon }
4257b7d5e03cSMatthew Dillon /*nptr=ar9300EepromRestoreInternalAddress(ah, mptr, mdataSize, CalibrationDataSourceAddress);*/
4258b7d5e03cSMatthew Dillon if(nptr < 0)
4259b7d5e03cSMatthew Dillon {
4260b7d5e03cSMatthew Dillon AH9300(ah)->calibration_data_source = calibration_data_none;
4261b7d5e03cSMatthew Dillon AH9300(ah)->calibration_data_source_address = 0;
4262b7d5e03cSMatthew Dillon }
4263b7d5e03cSMatthew Dillon }
4264b7d5e03cSMatthew Dillon #endif
4265b7d5e03cSMatthew Dillon if (nptr < 0) {
4266b7d5e03cSMatthew Dillon ath_hal_printf(ah, "%s[%d] No vaid CAL, calling default template\n",
4267b7d5e03cSMatthew Dillon __func__, __LINE__);
4268b7d5e03cSMatthew Dillon nptr = ar9300_eeprom_restore_something(ah, mptr, mdata_size);
4269b7d5e03cSMatthew Dillon }
4270b7d5e03cSMatthew Dillon
4271b7d5e03cSMatthew Dillon return nptr;
4272b7d5e03cSMatthew Dillon }
4273b7d5e03cSMatthew Dillon
4274b7d5e03cSMatthew Dillon /******************************************************************************/
4275b7d5e03cSMatthew Dillon /*!
4276b7d5e03cSMatthew Dillon ** \brief Eeprom Swapping Function
4277b7d5e03cSMatthew Dillon **
4278b7d5e03cSMatthew Dillon ** This function will swap the contents of the "longer" EEPROM data items
4279b7d5e03cSMatthew Dillon ** to ensure they are consistent with the endian requirements for the platform
4280b7d5e03cSMatthew Dillon ** they are being compiled for
4281b7d5e03cSMatthew Dillon **
4282b7d5e03cSMatthew Dillon ** \param eh Pointer to the EEPROM data structure
4283b7d5e03cSMatthew Dillon ** \return N/A
4284b7d5e03cSMatthew Dillon */
4285b7d5e03cSMatthew Dillon #if AH_BYTE_ORDER == AH_BIG_ENDIAN
4286b7d5e03cSMatthew Dillon void
ar9300_swap_eeprom(ar9300_eeprom_t * eep)4287b7d5e03cSMatthew Dillon ar9300_swap_eeprom(ar9300_eeprom_t *eep)
4288b7d5e03cSMatthew Dillon {
4289b7d5e03cSMatthew Dillon u_int32_t dword;
4290b7d5e03cSMatthew Dillon u_int16_t word;
4291b7d5e03cSMatthew Dillon int i;
4292b7d5e03cSMatthew Dillon
4293b7d5e03cSMatthew Dillon word = __bswap16(eep->base_eep_header.reg_dmn[0]);
4294b7d5e03cSMatthew Dillon eep->base_eep_header.reg_dmn[0] = word;
4295b7d5e03cSMatthew Dillon
4296b7d5e03cSMatthew Dillon word = __bswap16(eep->base_eep_header.reg_dmn[1]);
4297b7d5e03cSMatthew Dillon eep->base_eep_header.reg_dmn[1] = word;
4298b7d5e03cSMatthew Dillon
4299b7d5e03cSMatthew Dillon dword = __bswap32(eep->base_eep_header.swreg);
4300b7d5e03cSMatthew Dillon eep->base_eep_header.swreg = dword;
4301b7d5e03cSMatthew Dillon
4302b7d5e03cSMatthew Dillon dword = __bswap32(eep->modal_header_2g.ant_ctrl_common);
4303b7d5e03cSMatthew Dillon eep->modal_header_2g.ant_ctrl_common = dword;
4304b7d5e03cSMatthew Dillon
4305b7d5e03cSMatthew Dillon dword = __bswap32(eep->modal_header_2g.ant_ctrl_common2);
4306b7d5e03cSMatthew Dillon eep->modal_header_2g.ant_ctrl_common2 = dword;
4307b7d5e03cSMatthew Dillon
4308b7d5e03cSMatthew Dillon dword = __bswap32(eep->modal_header_2g.paprd_rate_mask_ht20);
4309b7d5e03cSMatthew Dillon eep->modal_header_2g.paprd_rate_mask_ht20 = dword;
4310b7d5e03cSMatthew Dillon
4311b7d5e03cSMatthew Dillon dword = __bswap32(eep->modal_header_2g.paprd_rate_mask_ht40);
4312b7d5e03cSMatthew Dillon eep->modal_header_2g.paprd_rate_mask_ht40 = dword;
4313b7d5e03cSMatthew Dillon
4314b7d5e03cSMatthew Dillon dword = __bswap32(eep->modal_header_5g.ant_ctrl_common);
4315b7d5e03cSMatthew Dillon eep->modal_header_5g.ant_ctrl_common = dword;
4316b7d5e03cSMatthew Dillon
4317b7d5e03cSMatthew Dillon dword = __bswap32(eep->modal_header_5g.ant_ctrl_common2);
4318b7d5e03cSMatthew Dillon eep->modal_header_5g.ant_ctrl_common2 = dword;
4319b7d5e03cSMatthew Dillon
4320b7d5e03cSMatthew Dillon dword = __bswap32(eep->modal_header_5g.paprd_rate_mask_ht20);
4321b7d5e03cSMatthew Dillon eep->modal_header_5g.paprd_rate_mask_ht20 = dword;
4322b7d5e03cSMatthew Dillon
4323b7d5e03cSMatthew Dillon dword = __bswap32(eep->modal_header_5g.paprd_rate_mask_ht40);
4324b7d5e03cSMatthew Dillon eep->modal_header_5g.paprd_rate_mask_ht40 = dword;
4325b7d5e03cSMatthew Dillon
4326b7d5e03cSMatthew Dillon for (i = 0; i < OSPREY_MAX_CHAINS; i++) {
4327b7d5e03cSMatthew Dillon word = __bswap16(eep->modal_header_2g.ant_ctrl_chain[i]);
4328b7d5e03cSMatthew Dillon eep->modal_header_2g.ant_ctrl_chain[i] = word;
4329b7d5e03cSMatthew Dillon
4330b7d5e03cSMatthew Dillon word = __bswap16(eep->modal_header_5g.ant_ctrl_chain[i]);
4331b7d5e03cSMatthew Dillon eep->modal_header_5g.ant_ctrl_chain[i] = word;
4332b7d5e03cSMatthew Dillon }
4333b7d5e03cSMatthew Dillon }
4334b7d5e03cSMatthew Dillon
ar9300_eeprom_template_swap(void)4335b7d5e03cSMatthew Dillon void ar9300_eeprom_template_swap(void)
4336b7d5e03cSMatthew Dillon {
4337b7d5e03cSMatthew Dillon int it;
4338b7d5e03cSMatthew Dillon ar9300_eeprom_t *dptr;
4339b7d5e03cSMatthew Dillon
4340b7d5e03cSMatthew Dillon for (it = 0; it < ARRAY_LENGTH(default9300); it++) {
4341b7d5e03cSMatthew Dillon dptr = ar9300_eeprom_struct_default(it);
4342b7d5e03cSMatthew Dillon if (dptr != 0) {
4343b7d5e03cSMatthew Dillon ar9300_swap_eeprom(dptr);
4344b7d5e03cSMatthew Dillon }
4345b7d5e03cSMatthew Dillon }
4346b7d5e03cSMatthew Dillon }
4347b7d5e03cSMatthew Dillon #endif
4348b7d5e03cSMatthew Dillon
4349b7d5e03cSMatthew Dillon
4350b7d5e03cSMatthew Dillon /*
4351b7d5e03cSMatthew Dillon * Restore the configuration structure by reading the eeprom.
4352b7d5e03cSMatthew Dillon * This function destroys any existing in-memory structure content.
4353b7d5e03cSMatthew Dillon */
4354b7d5e03cSMatthew Dillon HAL_BOOL
ar9300_eeprom_restore(struct ath_hal * ah)4355b7d5e03cSMatthew Dillon ar9300_eeprom_restore(struct ath_hal *ah)
4356b7d5e03cSMatthew Dillon {
4357b7d5e03cSMatthew Dillon struct ath_hal_9300 *ahp = AH9300(ah);
4358b7d5e03cSMatthew Dillon ar9300_eeprom_t *mptr;
4359b7d5e03cSMatthew Dillon int mdata_size;
4360b7d5e03cSMatthew Dillon HAL_BOOL status = AH_FALSE;
4361b7d5e03cSMatthew Dillon
4362b7d5e03cSMatthew Dillon mptr = &ahp->ah_eeprom;
4363b7d5e03cSMatthew Dillon mdata_size = ar9300_eeprom_struct_size();
4364b7d5e03cSMatthew Dillon
4365b7d5e03cSMatthew Dillon if (mptr != 0 && mdata_size > 0) {
4366b7d5e03cSMatthew Dillon #if AH_BYTE_ORDER == AH_BIG_ENDIAN
4367b7d5e03cSMatthew Dillon ar9300_eeprom_template_swap();
4368b7d5e03cSMatthew Dillon ar9300_swap_eeprom(mptr);
4369b7d5e03cSMatthew Dillon #endif
4370b7d5e03cSMatthew Dillon /*
4371b7d5e03cSMatthew Dillon * At this point, mptr points to the eeprom data structure
4372b7d5e03cSMatthew Dillon * in it's "default" state. If this is big endian, swap the
4373b7d5e03cSMatthew Dillon * data structures back to "little endian" form.
4374b7d5e03cSMatthew Dillon */
4375b7d5e03cSMatthew Dillon if (ar9300_eeprom_restore_internal(ah, mptr, mdata_size) >= 0) {
4376b7d5e03cSMatthew Dillon status = AH_TRUE;
4377b7d5e03cSMatthew Dillon }
4378b7d5e03cSMatthew Dillon
4379b7d5e03cSMatthew Dillon #if AH_BYTE_ORDER == AH_BIG_ENDIAN
4380b7d5e03cSMatthew Dillon /* Second Swap, back to Big Endian */
4381b7d5e03cSMatthew Dillon ar9300_eeprom_template_swap();
4382b7d5e03cSMatthew Dillon ar9300_swap_eeprom(mptr);
4383b7d5e03cSMatthew Dillon #endif
4384b7d5e03cSMatthew Dillon
4385b7d5e03cSMatthew Dillon }
4386b7d5e03cSMatthew Dillon ahp->ah_2g_paprd_rate_mask_ht40 =
4387b7d5e03cSMatthew Dillon mptr->modal_header_2g.paprd_rate_mask_ht40;
4388b7d5e03cSMatthew Dillon ahp->ah_2g_paprd_rate_mask_ht20 =
4389b7d5e03cSMatthew Dillon mptr->modal_header_2g.paprd_rate_mask_ht20;
4390b7d5e03cSMatthew Dillon ahp->ah_5g_paprd_rate_mask_ht40 =
4391b7d5e03cSMatthew Dillon mptr->modal_header_5g.paprd_rate_mask_ht40;
4392b7d5e03cSMatthew Dillon ahp->ah_5g_paprd_rate_mask_ht20 =
4393b7d5e03cSMatthew Dillon mptr->modal_header_5g.paprd_rate_mask_ht20;
4394b7d5e03cSMatthew Dillon return status;
4395b7d5e03cSMatthew Dillon }
4396b7d5e03cSMatthew Dillon
ar9300_thermometer_get(struct ath_hal * ah)4397b7d5e03cSMatthew Dillon int32_t ar9300_thermometer_get(struct ath_hal *ah)
4398b7d5e03cSMatthew Dillon {
4399b7d5e03cSMatthew Dillon struct ath_hal_9300 *ahp = AH9300(ah);
4400b7d5e03cSMatthew Dillon int thermometer;
4401b7d5e03cSMatthew Dillon thermometer =
4402b7d5e03cSMatthew Dillon (ahp->ah_eeprom.base_eep_header.misc_configuration >> 1) & 0x3;
4403b7d5e03cSMatthew Dillon thermometer--;
4404b7d5e03cSMatthew Dillon return thermometer;
4405b7d5e03cSMatthew Dillon }
4406b7d5e03cSMatthew Dillon
ar9300_thermometer_apply(struct ath_hal * ah)4407b7d5e03cSMatthew Dillon HAL_BOOL ar9300_thermometer_apply(struct ath_hal *ah)
4408b7d5e03cSMatthew Dillon {
4409b7d5e03cSMatthew Dillon int thermometer = ar9300_thermometer_get(ah);
4410b7d5e03cSMatthew Dillon
4411b7d5e03cSMatthew Dillon /* ch0_RXTX4 */
4412b7d5e03cSMatthew Dillon /*#define AR_PHY_65NM_CH0_RXTX4 AR_PHY_65NM(ch0_RXTX4)*/
4413b7d5e03cSMatthew Dillon #define AR_PHY_65NM_CH1_RXTX4 AR_PHY_65NM(ch1_RXTX4)
4414b7d5e03cSMatthew Dillon #define AR_PHY_65NM_CH2_RXTX4 AR_PHY_65NM(ch2_RXTX4)
4415b7d5e03cSMatthew Dillon /*#define AR_PHY_65NM_CH0_RXTX4_THERM_ON 0x10000000*/
4416b7d5e03cSMatthew Dillon /*#define AR_PHY_65NM_CH0_RXTX4_THERM_ON_S 28*/
4417b7d5e03cSMatthew Dillon #define AR_PHY_65NM_CH0_RXTX4_THERM_ON_OVR_S 29
4418b7d5e03cSMatthew Dillon #define AR_PHY_65NM_CH0_RXTX4_THERM_ON_OVR \
4419b7d5e03cSMatthew Dillon (0x1<<AR_PHY_65NM_CH0_RXTX4_THERM_ON_OVR_S)
4420b7d5e03cSMatthew Dillon
4421b7d5e03cSMatthew Dillon if (thermometer < 0) {
4422b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah,
4423b7d5e03cSMatthew Dillon AR_PHY_65NM_CH0_RXTX4, AR_PHY_65NM_CH0_RXTX4_THERM_ON_OVR, 0);
4424b7d5e03cSMatthew Dillon if (!AR_SREV_HORNET(ah) && !AR_SREV_POSEIDON(ah)) {
4425b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah,
4426b7d5e03cSMatthew Dillon AR_PHY_65NM_CH1_RXTX4, AR_PHY_65NM_CH0_RXTX4_THERM_ON_OVR, 0);
4427a20e5e51SMatthew Dillon if (!AR_SREV_WASP(ah) && !AR_SREV_JUPITER(ah) && !AR_SREV_HONEYBEE(ah) ) {
4428b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah, AR_PHY_65NM_CH2_RXTX4,
4429b7d5e03cSMatthew Dillon AR_PHY_65NM_CH0_RXTX4_THERM_ON_OVR, 0);
4430b7d5e03cSMatthew Dillon }
4431b7d5e03cSMatthew Dillon }
4432b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah,
4433b7d5e03cSMatthew Dillon AR_PHY_65NM_CH0_RXTX4, AR_PHY_65NM_CH0_RXTX4_THERM_ON, 0);
4434b7d5e03cSMatthew Dillon if (!AR_SREV_HORNET(ah) && !AR_SREV_POSEIDON(ah)) {
4435b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah,
4436b7d5e03cSMatthew Dillon AR_PHY_65NM_CH1_RXTX4, AR_PHY_65NM_CH0_RXTX4_THERM_ON, 0);
4437a20e5e51SMatthew Dillon if (!AR_SREV_WASP(ah) && !AR_SREV_JUPITER(ah) && !AR_SREV_HONEYBEE(ah) ) {
4438b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah,
4439b7d5e03cSMatthew Dillon AR_PHY_65NM_CH2_RXTX4, AR_PHY_65NM_CH0_RXTX4_THERM_ON, 0);
4440b7d5e03cSMatthew Dillon }
4441b7d5e03cSMatthew Dillon }
4442b7d5e03cSMatthew Dillon } else {
4443b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah,
4444b7d5e03cSMatthew Dillon AR_PHY_65NM_CH0_RXTX4, AR_PHY_65NM_CH0_RXTX4_THERM_ON_OVR, 1);
4445b7d5e03cSMatthew Dillon if (!AR_SREV_HORNET(ah) && !AR_SREV_POSEIDON(ah)) {
4446b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah,
4447b7d5e03cSMatthew Dillon AR_PHY_65NM_CH1_RXTX4, AR_PHY_65NM_CH0_RXTX4_THERM_ON_OVR, 1);
4448a20e5e51SMatthew Dillon if (!AR_SREV_WASP(ah) && !AR_SREV_JUPITER(ah) && !AR_SREV_HONEYBEE(ah) ) {
4449b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah, AR_PHY_65NM_CH2_RXTX4,
4450b7d5e03cSMatthew Dillon AR_PHY_65NM_CH0_RXTX4_THERM_ON_OVR, 1);
4451b7d5e03cSMatthew Dillon }
4452b7d5e03cSMatthew Dillon }
4453b7d5e03cSMatthew Dillon if (thermometer == 0) {
4454b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah,
4455b7d5e03cSMatthew Dillon AR_PHY_65NM_CH0_RXTX4, AR_PHY_65NM_CH0_RXTX4_THERM_ON, 1);
4456b7d5e03cSMatthew Dillon if (!AR_SREV_HORNET(ah) && !AR_SREV_POSEIDON(ah)) {
4457b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah,
4458b7d5e03cSMatthew Dillon AR_PHY_65NM_CH1_RXTX4, AR_PHY_65NM_CH0_RXTX4_THERM_ON, 0);
4459a20e5e51SMatthew Dillon if (!AR_SREV_WASP(ah) && !AR_SREV_JUPITER(ah) && !AR_SREV_HONEYBEE(ah) ) {
4460b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah, AR_PHY_65NM_CH2_RXTX4,
4461b7d5e03cSMatthew Dillon AR_PHY_65NM_CH0_RXTX4_THERM_ON, 0);
4462b7d5e03cSMatthew Dillon }
4463b7d5e03cSMatthew Dillon }
4464b7d5e03cSMatthew Dillon } else if (thermometer == 1) {
4465b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah,
4466b7d5e03cSMatthew Dillon AR_PHY_65NM_CH0_RXTX4, AR_PHY_65NM_CH0_RXTX4_THERM_ON, 0);
4467b7d5e03cSMatthew Dillon if (!AR_SREV_HORNET(ah) && !AR_SREV_POSEIDON(ah)) {
4468b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah,
4469b7d5e03cSMatthew Dillon AR_PHY_65NM_CH1_RXTX4, AR_PHY_65NM_CH0_RXTX4_THERM_ON, 1);
4470a20e5e51SMatthew Dillon if (!AR_SREV_WASP(ah) && !AR_SREV_JUPITER(ah) && !AR_SREV_HONEYBEE(ah) ) {
4471b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah, AR_PHY_65NM_CH2_RXTX4,
4472b7d5e03cSMatthew Dillon AR_PHY_65NM_CH0_RXTX4_THERM_ON, 0);
4473b7d5e03cSMatthew Dillon }
4474b7d5e03cSMatthew Dillon }
4475b7d5e03cSMatthew Dillon } else if (thermometer == 2) {
4476b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah,
4477b7d5e03cSMatthew Dillon AR_PHY_65NM_CH0_RXTX4, AR_PHY_65NM_CH0_RXTX4_THERM_ON, 0);
4478b7d5e03cSMatthew Dillon if (!AR_SREV_HORNET(ah) && !AR_SREV_POSEIDON(ah)) {
4479b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah,
4480b7d5e03cSMatthew Dillon AR_PHY_65NM_CH1_RXTX4, AR_PHY_65NM_CH0_RXTX4_THERM_ON, 0);
4481a20e5e51SMatthew Dillon if (!AR_SREV_WASP(ah) && !AR_SREV_JUPITER(ah) && !AR_SREV_HONEYBEE(ah) ) {
4482b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah, AR_PHY_65NM_CH2_RXTX4,
4483b7d5e03cSMatthew Dillon AR_PHY_65NM_CH0_RXTX4_THERM_ON, 1);
4484b7d5e03cSMatthew Dillon }
4485b7d5e03cSMatthew Dillon }
4486b7d5e03cSMatthew Dillon }
4487b7d5e03cSMatthew Dillon }
4488b7d5e03cSMatthew Dillon return AH_TRUE;
4489b7d5e03cSMatthew Dillon }
4490b7d5e03cSMatthew Dillon
ar9300_tuning_caps_params_get(struct ath_hal * ah)4491b7d5e03cSMatthew Dillon static int32_t ar9300_tuning_caps_params_get(struct ath_hal *ah)
4492b7d5e03cSMatthew Dillon {
4493b7d5e03cSMatthew Dillon int tuning_caps_params;
4494b7d5e03cSMatthew Dillon ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom;
4495b7d5e03cSMatthew Dillon tuning_caps_params = eep->base_eep_header.params_for_tuning_caps[0];
4496b7d5e03cSMatthew Dillon return tuning_caps_params;
4497b7d5e03cSMatthew Dillon }
4498b7d5e03cSMatthew Dillon
4499b7d5e03cSMatthew Dillon /*
4500b7d5e03cSMatthew Dillon * Read the tuning caps params from eeprom and set to correct register.
4501b7d5e03cSMatthew Dillon * To regulation the frequency accuracy.
4502b7d5e03cSMatthew Dillon */
ar9300_tuning_caps_apply(struct ath_hal * ah)4503b7d5e03cSMatthew Dillon HAL_BOOL ar9300_tuning_caps_apply(struct ath_hal *ah)
4504b7d5e03cSMatthew Dillon {
4505b7d5e03cSMatthew Dillon int tuning_caps_params;
4506b7d5e03cSMatthew Dillon ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom;
4507b7d5e03cSMatthew Dillon tuning_caps_params = ar9300_tuning_caps_params_get(ah);
4508b7d5e03cSMatthew Dillon if ((eep->base_eep_header.feature_enable & 0x40) >> 6) {
4509b7d5e03cSMatthew Dillon tuning_caps_params &= 0x7f;
4510b7d5e03cSMatthew Dillon
4511a20e5e51SMatthew Dillon if (AR_SREV_POSEIDON(ah) || AR_SREV_WASP(ah) || AR_SREV_HONEYBEE(ah)) {
4512a20e5e51SMatthew Dillon return true;
4513a20e5e51SMatthew Dillon } else if (AR_SREV_HORNET(ah)) {
4514a20e5e51SMatthew Dillon OS_REG_RMW_FIELD(ah,
4515a20e5e51SMatthew Dillon AR_HORNET_CH0_XTAL, AR_OSPREY_CHO_XTAL_CAPINDAC,
4516a20e5e51SMatthew Dillon tuning_caps_params);
4517a20e5e51SMatthew Dillon OS_REG_RMW_FIELD(ah,
4518a20e5e51SMatthew Dillon AR_HORNET_CH0_XTAL, AR_OSPREY_CHO_XTAL_CAPOUTDAC,
4519a20e5e51SMatthew Dillon tuning_caps_params);
4520b7d5e03cSMatthew Dillon } else if (AR_SREV_SCORPION(ah)) {
4521b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah,
4522b7d5e03cSMatthew Dillon AR_SCORPION_CH0_XTAL, AR_OSPREY_CHO_XTAL_CAPINDAC,
4523b7d5e03cSMatthew Dillon tuning_caps_params);
4524b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah,
4525b7d5e03cSMatthew Dillon AR_SCORPION_CH0_XTAL, AR_OSPREY_CHO_XTAL_CAPOUTDAC,
4526b7d5e03cSMatthew Dillon tuning_caps_params);
4527b7d5e03cSMatthew Dillon } else {
4528b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah,
4529b7d5e03cSMatthew Dillon AR_OSPREY_CH0_XTAL, AR_OSPREY_CHO_XTAL_CAPINDAC,
4530b7d5e03cSMatthew Dillon tuning_caps_params);
4531b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah,
4532b7d5e03cSMatthew Dillon AR_OSPREY_CH0_XTAL, AR_OSPREY_CHO_XTAL_CAPOUTDAC,
4533b7d5e03cSMatthew Dillon tuning_caps_params);
4534b7d5e03cSMatthew Dillon }
4535b7d5e03cSMatthew Dillon
4536b7d5e03cSMatthew Dillon }
4537b7d5e03cSMatthew Dillon return AH_TRUE;
4538b7d5e03cSMatthew Dillon }
4539b7d5e03cSMatthew Dillon
4540b7d5e03cSMatthew Dillon /*
4541b7d5e03cSMatthew Dillon * Read the tx_frame_to_xpa_on param from eeprom and apply the value to
4542b7d5e03cSMatthew Dillon * correct register.
4543b7d5e03cSMatthew Dillon */
ar9300_xpa_timing_control_apply(struct ath_hal * ah,HAL_BOOL is_2ghz)4544b7d5e03cSMatthew Dillon HAL_BOOL ar9300_xpa_timing_control_apply(struct ath_hal *ah, HAL_BOOL is_2ghz)
4545b7d5e03cSMatthew Dillon {
4546b7d5e03cSMatthew Dillon u_int8_t xpa_timing_control;
4547b7d5e03cSMatthew Dillon ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom;
4548b7d5e03cSMatthew Dillon if ((eep->base_eep_header.feature_enable & 0x80) >> 7) {
4549a20e5e51SMatthew Dillon if (AR_SREV_OSPREY(ah) || AR_SREV_AR9580(ah) || AR_SREV_WASP(ah) || AR_SREV_HONEYBEE(ah)) {
4550b7d5e03cSMatthew Dillon if (is_2ghz) {
4551b7d5e03cSMatthew Dillon xpa_timing_control = eep->modal_header_2g.tx_frame_to_xpa_on;
4552b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah,
4553b7d5e03cSMatthew Dillon AR_PHY_XPA_TIMING_CTL, AR_PHY_XPA_TIMING_CTL_FRAME_XPAB_ON,
4554b7d5e03cSMatthew Dillon xpa_timing_control);
4555b7d5e03cSMatthew Dillon } else {
4556b7d5e03cSMatthew Dillon xpa_timing_control = eep->modal_header_5g.tx_frame_to_xpa_on;
4557b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah,
4558b7d5e03cSMatthew Dillon AR_PHY_XPA_TIMING_CTL, AR_PHY_XPA_TIMING_CTL_FRAME_XPAA_ON,
4559b7d5e03cSMatthew Dillon xpa_timing_control);
4560b7d5e03cSMatthew Dillon }
4561b7d5e03cSMatthew Dillon }
4562b7d5e03cSMatthew Dillon }
4563b7d5e03cSMatthew Dillon return AH_TRUE;
4564b7d5e03cSMatthew Dillon }
4565b7d5e03cSMatthew Dillon
4566b7d5e03cSMatthew Dillon
4567b7d5e03cSMatthew Dillon /*
4568b7d5e03cSMatthew Dillon * Read the xLNA_bias_strength param from eeprom and apply the value to
4569b7d5e03cSMatthew Dillon * correct register.
4570b7d5e03cSMatthew Dillon */
ar9300_x_lNA_bias_strength_apply(struct ath_hal * ah,HAL_BOOL is_2ghz)4571b7d5e03cSMatthew Dillon HAL_BOOL ar9300_x_lNA_bias_strength_apply(struct ath_hal *ah, HAL_BOOL is_2ghz)
4572b7d5e03cSMatthew Dillon {
4573b7d5e03cSMatthew Dillon u_int8_t x_lNABias;
4574b7d5e03cSMatthew Dillon u_int32_t value = 0;
4575b7d5e03cSMatthew Dillon ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom;
4576b7d5e03cSMatthew Dillon
4577b7d5e03cSMatthew Dillon if ((eep->base_eep_header.misc_configuration & 0x40) >> 6) {
4578b7d5e03cSMatthew Dillon if (AR_SREV_OSPREY(ah)) {
4579b7d5e03cSMatthew Dillon if (is_2ghz) {
4580b7d5e03cSMatthew Dillon x_lNABias = eep->modal_header_2g.xLNA_bias_strength;
4581b7d5e03cSMatthew Dillon } else {
4582b7d5e03cSMatthew Dillon x_lNABias = eep->modal_header_5g.xLNA_bias_strength;
4583b7d5e03cSMatthew Dillon }
4584b7d5e03cSMatthew Dillon value = x_lNABias & ( 0x03 ); // bit0,1 for chain0
4585b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah,
4586b7d5e03cSMatthew Dillon AR_PHY_65NM_CH0_RXTX4, AR_PHY_65NM_RXTX4_XLNA_BIAS, value);
4587b7d5e03cSMatthew Dillon value = (x_lNABias >> 2) & ( 0x03 ); // bit2,3 for chain1
4588b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah,
4589b7d5e03cSMatthew Dillon AR_PHY_65NM_CH1_RXTX4, AR_PHY_65NM_RXTX4_XLNA_BIAS, value);
4590b7d5e03cSMatthew Dillon value = (x_lNABias >> 4) & ( 0x03 ); // bit4,5 for chain2
4591b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah,
4592b7d5e03cSMatthew Dillon AR_PHY_65NM_CH2_RXTX4, AR_PHY_65NM_RXTX4_XLNA_BIAS, value);
4593b7d5e03cSMatthew Dillon }
4594b7d5e03cSMatthew Dillon }
4595b7d5e03cSMatthew Dillon return AH_TRUE;
4596b7d5e03cSMatthew Dillon }
4597b7d5e03cSMatthew Dillon
4598b7d5e03cSMatthew Dillon
4599b7d5e03cSMatthew Dillon /*
4600b7d5e03cSMatthew Dillon * Read EEPROM header info and program the device for correct operation
4601b7d5e03cSMatthew Dillon * given the channel value.
4602b7d5e03cSMatthew Dillon */
4603b7d5e03cSMatthew Dillon HAL_BOOL
ar9300_eeprom_set_board_values(struct ath_hal * ah,const struct ieee80211_channel * chan)4604b7d5e03cSMatthew Dillon ar9300_eeprom_set_board_values(struct ath_hal *ah, const struct ieee80211_channel *chan)
4605b7d5e03cSMatthew Dillon {
4606b7d5e03cSMatthew Dillon HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan);
4607b7d5e03cSMatthew Dillon
4608b7d5e03cSMatthew Dillon ar9300_xpa_bias_level_apply(ah, IEEE80211_IS_CHAN_2GHZ(chan));
4609b7d5e03cSMatthew Dillon
4610b7d5e03cSMatthew Dillon ar9300_xpa_timing_control_apply(ah, IEEE80211_IS_CHAN_2GHZ(chan));
4611b7d5e03cSMatthew Dillon
4612b7d5e03cSMatthew Dillon ar9300_ant_ctrl_apply(ah, IEEE80211_IS_CHAN_2GHZ(chan));
4613b7d5e03cSMatthew Dillon ar9300_drive_strength_apply(ah);
4614b7d5e03cSMatthew Dillon
4615b7d5e03cSMatthew Dillon ar9300_x_lNA_bias_strength_apply(ah, IEEE80211_IS_CHAN_2GHZ(chan));
4616b7d5e03cSMatthew Dillon
4617b7d5e03cSMatthew Dillon /* wait for Poseidon internal regular turnning */
4618b7d5e03cSMatthew Dillon /* for Hornet we move it before initPLL to avoid an access issue */
4619b7d5e03cSMatthew Dillon /* Function not used when EMULATION. */
4620a20e5e51SMatthew Dillon if (!AR_SREV_HORNET(ah) && !AR_SREV_WASP(ah) && !AR_SREV_HONEYBEE(ah)) {
4621b7d5e03cSMatthew Dillon ar9300_internal_regulator_apply(ah);
4622b7d5e03cSMatthew Dillon }
4623b7d5e03cSMatthew Dillon
4624b7d5e03cSMatthew Dillon ar9300_attenuation_apply(ah, ichan->channel);
4625b7d5e03cSMatthew Dillon ar9300_quick_drop_apply(ah, ichan->channel);
4626b7d5e03cSMatthew Dillon ar9300_thermometer_apply(ah);
4627b7d5e03cSMatthew Dillon if(!AR_SREV_WASP(ah))
4628b7d5e03cSMatthew Dillon {
4629b7d5e03cSMatthew Dillon ar9300_tuning_caps_apply(ah);
4630b7d5e03cSMatthew Dillon }
4631b7d5e03cSMatthew Dillon
4632b7d5e03cSMatthew Dillon ar9300_tx_end_to_xpab_off_apply(ah, ichan->channel);
4633b7d5e03cSMatthew Dillon
4634b7d5e03cSMatthew Dillon return AH_TRUE;
4635b7d5e03cSMatthew Dillon }
4636b7d5e03cSMatthew Dillon
4637b7d5e03cSMatthew Dillon u_int8_t *
ar9300_eeprom_get_spur_chans_ptr(struct ath_hal * ah,HAL_BOOL is_2ghz)4638b7d5e03cSMatthew Dillon ar9300_eeprom_get_spur_chans_ptr(struct ath_hal *ah, HAL_BOOL is_2ghz)
4639b7d5e03cSMatthew Dillon {
4640b7d5e03cSMatthew Dillon ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom;
4641b7d5e03cSMatthew Dillon
4642b7d5e03cSMatthew Dillon if (is_2ghz) {
4643b7d5e03cSMatthew Dillon return &(eep->modal_header_2g.spur_chans[0]);
4644b7d5e03cSMatthew Dillon } else {
4645b7d5e03cSMatthew Dillon return &(eep->modal_header_5g.spur_chans[0]);
4646b7d5e03cSMatthew Dillon }
4647b7d5e03cSMatthew Dillon }
4648b7d5e03cSMatthew Dillon
ar9300_eeprom_get_tx_gain_table_number_max(struct ath_hal * ah)4649b7d5e03cSMatthew Dillon static u_int8_t ar9300_eeprom_get_tx_gain_table_number_max(struct ath_hal *ah)
4650b7d5e03cSMatthew Dillon {
4651b7d5e03cSMatthew Dillon unsigned long tx_gain_table_max;
4652b7d5e03cSMatthew Dillon tx_gain_table_max = OS_REG_READ_FIELD(ah,
4653b7d5e03cSMatthew Dillon AR_PHY_TPC_7, AR_PHY_TPC_7_TX_GAIN_TABLE_MAX);
4654b7d5e03cSMatthew Dillon return tx_gain_table_max;
4655b7d5e03cSMatthew Dillon }
4656b7d5e03cSMatthew Dillon
ar9300_eeprom_tx_gain_table_index_max_apply(struct ath_hal * ah,u_int16_t channel)4657b7d5e03cSMatthew Dillon u_int8_t ar9300_eeprom_tx_gain_table_index_max_apply(struct ath_hal *ah, u_int16_t channel)
4658b7d5e03cSMatthew Dillon {
4659b7d5e03cSMatthew Dillon unsigned int index;
4660b7d5e03cSMatthew Dillon ar9300_eeprom_t *ahp_Eeprom;
4661b7d5e03cSMatthew Dillon struct ath_hal_9300 *ahp = AH9300(ah);
4662b7d5e03cSMatthew Dillon
4663b7d5e03cSMatthew Dillon ahp_Eeprom = &ahp->ah_eeprom;
4664b7d5e03cSMatthew Dillon
4665b7d5e03cSMatthew Dillon if (ahp_Eeprom->base_ext1.misc_enable == 0)
4666b7d5e03cSMatthew Dillon return AH_FALSE;
4667b7d5e03cSMatthew Dillon
4668b7d5e03cSMatthew Dillon if (channel < 4000)
4669b7d5e03cSMatthew Dillon {
4670b7d5e03cSMatthew Dillon index = ahp_Eeprom->modal_header_2g.tx_gain_cap;
4671b7d5e03cSMatthew Dillon }
4672b7d5e03cSMatthew Dillon else
4673b7d5e03cSMatthew Dillon {
4674b7d5e03cSMatthew Dillon index = ahp_Eeprom->modal_header_5g.tx_gain_cap;
4675b7d5e03cSMatthew Dillon }
4676b7d5e03cSMatthew Dillon
4677b7d5e03cSMatthew Dillon OS_REG_RMW_FIELD(ah,
4678b7d5e03cSMatthew Dillon AR_PHY_TPC_7, AR_PHY_TPC_7_TX_GAIN_TABLE_MAX, index);
4679b7d5e03cSMatthew Dillon return AH_TRUE;
4680b7d5e03cSMatthew Dillon }
4681b7d5e03cSMatthew Dillon
ar9300_eeprom_get_pcdac_tx_gain_table_i(struct ath_hal * ah,int i,u_int8_t * pcdac)4682b7d5e03cSMatthew Dillon static u_int8_t ar9300_eeprom_get_pcdac_tx_gain_table_i(struct ath_hal *ah,
4683b7d5e03cSMatthew Dillon int i, u_int8_t *pcdac)
4684b7d5e03cSMatthew Dillon {
4685b7d5e03cSMatthew Dillon unsigned long tx_gain;
4686b7d5e03cSMatthew Dillon u_int8_t tx_gain_table_max;
4687b7d5e03cSMatthew Dillon tx_gain_table_max = ar9300_eeprom_get_tx_gain_table_number_max(ah);
4688b7d5e03cSMatthew Dillon if (i <= 0 || i > tx_gain_table_max) {
4689b7d5e03cSMatthew Dillon *pcdac = 0;
4690b7d5e03cSMatthew Dillon return AH_FALSE;
4691b7d5e03cSMatthew Dillon }
4692b7d5e03cSMatthew Dillon
4693b7d5e03cSMatthew Dillon tx_gain = OS_REG_READ(ah, AR_PHY_TXGAIN_TAB(1) + i * 4);
4694b7d5e03cSMatthew Dillon *pcdac = ((tx_gain >> 24) & 0xff);
4695b7d5e03cSMatthew Dillon return AH_TRUE;
4696b7d5e03cSMatthew Dillon }
4697b7d5e03cSMatthew Dillon
ar9300_eeprom_set_tx_gain_cap(struct ath_hal * ah,int * tx_gain_max)4698b7d5e03cSMatthew Dillon u_int8_t ar9300_eeprom_set_tx_gain_cap(struct ath_hal *ah,
4699b7d5e03cSMatthew Dillon int *tx_gain_max)
4700b7d5e03cSMatthew Dillon // pcdac read back from reg, read back value depends on reset 2GHz/5GHz ini
4701b7d5e03cSMatthew Dillon // tx_gain_table, this function will be called twice after each
4702b7d5e03cSMatthew Dillon // band's calibration.
4703b7d5e03cSMatthew Dillon // after 2GHz cal, tx_gain_max[0] has 2GHz, calibration max txgain,
4704b7d5e03cSMatthew Dillon // tx_gain_max[1]=-100
4705b7d5e03cSMatthew Dillon // after 5GHz cal, tx_gain_max[0],tx_gain_max[1] have calibration
4706b7d5e03cSMatthew Dillon // value for both band
4707b7d5e03cSMatthew Dillon // reset is on 5GHz, reg reading from tx_gain_table is for 5GHz,
4708b7d5e03cSMatthew Dillon // so program can't recalculate 2g.tx_gain_cap at this point.
4709b7d5e03cSMatthew Dillon {
4710b7d5e03cSMatthew Dillon int i = 0, ig, im = 0;
4711b7d5e03cSMatthew Dillon u_int8_t pcdac = 0;
4712b7d5e03cSMatthew Dillon u_int8_t tx_gain_table_max;
4713b7d5e03cSMatthew Dillon ar9300_eeprom_t *ahp_Eeprom;
4714b7d5e03cSMatthew Dillon struct ath_hal_9300 *ahp = AH9300(ah);
4715b7d5e03cSMatthew Dillon
4716b7d5e03cSMatthew Dillon ahp_Eeprom = &ahp->ah_eeprom;
4717b7d5e03cSMatthew Dillon
4718b7d5e03cSMatthew Dillon if (ahp_Eeprom->base_ext1.misc_enable == 0)
4719b7d5e03cSMatthew Dillon return AH_FALSE;
4720b7d5e03cSMatthew Dillon
4721b7d5e03cSMatthew Dillon tx_gain_table_max = ar9300_eeprom_get_tx_gain_table_number_max(ah);
4722b7d5e03cSMatthew Dillon
4723b7d5e03cSMatthew Dillon for (i = 0; i < 2; i++) {
4724b7d5e03cSMatthew Dillon if (tx_gain_max[i]>-100) { // -100 didn't cal that band.
4725b7d5e03cSMatthew Dillon if ( i== 0) {
4726b7d5e03cSMatthew Dillon if (tx_gain_max[1]>-100) {
4727b7d5e03cSMatthew Dillon continue;
4728b7d5e03cSMatthew Dillon // both band are calibrated, skip 2GHz 2g.tx_gain_cap reset
4729b7d5e03cSMatthew Dillon }
4730b7d5e03cSMatthew Dillon }
4731b7d5e03cSMatthew Dillon for (ig = 1; ig <= tx_gain_table_max; ig++) {
4732b7d5e03cSMatthew Dillon if (ah != 0 && ah->ah_reset != 0)
4733b7d5e03cSMatthew Dillon {
4734b7d5e03cSMatthew Dillon ar9300_eeprom_get_pcdac_tx_gain_table_i(ah, ig, &pcdac);
4735b7d5e03cSMatthew Dillon if (pcdac >= tx_gain_max[i])
4736b7d5e03cSMatthew Dillon break;
4737b7d5e03cSMatthew Dillon }
4738b7d5e03cSMatthew Dillon }
4739b7d5e03cSMatthew Dillon if (ig+1 <= tx_gain_table_max) {
4740b7d5e03cSMatthew Dillon if (pcdac == tx_gain_max[i])
4741b7d5e03cSMatthew Dillon im = ig;
4742b7d5e03cSMatthew Dillon else
4743b7d5e03cSMatthew Dillon im = ig + 1;
4744b7d5e03cSMatthew Dillon if (i == 0) {
4745b7d5e03cSMatthew Dillon ahp_Eeprom->modal_header_2g.tx_gain_cap = im;
4746b7d5e03cSMatthew Dillon } else {
4747b7d5e03cSMatthew Dillon ahp_Eeprom->modal_header_5g.tx_gain_cap = im;
4748b7d5e03cSMatthew Dillon }
4749b7d5e03cSMatthew Dillon } else {
4750b7d5e03cSMatthew Dillon if (i == 0) {
4751b7d5e03cSMatthew Dillon ahp_Eeprom->modal_header_2g.tx_gain_cap = ig;
4752b7d5e03cSMatthew Dillon } else {
4753b7d5e03cSMatthew Dillon ahp_Eeprom->modal_header_5g.tx_gain_cap = ig;
4754b7d5e03cSMatthew Dillon }
4755b7d5e03cSMatthew Dillon }
4756b7d5e03cSMatthew Dillon }
4757b7d5e03cSMatthew Dillon }
4758b7d5e03cSMatthew Dillon return AH_TRUE;
4759b7d5e03cSMatthew Dillon }
4760