xref: /openbsd-src/sys/dev/ic/ar5xxx.c (revision 6696c7f416694a135c9cfec40fdd875cf7f586fb)
1*6696c7f4Sstsp /*	$OpenBSD: ar5xxx.c,v 1.63 2018/01/31 11:27:03 stsp Exp $	*/
2f51c4ae1Sreyk 
3f51c4ae1Sreyk /*
4ea5b165aSreyk  * Copyright (c) 2004, 2005, 2006, 2007 Reyk Floeter <reyk@openbsd.org>
5f51c4ae1Sreyk  *
691dca01fSreyk  * Permission to use, copy, modify, and distribute this software for any
791dca01fSreyk  * purpose with or without fee is hereby granted, provided that the above
891dca01fSreyk  * copyright notice and this permission notice appear in all copies.
9f51c4ae1Sreyk  *
1091dca01fSreyk  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1191dca01fSreyk  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1291dca01fSreyk  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1391dca01fSreyk  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1491dca01fSreyk  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1591dca01fSreyk  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1691dca01fSreyk  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17f51c4ae1Sreyk  */
18f51c4ae1Sreyk 
19f51c4ae1Sreyk /*
20f51c4ae1Sreyk  * HAL interface for Atheros Wireless LAN devices.
219ebef271Sreyk  * (Please have a look at ar5xxx.h for further information)
22f51c4ae1Sreyk  */
23f51c4ae1Sreyk 
24f51c4ae1Sreyk #include <dev/pci/pcidevs.h>
25f51c4ae1Sreyk #include <dev/ic/ar5xxx.h>
26f51c4ae1Sreyk 
27f51c4ae1Sreyk extern ar5k_attach_t ar5k_ar5210_attach;
28f51c4ae1Sreyk extern ar5k_attach_t ar5k_ar5211_attach;
298a4258edSreyk extern ar5k_attach_t ar5k_ar5212_attach;
30f51c4ae1Sreyk 
31f51c4ae1Sreyk static const struct {
32f51c4ae1Sreyk 	u_int16_t	vendor;
33f51c4ae1Sreyk 	u_int16_t	device;
34f51c4ae1Sreyk 	ar5k_attach_t	(*attach);
35f51c4ae1Sreyk } ar5k_known_products[] = {
36f51c4ae1Sreyk 	/*
37f51c4ae1Sreyk 	 * From pcidevs_data.h
38f51c4ae1Sreyk 	 */
39f51c4ae1Sreyk 	{ PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR5210,
40717dfb41Sreyk 	    ar5k_ar5210_attach },
41f51c4ae1Sreyk 	{ PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR5210_AP,
42717dfb41Sreyk 	    ar5k_ar5210_attach },
43f51c4ae1Sreyk 	{ PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR5210_DEFAULT,
44717dfb41Sreyk 	    ar5k_ar5210_attach },
45f51c4ae1Sreyk 	{ PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR5211,
46717dfb41Sreyk 	    ar5k_ar5211_attach },
47f51c4ae1Sreyk 	{ PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR5211_DEFAULT,
48717dfb41Sreyk 	    ar5k_ar5211_attach },
49f51c4ae1Sreyk 	{ PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR5311,
50717dfb41Sreyk 	    ar5k_ar5211_attach },
51f51c4ae1Sreyk 	{ PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR5211_FPGA11B,
52717dfb41Sreyk 	    ar5k_ar5211_attach },
53f51c4ae1Sreyk 	{ PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR5211_LEGACY,
54717dfb41Sreyk 	    ar5k_ar5211_attach },
55f51c4ae1Sreyk 	{ PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR5212,
56717dfb41Sreyk 	    ar5k_ar5212_attach },
57f51c4ae1Sreyk 	{ PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR5212_DEFAULT,
58717dfb41Sreyk 	    ar5k_ar5212_attach },
59f51c4ae1Sreyk 	{ PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR5212_FPGA,
60717dfb41Sreyk 	    ar5k_ar5212_attach },
61717dfb41Sreyk 	{ PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR5212_IBM,
62717dfb41Sreyk 	    ar5k_ar5212_attach },
63bafd5704Sreyk 	{ PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR2413,
64bafd5704Sreyk 	    ar5k_ar5212_attach },
65bafd5704Sreyk 	{ PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR5413,
66bafd5704Sreyk 	    ar5k_ar5212_attach },
67bafd5704Sreyk 	{ PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR5424,
68bafd5704Sreyk 	    ar5k_ar5212_attach },
69717dfb41Sreyk 	{ PCI_VENDOR_3COM, PCI_PRODUCT_3COM_3CRDAG675,
70717dfb41Sreyk 	    ar5k_ar5212_attach },
71717dfb41Sreyk 	{ PCI_VENDOR_3COM2, PCI_PRODUCT_3COM2_3CRPAG175,
728a4258edSreyk 	    ar5k_ar5212_attach }
73f51c4ae1Sreyk };
74f51c4ae1Sreyk 
7512410832Sreyk static const HAL_RATE_TABLE ar5k_rt_11a = AR5K_RATES_11A;
7612410832Sreyk static const HAL_RATE_TABLE ar5k_rt_11b = AR5K_RATES_11B;
7712410832Sreyk static const HAL_RATE_TABLE ar5k_rt_11g = AR5K_RATES_11G;
7812410832Sreyk static const HAL_RATE_TABLE ar5k_rt_xr = AR5K_RATES_XR;
7912410832Sreyk 
809ebef271Sreyk int		 ar5k_eeprom_read_ants(struct ath_hal *, u_int32_t *, u_int);
819ebef271Sreyk int		 ar5k_eeprom_read_modes(struct ath_hal *, u_int32_t *, u_int);
829ebef271Sreyk u_int16_t	 ar5k_eeprom_bin2freq(struct ath_hal *, u_int16_t, u_int);
839ebef271Sreyk 
849ebef271Sreyk HAL_BOOL	 ar5k_ar5110_channel(struct ath_hal *, HAL_CHANNEL *);
85130b77b5Skevlo u_int32_t	 ar5k_ar5110_chan2athchan(HAL_CHANNEL *);
869ebef271Sreyk HAL_BOOL	 ar5k_ar5111_channel(struct ath_hal *, HAL_CHANNEL *);
879ebef271Sreyk HAL_BOOL	 ar5k_ar5111_chan2athchan(u_int, struct ar5k_athchan_2ghz *);
889ebef271Sreyk HAL_BOOL	 ar5k_ar5112_channel(struct ath_hal *, HAL_CHANNEL *);
8988a3d8deSreyk HAL_BOOL	 ar5k_check_channel(struct ath_hal *, u_int16_t, u_int flags);
909ebef271Sreyk 
919ebef271Sreyk HAL_BOOL	 ar5k_ar5111_rfregs(struct ath_hal *, HAL_CHANNEL *, u_int);
929ebef271Sreyk HAL_BOOL	 ar5k_ar5112_rfregs(struct ath_hal *, HAL_CHANNEL *, u_int);
93b59011f9Sreyk HAL_BOOL	 ar5k_arxxxx_rfregs(struct ath_hal *, HAL_CHANNEL *, u_int);
94e9147aabSreyk u_int		 ar5k_rfregs_op(u_int32_t *, u_int32_t, u_int32_t, u_int32_t,
95dd37d60cSreyk     u_int32_t, u_int32_t, HAL_BOOL);
96dd37d60cSreyk 
97dd37d60cSreyk /*
98dd37d60cSreyk  * Supported channels
99dd37d60cSreyk  */
100dd37d60cSreyk static const struct
101dd37d60cSreyk ieee80211_regchannel ar5k_5ghz_channels[] = IEEE80211_CHANNELS_5GHZ;
102dd37d60cSreyk static const struct
103dd37d60cSreyk ieee80211_regchannel ar5k_2ghz_channels[] = IEEE80211_CHANNELS_2GHZ;
104dd37d60cSreyk 
105dd37d60cSreyk /*
106dd37d60cSreyk  * Initial gain optimization values
107dd37d60cSreyk  */
108dd37d60cSreyk static const struct ar5k_gain_opt ar5111_gain_opt = AR5K_AR5111_GAIN_OPT;
109dd37d60cSreyk static const struct ar5k_gain_opt ar5112_gain_opt = AR5K_AR5112_GAIN_OPT;
1109ebef271Sreyk 
1119ebef271Sreyk /*
1129ebef271Sreyk  * Initial register for the radio chipsets
1139ebef271Sreyk  */
114dd37d60cSreyk static const struct ar5k_ini_rf ar5111_rf[] = AR5K_AR5111_INI_RF;
115dd37d60cSreyk static const struct ar5k_ini_rf ar5112_rf[] = AR5K_AR5112_INI_RF;
1160ce211edSreyk static const struct ar5k_ini_rf ar5112a_rf[] = AR5K_AR5112A_INI_RF;
117b59011f9Sreyk static const struct ar5k_ini_rf ar5413_rf[] = AR5K_AR5413_INI_RF;
118b59011f9Sreyk static const struct ar5k_ini_rf ar2413_rf[] = AR5K_AR2413_INI_RF;
119b59011f9Sreyk static const struct ar5k_ini_rf ar2425_rf[] = AR5K_AR2425_INI_RF;
120b59011f9Sreyk static const struct ar5k_ini_rfgain ar5111_rfg[] = AR5K_AR5111_INI_RFGAIN;
121b59011f9Sreyk static const struct ar5k_ini_rfgain ar5112_rfg[] = AR5K_AR5112_INI_RFGAIN;
122b59011f9Sreyk static const struct ar5k_ini_rfgain ar5413_rfg[] = AR5K_AR5413_INI_RFGAIN;
123b59011f9Sreyk static const struct ar5k_ini_rfgain ar2413_rfg[] = AR5K_AR2413_INI_RFGAIN;
1249ebef271Sreyk 
125f51c4ae1Sreyk /*
12688a3d8deSreyk  * Enable to overwrite the country code (use "00" for debug)
1278a4258edSreyk  */
12888a3d8deSreyk #if 0
12988a3d8deSreyk #define COUNTRYCODE "00"
1308a4258edSreyk #endif
1318a4258edSreyk 
1328a4258edSreyk /*
133f51c4ae1Sreyk  * Perform a lookup if the device is supported by the HAL
134f51c4ae1Sreyk  */
135f51c4ae1Sreyk const char *
ath_hal_probe(u_int16_t vendor,u_int16_t device)136a9b481abSjsg ath_hal_probe(u_int16_t vendor, u_int16_t device)
137f51c4ae1Sreyk {
138f51c4ae1Sreyk 	int i;
139f51c4ae1Sreyk 
140f51c4ae1Sreyk 	/*
141f51c4ae1Sreyk 	 * Perform a linear search on the table of supported devices
142f51c4ae1Sreyk 	 */
1434d0d30b5Sreyk 	for (i = 0; i < nitems(ar5k_known_products); i++) {
144f51c4ae1Sreyk 		if (vendor == ar5k_known_products[i].vendor &&
145f51c4ae1Sreyk 		    device == ar5k_known_products[i].device)
146717dfb41Sreyk 			return ("");
147f51c4ae1Sreyk 	}
148f51c4ae1Sreyk 
149f51c4ae1Sreyk 	return (NULL);
150f51c4ae1Sreyk }
151f51c4ae1Sreyk 
152f51c4ae1Sreyk /*
153f51c4ae1Sreyk  * Fills in the HAL structure and initialises the device
154f51c4ae1Sreyk  */
155f51c4ae1Sreyk struct ath_hal *
ath_hal_attach(u_int16_t device,void * arg,bus_space_tag_t st,bus_space_handle_t sh,u_int is_pcie,int * status)1569cfa9686Sreyk ath_hal_attach(u_int16_t device, void *arg, bus_space_tag_t st,
157f26dd3a5Sreyk     bus_space_handle_t sh, u_int is_pcie, int *status)
158f51c4ae1Sreyk {
1599cfa9686Sreyk 	struct ath_softc *sc = (struct ath_softc *)arg;
160f51c4ae1Sreyk 	struct ath_hal *hal = NULL;
161b28497f7Sreyk 	ar5k_attach_t *attach = NULL;
162f51c4ae1Sreyk 	u_int8_t mac[IEEE80211_ADDR_LEN];
163f51c4ae1Sreyk 	int i;
164f51c4ae1Sreyk 
165c39ae617Sreyk 	*status = EINVAL;
166f51c4ae1Sreyk 
167f51c4ae1Sreyk 	/*
168f51c4ae1Sreyk 	 * Call the chipset-dependent attach routine by device id
169f51c4ae1Sreyk 	 */
1704d0d30b5Sreyk 	for (i = 0; i < nitems(ar5k_known_products); i++) {
171f51c4ae1Sreyk 		if (device == ar5k_known_products[i].device &&
172f51c4ae1Sreyk 		    ar5k_known_products[i].attach != NULL)
173f51c4ae1Sreyk 			attach = ar5k_known_products[i].attach;
174f51c4ae1Sreyk 	}
175f51c4ae1Sreyk 
176f51c4ae1Sreyk 	if (attach == NULL) {
177c39ae617Sreyk 		*status = ENXIO;
178b28497f7Sreyk 		AR5K_PRINTF("device not supported: 0x%04x\n", device);
179f51c4ae1Sreyk 		return (NULL);
180f51c4ae1Sreyk 	}
181f51c4ae1Sreyk 
182c39ae617Sreyk 	if ((hal = malloc(sizeof(struct ath_hal),
1834ba500adSreyk 		 M_DEVBUF, M_NOWAIT | M_ZERO)) == NULL) {
184c39ae617Sreyk 		*status = ENOMEM;
185b28497f7Sreyk 		AR5K_PRINT("out of memory\n");
186f51c4ae1Sreyk 		return (NULL);
187f51c4ae1Sreyk 	}
188f51c4ae1Sreyk 
189f51c4ae1Sreyk 	hal->ah_sc = sc;
190f51c4ae1Sreyk 	hal->ah_st = st;
191f51c4ae1Sreyk 	hal->ah_sh = sh;
192f51c4ae1Sreyk 	hal->ah_device = device;
193f51c4ae1Sreyk 	hal->ah_sub_vendor = 0; /* XXX unknown?! */
194f51c4ae1Sreyk 
195f51c4ae1Sreyk 	/*
196f51c4ae1Sreyk 	 * HAL information
197f51c4ae1Sreyk 	 */
198f51c4ae1Sreyk 	hal->ah_abi = HAL_ABI_VERSION;
199f51c4ae1Sreyk 	hal->ah_op_mode = HAL_M_STA;
200f51c4ae1Sreyk 	hal->ah_radar.r_enabled = AR5K_TUNE_RADAR_ALERT;
2019ebef271Sreyk 	hal->ah_txpower.txp_tpc = AR5K_TUNE_TPC_TXPOWER;
202f51c4ae1Sreyk 	hal->ah_imr = 0;
203f51c4ae1Sreyk 	hal->ah_atim_window = 0;
204f51c4ae1Sreyk 	hal->ah_aifs = AR5K_TUNE_AIFS;
205f51c4ae1Sreyk 	hal->ah_cw_min = AR5K_TUNE_CWMIN;
206f51c4ae1Sreyk 	hal->ah_limit_tx_retries = AR5K_INIT_TX_RETRY;
207f51c4ae1Sreyk 	hal->ah_software_retry = AH_FALSE;
2089ebef271Sreyk 	hal->ah_ant_diversity = AR5K_TUNE_ANT_DIVERSITY;
209f26dd3a5Sreyk 	hal->ah_pci_express = is_pcie ? AH_TRUE : AH_FALSE;
210f51c4ae1Sreyk 
211347bfc5fSreyk 	switch (device) {
212347bfc5fSreyk 	case PCI_PRODUCT_ATHEROS_AR2413:
213347bfc5fSreyk 	case PCI_PRODUCT_ATHEROS_AR5413:
214347bfc5fSreyk 	case PCI_PRODUCT_ATHEROS_AR5424:
215347bfc5fSreyk 		/*
216347bfc5fSreyk 		 * Known single chip solutions
217347bfc5fSreyk 		 */
218347bfc5fSreyk 		hal->ah_single_chip = AH_TRUE;
219347bfc5fSreyk 		break;
220347bfc5fSreyk 	default:
221347bfc5fSreyk 		/*
222347bfc5fSreyk 		 * Multi chip solutions
223347bfc5fSreyk 		 */
224347bfc5fSreyk 		hal->ah_single_chip = AH_FALSE;
225347bfc5fSreyk 		break;
226347bfc5fSreyk 	}
227347bfc5fSreyk 
228e9147aabSreyk 	if ((attach)(device, hal, st, sh, status) == NULL)
229f51c4ae1Sreyk 		goto failed;
230f51c4ae1Sreyk 
231c6d5838dSreyk #ifdef AR5K_DEBUG
232d93ea26fSreyk 	hal->ah_dump_state(hal);
233c6d5838dSreyk #endif
234c6d5838dSreyk 
235f51c4ae1Sreyk 	/*
236f51c4ae1Sreyk 	 * Get card capabilities, values, ...
237f51c4ae1Sreyk 	 */
238f51c4ae1Sreyk 
2399ebef271Sreyk 	if (ar5k_eeprom_init(hal) != 0) {
2409ebef271Sreyk 		AR5K_PRINT("unable to init EEPROM\n");
2419ebef271Sreyk 		goto failed;
2429ebef271Sreyk 	}
2439ebef271Sreyk 
2449ebef271Sreyk 	/* Get misc capabilities */
245f51c4ae1Sreyk 	if (hal->ah_get_capabilities(hal) != AH_TRUE) {
246b28497f7Sreyk 		AR5K_PRINTF("unable to get device capabilities: 0x%04x\n",
247b28497f7Sreyk 		    device);
248f51c4ae1Sreyk 		goto failed;
249f51c4ae1Sreyk 	}
250f51c4ae1Sreyk 
2519ebef271Sreyk 	/* Get MAC address */
252bba49c9dSreyk 	if ((*status = ar5k_eeprom_read_mac(hal, mac)) != 0) {
253b28497f7Sreyk 		AR5K_PRINTF("unable to read address from EEPROM: 0x%04x\n",
254b28497f7Sreyk 		    device);
255f51c4ae1Sreyk 		goto failed;
256f51c4ae1Sreyk 	}
257f51c4ae1Sreyk 
258d93ea26fSreyk 	hal->ah_set_lladdr(hal, mac);
259f51c4ae1Sreyk 
2609ebef271Sreyk 	/* Get rate tables */
261f51c4ae1Sreyk 	if (hal->ah_capabilities.cap_mode & HAL_MODE_11A)
26212410832Sreyk 		ar5k_rt_copy(&hal->ah_rt_11a, &ar5k_rt_11a);
2631d0a4d88Sreyk 	if (hal->ah_capabilities.cap_mode & HAL_MODE_11B)
26412410832Sreyk 		ar5k_rt_copy(&hal->ah_rt_11b, &ar5k_rt_11b);
2651d0a4d88Sreyk 	if (hal->ah_capabilities.cap_mode & HAL_MODE_11G)
26612410832Sreyk 		ar5k_rt_copy(&hal->ah_rt_11g, &ar5k_rt_11g);
267dd37d60cSreyk 	if (hal->ah_capabilities.cap_mode & HAL_MODE_XR)
26812410832Sreyk 		ar5k_rt_copy(&hal->ah_rt_xr, &ar5k_rt_xr);
269dd37d60cSreyk 
270dd37d60cSreyk 	/* Initialize the gain optimization values */
271dd37d60cSreyk 	if (hal->ah_radio == AR5K_AR5111) {
272dd37d60cSreyk 		hal->ah_gain.g_step_idx = ar5111_gain_opt.go_default;
273dd37d60cSreyk 		hal->ah_gain.g_step =
274dd37d60cSreyk 		    &ar5111_gain_opt.go_step[hal->ah_gain.g_step_idx];
275dd37d60cSreyk 		hal->ah_gain.g_low = 20;
276dd37d60cSreyk 		hal->ah_gain.g_high = 35;
277dd37d60cSreyk 		hal->ah_gain.g_active = 1;
278dd37d60cSreyk 	} else if (hal->ah_radio == AR5K_AR5112) {
279dd37d60cSreyk 		hal->ah_gain.g_step_idx = ar5112_gain_opt.go_default;
280dd37d60cSreyk 		hal->ah_gain.g_step =
28183261a41Smestre 		    &ar5112_gain_opt.go_step[hal->ah_gain.g_step_idx];
282dd37d60cSreyk 		hal->ah_gain.g_low = 20;
283dd37d60cSreyk 		hal->ah_gain.g_high = 85;
284dd37d60cSreyk 		hal->ah_gain.g_active = 1;
285b59011f9Sreyk 	} else {
286b59011f9Sreyk 		/* XXX not needed for newer chipsets? */
287dd37d60cSreyk 	}
288f51c4ae1Sreyk 
289f51c4ae1Sreyk 	*status = HAL_OK;
290f51c4ae1Sreyk 
291f51c4ae1Sreyk 	return (hal);
292f51c4ae1Sreyk 
293f51c4ae1Sreyk  failed:
294aa3cabd0Stedu 	free(hal, M_DEVBUF, 0);
295f51c4ae1Sreyk 	return (NULL);
296f51c4ae1Sreyk }
297f51c4ae1Sreyk 
298f51c4ae1Sreyk u_int16_t
ath_hal_computetxtime(struct ath_hal * hal,const HAL_RATE_TABLE * rates,u_int32_t frame_length,u_int16_t rate_index,HAL_BOOL short_preamble)299a9b481abSjsg ath_hal_computetxtime(struct ath_hal *hal, const HAL_RATE_TABLE *rates,
300a9b481abSjsg     u_int32_t frame_length, u_int16_t rate_index, HAL_BOOL short_preamble)
301f51c4ae1Sreyk {
302b28497f7Sreyk 	const HAL_RATE *rate;
303f51c4ae1Sreyk 	u_int32_t value;
304f51c4ae1Sreyk 
305f51c4ae1Sreyk 	AR5K_ASSERT_ENTRY(rate_index, rates->rateCount);
306f51c4ae1Sreyk 
307f51c4ae1Sreyk 	/*
308f51c4ae1Sreyk 	 * Get rate by index
309f51c4ae1Sreyk 	 */
310b28497f7Sreyk 	rate = &rates->info[rate_index];
311f51c4ae1Sreyk 
312f51c4ae1Sreyk 	/*
313f51c4ae1Sreyk 	 * Calculate the transmission time by operation (PHY) mode
314f51c4ae1Sreyk 	 */
315f51c4ae1Sreyk 	switch (rate->phy) {
316f51c4ae1Sreyk 	case IEEE80211_T_CCK:
317f51c4ae1Sreyk 		/*
318f51c4ae1Sreyk 		 * CCK / DS mode (802.11b)
319f51c4ae1Sreyk 		 */
320f51c4ae1Sreyk 		value = AR5K_CCK_TX_TIME(rate->rateKbps, frame_length,
321f51c4ae1Sreyk 		    (short_preamble && rate->shortPreamble));
322f51c4ae1Sreyk 		break;
323f51c4ae1Sreyk 
324f51c4ae1Sreyk 	case IEEE80211_T_OFDM:
325f51c4ae1Sreyk 		/*
326f51c4ae1Sreyk 		 * Orthogonal Frequency Division Multiplexing
327f51c4ae1Sreyk 		 */
328f51c4ae1Sreyk 		if (AR5K_OFDM_NUM_BITS_PER_SYM(rate->rateKbps) == 0)
329f51c4ae1Sreyk 			return (0);
330f51c4ae1Sreyk 		value = AR5K_OFDM_TX_TIME(rate->rateKbps, frame_length);
331f51c4ae1Sreyk 		break;
332f51c4ae1Sreyk 
333f51c4ae1Sreyk 	case IEEE80211_T_XR:
334f51c4ae1Sreyk 		/*
335f51c4ae1Sreyk 		 * Orthogonal Frequency Division Multiplexing
336f51c4ae1Sreyk 		 * Atheros "eXtended Range" (XR)
337f51c4ae1Sreyk 		 */
338f51c4ae1Sreyk 		if (AR5K_XR_NUM_BITS_PER_SYM(rate->rateKbps) == 0)
339f51c4ae1Sreyk 			return (0);
340f51c4ae1Sreyk 		value = AR5K_XR_TX_TIME(rate->rateKbps, frame_length);
341f51c4ae1Sreyk 		break;
342f51c4ae1Sreyk 
343f51c4ae1Sreyk 	default:
344f51c4ae1Sreyk 		return (0);
345f51c4ae1Sreyk 	}
346f51c4ae1Sreyk 
347f51c4ae1Sreyk 	return (value);
348f51c4ae1Sreyk }
349f51c4ae1Sreyk 
350f51c4ae1Sreyk HAL_BOOL
ar5k_check_channel(struct ath_hal * hal,u_int16_t freq,u_int flags)351a9b481abSjsg ar5k_check_channel(struct ath_hal *hal, u_int16_t freq, u_int flags)
35288a3d8deSreyk {
35388a3d8deSreyk 	/* Check if the channel is in our supported range */
35488a3d8deSreyk 	if (flags & IEEE80211_CHAN_2GHZ) {
35588a3d8deSreyk 		if ((freq >= hal->ah_capabilities.cap_range.range_2ghz_min) &&
35688a3d8deSreyk 		    (freq <= hal->ah_capabilities.cap_range.range_2ghz_max))
35788a3d8deSreyk 			return (AH_TRUE);
35888a3d8deSreyk 	} else if (flags & IEEE80211_CHAN_5GHZ) {
35988a3d8deSreyk 		if ((freq >= hal->ah_capabilities.cap_range.range_5ghz_min) &&
36088a3d8deSreyk 		    (freq <= hal->ah_capabilities.cap_range.range_5ghz_max))
36188a3d8deSreyk 			return (AH_TRUE);
36288a3d8deSreyk 	}
36388a3d8deSreyk 
36488a3d8deSreyk 	return (AH_FALSE);
36588a3d8deSreyk }
36688a3d8deSreyk 
36788a3d8deSreyk HAL_BOOL
ath_hal_init_channels(struct ath_hal * hal,HAL_CHANNEL * channels,u_int max_channels,u_int * channels_size,u_int16_t mode,HAL_BOOL outdoor,HAL_BOOL extended)368a9b481abSjsg ath_hal_init_channels(struct ath_hal *hal, HAL_CHANNEL *channels,
36923349211Sreyk     u_int max_channels, u_int *channels_size, u_int16_t mode,
37023349211Sreyk     HAL_BOOL outdoor, HAL_BOOL extended)
371f51c4ae1Sreyk {
372f51c4ae1Sreyk 	u_int i, c;
373f51c4ae1Sreyk 	u_int32_t domain_current;
374f51c4ae1Sreyk 	u_int domain_5ghz, domain_2ghz;
375f1b145afSreyk 	HAL_CHANNEL *all_channels;
376f1b145afSreyk 
3779f6fb5c7Sderaadt 	if ((all_channels = mallocarray(max_channels, sizeof(HAL_CHANNEL),
3784ba500adSreyk 	    M_TEMP, M_NOWAIT | M_ZERO)) == NULL)
379f1b145afSreyk 		return (AH_FALSE);
380f51c4ae1Sreyk 
38188a3d8deSreyk 	i = c = 0;
38223349211Sreyk 	domain_current = hal->ah_regdomain;
38388a3d8deSreyk 
38488a3d8deSreyk 	/*
38588a3d8deSreyk 	 * In debugging mode, enable all channels supported by the chipset
38688a3d8deSreyk 	 */
38788a3d8deSreyk 	if (domain_current == DMN_DEFAULT) {
38888a3d8deSreyk 		int min, max, freq;
38988a3d8deSreyk 		u_int flags;
39088a3d8deSreyk 
39188a3d8deSreyk 		min = ieee80211_mhz2ieee(IEEE80211_CHANNELS_2GHZ_MIN,
39288a3d8deSreyk 		    IEEE80211_CHAN_2GHZ);
39388a3d8deSreyk 		max = ieee80211_mhz2ieee(IEEE80211_CHANNELS_2GHZ_MAX,
39488a3d8deSreyk 		    IEEE80211_CHAN_2GHZ);
3958fa13e1fSstsp 		flags = CHANNEL_B |
39688a3d8deSreyk 		    (hal->ah_version == AR5K_AR5211 ?
39788a3d8deSreyk 		    CHANNEL_PUREG : CHANNEL_G);
39888a3d8deSreyk 
39988a3d8deSreyk  debugchan:
40088a3d8deSreyk 		for (i = min; i <= max && c < max_channels; i++) {
40188a3d8deSreyk 			freq = ieee80211_ieee2mhz(i, flags);
40288a3d8deSreyk 			if (ar5k_check_channel(hal, freq, flags) == AH_FALSE)
40388a3d8deSreyk 				continue;
40488a3d8deSreyk 			all_channels[c].c_channel = freq;
40588a3d8deSreyk 			all_channels[c++].c_channel_flags = flags;
40688a3d8deSreyk 		}
40788a3d8deSreyk 
40888a3d8deSreyk 		if (flags & IEEE80211_CHAN_2GHZ) {
40988a3d8deSreyk 			min = ieee80211_mhz2ieee(IEEE80211_CHANNELS_5GHZ_MIN,
41088a3d8deSreyk 			    IEEE80211_CHAN_5GHZ);
41188a3d8deSreyk 			max = ieee80211_mhz2ieee(IEEE80211_CHANNELS_5GHZ_MAX,
41288a3d8deSreyk 			    IEEE80211_CHAN_5GHZ);
4138fa13e1fSstsp 			flags = CHANNEL_A | CHANNEL_XR;
41488a3d8deSreyk 			goto debugchan;
41588a3d8deSreyk 		}
41688a3d8deSreyk 
41788a3d8deSreyk 		goto done;
41888a3d8deSreyk 	}
41988a3d8deSreyk 
4202ba31b92Sreyk 	domain_5ghz = ieee80211_regdomain2flag(domain_current,
4212ba31b92Sreyk 	    IEEE80211_CHANNELS_5GHZ_MIN);
4222ba31b92Sreyk 	domain_2ghz = ieee80211_regdomain2flag(domain_current,
4232ba31b92Sreyk 	    IEEE80211_CHANNELS_2GHZ_MIN);
424f51c4ae1Sreyk 
425f51c4ae1Sreyk 	/*
426f51c4ae1Sreyk 	 * Create channel list based on chipset capabilities, regulation domain
427f51c4ae1Sreyk 	 * and mode. 5GHz...
428f51c4ae1Sreyk 	 */
429f51c4ae1Sreyk 	for (i = 0; (hal->ah_capabilities.cap_range.range_5ghz_max > 0) &&
4304d0d30b5Sreyk 		 (i < nitems(ar5k_5ghz_channels)) &&
431f51c4ae1Sreyk 		 (c < max_channels); i++) {
432f51c4ae1Sreyk 		/* Check if channel is supported by the chipset */
43388a3d8deSreyk 		if (ar5k_check_channel(hal,
43488a3d8deSreyk 		    ar5k_5ghz_channels[i].rc_channel,
43588a3d8deSreyk 		    IEEE80211_CHAN_5GHZ) == AH_FALSE)
436f51c4ae1Sreyk 			continue;
437f51c4ae1Sreyk 
438f51c4ae1Sreyk 		/* Match regulation domain */
43988a3d8deSreyk 		if ((IEEE80211_DMN(ar5k_5ghz_channels[i].rc_domain) &
440f51c4ae1Sreyk 			IEEE80211_DMN(domain_5ghz)) == 0)
441f51c4ae1Sreyk 			continue;
442f51c4ae1Sreyk 
443f51c4ae1Sreyk 		/* Match modes */
4448fa13e1fSstsp 		if (ar5k_5ghz_channels[i].rc_mode & IEEE80211_CHAN_OFDM)
44588a3d8deSreyk 			all_channels[c].c_channel_flags = CHANNEL_A;
4468fa13e1fSstsp 		else
447958b4d3eSreyk 			continue;
448f51c4ae1Sreyk 
449f51c4ae1Sreyk 		/* Write channel and increment counter */
450f51c4ae1Sreyk 		all_channels[c++].channel = ar5k_5ghz_channels[i].rc_channel;
451f51c4ae1Sreyk 	}
452f51c4ae1Sreyk 
453f51c4ae1Sreyk 	/*
454f51c4ae1Sreyk 	 * ...and 2GHz.
455f51c4ae1Sreyk 	 */
456f51c4ae1Sreyk 	for (i = 0; (hal->ah_capabilities.cap_range.range_2ghz_max > 0) &&
4574d0d30b5Sreyk 		 (i < nitems(ar5k_2ghz_channels)) &&
458f51c4ae1Sreyk 		 (c < max_channels); i++) {
459f51c4ae1Sreyk 		/* Check if channel is supported by the chipset */
46088a3d8deSreyk 		if (ar5k_check_channel(hal,
46188a3d8deSreyk 		    ar5k_2ghz_channels[i].rc_channel,
46288a3d8deSreyk 		    IEEE80211_CHAN_2GHZ) == AH_FALSE)
463f51c4ae1Sreyk 			continue;
464f51c4ae1Sreyk 
465f51c4ae1Sreyk 		/* Match regulation domain */
46688a3d8deSreyk 		if ((IEEE80211_DMN(ar5k_2ghz_channels[i].rc_domain) &
467f51c4ae1Sreyk 			IEEE80211_DMN(domain_2ghz)) == 0)
468f51c4ae1Sreyk 			continue;
469f51c4ae1Sreyk 
470f51c4ae1Sreyk 		/* Match modes */
47121c2be8aSreyk 		if ((hal->ah_capabilities.cap_mode & HAL_MODE_11B) &&
47221c2be8aSreyk 		    (ar5k_2ghz_channels[i].rc_mode & IEEE80211_CHAN_CCK))
47388a3d8deSreyk 			all_channels[c].c_channel_flags = CHANNEL_B;
47488a3d8deSreyk 
475*6696c7f4Sstsp 		if (hal->ah_capabilities.cap_mode & HAL_MODE_11G) {
476*6696c7f4Sstsp 			if (ar5k_2ghz_channels[i].rc_mode & IEEE80211_CHAN_CCK)
477*6696c7f4Sstsp 			    all_channels[c].c_channel_flags = CHANNEL_B;
478*6696c7f4Sstsp 			if (ar5k_2ghz_channels[i].rc_mode & IEEE80211_CHAN_OFDM)
479*6696c7f4Sstsp 				all_channels[c].c_channel_flags |= (CHANNEL_G | CHANNEL_PUREG);
48088a3d8deSreyk 		}
481f51c4ae1Sreyk 
482f51c4ae1Sreyk 		/* Write channel and increment counter */
483f51c4ae1Sreyk 		all_channels[c++].channel = ar5k_2ghz_channels[i].rc_channel;
484f51c4ae1Sreyk 	}
485f51c4ae1Sreyk 
48688a3d8deSreyk  done:
487f1b145afSreyk 	bcopy(all_channels, channels, sizeof(HAL_CHANNEL) * max_channels);
488f51c4ae1Sreyk 	*channels_size = c;
489aa3cabd0Stedu 	free(all_channels, M_TEMP, 0);
490f51c4ae1Sreyk 	return (AH_TRUE);
491f51c4ae1Sreyk }
492f51c4ae1Sreyk 
493f51c4ae1Sreyk /*
494f51c4ae1Sreyk  * Common internal functions
495f51c4ae1Sreyk  */
496f51c4ae1Sreyk 
497fead7ab4Sreyk const char *
ar5k_printver(enum ar5k_srev_type type,u_int32_t val)498a9b481abSjsg ar5k_printver(enum ar5k_srev_type type, u_int32_t val)
499fead7ab4Sreyk {
500fead7ab4Sreyk 	struct ar5k_srev_name names[] = AR5K_SREV_NAME;
501fead7ab4Sreyk 	const char *name = "xxxx";
502fead7ab4Sreyk 	int i;
503fead7ab4Sreyk 
5044d0d30b5Sreyk 	for (i = 0; i < nitems(names); i++) {
505bafd5704Sreyk 		if (type == AR5K_VERSION_DEV) {
506bafd5704Sreyk 			if (names[i].sr_type == type &&
507bafd5704Sreyk 			    names[i].sr_val == val) {
508bafd5704Sreyk 				name = names[i].sr_name;
509bafd5704Sreyk 				break;
510bafd5704Sreyk 			}
511bafd5704Sreyk 			continue;
512bafd5704Sreyk 		}
513fead7ab4Sreyk 		if (names[i].sr_type != type ||
514fead7ab4Sreyk 		    names[i].sr_val == AR5K_SREV_UNKNOWN)
515fead7ab4Sreyk 			continue;
516c082a991Stb 		/*
517c082a991Stb 		 * The final iteration has names[i].sr_val == AR5K_SREV_UNKNOWN,
518c082a991Stb 		 * so there is no out-of-bounds access with names[i + 1] below.
519c082a991Stb 		 */
52019e33da8Sreyk 		if ((val & 0xff) < names[i + 1].sr_val) {
521fead7ab4Sreyk 			name = names[i].sr_name;
522fead7ab4Sreyk 			break;
523fead7ab4Sreyk 		}
524fead7ab4Sreyk 	}
525fead7ab4Sreyk 
526fead7ab4Sreyk 	return (name);
527fead7ab4Sreyk }
528fead7ab4Sreyk 
529f51c4ae1Sreyk void
ar5k_radar_alert(struct ath_hal * hal)530a9b481abSjsg ar5k_radar_alert(struct ath_hal *hal)
531f51c4ae1Sreyk {
532f51c4ae1Sreyk 	/*
533f51c4ae1Sreyk 	 * Limit ~1/s
534f51c4ae1Sreyk 	 */
535f51c4ae1Sreyk 	if (hal->ah_radar.r_last_channel.channel ==
536f51c4ae1Sreyk 	    hal->ah_current_channel.channel &&
537f51c4ae1Sreyk 	    tick < (hal->ah_radar.r_last_alert + hz))
538f51c4ae1Sreyk 		return;
539f51c4ae1Sreyk 
540f51c4ae1Sreyk 	hal->ah_radar.r_last_channel.channel =
541f51c4ae1Sreyk 	    hal->ah_current_channel.channel;
54288a3d8deSreyk 	hal->ah_radar.r_last_channel.c_channel_flags =
54388a3d8deSreyk 	    hal->ah_current_channel.c_channel_flags;
544f51c4ae1Sreyk 	hal->ah_radar.r_last_alert = tick;
545f51c4ae1Sreyk 
546f51c4ae1Sreyk 	AR5K_PRINTF("Possible radar activity detected at %u MHz (tick %u)\n",
547f51c4ae1Sreyk 	    hal->ah_radar.r_last_alert, hal->ah_current_channel.channel);
548f51c4ae1Sreyk }
549f51c4ae1Sreyk 
5509ebef271Sreyk u_int16_t
ar5k_regdomain_from_ieee(ieee80211_regdomain_t ieee)551a9b481abSjsg ar5k_regdomain_from_ieee(ieee80211_regdomain_t ieee)
552f51c4ae1Sreyk {
553ff3f4e6cSreyk 	u_int32_t regdomain = (u_int32_t)ieee;
554ff3f4e6cSreyk 
55523349211Sreyk 	/*
55623349211Sreyk 	 * Use the default regulation domain if the value is empty
55723349211Sreyk 	 * or not supported by the net80211 regulation code.
55823349211Sreyk 	 */
55923349211Sreyk 	if (ieee80211_regdomain2flag(regdomain,
56023349211Sreyk 	    IEEE80211_CHANNELS_5GHZ_MIN) == DMN_DEBUG)
561486f10cbSreyk 		return ((u_int16_t)AR5K_TUNE_REGDOMAIN);
562ff3f4e6cSreyk 
56323349211Sreyk 	/* It is supported, just return the value */
56423349211Sreyk 	return (regdomain);
565f51c4ae1Sreyk }
566f51c4ae1Sreyk 
567ff3f4e6cSreyk ieee80211_regdomain_t
ar5k_regdomain_to_ieee(u_int16_t regdomain)568a9b481abSjsg ar5k_regdomain_to_ieee(u_int16_t regdomain)
569f51c4ae1Sreyk {
57023349211Sreyk 	ieee80211_regdomain_t ieee = (ieee80211_regdomain_t)regdomain;
571ff3f4e6cSreyk 
572ff3f4e6cSreyk 	return (ieee);
573f51c4ae1Sreyk }
574f51c4ae1Sreyk 
575486f10cbSreyk u_int16_t
ar5k_get_regdomain(struct ath_hal * hal)576a9b481abSjsg ar5k_get_regdomain(struct ath_hal *hal)
577486f10cbSreyk {
578486f10cbSreyk 	u_int16_t regdomain;
579486f10cbSreyk 	ieee80211_regdomain_t ieee_regdomain;
58023349211Sreyk #ifdef COUNTRYCODE
58123349211Sreyk 	u_int16_t code;
58223349211Sreyk #endif
583486f10cbSreyk 
58423349211Sreyk 	ar5k_eeprom_regulation_domain(hal, AH_FALSE, &ieee_regdomain);
58523349211Sreyk 	hal->ah_capabilities.cap_regdomain.reg_hw = ieee_regdomain;
586486f10cbSreyk 
58723349211Sreyk #ifdef COUNTRYCODE
588486f10cbSreyk 	/*
589486f10cbSreyk 	 * Get the regulation domain by country code. This will ignore
590486f10cbSreyk 	 * the settings found in the EEPROM.
591486f10cbSreyk 	 */
592486f10cbSreyk 	code = ieee80211_name2countrycode(COUNTRYCODE);
59323349211Sreyk 	ieee_regdomain = ieee80211_countrycode2regdomain(code);
594486f10cbSreyk #endif
59523349211Sreyk 
59623349211Sreyk 	regdomain = ar5k_regdomain_from_ieee(ieee_regdomain);
59723349211Sreyk 	hal->ah_capabilities.cap_regdomain.reg_current = regdomain;
59823349211Sreyk 
59923349211Sreyk 	return (regdomain);
600486f10cbSreyk }
601486f10cbSreyk 
602f51c4ae1Sreyk u_int32_t
ar5k_bitswap(u_int32_t val,u_int bits)603a9b481abSjsg ar5k_bitswap(u_int32_t val, u_int bits)
604f51c4ae1Sreyk {
605f53f9518Stom 	if (bits == 8) {
606f53f9518Stom 		val = ((val & 0xF0) >>  4) | ((val & 0x0F) <<  4);
607f53f9518Stom 		val = ((val & 0xCC) >>  2) | ((val & 0x33) <<  2);
608f53f9518Stom 		val = ((val & 0xAA) >>  1) | ((val & 0x55) <<  1);
609f53f9518Stom 
610f53f9518Stom 		return val;
611f53f9518Stom 	} else {
612f51c4ae1Sreyk 		u_int32_t retval = 0, bit, i;
613f51c4ae1Sreyk 
614f51c4ae1Sreyk 		for (i = 0; i < bits; i++) {
615f51c4ae1Sreyk 			bit = (val >> i) & 1;
616f51c4ae1Sreyk 			retval = (retval << 1) | bit;
617f51c4ae1Sreyk 		}
618f51c4ae1Sreyk 
619f53f9518Stom 		return retval;
620f53f9518Stom 	}
621f51c4ae1Sreyk }
622f51c4ae1Sreyk 
623f51c4ae1Sreyk u_int
ar5k_htoclock(u_int usec)6248fa13e1fSstsp ar5k_htoclock(u_int usec)
625f51c4ae1Sreyk {
6268fa13e1fSstsp 	return (usec * 40);
627f51c4ae1Sreyk }
628f51c4ae1Sreyk 
629f51c4ae1Sreyk u_int
ar5k_clocktoh(u_int clock)6308fa13e1fSstsp ar5k_clocktoh(u_int clock)
631f51c4ae1Sreyk {
6328fa13e1fSstsp 	return (clock / 40);
633f51c4ae1Sreyk }
634f51c4ae1Sreyk 
635f51c4ae1Sreyk void
ar5k_rt_copy(HAL_RATE_TABLE * dst,const HAL_RATE_TABLE * src)636a9b481abSjsg ar5k_rt_copy(HAL_RATE_TABLE *dst, const HAL_RATE_TABLE *src)
637f51c4ae1Sreyk {
638c6d5838dSreyk 	bzero(dst, sizeof(HAL_RATE_TABLE));
639f51c4ae1Sreyk 	dst->rateCount = src->rateCount;
640f3fffee0Sstsp 	bcopy(src->rateCodeToIndex, dst->rateCodeToIndex,
641f3fffee0Sstsp 	    sizeof(dst->rateCodeToIndex));
642c6d5838dSreyk 	bcopy(src->info, dst->info, sizeof(dst->info));
643f51c4ae1Sreyk }
644f51c4ae1Sreyk 
645f51c4ae1Sreyk HAL_BOOL
ar5k_register_timeout(struct ath_hal * hal,u_int32_t reg,u_int32_t flag,u_int32_t val,HAL_BOOL is_set)646a9b481abSjsg ar5k_register_timeout(struct ath_hal *hal, u_int32_t reg, u_int32_t flag,
647a9b481abSjsg     u_int32_t val, HAL_BOOL is_set)
648f51c4ae1Sreyk {
649f51c4ae1Sreyk 	int i;
6509ebef271Sreyk 	u_int32_t data;
651f51c4ae1Sreyk 
652f51c4ae1Sreyk 	for (i = AR5K_TUNE_REGISTER_TIMEOUT; i > 0; i--) {
6539ebef271Sreyk 		data = AR5K_REG_READ(reg);
6549ebef271Sreyk 		if ((is_set == AH_TRUE) && (data & flag))
655f51c4ae1Sreyk 			break;
6569ebef271Sreyk 		else if ((data & flag) == val)
657f51c4ae1Sreyk 			break;
658f51c4ae1Sreyk 		AR5K_DELAY(15);
659f51c4ae1Sreyk 	}
660f51c4ae1Sreyk 
661f51c4ae1Sreyk 	if (i <= 0)
662f51c4ae1Sreyk 		return (AH_FALSE);
663f51c4ae1Sreyk 
664f51c4ae1Sreyk 	return (AH_TRUE);
665f51c4ae1Sreyk }
6669ebef271Sreyk 
6679ebef271Sreyk /*
6689ebef271Sreyk  * Common ar5xx EEPROM access functions
6699ebef271Sreyk  */
6709ebef271Sreyk 
6719ebef271Sreyk u_int16_t
ar5k_eeprom_bin2freq(struct ath_hal * hal,u_int16_t bin,u_int mode)672a9b481abSjsg ar5k_eeprom_bin2freq(struct ath_hal *hal, u_int16_t bin, u_int mode)
6739ebef271Sreyk {
6749ebef271Sreyk 	u_int16_t val;
6759ebef271Sreyk 
6769ebef271Sreyk 	if (bin == AR5K_EEPROM_CHANNEL_DIS)
6779ebef271Sreyk 		return (bin);
6789ebef271Sreyk 
6799ebef271Sreyk 	if (mode == AR5K_EEPROM_MODE_11A) {
6809ebef271Sreyk 		if (hal->ah_ee_version > AR5K_EEPROM_VERSION_3_2)
6819ebef271Sreyk 			val = (5 * bin) + 4800;
6829ebef271Sreyk 		else
6839ebef271Sreyk 			val = bin > 62 ?
6849ebef271Sreyk 			    (10 * 62) + (5 * (bin - 62)) + 5100 :
6859ebef271Sreyk 			    (bin * 10) + 5100;
6869ebef271Sreyk 	} else {
6879ebef271Sreyk 		if (hal->ah_ee_version > AR5K_EEPROM_VERSION_3_2)
6889ebef271Sreyk 			val = bin + 2300;
6899ebef271Sreyk 		else
6909ebef271Sreyk 			val = bin + 2400;
6919ebef271Sreyk 	}
6929ebef271Sreyk 
6939ebef271Sreyk 	return (val);
6949ebef271Sreyk }
6959ebef271Sreyk 
6969ebef271Sreyk int
ar5k_eeprom_read_ants(struct ath_hal * hal,u_int32_t * offset,u_int mode)697a9b481abSjsg ar5k_eeprom_read_ants(struct ath_hal *hal, u_int32_t *offset, u_int mode)
6989ebef271Sreyk {
6999ebef271Sreyk 	struct ar5k_eeprom_info *ee = &hal->ah_capabilities.cap_eeprom;
7009ebef271Sreyk 	u_int32_t o = *offset;
7019ebef271Sreyk 	u_int16_t val;
7029ebef271Sreyk 	int ret, i = 0;
7039ebef271Sreyk 
704486f10cbSreyk 	AR5K_EEPROM_READ(o++, val);
7059ebef271Sreyk 	ee->ee_switch_settling[mode]	= (val >> 8) & 0x7f;
7069ebef271Sreyk 	ee->ee_ant_tx_rx[mode]		= (val >> 2) & 0x3f;
7079ebef271Sreyk 	ee->ee_ant_control[mode][i]	= (val << 4) & 0x3f;
7089ebef271Sreyk 
709486f10cbSreyk 	AR5K_EEPROM_READ(o++, val);
7109ebef271Sreyk 	ee->ee_ant_control[mode][i++]	|= (val >> 12) & 0xf;
7119ebef271Sreyk 	ee->ee_ant_control[mode][i++]	= (val >> 6) & 0x3f;
7129ebef271Sreyk 	ee->ee_ant_control[mode][i++]	= val & 0x3f;
7139ebef271Sreyk 
714486f10cbSreyk 	AR5K_EEPROM_READ(o++, val);
7159ebef271Sreyk 	ee->ee_ant_control[mode][i++]	= (val >> 10) & 0x3f;
7169ebef271Sreyk 	ee->ee_ant_control[mode][i++]	= (val >> 4) & 0x3f;
7179ebef271Sreyk 	ee->ee_ant_control[mode][i]	= (val << 2) & 0x3f;
7189ebef271Sreyk 
719486f10cbSreyk 	AR5K_EEPROM_READ(o++, val);
7209ebef271Sreyk 	ee->ee_ant_control[mode][i++]	|= (val >> 14) & 0x3;
7219ebef271Sreyk 	ee->ee_ant_control[mode][i++]	= (val >> 8) & 0x3f;
7229ebef271Sreyk 	ee->ee_ant_control[mode][i++]	= (val >> 2) & 0x3f;
7239ebef271Sreyk 	ee->ee_ant_control[mode][i]	= (val << 4) & 0x3f;
7249ebef271Sreyk 
725486f10cbSreyk 	AR5K_EEPROM_READ(o++, val);
7269ebef271Sreyk 	ee->ee_ant_control[mode][i++]	|= (val >> 12) & 0xf;
7279ebef271Sreyk 	ee->ee_ant_control[mode][i++]	= (val >> 6) & 0x3f;
7289ebef271Sreyk 	ee->ee_ant_control[mode][i++]	= val & 0x3f;
7299ebef271Sreyk 
7309ebef271Sreyk 	/* Get antenna modes */
7319ebef271Sreyk 	hal->ah_antenna[mode][0] =
7329ebef271Sreyk 	    (ee->ee_ant_control[mode][0] << 4) | 0x1;
7339ebef271Sreyk 	hal->ah_antenna[mode][HAL_ANT_FIXED_A] =
7349ebef271Sreyk 	    ee->ee_ant_control[mode][1] |
7359ebef271Sreyk 	    (ee->ee_ant_control[mode][2] << 6) |
7369ebef271Sreyk 	    (ee->ee_ant_control[mode][3] << 12) |
7379ebef271Sreyk 	    (ee->ee_ant_control[mode][4] << 18) |
7389ebef271Sreyk 	    (ee->ee_ant_control[mode][5] << 24);
7399ebef271Sreyk 	hal->ah_antenna[mode][HAL_ANT_FIXED_B] =
7409ebef271Sreyk 	    ee->ee_ant_control[mode][6] |
7419ebef271Sreyk 	    (ee->ee_ant_control[mode][7] << 6) |
7429ebef271Sreyk 	    (ee->ee_ant_control[mode][8] << 12) |
7439ebef271Sreyk 	    (ee->ee_ant_control[mode][9] << 18) |
7449ebef271Sreyk 	    (ee->ee_ant_control[mode][10] << 24);
7459ebef271Sreyk 
7469ebef271Sreyk 	/* return new offset */
7479ebef271Sreyk 	*offset = o;
7489ebef271Sreyk 
7499ebef271Sreyk 	return (0);
7509ebef271Sreyk }
7519ebef271Sreyk 
7529ebef271Sreyk int
ar5k_eeprom_read_modes(struct ath_hal * hal,u_int32_t * offset,u_int mode)753a9b481abSjsg ar5k_eeprom_read_modes(struct ath_hal *hal, u_int32_t *offset, u_int mode)
7549ebef271Sreyk {
7559ebef271Sreyk 	struct ar5k_eeprom_info *ee = &hal->ah_capabilities.cap_eeprom;
7569ebef271Sreyk 	u_int32_t o = *offset;
7579ebef271Sreyk 	u_int16_t val;
7589ebef271Sreyk 	int ret;
7599ebef271Sreyk 
760486f10cbSreyk 	AR5K_EEPROM_READ(o++, val);
7619ebef271Sreyk 	ee->ee_tx_end2xlna_enable[mode]	= (val >> 8) & 0xff;
7629ebef271Sreyk 	ee->ee_thr_62[mode]		= val & 0xff;
7639ebef271Sreyk 
7649ebef271Sreyk 	if (hal->ah_ee_version <= AR5K_EEPROM_VERSION_3_2)
7659ebef271Sreyk 		ee->ee_thr_62[mode] =
7669ebef271Sreyk 		    mode == AR5K_EEPROM_MODE_11A ? 15 : 28;
7679ebef271Sreyk 
768486f10cbSreyk 	AR5K_EEPROM_READ(o++, val);
7699ebef271Sreyk 	ee->ee_tx_end2xpa_disable[mode]	= (val >> 8) & 0xff;
7709ebef271Sreyk 	ee->ee_tx_frm2xpa_enable[mode]	= val & 0xff;
7719ebef271Sreyk 
772486f10cbSreyk 	AR5K_EEPROM_READ(o++, val);
7739ebef271Sreyk 	ee->ee_pga_desired_size[mode]	= (val >> 8) & 0xff;
7749ebef271Sreyk 
7759ebef271Sreyk 	if ((val & 0xff) & 0x80)
7769ebef271Sreyk 		ee->ee_noise_floor_thr[mode] = -((((val & 0xff) ^ 0xff)) + 1);
7779ebef271Sreyk 	else
7789ebef271Sreyk 		ee->ee_noise_floor_thr[mode] = val & 0xff;
7799ebef271Sreyk 
7809ebef271Sreyk 	if (hal->ah_ee_version <= AR5K_EEPROM_VERSION_3_2)
7819ebef271Sreyk 		ee->ee_noise_floor_thr[mode] =
7829ebef271Sreyk 		    mode == AR5K_EEPROM_MODE_11A ? -54 : -1;
7839ebef271Sreyk 
784486f10cbSreyk 	AR5K_EEPROM_READ(o++, val);
7859ebef271Sreyk 	ee->ee_xlna_gain[mode]		= (val >> 5) & 0xff;
7869ebef271Sreyk 	ee->ee_x_gain[mode]		= (val >> 1) & 0xf;
7879ebef271Sreyk 	ee->ee_xpd[mode]		= val & 0x1;
7889ebef271Sreyk 
7899ebef271Sreyk 	if (hal->ah_ee_version >= AR5K_EEPROM_VERSION_4_0)
7909ebef271Sreyk 		ee->ee_fixed_bias[mode] = (val >> 13) & 0x1;
7919ebef271Sreyk 
7929ebef271Sreyk 	if (hal->ah_ee_version >= AR5K_EEPROM_VERSION_3_3) {
793486f10cbSreyk 		AR5K_EEPROM_READ(o++, val);
7949ebef271Sreyk 		ee->ee_false_detect[mode] = (val >> 6) & 0x7f;
7959ebef271Sreyk 
7969ebef271Sreyk 		if (mode == AR5K_EEPROM_MODE_11A)
7979ebef271Sreyk 			ee->ee_xr_power[mode] = val & 0x3f;
7989ebef271Sreyk 		else {
7999ebef271Sreyk 			ee->ee_ob[mode][0] = val & 0x7;
8009ebef271Sreyk 			ee->ee_db[mode][0] = (val >> 3) & 0x7;
8019ebef271Sreyk 		}
8029ebef271Sreyk 	}
8039ebef271Sreyk 
8049ebef271Sreyk 	if (hal->ah_ee_version < AR5K_EEPROM_VERSION_3_4) {
8059ebef271Sreyk 		ee->ee_i_gain[mode] = AR5K_EEPROM_I_GAIN;
8069ebef271Sreyk 		ee->ee_cck_ofdm_power_delta = AR5K_EEPROM_CCK_OFDM_DELTA;
8079ebef271Sreyk 	} else {
8089ebef271Sreyk 		ee->ee_i_gain[mode] = (val >> 13) & 0x7;
8099ebef271Sreyk 
810486f10cbSreyk 		AR5K_EEPROM_READ(o++, val);
8119ebef271Sreyk 		ee->ee_i_gain[mode] |= (val << 3) & 0x38;
8129ebef271Sreyk 
8139ebef271Sreyk 		if (mode == AR5K_EEPROM_MODE_11G)
8149ebef271Sreyk 			ee->ee_cck_ofdm_power_delta = (val >> 3) & 0xff;
8159ebef271Sreyk 	}
8169ebef271Sreyk 
8179ebef271Sreyk 	if (hal->ah_ee_version >= AR5K_EEPROM_VERSION_4_0 &&
8189ebef271Sreyk 	    mode == AR5K_EEPROM_MODE_11A) {
8199ebef271Sreyk 		ee->ee_i_cal[mode] = (val >> 8) & 0x3f;
8209ebef271Sreyk 		ee->ee_q_cal[mode] = (val >> 3) & 0x1f;
8219ebef271Sreyk 	}
8229ebef271Sreyk 
8239ebef271Sreyk 	if (hal->ah_ee_version >= AR5K_EEPROM_VERSION_4_6 &&
8249ebef271Sreyk 	    mode == AR5K_EEPROM_MODE_11G)
8259ebef271Sreyk 		ee->ee_scaled_cck_delta = (val >> 11) & 0x1f;
8269ebef271Sreyk 
8279ebef271Sreyk 	/* return new offset */
8289ebef271Sreyk 	*offset = o;
8299ebef271Sreyk 
8309ebef271Sreyk 	return (0);
8319ebef271Sreyk }
8329ebef271Sreyk 
8339ebef271Sreyk int
ar5k_eeprom_init(struct ath_hal * hal)834a9b481abSjsg ar5k_eeprom_init(struct ath_hal *hal)
8359ebef271Sreyk {
8369ebef271Sreyk 	struct ar5k_eeprom_info *ee = &hal->ah_capabilities.cap_eeprom;
8379ebef271Sreyk 	u_int32_t offset;
8389ebef271Sreyk 	u_int16_t val;
8399ebef271Sreyk 	int ret, i;
8409ebef271Sreyk 	u_int mode;
8419ebef271Sreyk 
8429ebef271Sreyk 	/* Initial TX thermal adjustment values */
8439ebef271Sreyk 	ee->ee_tx_clip = 4;
8449ebef271Sreyk 	ee->ee_pwd_84 = ee->ee_pwd_90 = 1;
8459ebef271Sreyk 	ee->ee_gain_select = 1;
8469ebef271Sreyk 
8479ebef271Sreyk 	/*
8489ebef271Sreyk 	 * Read values from EEPROM and store them in the capability structure
8499ebef271Sreyk 	 */
850486f10cbSreyk 	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MAGIC, ee_magic);
851486f10cbSreyk 	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_PROTECT, ee_protect);
852486f10cbSreyk 	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_REG_DOMAIN, ee_regdomain);
853486f10cbSreyk 	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_VERSION, ee_version);
854486f10cbSreyk 	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_HDR, ee_header);
8559ebef271Sreyk 
8569ebef271Sreyk 	/* Return if we have an old EEPROM */
8579ebef271Sreyk 	if (hal->ah_ee_version < AR5K_EEPROM_VERSION_3_0)
8589ebef271Sreyk 		return (0);
8599ebef271Sreyk 
8600ce211edSreyk #ifdef notyet
8610ce211edSreyk 	/*
8620ce211edSreyk 	 * Validate the checksum of the EEPROM date. There are some
8630ce211edSreyk 	 * devices with invalid EEPROMs.
8640ce211edSreyk 	 */
8650ce211edSreyk 	for (cksum = 0, offset = 0; offset < AR5K_EEPROM_INFO_MAX; offset++) {
8660ce211edSreyk 		AR5K_EEPROM_READ(AR5K_EEPROM_INFO(offset), val);
8670ce211edSreyk 		cksum ^= val;
8680ce211edSreyk 	}
8690ce211edSreyk 	if (cksum != AR5K_EEPROM_INFO_CKSUM) {
8700ce211edSreyk 		AR5K_PRINTF("Invalid EEPROM checksum 0x%04x\n", cksum);
8710ce211edSreyk 		return (EINVAL);
8720ce211edSreyk 	}
8730ce211edSreyk #endif
8740ce211edSreyk 
875cd42f1d6Sreyk 	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_ANT_GAIN(hal->ah_ee_version),
876cd42f1d6Sreyk 	    ee_ant_gain);
8779ebef271Sreyk 
8789ebef271Sreyk 	if (hal->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) {
879486f10cbSreyk 		AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC0, ee_misc0);
880486f10cbSreyk 		AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC1, ee_misc1);
8819ebef271Sreyk 	}
8829ebef271Sreyk 
8839ebef271Sreyk 	if (hal->ah_ee_version < AR5K_EEPROM_VERSION_3_3) {
884486f10cbSreyk 		AR5K_EEPROM_READ(AR5K_EEPROM_OBDB0_2GHZ, val);
8859ebef271Sreyk 		ee->ee_ob[AR5K_EEPROM_MODE_11B][0] = val & 0x7;
8869ebef271Sreyk 		ee->ee_db[AR5K_EEPROM_MODE_11B][0] = (val >> 3) & 0x7;
8879ebef271Sreyk 
888486f10cbSreyk 		AR5K_EEPROM_READ(AR5K_EEPROM_OBDB1_2GHZ, val);
8899ebef271Sreyk 		ee->ee_ob[AR5K_EEPROM_MODE_11G][0] = val & 0x7;
8909ebef271Sreyk 		ee->ee_db[AR5K_EEPROM_MODE_11G][0] = (val >> 3) & 0x7;
8919ebef271Sreyk 	}
8929ebef271Sreyk 
8939ebef271Sreyk 	/*
8949ebef271Sreyk 	 * Get conformance test limit values
8959ebef271Sreyk 	 */
8969ebef271Sreyk 	offset = AR5K_EEPROM_CTL(hal->ah_ee_version);
8979ebef271Sreyk 	ee->ee_ctls = AR5K_EEPROM_N_CTLS(hal->ah_ee_version);
8989ebef271Sreyk 
89969aafab6Smestre 	for (i = 0; i < ee->ee_ctls - 1; i++) {
900486f10cbSreyk 		AR5K_EEPROM_READ(offset++, val);
9019ebef271Sreyk 		ee->ee_ctl[i] = (val >> 8) & 0xff;
9029ebef271Sreyk 		ee->ee_ctl[i + 1] = val & 0xff;
9039ebef271Sreyk 	}
9049ebef271Sreyk 
9059ebef271Sreyk 	/*
9069ebef271Sreyk 	 * Get values for 802.11a (5GHz)
9079ebef271Sreyk 	 */
9089ebef271Sreyk 	mode = AR5K_EEPROM_MODE_11A;
9099ebef271Sreyk 
9109ebef271Sreyk 	offset = AR5K_EEPROM_MODES_11A(hal->ah_ee_version);
9119ebef271Sreyk 
9129ebef271Sreyk 	if ((ret = ar5k_eeprom_read_ants(hal, &offset, mode)) != 0)
9139ebef271Sreyk 		return (ret);
9149ebef271Sreyk 
915486f10cbSreyk 	AR5K_EEPROM_READ(offset++, val);
9169ebef271Sreyk 	ee->ee_adc_desired_size[mode]	= (int8_t)((val >> 8) & 0xff);
9179ebef271Sreyk 	ee->ee_ob[mode][3]		= (val >> 5) & 0x7;
9189ebef271Sreyk 	ee->ee_db[mode][3]		= (val >> 2) & 0x7;
9199ebef271Sreyk 	ee->ee_ob[mode][2]		= (val << 1) & 0x7;
9209ebef271Sreyk 
921486f10cbSreyk 	AR5K_EEPROM_READ(offset++, val);
9229ebef271Sreyk 	ee->ee_ob[mode][2]		|= (val >> 15) & 0x1;
9239ebef271Sreyk 	ee->ee_db[mode][2]		= (val >> 12) & 0x7;
9249ebef271Sreyk 	ee->ee_ob[mode][1]		= (val >> 9) & 0x7;
9259ebef271Sreyk 	ee->ee_db[mode][1]		= (val >> 6) & 0x7;
9269ebef271Sreyk 	ee->ee_ob[mode][0]		= (val >> 3) & 0x7;
9279ebef271Sreyk 	ee->ee_db[mode][0]		= val & 0x7;
9289ebef271Sreyk 
9299ebef271Sreyk 	if ((ret = ar5k_eeprom_read_modes(hal, &offset, mode)) != 0)
9309ebef271Sreyk 		return (ret);
9319ebef271Sreyk 
9329ebef271Sreyk 	if (hal->ah_ee_version >= AR5K_EEPROM_VERSION_4_1) {
933486f10cbSreyk 		AR5K_EEPROM_READ(offset++, val);
9349ebef271Sreyk 		ee->ee_margin_tx_rx[mode] = val & 0x3f;
9359ebef271Sreyk 	}
9369ebef271Sreyk 
9379ebef271Sreyk 	/*
9389ebef271Sreyk 	 * Get values for 802.11b (2.4GHz)
9399ebef271Sreyk 	 */
9409ebef271Sreyk 	mode = AR5K_EEPROM_MODE_11B;
9419ebef271Sreyk 	offset = AR5K_EEPROM_MODES_11B(hal->ah_ee_version);
9429ebef271Sreyk 
9439ebef271Sreyk 	if ((ret = ar5k_eeprom_read_ants(hal, &offset, mode)) != 0)
9449ebef271Sreyk 		return (ret);
9459ebef271Sreyk 
946486f10cbSreyk 	AR5K_EEPROM_READ(offset++, val);
9479ebef271Sreyk 	ee->ee_adc_desired_size[mode]	= (int8_t)((val >> 8) & 0xff);
9489ebef271Sreyk 	ee->ee_ob[mode][1]		= (val >> 4) & 0x7;
9499ebef271Sreyk 	ee->ee_db[mode][1]		= val & 0x7;
9509ebef271Sreyk 
9519ebef271Sreyk 	if ((ret = ar5k_eeprom_read_modes(hal, &offset, mode)) != 0)
9529ebef271Sreyk 		return (ret);
9539ebef271Sreyk 
9549ebef271Sreyk 	if (hal->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) {
955486f10cbSreyk 		AR5K_EEPROM_READ(offset++, val);
9569ebef271Sreyk 		ee->ee_cal_pier[mode][0] =
9579ebef271Sreyk 		    ar5k_eeprom_bin2freq(hal, val & 0xff, mode);
9589ebef271Sreyk 		ee->ee_cal_pier[mode][1] =
9599ebef271Sreyk 		    ar5k_eeprom_bin2freq(hal, (val >> 8) & 0xff, mode);
9609ebef271Sreyk 
961486f10cbSreyk 		AR5K_EEPROM_READ(offset++, val);
9629ebef271Sreyk 		ee->ee_cal_pier[mode][2] =
9639ebef271Sreyk 		    ar5k_eeprom_bin2freq(hal, val & 0xff, mode);
9649ebef271Sreyk 	}
9659ebef271Sreyk 
9669ebef271Sreyk 	if (hal->ah_ee_version >= AR5K_EEPROM_VERSION_4_1) {
9679ebef271Sreyk 		ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f;
9689ebef271Sreyk 	}
9699ebef271Sreyk 
9709ebef271Sreyk 	/*
9719ebef271Sreyk 	 * Get values for 802.11g (2.4GHz)
9729ebef271Sreyk 	 */
9739ebef271Sreyk 	mode = AR5K_EEPROM_MODE_11G;
9749ebef271Sreyk 	offset = AR5K_EEPROM_MODES_11G(hal->ah_ee_version);
9759ebef271Sreyk 
9769ebef271Sreyk 	if ((ret = ar5k_eeprom_read_ants(hal, &offset, mode)) != 0)
9779ebef271Sreyk 		return (ret);
9789ebef271Sreyk 
979486f10cbSreyk 	AR5K_EEPROM_READ(offset++, val);
9809ebef271Sreyk 	ee->ee_adc_desired_size[mode]	= (int8_t)((val >> 8) & 0xff);
9819ebef271Sreyk 	ee->ee_ob[mode][1]		= (val >> 4) & 0x7;
9829ebef271Sreyk 	ee->ee_db[mode][1]		= val & 0x7;
9839ebef271Sreyk 
9849ebef271Sreyk 	if ((ret = ar5k_eeprom_read_modes(hal, &offset, mode)) != 0)
9859ebef271Sreyk 		return (ret);
9869ebef271Sreyk 
9879ebef271Sreyk 	if (hal->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) {
988486f10cbSreyk 		AR5K_EEPROM_READ(offset++, val);
9899ebef271Sreyk 		ee->ee_cal_pier[mode][0] =
9909ebef271Sreyk 		    ar5k_eeprom_bin2freq(hal, val & 0xff, mode);
9919ebef271Sreyk 		ee->ee_cal_pier[mode][1] =
9929ebef271Sreyk 		    ar5k_eeprom_bin2freq(hal, (val >> 8) & 0xff, mode);
9939ebef271Sreyk 
994486f10cbSreyk 		AR5K_EEPROM_READ(offset++, val);
9959ebef271Sreyk 		ee->ee_xr_power[mode] = (val >> 7) & 0x3f;
9969ebef271Sreyk 
997486f10cbSreyk 		AR5K_EEPROM_READ(offset++, val);
9989ebef271Sreyk 		ee->ee_cal_pier[mode][2] =
9999ebef271Sreyk 		    ar5k_eeprom_bin2freq(hal, val & 0xff, mode);
10009ebef271Sreyk 
10019ebef271Sreyk 		if (hal->ah_ee_version >= AR5K_EEPROM_VERSION_4_1) {
10029ebef271Sreyk 			ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f;
10039ebef271Sreyk 		}
10049ebef271Sreyk 
1005486f10cbSreyk 		AR5K_EEPROM_READ(offset++, val);
10069ebef271Sreyk 		ee->ee_i_cal[mode] = (val >> 8) & 0x3f;
10079ebef271Sreyk 		ee->ee_q_cal[mode] = (val >> 3) & 0x1f;
10089ebef271Sreyk 
10099ebef271Sreyk 		if (hal->ah_ee_version >= AR5K_EEPROM_VERSION_4_2) {
1010486f10cbSreyk 			AR5K_EEPROM_READ(offset++, val);
10119ebef271Sreyk 			ee->ee_cck_ofdm_gain_delta = val & 0xff;
10129ebef271Sreyk 		}
10139ebef271Sreyk 	}
10149ebef271Sreyk 
10159ebef271Sreyk 	/*
10169ebef271Sreyk 	 * Read 5GHz EEPROM channels
10179ebef271Sreyk 	 */
10189ebef271Sreyk 
10199ebef271Sreyk 	return (0);
10209ebef271Sreyk }
10219ebef271Sreyk 
10229ebef271Sreyk int
ar5k_eeprom_read_mac(struct ath_hal * hal,u_int8_t * mac)1023a9b481abSjsg ar5k_eeprom_read_mac(struct ath_hal *hal, u_int8_t *mac)
10249ebef271Sreyk {
10259ebef271Sreyk 	u_int32_t total, offset;
10269ebef271Sreyk 	u_int16_t data;
10279ebef271Sreyk 	int octet;
10289ebef271Sreyk 	u_int8_t mac_d[IEEE80211_ADDR_LEN];
10299ebef271Sreyk 
10309ebef271Sreyk 	bzero(mac, IEEE80211_ADDR_LEN);
10319ebef271Sreyk 	bzero(&mac_d, IEEE80211_ADDR_LEN);
10329ebef271Sreyk 
10339ebef271Sreyk 	if (hal->ah_eeprom_read(hal, 0x20, &data) != 0)
10349ebef271Sreyk 		return (EIO);
10359ebef271Sreyk 
10369ebef271Sreyk 	for (offset = 0x1f, octet = 0, total = 0;
10379ebef271Sreyk 	     offset >= 0x1d; offset--) {
10389ebef271Sreyk 		if (hal->ah_eeprom_read(hal, offset, &data) != 0)
10399ebef271Sreyk 			return (EIO);
10409ebef271Sreyk 
10419ebef271Sreyk 		total += data;
10429ebef271Sreyk 		mac_d[octet + 1] = data & 0xff;
10439ebef271Sreyk 		mac_d[octet] = data >> 8;
10449ebef271Sreyk 		octet += 2;
10459ebef271Sreyk 	}
10469ebef271Sreyk 
1047c6d5838dSreyk 	bcopy(mac_d, mac, IEEE80211_ADDR_LEN);
10489ebef271Sreyk 
10499ebef271Sreyk 	if ((!total) || total == (3 * 0xffff))
10509ebef271Sreyk 		return (EINVAL);
10519ebef271Sreyk 
10529ebef271Sreyk 	return (0);
10539ebef271Sreyk }
10549ebef271Sreyk 
10559ebef271Sreyk HAL_BOOL
ar5k_eeprom_regulation_domain(struct ath_hal * hal,HAL_BOOL write,ieee80211_regdomain_t * regdomain)1056a9b481abSjsg ar5k_eeprom_regulation_domain(struct ath_hal *hal, HAL_BOOL write,
1057a9b481abSjsg     ieee80211_regdomain_t *regdomain)
10589ebef271Sreyk {
105923349211Sreyk 	u_int16_t ee_regdomain;
106023349211Sreyk 
10619ebef271Sreyk 	/* Read current value */
10629ebef271Sreyk 	if (write != AH_TRUE) {
106323349211Sreyk 		ee_regdomain = hal->ah_capabilities.cap_eeprom.ee_regdomain;
106423349211Sreyk 		*regdomain = ar5k_regdomain_to_ieee(ee_regdomain);
10659ebef271Sreyk 		return (AH_TRUE);
10669ebef271Sreyk 	}
10679ebef271Sreyk 
106823349211Sreyk 	ee_regdomain = ar5k_regdomain_from_ieee(*regdomain);
10699ebef271Sreyk 
107023349211Sreyk 	/* Try to write a new value */
10719ebef271Sreyk 	if (hal->ah_capabilities.cap_eeprom.ee_protect &
10729ebef271Sreyk 	    AR5K_EEPROM_PROTECT_WR_128_191)
10739ebef271Sreyk 		return (AH_FALSE);
10749ebef271Sreyk 	if (hal->ah_eeprom_write(hal, AR5K_EEPROM_REG_DOMAIN,
107523349211Sreyk 	    ee_regdomain) != 0)
10769ebef271Sreyk 		return (AH_FALSE);
10779ebef271Sreyk 
107823349211Sreyk 	hal->ah_capabilities.cap_eeprom.ee_regdomain = ee_regdomain;
1079486f10cbSreyk 
10809ebef271Sreyk 	return (AH_TRUE);
10819ebef271Sreyk }
10829ebef271Sreyk 
10839ebef271Sreyk /*
10849ebef271Sreyk  * PHY/RF access functions
10859ebef271Sreyk  */
10869ebef271Sreyk 
10879ebef271Sreyk HAL_BOOL
ar5k_channel(struct ath_hal * hal,HAL_CHANNEL * channel)1088a9b481abSjsg ar5k_channel(struct ath_hal *hal, HAL_CHANNEL *channel)
10899ebef271Sreyk {
10909ebef271Sreyk 	HAL_BOOL ret;
10919ebef271Sreyk 
10929ebef271Sreyk 	/*
10939ebef271Sreyk 	 * Check bounds supported by the PHY
10949ebef271Sreyk 	 * (don't care about regulation restrictions at this point)
10959ebef271Sreyk 	 */
10969ebef271Sreyk 	if ((channel->channel < hal->ah_capabilities.cap_range.range_2ghz_min ||
10979ebef271Sreyk 	    channel->channel > hal->ah_capabilities.cap_range.range_2ghz_max) &&
10989ebef271Sreyk 	    (channel->channel < hal->ah_capabilities.cap_range.range_5ghz_min ||
10999ebef271Sreyk 	    channel->channel > hal->ah_capabilities.cap_range.range_5ghz_max)) {
11009ebef271Sreyk 		AR5K_PRINTF("channel out of supported range (%u MHz)\n",
11019ebef271Sreyk 		    channel->channel);
11029ebef271Sreyk 		return (AH_FALSE);
11039ebef271Sreyk 	}
11049ebef271Sreyk 
11059ebef271Sreyk 	/*
11069ebef271Sreyk 	 * Set the channel and wait
11079ebef271Sreyk 	 */
1108486f10cbSreyk 	if (hal->ah_radio == AR5K_AR5110)
11099ebef271Sreyk 		ret = ar5k_ar5110_channel(hal, channel);
1110486f10cbSreyk 	else if (hal->ah_radio == AR5K_AR5111)
11119ebef271Sreyk 		ret = ar5k_ar5111_channel(hal, channel);
1112486f10cbSreyk 	else
11139ebef271Sreyk 		ret = ar5k_ar5112_channel(hal, channel);
11149ebef271Sreyk 
11159ebef271Sreyk 	if (ret == AH_FALSE)
11169ebef271Sreyk 		return (ret);
11179ebef271Sreyk 
11189ebef271Sreyk 	hal->ah_current_channel.c_channel = channel->c_channel;
11199ebef271Sreyk 	hal->ah_current_channel.c_channel_flags = channel->c_channel_flags;
11209ebef271Sreyk 
11219ebef271Sreyk 	return (AH_TRUE);
11229ebef271Sreyk }
11239ebef271Sreyk 
11249ebef271Sreyk u_int32_t
ar5k_ar5110_chan2athchan(HAL_CHANNEL * channel)1125a9b481abSjsg ar5k_ar5110_chan2athchan(HAL_CHANNEL *channel)
11269ebef271Sreyk {
11279ebef271Sreyk 	u_int32_t athchan;
11289ebef271Sreyk 
11299ebef271Sreyk 	/*
11309ebef271Sreyk 	 * Convert IEEE channel/MHz to an internal channel value used
11319ebef271Sreyk 	 * by the AR5210 chipset. This has not been verified with
11329ebef271Sreyk 	 * newer chipsets like the AR5212A who have a completely
11339ebef271Sreyk 	 * different RF/PHY part.
11349ebef271Sreyk 	 */
11359ebef271Sreyk 	athchan = (ar5k_bitswap((ieee80211_mhz2ieee(channel->c_channel,
1136cd42f1d6Sreyk 	    channel->c_channel_flags) - 24) / 2, 5) << 1) |
1137cd42f1d6Sreyk 	    (1 << 6) | 0x1;
11389ebef271Sreyk 
11399ebef271Sreyk 	return (athchan);
11409ebef271Sreyk }
11419ebef271Sreyk 
11429ebef271Sreyk HAL_BOOL
ar5k_ar5110_channel(struct ath_hal * hal,HAL_CHANNEL * channel)1143a9b481abSjsg ar5k_ar5110_channel(struct ath_hal *hal, HAL_CHANNEL *channel)
11449ebef271Sreyk {
11459ebef271Sreyk 	u_int32_t data;
11469ebef271Sreyk 
11479ebef271Sreyk 	/*
11489ebef271Sreyk 	 * Set the channel and wait
11499ebef271Sreyk 	 */
11509ebef271Sreyk 	data = ar5k_ar5110_chan2athchan(channel);
11519ebef271Sreyk 	AR5K_PHY_WRITE(0x27, data);
11529ebef271Sreyk 	AR5K_PHY_WRITE(0x30, 0);
11539ebef271Sreyk 	AR5K_DELAY(1000);
11549ebef271Sreyk 
11559ebef271Sreyk 	return (AH_TRUE);
11569ebef271Sreyk }
11579ebef271Sreyk 
11589ebef271Sreyk HAL_BOOL
ar5k_ar5111_chan2athchan(u_int ieee,struct ar5k_athchan_2ghz * athchan)1159a9b481abSjsg ar5k_ar5111_chan2athchan(u_int ieee, struct ar5k_athchan_2ghz *athchan)
11609ebef271Sreyk {
11619ebef271Sreyk 	int channel;
11629ebef271Sreyk 
11639ebef271Sreyk 	/* Cast this value to catch negative channel numbers (>= -19) */
11649ebef271Sreyk 	channel = (int)ieee;
11659ebef271Sreyk 
11669ebef271Sreyk 	/*
11679ebef271Sreyk 	 * Map 2GHz IEEE channel to 5GHz Atheros channel
11689ebef271Sreyk 	 */
11699ebef271Sreyk 	if (channel <= 13) {
11709ebef271Sreyk 		athchan->a2_athchan = 115 + channel;
11719ebef271Sreyk 		athchan->a2_flags = 0x46;
11729ebef271Sreyk 	} else if (channel == 14) {
11739ebef271Sreyk 		athchan->a2_athchan = 124;
11749ebef271Sreyk 		athchan->a2_flags = 0x44;
11759ebef271Sreyk 	} else if (channel >= 15 && channel <= 26) {
11769ebef271Sreyk 		athchan->a2_athchan = ((channel - 14) * 4) + 132;
11779ebef271Sreyk 		athchan->a2_flags = 0x46;
11789ebef271Sreyk 	} else
11799ebef271Sreyk 		return (AH_FALSE);
11809ebef271Sreyk 
11819ebef271Sreyk 	return (AH_TRUE);
11829ebef271Sreyk }
11839ebef271Sreyk 
11849ebef271Sreyk HAL_BOOL
ar5k_ar5111_channel(struct ath_hal * hal,HAL_CHANNEL * channel)1185a9b481abSjsg ar5k_ar5111_channel(struct ath_hal *hal, HAL_CHANNEL *channel)
11869ebef271Sreyk {
11879ebef271Sreyk 	u_int ieee_channel, ath_channel;
11889ebef271Sreyk 	u_int32_t data0, data1, clock;
11899ebef271Sreyk 	struct ar5k_athchan_2ghz ath_channel_2ghz;
11909ebef271Sreyk 
11919ebef271Sreyk 	/*
11929ebef271Sreyk 	 * Set the channel on the AR5111 radio
11939ebef271Sreyk 	 */
1194d404baa7Sreyk 	data0 = data1 = 0;
119522e1ded6Sreyk 	ath_channel = ieee_channel = ieee80211_mhz2ieee(channel->c_channel,
11969ebef271Sreyk 	    channel->c_channel_flags);
11979ebef271Sreyk 
11989ebef271Sreyk 	if (channel->c_channel_flags & IEEE80211_CHAN_2GHZ) {
11999ebef271Sreyk 		/* Map 2GHz channel to 5GHz Atheros channel ID */
12009ebef271Sreyk 		if (ar5k_ar5111_chan2athchan(ieee_channel,
12019ebef271Sreyk 			&ath_channel_2ghz) == AH_FALSE)
12029ebef271Sreyk 			return (AH_FALSE);
12039ebef271Sreyk 
12049ebef271Sreyk 		ath_channel = ath_channel_2ghz.a2_athchan;
12059ebef271Sreyk 		data0 = ((ar5k_bitswap(ath_channel_2ghz.a2_flags, 8) & 0xff)
12069ebef271Sreyk 		    << 5) | (1 << 4);
12079ebef271Sreyk 	}
12089ebef271Sreyk 
12099ebef271Sreyk 	if (ath_channel < 145 || !(ath_channel & 1)) {
12109ebef271Sreyk 		clock = 1;
12119ebef271Sreyk 		data1 = ((ar5k_bitswap(ath_channel - 24, 8) & 0xff) << 2)
12129ebef271Sreyk 		    | (clock << 1) | (1 << 10) | 1;
12139ebef271Sreyk 	} else {
12149ebef271Sreyk 		clock = 0;
12159ebef271Sreyk 		data1 = ((ar5k_bitswap((ath_channel - 24) / 2, 8) & 0xff) << 2)
12169ebef271Sreyk 		    | (clock << 1) | (1 << 10) | 1;
12179ebef271Sreyk 	}
12189ebef271Sreyk 
12199ebef271Sreyk 	AR5K_PHY_WRITE(0x27, (data1 & 0xff) | ((data0 & 0xff) << 8));
12209ebef271Sreyk 	AR5K_PHY_WRITE(0x34, ((data1 >> 8) & 0xff) | (data0 & 0xff00));
12219ebef271Sreyk 
12229ebef271Sreyk 	return (AH_TRUE);
12239ebef271Sreyk }
12249ebef271Sreyk 
12259ebef271Sreyk HAL_BOOL
ar5k_ar5112_channel(struct ath_hal * hal,HAL_CHANNEL * channel)1226a9b481abSjsg ar5k_ar5112_channel(struct ath_hal *hal, HAL_CHANNEL *channel)
12279ebef271Sreyk {
12289ebef271Sreyk 	u_int32_t data, data0, data1, data2;
12299ebef271Sreyk 	u_int16_t c;
12309ebef271Sreyk 
1231d404baa7Sreyk 	data = data0 = data1 = data2 = 0;
12320a6c70f8Sreyk 	c = channel->c_channel + hal->ah_chanoff;
12339ebef271Sreyk 
12349ebef271Sreyk 	/*
12359ebef271Sreyk 	 * Set the channel on the AR5112 or newer
12369ebef271Sreyk 	 */
12379ebef271Sreyk 	if (c < 4800) {
12389ebef271Sreyk 		if (!((c - 2224) % 5)) {
12399ebef271Sreyk 			data0 = ((2 * (c - 704)) - 3040) / 10;
12409ebef271Sreyk 			data1 = 1;
12419ebef271Sreyk 		} else if (!((c - 2192) % 5)) {
12429ebef271Sreyk 			data0 = ((2 * (c - 672)) - 3040) / 10;
12439ebef271Sreyk 			data1 = 0;
12449ebef271Sreyk 		} else
12459ebef271Sreyk 			return (AH_FALSE);
12469ebef271Sreyk 
12479ebef271Sreyk 		data0 = ar5k_bitswap((data0 << 2) & 0xff, 8);
12489ebef271Sreyk 	} else {
12499ebef271Sreyk 		if (!(c % 20) && c >= 5120) {
12509ebef271Sreyk 			data0 = ar5k_bitswap(((c - 4800) / 20 << 2), 8);
12519ebef271Sreyk 			data2 = ar5k_bitswap(3, 2);
12529ebef271Sreyk 		} else if (!(c % 10)) {
12539ebef271Sreyk 			data0 = ar5k_bitswap(((c - 4800) / 10 << 1), 8);
12549ebef271Sreyk 			data2 = ar5k_bitswap(2, 2);
12559ebef271Sreyk 		} else if (!(c % 5)) {
12569ebef271Sreyk 			data0 = ar5k_bitswap((c - 4800) / 5, 8);
12579ebef271Sreyk 			data2 = ar5k_bitswap(1, 2);
12589ebef271Sreyk 		} else
12599ebef271Sreyk 			return (AH_FALSE);
12609ebef271Sreyk 	}
12619ebef271Sreyk 
12629ebef271Sreyk 	data = (data0 << 4) | (data1 << 1) | (data2 << 2) | 0x1001;
12639ebef271Sreyk 
12649ebef271Sreyk 	AR5K_PHY_WRITE(0x27, data & 0xff);
12659ebef271Sreyk 	AR5K_PHY_WRITE(0x36, (data >> 8) & 0x7f);
12669ebef271Sreyk 
12679ebef271Sreyk 	return (AH_TRUE);
12689ebef271Sreyk }
12699ebef271Sreyk 
1270e9147aabSreyk u_int
ar5k_rfregs_op(u_int32_t * rf,u_int32_t offset,u_int32_t reg,u_int32_t bits,u_int32_t first,u_int32_t col,HAL_BOOL set)1271a9b481abSjsg ar5k_rfregs_op(u_int32_t *rf, u_int32_t offset, u_int32_t reg, u_int32_t bits,
1272a9b481abSjsg     u_int32_t first, u_int32_t col, HAL_BOOL set)
12739ebef271Sreyk {
1274dd37d60cSreyk 	u_int32_t mask, entry, last, data, shift, position;
1275dd37d60cSreyk 	int32_t left;
12769ebef271Sreyk 	int i;
12779ebef271Sreyk 
1278e9147aabSreyk 	if (rf == NULL) {
1279e9147aabSreyk 		/* should not happen */
1280e9147aabSreyk 		return (0);
1281e9147aabSreyk 	}
1282e9147aabSreyk 
12839ebef271Sreyk 	if (!(col <= 3 && bits <= 32 && first + bits <= 319)) {
12849ebef271Sreyk 		AR5K_PRINTF("invalid values at offset %u\n", offset);
1285dd37d60cSreyk 		return (0);
12869ebef271Sreyk 	}
12879ebef271Sreyk 
12889ebef271Sreyk 	entry = ((first - 1) / 8) + offset;
12899ebef271Sreyk 	position = (first - 1) % 8;
12909ebef271Sreyk 
1291dd37d60cSreyk 	if (set == AH_TRUE)
1292dd37d60cSreyk 		data = ar5k_bitswap(reg, bits);
1293dd37d60cSreyk 
1294dd37d60cSreyk 	for (i = shift = 0, left = bits; left > 0; position = 0, entry++, i++) {
12959ebef271Sreyk 		last = (position + left > 8) ? 8 : position + left;
12969ebef271Sreyk 		mask = (((1 << last) - 1) ^ ((1 << position) - 1)) <<
12979ebef271Sreyk 		    (col * 8);
1298dd37d60cSreyk 
1299dd37d60cSreyk 		if (set == AH_TRUE) {
13009ebef271Sreyk 			rf[entry] &= ~mask;
1301dd37d60cSreyk 			rf[entry] |= ((data << position) << (col * 8)) & mask;
1302dd37d60cSreyk 			data >>= (8 - position);
1303dd37d60cSreyk 		} else {
1304dd37d60cSreyk 			data = (((rf[entry] & mask) >> (col * 8)) >>
1305dd37d60cSreyk 			    position) << shift;
1306dd37d60cSreyk 			shift += last - position;
13079ebef271Sreyk 		}
13089ebef271Sreyk 
1309dd37d60cSreyk 		left -= 8 - position;
1310dd37d60cSreyk 	}
1311dd37d60cSreyk 
1312dd37d60cSreyk 	data = set == AH_TRUE ? 1 : ar5k_bitswap(data, bits);
1313dd37d60cSreyk 
1314dd37d60cSreyk 	return (data);
1315dd37d60cSreyk }
1316dd37d60cSreyk 
1317dd37d60cSreyk u_int32_t
ar5k_rfregs_gainf_corr(struct ath_hal * hal)1318a9b481abSjsg ar5k_rfregs_gainf_corr(struct ath_hal *hal)
1319dd37d60cSreyk {
1320dd37d60cSreyk 	u_int32_t mix, step;
1321e9147aabSreyk 	u_int32_t *rf;
1322dd37d60cSreyk 
1323e9147aabSreyk 	if (hal->ah_rf_banks == NULL)
1324dd37d60cSreyk 		return (0);
1325dd37d60cSreyk 
1326e9147aabSreyk 	rf = hal->ah_rf_banks;
1327e9147aabSreyk 	hal->ah_gain.g_f_corr = 0;
1328e9147aabSreyk 
1329e9147aabSreyk 	if (ar5k_rfregs_op(rf, hal->ah_offset[7], 0, 1, 36, 0, AH_FALSE) != 1)
1330e9147aabSreyk 		return (0);
1331e9147aabSreyk 
1332e9147aabSreyk 	step = ar5k_rfregs_op(rf, hal->ah_offset[7], 0, 4, 32, 0, AH_FALSE);
1333dd37d60cSreyk 	mix = hal->ah_gain.g_step->gos_param[0];
1334dd37d60cSreyk 
1335dd37d60cSreyk 	switch (mix) {
1336dd37d60cSreyk 	case 3:
1337dd37d60cSreyk 		hal->ah_gain.g_f_corr = step * 2;
1338dd37d60cSreyk 		break;
1339dd37d60cSreyk 	case 2:
1340dd37d60cSreyk 		hal->ah_gain.g_f_corr = (step - 5) * 2;
1341dd37d60cSreyk 		break;
1342dd37d60cSreyk 	case 1:
1343dd37d60cSreyk 		hal->ah_gain.g_f_corr = step;
1344dd37d60cSreyk 		break;
1345dd37d60cSreyk 	default:
1346dd37d60cSreyk 		hal->ah_gain.g_f_corr = 0;
1347dd37d60cSreyk 		break;
1348dd37d60cSreyk 	}
1349dd37d60cSreyk 
1350dd37d60cSreyk 	return (hal->ah_gain.g_f_corr);
1351dd37d60cSreyk }
1352dd37d60cSreyk 
1353dd37d60cSreyk HAL_BOOL
ar5k_rfregs_gain_readback(struct ath_hal * hal)1354a9b481abSjsg ar5k_rfregs_gain_readback(struct ath_hal *hal)
1355dd37d60cSreyk {
1356dd37d60cSreyk 	u_int32_t step, mix, level[4];
1357e9147aabSreyk 	u_int32_t *rf;
1358e9147aabSreyk 
1359e9147aabSreyk 	if (hal->ah_rf_banks == NULL)
1360e9147aabSreyk 		return (0);
1361e9147aabSreyk 
1362e9147aabSreyk 	rf = hal->ah_rf_banks;
1363dd37d60cSreyk 
1364dd37d60cSreyk 	if (hal->ah_radio == AR5K_AR5111) {
1365e9147aabSreyk 		step = ar5k_rfregs_op(rf, hal->ah_offset[7],
1366dd37d60cSreyk 		    0, 6, 37, 0, AH_FALSE);
1367dd37d60cSreyk 		level[0] = 0;
1368dd37d60cSreyk 		level[1] = (step == 0x3f) ? 0x32 : step + 4;
1369dd37d60cSreyk 		level[2] = (step != 0x3f) ? 0x40 : level[0];
1370dd37d60cSreyk 		level[3] = level[2] + 0x32;
1371dd37d60cSreyk 
1372dd37d60cSreyk 		hal->ah_gain.g_high = level[3] -
1373dd37d60cSreyk 		    (step == 0x3f ? AR5K_GAIN_DYN_ADJUST_HI_MARGIN : -5);
1374dd37d60cSreyk 		hal->ah_gain.g_low = level[0] +
1375dd37d60cSreyk 		    (step == 0x3f ? AR5K_GAIN_DYN_ADJUST_LO_MARGIN : 0);
1376dd37d60cSreyk 	} else {
1377e9147aabSreyk 		mix = ar5k_rfregs_op(rf, hal->ah_offset[7],
1378dd37d60cSreyk 		    0, 1, 36, 0, AH_FALSE);
1379dd37d60cSreyk 		level[0] = level[2] = 0;
1380dd37d60cSreyk 
1381dd37d60cSreyk 		if (mix == 1) {
1382dd37d60cSreyk 			level[1] = level[3] = 83;
1383dd37d60cSreyk 		} else {
1384dd37d60cSreyk 			level[1] = level[3] = 107;
1385dd37d60cSreyk 			hal->ah_gain.g_high = 55;
1386dd37d60cSreyk 		}
1387dd37d60cSreyk 	}
1388dd37d60cSreyk 
1389dd37d60cSreyk 	return ((hal->ah_gain.g_current >= level[0] &&
1390dd37d60cSreyk 	    hal->ah_gain.g_current <= level[1]) ||
1391dd37d60cSreyk 	    (hal->ah_gain.g_current >= level[2] &&
1392dd37d60cSreyk 	    hal->ah_gain.g_current <= level[3]));
1393dd37d60cSreyk }
1394dd37d60cSreyk 
1395dd37d60cSreyk int32_t
ar5k_rfregs_gain_adjust(struct ath_hal * hal)1396a9b481abSjsg ar5k_rfregs_gain_adjust(struct ath_hal *hal)
1397dd37d60cSreyk {
1398dd37d60cSreyk 	int ret = 0;
1399dd37d60cSreyk 	const struct ar5k_gain_opt *go;
1400dd37d60cSreyk 
1401dd37d60cSreyk 	go = hal->ah_radio == AR5K_AR5111 ?
1402dd37d60cSreyk 	    &ar5111_gain_opt : &ar5112_gain_opt;
1403dd37d60cSreyk 
1404dd37d60cSreyk 	hal->ah_gain.g_step = &go->go_step[hal->ah_gain.g_step_idx];
1405dd37d60cSreyk 
1406dd37d60cSreyk 	if (hal->ah_gain.g_current >= hal->ah_gain.g_high) {
1407dd37d60cSreyk 		if (hal->ah_gain.g_step_idx == 0)
1408dd37d60cSreyk 			return (-1);
1409dd37d60cSreyk 		for (hal->ah_gain.g_target = hal->ah_gain.g_current;
1410dd37d60cSreyk 		    hal->ah_gain.g_target >=  hal->ah_gain.g_high &&
1411dd37d60cSreyk 		    hal->ah_gain.g_step_idx > 0;
1412dd37d60cSreyk 		    hal->ah_gain.g_step =
1413dd37d60cSreyk 		    &go->go_step[hal->ah_gain.g_step_idx]) {
1414dd37d60cSreyk 			hal->ah_gain.g_target -= 2 *
1415dd37d60cSreyk 			    (go->go_step[--(hal->ah_gain.g_step_idx)].gos_gain -
1416dd37d60cSreyk 			    hal->ah_gain.g_step->gos_gain);
1417dd37d60cSreyk 		}
1418dd37d60cSreyk 
1419dd37d60cSreyk 		ret = 1;
1420dd37d60cSreyk 		goto done;
1421dd37d60cSreyk 	}
1422dd37d60cSreyk 
1423dd37d60cSreyk 	if (hal->ah_gain.g_current <= hal->ah_gain.g_low) {
1424dd37d60cSreyk 		if (hal->ah_gain.g_step_idx == (go->go_steps_count - 1))
1425dd37d60cSreyk 			return (-2);
1426dd37d60cSreyk 		for (hal->ah_gain.g_target = hal->ah_gain.g_current;
1427dd37d60cSreyk 		    hal->ah_gain.g_target <=  hal->ah_gain.g_low &&
1428dd37d60cSreyk 		    hal->ah_gain.g_step_idx < (go->go_steps_count - 1);
1429dd37d60cSreyk 		    hal->ah_gain.g_step =
1430dd37d60cSreyk 		    &go->go_step[hal->ah_gain.g_step_idx]) {
1431dd37d60cSreyk 			hal->ah_gain.g_target -= 2 *
1432dd37d60cSreyk 			    (go->go_step[++(hal->ah_gain.g_step_idx)].gos_gain -
1433dd37d60cSreyk 			    hal->ah_gain.g_step->gos_gain);
1434dd37d60cSreyk 		}
1435dd37d60cSreyk 
1436dd37d60cSreyk 		ret = 2;
1437dd37d60cSreyk 		goto done;
1438dd37d60cSreyk 	}
1439dd37d60cSreyk 
1440dd37d60cSreyk  done:
1441dd37d60cSreyk #ifdef AR5K_DEBUG
1442dd37d60cSreyk 	AR5K_PRINTF("ret %d, gain step %u, current gain %u, target gain %u\n",
1443f89ed979Sreyk 	    ret,
1444dd37d60cSreyk 	    hal->ah_gain.g_step_idx,
1445dd37d60cSreyk 	    hal->ah_gain.g_current,
1446dd37d60cSreyk 	    hal->ah_gain.g_target);
1447dd37d60cSreyk #endif
1448dd37d60cSreyk 
1449dd37d60cSreyk 	return (ret);
14509ebef271Sreyk }
14519ebef271Sreyk 
14529ebef271Sreyk HAL_BOOL
ar5k_rfregs(struct ath_hal * hal,HAL_CHANNEL * channel,u_int mode)1453a9b481abSjsg ar5k_rfregs(struct ath_hal *hal, HAL_CHANNEL *channel, u_int mode)
14549ebef271Sreyk {
1455e9147aabSreyk 	ar5k_rfgain_t *func = NULL;
1456dd37d60cSreyk 	HAL_BOOL ret;
1457dd37d60cSreyk 
1458b59011f9Sreyk 	switch (hal->ah_radio) {
1459b59011f9Sreyk 	case AR5K_AR5111:
1460e9147aabSreyk 		hal->ah_rf_banks_size = sizeof(ar5111_rf);
1461e9147aabSreyk 		func = ar5k_ar5111_rfregs;
1462b59011f9Sreyk 		break;
1463b59011f9Sreyk 	case AR5K_AR5112:
14640ce211edSreyk 		if (hal->ah_radio_5ghz_revision >= AR5K_SREV_RAD_5112A)
14650ce211edSreyk 			hal->ah_rf_banks_size = sizeof(ar5112a_rf);
14660ce211edSreyk 		else
1467e9147aabSreyk 			hal->ah_rf_banks_size = sizeof(ar5112_rf);
1468e9147aabSreyk 		func = ar5k_ar5112_rfregs;
1469b59011f9Sreyk 		break;
1470b59011f9Sreyk 	case AR5K_AR5413:
1471b59011f9Sreyk 		hal->ah_rf_banks_size = sizeof(ar5413_rf);
1472b59011f9Sreyk 		func = ar5k_arxxxx_rfregs;
1473b59011f9Sreyk 		break;
1474b59011f9Sreyk 	case AR5K_AR2413:
1475b59011f9Sreyk 		hal->ah_rf_banks_size = sizeof(ar2413_rf);
1476b59011f9Sreyk 		func = ar5k_arxxxx_rfregs;
1477b59011f9Sreyk 		break;
1478b59011f9Sreyk 	case AR5K_AR2425:
1479b59011f9Sreyk 		hal->ah_rf_banks_size = sizeof(ar2425_rf);
1480b59011f9Sreyk 		func = ar5k_arxxxx_rfregs;
1481b59011f9Sreyk 		break;
1482b59011f9Sreyk 	default:
14839ebef271Sreyk 		return (AH_FALSE);
1484b59011f9Sreyk 	}
14859ebef271Sreyk 
1486e9147aabSreyk 	if (hal->ah_rf_banks == NULL) {
1487e9147aabSreyk 		/* XXX do extra checks? */
1488d93ea26fSreyk 		if ((hal->ah_rf_banks = malloc(hal->ah_rf_banks_size,
14894ba500adSreyk 		    M_DEVBUF, M_NOWAIT | M_ZERO)) == NULL) {
1490e9147aabSreyk 			AR5K_PRINT("out of memory\n");
1491e9147aabSreyk 			return (AH_FALSE);
1492e9147aabSreyk 		}
1493e9147aabSreyk 	}
1494e9147aabSreyk 
1495e9147aabSreyk 	ret = (func)(hal, channel, mode);
1496dd37d60cSreyk 
1497dd37d60cSreyk 	if (ret == AH_TRUE)
1498dd37d60cSreyk 		hal->ah_rf_gain = HAL_RFGAIN_INACTIVE;
1499dd37d60cSreyk 
1500dd37d60cSreyk 	return (ret);
15019ebef271Sreyk }
15029ebef271Sreyk 
15039ebef271Sreyk HAL_BOOL
ar5k_ar5111_rfregs(struct ath_hal * hal,HAL_CHANNEL * channel,u_int mode)1504a9b481abSjsg ar5k_ar5111_rfregs(struct ath_hal *hal, HAL_CHANNEL *channel, u_int mode)
15059ebef271Sreyk {
15069ebef271Sreyk 	struct ar5k_eeprom_info *ee = &hal->ah_capabilities.cap_eeprom;
15074d0d30b5Sreyk 	const u_int rf_size = nitems(ar5111_rf);
1508e9147aabSreyk 	u_int32_t *rf;
15099ebef271Sreyk 	int i, obdb = -1, bank = -1;
1510dd37d60cSreyk 	u_int32_t ee_mode;
15119ebef271Sreyk 
15129ebef271Sreyk 	AR5K_ASSERT_ENTRY(mode, AR5K_INI_VAL_MAX);
15139ebef271Sreyk 
1514e9147aabSreyk 	rf = hal->ah_rf_banks;
1515e9147aabSreyk 
15169ebef271Sreyk 	/* Copy values to modify them */
15179ebef271Sreyk 	for (i = 0; i < rf_size; i++) {
15189ebef271Sreyk 		if (ar5111_rf[i].rf_bank >=
15199ebef271Sreyk 		    AR5K_AR5111_INI_RF_MAX_BANKS) {
15209ebef271Sreyk 			AR5K_PRINT("invalid bank\n");
15219ebef271Sreyk 			return (AH_FALSE);
15229ebef271Sreyk 		}
15239ebef271Sreyk 
15249ebef271Sreyk 		if (bank != ar5111_rf[i].rf_bank) {
15259ebef271Sreyk 			bank = ar5111_rf[i].rf_bank;
1526dd37d60cSreyk 			hal->ah_offset[bank] = i;
15279ebef271Sreyk 		}
15289ebef271Sreyk 
15299ebef271Sreyk 		rf[i] = ar5111_rf[i].rf_value[mode];
15309ebef271Sreyk 	}
15319ebef271Sreyk 
15329ebef271Sreyk 	if (channel->c_channel_flags & IEEE80211_CHAN_2GHZ) {
15339d35d16dSfgsch 		if ((channel->c_channel_flags & IEEE80211_CHAN_G) ==
15349d35d16dSfgsch 		    IEEE80211_CHAN_G)
15359ebef271Sreyk 			ee_mode = AR5K_EEPROM_MODE_11G;
15369d35d16dSfgsch 		else
15379d35d16dSfgsch 			ee_mode = AR5K_EEPROM_MODE_11B;
15389ebef271Sreyk 		obdb = 0;
15399ebef271Sreyk 
1540dd37d60cSreyk 		if (!ar5k_rfregs_op(rf, hal->ah_offset[0],
1541dd37d60cSreyk 			ee->ee_ob[ee_mode][obdb], 3, 119, 0, AH_TRUE))
15429ebef271Sreyk 			return (AH_FALSE);
15439ebef271Sreyk 
1544dd37d60cSreyk 		if (!ar5k_rfregs_op(rf, hal->ah_offset[0],
1545dd37d60cSreyk 			ee->ee_ob[ee_mode][obdb], 3, 122, 0, AH_TRUE))
15469ebef271Sreyk 			return (AH_FALSE);
15479ebef271Sreyk 
15489ebef271Sreyk 		obdb = 1;
15499ebef271Sreyk 	} else {
15509ebef271Sreyk 		/* For 11a, Turbo and XR */
15519ebef271Sreyk 		ee_mode = AR5K_EEPROM_MODE_11A;
15529ebef271Sreyk 		obdb = channel->c_channel >= 5725 ? 3 :
15539ebef271Sreyk 		    (channel->c_channel >= 5500 ? 2 :
15549ebef271Sreyk 			(channel->c_channel >= 5260 ? 1 :
15559ebef271Sreyk 			    (channel->c_channel > 4000 ? 0 : -1)));
15569ebef271Sreyk 
1557dd37d60cSreyk 		if (!ar5k_rfregs_op(rf, hal->ah_offset[6],
1558dd37d60cSreyk 			ee->ee_pwd_84, 1, 51, 3, AH_TRUE))
15599ebef271Sreyk 			return (AH_FALSE);
15609ebef271Sreyk 
1561dd37d60cSreyk 		if (!ar5k_rfregs_op(rf, hal->ah_offset[6],
1562dd37d60cSreyk 			ee->ee_pwd_90, 1, 45, 3, AH_TRUE))
15639ebef271Sreyk 			return (AH_FALSE);
15649ebef271Sreyk 	}
15659ebef271Sreyk 
1566dd37d60cSreyk 	if (!ar5k_rfregs_op(rf, hal->ah_offset[6],
1567dd37d60cSreyk 		!ee->ee_xpd[ee_mode], 1, 95, 0, AH_TRUE))
15689ebef271Sreyk 		return (AH_FALSE);
15699ebef271Sreyk 
1570dd37d60cSreyk 	if (!ar5k_rfregs_op(rf, hal->ah_offset[6],
1571dd37d60cSreyk 		ee->ee_x_gain[ee_mode], 4, 96, 0, AH_TRUE))
15729ebef271Sreyk 		return (AH_FALSE);
15739ebef271Sreyk 
1574dd37d60cSreyk 	if (!ar5k_rfregs_op(rf, hal->ah_offset[6],
1575dd37d60cSreyk 		obdb >= 0 ? ee->ee_ob[ee_mode][obdb] : 0, 3, 104, 0, AH_TRUE))
15769ebef271Sreyk 		return (AH_FALSE);
15779ebef271Sreyk 
1578dd37d60cSreyk 	if (!ar5k_rfregs_op(rf, hal->ah_offset[6],
1579dd37d60cSreyk 		obdb >= 0 ? ee->ee_db[ee_mode][obdb] : 0, 3, 107, 0, AH_TRUE))
15809ebef271Sreyk 		return (AH_FALSE);
15819ebef271Sreyk 
1582dd37d60cSreyk 	if (!ar5k_rfregs_op(rf, hal->ah_offset[7],
1583dd37d60cSreyk 		ee->ee_i_gain[ee_mode], 6, 29, 0, AH_TRUE))
15849ebef271Sreyk 		return (AH_FALSE);
15859ebef271Sreyk 
1586dd37d60cSreyk 	if (!ar5k_rfregs_op(rf, hal->ah_offset[7],
1587dd37d60cSreyk 		ee->ee_xpd[ee_mode], 1, 4, 0, AH_TRUE))
15889ebef271Sreyk 		return (AH_FALSE);
15899ebef271Sreyk 
15909ebef271Sreyk 	/* Write RF values */
15919ebef271Sreyk 	for (i = 0; i < rf_size; i++) {
1592e9147aabSreyk 		AR5K_REG_WAIT(i);
15939ebef271Sreyk 		AR5K_REG_WRITE(ar5111_rf[i].rf_register, rf[i]);
15949ebef271Sreyk 	}
15959ebef271Sreyk 
15969ebef271Sreyk 	return (AH_TRUE);
15979ebef271Sreyk }
15989ebef271Sreyk 
15999ebef271Sreyk HAL_BOOL
ar5k_ar5112_rfregs(struct ath_hal * hal,HAL_CHANNEL * channel,u_int mode)1600a9b481abSjsg ar5k_ar5112_rfregs(struct ath_hal *hal, HAL_CHANNEL *channel, u_int mode)
16019ebef271Sreyk {
16029ebef271Sreyk 	struct ar5k_eeprom_info *ee = &hal->ah_capabilities.cap_eeprom;
16030ce211edSreyk 	u_int rf_size;
1604e9147aabSreyk 	u_int32_t *rf;
16059ebef271Sreyk 	int i, obdb = -1, bank = -1;
1606dd37d60cSreyk 	u_int32_t ee_mode;
16070ce211edSreyk 	const struct ar5k_ini_rf *rf_ini;
16089ebef271Sreyk 
16099ebef271Sreyk 	AR5K_ASSERT_ENTRY(mode, AR5K_INI_VAL_MAX);
16109ebef271Sreyk 
1611e9147aabSreyk 	rf = hal->ah_rf_banks;
1612e9147aabSreyk 
16130ce211edSreyk 	if (hal->ah_radio_5ghz_revision >= AR5K_SREV_RAD_5112A) {
16140ce211edSreyk 		rf_ini = ar5112a_rf;
16154d0d30b5Sreyk 		rf_size = nitems(ar5112a_rf);
16160ce211edSreyk 	} else {
16170ce211edSreyk 		rf_ini = ar5112_rf;
16184d0d30b5Sreyk 		rf_size = nitems(ar5112_rf);
16190ce211edSreyk 	}
16200ce211edSreyk 
16219ebef271Sreyk 	/* Copy values to modify them */
16229ebef271Sreyk 	for (i = 0; i < rf_size; i++) {
16230ce211edSreyk 		if (rf_ini[i].rf_bank >=
16249ebef271Sreyk 		    AR5K_AR5112_INI_RF_MAX_BANKS) {
16259ebef271Sreyk 			AR5K_PRINT("invalid bank\n");
16269ebef271Sreyk 			return (AH_FALSE);
16279ebef271Sreyk 		}
16289ebef271Sreyk 
16290ce211edSreyk 		if (bank != rf_ini[i].rf_bank) {
16300ce211edSreyk 			bank = rf_ini[i].rf_bank;
1631dd37d60cSreyk 			hal->ah_offset[bank] = i;
16329ebef271Sreyk 		}
16339ebef271Sreyk 
16340ce211edSreyk 		rf[i] = rf_ini[i].rf_value[mode];
16359ebef271Sreyk 	}
16369ebef271Sreyk 
16379ebef271Sreyk 	if (channel->c_channel_flags & IEEE80211_CHAN_2GHZ) {
16389d35d16dSfgsch 		if ((channel->c_channel_flags & IEEE80211_CHAN_G) ==
16399d35d16dSfgsch 		    IEEE80211_CHAN_G)
16409ebef271Sreyk 			ee_mode = AR5K_EEPROM_MODE_11G;
16419d35d16dSfgsch 		else
16429d35d16dSfgsch 			ee_mode = AR5K_EEPROM_MODE_11B;
16439ebef271Sreyk 		obdb = 0;
16449ebef271Sreyk 
1645dd37d60cSreyk 		if (!ar5k_rfregs_op(rf, hal->ah_offset[6],
1646dd37d60cSreyk 			ee->ee_ob[ee_mode][obdb], 3, 287, 0, AH_TRUE))
16479ebef271Sreyk 			return (AH_FALSE);
16489ebef271Sreyk 
1649dd37d60cSreyk 		if (!ar5k_rfregs_op(rf, hal->ah_offset[6],
1650dd37d60cSreyk 			ee->ee_ob[ee_mode][obdb], 3, 290, 0, AH_TRUE))
16519ebef271Sreyk 			return (AH_FALSE);
16529ebef271Sreyk 	} else {
16539ebef271Sreyk 		/* For 11a, Turbo and XR */
16549ebef271Sreyk 		ee_mode = AR5K_EEPROM_MODE_11A;
16559ebef271Sreyk 		obdb = channel->c_channel >= 5725 ? 3 :
16569ebef271Sreyk 		    (channel->c_channel >= 5500 ? 2 :
16579ebef271Sreyk 			(channel->c_channel >= 5260 ? 1 :
16589ebef271Sreyk 			    (channel->c_channel > 4000 ? 0 : -1)));
16599ebef271Sreyk 
16609c807d58Sguenther 		/* bogus channel: bad beacon? */
16619c807d58Sguenther 		if (obdb < 0)
16629c807d58Sguenther 			return (AH_FALSE);
16639c807d58Sguenther 
1664dd37d60cSreyk 		if (!ar5k_rfregs_op(rf, hal->ah_offset[6],
1665dd37d60cSreyk 			ee->ee_ob[ee_mode][obdb], 3, 279, 0, AH_TRUE))
16669ebef271Sreyk 			return (AH_FALSE);
16679ebef271Sreyk 
1668dd37d60cSreyk 		if (!ar5k_rfregs_op(rf, hal->ah_offset[6],
1669dd37d60cSreyk 			ee->ee_ob[ee_mode][obdb], 3, 282, 0, AH_TRUE))
16709ebef271Sreyk 			return (AH_FALSE);
16719ebef271Sreyk 	}
16729ebef271Sreyk 
16739ebef271Sreyk #ifdef notyet
1674dd37d60cSreyk 	ar5k_rfregs_op(rf, hal->ah_offset[6],
1675dd37d60cSreyk 	    ee->ee_x_gain[ee_mode], 2, 270, 0, AH_TRUE);
1676dd37d60cSreyk 	ar5k_rfregs_op(rf, hal->ah_offset[6],
1677dd37d60cSreyk 	    ee->ee_x_gain[ee_mode], 2, 257, 0, AH_TRUE);
16789ebef271Sreyk #endif
16799ebef271Sreyk 
1680dd37d60cSreyk 	if (!ar5k_rfregs_op(rf, hal->ah_offset[6],
1681dd37d60cSreyk 		ee->ee_xpd[ee_mode], 1, 302, 0, AH_TRUE))
16829ebef271Sreyk 		return (AH_FALSE);
16839ebef271Sreyk 
1684dd37d60cSreyk 	if (!ar5k_rfregs_op(rf, hal->ah_offset[7],
1685dd37d60cSreyk 		ee->ee_i_gain[ee_mode], 6, 14, 0, AH_TRUE))
16869ebef271Sreyk 		return (AH_FALSE);
16879ebef271Sreyk 
16889ebef271Sreyk 	/* Write RF values */
1689ae42076dSreyk 	for (i = 0; i < rf_size; i++)
1690b59011f9Sreyk 		AR5K_REG_WRITE(rf_ini[i].rf_register, rf[i]);
16919ebef271Sreyk 
16929ebef271Sreyk 	return (AH_TRUE);
16939ebef271Sreyk }
1694f23d19fdSreyk 
1695f23d19fdSreyk HAL_BOOL
ar5k_arxxxx_rfregs(struct ath_hal * hal,HAL_CHANNEL * channel,u_int mode)1696b59011f9Sreyk ar5k_arxxxx_rfregs(struct ath_hal *hal, HAL_CHANNEL *channel, u_int mode)
1697f23d19fdSreyk {
1698b59011f9Sreyk 	const struct ar5k_ini_rf	*rf_ini;
1699b59011f9Sreyk 	u_int				 rf_size;
1700b59011f9Sreyk 	u_int32_t			*rf;
1701b59011f9Sreyk 	int				 i, bank = -1;
1702b59011f9Sreyk 
1703b59011f9Sreyk 	AR5K_ASSERT_ENTRY(mode, AR5K_INI_VAL_MAX);
1704b59011f9Sreyk 
1705b59011f9Sreyk 	rf = hal->ah_rf_banks;
1706b59011f9Sreyk 
1707b59011f9Sreyk 	switch (hal->ah_radio) {
1708b59011f9Sreyk 	case AR5K_AR5413:
1709b59011f9Sreyk 		rf_ini = ar5413_rf;
17104d0d30b5Sreyk 		rf_size = nitems(ar5413_rf);
1711b59011f9Sreyk 		break;
1712b59011f9Sreyk 	case AR5K_AR2413:
1713b59011f9Sreyk 		rf_ini = ar2413_rf;
17144d0d30b5Sreyk 		rf_size = nitems(ar2413_rf);
1715b59011f9Sreyk 		break;
1716b59011f9Sreyk 	case AR5K_AR2425:
1717b59011f9Sreyk 		if (mode == AR5K_INI_VAL_11B)
1718b59011f9Sreyk 			mode = AR5K_INI_VAL_11G;
1719b59011f9Sreyk 		rf_ini = ar2425_rf;
17204d0d30b5Sreyk 		rf_size = nitems(ar2425_rf);
1721b59011f9Sreyk 		break;
1722b59011f9Sreyk 	default:
1723b59011f9Sreyk 		return (AH_FALSE);
1724b59011f9Sreyk 	}
1725b59011f9Sreyk 
1726b59011f9Sreyk 	/* Copy values to modify them */
1727b59011f9Sreyk 	for (i = 0; i < rf_size; i++) {
1728b59011f9Sreyk 		if (rf_ini[i].rf_bank >= AR5K_MAX_RF_BANKS) {
1729b59011f9Sreyk 			AR5K_PRINT("invalid bank\n");
1730b59011f9Sreyk 			return (AH_FALSE);
1731b59011f9Sreyk 		}
1732b59011f9Sreyk 
1733b59011f9Sreyk 		if (bank != rf_ini[i].rf_bank) {
1734b59011f9Sreyk 			bank = rf_ini[i].rf_bank;
1735b59011f9Sreyk 			hal->ah_offset[bank] = i;
1736b59011f9Sreyk 		}
1737b59011f9Sreyk 
1738b59011f9Sreyk 		rf[i] = rf_ini[i].rf_value[mode];
1739b59011f9Sreyk 	}
1740b59011f9Sreyk 
1741b59011f9Sreyk 	/* Write RF values */
1742b59011f9Sreyk 	for (i = 0; i < rf_size; i++)
1743b59011f9Sreyk 		AR5K_REG_WRITE(rf_ini[i].rf_register, rf[i]);
1744b59011f9Sreyk 
1745b59011f9Sreyk 	return (AH_TRUE);
1746b59011f9Sreyk }
1747b59011f9Sreyk 
1748b59011f9Sreyk HAL_BOOL
ar5k_rfgain(struct ath_hal * hal,u_int freq)1749b59011f9Sreyk ar5k_rfgain(struct ath_hal *hal, u_int freq)
1750b59011f9Sreyk {
1751b59011f9Sreyk 	const struct ar5k_ini_rfgain	*rfg;
1752b59011f9Sreyk 	size_t				 rfg_size;
1753f23d19fdSreyk 	int				 i;
1754f23d19fdSreyk 
1755b59011f9Sreyk 	switch (hal->ah_radio) {
1756b59011f9Sreyk 	case AR5K_AR5111:
1757b59011f9Sreyk 		rfg = ar5111_rfg;
17584d0d30b5Sreyk 		rfg_size = nitems(ar5111_rfg);
1759b59011f9Sreyk 		break;
1760b59011f9Sreyk 	case AR5K_AR5112:
1761b59011f9Sreyk 		rfg = ar5112_rfg;
17624d0d30b5Sreyk 		rfg_size = nitems(ar5112_rfg);
1763b59011f9Sreyk 		break;
1764b59011f9Sreyk 	case AR5K_AR5413:
1765b59011f9Sreyk 		rfg = ar5413_rfg;
17664d0d30b5Sreyk 		rfg_size = nitems(ar5413_rfg);
1767b59011f9Sreyk 		break;
1768b59011f9Sreyk 	case AR5K_AR2413:
1769b59011f9Sreyk 	case AR5K_AR2425:
1770b59011f9Sreyk 		if (freq == AR5K_INI_RFGAIN_5GHZ)
1771b59011f9Sreyk 			return (AH_FALSE);
1772b59011f9Sreyk 		rfg = ar2413_rfg;
17734d0d30b5Sreyk 		rfg_size = nitems(ar2413_rfg);
1774f23d19fdSreyk 		break;
1775f23d19fdSreyk 	default:
1776f23d19fdSreyk 		return (AH_FALSE);
1777f23d19fdSreyk 	}
1778f23d19fdSreyk 
1779f23d19fdSreyk 	switch (freq) {
1780f23d19fdSreyk 	case AR5K_INI_RFGAIN_2GHZ:
1781f23d19fdSreyk 	case AR5K_INI_RFGAIN_5GHZ:
1782f23d19fdSreyk 		break;
1783f23d19fdSreyk 	default:
1784f23d19fdSreyk 		return (AH_FALSE);
1785f23d19fdSreyk 	}
1786f23d19fdSreyk 
1787b59011f9Sreyk 	for (i = 0; i < rfg_size; i++) {
1788e9147aabSreyk 		AR5K_REG_WAIT(i);
1789b59011f9Sreyk 		AR5K_REG_WRITE((u_int32_t)rfg[i].rfg_register,
1790b59011f9Sreyk 		    rfg[i].rfg_value[freq]);
1791f23d19fdSreyk 	}
1792f23d19fdSreyk 
1793f23d19fdSreyk 	return (AH_TRUE);
1794f23d19fdSreyk }
1795e9147aabSreyk 
1796e9147aabSreyk /*
1797e9147aabSreyk  * Common TX power setup
1798e9147aabSreyk  */
1799e9147aabSreyk void
ar5k_txpower_table(struct ath_hal * hal,HAL_CHANNEL * channel,int16_t max_power)1800a9b481abSjsg ar5k_txpower_table(struct ath_hal *hal, HAL_CHANNEL *channel, int16_t max_power)
1801e9147aabSreyk {
1802e9147aabSreyk 	u_int16_t txpower, *rates;
18030ce211edSreyk 	int i, min, max, n;
1804e9147aabSreyk 
1805e9147aabSreyk 	rates = hal->ah_txpower.txp_rates;
1806e9147aabSreyk 
1807e9147aabSreyk 	txpower = AR5K_TUNE_DEFAULT_TXPOWER * 2;
1808e9147aabSreyk 	if (max_power > txpower) {
1809e9147aabSreyk 		txpower = max_power > AR5K_TUNE_MAX_TXPOWER ?
1810e9147aabSreyk 		    AR5K_TUNE_MAX_TXPOWER : max_power;
1811e9147aabSreyk 	}
1812e9147aabSreyk 
1813e9147aabSreyk 	for (i = 0; i < AR5K_MAX_RATES; i++)
1814e9147aabSreyk 		rates[i] = txpower;
1815e9147aabSreyk 
1816e9147aabSreyk 	/* XXX setup target powers by rate */
1817e9147aabSreyk 
1818e9147aabSreyk 	hal->ah_txpower.txp_min = rates[7];
1819e9147aabSreyk 	hal->ah_txpower.txp_max = rates[0];
1820e9147aabSreyk 	hal->ah_txpower.txp_ofdm = rates[0];
1821e9147aabSreyk 
18220ce211edSreyk 	/* Calculate the power table */
18234d0d30b5Sreyk 	n = nitems(hal->ah_txpower.txp_pcdac);
18240ce211edSreyk 	min = AR5K_EEPROM_PCDAC_START;
18250ce211edSreyk 	max = AR5K_EEPROM_PCDAC_STOP;
18260ce211edSreyk 	for (i = 0; i < n; i += AR5K_EEPROM_PCDAC_STEP)
18270ce211edSreyk 		hal->ah_txpower.txp_pcdac[i] =
18280ce211edSreyk #ifdef notyet
18290ce211edSreyk 		    min + ((i * (max - min)) / n);
18300ce211edSreyk #else
18310ce211edSreyk 		    min;
18320ce211edSreyk #endif
1833e9147aabSreyk }
1834b59011f9Sreyk 
1835b59011f9Sreyk void
ar5k_write_ini(struct ath_hal * hal,const struct ar5k_ini * ini,size_t n,HAL_BOOL change_channel)1836b59011f9Sreyk ar5k_write_ini(struct ath_hal *hal, const struct ar5k_ini *ini,
1837b59011f9Sreyk     size_t n, HAL_BOOL change_channel)
1838b59011f9Sreyk {
1839b59011f9Sreyk 	u_int	 i;
1840b59011f9Sreyk 
1841b59011f9Sreyk 	for (i = 0; i < n; i++) {
1842b59011f9Sreyk 		if (change_channel == AH_TRUE &&
1843b59011f9Sreyk 		    ini[i].ini_register >= AR5K_PCU_MIN &&
1844b59011f9Sreyk 		    ini[i].ini_register <= AR5K_PCU_MAX)
1845b59011f9Sreyk 			continue;
1846b59011f9Sreyk 		switch (ini[i].ini_mode) {
1847b59011f9Sreyk 		case AR5K_INI_READ:
1848b59011f9Sreyk 			/* cleared on read */
1849b59011f9Sreyk 			AR5K_REG_READ((u_int32_t)ini[i].ini_register);
1850b59011f9Sreyk 			break;
1851b59011f9Sreyk 		case AR5K_INI_WRITE:
1852b59011f9Sreyk 			AR5K_REG_WAIT(i);
1853b59011f9Sreyk 			AR5K_REG_WRITE((u_int32_t)ini[i].ini_register,
1854b59011f9Sreyk 			    ini[i].ini_value);
1855b59011f9Sreyk 			break;
1856b59011f9Sreyk 		}
1857b59011f9Sreyk 	}
1858b59011f9Sreyk }
1859b59011f9Sreyk 
1860b59011f9Sreyk void
ar5k_write_mode(struct ath_hal * hal,const struct ar5k_mode * ini,size_t n,u_int mode)1861b59011f9Sreyk ar5k_write_mode(struct ath_hal *hal, const struct ar5k_mode *ini,
1862b59011f9Sreyk     size_t n, u_int mode)
1863b59011f9Sreyk {
1864b59011f9Sreyk 	u_int	 i;
1865b59011f9Sreyk 
1866b59011f9Sreyk 	for (i = 0; i < n; i++) {
1867b59011f9Sreyk 		AR5K_REG_WAIT(i);
1868b59011f9Sreyk 		AR5K_REG_WRITE((u_int32_t)ini[i].mode_register,
1869b59011f9Sreyk 		    ini[i].mode_value[mode]);
1870b59011f9Sreyk 	}
1871b59011f9Sreyk }
1872