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_2p0_initvals.h" 20#include "ar9003_2p2_initvals.h" 21 22/* General hardware code for the AR9003 hadware family */ 23 24static bool ar9003_hw_macversion_supported(u32 macversion) 25{ 26 switch (macversion) { 27 case AR_SREV_VERSION_9300: 28 return true; 29 default: 30 break; 31 } 32 return false; 33} 34 35/* AR9003 2.0 */ 36static void ar9003_2p0_hw_init_mode_regs(struct ath_hw *ah) 37{ 38 /* mac */ 39 INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0); 40 INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], 41 ar9300_2p0_mac_core, 42 ARRAY_SIZE(ar9300_2p0_mac_core), 2); 43 INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST], 44 ar9300_2p0_mac_postamble, 45 ARRAY_SIZE(ar9300_2p0_mac_postamble), 5); 46 47 /* bb */ 48 INIT_INI_ARRAY(&ah->iniBB[ATH_INI_PRE], NULL, 0, 0); 49 INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE], 50 ar9300_2p0_baseband_core, 51 ARRAY_SIZE(ar9300_2p0_baseband_core), 2); 52 INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST], 53 ar9300_2p0_baseband_postamble, 54 ARRAY_SIZE(ar9300_2p0_baseband_postamble), 5); 55 56 /* radio */ 57 INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_PRE], NULL, 0, 0); 58 INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE], 59 ar9300_2p0_radio_core, 60 ARRAY_SIZE(ar9300_2p0_radio_core), 2); 61 INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST], 62 ar9300_2p0_radio_postamble, 63 ARRAY_SIZE(ar9300_2p0_radio_postamble), 5); 64 65 /* soc */ 66 INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE], 67 ar9300_2p0_soc_preamble, 68 ARRAY_SIZE(ar9300_2p0_soc_preamble), 2); 69 INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_CORE], NULL, 0, 0); 70 INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST], 71 ar9300_2p0_soc_postamble, 72 ARRAY_SIZE(ar9300_2p0_soc_postamble), 5); 73 74 /* rx/tx gain */ 75 INIT_INI_ARRAY(&ah->iniModesRxGain, 76 ar9300Common_rx_gain_table_2p0, 77 ARRAY_SIZE(ar9300Common_rx_gain_table_2p0), 2); 78 INIT_INI_ARRAY(&ah->iniModesTxGain, 79 ar9300Modes_lowest_ob_db_tx_gain_table_2p0, 80 ARRAY_SIZE(ar9300Modes_lowest_ob_db_tx_gain_table_2p0), 81 5); 82 83 /* Load PCIE SERDES settings from INI */ 84 85 /* Awake Setting */ 86 87 INIT_INI_ARRAY(&ah->iniPcieSerdes, 88 ar9300PciePhy_pll_on_clkreq_disable_L1_2p0, 89 ARRAY_SIZE(ar9300PciePhy_pll_on_clkreq_disable_L1_2p0), 90 2); 91 92 /* Sleep Setting */ 93 94 INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower, 95 ar9300PciePhy_clkreq_enable_L1_2p0, 96 ARRAY_SIZE(ar9300PciePhy_clkreq_enable_L1_2p0), 97 2); 98 99 /* Fast clock modal settings */ 100 INIT_INI_ARRAY(&ah->iniModesAdditional, 101 ar9300Modes_fast_clock_2p0, 102 ARRAY_SIZE(ar9300Modes_fast_clock_2p0), 103 3); 104} 105 106/* AR9003 2.2 */ 107static void ar9003_2p2_hw_init_mode_regs(struct ath_hw *ah) 108{ 109 /* mac */ 110 INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0); 111 INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], 112 ar9300_2p2_mac_core, 113 ARRAY_SIZE(ar9300_2p2_mac_core), 2); 114 INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST], 115 ar9300_2p2_mac_postamble, 116 ARRAY_SIZE(ar9300_2p2_mac_postamble), 5); 117 118 /* bb */ 119 INIT_INI_ARRAY(&ah->iniBB[ATH_INI_PRE], NULL, 0, 0); 120 INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE], 121 ar9300_2p2_baseband_core, 122 ARRAY_SIZE(ar9300_2p2_baseband_core), 2); 123 INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST], 124 ar9300_2p2_baseband_postamble, 125 ARRAY_SIZE(ar9300_2p2_baseband_postamble), 5); 126 127 /* radio */ 128 INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_PRE], NULL, 0, 0); 129 INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE], 130 ar9300_2p2_radio_core, 131 ARRAY_SIZE(ar9300_2p2_radio_core), 2); 132 INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST], 133 ar9300_2p2_radio_postamble, 134 ARRAY_SIZE(ar9300_2p2_radio_postamble), 5); 135 136 /* soc */ 137 INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE], 138 ar9300_2p2_soc_preamble, 139 ARRAY_SIZE(ar9300_2p2_soc_preamble), 2); 140 INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_CORE], NULL, 0, 0); 141 INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST], 142 ar9300_2p2_soc_postamble, 143 ARRAY_SIZE(ar9300_2p2_soc_postamble), 5); 144 145 /* rx/tx gain */ 146 INIT_INI_ARRAY(&ah->iniModesRxGain, 147 ar9300Common_rx_gain_table_2p2, 148 ARRAY_SIZE(ar9300Common_rx_gain_table_2p2), 2); 149 INIT_INI_ARRAY(&ah->iniModesTxGain, 150 ar9300Modes_lowest_ob_db_tx_gain_table_2p2, 151 ARRAY_SIZE(ar9300Modes_lowest_ob_db_tx_gain_table_2p2), 152 5); 153 154 /* Load PCIE SERDES settings from INI */ 155 156 /* Awake Setting */ 157 158 INIT_INI_ARRAY(&ah->iniPcieSerdes, 159 ar9300PciePhy_pll_on_clkreq_disable_L1_2p2, 160 ARRAY_SIZE(ar9300PciePhy_pll_on_clkreq_disable_L1_2p2), 161 2); 162 163 /* Sleep Setting */ 164 165 INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower, 166 ar9300PciePhy_clkreq_enable_L1_2p2, 167 ARRAY_SIZE(ar9300PciePhy_clkreq_enable_L1_2p2), 168 2); 169 170 /* Fast clock modal settings */ 171 INIT_INI_ARRAY(&ah->iniModesAdditional, 172 ar9300Modes_fast_clock_2p2, 173 ARRAY_SIZE(ar9300Modes_fast_clock_2p2), 174 3); 175} 176 177/* 178 * The AR9003 family uses a new INI format (pre, core, post 179 * arrays per subsystem). 180 */ 181static void ar9003_hw_init_mode_regs(struct ath_hw *ah) 182{ 183 if (AR_SREV_9300_20(ah)) 184 ar9003_2p0_hw_init_mode_regs(ah); 185 else 186 ar9003_2p2_hw_init_mode_regs(ah); 187} 188 189static void ar9003_tx_gain_table_apply(struct ath_hw *ah) 190{ 191 switch (ar9003_hw_get_tx_gain_idx(ah)) { 192 case 0: 193 default: 194 if (AR_SREV_9300_20(ah)) 195 INIT_INI_ARRAY(&ah->iniModesTxGain, 196 ar9300Modes_lowest_ob_db_tx_gain_table_2p0, 197 ARRAY_SIZE(ar9300Modes_lowest_ob_db_tx_gain_table_2p0), 198 5); 199 else 200 INIT_INI_ARRAY(&ah->iniModesTxGain, 201 ar9300Modes_lowest_ob_db_tx_gain_table_2p2, 202 ARRAY_SIZE(ar9300Modes_lowest_ob_db_tx_gain_table_2p2), 203 5); 204 break; 205 case 1: 206 if (AR_SREV_9300_20(ah)) 207 INIT_INI_ARRAY(&ah->iniModesTxGain, 208 ar9300Modes_high_ob_db_tx_gain_table_2p0, 209 ARRAY_SIZE(ar9300Modes_high_ob_db_tx_gain_table_2p0), 210 5); 211 else 212 INIT_INI_ARRAY(&ah->iniModesTxGain, 213 ar9300Modes_high_ob_db_tx_gain_table_2p2, 214 ARRAY_SIZE(ar9300Modes_high_ob_db_tx_gain_table_2p2), 215 5); 216 break; 217 case 2: 218 if (AR_SREV_9300_20(ah)) 219 INIT_INI_ARRAY(&ah->iniModesTxGain, 220 ar9300Modes_low_ob_db_tx_gain_table_2p0, 221 ARRAY_SIZE(ar9300Modes_low_ob_db_tx_gain_table_2p0), 222 5); 223 else 224 INIT_INI_ARRAY(&ah->iniModesTxGain, 225 ar9300Modes_low_ob_db_tx_gain_table_2p2, 226 ARRAY_SIZE(ar9300Modes_low_ob_db_tx_gain_table_2p2), 227 5); 228 break; 229 } 230} 231 232static void ar9003_rx_gain_table_apply(struct ath_hw *ah) 233{ 234 switch (ar9003_hw_get_rx_gain_idx(ah)) { 235 case 0: 236 default: 237 if (AR_SREV_9300_20(ah)) 238 INIT_INI_ARRAY(&ah->iniModesRxGain, 239 ar9300Common_rx_gain_table_2p0, 240 ARRAY_SIZE(ar9300Common_rx_gain_table_2p0), 241 2); 242 else 243 INIT_INI_ARRAY(&ah->iniModesRxGain, 244 ar9300Common_rx_gain_table_2p2, 245 ARRAY_SIZE(ar9300Common_rx_gain_table_2p2), 246 2); 247 break; 248 case 1: 249 if (AR_SREV_9300_20(ah)) 250 INIT_INI_ARRAY(&ah->iniModesRxGain, 251 ar9300Common_wo_xlna_rx_gain_table_2p0, 252 ARRAY_SIZE(ar9300Common_wo_xlna_rx_gain_table_2p0), 253 2); 254 else 255 INIT_INI_ARRAY(&ah->iniModesRxGain, 256 ar9300Common_wo_xlna_rx_gain_table_2p2, 257 ARRAY_SIZE(ar9300Common_wo_xlna_rx_gain_table_2p2), 258 2); 259 break; 260 } 261} 262 263/* set gain table pointers according to values read from the eeprom */ 264static void ar9003_hw_init_mode_gain_regs(struct ath_hw *ah) 265{ 266 ar9003_tx_gain_table_apply(ah); 267 ar9003_rx_gain_table_apply(ah); 268} 269 270/* 271 * Helper for ASPM support. 272 * 273 * Disable PLL when in L0s as well as receiver clock when in L1. 274 * This power saving option must be enabled through the SerDes. 275 * 276 * Programming the SerDes must go through the same 288 bit serial shift 277 * register as the other analog registers. Hence the 9 writes. 278 */ 279static void ar9003_hw_configpcipowersave(struct ath_hw *ah, 280 int restore, 281 int power_off) 282{ 283 if (ah->is_pciexpress != true) 284 return; 285 286 /* Do not touch SerDes registers */ 287 if (ah->config.pcie_powersave_enable == 2) 288 return; 289 290 /* Nothing to do on restore for 11N */ 291 if (!restore) { 292 /* set bit 19 to allow forcing of pcie core into L1 state */ 293 REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA); 294 295 /* Several PCIe massages to ensure proper behaviour */ 296 if (ah->config.pcie_waen) 297 REG_WRITE(ah, AR_WA, ah->config.pcie_waen); 298 else 299 REG_WRITE(ah, AR_WA, ah->WARegVal); 300 } 301 302 /* 303 * Configire PCIE after Ini init. SERDES values now come from ini file 304 * This enables PCIe low power mode. 305 */ 306 if (ah->config.pcieSerDesWrite) { 307 unsigned int i; 308 struct ar5416IniArray *array; 309 310 array = power_off ? &ah->iniPcieSerdes : 311 &ah->iniPcieSerdesLowPower; 312 313 for (i = 0; i < array->ia_rows; i++) { 314 REG_WRITE(ah, 315 INI_RA(array, i, 0), 316 INI_RA(array, i, 1)); 317 } 318 } 319} 320 321/* Sets up the AR9003 hardware familiy callbacks */ 322void ar9003_hw_attach_ops(struct ath_hw *ah) 323{ 324 struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); 325 struct ath_hw_ops *ops = ath9k_hw_ops(ah); 326 327 priv_ops->init_mode_regs = ar9003_hw_init_mode_regs; 328 priv_ops->init_mode_gain_regs = ar9003_hw_init_mode_gain_regs; 329 priv_ops->macversion_supported = ar9003_hw_macversion_supported; 330 331 ops->config_pci_powersave = ar9003_hw_configpcipowersave; 332 333 ar9003_hw_attach_phy_ops(ah); 334 ar9003_hw_attach_calib_ops(ah); 335 ar9003_hw_attach_mac_ops(ah); 336 337 ath9k_hw_attach_ani_ops_new(ah); 338} 339