blob: 7db984ce90fb0c64c778d641ded12be7f93569dc [file] [log] [blame]
Nick Kossifidisc6e387a2008-08-29 22:45:39 +03001/*
2 * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
3 * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
4 * Copyright (c) 2007-2008 Luis Rodriguez <mcgrof@winlab.rutgers.edu>
5 * Copyright (c) 2007-2008 Pavel Roskin <proski@gnu.org>
6 * Copyright (c) 2007-2008 Jiri Slaby <jirislaby@gmail.com>
7 *
8 * Permission to use, copy, modify, and distribute this software for any
9 * purpose with or without fee is hereby granted, provided that the above
10 * copyright notice and this permission notice appear in all copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 *
20 */
21
Nick Kossifidisc6e387a2008-08-29 22:45:39 +030022/*****************************\
23 Reset functions and helpers
24\*****************************/
25
Luis R. Rodriguezbcd8f542009-09-09 22:43:17 -070026#include <asm/unaligned.h>
27
Nick Kossifidise8f055f2009-02-09 06:12:58 +020028#include <linux/pci.h> /* To determine if a card is pci-e */
Forrest Zhanga54be5d2009-05-13 11:14:39 -040029#include <linux/log2.h>
Nick Kossifidisc6e387a2008-08-29 22:45:39 +030030#include "ath5k.h"
31#include "reg.h"
32#include "base.h"
33#include "debug.h"
34
Nick Kossifidis9320b5c42010-11-23 20:36:45 +020035
36/******************\
37* Helper functions *
38\******************/
39
Pavel Roskinec182d92010-02-18 20:28:41 -050040/*
41 * Check if a register write has been completed
42 */
43int ath5k_hw_register_timeout(struct ath5k_hw *ah, u32 reg, u32 flag, u32 val,
44 bool is_set)
45{
46 int i;
47 u32 data;
48
49 for (i = AR5K_TUNE_REGISTER_TIMEOUT; i > 0; i--) {
50 data = ath5k_hw_reg_read(ah, reg);
51 if (is_set && (data & flag))
52 break;
53 else if ((data & flag) == val)
54 break;
55 udelay(15);
56 }
57
58 return (i <= 0) ? -EAGAIN : 0;
59}
60
Nick Kossifidis9320b5c42010-11-23 20:36:45 +020061
62/*************************\
63* Clock related functions *
64\*************************/
65
Nick Kossifidisc6e387a2008-08-29 22:45:39 +030066/**
Nick Kossifidis9320b5c42010-11-23 20:36:45 +020067 * ath5k_hw_htoclock - Translate usec to hw clock units
Nick Kossifidisc6e387a2008-08-29 22:45:39 +030068 *
Nick Kossifidis9320b5c42010-11-23 20:36:45 +020069 * @ah: The &struct ath5k_hw
70 * @usec: value in microseconds
Nick Kossifidisc6e387a2008-08-29 22:45:39 +030071 */
Nick Kossifidis9320b5c42010-11-23 20:36:45 +020072unsigned int ath5k_hw_htoclock(struct ath5k_hw *ah, unsigned int usec)
Nick Kossifidisc6e387a2008-08-29 22:45:39 +030073{
Nick Kossifidis9320b5c42010-11-23 20:36:45 +020074 struct ath_common *common = ath5k_hw_common(ah);
75 return usec * common->clockrate;
Nick Kossifidisc6e387a2008-08-29 22:45:39 +030076}
77
Nick Kossifidis9320b5c42010-11-23 20:36:45 +020078/**
79 * ath5k_hw_clocktoh - Translate hw clock units to usec
80 * @clock: value in hw clock units
81 */
82unsigned int ath5k_hw_clocktoh(struct ath5k_hw *ah, unsigned int clock)
83{
84 struct ath_common *common = ath5k_hw_common(ah);
85 return clock / common->clockrate;
86}
87
88/**
Nick Kossifidisc2975602010-11-23 21:00:37 +020089 * ath5k_hw_init_core_clock - Initialize core clock
Nick Kossifidis9320b5c42010-11-23 20:36:45 +020090 *
Nick Kossifidisc2975602010-11-23 21:00:37 +020091 * @ah The &struct ath5k_hw
92 *
93 * Initialize core clock parameters (usec, usec32, latencies etc).
Nick Kossifidis9320b5c42010-11-23 20:36:45 +020094 */
Nick Kossifidisc2975602010-11-23 21:00:37 +020095static void ath5k_hw_init_core_clock(struct ath5k_hw *ah)
Nick Kossifidis9320b5c42010-11-23 20:36:45 +020096{
97 struct ieee80211_channel *channel = ah->ah_current_channel;
98 struct ath_common *common = ath5k_hw_common(ah);
Nick Kossifidisc2975602010-11-23 21:00:37 +020099 u32 usec_reg, txlat, rxlat, usec, clock, sclock, txf2txs;
Nick Kossifidis9320b5c42010-11-23 20:36:45 +0200100
Nick Kossifidisc2975602010-11-23 21:00:37 +0200101 /*
102 * Set core clock frequency
103 */
Nick Kossifidis9320b5c42010-11-23 20:36:45 +0200104 if (channel->hw_value & CHANNEL_5GHZ)
105 clock = 40; /* 802.11a */
106 else if (channel->hw_value & CHANNEL_CCK)
107 clock = 22; /* 802.11b */
108 else
109 clock = 44; /* 802.11g */
110
Nick Kossifidisc2975602010-11-23 21:00:37 +0200111 /* Use clock multiplier for non-default
112 * bwmode */
113 switch (ah->ah_bwmode) {
114 case AR5K_BWMODE_40MHZ:
Nick Kossifidis9320b5c42010-11-23 20:36:45 +0200115 clock *= 2;
Nick Kossifidisc2975602010-11-23 21:00:37 +0200116 break;
117 case AR5K_BWMODE_10MHZ:
118 clock /= 2;
119 break;
120 case AR5K_BWMODE_5MHZ:
121 clock /= 4;
122 break;
123 default:
124 break;
125 }
Nick Kossifidis9320b5c42010-11-23 20:36:45 +0200126
127 common->clockrate = clock;
Nick Kossifidisc2975602010-11-23 21:00:37 +0200128
129 /*
130 * Set USEC parameters
131 */
132 /* Set USEC counter on PCU*/
133 usec = clock - 1;
134 usec = AR5K_REG_SM(usec, AR5K_USEC_1);
135
136 /* Set usec duration on DCU */
137 if (ah->ah_version != AR5K_AR5210)
138 AR5K_REG_WRITE_BITS(ah, AR5K_DCU_GBL_IFS_MISC,
139 AR5K_DCU_GBL_IFS_MISC_USEC_DUR,
140 clock);
141
142 /* Set 32MHz USEC counter */
143 if ((ah->ah_radio == AR5K_RF5112) ||
144 (ah->ah_radio == AR5K_RF5413))
145 /* Remain on 40MHz clock ? */
146 sclock = 40 - 1;
147 else
148 sclock = 32 - 1;
149 sclock = AR5K_REG_SM(sclock, AR5K_USEC_32);
150
151 /*
152 * Set tx/rx latencies
153 */
154 usec_reg = ath5k_hw_reg_read(ah, AR5K_USEC_5211);
155 txlat = AR5K_REG_MS(usec_reg, AR5K_USEC_TX_LATENCY_5211);
156 rxlat = AR5K_REG_MS(usec_reg, AR5K_USEC_RX_LATENCY_5211);
157
158 /*
159 * 5210 initvals don't include usec settings
160 * so we need to use magic values here for
161 * tx/rx latencies
162 */
163 if (ah->ah_version == AR5K_AR5210) {
164 /* same for turbo */
165 txlat = AR5K_INIT_TX_LATENCY_5210;
166 rxlat = AR5K_INIT_RX_LATENCY_5210;
167 }
168
169 if (ah->ah_mac_srev < AR5K_SREV_AR5211) {
170 /* 5311 has different tx/rx latency masks
171 * from 5211, since we deal 5311 the same
172 * as 5211 when setting initvals, shift
173 * values here to their proper locations
174 *
175 * Note: Initvals indicate tx/rx/ latencies
176 * are the same for turbo mode */
177 txlat = AR5K_REG_SM(txlat, AR5K_USEC_TX_LATENCY_5210);
178 rxlat = AR5K_REG_SM(rxlat, AR5K_USEC_RX_LATENCY_5210);
179 } else
180 switch (ah->ah_bwmode) {
181 case AR5K_BWMODE_10MHZ:
182 txlat = AR5K_REG_SM(txlat * 2,
183 AR5K_USEC_TX_LATENCY_5211);
184 rxlat = AR5K_REG_SM(AR5K_INIT_RX_LAT_MAX,
185 AR5K_USEC_RX_LATENCY_5211);
186 txf2txs = AR5K_INIT_TXF2TXD_START_DELAY_10MHZ;
187 break;
188 case AR5K_BWMODE_5MHZ:
189 txlat = AR5K_REG_SM(txlat * 4,
190 AR5K_USEC_TX_LATENCY_5211);
191 rxlat = AR5K_REG_SM(AR5K_INIT_RX_LAT_MAX,
192 AR5K_USEC_RX_LATENCY_5211);
193 txf2txs = AR5K_INIT_TXF2TXD_START_DELAY_5MHZ;
194 break;
195 case AR5K_BWMODE_40MHZ:
196 txlat = AR5K_INIT_TX_LAT_MIN;
197 rxlat = AR5K_REG_SM(rxlat / 2,
198 AR5K_USEC_RX_LATENCY_5211);
199 txf2txs = AR5K_INIT_TXF2TXD_START_DEFAULT;
200 break;
201 default:
202 break;
203 }
204
205 usec_reg = (usec | sclock | txlat | rxlat);
206 ath5k_hw_reg_write(ah, usec_reg, AR5K_USEC);
207
208 /* On 5112 set tx frane to tx data start delay */
209 if (ah->ah_radio == AR5K_RF5112) {
210 AR5K_REG_WRITE_BITS(ah, AR5K_PHY_RF_CTL2,
211 AR5K_PHY_RF_CTL2_TXF2TXD_START,
212 txf2txs);
213 }
Nick Kossifidis9320b5c42010-11-23 20:36:45 +0200214}
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300215
216/*
Nick Kossifidis9320b5c42010-11-23 20:36:45 +0200217 * If there is an external 32KHz crystal available, use it
218 * as ref. clock instead of 32/40MHz clock and baseband clocks
219 * to save power during sleep or restore normal 32/40MHz
220 * operation.
221 *
222 * XXX: When operating on 32KHz certain PHY registers (27 - 31,
223 * 123 - 127) require delay on access.
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300224 */
Nick Kossifidis9320b5c42010-11-23 20:36:45 +0200225static void ath5k_hw_set_sleep_clock(struct ath5k_hw *ah, bool enable)
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300226{
Nick Kossifidis9320b5c42010-11-23 20:36:45 +0200227 struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
Nick Kossifidisc2975602010-11-23 21:00:37 +0200228 u32 scal, spending;
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300229
Nick Kossifidis9320b5c42010-11-23 20:36:45 +0200230 /* Only set 32KHz settings if we have an external
231 * 32KHz crystal present */
232 if ((AR5K_EEPROM_HAS32KHZCRYSTAL(ee->ee_misc1) ||
233 AR5K_EEPROM_HAS32KHZCRYSTAL_OLD(ee->ee_misc1)) &&
234 enable) {
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300235
Nick Kossifidis9320b5c42010-11-23 20:36:45 +0200236 /* 1 usec/cycle */
237 AR5K_REG_WRITE_BITS(ah, AR5K_USEC_5211, AR5K_USEC_32, 1);
238 /* Set up tsf increment on each cycle */
239 AR5K_REG_WRITE_BITS(ah, AR5K_TSF_PARM, AR5K_TSF_PARM_INC, 61);
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300240
Nick Kossifidis9320b5c42010-11-23 20:36:45 +0200241 /* Set baseband sleep control registers
242 * and sleep control rate */
243 ath5k_hw_reg_write(ah, 0x1f, AR5K_PHY_SCR);
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300244
Nick Kossifidis9320b5c42010-11-23 20:36:45 +0200245 if ((ah->ah_radio == AR5K_RF5112) ||
246 (ah->ah_radio == AR5K_RF5413) ||
247 (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4)))
248 spending = 0x14;
249 else
250 spending = 0x18;
251 ath5k_hw_reg_write(ah, spending, AR5K_PHY_SPENDING);
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300252
Nick Kossifidis9320b5c42010-11-23 20:36:45 +0200253 if ((ah->ah_radio == AR5K_RF5112) ||
254 (ah->ah_radio == AR5K_RF5413) ||
255 (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4))) {
256 ath5k_hw_reg_write(ah, 0x26, AR5K_PHY_SLMT);
257 ath5k_hw_reg_write(ah, 0x0d, AR5K_PHY_SCAL);
258 ath5k_hw_reg_write(ah, 0x07, AR5K_PHY_SCLOCK);
259 ath5k_hw_reg_write(ah, 0x3f, AR5K_PHY_SDELAY);
260 AR5K_REG_WRITE_BITS(ah, AR5K_PCICFG,
261 AR5K_PCICFG_SLEEP_CLOCK_RATE, 0x02);
262 } else {
263 ath5k_hw_reg_write(ah, 0x0a, AR5K_PHY_SLMT);
264 ath5k_hw_reg_write(ah, 0x0c, AR5K_PHY_SCAL);
265 ath5k_hw_reg_write(ah, 0x03, AR5K_PHY_SCLOCK);
266 ath5k_hw_reg_write(ah, 0x20, AR5K_PHY_SDELAY);
267 AR5K_REG_WRITE_BITS(ah, AR5K_PCICFG,
268 AR5K_PCICFG_SLEEP_CLOCK_RATE, 0x03);
269 }
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300270
Nick Kossifidis9320b5c42010-11-23 20:36:45 +0200271 /* Enable sleep clock operation */
272 AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG,
273 AR5K_PCICFG_SLEEP_CLOCK_EN);
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300274
Nick Kossifidis9320b5c42010-11-23 20:36:45 +0200275 } else {
276
277 /* Disable sleep clock operation and
278 * restore default parameters */
279 AR5K_REG_DISABLE_BITS(ah, AR5K_PCICFG,
280 AR5K_PCICFG_SLEEP_CLOCK_EN);
281
282 AR5K_REG_WRITE_BITS(ah, AR5K_PCICFG,
283 AR5K_PCICFG_SLEEP_CLOCK_RATE, 0);
284
Nick Kossifidisc2975602010-11-23 21:00:37 +0200285 /* Set DAC/ADC delays */
Nick Kossifidis9320b5c42010-11-23 20:36:45 +0200286 ath5k_hw_reg_write(ah, 0x1f, AR5K_PHY_SCR);
287 ath5k_hw_reg_write(ah, AR5K_PHY_SLMT_32MHZ, AR5K_PHY_SLMT);
288
289 if (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4))
290 scal = AR5K_PHY_SCAL_32MHZ_2417;
291 else if (ee->ee_is_hb63)
292 scal = AR5K_PHY_SCAL_32MHZ_HB63;
293 else
294 scal = AR5K_PHY_SCAL_32MHZ;
295 ath5k_hw_reg_write(ah, scal, AR5K_PHY_SCAL);
296
297 ath5k_hw_reg_write(ah, AR5K_PHY_SCLOCK_32MHZ, AR5K_PHY_SCLOCK);
298 ath5k_hw_reg_write(ah, AR5K_PHY_SDELAY_32MHZ, AR5K_PHY_SDELAY);
299
300 if ((ah->ah_radio == AR5K_RF5112) ||
301 (ah->ah_radio == AR5K_RF5413) ||
302 (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4)))
303 spending = 0x14;
304 else
305 spending = 0x18;
306 ath5k_hw_reg_write(ah, spending, AR5K_PHY_SPENDING);
307
Nick Kossifidisc2975602010-11-23 21:00:37 +0200308 /* Set up tsf increment on each cycle */
Nick Kossifidis9320b5c42010-11-23 20:36:45 +0200309 AR5K_REG_WRITE_BITS(ah, AR5K_TSF_PARM, AR5K_TSF_PARM_INC, 1);
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300310 }
311}
312
Nick Kossifidis9320b5c42010-11-23 20:36:45 +0200313
314/*********************\
315* Reset/Sleep control *
316\*********************/
317
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300318/*
319 * Reset chipset
320 */
321static int ath5k_hw_nic_reset(struct ath5k_hw *ah, u32 val)
322{
323 int ret;
324 u32 mask = val ? val : ~0U;
325
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300326 /* Read-and-clear RX Descriptor Pointer*/
327 ath5k_hw_reg_read(ah, AR5K_RXDP);
328
329 /*
330 * Reset the device and wait until success
331 */
332 ath5k_hw_reg_write(ah, val, AR5K_RESET_CTL);
333
334 /* Wait at least 128 PCI clocks */
335 udelay(15);
336
337 if (ah->ah_version == AR5K_AR5210) {
Nick Kossifidis84e463f2008-09-17 03:33:19 +0300338 val &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_DMA
339 | AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_PHY;
340 mask &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_DMA
341 | AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_PHY;
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300342 } else {
343 val &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_BASEBAND;
344 mask &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_BASEBAND;
345 }
346
347 ret = ath5k_hw_register_timeout(ah, AR5K_RESET_CTL, mask, val, false);
348
349 /*
350 * Reset configuration register (for hw byte-swap). Note that this
351 * is only set for big endian. We do the necessary magic in
352 * AR5K_INIT_CFG.
353 */
354 if ((val & AR5K_RESET_CTL_PCU) == 0)
355 ath5k_hw_reg_write(ah, AR5K_INIT_CFG, AR5K_CFG);
356
357 return ret;
358}
359
360/*
361 * Sleep control
362 */
Pavel Roskin626ede62010-02-18 20:28:02 -0500363static int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode,
364 bool set_chip, u16 sleep_duration)
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300365{
366 unsigned int i;
367 u32 staid, data;
368
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300369 staid = ath5k_hw_reg_read(ah, AR5K_STA_ID1);
370
371 switch (mode) {
372 case AR5K_PM_AUTO:
373 staid &= ~AR5K_STA_ID1_DEFAULT_ANTENNA;
374 /* fallthrough */
375 case AR5K_PM_NETWORK_SLEEP:
376 if (set_chip)
377 ath5k_hw_reg_write(ah,
378 AR5K_SLEEP_CTL_SLE_ALLOW |
379 sleep_duration,
380 AR5K_SLEEP_CTL);
381
382 staid |= AR5K_STA_ID1_PWR_SV;
383 break;
384
385 case AR5K_PM_FULL_SLEEP:
386 if (set_chip)
387 ath5k_hw_reg_write(ah, AR5K_SLEEP_CTL_SLE_SLP,
388 AR5K_SLEEP_CTL);
389
390 staid |= AR5K_STA_ID1_PWR_SV;
391 break;
392
393 case AR5K_PM_AWAKE:
394
395 staid &= ~AR5K_STA_ID1_PWR_SV;
396
397 if (!set_chip)
398 goto commit;
399
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300400 data = ath5k_hw_reg_read(ah, AR5K_SLEEP_CTL);
Nick Kossifidisedd7fc72009-08-10 03:29:02 +0300401
402 /* If card is down we 'll get 0xffff... so we
403 * need to clean this up before we write the register
404 */
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300405 if (data & 0xffc00000)
406 data = 0;
407 else
Nick Kossifidisedd7fc72009-08-10 03:29:02 +0300408 /* Preserve sleep duration etc */
409 data = data & ~AR5K_SLEEP_CTL_SLE;
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300410
Nick Kossifidisedd7fc72009-08-10 03:29:02 +0300411 ath5k_hw_reg_write(ah, data | AR5K_SLEEP_CTL_SLE_WAKE,
412 AR5K_SLEEP_CTL);
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300413 udelay(15);
414
Nick Kossifidisedd7fc72009-08-10 03:29:02 +0300415 for (i = 200; i > 0; i--) {
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300416 /* Check if the chip did wake up */
417 if ((ath5k_hw_reg_read(ah, AR5K_PCICFG) &
418 AR5K_PCICFG_SPWR_DN) == 0)
419 break;
420
421 /* Wait a bit and retry */
Nick Kossifidisedd7fc72009-08-10 03:29:02 +0300422 udelay(50);
423 ath5k_hw_reg_write(ah, data | AR5K_SLEEP_CTL_SLE_WAKE,
424 AR5K_SLEEP_CTL);
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300425 }
426
427 /* Fail if the chip didn't wake up */
Nick Kossifidisedd7fc72009-08-10 03:29:02 +0300428 if (i == 0)
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300429 return -EIO;
430
431 break;
432
433 default:
434 return -EINVAL;
435 }
436
437commit:
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300438 ath5k_hw_reg_write(ah, staid, AR5K_STA_ID1);
439
440 return 0;
441}
442
443/*
Nick Kossifidisedd7fc72009-08-10 03:29:02 +0300444 * Put device on hold
445 *
446 * Put MAC and Baseband on warm reset and
447 * keep that state (don't clean sleep control
448 * register). After this MAC and Baseband are
449 * disabled and a full reset is needed to come
450 * back. This way we save as much power as possible
Bob Copeland8801df82010-08-21 16:39:02 -0400451 * without putting the card on full sleep.
Nick Kossifidisedd7fc72009-08-10 03:29:02 +0300452 */
453int ath5k_hw_on_hold(struct ath5k_hw *ah)
454{
455 struct pci_dev *pdev = ah->ah_sc->pdev;
456 u32 bus_flags;
457 int ret;
458
459 /* Make sure device is awake */
460 ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0);
461 if (ret) {
462 ATH5K_ERR(ah->ah_sc, "failed to wakeup the MAC Chip\n");
463 return ret;
464 }
465
466 /*
467 * Put chipset on warm reset...
468 *
Bob Copeland8801df82010-08-21 16:39:02 -0400469 * Note: putting PCI core on warm reset on PCI-E cards
Nick Kossifidisedd7fc72009-08-10 03:29:02 +0300470 * results card to hang and always return 0xffff... so
471 * we ingore that flag for PCI-E cards. On PCI cards
472 * this flag gets cleared after 64 PCI clocks.
473 */
474 bus_flags = (pdev->is_pcie) ? 0 : AR5K_RESET_CTL_PCI;
475
476 if (ah->ah_version == AR5K_AR5210) {
477 ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
478 AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_DMA |
479 AR5K_RESET_CTL_PHY | AR5K_RESET_CTL_PCI);
480 mdelay(2);
481 } else {
482 ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
483 AR5K_RESET_CTL_BASEBAND | bus_flags);
484 }
485
486 if (ret) {
487 ATH5K_ERR(ah->ah_sc, "failed to put device on warm reset\n");
488 return -EIO;
489 }
490
491 /* ...wakeup again!*/
492 ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0);
493 if (ret) {
494 ATH5K_ERR(ah->ah_sc, "failed to put device on hold\n");
495 return ret;
496 }
497
498 return ret;
499}
500
501/*
Nick Kossifidise8f055f2009-02-09 06:12:58 +0200502 * Bring up MAC + PHY Chips and program PLL
503 * TODO: Half/Quarter rate support
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300504 */
505int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
506{
507 struct pci_dev *pdev = ah->ah_sc->pdev;
508 u32 turbo, mode, clock, bus_flags;
509 int ret;
510
511 turbo = 0;
512 mode = 0;
513 clock = 0;
514
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300515 /* Wakeup the device */
516 ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0);
517 if (ret) {
518 ATH5K_ERR(ah->ah_sc, "failed to wakeup the MAC Chip\n");
519 return ret;
520 }
521
Nick Kossifidisedd7fc72009-08-10 03:29:02 +0300522 /*
523 * Put chipset on warm reset...
524 *
Bob Copeland8801df82010-08-21 16:39:02 -0400525 * Note: putting PCI core on warm reset on PCI-E cards
Nick Kossifidisedd7fc72009-08-10 03:29:02 +0300526 * results card to hang and always return 0xffff... so
527 * we ingore that flag for PCI-E cards. On PCI cards
528 * this flag gets cleared after 64 PCI clocks.
529 */
530 bus_flags = (pdev->is_pcie) ? 0 : AR5K_RESET_CTL_PCI;
531
532 if (ah->ah_version == AR5K_AR5210) {
533 ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
534 AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_DMA |
535 AR5K_RESET_CTL_PHY | AR5K_RESET_CTL_PCI);
536 mdelay(2);
537 } else {
538 ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
539 AR5K_RESET_CTL_BASEBAND | bus_flags);
540 }
541
542 if (ret) {
543 ATH5K_ERR(ah->ah_sc, "failed to reset the MAC Chip\n");
544 return -EIO;
545 }
546
547 /* ...wakeup again!...*/
548 ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0);
549 if (ret) {
550 ATH5K_ERR(ah->ah_sc, "failed to resume the MAC Chip\n");
551 return ret;
552 }
553
554 /* ...clear reset control register and pull device out of
555 * warm reset */
556 if (ath5k_hw_nic_reset(ah, 0)) {
557 ATH5K_ERR(ah->ah_sc, "failed to warm reset the MAC Chip\n");
558 return -EIO;
559 }
560
561 /* On initialization skip PLL programming since we don't have
562 * a channel / mode set yet */
563 if (initial)
564 return 0;
565
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300566 if (ah->ah_version != AR5K_AR5210) {
567 /*
568 * Get channel mode flags
569 */
570
571 if (ah->ah_radio >= AR5K_RF5112) {
572 mode = AR5K_PHY_MODE_RAD_RF5112;
573 clock = AR5K_PHY_PLL_RF5112;
574 } else {
575 mode = AR5K_PHY_MODE_RAD_RF5111; /*Zero*/
576 clock = AR5K_PHY_PLL_RF5111; /*Zero*/
577 }
578
579 if (flags & CHANNEL_2GHZ) {
580 mode |= AR5K_PHY_MODE_FREQ_2GHZ;
581 clock |= AR5K_PHY_PLL_44MHZ;
582
583 if (flags & CHANNEL_CCK) {
584 mode |= AR5K_PHY_MODE_MOD_CCK;
585 } else if (flags & CHANNEL_OFDM) {
586 /* XXX Dynamic OFDM/CCK is not supported by the
587 * AR5211 so we set MOD_OFDM for plain g (no
588 * CCK headers) operation. We need to test
589 * this, 5211 might support ofdm-only g after
590 * all, there are also initial register values
591 * in the code for g mode (see initvals.c). */
592 if (ah->ah_version == AR5K_AR5211)
593 mode |= AR5K_PHY_MODE_MOD_OFDM;
594 else
595 mode |= AR5K_PHY_MODE_MOD_DYN;
596 } else {
597 ATH5K_ERR(ah->ah_sc,
598 "invalid radio modulation mode\n");
599 return -EINVAL;
600 }
601 } else if (flags & CHANNEL_5GHZ) {
602 mode |= AR5K_PHY_MODE_FREQ_5GHZ;
Nick Kossifidise8f055f2009-02-09 06:12:58 +0200603
604 if (ah->ah_radio == AR5K_RF5413)
Pavel Roskin807e3732009-03-27 17:47:27 -0400605 clock = AR5K_PHY_PLL_40MHZ_5413;
Nick Kossifidise8f055f2009-02-09 06:12:58 +0200606 else
607 clock |= AR5K_PHY_PLL_40MHZ;
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300608
609 if (flags & CHANNEL_OFDM)
610 mode |= AR5K_PHY_MODE_MOD_OFDM;
611 else {
612 ATH5K_ERR(ah->ah_sc,
613 "invalid radio modulation mode\n");
614 return -EINVAL;
615 }
616 } else {
617 ATH5K_ERR(ah->ah_sc, "invalid radio frequency mode\n");
618 return -EINVAL;
619 }
620
621 if (flags & CHANNEL_TURBO)
622 turbo = AR5K_PHY_TURBO_MODE | AR5K_PHY_TURBO_SHORT;
623 } else { /* Reset the device */
624
625 /* ...enable Atheros turbo mode if requested */
626 if (flags & CHANNEL_TURBO)
627 ath5k_hw_reg_write(ah, AR5K_PHY_TURBO_MODE,
628 AR5K_PHY_TURBO);
629 }
630
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300631 if (ah->ah_version != AR5K_AR5210) {
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300632
Nick Kossifidise8f055f2009-02-09 06:12:58 +0200633 /* ...update PLL if needed */
634 if (ath5k_hw_reg_read(ah, AR5K_PHY_PLL) != clock) {
635 ath5k_hw_reg_write(ah, clock, AR5K_PHY_PLL);
636 udelay(300);
637 }
638
639 /* ...set the PHY operating mode */
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300640 ath5k_hw_reg_write(ah, mode, AR5K_PHY_MODE);
641 ath5k_hw_reg_write(ah, turbo, AR5K_PHY_TURBO);
642 }
643
644 return 0;
645}
646
Nick Kossifidise8f055f2009-02-09 06:12:58 +0200647
Nick Kossifidis9320b5c42010-11-23 20:36:45 +0200648/**************************************\
649* Post-initvals register modifications *
650\**************************************/
Nick Kossifidise8f055f2009-02-09 06:12:58 +0200651
Nick Kossifidise8f055f2009-02-09 06:12:58 +0200652/* TODO: Half/Quarter rate */
653static void ath5k_hw_tweak_initval_settings(struct ath5k_hw *ah,
654 struct ieee80211_channel *channel)
655{
656 if (ah->ah_version == AR5K_AR5212 &&
657 ah->ah_phy_revision >= AR5K_SREV_PHY_5212A) {
658
659 /* Setup ADC control */
660 ath5k_hw_reg_write(ah,
661 (AR5K_REG_SM(2,
662 AR5K_PHY_ADC_CTL_INBUFGAIN_OFF) |
663 AR5K_REG_SM(2,
664 AR5K_PHY_ADC_CTL_INBUFGAIN_ON) |
665 AR5K_PHY_ADC_CTL_PWD_DAC_OFF |
666 AR5K_PHY_ADC_CTL_PWD_ADC_OFF),
667 AR5K_PHY_ADC_CTL);
668
669
670
671 /* Disable barker RSSI threshold */
672 AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_DAG_CCK_CTL,
673 AR5K_PHY_DAG_CCK_CTL_EN_RSSI_THR);
674
675 AR5K_REG_WRITE_BITS(ah, AR5K_PHY_DAG_CCK_CTL,
676 AR5K_PHY_DAG_CCK_CTL_RSSI_THR, 2);
677
678 /* Set the mute mask */
679 ath5k_hw_reg_write(ah, 0x0000000f, AR5K_SEQ_MASK);
680 }
681
682 /* Clear PHY_BLUETOOTH to allow RX_CLEAR line debug */
683 if (ah->ah_phy_revision >= AR5K_SREV_PHY_5212B)
684 ath5k_hw_reg_write(ah, 0, AR5K_PHY_BLUETOOTH);
685
686 /* Enable DCU double buffering */
687 if (ah->ah_phy_revision > AR5K_SREV_PHY_5212B)
688 AR5K_REG_DISABLE_BITS(ah, AR5K_TXCFG,
689 AR5K_TXCFG_DCU_DBL_BUF_DIS);
690
691 /* Set DAC/ADC delays */
692 if (ah->ah_version == AR5K_AR5212) {
693 u32 scal;
Nick Kossifidis1889ba02009-04-30 15:55:46 -0400694 struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
Nick Kossifidise8f055f2009-02-09 06:12:58 +0200695 if (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4))
696 scal = AR5K_PHY_SCAL_32MHZ_2417;
Nick Kossifidis1889ba02009-04-30 15:55:46 -0400697 else if (ee->ee_is_hb63)
Nick Kossifidise8f055f2009-02-09 06:12:58 +0200698 scal = AR5K_PHY_SCAL_32MHZ_HB63;
699 else
700 scal = AR5K_PHY_SCAL_32MHZ;
701 ath5k_hw_reg_write(ah, scal, AR5K_PHY_SCAL);
702 }
703
704 /* Set fast ADC */
705 if ((ah->ah_radio == AR5K_RF5413) ||
706 (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4))) {
707 u32 fast_adc = true;
708
709 if (channel->center_freq == 2462 ||
710 channel->center_freq == 2467)
711 fast_adc = 0;
712
713 /* Only update if needed */
714 if (ath5k_hw_reg_read(ah, AR5K_PHY_FAST_ADC) != fast_adc)
715 ath5k_hw_reg_write(ah, fast_adc,
716 AR5K_PHY_FAST_ADC);
717 }
718
719 /* Fix for first revision of the RF5112 RF chipset */
720 if (ah->ah_radio == AR5K_RF5112 &&
721 ah->ah_radio_5ghz_revision <
722 AR5K_SREV_RAD_5112A) {
723 u32 data;
724 ath5k_hw_reg_write(ah, AR5K_PHY_CCKTXCTL_WORLD,
725 AR5K_PHY_CCKTXCTL);
726 if (channel->hw_value & CHANNEL_5GHZ)
727 data = 0xffb81020;
728 else
729 data = 0xffb80d20;
730 ath5k_hw_reg_write(ah, data, AR5K_PHY_FRAME_CTL);
731 }
732
Nick Kossifidis9320b5c42010-11-23 20:36:45 +0200733 if ((ah->ah_radio == AR5K_RF5112) &&
734 (ah->ah_mac_srev < AR5K_SREV_AR5211)) {
Nick Kossifidise8f055f2009-02-09 06:12:58 +0200735 u32 usec_reg;
736 /* 5311 has different tx/rx latency masks
737 * from 5211, since we deal 5311 the same
738 * as 5211 when setting initvals, shift
739 * values here to their proper locations */
740 usec_reg = ath5k_hw_reg_read(ah, AR5K_USEC_5211);
741 ath5k_hw_reg_write(ah, usec_reg & (AR5K_USEC_1 |
742 AR5K_USEC_32 |
743 AR5K_USEC_TX_LATENCY_5211 |
744 AR5K_REG_SM(29,
745 AR5K_USEC_RX_LATENCY_5210)),
746 AR5K_USEC_5211);
747 /* Clear QCU/DCU clock gating register */
748 ath5k_hw_reg_write(ah, 0, AR5K_QCUDCU_CLKGT);
749 /* Set DAC/ADC delays */
750 ath5k_hw_reg_write(ah, 0x08, AR5K_PHY_SCAL);
751 /* Enable PCU FIFO corruption ECO */
752 AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW_5211,
753 AR5K_DIAG_SW_ECO_ENABLE);
754 }
755}
756
757static void ath5k_hw_commit_eeprom_settings(struct ath5k_hw *ah,
Bruno Randolf0ca74022010-06-07 13:11:30 +0900758 struct ieee80211_channel *channel, u8 ee_mode)
Nick Kossifidise8f055f2009-02-09 06:12:58 +0200759{
760 struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
Nick Kossifidis8f655dd2009-03-15 22:20:35 +0200761 s16 cck_ofdm_pwr_delta;
Nick Kossifidise8f055f2009-02-09 06:12:58 +0200762
Nick Kossifidis9320b5c42010-11-23 20:36:45 +0200763 /* TODO: Add support for AR5210 EEPROM */
764 if (ah->ah_version == AR5K_AR5210)
765 return;
766
Nick Kossifidis8f655dd2009-03-15 22:20:35 +0200767 /* Adjust power delta for channel 14 */
768 if (channel->center_freq == 2484)
769 cck_ofdm_pwr_delta =
770 ((ee->ee_cck_ofdm_power_delta -
771 ee->ee_scaled_cck_delta) * 2) / 10;
772 else
773 cck_ofdm_pwr_delta =
774 (ee->ee_cck_ofdm_power_delta * 2) / 10;
775
776 /* Set CCK to OFDM power delta on tx power
777 * adjustment register */
Nick Kossifidise8f055f2009-02-09 06:12:58 +0200778 if (ah->ah_phy_revision >= AR5K_SREV_PHY_5212A) {
Nick Kossifidise8f055f2009-02-09 06:12:58 +0200779 if (channel->hw_value == CHANNEL_G)
780 ath5k_hw_reg_write(ah,
Nick Kossifidis8f655dd2009-03-15 22:20:35 +0200781 AR5K_REG_SM((ee->ee_cck_ofdm_gain_delta * -1),
Nick Kossifidise8f055f2009-02-09 06:12:58 +0200782 AR5K_PHY_TX_PWR_ADJ_CCK_GAIN_DELTA) |
783 AR5K_REG_SM((cck_ofdm_pwr_delta * -1),
784 AR5K_PHY_TX_PWR_ADJ_CCK_PCDAC_INDEX),
785 AR5K_PHY_TX_PWR_ADJ);
786 else
787 ath5k_hw_reg_write(ah, 0, AR5K_PHY_TX_PWR_ADJ);
Nick Kossifidis8f655dd2009-03-15 22:20:35 +0200788 } else {
789 /* For older revs we scale power on sw during tx power
790 * setup */
791 ah->ah_txpower.txp_cck_ofdm_pwr_delta = cck_ofdm_pwr_delta;
792 ah->ah_txpower.txp_cck_ofdm_gainf_delta =
793 ee->ee_cck_ofdm_gain_delta;
Nick Kossifidise8f055f2009-02-09 06:12:58 +0200794 }
795
Bruno Randolf0ca74022010-06-07 13:11:30 +0900796 /* XXX: necessary here? is called from ath5k_hw_set_antenna_mode()
797 * too */
798 ath5k_hw_set_antenna_switch(ah, ee_mode);
Nick Kossifidise8f055f2009-02-09 06:12:58 +0200799
800 /* Noise floor threshold */
801 ath5k_hw_reg_write(ah,
802 AR5K_PHY_NF_SVAL(ee->ee_noise_floor_thr[ee_mode]),
803 AR5K_PHY_NFTHRES);
804
805 if ((channel->hw_value & CHANNEL_TURBO) &&
806 (ah->ah_ee_version >= AR5K_EEPROM_VERSION_5_0)) {
807 /* Switch settling time (Turbo) */
808 AR5K_REG_WRITE_BITS(ah, AR5K_PHY_SETTLING,
809 AR5K_PHY_SETTLING_SWITCH,
810 ee->ee_switch_settling_turbo[ee_mode]);
811
812 /* Tx/Rx attenuation (Turbo) */
813 AR5K_REG_WRITE_BITS(ah, AR5K_PHY_GAIN,
814 AR5K_PHY_GAIN_TXRX_ATTEN,
815 ee->ee_atn_tx_rx_turbo[ee_mode]);
816
817 /* ADC/PGA desired size (Turbo) */
818 AR5K_REG_WRITE_BITS(ah, AR5K_PHY_DESIRED_SIZE,
819 AR5K_PHY_DESIRED_SIZE_ADC,
820 ee->ee_adc_desired_size_turbo[ee_mode]);
821
822 AR5K_REG_WRITE_BITS(ah, AR5K_PHY_DESIRED_SIZE,
823 AR5K_PHY_DESIRED_SIZE_PGA,
824 ee->ee_pga_desired_size_turbo[ee_mode]);
825
826 /* Tx/Rx margin (Turbo) */
827 AR5K_REG_WRITE_BITS(ah, AR5K_PHY_GAIN_2GHZ,
828 AR5K_PHY_GAIN_2GHZ_MARGIN_TXRX,
829 ee->ee_margin_tx_rx_turbo[ee_mode]);
830
831 } else {
832 /* Switch settling time */
833 AR5K_REG_WRITE_BITS(ah, AR5K_PHY_SETTLING,
834 AR5K_PHY_SETTLING_SWITCH,
835 ee->ee_switch_settling[ee_mode]);
836
837 /* Tx/Rx attenuation */
838 AR5K_REG_WRITE_BITS(ah, AR5K_PHY_GAIN,
839 AR5K_PHY_GAIN_TXRX_ATTEN,
840 ee->ee_atn_tx_rx[ee_mode]);
841
842 /* ADC/PGA desired size */
843 AR5K_REG_WRITE_BITS(ah, AR5K_PHY_DESIRED_SIZE,
844 AR5K_PHY_DESIRED_SIZE_ADC,
845 ee->ee_adc_desired_size[ee_mode]);
846
847 AR5K_REG_WRITE_BITS(ah, AR5K_PHY_DESIRED_SIZE,
848 AR5K_PHY_DESIRED_SIZE_PGA,
849 ee->ee_pga_desired_size[ee_mode]);
850
851 /* Tx/Rx margin */
852 if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1)
853 AR5K_REG_WRITE_BITS(ah, AR5K_PHY_GAIN_2GHZ,
854 AR5K_PHY_GAIN_2GHZ_MARGIN_TXRX,
855 ee->ee_margin_tx_rx[ee_mode]);
856 }
857
858 /* XPA delays */
859 ath5k_hw_reg_write(ah,
860 (ee->ee_tx_end2xpa_disable[ee_mode] << 24) |
861 (ee->ee_tx_end2xpa_disable[ee_mode] << 16) |
862 (ee->ee_tx_frm2xpa_enable[ee_mode] << 8) |
863 (ee->ee_tx_frm2xpa_enable[ee_mode]), AR5K_PHY_RF_CTL4);
864
865 /* XLNA delay */
866 AR5K_REG_WRITE_BITS(ah, AR5K_PHY_RF_CTL3,
867 AR5K_PHY_RF_CTL3_TXE2XLNA_ON,
868 ee->ee_tx_end2xlna_enable[ee_mode]);
869
870 /* Thresh64 (ANI) */
871 AR5K_REG_WRITE_BITS(ah, AR5K_PHY_NF,
872 AR5K_PHY_NF_THRESH62,
873 ee->ee_thr_62[ee_mode]);
874
Nick Kossifidise8f055f2009-02-09 06:12:58 +0200875 /* False detect backoff for channels
876 * that have spur noise. Write the new
877 * cyclic power RSSI threshold. */
878 if (ath5k_hw_chan_has_spur_noise(ah, channel))
879 AR5K_REG_WRITE_BITS(ah, AR5K_PHY_OFDM_SELFCORR,
880 AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1,
881 AR5K_INIT_CYCRSSI_THR1 +
882 ee->ee_false_detect[ee_mode]);
883 else
884 AR5K_REG_WRITE_BITS(ah, AR5K_PHY_OFDM_SELFCORR,
885 AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1,
886 AR5K_INIT_CYCRSSI_THR1);
887
Bruno Randolf5f13bfa2010-03-09 16:56:10 +0900888 /* I/Q correction (set enable bit last to match HAL sources) */
889 /* TODO: Per channel i/q infos ? */
890 if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) {
891 AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CORR_Q_I_COFF,
892 ee->ee_i_cal[ee_mode]);
893 AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CORR_Q_Q_COFF,
894 ee->ee_q_cal[ee_mode]);
895 AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CORR_ENABLE);
896 }
Nick Kossifidise8f055f2009-02-09 06:12:58 +0200897
898 /* Heavy clipping -disable for now */
899 if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_5_1)
900 ath5k_hw_reg_write(ah, 0, AR5K_PHY_HEAVY_CLIP_ENABLE);
Nick Kossifidise8f055f2009-02-09 06:12:58 +0200901}
902
Nick Kossifidis9320b5c42010-11-23 20:36:45 +0200903
904/*********************\
905* Main reset function *
906\*********************/
907
Johannes Berg05c914f2008-09-11 00:01:58 +0200908int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300909 struct ieee80211_channel *channel, bool change_channel)
910{
Luis R. Rodriguez954fece2009-09-10 10:51:33 -0700911 struct ath_common *common = ath5k_hw_common(ah);
Bruno Randolf20fbed22010-06-07 13:11:35 +0900912 u32 s_seq[10], s_led[3], staid1_flags, tsf_up, tsf_lo;
Bruno Randolf0ca74022010-06-07 13:11:30 +0900913 u8 mode, freq, ee_mode;
Nick Kossifidise8f055f2009-02-09 06:12:58 +0200914 int i, ret;
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300915
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300916 ee_mode = 0;
Nick Kossifidise8f055f2009-02-09 06:12:58 +0200917 staid1_flags = 0;
918 tsf_up = 0;
919 tsf_lo = 0;
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300920 freq = 0;
921 mode = 0;
922
Nick Kossifidisc2975602010-11-23 21:00:37 +0200923
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300924 /*
Nick Kossifidise088f232010-11-23 20:43:18 +0200925 * Stop PCU
926 */
927 ath5k_hw_stop_rx_pcu(ah);
928
929 /*
Nick Kossifidisd41174f2010-11-23 20:41:15 +0200930 * Stop DMA
931 *
932 * Note: If DMA didn't stop continue
933 * since only a reset will fix it.
934 */
935 ath5k_hw_dma_stop(ah);
936
937 /*
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300938 * Save some registers before a reset
939 */
940 /*DCU/Antenna selection not available on 5210*/
941 if (ah->ah_version != AR5K_AR5210) {
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300942
943 switch (channel->hw_value & CHANNEL_MODES) {
944 case CHANNEL_A:
945 mode = AR5K_MODE_11A;
946 freq = AR5K_INI_RFGAIN_5GHZ;
947 ee_mode = AR5K_EEPROM_MODE_11A;
948 break;
949 case CHANNEL_G:
950 mode = AR5K_MODE_11G;
951 freq = AR5K_INI_RFGAIN_2GHZ;
952 ee_mode = AR5K_EEPROM_MODE_11G;
953 break;
954 case CHANNEL_B:
955 mode = AR5K_MODE_11B;
956 freq = AR5K_INI_RFGAIN_2GHZ;
957 ee_mode = AR5K_EEPROM_MODE_11B;
958 break;
959 case CHANNEL_T:
960 mode = AR5K_MODE_11A_TURBO;
961 freq = AR5K_INI_RFGAIN_5GHZ;
962 ee_mode = AR5K_EEPROM_MODE_11A;
963 break;
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300964 case CHANNEL_TG:
Nick Kossifidise8f055f2009-02-09 06:12:58 +0200965 if (ah->ah_version == AR5K_AR5211) {
966 ATH5K_ERR(ah->ah_sc,
967 "TurboG mode not available on 5211");
968 return -EINVAL;
969 }
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300970 mode = AR5K_MODE_11G_TURBO;
971 freq = AR5K_INI_RFGAIN_2GHZ;
972 ee_mode = AR5K_EEPROM_MODE_11G;
973 break;
974 case CHANNEL_XR:
975 if (ah->ah_version == AR5K_AR5211) {
976 ATH5K_ERR(ah->ah_sc,
977 "XR mode not available on 5211");
978 return -EINVAL;
979 }
980 mode = AR5K_MODE_XR;
981 freq = AR5K_INI_RFGAIN_5GHZ;
982 ee_mode = AR5K_EEPROM_MODE_11A;
983 break;
984 default:
985 ATH5K_ERR(ah->ah_sc,
986 "invalid channel: %d\n", channel->center_freq);
987 return -EINVAL;
988 }
989
Nick Kossifidise8f055f2009-02-09 06:12:58 +0200990 if (change_channel) {
991 /*
992 * Save frame sequence count
993 * For revs. after Oahu, only save
994 * seq num for DCU 0 (Global seq num)
995 */
996 if (ah->ah_mac_srev < AR5K_SREV_AR5211) {
997
998 for (i = 0; i < 10; i++)
999 s_seq[i] = ath5k_hw_reg_read(ah,
1000 AR5K_QUEUE_DCU_SEQNUM(i));
1001
1002 } else {
1003 s_seq[0] = ath5k_hw_reg_read(ah,
1004 AR5K_QUEUE_DCU_SEQNUM(0));
1005 }
1006
Bob Copelanda180a132010-08-15 13:03:12 -04001007 /* TSF accelerates on AR5211 during reset
Nick Kossifidise8f055f2009-02-09 06:12:58 +02001008 * As a workaround save it here and restore
1009 * it later so that it's back in time after
1010 * reset. This way it'll get re-synced on the
1011 * next beacon without breaking ad-hoc.
1012 *
1013 * On AR5212 TSF is almost preserved across a
1014 * reset so it stays back in time anyway and
1015 * we don't have to save/restore it.
1016 *
1017 * XXX: Since this breaks power saving we have
1018 * to disable power saving until we receive the
1019 * next beacon, so we can resync beacon timers */
1020 if (ah->ah_version == AR5K_AR5211) {
1021 tsf_up = ath5k_hw_reg_read(ah, AR5K_TSF_U32);
1022 tsf_lo = ath5k_hw_reg_read(ah, AR5K_TSF_L32);
1023 }
1024 }
1025
Nick Kossifidise8f055f2009-02-09 06:12:58 +02001026 if (ah->ah_version == AR5K_AR5212) {
1027 /* Restore normal 32/40MHz clock operation
1028 * to avoid register access delay on certain
1029 * PHY registers */
1030 ath5k_hw_set_sleep_clock(ah, false);
1031
1032 /* Since we are going to write rf buffer
1033 * check if we have any pending gain_F
1034 * optimization settings */
1035 if (change_channel && ah->ah_rf_banks != NULL)
1036 ath5k_hw_gainf_calibrate(ah);
1037 }
Nick Kossifidisc6e387a2008-08-29 22:45:39 +03001038 }
1039
Nick Kossifidise8f055f2009-02-09 06:12:58 +02001040 /*GPIOs*/
1041 s_led[0] = ath5k_hw_reg_read(ah, AR5K_PCICFG) &
1042 AR5K_PCICFG_LEDSTATE;
1043 s_led[1] = ath5k_hw_reg_read(ah, AR5K_GPIOCR);
1044 s_led[2] = ath5k_hw_reg_read(ah, AR5K_GPIODO);
Nick Kossifidisa406c132009-02-09 06:08:51 +02001045
Nick Kossifidise8f055f2009-02-09 06:12:58 +02001046 /* AR5K_STA_ID1 flags, only preserve antenna
1047 * settings and ack/cts rate mode */
1048 staid1_flags = ath5k_hw_reg_read(ah, AR5K_STA_ID1) &
1049 (AR5K_STA_ID1_DEFAULT_ANTENNA |
1050 AR5K_STA_ID1_DESC_ANTENNA |
1051 AR5K_STA_ID1_RTS_DEF_ANTENNA |
1052 AR5K_STA_ID1_ACKCTS_6MB |
1053 AR5K_STA_ID1_BASE_RATE_11B |
1054 AR5K_STA_ID1_SELFGEN_DEF_ANT);
1055
1056 /* Wakeup the device */
1057 ret = ath5k_hw_nic_wakeup(ah, channel->hw_value, false);
1058 if (ret)
1059 return ret;
1060
Nick Kossifidise8f055f2009-02-09 06:12:58 +02001061 /* PHY access enable */
1062 if (ah->ah_mac_srev >= AR5K_SREV_AR5211)
1063 ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0));
1064 else
1065 ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ | 0x40,
1066 AR5K_PHY(0));
1067
1068 /* Write initial settings */
Nick Kossifidisc6e387a2008-08-29 22:45:39 +03001069 ret = ath5k_hw_write_initvals(ah, mode, change_channel);
1070 if (ret)
1071 return ret;
1072
Nick Kossifidisc2975602010-11-23 21:00:37 +02001073 /* Initialize core clock settings */
1074 ath5k_hw_init_core_clock(ah);
1075
Nick Kossifidisc6e387a2008-08-29 22:45:39 +03001076 /*
Nick Kossifidis9320b5c42010-11-23 20:36:45 +02001077 * Tweak initval settings for revised
1078 * chipsets and add some more config
1079 * bits
Nick Kossifidisc6e387a2008-08-29 22:45:39 +03001080 */
Nick Kossifidis9320b5c42010-11-23 20:36:45 +02001081 ath5k_hw_tweak_initval_settings(ah, channel);
Nick Kossifidise8f055f2009-02-09 06:12:58 +02001082
Nick Kossifidis9320b5c42010-11-23 20:36:45 +02001083 /* Commit values from EEPROM */
1084 ath5k_hw_commit_eeprom_settings(ah, channel, ee_mode);
Nick Kossifidisc6e387a2008-08-29 22:45:39 +03001085
Nick Kossifidisc6e387a2008-08-29 22:45:39 +03001086
1087 /*
1088 * Restore saved values
1089 */
Nick Kossifidise8f055f2009-02-09 06:12:58 +02001090
Nick Kossifidisc6e387a2008-08-29 22:45:39 +03001091 /*DCU/Antenna selection not available on 5210*/
1092 if (ah->ah_version != AR5K_AR5210) {
Nick Kossifidise8f055f2009-02-09 06:12:58 +02001093
1094 if (change_channel) {
1095 if (ah->ah_mac_srev < AR5K_SREV_AR5211) {
1096 for (i = 0; i < 10; i++)
1097 ath5k_hw_reg_write(ah, s_seq[i],
1098 AR5K_QUEUE_DCU_SEQNUM(i));
1099 } else {
1100 ath5k_hw_reg_write(ah, s_seq[0],
1101 AR5K_QUEUE_DCU_SEQNUM(0));
1102 }
1103
1104
1105 if (ah->ah_version == AR5K_AR5211) {
1106 ath5k_hw_reg_write(ah, tsf_up, AR5K_TSF_U32);
1107 ath5k_hw_reg_write(ah, tsf_lo, AR5K_TSF_L32);
1108 }
1109 }
Nick Kossifidisc6e387a2008-08-29 22:45:39 +03001110 }
Nick Kossifidise8f055f2009-02-09 06:12:58 +02001111
1112 /* Ledstate */
Nick Kossifidisc6e387a2008-08-29 22:45:39 +03001113 AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, s_led[0]);
Nick Kossifidise8f055f2009-02-09 06:12:58 +02001114
1115 /* Gpio settings */
Nick Kossifidisc6e387a2008-08-29 22:45:39 +03001116 ath5k_hw_reg_write(ah, s_led[1], AR5K_GPIOCR);
1117 ath5k_hw_reg_write(ah, s_led[2], AR5K_GPIODO);
1118
Nick Kossifidise8f055f2009-02-09 06:12:58 +02001119 /* Restore sta_id flags and preserve our mac address*/
Luis R. Rodriguez954fece2009-09-10 10:51:33 -07001120 ath5k_hw_reg_write(ah,
1121 get_unaligned_le32(common->macaddr),
1122 AR5K_STA_ID0);
1123 ath5k_hw_reg_write(ah,
Luis R. Rodriguez91b9eb82009-10-06 20:44:30 -04001124 staid1_flags | get_unaligned_le16(common->macaddr + 4),
Luis R. Rodriguez954fece2009-09-10 10:51:33 -07001125 AR5K_STA_ID1);
Nick Kossifidise8f055f2009-02-09 06:12:58 +02001126
1127
Nick Kossifidisc6e387a2008-08-29 22:45:39 +03001128 /*
Nick Kossifidis9320b5c42010-11-23 20:36:45 +02001129 * Initialize PCU
Nick Kossifidisc6e387a2008-08-29 22:45:39 +03001130 */
Nick Kossifidis9320b5c42010-11-23 20:36:45 +02001131 ath5k_hw_pcu_init(ah, op_mode, mode);
Nick Kossifidise8f055f2009-02-09 06:12:58 +02001132
Nick Kossifidise8f055f2009-02-09 06:12:58 +02001133 /*
Nick Kossifidis9320b5c42010-11-23 20:36:45 +02001134 * Initialize PHY
Nick Kossifidise8f055f2009-02-09 06:12:58 +02001135 */
Nick Kossifidis9320b5c42010-11-23 20:36:45 +02001136 ret = ath5k_hw_phy_init(ah, channel, mode, ee_mode, freq);
1137 if (ret) {
1138 ATH5K_ERR(ah->ah_sc,
1139 "failed to initialize PHY (%i) !\n", ret);
Nick Kossifidise8f055f2009-02-09 06:12:58 +02001140 return ret;
Nick Kossifidisc6e387a2008-08-29 22:45:39 +03001141 }
1142
1143 /*
Nick Kossifidise8f055f2009-02-09 06:12:58 +02001144 * Configure QCUs/DCUs
1145 */
Nick Kossifidis9320b5c42010-11-23 20:36:45 +02001146 ret = ath5k_hw_init_queues(ah);
1147 if (ret)
1148 return ret;
Nick Kossifidisc6e387a2008-08-29 22:45:39 +03001149
Nick Kossifidise8f055f2009-02-09 06:12:58 +02001150
1151 /*
Nick Kossifidis9320b5c42010-11-23 20:36:45 +02001152 * Initialize DMA/Interrupts
Nick Kossifidise8f055f2009-02-09 06:12:58 +02001153 */
Nick Kossifidis9320b5c42010-11-23 20:36:45 +02001154 ath5k_hw_dma_init(ah);
Nick Kossifidise8f055f2009-02-09 06:12:58 +02001155
Nick Kossifidisc6e387a2008-08-29 22:45:39 +03001156
Nick Kossifidise8f055f2009-02-09 06:12:58 +02001157 /* Enable 32KHz clock function for AR5212+ chips
1158 * Set clocks to 32KHz operation and use an
1159 * external 32KHz crystal when sleeping if one
1160 * exists */
Bob Copeland5d6ce622010-01-20 23:51:03 -05001161 if (ah->ah_version == AR5K_AR5212 &&
Bruno Randolfccfe5552010-03-09 16:55:38 +09001162 op_mode != NL80211_IFTYPE_AP)
Bob Copeland5d6ce622010-01-20 23:51:03 -05001163 ath5k_hw_set_sleep_clock(ah, true);
Nick Kossifidisc6e387a2008-08-29 22:45:39 +03001164
1165 /*
Bruno Randolfa3b980f2010-03-09 16:55:33 +09001166 * Disable beacons and reset the TSF
Nick Kossifidisc6e387a2008-08-29 22:45:39 +03001167 */
Bruno Randolfa3b980f2010-03-09 16:55:33 +09001168 AR5K_REG_DISABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_ENABLE);
1169 ath5k_hw_reset_tsf(ah);
Nick Kossifidisc6e387a2008-08-29 22:45:39 +03001170 return 0;
1171}