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