Newer
Older
nphy->txiqlocal_bestc);
nphy->txiqlocal_coeffsvalid = true;
nphy->txiqlocal_chanspec.center_freq =
dev->phy.channel_freq;
nphy->txiqlocal_chanspec.channel_type =
dev->phy.channel_type;
} else {
length = 11;
if (dev->phy.rev < 3)
length -= 2;
b43_ntab_read_bulk(dev, B43_NTAB16(15, 96), length,
nphy->mphase_txcal_bestcoeffs);
b43_phy_write(dev, B43_NPHY_IQLOCAL_CMDGCTL, 0);
}
b43_nphy_tx_cal_phy_cleanup(dev);
b43_ntab_write_bulk(dev, B43_NTAB16(7, 0x110), 2, save);
if (dev->phy.rev < 2 && (!mphase || nphy->mphase_cal_phase_id == last))
b43_nphy_tx_iq_workaround(dev);
if (dev->phy.rev >= 4)
nphy->hang_avoid = avoid;
b43_nphy_stay_in_carrier_search(dev, false);
return error;
}
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/ReapplyTxCalCoeffs */
static void b43_nphy_reapply_tx_cal_coeffs(struct b43_wldev *dev)
{
struct b43_phy_n *nphy = dev->phy.n;
u8 i;
u16 buffer[7];
bool equal = true;
if (!nphy->txiqlocal_coeffsvalid ||
nphy->txiqlocal_chanspec.center_freq != dev->phy.channel_freq ||
nphy->txiqlocal_chanspec.channel_type != dev->phy.channel_type)
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
return;
b43_ntab_read_bulk(dev, B43_NTAB16(15, 80), 7, buffer);
for (i = 0; i < 4; i++) {
if (buffer[i] != nphy->txiqlocal_bestc[i]) {
equal = false;
break;
}
}
if (!equal) {
b43_ntab_write_bulk(dev, B43_NTAB16(15, 80), 4,
nphy->txiqlocal_bestc);
for (i = 0; i < 4; i++)
buffer[i] = 0;
b43_ntab_write_bulk(dev, B43_NTAB16(15, 88), 4,
buffer);
b43_ntab_write_bulk(dev, B43_NTAB16(15, 85), 2,
&nphy->txiqlocal_bestc[5]);
b43_ntab_write_bulk(dev, B43_NTAB16(15, 93), 2,
&nphy->txiqlocal_bestc[5]);
}
}
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/CalRxIqRev2 */
static int b43_nphy_rev2_cal_rx_iq(struct b43_wldev *dev,
struct nphy_txgains target, u8 type, bool debug)
{
struct b43_phy_n *nphy = dev->phy.n;
int i, j, index;
u8 rfctl[2];
u8 afectl_core;
u16 tmp[6];
u16 uninitialized_var(cur_hpf1), uninitialized_var(cur_hpf2), cur_lna;
u32 real, imag;
enum ieee80211_band band;
u8 use;
u16 cur_hpf;
u16 lna[3] = { 3, 3, 1 };
u16 hpf1[3] = { 7, 2, 0 };
u16 hpf2[3] = { 2, 0, 0 };
u16 gain_save[2];
u16 cal_gain[2];
struct nphy_iqcal_params cal_params[2];
struct nphy_iq_est est;
int ret = 0;
bool playtone = true;
int desired = 13;
b43_nphy_stay_in_carrier_search(dev, 1);
if (dev->phy.rev < 2)
b43_nphy_reapply_tx_cal_coeffs(dev);
b43_ntab_read_bulk(dev, B43_NTAB16(7, 0x110), 2, gain_save);
for (i = 0; i < 2; i++) {
b43_nphy_iq_cal_gain_params(dev, i, target, &cal_params[i]);
cal_gain[i] = cal_params[i].cal_gain;
}
b43_ntab_write_bulk(dev, B43_NTAB16(7, 0x110), 2, cal_gain);
for (i = 0; i < 2; i++) {
if (i == 0) {
rfctl[0] = B43_NPHY_RFCTL_INTC1;
rfctl[1] = B43_NPHY_RFCTL_INTC2;
afectl_core = B43_NPHY_AFECTL_C1;
} else {
rfctl[0] = B43_NPHY_RFCTL_INTC2;
rfctl[1] = B43_NPHY_RFCTL_INTC1;
afectl_core = B43_NPHY_AFECTL_C2;
}
tmp[1] = b43_phy_read(dev, B43_NPHY_RFSEQCA);
tmp[2] = b43_phy_read(dev, afectl_core);
tmp[3] = b43_phy_read(dev, B43_NPHY_AFECTL_OVER);
tmp[4] = b43_phy_read(dev, rfctl[0]);
tmp[5] = b43_phy_read(dev, rfctl[1]);
b43_phy_maskset(dev, B43_NPHY_RFSEQCA,
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
3142
3143
3144
3145
3146
3147
3148
3149
3150
3151
3152
3153
3154
3155
3156
((1 - i) << B43_NPHY_RFSEQCA_RXDIS_SHIFT));
b43_phy_maskset(dev, B43_NPHY_RFSEQCA, ~B43_NPHY_RFSEQCA_TXEN,
(1 - i));
b43_phy_set(dev, afectl_core, 0x0006);
b43_phy_set(dev, B43_NPHY_AFECTL_OVER, 0x0006);
band = b43_current_band(dev->wl);
if (nphy->rxcalparams & 0xFF000000) {
if (band == IEEE80211_BAND_5GHZ)
b43_phy_write(dev, rfctl[0], 0x140);
else
b43_phy_write(dev, rfctl[0], 0x110);
} else {
if (band == IEEE80211_BAND_5GHZ)
b43_phy_write(dev, rfctl[0], 0x180);
else
b43_phy_write(dev, rfctl[0], 0x120);
}
if (band == IEEE80211_BAND_5GHZ)
b43_phy_write(dev, rfctl[1], 0x148);
else
b43_phy_write(dev, rfctl[1], 0x114);
if (nphy->rxcalparams & 0x10000) {
b43_radio_maskset(dev, B2055_C1_GENSPARE2, 0xFC,
(i + 1));
b43_radio_maskset(dev, B2055_C2_GENSPARE2, 0xFC,
(2 - i));
}
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
if (j < 3) {
cur_lna = lna[j];
cur_hpf1 = hpf1[j];
cur_hpf2 = hpf2[j];
} else {
if (power[1] > 10000) {
use = 1;
cur_hpf = cur_hpf1;
index = 2;
} else {
if (power[0] > 10000) {
use = 1;
cur_hpf = cur_hpf1;
index = 1;
} else {
index = 0;
use = 2;
cur_hpf = cur_hpf2;
}
}
cur_lna = lna[index];
cur_hpf1 = hpf1[index];
cur_hpf2 = hpf2[index];
cur_hpf += desired - hweight32(power[index]);
cur_hpf = clamp_val(cur_hpf, 0, 10);
if (use == 1)
cur_hpf1 = cur_hpf;
else
cur_hpf2 = cur_hpf;
}
tmp[0] = ((cur_hpf2 << 8) | (cur_hpf1 << 4) |
(cur_lna << 2));
b43_nphy_rf_control_override(dev, 0x400, tmp[0], 3,
false);
b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX);
ret = b43_nphy_tx_tone(dev, 4000,
(nphy->rxcalparams & 0xFFFF),
false, false);
playtone = false;
} else {
b43_nphy_run_samples(dev, 160, 0xFFFF, 0,
false, false);
}
if (ret == 0) {
if (j < 3) {
b43_nphy_rx_iq_est(dev, &est, 1024, 32,
false);
if (i == 0) {
real = est.i0_pwr;
imag = est.q0_pwr;
} else {
real = est.i1_pwr;
imag = est.q1_pwr;
}
power[i] = ((real + imag) / 1024) + 1;
} else {
b43_nphy_calc_rx_iq_comp(dev, 1 << i);
}
}
if (ret != 0)
break;
}
b43_radio_mask(dev, B2055_C1_GENSPARE2, 0xFC);
b43_radio_mask(dev, B2055_C2_GENSPARE2, 0xFC);
b43_phy_write(dev, rfctl[1], tmp[5]);
b43_phy_write(dev, rfctl[0], tmp[4]);
b43_phy_write(dev, B43_NPHY_AFECTL_OVER, tmp[3]);
b43_phy_write(dev, afectl_core, tmp[2]);
b43_phy_write(dev, B43_NPHY_RFSEQCA, tmp[1]);
if (ret != 0)
break;
}
b43_nphy_rf_control_override(dev, 0x400, 0, 3, true);
b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX);
b43_ntab_write_bulk(dev, B43_NTAB16(7, 0x110), 2, gain_save);
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
b43_nphy_stay_in_carrier_search(dev, 0);
return ret;
}
static int b43_nphy_rev3_cal_rx_iq(struct b43_wldev *dev,
struct nphy_txgains target, u8 type, bool debug)
{
return -1;
}
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/CalRxIq */
static int b43_nphy_cal_rx_iq(struct b43_wldev *dev,
struct nphy_txgains target, u8 type, bool debug)
{
if (dev->phy.rev >= 3)
return b43_nphy_rev3_cal_rx_iq(dev, target, type, debug);
else
return b43_nphy_rev2_cal_rx_iq(dev, target, type, debug);
}
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/MacPhyClkSet */
static void b43_nphy_mac_phy_clock_set(struct b43_wldev *dev, bool on)
{
u32 tmslow = ssb_read32(dev->dev, SSB_TMSLOW);
if (on)
tmslow |= B43_TMSLOW_MACPHYCLKEN;
tmslow &= ~B43_TMSLOW_MACPHYCLKEN;
ssb_write32(dev->dev, SSB_TMSLOW, tmslow);
}
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RxCoreSetState */
static void b43_nphy_set_rx_core_state(struct b43_wldev *dev, u8 mask)
{
struct b43_phy *phy = &dev->phy;
struct b43_phy_n *nphy = phy->n;

Rafał Miłecki
committed
nphy->phyrxchain = mask;
if (0 /* FIXME clk */)
return;
b43_mac_suspend(dev);
if (nphy->hang_avoid)
b43_nphy_stay_in_carrier_search(dev, true);
b43_phy_maskset(dev, B43_NPHY_RFSEQCA, ~B43_NPHY_RFSEQCA_RXEN,
(mask & 0x3) << B43_NPHY_RFSEQCA_RXEN_SHIFT);

Rafał Miłecki
committed
if ((mask & 0x3) != 0x3) {
b43_phy_write(dev, B43_NPHY_HPANT_SWTHRES, 1);
if (dev->phy.rev >= 3) {
/* TODO */
}
} else {
b43_phy_write(dev, B43_NPHY_HPANT_SWTHRES, 0x1E);
if (dev->phy.rev >= 3) {
/* TODO */
}
}
b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX);
if (nphy->hang_avoid)
b43_nphy_stay_in_carrier_search(dev, false);
b43_mac_enable(dev);
}
/*
* Init N-PHY
* http://bcm-v4.sipsolutions.net/802.11/PHY/Init/N
*/
int b43_phy_initn(struct b43_wldev *dev)
{
struct ssb_bus *bus = dev->dev->bus;
struct b43_phy_n *nphy = phy->n;
u8 tx_pwr_state;
struct nphy_txgains target;
enum ieee80211_band tmp2;
bool do_rssi_cal;
u16 clip[2];
bool do_cal = false;
if ((dev->phy.rev >= 3) &&
(bus->sprom.boardflags_lo & B43_BFL_EXTLNA) &&
(b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)) {
chipco_set32(&dev->dev->bus->chipco, SSB_CHIPCO_CHIPCTL, 0x40);
}
nphy->deaf_count = 0;
nphy->crsminpwr_adjusted = false;
nphy->noisevars_adjusted = false;
if (dev->phy.rev >= 3) {
b43_phy_write(dev, B43_NPHY_TXF_40CO_B1S1, 0);
b43_phy_write(dev, B43_NPHY_RFCTL_OVER, 0);
b43_phy_write(dev, B43_NPHY_TXF_40CO_B1S0, 0);
b43_phy_write(dev, B43_NPHY_TXF_40CO_B32S1, 0);
} else {
b43_phy_write(dev, B43_NPHY_RFCTL_OVER, 0);
}
b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, 0);
b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, 0);
if (dev->phy.rev < 6) {
b43_phy_write(dev, B43_NPHY_RFCTL_INTC3, 0);
b43_phy_write(dev, B43_NPHY_RFCTL_INTC4, 0);
}
b43_phy_mask(dev, B43_NPHY_RFSEQMODE,
~(B43_NPHY_RFSEQMODE_CAOVER |
B43_NPHY_RFSEQMODE_TROVER));
if (dev->phy.rev >= 3)
b43_phy_write(dev, B43_NPHY_AFECTL_OVER1, 0);
b43_phy_write(dev, B43_NPHY_AFECTL_OVER, 0);
if (dev->phy.rev <= 2) {
tmp = (dev->phy.rev == 2) ? 0x3B : 0x40;
b43_phy_maskset(dev, B43_NPHY_BPHY_CTL3,
~B43_NPHY_BPHY_CTL3_SCALE,
tmp << B43_NPHY_BPHY_CTL3_SCALE_SHIFT);
}
b43_phy_write(dev, B43_NPHY_AFESEQ_TX2RX_PUD_20M, 0x20);
b43_phy_write(dev, B43_NPHY_AFESEQ_TX2RX_PUD_40M, 0x20);
if (bus->sprom.boardflags2_lo & 0x100 ||
(bus->boardinfo.vendor == PCI_VENDOR_ID_APPLE &&
bus->boardinfo.type == 0x8B))
b43_phy_write(dev, B43_NPHY_TXREALFD, 0xA0);
else
b43_phy_write(dev, B43_NPHY_TXREALFD, 0xB8);
b43_phy_write(dev, B43_NPHY_MIMO_CRSTXEXT, 0xC8);
b43_phy_write(dev, B43_NPHY_PLOAD_CSENSE_EXTLEN, 0x50);
b43_phy_write(dev, B43_NPHY_TXRIFS_FRDEL, 0x30);
b43_nphy_update_mimo_config(dev, nphy->preamble_override);
if (phy->rev < 2) {
b43_phy_write(dev, B43_NPHY_DUP40_GFBL, 0xAA8);
b43_phy_write(dev, B43_NPHY_DUP40_BL, 0x9A4);
}
tmp2 = b43_current_band(dev->wl);
if ((nphy->ipa2g_on && tmp2 == IEEE80211_BAND_2GHZ) ||
(nphy->ipa5g_on && tmp2 == IEEE80211_BAND_5GHZ)) {
b43_phy_set(dev, B43_NPHY_PAPD_EN0, 0x1);
b43_phy_maskset(dev, B43_NPHY_EPS_TABLE_ADJ0, 0x007F,
nphy->papd_epsilon_offset[0] << 7);
b43_phy_set(dev, B43_NPHY_PAPD_EN1, 0x1);
b43_phy_maskset(dev, B43_NPHY_EPS_TABLE_ADJ1, 0x007F,
nphy->papd_epsilon_offset[1] << 7);
b43_nphy_int_pa_set_tx_dig_filters(dev);
} else if (phy->rev >= 5) {
b43_nphy_ext_pa_set_tx_dig_filters(dev);
/* Reset CCA, in init code it differs a little from standard way */
b43_nphy_bmac_clock_fgc(dev, 1);
tmp = b43_phy_read(dev, B43_NPHY_BBCFG);
b43_phy_write(dev, B43_NPHY_BBCFG, tmp | B43_NPHY_BBCFG_RSTCCA);
b43_phy_write(dev, B43_NPHY_BBCFG, tmp & ~B43_NPHY_BBCFG_RSTCCA);
b43_nphy_bmac_clock_fgc(dev, 0);
b43_nphy_mac_phy_clock_set(dev, true);
b43_nphy_pa_override(dev, false);
b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RX2TX);
b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX);
b43_nphy_pa_override(dev, true);
b43_nphy_classifier(dev, 0, 0);
b43_nphy_read_clip_detection(dev, clip);
if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
b43_nphy_bphy_init(dev);
tx_pwr_state = nphy->txpwrctrl;
b43_nphy_tx_power_ctrl(dev, false);
b43_nphy_tx_power_fix(dev);
/* TODO N PHY TX Power Control Idle TSSI */
/* TODO N PHY TX Power Control Setup */
if (phy->rev >= 3) {
/* TODO */
} else {
b43_ntab_write_bulk(dev, B43_NTAB32(26, 192), 128,
b43_ntab_tx_gain_rev0_1_2);
b43_ntab_write_bulk(dev, B43_NTAB32(27, 192), 128,
b43_ntab_tx_gain_rev0_1_2);
if (nphy->phyrxchain != 3)
b43_nphy_set_rx_core_state(dev, nphy->phyrxchain);
if (nphy->mphase_cal_phase_id > 0)
;/* TODO PHY Periodic Calibration Multi-Phase Restart */
do_rssi_cal = false;
if (phy->rev >= 3) {
if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
do_rssi_cal = !nphy->rssical_chanspec_2G.center_freq;
do_rssi_cal = !nphy->rssical_chanspec_5G.center_freq;
if (do_rssi_cal)
b43_nphy_rssi_cal(dev);
b43_nphy_restore_rssi_cal(dev);
b43_nphy_rssi_cal(dev);
}
if (!((nphy->measure_hold & 0x6) != 0)) {
if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
do_cal = !nphy->iqcal_chanspec_2G.center_freq;
do_cal = !nphy->iqcal_chanspec_5G.center_freq;
if (nphy->mute)
do_cal = false;
if (do_cal) {
target = b43_nphy_get_tx_gains(dev);
if (nphy->antsel_type == 2)
b43_nphy_superswitch_init(dev, true);
if (nphy->perical != 2) {
if (phy->rev >= 3) {
nphy->cal_orig_pwr_idx[0] =
nphy->txpwrindex[0].index_internal;
nphy->cal_orig_pwr_idx[1] =
nphy->txpwrindex[1].index_internal;
/* TODO N PHY Pre Calibrate TX Gain */
target = b43_nphy_get_tx_gains(dev);
if (!b43_nphy_cal_tx_iq_lo(dev, target, true, false))
if (b43_nphy_cal_rx_iq(dev, target, 2, 0) == 0)
b43_nphy_save_cal(dev);
} else if (nphy->mphase_cal_phase_id == 0)
;/* N PHY Periodic Calibration with arg 3 */
} else {
b43_nphy_restore_cal(dev);
b43_nphy_tx_pwr_ctrl_coef_setup(dev);
b43_nphy_tx_power_ctrl(dev, tx_pwr_state);
b43_phy_write(dev, B43_NPHY_TXMACIF_HOLDOFF, 0x0015);
b43_phy_write(dev, B43_NPHY_TXMACDELAY, 0x0320);
if (phy->rev >= 3 && phy->rev <= 6)
b43_phy_write(dev, B43_NPHY_PLOAD_CSENSE_EXTLEN, 0x0014);
b43_nphy_tx_lp_fbw(dev);
if (phy->rev >= 3)
b43_nphy_spur_workaround(dev);
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/ChanspecSetup */
static void b43_nphy_channel_setup(struct b43_wldev *dev,
const struct b43_phy_n_sfo_cfg *e,
struct ieee80211_channel *new_channel)
{
struct b43_phy *phy = &dev->phy;
struct b43_phy_n *nphy = dev->phy.n;
old_band_5ghz =
b43_phy_read(dev, B43_NPHY_BANDCTL) & B43_NPHY_BANDCTL_5GHZ;
if (new_channel->band == IEEE80211_BAND_5GHZ && !old_band_5ghz) {
tmp32 = b43_read32(dev, B43_MMIO_PSM_PHY_HDR);
b43_write32(dev, B43_MMIO_PSM_PHY_HDR, tmp32 | 4);
b43_phy_set(dev, B43_PHY_B_BBCFG, 0xC000);
b43_write32(dev, B43_MMIO_PSM_PHY_HDR, tmp32);
b43_phy_set(dev, B43_NPHY_BANDCTL, B43_NPHY_BANDCTL_5GHZ);
} else if (new_channel->band == IEEE80211_BAND_2GHZ && old_band_5ghz) {
b43_phy_mask(dev, B43_NPHY_BANDCTL, ~B43_NPHY_BANDCTL_5GHZ);
tmp32 = b43_read32(dev, B43_MMIO_PSM_PHY_HDR);
b43_write32(dev, B43_MMIO_PSM_PHY_HDR, tmp32 | 4);
b43_phy_mask(dev, B43_PHY_B_BBCFG, 0x3FFF);
b43_write32(dev, B43_MMIO_PSM_PHY_HDR, tmp32);
}
b43_chantab_phy_upload(dev, e);
if (new_channel->hw_value == 14) {
b43_nphy_classifier(dev, 2, 0);
b43_phy_set(dev, B43_PHY_B_TEST, 0x0800);
} else {
b43_nphy_classifier(dev, 2, 2);
if (new_channel->band == IEEE80211_BAND_2GHZ)
b43_phy_mask(dev, B43_PHY_B_TEST, ~0x840);
}
if (!nphy->txpwrctrl)
b43_nphy_tx_power_fix(dev);
if (dev->phy.rev < 3)
b43_nphy_adjust_lna_gain_table(dev);
b43_nphy_tx_lp_fbw(dev);
if (dev->phy.rev >= 3 && 0) {
/* TODO */
}
b43_phy_write(dev, B43_NPHY_NDATAT_DUP40, 0x3830);
if (phy->rev >= 3)
b43_nphy_spur_workaround(dev);
}
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/SetChanspec */
static int b43_nphy_set_channel(struct b43_wldev *dev,
struct ieee80211_channel *channel,
enum nl80211_channel_type channel_type)
struct b43_phy *phy = &dev->phy;
const struct b43_nphy_channeltab_entry_rev2 *tabent_r2;
const struct b43_nphy_channeltab_entry_rev3 *tabent_r3;
u8 tmp;
if (dev->phy.rev >= 3) {
tabent_r3 = b43_nphy_get_chantabent_rev3(dev,
channel->center_freq);
tabent_r3 = NULL;
if (!tabent_r3)
return -ESRCH;
tabent_r2 = b43_nphy_get_chantabent_rev2(dev,
channel->hw_value);
return -ESRCH;
/* Channel is set later in common code, but we need to set it on our
own to let this function's subcalls work properly. */
phy->channel = channel->hw_value;
phy->channel_freq = channel->center_freq;
if (b43_channel_type_is_40mhz(phy->channel_type) !=
b43_channel_type_is_40mhz(channel_type))
; /* TODO: BMAC BW Set (channel_type) */
if (channel_type == NL80211_CHAN_HT40PLUS)
b43_phy_set(dev, B43_NPHY_RXCTL,
B43_NPHY_RXCTL_BSELU20);
else if (channel_type == NL80211_CHAN_HT40MINUS)
b43_phy_mask(dev, B43_NPHY_RXCTL,
~B43_NPHY_RXCTL_BSELU20);
tmp = (channel->band == IEEE80211_BAND_5GHZ) ? 4 : 0;
b43_radio_maskset(dev, 0x08, 0xFFFB, tmp);
/* TODO: PHY Radio2056 Setup (dev, tabent_r3); */
b43_nphy_channel_setup(dev, &(tabent_r3->phy_regs), channel);
tmp = (channel->band == IEEE80211_BAND_5GHZ) ? 0x0020 : 0x0050;
b43_radio_maskset(dev, B2055_MASTER1, 0xFF8F, tmp);
b43_radio_2055_setup(dev, tabent_r2);
b43_nphy_channel_setup(dev, &(tabent_r2->phy_regs), channel);
static int b43_nphy_op_allocate(struct b43_wldev *dev)
{
struct b43_phy_n *nphy;
nphy = kzalloc(sizeof(*nphy), GFP_KERNEL);
if (!nphy)
return -ENOMEM;
dev->phy.n = nphy;
return 0;
}
static void b43_nphy_op_prepare_structs(struct b43_wldev *dev)
struct b43_phy *phy = &dev->phy;
struct b43_phy_n *nphy = phy->n;
nphy->gain_boost = true; /* this way we follow wl, assume it is true */
nphy->txrx_chain = 2; /* sth different than 0 and 1 for now */
nphy->phyrxchain = 3; /* to avoid b43_nphy_set_rx_core_state like wl */
nphy->perical = 2; /* avoid additional rssi cal on init (like wl) */
static void b43_nphy_op_free(struct b43_wldev *dev)
struct b43_phy *phy = &dev->phy;
struct b43_phy_n *nphy = phy->n;
phy->n = NULL;
}
static int b43_nphy_op_init(struct b43_wldev *dev)
{
return b43_phy_initn(dev);
3659
3660
3661
3662
3663
3664
3665
3666
3667
3668
3669
3670
3671
3672
3673
3674
3675
3676
3677
3678
3679
3680
3681
3682
3683
3684
3685
3686
3687
3688
3689
3690
3691
3692
}
static inline void check_phyreg(struct b43_wldev *dev, u16 offset)
{
#if B43_DEBUG
if ((offset & B43_PHYROUTE) == B43_PHYROUTE_OFDM_GPHY) {
/* OFDM registers are onnly available on A/G-PHYs */
b43err(dev->wl, "Invalid OFDM PHY access at "
"0x%04X on N-PHY\n", offset);
dump_stack();
}
if ((offset & B43_PHYROUTE) == B43_PHYROUTE_EXT_GPHY) {
/* Ext-G registers are only available on G-PHYs */
b43err(dev->wl, "Invalid EXT-G PHY access at "
"0x%04X on N-PHY\n", offset);
dump_stack();
}
#endif /* B43_DEBUG */
}
static u16 b43_nphy_op_read(struct b43_wldev *dev, u16 reg)
{
check_phyreg(dev, reg);
b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
return b43_read16(dev, B43_MMIO_PHY_DATA);
}
static void b43_nphy_op_write(struct b43_wldev *dev, u16 reg, u16 value)
{
check_phyreg(dev, reg);
b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
b43_write16(dev, B43_MMIO_PHY_DATA, value);
}
static void b43_nphy_op_maskset(struct b43_wldev *dev, u16 reg, u16 mask,
u16 set)
{
check_phyreg(dev, reg);
b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
b43_write16(dev, B43_MMIO_PHY_DATA,
(b43_read16(dev, B43_MMIO_PHY_DATA) & mask) | set);
}
static u16 b43_nphy_op_radio_read(struct b43_wldev *dev, u16 reg)
{
/* Register 1 is a 32-bit register. */
B43_WARN_ON(reg == 1);
/* N-PHY needs 0x100 for read access */
reg |= 0x100;
b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg);
return b43_read16(dev, B43_MMIO_RADIO_DATA_LOW);
}
static void b43_nphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value)
{
/* Register 1 is a 32-bit register. */
B43_WARN_ON(reg == 1);
b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg);
b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, value);
}
/* http://bcm-v4.sipsolutions.net/802.11/Radio/Switch%20Radio */
static void b43_nphy_op_software_rfkill(struct b43_wldev *dev,
3725
3726
3727
3728
3729
3730
3731
3732
3733
3734
3735
3736
3737
3738
3739
3740
3741
3742
3743
3744
3745
3746
3747
3748
3749
3750
{
if (b43_read32(dev, B43_MMIO_MACCTL) & B43_MACCTL_ENABLED)
b43err(dev->wl, "MAC not suspended\n");
if (blocked) {
b43_phy_mask(dev, B43_NPHY_RFCTL_CMD,
~B43_NPHY_RFCTL_CMD_CHIP0PU);
if (dev->phy.rev >= 3) {
b43_radio_mask(dev, 0x09, ~0x2);
b43_radio_write(dev, 0x204D, 0);
b43_radio_write(dev, 0x2053, 0);
b43_radio_write(dev, 0x2058, 0);
b43_radio_write(dev, 0x205E, 0);
b43_radio_mask(dev, 0x2062, ~0xF0);
b43_radio_write(dev, 0x2064, 0);
b43_radio_write(dev, 0x304D, 0);
b43_radio_write(dev, 0x3053, 0);
b43_radio_write(dev, 0x3058, 0);
b43_radio_write(dev, 0x305E, 0);
b43_radio_mask(dev, 0x3062, ~0xF0);
b43_radio_write(dev, 0x3064, 0);
}
} else {
if (dev->phy.rev >= 3) {
b43_switch_channel(dev, dev->phy.channel);
} else {
b43_radio_init2055(dev);
}
}
static void b43_nphy_op_switch_analog(struct b43_wldev *dev, bool on)
{
b43_phy_write(dev, B43_NPHY_AFECTL_OVER,
on ? 0 : 0x7FFF);
}
static int b43_nphy_op_switch_channel(struct b43_wldev *dev,
unsigned int new_channel)
{
struct ieee80211_channel *channel = dev->wl->hw->conf.channel;
enum nl80211_channel_type channel_type = dev->wl->hw->conf.channel_type;
if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
if ((new_channel < 1) || (new_channel > 14))
return -EINVAL;
} else {
if (new_channel > 200)
return -EINVAL;
}
return b43_nphy_set_channel(dev, channel, channel_type);
}
static unsigned int b43_nphy_op_get_default_chan(struct b43_wldev *dev)
{
if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
return 1;
return 36;
}
const struct b43_phy_operations b43_phyops_n = {
.allocate = b43_nphy_op_allocate,
.free = b43_nphy_op_free,
.prepare_structs = b43_nphy_op_prepare_structs,
.init = b43_nphy_op_init,
.phy_read = b43_nphy_op_read,
.phy_write = b43_nphy_op_write,
.radio_read = b43_nphy_op_radio_read,
.radio_write = b43_nphy_op_radio_write,
.software_rfkill = b43_nphy_op_software_rfkill,
.switch_analog = b43_nphy_op_switch_analog,
.switch_channel = b43_nphy_op_switch_channel,
.get_default_chan = b43_nphy_op_get_default_chan,
.recalc_txpower = b43_nphy_op_recalc_txpower,
.adjust_txpower = b43_nphy_op_adjust_txpower,