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