diff options
author | Nick Kossifidis <mick@madwifi-project.org> | 2009-04-30 15:55:50 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-05-06 15:14:56 -0400 |
commit | 57e6c56dbb52d680f61dd629759fe2974840ed93 (patch) | |
tree | 66a9671168f7eb67aa42fa1ce8def3ded45e21ae /drivers/net/wireless/ath/ath5k/phy.c | |
parent | 2bed03ebf62f9d013a455209bf30d7e086120443 (diff) |
ath5k: Add Spur filter support on newer chips
* Add spur filter support for RF5413 and later chips
Signed-off-by: Nick Kossifidis <mickflemm@gmail.com>
Signed-off-by: Bob Copeland <me@bobcopeland.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/ath/ath5k/phy.c')
-rw-r--r-- | drivers/net/wireless/ath/ath5k/phy.c | 255 |
1 files changed, 251 insertions, 4 deletions
diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c index fd93c4e20214..6737ba0a4de3 100644 --- a/drivers/net/wireless/ath/ath5k/phy.c +++ b/drivers/net/wireless/ath/ath5k/phy.c | |||
@@ -1353,6 +1353,257 @@ int ath5k_hw_phy_calibrate(struct ath5k_hw *ah, | |||
1353 | return ret; | 1353 | return ret; |
1354 | } | 1354 | } |
1355 | 1355 | ||
1356 | /***************************\ | ||
1357 | * Spur mitigation functions * | ||
1358 | \***************************/ | ||
1359 | |||
1360 | bool ath5k_hw_chan_has_spur_noise(struct ath5k_hw *ah, | ||
1361 | struct ieee80211_channel *channel) | ||
1362 | { | ||
1363 | u8 refclk_freq; | ||
1364 | |||
1365 | if ((ah->ah_radio == AR5K_RF5112) || | ||
1366 | (ah->ah_radio == AR5K_RF5413) || | ||
1367 | (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4))) | ||
1368 | refclk_freq = 40; | ||
1369 | else | ||
1370 | refclk_freq = 32; | ||
1371 | |||
1372 | if ((channel->center_freq % refclk_freq != 0) && | ||
1373 | ((channel->center_freq % refclk_freq < 10) || | ||
1374 | (channel->center_freq % refclk_freq > 22))) | ||
1375 | return true; | ||
1376 | else | ||
1377 | return false; | ||
1378 | } | ||
1379 | |||
1380 | void | ||
1381 | ath5k_hw_set_spur_mitigation_filter(struct ath5k_hw *ah, | ||
1382 | struct ieee80211_channel *channel) | ||
1383 | { | ||
1384 | struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; | ||
1385 | u32 mag_mask[4] = {0, 0, 0, 0}; | ||
1386 | u32 pilot_mask[2] = {0, 0}; | ||
1387 | /* Note: fbin values are scaled up by 2 */ | ||
1388 | u16 spur_chan_fbin, chan_fbin, symbol_width, spur_detection_window; | ||
1389 | s32 spur_delta_phase, spur_freq_sigma_delta; | ||
1390 | s32 spur_offset, num_symbols_x16; | ||
1391 | u8 num_symbol_offsets, i, freq_band; | ||
1392 | |||
1393 | /* Convert current frequency to fbin value (the same way channels | ||
1394 | * are stored on EEPROM, check out ath5k_eeprom_bin2freq) and scale | ||
1395 | * up by 2 so we can compare it later */ | ||
1396 | if (channel->hw_value & CHANNEL_2GHZ) { | ||
1397 | chan_fbin = (channel->center_freq - 2300) * 10; | ||
1398 | freq_band = AR5K_EEPROM_BAND_2GHZ; | ||
1399 | } else { | ||
1400 | chan_fbin = (channel->center_freq - 4900) * 10; | ||
1401 | freq_band = AR5K_EEPROM_BAND_5GHZ; | ||
1402 | } | ||
1403 | |||
1404 | /* Check if any spur_chan_fbin from EEPROM is | ||
1405 | * within our current channel's spur detection range */ | ||
1406 | spur_chan_fbin = AR5K_EEPROM_NO_SPUR; | ||
1407 | spur_detection_window = AR5K_SPUR_CHAN_WIDTH; | ||
1408 | /* XXX: Half/Quarter channels ?*/ | ||
1409 | if (channel->hw_value & CHANNEL_TURBO) | ||
1410 | spur_detection_window *= 2; | ||
1411 | |||
1412 | for (i = 0; i < AR5K_EEPROM_N_SPUR_CHANS; i++) { | ||
1413 | spur_chan_fbin = ee->ee_spur_chans[i][freq_band]; | ||
1414 | |||
1415 | /* Note: mask cleans AR5K_EEPROM_NO_SPUR flag | ||
1416 | * so it's zero if we got nothing from EEPROM */ | ||
1417 | if (spur_chan_fbin == AR5K_EEPROM_NO_SPUR) { | ||
1418 | spur_chan_fbin &= AR5K_EEPROM_SPUR_CHAN_MASK; | ||
1419 | break; | ||
1420 | } | ||
1421 | |||
1422 | if ((chan_fbin - spur_detection_window <= | ||
1423 | (spur_chan_fbin & AR5K_EEPROM_SPUR_CHAN_MASK)) && | ||
1424 | (chan_fbin + spur_detection_window >= | ||
1425 | (spur_chan_fbin & AR5K_EEPROM_SPUR_CHAN_MASK))) { | ||
1426 | spur_chan_fbin &= AR5K_EEPROM_SPUR_CHAN_MASK; | ||
1427 | break; | ||
1428 | } | ||
1429 | } | ||
1430 | |||
1431 | /* We need to enable spur filter for this channel */ | ||
1432 | if (spur_chan_fbin) { | ||
1433 | spur_offset = spur_chan_fbin - chan_fbin; | ||
1434 | /* | ||
1435 | * Calculate deltas: | ||
1436 | * spur_freq_sigma_delta -> spur_offset / sample_freq << 21 | ||
1437 | * spur_delta_phase -> spur_offset / chip_freq << 11 | ||
1438 | * Note: Both values have 100KHz resolution | ||
1439 | */ | ||
1440 | /* XXX: Half/Quarter rate channels ? */ | ||
1441 | switch (channel->hw_value) { | ||
1442 | case CHANNEL_A: | ||
1443 | /* Both sample_freq and chip_freq are 40MHz */ | ||
1444 | spur_delta_phase = (spur_offset << 17) / 25; | ||
1445 | spur_freq_sigma_delta = (spur_delta_phase >> 10); | ||
1446 | symbol_width = AR5K_SPUR_SYMBOL_WIDTH_BASE_100Hz; | ||
1447 | break; | ||
1448 | case CHANNEL_G: | ||
1449 | /* sample_freq -> 40MHz chip_freq -> 44MHz | ||
1450 | * (for b compatibility) */ | ||
1451 | spur_freq_sigma_delta = (spur_offset << 8) / 55; | ||
1452 | spur_delta_phase = (spur_offset << 17) / 25; | ||
1453 | symbol_width = AR5K_SPUR_SYMBOL_WIDTH_BASE_100Hz; | ||
1454 | break; | ||
1455 | case CHANNEL_T: | ||
1456 | case CHANNEL_TG: | ||
1457 | /* Both sample_freq and chip_freq are 80MHz */ | ||
1458 | spur_delta_phase = (spur_offset << 16) / 25; | ||
1459 | spur_freq_sigma_delta = (spur_delta_phase >> 10); | ||
1460 | symbol_width = AR5K_SPUR_SYMBOL_WIDTH_TURBO_100Hz; | ||
1461 | break; | ||
1462 | default: | ||
1463 | return; | ||
1464 | } | ||
1465 | |||
1466 | /* Calculate pilot and magnitude masks */ | ||
1467 | |||
1468 | /* Scale up spur_offset by 1000 to switch to 100HZ resolution | ||
1469 | * and divide by symbol_width to find how many symbols we have | ||
1470 | * Note: number of symbols is scaled up by 16 */ | ||
1471 | num_symbols_x16 = ((spur_offset * 1000) << 4) / symbol_width; | ||
1472 | |||
1473 | /* Spur is on a symbol if num_symbols_x16 % 16 is zero */ | ||
1474 | if (!(num_symbols_x16 & 0xF)) | ||
1475 | /* _X_ */ | ||
1476 | num_symbol_offsets = 3; | ||
1477 | else | ||
1478 | /* _xx_ */ | ||
1479 | num_symbol_offsets = 4; | ||
1480 | |||
1481 | for (i = 0; i < num_symbol_offsets; i++) { | ||
1482 | |||
1483 | /* Calculate pilot mask */ | ||
1484 | s32 curr_sym_off = | ||
1485 | (num_symbols_x16 / 16) + i + 25; | ||
1486 | |||
1487 | /* Pilot magnitude mask seems to be a way to | ||
1488 | * declare the boundaries for our detection | ||
1489 | * window or something, it's 2 for the middle | ||
1490 | * value(s) where the symbol is expected to be | ||
1491 | * and 1 on the boundary values */ | ||
1492 | u8 plt_mag_map = | ||
1493 | (i == 0 || i == (num_symbol_offsets - 1)) | ||
1494 | ? 1 : 2; | ||
1495 | |||
1496 | if (curr_sym_off >= 0 && curr_sym_off <= 32) { | ||
1497 | if (curr_sym_off <= 25) | ||
1498 | pilot_mask[0] |= 1 << curr_sym_off; | ||
1499 | else if (curr_sym_off >= 27) | ||
1500 | pilot_mask[0] |= 1 << (curr_sym_off - 1); | ||
1501 | } else if (curr_sym_off >= 33 && curr_sym_off <= 52) | ||
1502 | pilot_mask[1] |= 1 << (curr_sym_off - 33); | ||
1503 | |||
1504 | /* Calculate magnitude mask (for viterbi decoder) */ | ||
1505 | if (curr_sym_off >= -1 && curr_sym_off <= 14) | ||
1506 | mag_mask[0] |= | ||
1507 | plt_mag_map << (curr_sym_off + 1) * 2; | ||
1508 | else if (curr_sym_off >= 15 && curr_sym_off <= 30) | ||
1509 | mag_mask[1] |= | ||
1510 | plt_mag_map << (curr_sym_off - 15) * 2; | ||
1511 | else if (curr_sym_off >= 31 && curr_sym_off <= 46) | ||
1512 | mag_mask[2] |= | ||
1513 | plt_mag_map << (curr_sym_off - 31) * 2; | ||
1514 | else if (curr_sym_off >= 46 && curr_sym_off <= 53) | ||
1515 | mag_mask[3] |= | ||
1516 | plt_mag_map << (curr_sym_off - 47) * 2; | ||
1517 | |||
1518 | } | ||
1519 | |||
1520 | /* Write settings on hw to enable spur filter */ | ||
1521 | AR5K_REG_WRITE_BITS(ah, AR5K_PHY_BIN_MASK_CTL, | ||
1522 | AR5K_PHY_BIN_MASK_CTL_RATE, 0xff); | ||
1523 | /* XXX: Self correlator also ? */ | ||
1524 | AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, | ||
1525 | AR5K_PHY_IQ_PILOT_MASK_EN | | ||
1526 | AR5K_PHY_IQ_CHAN_MASK_EN | | ||
1527 | AR5K_PHY_IQ_SPUR_FILT_EN); | ||
1528 | |||
1529 | /* Set delta phase and freq sigma delta */ | ||
1530 | ath5k_hw_reg_write(ah, | ||
1531 | AR5K_REG_SM(spur_delta_phase, | ||
1532 | AR5K_PHY_TIMING_11_SPUR_DELTA_PHASE) | | ||
1533 | AR5K_REG_SM(spur_freq_sigma_delta, | ||
1534 | AR5K_PHY_TIMING_11_SPUR_FREQ_SD) | | ||
1535 | AR5K_PHY_TIMING_11_USE_SPUR_IN_AGC, | ||
1536 | AR5K_PHY_TIMING_11); | ||
1537 | |||
1538 | /* Write pilot masks */ | ||
1539 | ath5k_hw_reg_write(ah, pilot_mask[0], AR5K_PHY_TIMING_7); | ||
1540 | AR5K_REG_WRITE_BITS(ah, AR5K_PHY_TIMING_8, | ||
1541 | AR5K_PHY_TIMING_8_PILOT_MASK_2, | ||
1542 | pilot_mask[1]); | ||
1543 | |||
1544 | ath5k_hw_reg_write(ah, pilot_mask[0], AR5K_PHY_TIMING_9); | ||
1545 | AR5K_REG_WRITE_BITS(ah, AR5K_PHY_TIMING_10, | ||
1546 | AR5K_PHY_TIMING_10_PILOT_MASK_2, | ||
1547 | pilot_mask[1]); | ||
1548 | |||
1549 | /* Write magnitude masks */ | ||
1550 | ath5k_hw_reg_write(ah, mag_mask[0], AR5K_PHY_BIN_MASK_1); | ||
1551 | ath5k_hw_reg_write(ah, mag_mask[1], AR5K_PHY_BIN_MASK_2); | ||
1552 | ath5k_hw_reg_write(ah, mag_mask[2], AR5K_PHY_BIN_MASK_3); | ||
1553 | AR5K_REG_WRITE_BITS(ah, AR5K_PHY_BIN_MASK_CTL, | ||
1554 | AR5K_PHY_BIN_MASK_CTL_MASK_4, | ||
1555 | mag_mask[3]); | ||
1556 | |||
1557 | ath5k_hw_reg_write(ah, mag_mask[0], AR5K_PHY_BIN_MASK2_1); | ||
1558 | ath5k_hw_reg_write(ah, mag_mask[1], AR5K_PHY_BIN_MASK2_2); | ||
1559 | ath5k_hw_reg_write(ah, mag_mask[2], AR5K_PHY_BIN_MASK2_3); | ||
1560 | AR5K_REG_WRITE_BITS(ah, AR5K_PHY_BIN_MASK2_4, | ||
1561 | AR5K_PHY_BIN_MASK2_4_MASK_4, | ||
1562 | mag_mask[3]); | ||
1563 | |||
1564 | } else if (ath5k_hw_reg_read(ah, AR5K_PHY_IQ) & | ||
1565 | AR5K_PHY_IQ_SPUR_FILT_EN) { | ||
1566 | /* Clean up spur mitigation settings and disable fliter */ | ||
1567 | AR5K_REG_WRITE_BITS(ah, AR5K_PHY_BIN_MASK_CTL, | ||
1568 | AR5K_PHY_BIN_MASK_CTL_RATE, 0); | ||
1569 | AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_IQ, | ||
1570 | AR5K_PHY_IQ_PILOT_MASK_EN | | ||
1571 | AR5K_PHY_IQ_CHAN_MASK_EN | | ||
1572 | AR5K_PHY_IQ_SPUR_FILT_EN); | ||
1573 | ath5k_hw_reg_write(ah, 0, AR5K_PHY_TIMING_11); | ||
1574 | |||
1575 | /* Clear pilot masks */ | ||
1576 | ath5k_hw_reg_write(ah, 0, AR5K_PHY_TIMING_7); | ||
1577 | AR5K_REG_WRITE_BITS(ah, AR5K_PHY_TIMING_8, | ||
1578 | AR5K_PHY_TIMING_8_PILOT_MASK_2, | ||
1579 | 0); | ||
1580 | |||
1581 | ath5k_hw_reg_write(ah, 0, AR5K_PHY_TIMING_9); | ||
1582 | AR5K_REG_WRITE_BITS(ah, AR5K_PHY_TIMING_10, | ||
1583 | AR5K_PHY_TIMING_10_PILOT_MASK_2, | ||
1584 | 0); | ||
1585 | |||
1586 | /* Clear magnitude masks */ | ||
1587 | ath5k_hw_reg_write(ah, 0, AR5K_PHY_BIN_MASK_1); | ||
1588 | ath5k_hw_reg_write(ah, 0, AR5K_PHY_BIN_MASK_2); | ||
1589 | ath5k_hw_reg_write(ah, 0, AR5K_PHY_BIN_MASK_3); | ||
1590 | AR5K_REG_WRITE_BITS(ah, AR5K_PHY_BIN_MASK_CTL, | ||
1591 | AR5K_PHY_BIN_MASK_CTL_MASK_4, | ||
1592 | 0); | ||
1593 | |||
1594 | ath5k_hw_reg_write(ah, 0, AR5K_PHY_BIN_MASK2_1); | ||
1595 | ath5k_hw_reg_write(ah, 0, AR5K_PHY_BIN_MASK2_2); | ||
1596 | ath5k_hw_reg_write(ah, 0, AR5K_PHY_BIN_MASK2_3); | ||
1597 | AR5K_REG_WRITE_BITS(ah, AR5K_PHY_BIN_MASK2_4, | ||
1598 | AR5K_PHY_BIN_MASK2_4_MASK_4, | ||
1599 | 0); | ||
1600 | } | ||
1601 | } | ||
1602 | |||
1603 | /********************\ | ||
1604 | Misc PHY functions | ||
1605 | \********************/ | ||
1606 | |||
1356 | int ath5k_hw_phy_disable(struct ath5k_hw *ah) | 1607 | int ath5k_hw_phy_disable(struct ath5k_hw *ah) |
1357 | { | 1608 | { |
1358 | ATH5K_TRACE(ah->ah_sc); | 1609 | ATH5K_TRACE(ah->ah_sc); |
@@ -1362,10 +1613,6 @@ int ath5k_hw_phy_disable(struct ath5k_hw *ah) | |||
1362 | return 0; | 1613 | return 0; |
1363 | } | 1614 | } |
1364 | 1615 | ||
1365 | /********************\ | ||
1366 | Misc PHY functions | ||
1367 | \********************/ | ||
1368 | |||
1369 | /* | 1616 | /* |
1370 | * Get the PHY Chip revision | 1617 | * Get the PHY Chip revision |
1371 | */ | 1618 | */ |