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 24 static const u8 com_att_db_table[ATH_AIC_MAX_COM_ATT_DB_TABLE] = { 25 0, 3, 9, 15, 21, 27 26 }; 27 28 static 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 40 static 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 56 static int16_t ar9003_aic_find_valid(bool *cal_sram_valid, 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_valid[i]) 64 break; 65 } 66 } else { 67 for (i = index - 1; i >= 0; i--) { 68 if (cal_sram_valid[i]) 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 */ 82 static 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 106 static 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 165 static 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 264 static bool ar9003_aic_cal_post_process(struct ath_hw *ah) 265 { 266 struct ath9k_hw_aic *aic = &ah->btcoex_hw.aic; 267 bool cal_sram_valid[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_valid, 0, sizeof(cal_sram_valid)); 276 memset(&aic_sram, 0, sizeof(aic_sram)); 277 278 for (i = 0; i < ATH_AIC_MAX_BT_CHANNEL; i++) { 279 struct ath_aic_sram_info sram; 280 value = aic->aic_sram[i]; 281 282 cal_sram_valid[i] = sram.valid = 283 MS(value, AR_PHY_AIC_SRAM_VALID); 284 sram.rot_quad_att_db = 285 MS(value, AR_PHY_AIC_SRAM_ROT_QUAD_ATT_DB); 286 sram.vga_quad_sign = 287 MS(value, AR_PHY_AIC_SRAM_VGA_QUAD_SIGN); 288 sram.rot_dir_att_db = 289 MS(value, AR_PHY_AIC_SRAM_ROT_DIR_ATT_DB); 290 sram.vga_dir_sign = 291 MS(value, AR_PHY_AIC_SRAM_VGA_DIR_SIGN); 292 sram.com_att_6db = 293 MS(value, AR_PHY_AIC_SRAM_COM_ATT_6DB); 294 295 if (sram.valid) { 296 dir_path_gain_idx = sram.rot_dir_att_db + 297 com_att_db_table[sram.com_att_6db]; 298 quad_path_gain_idx = sram.rot_quad_att_db + 299 com_att_db_table[sram.com_att_6db]; 300 301 dir_path_sign = (sram.vga_dir_sign) ? 1 : -1; 302 quad_path_sign = (sram.vga_quad_sign) ? 1 : -1; 303 304 aic_sram[i].dir_path_gain_lin = dir_path_sign * 305 aic_lin_table[dir_path_gain_idx]; 306 aic_sram[i].quad_path_gain_lin = quad_path_sign * 307 aic_lin_table[quad_path_gain_idx]; 308 } 309 } 310 311 for (i = 0; i < ATH_AIC_MAX_BT_CHANNEL; i++) { 312 int16_t start_idx, end_idx; 313 314 if (cal_sram_valid[i]) 315 continue; 316 317 start_idx = ar9003_aic_find_valid(cal_sram_valid, 0, i); 318 end_idx = ar9003_aic_find_valid(cal_sram_valid, 1, i); 319 320 if (start_idx < 0) { 321 /* extrapolation */ 322 start_idx = end_idx; 323 end_idx = ar9003_aic_find_valid(cal_sram_valid, 1, start_idx); 324 325 if (end_idx < 0) { 326 ret = false; 327 break; 328 } 329 330 aic_sram[i].dir_path_gain_lin = 331 ((aic_sram[start_idx].dir_path_gain_lin - 332 aic_sram[end_idx].dir_path_gain_lin) * 333 (start_idx - i) + ((end_idx - i) >> 1)) / 334 (end_idx - i) + 335 aic_sram[start_idx].dir_path_gain_lin; 336 aic_sram[i].quad_path_gain_lin = 337 ((aic_sram[start_idx].quad_path_gain_lin - 338 aic_sram[end_idx].quad_path_gain_lin) * 339 (start_idx - i) + ((end_idx - i) >> 1)) / 340 (end_idx - i) + 341 aic_sram[start_idx].quad_path_gain_lin; 342 } 343 344 if (end_idx < 0) { 345 /* extrapolation */ 346 end_idx = ar9003_aic_find_valid(cal_sram_valid, 0, start_idx); 347 348 if (end_idx < 0) { 349 ret = false; 350 break; 351 } 352 353 aic_sram[i].dir_path_gain_lin = 354 ((aic_sram[start_idx].dir_path_gain_lin - 355 aic_sram[end_idx].dir_path_gain_lin) * 356 (i - start_idx) + ((start_idx - end_idx) >> 1)) / 357 (start_idx - end_idx) + 358 aic_sram[start_idx].dir_path_gain_lin; 359 aic_sram[i].quad_path_gain_lin = 360 ((aic_sram[start_idx].quad_path_gain_lin - 361 aic_sram[end_idx].quad_path_gain_lin) * 362 (i - start_idx) + ((start_idx - end_idx) >> 1)) / 363 (start_idx - end_idx) + 364 aic_sram[start_idx].quad_path_gain_lin; 365 366 } else if (start_idx >= 0){ 367 /* interpolation */ 368 aic_sram[i].dir_path_gain_lin = 369 (((end_idx - i) * aic_sram[start_idx].dir_path_gain_lin) + 370 ((i - start_idx) * aic_sram[end_idx].dir_path_gain_lin) + 371 ((end_idx - start_idx) >> 1)) / 372 (end_idx - start_idx); 373 aic_sram[i].quad_path_gain_lin = 374 (((end_idx - i) * aic_sram[start_idx].quad_path_gain_lin) + 375 ((i - start_idx) * aic_sram[end_idx].quad_path_gain_lin) + 376 ((end_idx - start_idx) >> 1))/ 377 (end_idx - start_idx); 378 } 379 } 380 381 /* From dir/quad_path_gain_lin to sram. */ 382 i = ar9003_aic_find_valid(cal_sram_valid, 1, 0); 383 if (i < 0) { 384 i = 0; 385 ret = false; 386 } 387 fixed_com_att_db = com_att_db_table[MS(aic->aic_sram[i], 388 AR_PHY_AIC_SRAM_COM_ATT_6DB)]; 389 390 for (i = 0; i < ATH_AIC_MAX_BT_CHANNEL; i++) { 391 int16_t rot_dir_path_att_db, rot_quad_path_att_db; 392 struct ath_aic_sram_info sram; 393 394 sram.vga_dir_sign = 395 (aic_sram[i].dir_path_gain_lin >= 0) ? 1 : 0; 396 sram.vga_quad_sign = 397 (aic_sram[i].quad_path_gain_lin >= 0) ? 1 : 0; 398 399 rot_dir_path_att_db = 400 ar9003_aic_find_index(0, abs(aic_sram[i].dir_path_gain_lin)) - 401 fixed_com_att_db; 402 rot_quad_path_att_db = 403 ar9003_aic_find_index(0, abs(aic_sram[i].quad_path_gain_lin)) - 404 fixed_com_att_db; 405 406 sram.com_att_6db = 407 ar9003_aic_find_index(1, fixed_com_att_db); 408 409 sram.valid = true; 410 411 sram.rot_dir_att_db = 412 min(max(rot_dir_path_att_db, 413 (int16_t)ATH_AIC_MIN_ROT_DIR_ATT_DB), 414 ATH_AIC_MAX_ROT_DIR_ATT_DB); 415 sram.rot_quad_att_db = 416 min(max(rot_quad_path_att_db, 417 (int16_t)ATH_AIC_MIN_ROT_QUAD_ATT_DB), 418 ATH_AIC_MAX_ROT_QUAD_ATT_DB); 419 420 aic->aic_sram[i] = (SM(sram.vga_dir_sign, 421 AR_PHY_AIC_SRAM_VGA_DIR_SIGN) | 422 SM(sram.vga_quad_sign, 423 AR_PHY_AIC_SRAM_VGA_QUAD_SIGN) | 424 SM(sram.com_att_6db, 425 AR_PHY_AIC_SRAM_COM_ATT_6DB) | 426 SM(sram.valid, 427 AR_PHY_AIC_SRAM_VALID) | 428 SM(sram.rot_dir_att_db, 429 AR_PHY_AIC_SRAM_ROT_DIR_ATT_DB) | 430 SM(sram.rot_quad_att_db, 431 AR_PHY_AIC_SRAM_ROT_QUAD_ATT_DB)); 432 } 433 434 return ret; 435 } 436 437 static void ar9003_aic_cal_done(struct ath_hw *ah) 438 { 439 struct ath9k_hw_aic *aic = &ah->btcoex_hw.aic; 440 441 /* Disable AIC reference signal in BT modem. */ 442 REG_WRITE(ah, ATH_AIC_BT_JUPITER_CTRL, 443 (REG_READ(ah, ATH_AIC_BT_JUPITER_CTRL) & 444 ~ATH_AIC_BT_AIC_ENABLE)); 445 446 if (ar9003_aic_cal_post_process(ah)) 447 aic->aic_cal_state = AIC_CAL_STATE_DONE; 448 else 449 aic->aic_cal_state = AIC_CAL_STATE_ERROR; 450 } 451 452 static u8 ar9003_aic_cal_continue(struct ath_hw *ah, bool cal_once) 453 { 454 struct ath_common *common = ath9k_hw_common(ah); 455 struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci; 456 struct ath9k_hw_aic *aic = &ah->btcoex_hw.aic; 457 int i, num_chan; 458 459 num_chan = MS(mci_hw->config, ATH_MCI_CONFIG_AIC_CAL_NUM_CHAN); 460 461 if (!num_chan) { 462 aic->aic_cal_state = AIC_CAL_STATE_ERROR; 463 return aic->aic_cal_state; 464 } 465 466 if (cal_once) { 467 for (i = 0; i < 10000; i++) { 468 if ((REG_READ(ah, AR_PHY_AIC_CTRL_0_B1) & 469 AR_PHY_AIC_CAL_ENABLE) == 0) 470 break; 471 472 udelay(100); 473 } 474 } 475 476 /* 477 * Use AR_PHY_AIC_CAL_ENABLE bit instead of AR_PHY_AIC_CAL_DONE. 478 * Sometimes CAL_DONE bit is not asserted. 479 */ 480 if ((REG_READ(ah, AR_PHY_AIC_CTRL_0_B1) & 481 AR_PHY_AIC_CAL_ENABLE) != 0) { 482 ath_dbg(common, MCI, "AIC cal is not done after 40ms"); 483 goto exit; 484 } 485 486 REG_WRITE(ah, AR_PHY_AIC_SRAM_ADDR_B1, 487 (ATH_AIC_SRAM_CAL_OFFSET | ATH_AIC_SRAM_AUTO_INCREMENT)); 488 489 for (i = 0; i < ATH_AIC_MAX_BT_CHANNEL; i++) { 490 u32 value; 491 492 value = REG_READ(ah, AR_PHY_AIC_SRAM_DATA_B1); 493 494 if (value & 0x01) { 495 if (aic->aic_sram[i] == 0) 496 aic->aic_caled_chan++; 497 498 aic->aic_sram[i] = value; 499 500 if (!cal_once) 501 break; 502 } 503 } 504 505 if ((aic->aic_caled_chan >= num_chan) || cal_once) { 506 ar9003_aic_cal_done(ah); 507 } else { 508 /* Start calibration */ 509 REG_CLR_BIT(ah, AR_PHY_AIC_CTRL_0_B1, AR_PHY_AIC_CAL_ENABLE); 510 REG_SET_BIT(ah, AR_PHY_AIC_CTRL_0_B1, 511 AR_PHY_AIC_CAL_CH_VALID_RESET); 512 REG_SET_BIT(ah, AR_PHY_AIC_CTRL_0_B1, AR_PHY_AIC_CAL_ENABLE); 513 } 514 exit: 515 return aic->aic_cal_state; 516 517 } 518 519 u8 ar9003_aic_calibration(struct ath_hw *ah) 520 { 521 struct ath9k_hw_aic *aic = &ah->btcoex_hw.aic; 522 u8 cal_ret = AIC_CAL_STATE_ERROR; 523 524 switch (aic->aic_cal_state) { 525 case AIC_CAL_STATE_IDLE: 526 cal_ret = ar9003_aic_cal_start(ah, 1); 527 break; 528 case AIC_CAL_STATE_STARTED: 529 cal_ret = ar9003_aic_cal_continue(ah, false); 530 break; 531 case AIC_CAL_STATE_DONE: 532 cal_ret = AIC_CAL_STATE_DONE; 533 break; 534 default: 535 break; 536 } 537 538 return cal_ret; 539 } 540 541 u8 ar9003_aic_start_normal(struct ath_hw *ah) 542 { 543 struct ath9k_hw_aic *aic = &ah->btcoex_hw.aic; 544 int16_t i; 545 546 if (aic->aic_cal_state != AIC_CAL_STATE_DONE) 547 return 1; 548 549 ar9003_aic_gain_table(ah); 550 551 REG_WRITE(ah, AR_PHY_AIC_SRAM_ADDR_B1, ATH_AIC_SRAM_AUTO_INCREMENT); 552 553 for (i = 0; i < ATH_AIC_MAX_BT_CHANNEL; i++) { 554 REG_WRITE(ah, AR_PHY_AIC_SRAM_DATA_B1, aic->aic_sram[i]); 555 } 556 557 /* FIXME: Replace these with proper register names */ 558 REG_WRITE(ah, 0xa6b0, 0x80); 559 REG_WRITE(ah, 0xa6b4, 0x5b2df0); 560 REG_WRITE(ah, 0xa6b8, 0x10762cc8); 561 REG_WRITE(ah, 0xa6bc, 0x1219a4b); 562 REG_WRITE(ah, 0xa6c0, 0x1e01); 563 REG_WRITE(ah, 0xb6b4, 0xf0); 564 REG_WRITE(ah, 0xb6c0, 0x1e01); 565 REG_WRITE(ah, 0xb6b0, 0x81); 566 REG_WRITE(ah, AR_PHY_65NM_CH1_RXTX4, 0x40000000); 567 568 aic->aic_enabled = true; 569 570 return 0; 571 } 572 573 u8 ar9003_aic_cal_reset(struct ath_hw *ah) 574 { 575 struct ath9k_hw_aic *aic = &ah->btcoex_hw.aic; 576 577 aic->aic_cal_state = AIC_CAL_STATE_IDLE; 578 return aic->aic_cal_state; 579 } 580 581 u8 ar9003_aic_calibration_single(struct ath_hw *ah) 582 { 583 struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci; 584 u8 cal_ret; 585 int num_chan; 586 587 num_chan = MS(mci_hw->config, ATH_MCI_CONFIG_AIC_CAL_NUM_CHAN); 588 589 (void) ar9003_aic_cal_start(ah, num_chan); 590 cal_ret = ar9003_aic_cal_continue(ah, true); 591 592 return cal_ret; 593 } 594 595 void ar9003_hw_attach_aic_ops(struct ath_hw *ah) 596 { 597 struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); 598 599 priv_ops->is_aic_enabled = ar9003_hw_is_aic_enabled; 600 } 601