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