1 /*
2 * Copyright (c) 2008-2011 Atheros Communications Inc.
3 *
4 * Modified for iPXE by Scott K Logan <logans@cottsay.net> July 2011
5 * Original from Linux kernel 3.0.1
6 *
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20 #include "hw.h"
21 #include "ar9003_mac.h"
22 #include "ar9003_2p2_initvals.h"
23 #include "ar9485_initvals.h"
24 #include "ar9340_initvals.h"
25
26 /* General hardware code for the AR9003 hadware family */
27
28 /*
29 * The AR9003 family uses a new INI format (pre, core, post
30 * arrays per subsystem). This provides support for the
31 * AR9003 2.2 chipsets.
32 */
ar9003_hw_init_mode_regs(struct ath_hw * ah)33 static void ar9003_hw_init_mode_regs(struct ath_hw *ah)
34 {
35 if (AR_SREV_9340(ah)) {
36 /* mac */
37 INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0);
38 INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE],
39 ar9340_1p0_mac_core,
40 ARRAY_SIZE(ar9340_1p0_mac_core), 2);
41 INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST],
42 ar9340_1p0_mac_postamble,
43 ARRAY_SIZE(ar9340_1p0_mac_postamble), 5);
44
45 /* bb */
46 INIT_INI_ARRAY(&ah->iniBB[ATH_INI_PRE], NULL, 0, 0);
47 INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE],
48 ar9340_1p0_baseband_core,
49 ARRAY_SIZE(ar9340_1p0_baseband_core), 2);
50 INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST],
51 ar9340_1p0_baseband_postamble,
52 ARRAY_SIZE(ar9340_1p0_baseband_postamble), 5);
53
54 /* radio */
55 INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_PRE], NULL, 0, 0);
56 INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE],
57 ar9340_1p0_radio_core,
58 ARRAY_SIZE(ar9340_1p0_radio_core), 2);
59 INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST],
60 ar9340_1p0_radio_postamble,
61 ARRAY_SIZE(ar9340_1p0_radio_postamble), 5);
62
63 /* soc */
64 INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE],
65 ar9340_1p0_soc_preamble,
66 ARRAY_SIZE(ar9340_1p0_soc_preamble), 2);
67 INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_CORE], NULL, 0, 0);
68 INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST],
69 ar9340_1p0_soc_postamble,
70 ARRAY_SIZE(ar9340_1p0_soc_postamble), 5);
71
72 /* rx/tx gain */
73 INIT_INI_ARRAY(&ah->iniModesRxGain,
74 ar9340Common_wo_xlna_rx_gain_table_1p0,
75 ARRAY_SIZE(ar9340Common_wo_xlna_rx_gain_table_1p0),
76 5);
77 INIT_INI_ARRAY(&ah->iniModesTxGain,
78 ar9340Modes_high_ob_db_tx_gain_table_1p0,
79 ARRAY_SIZE(ar9340Modes_high_ob_db_tx_gain_table_1p0),
80 5);
81
82 INIT_INI_ARRAY(&ah->iniModesAdditional,
83 ar9340Modes_fast_clock_1p0,
84 ARRAY_SIZE(ar9340Modes_fast_clock_1p0),
85 3);
86
87 INIT_INI_ARRAY(&ah->iniModesAdditional_40M,
88 ar9340_1p0_radio_core_40M,
89 ARRAY_SIZE(ar9340_1p0_radio_core_40M),
90 2);
91 } else if (AR_SREV_9485_11(ah)) {
92 /* mac */
93 INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0);
94 INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE],
95 ar9485_1_1_mac_core,
96 ARRAY_SIZE(ar9485_1_1_mac_core), 2);
97 INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST],
98 ar9485_1_1_mac_postamble,
99 ARRAY_SIZE(ar9485_1_1_mac_postamble), 5);
100
101 /* bb */
102 INIT_INI_ARRAY(&ah->iniBB[ATH_INI_PRE], ar9485_1_1,
103 ARRAY_SIZE(ar9485_1_1), 2);
104 INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE],
105 ar9485_1_1_baseband_core,
106 ARRAY_SIZE(ar9485_1_1_baseband_core), 2);
107 INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST],
108 ar9485_1_1_baseband_postamble,
109 ARRAY_SIZE(ar9485_1_1_baseband_postamble), 5);
110
111 /* radio */
112 INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_PRE], NULL, 0, 0);
113 INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE],
114 ar9485_1_1_radio_core,
115 ARRAY_SIZE(ar9485_1_1_radio_core), 2);
116 INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST],
117 ar9485_1_1_radio_postamble,
118 ARRAY_SIZE(ar9485_1_1_radio_postamble), 2);
119
120 /* soc */
121 INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE],
122 ar9485_1_1_soc_preamble,
123 ARRAY_SIZE(ar9485_1_1_soc_preamble), 2);
124 INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_CORE], NULL, 0, 0);
125 INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST], NULL, 0, 0);
126
127 /* rx/tx gain */
128 INIT_INI_ARRAY(&ah->iniModesRxGain,
129 ar9485Common_wo_xlna_rx_gain_1_1,
130 ARRAY_SIZE(ar9485Common_wo_xlna_rx_gain_1_1), 2);
131 INIT_INI_ARRAY(&ah->iniModesTxGain,
132 ar9485_modes_lowest_ob_db_tx_gain_1_1,
133 ARRAY_SIZE(ar9485_modes_lowest_ob_db_tx_gain_1_1),
134 5);
135
136 /* Load PCIE SERDES settings from INI */
137
138 /* Awake Setting */
139
140 INIT_INI_ARRAY(&ah->iniPcieSerdes,
141 ar9485_1_1_pcie_phy_clkreq_disable_L1,
142 ARRAY_SIZE(ar9485_1_1_pcie_phy_clkreq_disable_L1),
143 2);
144
145 /* Sleep Setting */
146
147 INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower,
148 ar9485_1_1_pcie_phy_clkreq_disable_L1,
149 ARRAY_SIZE(ar9485_1_1_pcie_phy_clkreq_disable_L1),
150 2);
151 } else {
152 /* mac */
153 INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0);
154 INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE],
155 ar9300_2p2_mac_core,
156 ARRAY_SIZE(ar9300_2p2_mac_core), 2);
157 INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST],
158 ar9300_2p2_mac_postamble,
159 ARRAY_SIZE(ar9300_2p2_mac_postamble), 5);
160
161 /* bb */
162 INIT_INI_ARRAY(&ah->iniBB[ATH_INI_PRE], NULL, 0, 0);
163 INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE],
164 ar9300_2p2_baseband_core,
165 ARRAY_SIZE(ar9300_2p2_baseband_core), 2);
166 INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST],
167 ar9300_2p2_baseband_postamble,
168 ARRAY_SIZE(ar9300_2p2_baseband_postamble), 5);
169
170 /* radio */
171 INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_PRE], NULL, 0, 0);
172 INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE],
173 ar9300_2p2_radio_core,
174 ARRAY_SIZE(ar9300_2p2_radio_core), 2);
175 INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST],
176 ar9300_2p2_radio_postamble,
177 ARRAY_SIZE(ar9300_2p2_radio_postamble), 5);
178
179 /* soc */
180 INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE],
181 ar9300_2p2_soc_preamble,
182 ARRAY_SIZE(ar9300_2p2_soc_preamble), 2);
183 INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_CORE], NULL, 0, 0);
184 INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST],
185 ar9300_2p2_soc_postamble,
186 ARRAY_SIZE(ar9300_2p2_soc_postamble), 5);
187
188 /* rx/tx gain */
189 INIT_INI_ARRAY(&ah->iniModesRxGain,
190 ar9300Common_rx_gain_table_2p2,
191 ARRAY_SIZE(ar9300Common_rx_gain_table_2p2), 2);
192 INIT_INI_ARRAY(&ah->iniModesTxGain,
193 ar9300Modes_lowest_ob_db_tx_gain_table_2p2,
194 ARRAY_SIZE(ar9300Modes_lowest_ob_db_tx_gain_table_2p2),
195 5);
196
197 /* Load PCIE SERDES settings from INI */
198
199 /* Awake Setting */
200
201 INIT_INI_ARRAY(&ah->iniPcieSerdes,
202 ar9300PciePhy_pll_on_clkreq_disable_L1_2p2,
203 ARRAY_SIZE(ar9300PciePhy_pll_on_clkreq_disable_L1_2p2),
204 2);
205
206 /* Sleep Setting */
207
208 INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower,
209 ar9300PciePhy_pll_on_clkreq_disable_L1_2p2,
210 ARRAY_SIZE(ar9300PciePhy_pll_on_clkreq_disable_L1_2p2),
211 2);
212
213 /* Fast clock modal settings */
214 INIT_INI_ARRAY(&ah->iniModesAdditional,
215 ar9300Modes_fast_clock_2p2,
216 ARRAY_SIZE(ar9300Modes_fast_clock_2p2),
217 3);
218 }
219 }
220
ar9003_tx_gain_table_apply(struct ath_hw * ah)221 static void ar9003_tx_gain_table_apply(struct ath_hw *ah)
222 {
223 switch (ar9003_hw_get_tx_gain_idx(ah)) {
224 case 0:
225 default:
226 if (AR_SREV_9340(ah))
227 INIT_INI_ARRAY(&ah->iniModesTxGain,
228 ar9340Modes_lowest_ob_db_tx_gain_table_1p0,
229 ARRAY_SIZE(ar9340Modes_lowest_ob_db_tx_gain_table_1p0),
230 5);
231 else if (AR_SREV_9485_11(ah))
232 INIT_INI_ARRAY(&ah->iniModesTxGain,
233 ar9485_modes_lowest_ob_db_tx_gain_1_1,
234 ARRAY_SIZE(ar9485_modes_lowest_ob_db_tx_gain_1_1),
235 5);
236 else
237 INIT_INI_ARRAY(&ah->iniModesTxGain,
238 ar9300Modes_lowest_ob_db_tx_gain_table_2p2,
239 ARRAY_SIZE(ar9300Modes_lowest_ob_db_tx_gain_table_2p2),
240 5);
241 break;
242 case 1:
243 if (AR_SREV_9340(ah))
244 INIT_INI_ARRAY(&ah->iniModesTxGain,
245 ar9340Modes_lowest_ob_db_tx_gain_table_1p0,
246 ARRAY_SIZE(ar9340Modes_lowest_ob_db_tx_gain_table_1p0),
247 5);
248 else if (AR_SREV_9485_11(ah))
249 INIT_INI_ARRAY(&ah->iniModesTxGain,
250 ar9485Modes_high_ob_db_tx_gain_1_1,
251 ARRAY_SIZE(ar9485Modes_high_ob_db_tx_gain_1_1),
252 5);
253 else
254 INIT_INI_ARRAY(&ah->iniModesTxGain,
255 ar9300Modes_high_ob_db_tx_gain_table_2p2,
256 ARRAY_SIZE(ar9300Modes_high_ob_db_tx_gain_table_2p2),
257 5);
258 break;
259 case 2:
260 if (AR_SREV_9340(ah))
261 INIT_INI_ARRAY(&ah->iniModesTxGain,
262 ar9340Modes_lowest_ob_db_tx_gain_table_1p0,
263 ARRAY_SIZE(ar9340Modes_lowest_ob_db_tx_gain_table_1p0),
264 5);
265 else if (AR_SREV_9485_11(ah))
266 INIT_INI_ARRAY(&ah->iniModesTxGain,
267 ar9485Modes_low_ob_db_tx_gain_1_1,
268 ARRAY_SIZE(ar9485Modes_low_ob_db_tx_gain_1_1),
269 5);
270 else
271 INIT_INI_ARRAY(&ah->iniModesTxGain,
272 ar9300Modes_low_ob_db_tx_gain_table_2p2,
273 ARRAY_SIZE(ar9300Modes_low_ob_db_tx_gain_table_2p2),
274 5);
275 break;
276 case 3:
277 if (AR_SREV_9340(ah))
278 INIT_INI_ARRAY(&ah->iniModesTxGain,
279 ar9340Modes_lowest_ob_db_tx_gain_table_1p0,
280 ARRAY_SIZE(ar9340Modes_lowest_ob_db_tx_gain_table_1p0),
281 5);
282 else if (AR_SREV_9485_11(ah))
283 INIT_INI_ARRAY(&ah->iniModesTxGain,
284 ar9485Modes_high_power_tx_gain_1_1,
285 ARRAY_SIZE(ar9485Modes_high_power_tx_gain_1_1),
286 5);
287 else
288 INIT_INI_ARRAY(&ah->iniModesTxGain,
289 ar9300Modes_high_power_tx_gain_table_2p2,
290 ARRAY_SIZE(ar9300Modes_high_power_tx_gain_table_2p2),
291 5);
292 break;
293 }
294 }
295
ar9003_rx_gain_table_apply(struct ath_hw * ah)296 static void ar9003_rx_gain_table_apply(struct ath_hw *ah)
297 {
298 switch (ar9003_hw_get_rx_gain_idx(ah)) {
299 case 0:
300 default:
301 if (AR_SREV_9340(ah))
302 INIT_INI_ARRAY(&ah->iniModesRxGain,
303 ar9340Common_rx_gain_table_1p0,
304 ARRAY_SIZE(ar9340Common_rx_gain_table_1p0),
305 2);
306 else if (AR_SREV_9485_11(ah))
307 INIT_INI_ARRAY(&ah->iniModesRxGain,
308 ar9485Common_wo_xlna_rx_gain_1_1,
309 ARRAY_SIZE(ar9485Common_wo_xlna_rx_gain_1_1),
310 2);
311 else
312 INIT_INI_ARRAY(&ah->iniModesRxGain,
313 ar9300Common_rx_gain_table_2p2,
314 ARRAY_SIZE(ar9300Common_rx_gain_table_2p2),
315 2);
316 break;
317 case 1:
318 if (AR_SREV_9340(ah))
319 INIT_INI_ARRAY(&ah->iniModesRxGain,
320 ar9340Common_wo_xlna_rx_gain_table_1p0,
321 ARRAY_SIZE(ar9340Common_wo_xlna_rx_gain_table_1p0),
322 2);
323 else if (AR_SREV_9485_11(ah))
324 INIT_INI_ARRAY(&ah->iniModesRxGain,
325 ar9485Common_wo_xlna_rx_gain_1_1,
326 ARRAY_SIZE(ar9485Common_wo_xlna_rx_gain_1_1),
327 2);
328 else
329 INIT_INI_ARRAY(&ah->iniModesRxGain,
330 ar9300Common_wo_xlna_rx_gain_table_2p2,
331 ARRAY_SIZE(ar9300Common_wo_xlna_rx_gain_table_2p2),
332 2);
333 break;
334 }
335 }
336
337 /* set gain table pointers according to values read from the eeprom */
ar9003_hw_init_mode_gain_regs(struct ath_hw * ah)338 static void ar9003_hw_init_mode_gain_regs(struct ath_hw *ah)
339 {
340 ar9003_tx_gain_table_apply(ah);
341 ar9003_rx_gain_table_apply(ah);
342 }
343
344 /*
345 * Helper for ASPM support.
346 *
347 * Disable PLL when in L0s as well as receiver clock when in L1.
348 * This power saving option must be enabled through the SerDes.
349 *
350 * Programming the SerDes must go through the same 288 bit serial shift
351 * register as the other analog registers. Hence the 9 writes.
352 */
ar9003_hw_configpcipowersave(struct ath_hw * ah,int restore,int power_off)353 static void ar9003_hw_configpcipowersave(struct ath_hw *ah,
354 int restore,
355 int power_off)
356 {
357 if (ah->is_pciexpress != 1)
358 return;
359
360 /* Do not touch SerDes registers */
361 if (ah->config.pcie_powersave_enable == 2)
362 return;
363
364 /* Nothing to do on restore for 11N */
365 if (!restore) {
366 /* set bit 19 to allow forcing of pcie core into L1 state */
367 REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA);
368
369 /* Several PCIe massages to ensure proper behaviour */
370 if (ah->config.pcie_waen)
371 REG_WRITE(ah, AR_WA, ah->config.pcie_waen);
372 else
373 REG_WRITE(ah, AR_WA, ah->WARegVal);
374 }
375
376 /*
377 * Configire PCIE after Ini init. SERDES values now come from ini file
378 * This enables PCIe low power mode.
379 */
380 if (ah->config.pcieSerDesWrite) {
381 unsigned int i;
382 struct ar5416IniArray *array;
383
384 array = power_off ? &ah->iniPcieSerdes :
385 &ah->iniPcieSerdesLowPower;
386
387 for (i = 0; i < array->ia_rows; i++) {
388 REG_WRITE(ah,
389 INI_RA(array, i, 0),
390 INI_RA(array, i, 1));
391 }
392 }
393 }
394
395 /* Sets up the AR9003 hardware familiy callbacks */
ar9003_hw_attach_ops(struct ath_hw * ah)396 void ar9003_hw_attach_ops(struct ath_hw *ah)
397 {
398 struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
399 struct ath_hw_ops *ops = ath9k_hw_ops(ah);
400
401 priv_ops->init_mode_regs = ar9003_hw_init_mode_regs;
402 priv_ops->init_mode_gain_regs = ar9003_hw_init_mode_gain_regs;
403
404 ops->config_pci_powersave = ar9003_hw_configpcipowersave;
405
406 ar9003_hw_attach_phy_ops(ah);
407 ar9003_hw_attach_calib_ops(ah);
408 ar9003_hw_attach_mac_ops(ah);
409 }
410