16 #include <linux/kernel.h>
18 #include <linux/bitops.h>
31 #define VALID_N_RADIO(radioid) ((radioid == BCM2055_ID) || \
32 (radioid == BCM2056_ID) || \
33 (radioid == BCM2057_ID))
35 #define VALID_LCN_RADIO(radioid) (radioid == BCM2064_ID)
37 #define VALID_RADIO(pi, radioid) ( \
38 (ISNPHY(pi) ? VALID_N_RADIO(radioid) : false) || \
39 (ISLCNPHY(pi) ? VALID_LCN_RADIO(radioid) : false))
42 #define MUX(pred, true, false) ((pred) ? (true) : (false))
45 #define MODINC(x, bound) MUX((x) == (bound) - 1, 0, (x) + 1)
48 #define MODDEC_POW2(x, bound) (((x) - 1) & ((bound) - 1))
49 #define MODINC_POW2(x, bound) (((x) + 1) & ((bound) - 1))
115 static const u8 ofdm_rate_lookup[] = {
127 #define PHY_WREG_LIMIT 24
165 switch (pi->
pubpi.phy_type) {
235 id = ((b0 & 0xf) << 28) | (((b2 << 8) | b1) << 12) | ((b0 >> 4)
294 #ifdef CONFIG_BCM47XX
333 static void wlc_set_phy_uninitted(
struct brcms_phy *pi)
402 static void wlc_phy_timercb_phycal(
struct brcms_phy *pi)
428 ver = read_radio_id(pi);
446 sflags = bcma_aread32(d11core,
BCMA_IOST);
504 idcode = wlc_phy_get_radio_ver(pi);
516 wlc_set_phy_uninitted(pi);
520 ch20mhz_chspec(1) : ch20mhz_chspec(36);
536 pi->
sh->phyrxchain = 0x3;
565 wlc_phy_timercb_phycal,
580 pi->
next = pi->
sh->phy_head;
605 if (pi->
sh->phy_head == pi)
606 pi->
sh->phy_head = pi->
next;
607 else if (pi->
sh->phy_head->next == pi)
608 pi->
sh->phy_head->next =
NULL;
619 u16 *radioid,
u16 *radiover)
622 *phytype = (
u16) pi->
pubpi.phy_type;
624 *radioid = pi->
pubpi.radioid;
625 *radiover = pi->
pubpi.radiorev;
633 return pi->
pubpi.abgphy_encore;
639 return pi->
pubpi.coreflags;
669 ~((0x1 << 0) | (0x1 << 1) | (0x1 << 2)));
672 (0x1 << 0) | (0x1 << 1) | (0x1 << 2));
674 (0x1 << 0) | (0x1 << 1) | (0x1 << 2));
683 u32 phy_bw_clkbits = 0;
701 return phy_bw_clkbits;
737 pi->
sh->clk = newstate;
747 pi->
sh->up = newstate;
771 "HW error SISF_FCLKA\n"))
776 if (phy_init ==
NULL)
810 MCTL_EN_MAC) != 0,
"HW error: MAC enabled during phy cal\n"))
814 cal_init = pi->
pi_fptr.calinit;
839 u16 tblAddr,
u16 tblDataHi,
u16 tblDataLo)
847 pi->
sh->chiprev == 1) {
857 (pi->
sh->chiprev == 1) &&
876 u16 tblAddr,
u16 tblDataHi,
u16 tblDataLo)
882 const u8 *ptbl_8b = (
const u8 *)ptbl_info->
tbl_ptr;
888 for (idx = 0; idx < ptbl_info->
tbl_len; idx++) {
891 (pi->
sh->chiprev == 1) &&
896 (tbl_id << 10) | (tbl_offset + idx));
899 if (tbl_width == 32) {
901 (
u16) (ptbl_32b[idx] >> 16));
903 }
else if (tbl_width == 16) {
913 u16 tblAddr,
u16 tblDataHi,
u16 tblDataLo)
925 for (idx = 0; idx < ptbl_info->
tbl_len; idx++) {
928 (pi->
sh->chiprev == 1)) {
932 (tbl_id << 10) | (tbl_offset + idx));
935 if (tbl_width == 32) {
938 }
else if (tbl_width == 16) {
953 if (radioregs[i].do_init)
958 }
while (radioregs[i].
address != 0xffff);
973 if (radioregs[i].do_init_a) {
977 (
u16) radioregs[i].init_a);
978 if (
ISNPHY(pi) && (++count % 4 == 0))
982 if (radioregs[i].do_init_g) {
986 (
u16) radioregs[i].init_g);
987 if (
ISNPHY(pi) && (++count % 4 == 0))
993 }
while (radioregs[i].
address != 0xffff);
1000 #define DUMMY_PKT_LEN 20
1004 0xcc, 0x01, 0x02, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00,
1005 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00
1008 0x6e, 0x84, 0x0b, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00,
1009 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00
1013 dummypkt = (
u32 *) (ofdm ? ofdmpkt : cckpkt);
1020 bcma_write16(core,
D11REGOFFS(wepctl), 0x100);
1027 bcma_write16(core,
D11REGOFFS(txe_phyctl1), 0x1A02);
1032 bcma_write16(core,
D11REGOFFS(xmttplatetxptr), 0);
1036 ((8 << 8) | (1 << 5) | (1 << 2) | 2));
1046 bcma_write16(core,
D11REGOFFS(txe_aux), 0xD0);
1048 bcma_write16(core,
D11REGOFFS(txe_aux), ((1 << 5) | (1 << 4)));
1053 count = ofdm ? 30 : 250;
1054 while ((i++ < count)
1055 && (bcma_read16(core,
D11REGOFFS(txe_status)) & (1 << 7)))
1060 while ((i++ < 10) &&
1061 ((bcma_read16(core,
D11REGOFFS(txe_status)) & (1 << 10)) == 0))
1066 while ((i++ < 10) &&
1067 ((bcma_read16(core,
D11REGOFFS(ifsstat)) & (1 << 8))))
1116 static bool wlc_phy_cal_txpower_recalc_sw(
struct brcms_phy *pi)
1133 (0x1 << 10) | (0x1 << 11) | (0x1 << 12)));
1134 and_phy_reg(pi, 0x4b0, ~((0x1 << 3) | (0x1 << 11)));
1140 (0x1 << 12) | (0x1 << 13) | (0x1 << 14)));
1144 (0x1 << 10) | (0x1 << 11) | (0x1 << 12));
1148 or_phy_reg(pi, 0x4b0, (0x1 << 3) | (0x1 << 11));
1195 chanspec_set = pi->
pi_fptr.chanset;
1197 (*chanspec_set)(pi, chanspec);
1207 else if (freq <= 5320)
1209 else if (freq <= 5700)
1244 for (i = 0; i <
ARRAY_SIZE(chan_info_all); i++)
1245 if (chan_info_all[i].
chan == channel)
1246 return chan_info_all[
i].
freq;
1260 for (i = 0; i <
ARRAY_SIZE(chan_info_all); i++) {
1261 channel = chan_info_all[
i].
chan;
1280 for (i = 0; i <
ARRAY_SIZE(chan_info_all); i++) {
1281 channel = chan_info_all[
i].
chan;
1286 for (j = 0; j <
ARRAY_SIZE(chan_info_all); j++) {
1287 if (chan_info_all[j].
chan ==
1295 channel = upper_20_sb(channel);
1303 chspec = ch20mhz_chspec(channel);
1322 if (
override !=
NULL)
1330 bool mac_enabled =
false;
1371 wlc_phy_cal_txpower_recalc_sw(pi);
1394 suspend = (0 == (bcma_read32(pi->
d11core,
1402 wlc_phy_cal_txpower_recalc_sw(pi);
1413 u8 *max_pwr,
int txp_rate_idx)
1421 if (txp_rate_idx < 0)
1427 if (txp_rate_idx < 0)
1434 if (txp_rate_idx < 0)
1437 for (i = 0; i <
ARRAY_SIZE(chan_info_all); i++) {
1438 if (channel == chan_info_all[i].
chan)
1462 u8 *max_txpwr,
u8 *min_txpwr)
1466 u8 tx_pwr_min = 255;
1468 u8 maxtxpwr, mintxpwr,
rate, pactrl;
1476 for (rate = 0; rate < max_num_rate; rate++) {
1481 maxtxpwr = (maxtxpwr > pactrl) ? (maxtxpwr - pactrl) : 0;
1483 maxtxpwr = (maxtxpwr > 6) ? (maxtxpwr - 6) : 0;
1485 tx_pwr_max =
max(tx_pwr_max, maxtxpwr);
1486 tx_pwr_min =
min(tx_pwr_min, maxtxpwr);
1488 *max_txpwr = tx_pwr_max;
1489 *min_txpwr = tx_pwr_min;
1494 s32 *max_pwr,
s32 *min_pwr,
u32 *step_pwr)
1513 static s8 wlc_phy_env_measure_vbat(
struct brcms_phy *pi)
1521 static s8 wlc_phy_env_measure_temperature(
struct brcms_phy *pi)
1529 static void wlc_phy_upd_env_txpwr_rate_limits(
struct brcms_phy *pi,
u32 band)
1537 vbat = wlc_phy_env_measure_vbat(pi);
1538 temp = wlc_phy_env_measure_temperature(pi);
1555 u8 maxtxpwr, mintxpwr,
rate, pactrl;
1559 u8 tx_pwr_min = 255;
1560 u8 tx_pwr_max_rate_ind = 0;
1585 ((offset_mcs & 0xf) * 2);
1594 ((offset_mcs & 0xf) * 2);
1600 max_num_rate = ((
ISNPHY(pi)) ? (TXP_NUM_RATES) :
1604 wlc_phy_upd_env_txpwr_rate_limits(pi, band);
1606 for (rate = start_rate; rate < max_num_rate; rate++) {
1611 tx_pwr_target[
rate] +=
1612 wlc_user_txpwr_antport_to_rfport(pi,
1619 &mintxpwr, &maxtxpwr, rate);
1623 maxtxpwr = (maxtxpwr > pactrl) ? (maxtxpwr - pactrl) : 0;
1625 maxtxpwr = (maxtxpwr > 6) ? (maxtxpwr - 6) : 0;
1627 maxtxpwr =
min(maxtxpwr, tx_pwr_target[rate]);
1632 tx_pwr_target[
rate] =
max(maxtxpwr, mintxpwr);
1634 tx_pwr_target[
rate] =
1637 if (tx_pwr_target[rate] > tx_pwr_max)
1638 tx_pwr_max_rate_ind =
rate;
1640 tx_pwr_max =
max(tx_pwr_max, tx_pwr_target[rate]);
1641 tx_pwr_min =
min(tx_pwr_min, tx_pwr_target[rate]);
1648 for (rate = 0; rate < max_num_rate; rate++) {
1660 txpwr_recalc_fn = pi->
pi_fptr.txpwrrecalc;
1661 if (txpwr_recalc_fn)
1662 (*txpwr_recalc_fn)(pi);
1671 int rate_start_index = 0, rate1, rate2,
k;
1683 for (k = 0; k < 4; k++) {
1688 txpwr_ptr2 = txpwr->
ofdm;
1714 tmp_txpwr_limit[rate2] = 0;
1715 tmp_txpwr_limit[BRCMS_NUM_RATES_OFDM + rate2] =
1720 BRCMS_NUM_RATES_OFDM -
1721 1, BRCMS_NUM_RATES_OFDM);
1722 for (rate1 = rate_start_index, rate2 = 0;
1725 min(txpwr_ptr2[rate2],
1726 tmp_txpwr_limit[rate2]);
1729 for (k = 0; k < 4; k++) {
1733 txpwr_ptr1 = txpwr->
ofdm;
1758 tmp_txpwr_limit[rate2] = 0;
1759 tmp_txpwr_limit[BRCMS_NUM_RATES_OFDM + rate2] =
1764 BRCMS_NUM_RATES_OFDM -
1765 1, BRCMS_NUM_RATES_OFDM);
1766 for (rate1 = rate_start_index, rate2 = 0;
1770 min(txpwr_ptr2[rate2],
1771 tmp_txpwr_limit[rate2]);
1774 for (k = 0; k < 2; k++) {
1787 for (rate1 = rate_start_index, rate2 = 0;
1793 for (k = 0; k < 2; k++) {
1806 for (rate1 = rate_start_index, rate2 = 0;
1833 pi->
sh->machwcap = machwcap;
1842 if (start_end ==
ON) {
1871 wlc_phy_txpower_reg_limit_calc(pi, txpwr, chanspec);
1887 wlc_phy_cal_txpower_recalc_sw(pi);
1928 const u8 ucode_ofdm_rates[] = {
1929 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c
1978 suspend = (0 == (bcma_read32(pi->
d11core,
2008 static u32 wlc_phy_txpower_est_power_nphy(
struct brcms_phy *pi)
2010 s16 tx0_status, tx1_status;
2011 u16 estPower1, estPower2;
2012 u8 pwr0, pwr1, adj_pwr0, adj_pwr1;
2018 if ((estPower1 & (0x1 << 8)) == (0x1 << 8))
2019 pwr0 = (
u8) (estPower1 & (0xff << 0)) >> 0;
2023 if ((estPower2 & (0x1 << 8)) == (0x1 << 8))
2024 pwr1 = (
u8) (estPower2 & (0xff << 0)) >> 0;
2031 if ((tx0_status & (0x1 << 15)) == (0x1 << 15))
2032 adj_pwr0 = (
u8) (tx0_status & (0xff << 0)) >> 0;
2035 if ((tx1_status & (0x1 << 15)) == (0x1 << 15))
2036 adj_pwr1 = (
u8) (tx1_status & (0xff << 0)) >> 0;
2040 est_pwr = (
u32) ((pwr0 << 24) | (pwr1 << 16) | (adj_pwr0 << 8) |
2052 u8 min_pwr, max_pwr;
2054 #if WL_TX_POWER_RATES != TXP_NUM_RATES
2055 #error "struct tx_power out of sync with this fn"
2073 num_rates = ((
ISNPHY(pi)) ? (TXP_NUM_RATES) :
2077 for (rate = 0; rate < num_rates; rate++) {
2090 est_pout = wlc_phy_txpower_est_power_nphy(pi);
2094 power->
est_Pout[0] = (est_pout >> 8) & 0xff;
2095 power->
est_Pout[1] = est_pout & 0xff;
2165 pi->
sh->rx_antdiv =
val;
2206 wlc_phy_noise_calc_phy(
struct brcms_phy *pi,
u32 *cmplx_pwr,
s8 *pwr_ant)
2211 memset((
u8 *) cmplx_pwr_dbm, 0,
sizeof(cmplx_pwr_dbm));
2214 for (i = 0; i < pi->
pubpi.phy_corenum; i++) {
2219 cmplx_pwr_dbm[
i] += (
s8) (16 - (15) * 3 - 70);
2222 for (i = 0; i < pi->
pubpi.phy_corenum; i++) {
2224 pwr_ant[
i] = cmplx_pwr_dbm[
i];
2238 pi->
sh->phy_noise_window[pi->
sh->phy_noise_index] =
2240 pi->
sh->phy_noise_index =
2251 static s8 wlc_phy_noise_read_shmem(
struct brcms_phy *pi)
2256 u32 cmplx_pwr_tot = 0;
2260 memset((
u8 *) cmplx_pwr, 0,
sizeof(cmplx_pwr));
2261 memset((
u8 *) noise_dbm_ant, 0,
sizeof(noise_dbm_ant));
2263 for (idx = 0, core = 0; core < pi->
pubpi.phy_corenum; idx += 2,
2268 cmplx_pwr[
core] = (hi << 16) + lo;
2269 cmplx_pwr_tot += cmplx_pwr[
core];
2270 if (cmplx_pwr[core] == 0)
2276 if (cmplx_pwr_tot != 0)
2277 wlc_phy_noise_calc_phy(pi, cmplx_pwr, noise_dbm_ant);
2279 for (core = 0; core < pi->
pubpi.phy_corenum; core++) {
2281 noise_dbm_ant[
core];
2283 if (noise_dbm_ant[core] > noise_dbm)
2284 noise_dbm = noise_dbm_ant[
core];
2301 u32 cmplx_pwr, cmplx_pwr0, cmplx_pwr1;
2303 s32 pwr_offset_dB, gain_dB;
2304 u16 status_0, status_1;
2311 cmplx_pwr0 = (hi << 16) + lo;
2315 cmplx_pwr1 = (hi << 16) + lo;
2316 cmplx_pwr = (cmplx_pwr0 + cmplx_pwr1) >> 6;
2320 if ((cmplx_pwr > 0 && cmplx_pwr < 500)
2321 && ((status_1 & 0xc000) == 0x4000)) {
2324 pi->
pubpi.phy_corenum);
2326 if (pwr_offset_dB > 127)
2327 pwr_offset_dB -= 256;
2329 noise_dbm += (
s8) (pwr_offset_dB - 30);
2331 gain_dB = (status_0 & 0x1ff);
2332 noise_dbm -= (
s8) (gain_dB);
2341 noise_dbm = wlc_phy_noise_read_shmem(pi);
2344 wlc_phy_noise_cb(pi, channel, noise_dbm);
2354 bool wait_for_intr =
true;
2370 if (sampling_in_progress)
2388 wait_for_intr =
false;
2409 wait_for_intr =
false;
2426 u16 log_num_samps, num_samps, classif_state = 0;
2431 memset((
u8 *) est, 0,
sizeof(est));
2432 memset((
u8 *) cmplx_pwr, 0,
sizeof(cmplx_pwr));
2433 memset((
u8 *) noise_dbm_ant, 0,
sizeof(noise_dbm_ant));
2436 num_samps = 1 << log_num_samps;
2446 for (i = 0; i < pi->
pubpi.phy_corenum; i++)
2447 cmplx_pwr[i] = (est[i].
i_pwr + est[i].
q_pwr) >>
2450 wlc_phy_noise_calc_phy(pi, cmplx_pwr, noise_dbm_ant);
2452 for (i = 0; i < pi->
pubpi.phy_corenum; i++) {
2456 if (noise_dbm_ant[i] > noise_dbm)
2457 noise_dbm = noise_dbm_ant[
i];
2462 wait_for_intr =
false;
2469 wlc_phy_noise_cb(pi, ch, noise_dbm);
2482 static const s8 lcnphy_gain_index_offset_for_pkt_rssi[] = {
2528 for (i = 0; i <
core; i++) {
2533 secondmsb = (
u8) ((tmp >> (--msb - 1)) & 1);
2534 p_cmplx_pwr_dB[
i] = (
s8) (3 * msb + 2 * secondmsb);
2545 if ((pi->
sh->corerev >= 11)
2558 rssi = rssi + lcnphy_gain_index_offset_for_pkt_rssi[gidx];
2559 if ((rssi > -46) && (gidx > 18))
2604 bool delay_phy_cal =
false;
2635 pi->
sh->glacial_timer))
2645 pi->
sh->glacial_timer)) {
2668 pi->
sh->phy_noise_window[i] = (
s8) (rssi & 0xff);
2671 pi->
sh->phy_noise_window[i] =
2674 pi->
sh->phy_noise_index = 0;
2686 *eps_imag = (epsilon >> 13);
2687 if (*eps_imag > 0xfff)
2688 *eps_imag -= 0x2000;
2690 *eps_real = (epsilon & 0x1fff);
2691 if (*eps_real > 0xfff)
2692 *eps_real -= 0x2000;
2705 wlc_phy_cal_perical_mphase_schedule(
struct brcms_phy *pi,
uint delay)
2720 s16 nphy_currtemp = 0;
2722 bool do_periodic_cal =
true;
2741 wlc_phy_cal_perical_mphase_schedule(
2775 do_periodic_cal =
false;
2780 if (do_periodic_cal) {
2783 wlc_phy_cal_perical_mphase_schedule(
2807 abs_val =
abs(value);
2808 while ((abs_val >> nbits) > 0)
2818 pi->
sh->hw_phytxchain = txchain;
2819 pi->
sh->hw_phyrxchain = rxchain;
2820 pi->
sh->phytxchain = txchain;
2821 pi->
sh->phyrxchain = rxchain;
2829 pi->
sh->phytxchain = txchain;
2841 *txchain = pi->
sh->phytxchain;
2842 *rxchain = pi->
sh->phyrxchain;
2854 return active_bitmap;
2863 active_bitmap &= 0xFD;
2868 active_bitmap |= 0x2;
2874 return active_bitmap;
2880 u8 siso_mcs_id, cdd_mcs_id;
2898 return ofdm_rate_lookup;