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 
21 /* General hardware code for the AR9003 hadware family */
22 
23 static bool ar9003_hw_macversion_supported(u32 macversion)
24 {
25 	switch (macversion) {
26 	case AR_SREV_VERSION_9300:
27 		return true;
28 	default:
29 		break;
30 	}
31 	return false;
32 }
33 
34 /*
35  * The AR9003 family uses a new INI format (pre, core, post
36  * arrays per subsystem). This provides support for the
37  * AR9003 2.2 chipsets.
38  */
39 static void ar9003_hw_init_mode_regs(struct ath_hw *ah)
40 {
41 	/* mac */
42 	INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0);
43 	INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE],
44 		       ar9300_2p2_mac_core,
45 		       ARRAY_SIZE(ar9300_2p2_mac_core), 2);
46 	INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST],
47 		       ar9300_2p2_mac_postamble,
48 		       ARRAY_SIZE(ar9300_2p2_mac_postamble), 5);
49 
50 	/* bb */
51 	INIT_INI_ARRAY(&ah->iniBB[ATH_INI_PRE], NULL, 0, 0);
52 	INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE],
53 		       ar9300_2p2_baseband_core,
54 		       ARRAY_SIZE(ar9300_2p2_baseband_core), 2);
55 	INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST],
56 		       ar9300_2p2_baseband_postamble,
57 		       ARRAY_SIZE(ar9300_2p2_baseband_postamble), 5);
58 
59 	/* radio */
60 	INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_PRE], NULL, 0, 0);
61 	INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE],
62 		       ar9300_2p2_radio_core,
63 		       ARRAY_SIZE(ar9300_2p2_radio_core), 2);
64 	INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST],
65 		       ar9300_2p2_radio_postamble,
66 		       ARRAY_SIZE(ar9300_2p2_radio_postamble), 5);
67 
68 	/* soc */
69 	INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE],
70 		       ar9300_2p2_soc_preamble,
71 		       ARRAY_SIZE(ar9300_2p2_soc_preamble), 2);
72 	INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_CORE], NULL, 0, 0);
73 	INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST],
74 		       ar9300_2p2_soc_postamble,
75 		       ARRAY_SIZE(ar9300_2p2_soc_postamble), 5);
76 
77 	/* rx/tx gain */
78 	INIT_INI_ARRAY(&ah->iniModesRxGain,
79 		       ar9300Common_rx_gain_table_2p2,
80 		       ARRAY_SIZE(ar9300Common_rx_gain_table_2p2), 2);
81 	INIT_INI_ARRAY(&ah->iniModesTxGain,
82 		       ar9300Modes_lowest_ob_db_tx_gain_table_2p2,
83 		       ARRAY_SIZE(ar9300Modes_lowest_ob_db_tx_gain_table_2p2),
84 		       5);
85 
86 	/* Load PCIE SERDES settings from INI */
87 
88 	/* Awake Setting */
89 
90 	INIT_INI_ARRAY(&ah->iniPcieSerdes,
91 		       ar9300PciePhy_pll_on_clkreq_disable_L1_2p2,
92 		       ARRAY_SIZE(ar9300PciePhy_pll_on_clkreq_disable_L1_2p2),
93 		       2);
94 
95 	/* Sleep Setting */
96 
97 	INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower,
98 		       ar9300PciePhy_clkreq_enable_L1_2p2,
99 		       ARRAY_SIZE(ar9300PciePhy_clkreq_enable_L1_2p2),
100 		       2);
101 
102 	/* Fast clock modal settings */
103 	INIT_INI_ARRAY(&ah->iniModesAdditional,
104 		       ar9300Modes_fast_clock_2p2,
105 		       ARRAY_SIZE(ar9300Modes_fast_clock_2p2),
106 		       3);
107 }
108 
109 static void ar9003_tx_gain_table_apply(struct ath_hw *ah)
110 {
111 	switch (ar9003_hw_get_tx_gain_idx(ah)) {
112 	case 0:
113 	default:
114 		INIT_INI_ARRAY(&ah->iniModesTxGain,
115 			       ar9300Modes_lowest_ob_db_tx_gain_table_2p2,
116 			       ARRAY_SIZE(ar9300Modes_lowest_ob_db_tx_gain_table_2p2),
117 			       5);
118 		break;
119 	case 1:
120 		INIT_INI_ARRAY(&ah->iniModesTxGain,
121 			       ar9300Modes_high_ob_db_tx_gain_table_2p2,
122 			       ARRAY_SIZE(ar9300Modes_high_ob_db_tx_gain_table_2p2),
123 			       5);
124 		break;
125 	case 2:
126 		INIT_INI_ARRAY(&ah->iniModesTxGain,
127 			       ar9300Modes_low_ob_db_tx_gain_table_2p2,
128 			       ARRAY_SIZE(ar9300Modes_low_ob_db_tx_gain_table_2p2),
129 			       5);
130 		break;
131 	}
132 }
133 
134 static void ar9003_rx_gain_table_apply(struct ath_hw *ah)
135 {
136 	switch (ar9003_hw_get_rx_gain_idx(ah)) {
137 	case 0:
138 	default:
139 		INIT_INI_ARRAY(&ah->iniModesRxGain,
140 			       ar9300Common_rx_gain_table_2p2,
141 			       ARRAY_SIZE(ar9300Common_rx_gain_table_2p2),
142 			       2);
143 		break;
144 	case 1:
145 		INIT_INI_ARRAY(&ah->iniModesRxGain,
146 			       ar9300Common_wo_xlna_rx_gain_table_2p2,
147 			       ARRAY_SIZE(ar9300Common_wo_xlna_rx_gain_table_2p2),
148 			       2);
149 		break;
150 	}
151 }
152 
153 /* set gain table pointers according to values read from the eeprom */
154 static void ar9003_hw_init_mode_gain_regs(struct ath_hw *ah)
155 {
156 	ar9003_tx_gain_table_apply(ah);
157 	ar9003_rx_gain_table_apply(ah);
158 }
159 
160 /*
161  * Helper for ASPM support.
162  *
163  * Disable PLL when in L0s as well as receiver clock when in L1.
164  * This power saving option must be enabled through the SerDes.
165  *
166  * Programming the SerDes must go through the same 288 bit serial shift
167  * register as the other analog registers.  Hence the 9 writes.
168  */
169 static void ar9003_hw_configpcipowersave(struct ath_hw *ah,
170 					 int restore,
171 					 int power_off)
172 {
173 	if (ah->is_pciexpress != true)
174 		return;
175 
176 	/* Do not touch SerDes registers */
177 	if (ah->config.pcie_powersave_enable == 2)
178 		return;
179 
180 	/* Nothing to do on restore for 11N */
181 	if (!restore) {
182 		/* set bit 19 to allow forcing of pcie core into L1 state */
183 		REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA);
184 
185 		/* Several PCIe massages to ensure proper behaviour */
186 		if (ah->config.pcie_waen)
187 			REG_WRITE(ah, AR_WA, ah->config.pcie_waen);
188 		else
189 			REG_WRITE(ah, AR_WA, ah->WARegVal);
190 	}
191 
192 	/*
193 	 * Configire PCIE after Ini init. SERDES values now come from ini file
194 	 * This enables PCIe low power mode.
195 	 */
196 	if (ah->config.pcieSerDesWrite) {
197 		unsigned int i;
198 		struct ar5416IniArray *array;
199 
200 		array = power_off ? &ah->iniPcieSerdes :
201 				    &ah->iniPcieSerdesLowPower;
202 
203 		for (i = 0; i < array->ia_rows; i++) {
204 			REG_WRITE(ah,
205 				  INI_RA(array, i, 0),
206 				  INI_RA(array, i, 1));
207 		}
208 	}
209 }
210 
211 /* Sets up the AR9003 hardware familiy callbacks */
212 void ar9003_hw_attach_ops(struct ath_hw *ah)
213 {
214 	struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
215 	struct ath_hw_ops *ops = ath9k_hw_ops(ah);
216 
217 	priv_ops->init_mode_regs = ar9003_hw_init_mode_regs;
218 	priv_ops->init_mode_gain_regs = ar9003_hw_init_mode_gain_regs;
219 	priv_ops->macversion_supported = ar9003_hw_macversion_supported;
220 
221 	ops->config_pci_powersave = ar9003_hw_configpcipowersave;
222 
223 	ar9003_hw_attach_phy_ops(ah);
224 	ar9003_hw_attach_calib_ops(ah);
225 	ar9003_hw_attach_mac_ops(ah);
226 }
227