1/* 2 * Copyright (c) 2015 Qualcomm Atheros 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 "hw-ops.h" 19#include "ar9003_mci.h" 20#include "ar9003_aic.h" 21#include "ar9003_phy.h" 22#include "reg_aic.h" 23 24static const u8 com_att_db_table[ATH_AIC_MAX_COM_ATT_DB_TABLE] = { 25 0, 3, 9, 15, 21, 27 26}; 27 28static const u16 aic_lin_table[ATH_AIC_MAX_AIC_LIN_TABLE] = { 29 8191, 7300, 6506, 5799, 5168, 4606, 4105, 3659, 30 3261, 2906, 2590, 2309, 2057, 1834, 1634, 1457, 31 1298, 1157, 1031, 919, 819, 730, 651, 580, 32 517, 461, 411, 366, 326, 291, 259, 231, 33 206, 183, 163, 146, 130, 116, 103, 92, 34 82, 73, 65, 58, 52, 46, 41, 37, 35 33, 29, 26, 23, 21, 18, 16, 15, 36 13, 12, 10, 9, 8, 7, 7, 6, 37 5, 5, 4, 4, 3 38}; 39 40static bool ar9003_hw_is_aic_enabled(struct ath_hw *ah) 41{ 42 struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci; 43 44 /* 45 * Disable AIC for now, until we have all the 46 * HW code and the driver-layer support ready. 47 */ 48 return false; 49 50 if (mci_hw->config & ATH_MCI_CONFIG_DISABLE_AIC) 51 return false; 52 53 return true; 54} 55 56static int16_t ar9003_aic_find_valid(struct ath_aic_sram_info *cal_sram, 57 bool dir, u8 index) 58{ 59 int16_t i; 60 61 if (dir) { 62 for (i = index + 1; i < ATH_AIC_MAX_BT_CHANNEL; i++) { 63 if (cal_sram[i].valid) 64 break; 65 } 66 } else { 67 for (i = index - 1; i >= 0; i--) { 68 if (cal_sram[i].valid) 69 break; 70 } 71 } 72 73 if ((i >= ATH_AIC_MAX_BT_CHANNEL) || (i < 0)) 74 i = -1; 75 76 return i; 77} 78 79/* 80 * type 0: aic_lin_table, 1: com_att_db_table 81 */ 82static int16_t ar9003_aic_find_index(u8 type, int16_t value) 83{ 84 int16_t i = -1; 85 86 if (type == 0) { 87 for (i = ATH_AIC_MAX_AIC_LIN_TABLE - 1; i >= 0; i--) { 88 if (aic_lin_table[i] >= value) 89 break; 90 } 91 } else if (type == 1) { 92 for (i = 0; i < ATH_AIC_MAX_COM_ATT_DB_TABLE; i++) { 93 if (com_att_db_table[i] > value) { 94 i--; 95 break; 96 } 97 } 98 99 if (i >= ATH_AIC_MAX_COM_ATT_DB_TABLE) 100 i = -1; 101 } 102 103 return i; 104} 105 106static void ar9003_aic_gain_table(struct ath_hw *ah) 107{ 108 u32 aic_atten_word[19], i; 109 110 /* Config LNA gain difference */ 111 REG_WRITE(ah, AR_PHY_BT_COEX_4, 0x2c200a00); 112 REG_WRITE(ah, AR_PHY_BT_COEX_5, 0x5c4e4438); 113 114 /* Program gain table */ 115 aic_atten_word[0] = (0x1 & 0xf) << 14 | (0x1f & 0x1f) << 9 | (0x0 & 0xf) << 5 | 116 (0x1f & 0x1f); /* -01 dB: 4'd1, 5'd31, 00 dB: 4'd0, 5'd31 */ 117 aic_atten_word[1] = (0x3 & 0xf) << 14 | (0x1f & 0x1f) << 9 | (0x2 & 0xf) << 5 | 118 (0x1f & 0x1f); /* -03 dB: 4'd3, 5'd31, -02 dB: 4'd2, 5'd31 */ 119 aic_atten_word[2] = (0x5 & 0xf) << 14 | (0x1f & 0x1f) << 9 | (0x4 & 0xf) << 5 | 120 (0x1f & 0x1f); /* -05 dB: 4'd5, 5'd31, -04 dB: 4'd4, 5'd31 */ 121 aic_atten_word[3] = (0x1 & 0xf) << 14 | (0x1e & 0x1f) << 9 | (0x0 & 0xf) << 5 | 122 (0x1e & 0x1f); /* -07 dB: 4'd1, 5'd30, -06 dB: 4'd0, 5'd30 */ 123 aic_atten_word[4] = (0x3 & 0xf) << 14 | (0x1e & 0x1f) << 9 | (0x2 & 0xf) << 5 | 124 (0x1e & 0x1f); /* -09 dB: 4'd3, 5'd30, -08 dB: 4'd2, 5'd30 */ 125 aic_atten_word[5] = (0x5 & 0xf) << 14 | (0x1e & 0x1f) << 9 | (0x4 & 0xf) << 5 | 126 (0x1e & 0x1f); /* -11 dB: 4'd5, 5'd30, -10 dB: 4'd4, 5'd30 */ 127 aic_atten_word[6] = (0x1 & 0xf) << 14 | (0xf & 0x1f) << 9 | (0x0 & 0xf) << 5 | 128 (0xf & 0x1f); /* -13 dB: 4'd1, 5'd15, -12 dB: 4'd0, 5'd15 */ 129 aic_atten_word[7] = (0x3 & 0xf) << 14 | (0xf & 0x1f) << 9 | (0x2 & 0xf) << 5 | 130 (0xf & 0x1f); /* -15 dB: 4'd3, 5'd15, -14 dB: 4'd2, 5'd15 */ 131 aic_atten_word[8] = (0x5 & 0xf) << 14 | (0xf & 0x1f) << 9 | (0x4 & 0xf) << 5 | 132 (0xf & 0x1f); /* -17 dB: 4'd5, 5'd15, -16 dB: 4'd4, 5'd15 */ 133 aic_atten_word[9] = (0x1 & 0xf) << 14 | (0x7 & 0x1f) << 9 | (0x0 & 0xf) << 5 | 134 (0x7 & 0x1f); /* -19 dB: 4'd1, 5'd07, -18 dB: 4'd0, 5'd07 */ 135 aic_atten_word[10] = (0x3 & 0xf) << 14 | (0x7 & 0x1f) << 9 | (0x2 & 0xf) << 5 | 136 (0x7 & 0x1f); /* -21 dB: 4'd3, 5'd07, -20 dB: 4'd2, 5'd07 */ 137 aic_atten_word[11] = (0x5 & 0xf) << 14 | (0x7 & 0x1f) << 9 | (0x4 & 0xf) << 5 | 138 (0x7 & 0x1f); /* -23 dB: 4'd5, 5'd07, -22 dB: 4'd4, 5'd07 */ 139 aic_atten_word[12] = (0x7 & 0xf) << 14 | (0x7 & 0x1f) << 9 | (0x6 & 0xf) << 5 | 140 (0x7 & 0x1f); /* -25 dB: 4'd7, 5'd07, -24 dB: 4'd6, 5'd07 */ 141 aic_atten_word[13] = (0x3 & 0xf) << 14 | (0x3 & 0x1f) << 9 | (0x2 & 0xf) << 5 | 142 (0x3 & 0x1f); /* -27 dB: 4'd3, 5'd03, -26 dB: 4'd2, 5'd03 */ 143 aic_atten_word[14] = (0x5 & 0xf) << 14 | (0x3 & 0x1f) << 9 | (0x4 & 0xf) << 5 | 144 (0x3 & 0x1f); /* -29 dB: 4'd5, 5'd03, -28 dB: 4'd4, 5'd03 */ 145 aic_atten_word[15] = (0x1 & 0xf) << 14 | (0x1 & 0x1f) << 9 | (0x0 & 0xf) << 5 | 146 (0x1 & 0x1f); /* -31 dB: 4'd1, 5'd01, -30 dB: 4'd0, 5'd01 */ 147 aic_atten_word[16] = (0x3 & 0xf) << 14 | (0x1 & 0x1f) << 9 | (0x2 & 0xf) << 5 | 148 (0x1 & 0x1f); /* -33 dB: 4'd3, 5'd01, -32 dB: 4'd2, 5'd01 */ 149 aic_atten_word[17] = (0x5 & 0xf) << 14 | (0x1 & 0x1f) << 9 | (0x4 & 0xf) << 5 | 150 (0x1 & 0x1f); /* -35 dB: 4'd5, 5'd01, -34 dB: 4'd4, 5'd01 */ 151 aic_atten_word[18] = (0x7 & 0xf) << 14 | (0x1 & 0x1f) << 9 | (0x6 & 0xf) << 5 | 152 (0x1 & 0x1f); /* -37 dB: 4'd7, 5'd01, -36 dB: 4'd6, 5'd01 */ 153 154 /* Write to Gain table with auto increment enabled. */ 155 REG_WRITE(ah, (AR_PHY_AIC_SRAM_ADDR_B0 + 0x3000), 156 (ATH_AIC_SRAM_AUTO_INCREMENT | 157 ATH_AIC_SRAM_GAIN_TABLE_OFFSET)); 158 159 for (i = 0; i < 19; i++) { 160 REG_WRITE(ah, (AR_PHY_AIC_SRAM_DATA_B0 + 0x3000), 161 aic_atten_word[i]); 162 } 163} 164 165static u8 ar9003_aic_cal_start(struct ath_hw *ah, u8 min_valid_count) 166{ 167 struct ath9k_hw_aic *aic = &ah->btcoex_hw.aic; 168 int i; 169 170 /* Write to Gain table with auto increment enabled. */ 171 REG_WRITE(ah, (AR_PHY_AIC_SRAM_ADDR_B0 + 0x3000), 172 (ATH_AIC_SRAM_AUTO_INCREMENT | 173 ATH_AIC_SRAM_CAL_OFFSET)); 174 175 for (i = 0; i < ATH_AIC_MAX_BT_CHANNEL; i++) { 176 REG_WRITE(ah, (AR_PHY_AIC_SRAM_DATA_B0 + 0x3000), 0); 177 aic->aic_sram[i] = 0; 178 } 179 180 REG_WRITE(ah, AR_PHY_AIC_CTRL_0_B0, 181 (SM(0, AR_PHY_AIC_MON_ENABLE) | 182 SM(127, AR_PHY_AIC_CAL_MAX_HOP_COUNT) | 183 SM(min_valid_count, AR_PHY_AIC_CAL_MIN_VALID_COUNT) | 184 SM(37, AR_PHY_AIC_F_WLAN) | 185 SM(1, AR_PHY_AIC_CAL_CH_VALID_RESET) | 186 SM(0, AR_PHY_AIC_CAL_ENABLE) | 187 SM(0x40, AR_PHY_AIC_BTTX_PWR_THR) | 188 SM(0, AR_PHY_AIC_ENABLE))); 189 190 REG_WRITE(ah, AR_PHY_AIC_CTRL_0_B1, 191 (SM(0, AR_PHY_AIC_MON_ENABLE) | 192 SM(1, AR_PHY_AIC_CAL_CH_VALID_RESET) | 193 SM(0, AR_PHY_AIC_CAL_ENABLE) | 194 SM(0x40, AR_PHY_AIC_BTTX_PWR_THR) | 195 SM(0, AR_PHY_AIC_ENABLE))); 196 197 REG_WRITE(ah, AR_PHY_AIC_CTRL_1_B0, 198 (SM(8, AR_PHY_AIC_CAL_BT_REF_DELAY) | 199 SM(0, AR_PHY_AIC_BT_IDLE_CFG) | 200 SM(1, AR_PHY_AIC_STDBY_COND) | 201 SM(37, AR_PHY_AIC_STDBY_ROT_ATT_DB) | 202 SM(5, AR_PHY_AIC_STDBY_COM_ATT_DB) | 203 SM(15, AR_PHY_AIC_RSSI_MAX) | 204 SM(0, AR_PHY_AIC_RSSI_MIN))); 205 206 REG_WRITE(ah, AR_PHY_AIC_CTRL_1_B1, 207 (SM(15, AR_PHY_AIC_RSSI_MAX) | 208 SM(0, AR_PHY_AIC_RSSI_MIN))); 209 210 REG_WRITE(ah, AR_PHY_AIC_CTRL_2_B0, 211 (SM(44, AR_PHY_AIC_RADIO_DELAY) | 212 SM(8, AR_PHY_AIC_CAL_STEP_SIZE_CORR) | 213 SM(12, AR_PHY_AIC_CAL_ROT_IDX_CORR) | 214 SM(2, AR_PHY_AIC_CAL_CONV_CHECK_FACTOR) | 215 SM(5, AR_PHY_AIC_ROT_IDX_COUNT_MAX) | 216 SM(0, AR_PHY_AIC_CAL_SYNTH_TOGGLE) | 217 SM(0, AR_PHY_AIC_CAL_SYNTH_AFTER_BTRX) | 218 SM(200, AR_PHY_AIC_CAL_SYNTH_SETTLING))); 219 220 REG_WRITE(ah, AR_PHY_AIC_CTRL_3_B0, 221 (SM(2, AR_PHY_AIC_MON_MAX_HOP_COUNT) | 222 SM(1, AR_PHY_AIC_MON_MIN_STALE_COUNT) | 223 SM(1, AR_PHY_AIC_MON_PWR_EST_LONG) | 224 SM(2, AR_PHY_AIC_MON_PD_TALLY_SCALING) | 225 SM(10, AR_PHY_AIC_MON_PERF_THR) | 226 SM(2, AR_PHY_AIC_CAL_TARGET_MAG_SETTING) | 227 SM(1, AR_PHY_AIC_CAL_PERF_CHECK_FACTOR) | 228 SM(1, AR_PHY_AIC_CAL_PWR_EST_LONG))); 229 230 REG_WRITE(ah, AR_PHY_AIC_CTRL_4_B0, 231 (SM(2, AR_PHY_AIC_CAL_ROT_ATT_DB_EST_ISO) | 232 SM(3, AR_PHY_AIC_CAL_COM_ATT_DB_EST_ISO) | 233 SM(0, AR_PHY_AIC_CAL_ISO_EST_INIT_SETTING) | 234 SM(2, AR_PHY_AIC_CAL_COM_ATT_DB_BACKOFF) | 235 SM(1, AR_PHY_AIC_CAL_COM_ATT_DB_FIXED))); 236 237 REG_WRITE(ah, AR_PHY_AIC_CTRL_4_B1, 238 (SM(2, AR_PHY_AIC_CAL_ROT_ATT_DB_EST_ISO) | 239 SM(3, AR_PHY_AIC_CAL_COM_ATT_DB_EST_ISO) | 240 SM(0, AR_PHY_AIC_CAL_ISO_EST_INIT_SETTING) | 241 SM(2, AR_PHY_AIC_CAL_COM_ATT_DB_BACKOFF) | 242 SM(1, AR_PHY_AIC_CAL_COM_ATT_DB_FIXED))); 243 244 ar9003_aic_gain_table(ah); 245 246 /* Need to enable AIC reference signal in BT modem. */ 247 REG_WRITE(ah, ATH_AIC_BT_JUPITER_CTRL, 248 (REG_READ(ah, ATH_AIC_BT_JUPITER_CTRL) | 249 ATH_AIC_BT_AIC_ENABLE)); 250 251 aic->aic_cal_start_time = REG_READ(ah, AR_TSF_L32); 252 253 /* Start calibration */ 254 REG_CLR_BIT(ah, AR_PHY_AIC_CTRL_0_B1, AR_PHY_AIC_CAL_ENABLE); 255 REG_SET_BIT(ah, AR_PHY_AIC_CTRL_0_B1, AR_PHY_AIC_CAL_CH_VALID_RESET); 256 REG_SET_BIT(ah, AR_PHY_AIC_CTRL_0_B1, AR_PHY_AIC_CAL_ENABLE); 257 258 aic->aic_caled_chan = 0; 259 aic->aic_cal_state = AIC_CAL_STATE_STARTED; 260 261 return aic->aic_cal_state; 262} 263 264static bool ar9003_aic_cal_post_process(struct ath_hw *ah) 265{ 266 struct ath9k_hw_aic *aic = &ah->btcoex_hw.aic; 267 struct ath_aic_sram_info cal_sram[ATH_AIC_MAX_BT_CHANNEL]; 268 struct ath_aic_out_info aic_sram[ATH_AIC_MAX_BT_CHANNEL]; 269 u32 dir_path_gain_idx, quad_path_gain_idx, value; 270 u32 fixed_com_att_db; 271 int8_t dir_path_sign, quad_path_sign; 272 int16_t i; 273 bool ret = true; 274 275 memset(&cal_sram, 0, sizeof(cal_sram)); 276 memset(&aic_sram, 0, sizeof(aic_sram)); 277 278 for (i = 0; i < ATH_AIC_MAX_BT_CHANNEL; i++) { 279 value = aic->aic_sram[i]; 280 281 cal_sram[i].valid = 282 MS(value, AR_PHY_AIC_SRAM_VALID); 283 cal_sram[i].rot_quad_att_db = 284 MS(value, AR_PHY_AIC_SRAM_ROT_QUAD_ATT_DB); 285 cal_sram[i].vga_quad_sign = 286 MS(value, AR_PHY_AIC_SRAM_VGA_QUAD_SIGN); 287 cal_sram[i].rot_dir_att_db = 288 MS(value, AR_PHY_AIC_SRAM_ROT_DIR_ATT_DB); 289 cal_sram[i].vga_dir_sign = 290 MS(value, AR_PHY_AIC_SRAM_VGA_DIR_SIGN); 291 cal_sram[i].com_att_6db = 292 MS(value, AR_PHY_AIC_SRAM_COM_ATT_6DB); 293 294 if (cal_sram[i].valid) { 295 dir_path_gain_idx = cal_sram[i].rot_dir_att_db + 296 com_att_db_table[cal_sram[i].com_att_6db]; 297 quad_path_gain_idx = cal_sram[i].rot_quad_att_db + 298 com_att_db_table[cal_sram[i].com_att_6db]; 299 300 dir_path_sign = (cal_sram[i].vga_dir_sign) ? 1 : -1; 301 quad_path_sign = (cal_sram[i].vga_quad_sign) ? 1 : -1; 302 303 aic_sram[i].dir_path_gain_lin = dir_path_sign * 304 aic_lin_table[dir_path_gain_idx]; 305 aic_sram[i].quad_path_gain_lin = quad_path_sign * 306 aic_lin_table[quad_path_gain_idx]; 307 } 308 } 309 310 for (i = 0; i < ATH_AIC_MAX_BT_CHANNEL; i++) { 311 int16_t start_idx, end_idx; 312 313 if (cal_sram[i].valid) 314 continue; 315 316 start_idx = ar9003_aic_find_valid(cal_sram, 0, i); 317 end_idx = ar9003_aic_find_valid(cal_sram, 1, i); 318 319 if (start_idx < 0) { 320 /* extrapolation */ 321 start_idx = end_idx; 322 end_idx = ar9003_aic_find_valid(cal_sram, 1, start_idx); 323 324 if (end_idx < 0) { 325 ret = false; 326 break; 327 } 328 329 aic_sram[i].dir_path_gain_lin = 330 ((aic_sram[start_idx].dir_path_gain_lin - 331 aic_sram[end_idx].dir_path_gain_lin) * 332 (start_idx - i) + ((end_idx - i) >> 1)) / 333 (end_idx - i) + 334 aic_sram[start_idx].dir_path_gain_lin; 335 aic_sram[i].quad_path_gain_lin = 336 ((aic_sram[start_idx].quad_path_gain_lin - 337 aic_sram[end_idx].quad_path_gain_lin) * 338 (start_idx - i) + ((end_idx - i) >> 1)) / 339 (end_idx - i) + 340 aic_sram[start_idx].quad_path_gain_lin; 341 } 342 343 if (end_idx < 0) { 344 /* extrapolation */ 345 end_idx = ar9003_aic_find_valid(cal_sram, 0, start_idx); 346 347 if (end_idx < 0) { 348 ret = false; 349 break; 350 } 351 352 aic_sram[i].dir_path_gain_lin = 353 ((aic_sram[start_idx].dir_path_gain_lin - 354 aic_sram[end_idx].dir_path_gain_lin) * 355 (i - start_idx) + ((start_idx - end_idx) >> 1)) / 356 (start_idx - end_idx) + 357 aic_sram[start_idx].dir_path_gain_lin; 358 aic_sram[i].quad_path_gain_lin = 359 ((aic_sram[start_idx].quad_path_gain_lin - 360 aic_sram[end_idx].quad_path_gain_lin) * 361 (i - start_idx) + ((start_idx - end_idx) >> 1)) / 362 (start_idx - end_idx) + 363 aic_sram[start_idx].quad_path_gain_lin; 364 365 } else if (start_idx >= 0){ 366 /* interpolation */ 367 aic_sram[i].dir_path_gain_lin = 368 (((end_idx - i) * aic_sram[start_idx].dir_path_gain_lin) + 369 ((i - start_idx) * aic_sram[end_idx].dir_path_gain_lin) + 370 ((end_idx - start_idx) >> 1)) / 371 (end_idx - start_idx); 372 aic_sram[i].quad_path_gain_lin = 373 (((end_idx - i) * aic_sram[start_idx].quad_path_gain_lin) + 374 ((i - start_idx) * aic_sram[end_idx].quad_path_gain_lin) + 375 ((end_idx - start_idx) >> 1))/ 376 (end_idx - start_idx); 377 } 378 } 379 380 /* From dir/quad_path_gain_lin to sram. */ 381 i = ar9003_aic_find_valid(cal_sram, 1, 0); 382 if (i < 0) { 383 i = 0; 384 ret = false; 385 } 386 fixed_com_att_db = com_att_db_table[cal_sram[i].com_att_6db]; 387 388 for (i = 0; i < ATH_AIC_MAX_BT_CHANNEL; i++) { 389 int16_t rot_dir_path_att_db, rot_quad_path_att_db; 390 391 aic_sram[i].sram.vga_dir_sign = 392 (aic_sram[i].dir_path_gain_lin >= 0) ? 1 : 0; 393 aic_sram[i].sram.vga_quad_sign= 394 (aic_sram[i].quad_path_gain_lin >= 0) ? 1 : 0; 395 396 rot_dir_path_att_db = 397 ar9003_aic_find_index(0, abs(aic_sram[i].dir_path_gain_lin)) - 398 fixed_com_att_db; 399 rot_quad_path_att_db = 400 ar9003_aic_find_index(0, abs(aic_sram[i].quad_path_gain_lin)) - 401 fixed_com_att_db; 402 403 aic_sram[i].sram.com_att_6db = 404 ar9003_aic_find_index(1, fixed_com_att_db); 405 406 aic_sram[i].sram.valid = 1; 407 408 aic_sram[i].sram.rot_dir_att_db = 409 min(max(rot_dir_path_att_db, 410 (int16_t)ATH_AIC_MIN_ROT_DIR_ATT_DB), 411 ATH_AIC_MAX_ROT_DIR_ATT_DB); 412 aic_sram[i].sram.rot_quad_att_db = 413 min(max(rot_quad_path_att_db, 414 (int16_t)ATH_AIC_MIN_ROT_QUAD_ATT_DB), 415 ATH_AIC_MAX_ROT_QUAD_ATT_DB); 416 } 417 418 for (i = 0; i < ATH_AIC_MAX_BT_CHANNEL; i++) { 419 aic->aic_sram[i] = (SM(aic_sram[i].sram.vga_dir_sign, 420 AR_PHY_AIC_SRAM_VGA_DIR_SIGN) | 421 SM(aic_sram[i].sram.vga_quad_sign, 422 AR_PHY_AIC_SRAM_VGA_QUAD_SIGN) | 423 SM(aic_sram[i].sram.com_att_6db, 424 AR_PHY_AIC_SRAM_COM_ATT_6DB) | 425 SM(aic_sram[i].sram.valid, 426 AR_PHY_AIC_SRAM_VALID) | 427 SM(aic_sram[i].sram.rot_dir_att_db, 428 AR_PHY_AIC_SRAM_ROT_DIR_ATT_DB) | 429 SM(aic_sram[i].sram.rot_quad_att_db, 430 AR_PHY_AIC_SRAM_ROT_QUAD_ATT_DB)); 431 } 432 433 return ret; 434} 435 436static void ar9003_aic_cal_done(struct ath_hw *ah) 437{ 438 struct ath9k_hw_aic *aic = &ah->btcoex_hw.aic; 439 440 /* Disable AIC reference signal in BT modem. */ 441 REG_WRITE(ah, ATH_AIC_BT_JUPITER_CTRL, 442 (REG_READ(ah, ATH_AIC_BT_JUPITER_CTRL) & 443 ~ATH_AIC_BT_AIC_ENABLE)); 444 445 if (ar9003_aic_cal_post_process(ah)) 446 aic->aic_cal_state = AIC_CAL_STATE_DONE; 447 else 448 aic->aic_cal_state = AIC_CAL_STATE_ERROR; 449} 450 451static u8 ar9003_aic_cal_continue(struct ath_hw *ah, bool cal_once) 452{ 453 struct ath_common *common = ath9k_hw_common(ah); 454 struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci; 455 struct ath9k_hw_aic *aic = &ah->btcoex_hw.aic; 456 int i, num_chan; 457 458 num_chan = MS(mci_hw->config, ATH_MCI_CONFIG_AIC_CAL_NUM_CHAN); 459 460 if (!num_chan) { 461 aic->aic_cal_state = AIC_CAL_STATE_ERROR; 462 return aic->aic_cal_state; 463 } 464 465 if (cal_once) { 466 for (i = 0; i < 10000; i++) { 467 if ((REG_READ(ah, AR_PHY_AIC_CTRL_0_B1) & 468 AR_PHY_AIC_CAL_ENABLE) == 0) 469 break; 470 471 udelay(100); 472 } 473 } 474 475 /* 476 * Use AR_PHY_AIC_CAL_ENABLE bit instead of AR_PHY_AIC_CAL_DONE. 477 * Sometimes CAL_DONE bit is not asserted. 478 */ 479 if ((REG_READ(ah, AR_PHY_AIC_CTRL_0_B1) & 480 AR_PHY_AIC_CAL_ENABLE) != 0) { 481 ath_dbg(common, MCI, "AIC cal is not done after 40ms"); 482 goto exit; 483 } 484 485 REG_WRITE(ah, AR_PHY_AIC_SRAM_ADDR_B1, 486 (ATH_AIC_SRAM_CAL_OFFSET | ATH_AIC_SRAM_AUTO_INCREMENT)); 487 488 for (i = 0; i < ATH_AIC_MAX_BT_CHANNEL; i++) { 489 u32 value; 490 491 value = REG_READ(ah, AR_PHY_AIC_SRAM_DATA_B1); 492 493 if (value & 0x01) { 494 if (aic->aic_sram[i] == 0) 495 aic->aic_caled_chan++; 496 497 aic->aic_sram[i] = value; 498 499 if (!cal_once) 500 break; 501 } 502 } 503 504 if ((aic->aic_caled_chan >= num_chan) || cal_once) { 505 ar9003_aic_cal_done(ah); 506 } else { 507 /* Start calibration */ 508 REG_CLR_BIT(ah, AR_PHY_AIC_CTRL_0_B1, AR_PHY_AIC_CAL_ENABLE); 509 REG_SET_BIT(ah, AR_PHY_AIC_CTRL_0_B1, 510 AR_PHY_AIC_CAL_CH_VALID_RESET); 511 REG_SET_BIT(ah, AR_PHY_AIC_CTRL_0_B1, AR_PHY_AIC_CAL_ENABLE); 512 } 513exit: 514 return aic->aic_cal_state; 515 516} 517 518u8 ar9003_aic_calibration(struct ath_hw *ah) 519{ 520 struct ath9k_hw_aic *aic = &ah->btcoex_hw.aic; 521 u8 cal_ret = AIC_CAL_STATE_ERROR; 522 523 switch (aic->aic_cal_state) { 524 case AIC_CAL_STATE_IDLE: 525 cal_ret = ar9003_aic_cal_start(ah, 1); 526 break; 527 case AIC_CAL_STATE_STARTED: 528 cal_ret = ar9003_aic_cal_continue(ah, false); 529 break; 530 case AIC_CAL_STATE_DONE: 531 cal_ret = AIC_CAL_STATE_DONE; 532 break; 533 default: 534 break; 535 } 536 537 return cal_ret; 538} 539 540u8 ar9003_aic_start_normal(struct ath_hw *ah) 541{ 542 struct ath9k_hw_aic *aic = &ah->btcoex_hw.aic; 543 int16_t i; 544 545 if (aic->aic_cal_state != AIC_CAL_STATE_DONE) 546 return 1; 547 548 ar9003_aic_gain_table(ah); 549 550 REG_WRITE(ah, AR_PHY_AIC_SRAM_ADDR_B1, ATH_AIC_SRAM_AUTO_INCREMENT); 551 552 for (i = 0; i < ATH_AIC_MAX_BT_CHANNEL; i++) { 553 REG_WRITE(ah, AR_PHY_AIC_SRAM_DATA_B1, aic->aic_sram[i]); 554 } 555 556 /* FIXME: Replace these with proper register names */ 557 REG_WRITE(ah, 0xa6b0, 0x80); 558 REG_WRITE(ah, 0xa6b4, 0x5b2df0); 559 REG_WRITE(ah, 0xa6b8, 0x10762cc8); 560 REG_WRITE(ah, 0xa6bc, 0x1219a4b); 561 REG_WRITE(ah, 0xa6c0, 0x1e01); 562 REG_WRITE(ah, 0xb6b4, 0xf0); 563 REG_WRITE(ah, 0xb6c0, 0x1e01); 564 REG_WRITE(ah, 0xb6b0, 0x81); 565 REG_WRITE(ah, AR_PHY_65NM_CH1_RXTX4, 0x40000000); 566 567 aic->aic_enabled = true; 568 569 return 0; 570} 571 572u8 ar9003_aic_cal_reset(struct ath_hw *ah) 573{ 574 struct ath9k_hw_aic *aic = &ah->btcoex_hw.aic; 575 576 aic->aic_cal_state = AIC_CAL_STATE_IDLE; 577 return aic->aic_cal_state; 578} 579 580u8 ar9003_aic_calibration_single(struct ath_hw *ah) 581{ 582 struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci; 583 u8 cal_ret; 584 int num_chan; 585 586 num_chan = MS(mci_hw->config, ATH_MCI_CONFIG_AIC_CAL_NUM_CHAN); 587 588 (void) ar9003_aic_cal_start(ah, num_chan); 589 cal_ret = ar9003_aic_cal_continue(ah, true); 590 591 return cal_ret; 592} 593 594void ar9003_hw_attach_aic_ops(struct ath_hw *ah) 595{ 596 struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); 597 598 priv_ops->is_aic_enabled = ar9003_hw_is_aic_enabled; 599} 600