aboutsummaryrefslogtreecommitdiff
path: root/drivers/net/wireless/b43
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/b43')
-rw-r--r--drivers/net/wireless/b43/Kconfig6
-rw-r--r--drivers/net/wireless/b43/b43.h6
-rw-r--r--drivers/net/wireless/b43/dma.c9
-rw-r--r--drivers/net/wireless/b43/main.c7
-rw-r--r--drivers/net/wireless/b43/phy_ht.c610
-rw-r--r--drivers/net/wireless/b43/phy_ht.h77
6 files changed, 636 insertions, 79 deletions
diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig
index 287c6b670a3..078e6f3477a 100644
--- a/drivers/net/wireless/b43/Kconfig
+++ b/drivers/net/wireless/b43/Kconfig
@@ -131,7 +131,7 @@ config B43_PHY_LP
config B43_PHY_HT
bool "Support for HT-PHY (high throughput) devices"
- depends on B43
+ depends on B43 && B43_BCMA
---help---
Support for the HT-PHY.
@@ -166,8 +166,8 @@ config B43_DEBUG
Broadcom 43xx debugging.
This adds additional runtime sanity checks and statistics to the driver.
- These checks and statistics might me expensive and hurt runtime performance
- of your system.
+ These checks and statistics might be expensive and hurt the runtime
+ performance of your system.
This also adds the b43 debugfs interface.
Do not enable this, unless you are debugging the driver.
diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h
index 10e288d470e..fe4a77ee05c 100644
--- a/drivers/net/wireless/b43/b43.h
+++ b/drivers/net/wireless/b43/b43.h
@@ -473,6 +473,12 @@ enum {
#define B43_MACCMD_CCA 0x00000008 /* Clear channel assessment */
#define B43_MACCMD_BGNOISE 0x00000010 /* Background noise */
+/* See BCMA_CLKCTLST_EXTRESREQ and BCMA_CLKCTLST_EXTRESST */
+#define B43_BCMA_CLKCTLST_80211_PLL_REQ 0x00000100
+#define B43_BCMA_CLKCTLST_PHY_PLL_REQ 0x00000200
+#define B43_BCMA_CLKCTLST_80211_PLL_ST 0x01000000
+#define B43_BCMA_CLKCTLST_PHY_PLL_ST 0x02000000
+
/* BCMA 802.11 core specific IO Control (BCMA_IOCTL) flags */
#define B43_BCMA_IOCTL_PHY_CLKEN 0x00000004 /* PHY Clock Enable */
#define B43_BCMA_IOCTL_PHY_RESET 0x00000008 /* PHY Reset */
diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c
index 122146943bf..523355b8765 100644
--- a/drivers/net/wireless/b43/dma.c
+++ b/drivers/net/wireless/b43/dma.c
@@ -419,8 +419,6 @@ static inline
static int alloc_ringmemory(struct b43_dmaring *ring)
{
- gfp_t flags = GFP_KERNEL;
-
/* The specs call for 4K buffers for 30- and 32-bit DMA with 4K
* alignment and 8K buffers for 64-bit DMA with 8K alignment.
* In practice we could use smaller buffers for the latter, but the
@@ -435,12 +433,9 @@ static int alloc_ringmemory(struct b43_dmaring *ring)
ring->descbase = dma_alloc_coherent(ring->dev->dev->dma_dev,
ring_mem_size, &(ring->dmabase),
- flags);
- if (!ring->descbase) {
- b43err(ring->dev->wl, "DMA ringmemory allocation failed\n");
+ GFP_KERNEL | __GFP_ZERO);
+ if (!ring->descbase)
return -ENOMEM;
- }
- memset(ring->descbase, 0, ring_mem_size);
return 0;
}
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index 05682736e46..c4d0cc58255 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -1189,10 +1189,15 @@ static void b43_bcma_phy_reset(struct b43_wldev *dev)
static void b43_bcma_wireless_core_reset(struct b43_wldev *dev, bool gmode)
{
+ u32 req = B43_BCMA_CLKCTLST_80211_PLL_REQ |
+ B43_BCMA_CLKCTLST_PHY_PLL_REQ;
+ u32 status = B43_BCMA_CLKCTLST_80211_PLL_ST |
+ B43_BCMA_CLKCTLST_PHY_PLL_ST;
+
b43_device_enable(dev, B43_BCMA_IOCTL_PHY_CLKEN);
bcma_core_set_clockmode(dev->dev->bdev, BCMA_CLKMODE_FAST);
b43_bcma_phy_reset(dev);
- bcma_core_pll_ctl(dev->dev->bdev, 0x300, 0x3000000, true);
+ bcma_core_pll_ctl(dev->dev->bdev, req, status, true);
}
#endif
diff --git a/drivers/net/wireless/b43/phy_ht.c b/drivers/net/wireless/b43/phy_ht.c
index 7416c5e9154..b8667706fc2 100644
--- a/drivers/net/wireless/b43/phy_ht.c
+++ b/drivers/net/wireless/b43/phy_ht.c
@@ -154,9 +154,84 @@ static void b43_radio_2059_init(struct b43_wldev *dev)
}
/**************************************************
+ * RF
+ **************************************************/
+
+static void b43_phy_ht_force_rf_sequence(struct b43_wldev *dev, u16 rf_seq)
+{
+ u8 i;
+
+ u16 save_seq_mode = b43_phy_read(dev, B43_PHY_HT_RF_SEQ_MODE);
+ b43_phy_set(dev, B43_PHY_HT_RF_SEQ_MODE, 0x3);
+
+ b43_phy_set(dev, B43_PHY_HT_RF_SEQ_TRIG, rf_seq);
+ for (i = 0; i < 200; i++) {
+ if (!(b43_phy_read(dev, B43_PHY_HT_RF_SEQ_STATUS) & rf_seq)) {
+ i = 0;
+ break;
+ }
+ msleep(1);
+ }
+ if (i)
+ b43err(dev->wl, "Forcing RF sequence timeout\n");
+
+ b43_phy_write(dev, B43_PHY_HT_RF_SEQ_MODE, save_seq_mode);
+}
+
+static void b43_phy_ht_pa_override(struct b43_wldev *dev, bool enable)
+{
+ struct b43_phy_ht *htphy = dev->phy.ht;
+ static const u16 regs[3] = { B43_PHY_HT_RF_CTL_INT_C1,
+ B43_PHY_HT_RF_CTL_INT_C2,
+ B43_PHY_HT_RF_CTL_INT_C3 };
+ int i;
+
+ if (enable) {
+ for (i = 0; i < 3; i++)
+ b43_phy_write(dev, regs[i], htphy->rf_ctl_int_save[i]);
+ } else {
+ for (i = 0; i < 3; i++)
+ htphy->rf_ctl_int_save[i] = b43_phy_read(dev, regs[i]);
+ /* TODO: Does 5GHz band use different value (not 0x0400)? */
+ for (i = 0; i < 3; i++)
+ b43_phy_write(dev, regs[i], 0x0400);
+ }
+}
+
+/**************************************************
* Various PHY ops
**************************************************/
+static u16 b43_phy_ht_classifier(struct b43_wldev *dev, u16 mask, u16 val)
+{
+ u16 tmp;
+ u16 allowed = B43_PHY_HT_CLASS_CTL_CCK_EN |
+ B43_PHY_HT_CLASS_CTL_OFDM_EN |
+ B43_PHY_HT_CLASS_CTL_WAITED_EN;
+
+ tmp = b43_phy_read(dev, B43_PHY_HT_CLASS_CTL);
+ tmp &= allowed;
+ tmp &= ~mask;
+ tmp |= (val & mask);
+ b43_phy_maskset(dev, B43_PHY_HT_CLASS_CTL, ~allowed, tmp);
+
+ return tmp;
+}
+
+static void b43_phy_ht_reset_cca(struct b43_wldev *dev)
+{
+ u16 bbcfg;
+
+ b43_phy_force_clock(dev, true);
+ bbcfg = b43_phy_read(dev, B43_PHY_HT_BBCFG);
+ b43_phy_write(dev, B43_PHY_HT_BBCFG, bbcfg | B43_PHY_HT_BBCFG_RSTCCA);
+ udelay(1);
+ b43_phy_write(dev, B43_PHY_HT_BBCFG, bbcfg & ~B43_PHY_HT_BBCFG_RSTCCA);
+ b43_phy_force_clock(dev, false);
+
+ b43_phy_ht_force_rf_sequence(dev, B43_PHY_HT_RF_SEQ_TRIG_RST2RX);
+}
+
static void b43_phy_ht_zero_extg(struct b43_wldev *dev)
{
u8 i, j;
@@ -176,10 +251,10 @@ static void b43_phy_ht_afe_unk1(struct b43_wldev *dev)
{
u8 i;
- const u16 ctl_regs[3][2] = {
- { B43_PHY_HT_AFE_CTL1, B43_PHY_HT_AFE_CTL2 },
- { B43_PHY_HT_AFE_CTL3, B43_PHY_HT_AFE_CTL4 },
- { B43_PHY_HT_AFE_CTL5, B43_PHY_HT_AFE_CTL6},
+ static const u16 ctl_regs[3][2] = {
+ { B43_PHY_HT_AFE_C1_OVER, B43_PHY_HT_AFE_C1 },
+ { B43_PHY_HT_AFE_C2_OVER, B43_PHY_HT_AFE_C2 },
+ { B43_PHY_HT_AFE_C3_OVER, B43_PHY_HT_AFE_C3},
};
for (i = 0; i < 3; i++) {
@@ -193,27 +268,6 @@ static void b43_phy_ht_afe_unk1(struct b43_wldev *dev)
}
}
-static void b43_phy_ht_force_rf_sequence(struct b43_wldev *dev, u16 rf_seq)
-{
- u8 i;
-
- u16 save_seq_mode = b43_phy_read(dev, B43_PHY_HT_RF_SEQ_MODE);
- b43_phy_set(dev, B43_PHY_HT_RF_SEQ_MODE, 0x3);
-
- b43_phy_set(dev, B43_PHY_HT_RF_SEQ_TRIG, rf_seq);
- for (i = 0; i < 200; i++) {
- if (!(b43_phy_read(dev, B43_PHY_HT_RF_SEQ_STATUS) & rf_seq)) {
- i = 0;
- break;
- }
- msleep(1);
- }
- if (i)
- b43err(dev->wl, "Forcing RF sequence timeout\n");
-
- b43_phy_write(dev, B43_PHY_HT_RF_SEQ_MODE, save_seq_mode);
-}
-
static void b43_phy_ht_read_clip_detection(struct b43_wldev *dev, u16 *clip_st)
{
clip_st[0] = b43_phy_read(dev, B43_PHY_HT_C1_CLIP1THRES);
@@ -240,15 +294,426 @@ static void b43_phy_ht_bphy_init(struct b43_wldev *dev)
}
/**************************************************
+ * Samples
+ **************************************************/
+
+static void b43_phy_ht_stop_playback(struct b43_wldev *dev)
+{
+ struct b43_phy_ht *phy_ht = dev->phy.ht;
+ u16 tmp;
+ int i;
+
+ tmp = b43_phy_read(dev, B43_PHY_HT_SAMP_STAT);
+ if (tmp & 0x1)
+ b43_phy_set(dev, B43_PHY_HT_SAMP_CMD, B43_PHY_HT_SAMP_CMD_STOP);
+ else if (tmp & 0x2)
+ b43_phy_mask(dev, B43_PHY_HT_IQLOCAL_CMDGCTL, 0x7FFF);
+
+ b43_phy_mask(dev, B43_PHY_HT_SAMP_CMD, ~0x0004);
+
+ for (i = 0; i < 3; i++) {
+ if (phy_ht->bb_mult_save[i] >= 0) {
+ b43_httab_write(dev, B43_HTTAB16(13, 0x63 + i * 4),
+ phy_ht->bb_mult_save[i]);
+ b43_httab_write(dev, B43_HTTAB16(13, 0x67 + i * 4),
+ phy_ht->bb_mult_save[i]);
+ }
+ }
+}
+
+static u16 b43_phy_ht_load_samples(struct b43_wldev *dev)
+{
+ int i;
+ u16 len = 20 << 3;
+
+ b43_phy_write(dev, B43_PHY_HT_TABLE_ADDR, 0x4400);
+
+ for (i = 0; i < len; i++) {
+ b43_phy_write(dev, B43_PHY_HT_TABLE_DATAHI, 0);
+ b43_phy_write(dev, B43_PHY_HT_TABLE_DATALO, 0);
+ }
+
+ return len;
+}
+
+static void b43_phy_ht_run_samples(struct b43_wldev *dev, u16 samps, u16 loops,
+ u16 wait)
+{
+ struct b43_phy_ht *phy_ht = dev->phy.ht;
+ u16 save_seq_mode;
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ if (phy_ht->bb_mult_save[i] < 0)
+ phy_ht->bb_mult_save[i] = b43_httab_read(dev, B43_HTTAB16(13, 0x63 + i * 4));
+ }
+
+ b43_phy_write(dev, B43_PHY_HT_SAMP_DEP_CNT, samps - 1);
+ if (loops != 0xFFFF)
+ loops--;
+ b43_phy_write(dev, B43_PHY_HT_SAMP_LOOP_CNT, loops);
+ b43_phy_write(dev, B43_PHY_HT_SAMP_WAIT_CNT, wait);
+
+ save_seq_mode = b43_phy_read(dev, B43_PHY_HT_RF_SEQ_MODE);
+ b43_phy_set(dev, B43_PHY_HT_RF_SEQ_MODE,
+ B43_PHY_HT_RF_SEQ_MODE_CA_OVER);
+
+ /* TODO: find out mask bits! Do we need more function arguments? */
+ b43_phy_mask(dev, B43_PHY_HT_SAMP_CMD, ~0);
+ b43_phy_mask(dev, B43_PHY_HT_SAMP_CMD, ~0);
+ b43_phy_mask(dev, B43_PHY_HT_IQLOCAL_CMDGCTL, ~0);
+ b43_phy_set(dev, B43_PHY_HT_SAMP_CMD, 0x1);
+
+ for (i = 0; i < 100; i++) {
+ if (!(b43_phy_read(dev, B43_PHY_HT_RF_SEQ_STATUS) & 1)) {
+ i = 0;
+ break;
+ }
+ udelay(10);
+ }
+ if (i)
+ b43err(dev->wl, "run samples timeout\n");
+
+ b43_phy_write(dev, B43_PHY_HT_RF_SEQ_MODE, save_seq_mode);
+}
+
+static void b43_phy_ht_tx_tone(struct b43_wldev *dev)
+{
+ u16 samp;
+
+ samp = b43_phy_ht_load_samples(dev);
+ b43_phy_ht_run_samples(dev, samp, 0xFFFF, 0);
+}
+
+/**************************************************
+ * RSSI
+ **************************************************/
+
+static void b43_phy_ht_rssi_select(struct b43_wldev *dev, u8 core_sel,
+ u8 rssi_type)
+{
+ static const u16 ctl_regs[3][2] = {
+ { B43_PHY_HT_AFE_C1, B43_PHY_HT_AFE_C1_OVER, },
+ { B43_PHY_HT_AFE_C2, B43_PHY_HT_AFE_C2_OVER, },
+ { B43_PHY_HT_AFE_C3, B43_PHY_HT_AFE_C3_OVER, },
+ };
+ static const u16 radio_r[] = { R2059_SYN, R2059_TXRX0, R2059_RXRX1, };
+ int core;
+
+ if (core_sel == 0) {
+ b43err(dev->wl, "RSSI selection for core off not implemented yet\n");
+ } else {
+ for (core = 0; core < 3; core++) {
+ /* Check if caller requested a one specific core */
+ if ((core_sel == 1 && core != 0) ||
+ (core_sel == 2 && core != 1) ||
+ (core_sel == 3 && core != 2))
+ continue;
+
+ switch (rssi_type) {
+ case 4:
+ b43_phy_set(dev, ctl_regs[core][0], 0x3 << 8);
+ b43_phy_set(dev, ctl_regs[core][0], 0x3 << 10);
+ b43_phy_set(dev, ctl_regs[core][1], 0x1 << 9);
+ b43_phy_set(dev, ctl_regs[core][1], 0x1 << 10);
+
+ b43_radio_set(dev, R2059_RXRX1 | 0xbf, 0x1);
+ b43_radio_write(dev, radio_r[core] | 0x159,
+ 0x11);
+ break;
+ default:
+ b43err(dev->wl, "RSSI selection for type %d not implemented yet\n",
+ rssi_type);
+ }
+ }
+ }
+}
+
+static void b43_phy_ht_poll_rssi(struct b43_wldev *dev, u8 type, s32 *buf,
+ u8 nsamp)
+{
+ u16 phy_regs_values[12];
+ static const u16 phy_regs_to_save[] = {
+ B43_PHY_HT_AFE_C1, B43_PHY_HT_AFE_C1_OVER,
+ 0x848, 0x841,
+ B43_PHY_HT_AFE_C2, B43_PHY_HT_AFE_C2_OVER,
+ 0x868, 0x861,
+ B43_PHY_HT_AFE_C3, B43_PHY_HT_AFE_C3_OVER,
+ 0x888, 0x881,
+ };
+ u16 tmp[3];
+ int i;
+
+ for (i = 0; i < 12; i++)
+ phy_regs_values[i] = b43_phy_read(dev, phy_regs_to_save[i]);
+
+ b43_phy_ht_rssi_select(dev, 5, type);
+
+ for (i = 0; i < 6; i++)
+ buf[i] = 0;
+
+ for (i = 0; i < nsamp; i++) {
+ tmp[0] = b43_phy_read(dev, B43_PHY_HT_RSSI_C1);
+ tmp[1] = b43_phy_read(dev, B43_PHY_HT_RSSI_C2);
+ tmp[2] = b43_phy_read(dev, B43_PHY_HT_RSSI_C3);
+
+ buf[0] += ((s8)((tmp[0] & 0x3F) << 2)) >> 2;
+ buf[1] += ((s8)(((tmp[0] >> 8) & 0x3F) << 2)) >> 2;
+ buf[2] += ((s8)((tmp[1] & 0x3F) << 2)) >> 2;
+ buf[3] += ((s8)(((tmp[1] >> 8) & 0x3F) << 2)) >> 2;
+ buf[4] += ((s8)((tmp[2] & 0x3F) << 2)) >> 2;
+ buf[5] += ((s8)(((tmp[2] >> 8) & 0x3F) << 2)) >> 2;
+ }
+
+ for (i = 0; i < 12; i++)
+ b43_phy_write(dev, phy_regs_to_save[i], phy_regs_values[i]);
+}
+
+/**************************************************
+ * Tx/Rx
+ **************************************************/
+
+static void b43_phy_ht_tx_power_fix(struct b43_wldev *dev)
+{
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ u16 mask;
+ u32 tmp = b43_httab_read(dev, B43_HTTAB32(26, 0xE8));
+
+ if (0) /* FIXME */
+ mask = 0x2 << (i * 4);
+ else
+ mask = 0;
+ b43_phy_mask(dev, B43_PHY_EXTG(0x108), mask);
+
+ b43_httab_write(dev, B43_HTTAB16(7, 0x110 + i), tmp >> 16);
+ b43_httab_write(dev, B43_HTTAB8(13, 0x63 + (i * 4)),
+ tmp & 0xFF);
+ b43_httab_write(dev, B43_HTTAB8(13, 0x73 + (i * 4)),
+ tmp & 0xFF);
+ }
+}
+
+static void b43_phy_ht_tx_power_ctl(struct b43_wldev *dev, bool enable)
+{
+ struct b43_phy_ht *phy_ht = dev->phy.ht;
+ u16 en_bits = B43_PHY_HT_TXPCTL_CMD_C1_COEFF |
+ B43_PHY_HT_TXPCTL_CMD_C1_HWPCTLEN |
+ B43_PHY_HT_TXPCTL_CMD_C1_PCTLEN;
+ static const u16 cmd_regs[3] = { B43_PHY_HT_TXPCTL_CMD_C1,
+ B43_PHY_HT_TXPCTL_CMD_C2,
+ B43_PHY_HT_TXPCTL_CMD_C3 };
+ int i;
+
+ if (!enable) {
+ if (b43_phy_read(dev, B43_PHY_HT_TXPCTL_CMD_C1) & en_bits) {
+ /* We disable enabled TX pwr ctl, save it's state */
+ /*
+ * TODO: find the registers. On N-PHY they were 0x1ed
+ * and 0x1ee, we need 3 such a registers for HT-PHY
+ */
+ }
+ b43_phy_mask(dev, B43_PHY_HT_TXPCTL_CMD_C1, ~en_bits);
+ } else {
+ b43_phy_set(dev, B43_PHY_HT_TXPCTL_CMD_C1, en_bits);
+
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) {
+ for (i = 0; i < 3; i++)
+ b43_phy_write(dev, cmd_regs[i], 0x32);
+ }
+
+ for (i = 0; i < 3; i++)
+ if (phy_ht->tx_pwr_idx[i] <=
+ B43_PHY_HT_TXPCTL_CMD_C1_INIT)
+ b43_phy_write(dev, cmd_regs[i],
+ phy_ht->tx_pwr_idx[i]);
+ }
+
+ phy_ht->tx_pwr_ctl = enable;
+}
+
+static void b43_phy_ht_tx_power_ctl_idle_tssi(struct b43_wldev *dev)
+{
+ struct b43_phy_ht *phy_ht = dev->phy.ht;
+ s32 rssi_buf[6];
+
+ /* TODO */
+
+ b43_phy_ht_tx_tone(dev);
+ udelay(20);
+ b43_phy_ht_poll_rssi(dev, 4, rssi_buf, 1);
+ b43_phy_ht_stop_playback(dev);
+ b43_phy_ht_reset_cca(dev);
+
+ phy_ht->idle_tssi[0] = rssi_buf[0] & 0xff;
+ phy_ht->idle_tssi[1] = rssi_buf[2] & 0xff;
+ phy_ht->idle_tssi[2] = rssi_buf[4] & 0xff;
+
+ /* TODO */
+}
+
+static void b43_phy_ht_tx_power_ctl_setup(struct b43_wldev *dev)
+{
+ struct b43_phy_ht *phy_ht = dev->phy.ht;
+ struct ssb_sprom *sprom = dev->dev->bus_sprom;
+
+ u8 *idle = phy_ht->idle_tssi;
+ u8 target[3];
+ s16 a1[3], b0[3], b1[3];
+
+ u16 freq = dev->phy.channel_freq;
+ int i, c;
+
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
+ for (c = 0; c < 3; c++) {
+ target[c] = sprom->core_pwr_info[c].maxpwr_2g;
+ a1[c] = sprom->core_pwr_info[c].pa_2g[0];
+ b0[c] = sprom->core_pwr_info[c].pa_2g[1];
+ b1[c] = sprom->core_pwr_info[c].pa_2g[2];
+ }
+ } else if (freq >= 4900 && freq < 5100) {
+ for (c = 0; c < 3; c++) {
+ target[c] = sprom->core_pwr_info[c].maxpwr_5gl;
+ a1[c] = sprom->core_pwr_info[c].pa_5gl[0];
+ b0[c] = sprom->core_pwr_info[c].pa_5gl[1];
+ b1[c] = sprom->core_pwr_info[c].pa_5gl[2];
+ }
+ } else if (freq >= 5100 && freq < 5500) {
+ for (c = 0; c < 3; c++) {
+ target[c] = sprom->core_pwr_info[c].maxpwr_5g;
+ a1[c] = sprom->core_pwr_info[c].pa_5g[0];
+ b0[c] = sprom->core_pwr_info[c].pa_5g[1];
+ b1[c] = sprom->core_pwr_info[c].pa_5g[2];
+ }
+ } else if (freq >= 5500) {
+ for (c = 0; c < 3; c++) {
+ target[c] = sprom->core_pwr_info[c].maxpwr_5gh;
+ a1[c] = sprom->core_pwr_info[c].pa_5gh[0];
+ b0[c] = sprom->core_pwr_info[c].pa_5gh[1];
+ b1[c] = sprom->core_pwr_info[c].pa_5gh[2];
+ }
+ } else {
+ target[0] = target[1] = target[2] = 52;
+ a1[0] = a1[1] = a1[2] = -424;
+ b0[0] = b0[1] = b0[2] = 5612;
+ b1[0] = b1[1] = b1[2] = -1393;
+ }
+
+ b43_phy_set(dev, B43_PHY_HT_TSSIMODE, B43_PHY_HT_TSSIMODE_EN);
+ b43_phy_mask(dev, B43_PHY_HT_TXPCTL_CMD_C1,
+ ~B43_PHY_HT_TXPCTL_CMD_C1_PCTLEN & 0xFFFF);
+
+ /* TODO: Does it depend on sprom->fem.ghz2.tssipos? */
+ b43_phy_set(dev, B43_PHY_HT_TXPCTL_IDLE_TSSI, 0x4000);
+
+ b43_phy_maskset(dev, B43_PHY_HT_TXPCTL_CMD_C1,
+ ~B43_PHY_HT_TXPCTL_CMD_C1_INIT, 0x19);
+ b43_phy_maskset(dev, B43_PHY_HT_TXPCTL_CMD_C2,
+ ~B43_PHY_HT_TXPCTL_CMD_C2_INIT, 0x19);
+ b43_phy_maskset(dev, B43_PHY_HT_TXPCTL_CMD_C3,
+ ~B43_PHY_HT_TXPCTL_CMD_C3_INIT, 0x19);
+
+ b43_phy_set(dev, B43_PHY_HT_TXPCTL_IDLE_TSSI,
+ B43_PHY_HT_TXPCTL_IDLE_TSSI_BINF);
+
+ b43_phy_maskset(dev, B43_PHY_HT_TXPCTL_IDLE_TSSI,
+ ~B43_PHY_HT_TXPCTL_IDLE_TSSI_C1,
+ idle[0] << B43_PHY_HT_TXPCTL_IDLE_TSSI_C1_SHIFT);
+ b43_phy_maskset(dev, B43_PHY_HT_TXPCTL_IDLE_TSSI,
+ ~B43_PHY_HT_TXPCTL_IDLE_TSSI_C2,
+ idle[1] << B43_PHY_HT_TXPCTL_IDLE_TSSI_C2_SHIFT);
+ b43_phy_maskset(dev, B43_PHY_HT_TXPCTL_IDLE_TSSI2,
+ ~B43_PHY_HT_TXPCTL_IDLE_TSSI2_C3,
+ idle[2] << B43_PHY_HT_TXPCTL_IDLE_TSSI2_C3_SHIFT);
+
+ b43_phy_maskset(dev, B43_PHY_HT_TXPCTL_N, ~B43_PHY_HT_TXPCTL_N_TSSID,
+ 0xf0);
+ b43_phy_maskset(dev, B43_PHY_HT_TXPCTL_N, ~B43_PHY_HT_TXPCTL_N_NPTIL2,
+ 0x3 << B43_PHY_HT_TXPCTL_N_NPTIL2_SHIFT);
+#if 0
+ /* TODO: what to mask/set? */
+ b43_phy_maskset(dev, B43_PHY_HT_TXPCTL_CMD_C1, 0x800, 0)
+ b43_phy_maskset(dev, B43_PHY_HT_TXPCTL_CMD_C1, 0x400, 0)
+#endif
+
+ b43_phy_maskset(dev, B43_PHY_HT_TXPCTL_TARG_PWR,
+ ~B43_PHY_HT_TXPCTL_TARG_PWR_C1,
+ target[0] << B43_PHY_HT_TXPCTL_TARG_PWR_C1_SHIFT);
+ b43_phy_maskset(dev, B43_PHY_HT_TXPCTL_TARG_PWR,
+ ~B43_PHY_HT_TXPCTL_TARG_PWR_C2 & 0xFFFF,
+ target[1] << B43_PHY_HT_TXPCTL_TARG_PWR_C2_SHIFT);
+ b43_phy_maskset(dev, B43_PHY_HT_TXPCTL_TARG_PWR2,
+ ~B43_PHY_HT_TXPCTL_TARG_PWR2_C3,
+ target[2] << B43_PHY_HT_TXPCTL_TARG_PWR2_C3_SHIFT);
+
+ for (c = 0; c < 3; c++) {
+ s32 num, den, pwr;
+ u32 regval[64];
+
+ for (i = 0; i < 64; i++) {
+ num = 8 * (16 * b0[c] + b1[c] * i);
+ den = 32768 + a1[c] * i;
+ pwr = max((4 * num + den / 2) / den, -8);
+ regval[i] = pwr;
+ }
+ b43_httab_write_bulk(dev, B43_HTTAB16(26 + c, 0), 64, regval);
+ }
+}
+
+/**************************************************
* Channel switching ops.
**************************************************/
+static void b43_phy_ht_spur_avoid(struct b43_wldev *dev,
+ struct ieee80211_channel *new_channel)
+{
+ struct bcma_device *core = dev->dev->bdev;
+ int spuravoid = 0;
+ u16 tmp;
+
+ /* Check for 13 and 14 is just a guess, we don't have enough logs. */
+ if (new_channel->hw_value == 13 || new_channel->hw_value == 14)
+ spuravoid = 1;
+ bcma_core_pll_ctl(core, B43_BCMA_CLKCTLST_PHY_PLL_REQ, 0, false);
+ bcma_pmu_spuravoid_pllupdate(&core->bus->drv_cc, spuravoid);
+ bcma_core_pll_ctl(core,
+ B43_BCMA_CLKCTLST_80211_PLL_REQ |
+ B43_BCMA_CLKCTLST_PHY_PLL_REQ,
+ B43_BCMA_CLKCTLST_80211_PLL_ST |
+ B43_BCMA_CLKCTLST_PHY_PLL_ST, false);
+
+ /* Values has been taken from wlc_bmac_switch_macfreq comments */
+ switch (spuravoid) {
+ case 2: /* 126MHz */
+ tmp = 0x2082;
+ break;
+ case 1: /* 123MHz */
+ tmp = 0x5341;
+ break;
+ default: /* 120MHz */
+ tmp = 0x8889;
+ }
+
+ b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, tmp);
+ b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0x8);
+
+ /* TODO: reset PLL */
+
+ if (spuravoid)
+ b43_phy_set(dev, B43_PHY_HT_BBCFG, B43_PHY_HT_BBCFG_RSTRX);
+ else
+ b43_phy_mask(dev, B43_PHY_HT_BBCFG,
+ ~B43_PHY_HT_BBCFG_RSTRX & 0xFFFF);
+
+ b43_phy_ht_reset_cca(dev);
+}
+
static void b43_phy_ht_channel_setup(struct b43_wldev *dev,
const struct b43_phy_ht_channeltab_e_phy *e,
struct ieee80211_channel *new_channel)
{
bool old_band_5ghz;
- u8 i;
old_band_5ghz = b43_phy_read(dev, B43_PHY_HT_BANDCTL) & 0; /* FIXME */
if (new_channel->band == IEEE80211_BAND_5GHZ && !old_band_5ghz) {
@@ -264,25 +729,20 @@ static void b43_phy_ht_channel_setup(struct b43_wldev *dev,
b43_phy_write(dev, B43_PHY_HT_BW5, e->bw5);
b43_phy_write(dev, B43_PHY_HT_BW6, e->bw6);
- /* TODO: some ops on PHY regs 0x0B0 and 0xC0A */
+ if (new_channel->hw_value == 14) {
+ b43_phy_ht_classifier(dev, B43_PHY_HT_CLASS_CTL_OFDM_EN, 0);
+ b43_phy_set(dev, B43_PHY_HT_TEST, 0x0800);
+ } else {
+ b43_phy_ht_classifier(dev, B43_PHY_HT_CLASS_CTL_OFDM_EN,
+ B43_PHY_HT_CLASS_CTL_OFDM_EN);
+ if (new_channel->band == IEEE80211_BAND_2GHZ)
+ b43_phy_mask(dev, B43_PHY_HT_TEST, ~0x840);
+ }
- /* TODO: separated function? */
- for (i = 0; i < 3; i++) {
- u16 mask;
- u32 tmp = b43_httab_read(dev, B43_HTTAB32(26, 0xE8));
+ if (1) /* TODO: On N it's for early devices only, what about HT? */
+ b43_phy_ht_tx_power_fix(dev);
- if (0) /* FIXME */
- mask = 0x2 << (i * 4);
- else
- mask = 0;
- b43_phy_mask(dev, B43_PHY_EXTG(0x108), mask);
-
- b43_httab_write(dev, B43_HTTAB16(7, 0x110 + i), tmp >> 16);
- b43_httab_write(dev, B43_HTTAB8(13, 0x63 + (i * 4)),
- tmp & 0xFF);
- b43_httab_write(dev, B43_HTTAB8(13, 0x73 + (i * 4)),
- tmp & 0xFF);
- }
+ b43_phy_ht_spur_avoid(dev, new_channel);
b43_phy_write(dev, 0x017e, 0x3830);
}
@@ -337,14 +797,29 @@ static void b43_phy_ht_op_prepare_structs(struct b43_wldev *dev)
{
struct b43_phy *phy = &dev->phy;
struct b43_phy_ht *phy_ht = phy->ht;
+ int i;
memset(phy_ht, 0, sizeof(*phy_ht));
+
+ phy_ht->tx_pwr_ctl = true;
+ for (i = 0; i < 3; i++)
+ phy_ht->tx_pwr_idx[i] = B43_PHY_HT_TXPCTL_CMD_C1_INIT + 1;
+
+ for (i = 0; i < 3; i++)
+ phy_ht->bb_mult_save[i] = -1;
}
static int b43_phy_ht_op_init(struct b43_wldev *dev)
{
+ struct b43_phy_ht *phy_ht = dev->phy.ht;
u16 tmp;
u16 clip_state[3];
+ bool saved_tx_pwr_ctl;
+
+ if (dev->dev->bus_type != B43_BUS_BCMA) {
+ b43err(dev->wl, "HT-PHY is supported only on BCMA bus!\n");
+ return -EOPNOTSUPP;
+ }
b43_phy_ht_tables_init(dev);
@@ -357,9 +832,9 @@ static int b43_phy_ht_op_init(struct b43_wldev *dev)
b43_phy_mask(dev, B43_PHY_EXTG(0), ~0x3);
- b43_phy_write(dev, B43_PHY_HT_AFE_CTL1, 0);
- b43_phy_write(dev, B43_PHY_HT_AFE_CTL3, 0);
- b43_phy_write(dev, B43_PHY_HT_AFE_CTL5, 0);
+ b43_phy_write(dev, B43_PHY_HT_AFE_C1_OVER, 0);
+ b43_phy_write(dev, B43_PHY_HT_AFE_C2_OVER, 0);
+ b43_phy_write(dev, B43_PHY_HT_AFE_C3_OVER, 0);
b43_phy_write(dev, B43_PHY_EXTG(0x103), 0x20);
b43_phy_write(dev, B43_PHY_EXTG(0x101), 0x20);
@@ -371,8 +846,11 @@ static int b43_phy_ht_op_init(struct b43_wldev *dev)
if (0) /* TODO: condition */
; /* TODO: PHY op on reg 0x217 */
- b43_phy_read(dev, 0xb0); /* TODO: what for? */
- b43_phy_set(dev, 0xb0, 0x1);
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ)
+ b43_phy_ht_classifier(dev, B43_PHY_HT_CLASS_CTL_CCK_EN, 0);
+ else
+ b43_phy_ht_classifier(dev, B43_PHY_HT_CLASS_CTL_CCK_EN,
+ B43_PHY_HT_CLASS_CTL_CCK_EN);
b43_phy_set(dev, 0xb1, 0x91);
b43_phy_write(dev, 0x32f, 0x0003);
@@ -448,12 +926,13 @@ static int b43_phy_ht_op_init(struct b43_wldev *dev)
b43_mac_phy_clock_set(dev, true);
+ b43_phy_ht_pa_override(dev, false);
b43_phy_ht_force_rf_sequence(dev, B43_PHY_HT_RF_SEQ_TRIG_RX2TX);
b43_phy_ht_force_rf_sequence(dev, B43_PHY_HT_RF_SEQ_TRIG_RST2RX);
-
- /* TODO: PHY op on reg 0xb0 */
+ b43_phy_ht_pa_override(dev, true);
/* TODO: Should we restore it? Or store it in global PHY info? */
+ b43_phy_ht_classifier(dev, 0, 0);
b43_phy_ht_read_clip_detection(dev, clip_state);
if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
@@ -462,6 +941,13 @@ static int b43_phy_ht_op_init(struct b43_wldev *dev)
b43_httab_write_bulk(dev, B43_HTTAB32(0x1a, 0xc0),
B43_HTTAB_1A_C0_LATE_SIZE, b43_httab_0x1a_0xc0_late);
+ saved_tx_pwr_ctl = phy_ht->tx_pwr_ctl;
+ b43_phy_ht_tx_power_fix(dev);
+ b43_phy_ht_tx_power_ctl(dev, false);
+ b43_phy_ht_tx_power_ctl_idle_tssi(dev);
+ b43_phy_ht_tx_power_ctl_setup(dev);
+ b43_phy_ht_tx_power_ctl(dev, saved_tx_pwr_ctl);
+
return 0;
}
@@ -506,19 +992,19 @@ static void b43_phy_ht_op_software_rfkill(struct b43_wldev *dev,
static void b43_phy_ht_op_switch_analog(struct b43_wldev *dev, bool on)
{
if (on) {
- b43_phy_write(dev, B43_PHY_HT_AFE_CTL2, 0x00cd);
- b43_phy_write(dev, B43_PHY_HT_AFE_CTL1, 0x0000);
- b43_phy_write(dev, B43_PHY_HT_AFE_CTL4, 0x00cd);
- b43_phy_write(dev, B43_PHY_HT_AFE_CTL3, 0x0000);
- b43_phy_write(dev, B43_PHY_HT_AFE_CTL6, 0x00cd);
- b43_phy_write(dev, B43_PHY_HT_AFE_CTL5, 0x0000);
+ b43_phy_write(dev, B43_PHY_HT_AFE_C1, 0x00cd);
+ b43_phy_write(dev, B43_PHY_HT_AFE_C1_OVER, 0x0000);
+ b43_phy_write(dev, B43_PHY_HT_AFE_C2, 0x00cd);
+ b43_phy_write(dev, B43_PHY_HT_AFE_C2_OVER, 0x0000);
+ b43_phy_write(dev, B43_PHY_HT_AFE_C3, 0x00cd);
+ b43_phy_write(dev, B43_PHY_HT_AFE_C3_OVER, 0x0000);
} else {
- b43_phy_write(dev, B43_PHY_HT_AFE_CTL1, 0x07ff);
- b43_phy_write(dev, B43_PHY_HT_AFE_CTL2, 0x00fd);
- b43_phy_write(dev, B43_PHY_HT_AFE_CTL3, 0x07ff);
- b43_phy_write(dev, B43_PHY_HT_AFE_CTL4, 0x00fd);
- b43_phy_write(dev, B43_PHY_HT_AFE_CTL5, 0x07ff);
- b43_phy_write(dev, B43_PHY_HT_AFE_CTL6, 0x00fd);
+ b43_phy_write(dev, B43_PHY_HT_AFE_C1_OVER, 0x07ff);
+ b43_phy_write(dev, B43_PHY_HT_AFE_C1, 0x00fd);
+ b43_phy_write(dev, B43_PHY_HT_AFE_C2_OVER, 0x07ff);
+ b43_phy_write(dev, B43_PHY_HT_AFE_C2, 0x00fd);
+ b43_phy_write(dev, B43_PHY_HT_AFE_C3_OVER, 0x07ff);
+ b43_phy_write(dev, B43_PHY_HT_AFE_C3, 0x00fd);
}
}
diff --git a/drivers/net/wireless/b43/phy_ht.h b/drivers/net/wireless/b43/phy_ht.h
index 6544c4293b3..9b2408efb22 100644
--- a/drivers/net/wireless/b43/phy_ht.h
+++ b/drivers/net/wireless/b43/phy_ht.h
@@ -12,18 +12,60 @@
#define B43_PHY_HT_TABLE_ADDR 0x072 /* Table address */
#define B43_PHY_HT_TABLE_DATALO 0x073 /* Table data low */
#define B43_PHY_HT_TABLE_DATAHI 0x074 /* Table data high */
+#define B43_PHY_HT_CLASS_CTL 0x0B0 /* Classifier control */
+#define B43_PHY_HT_CLASS_CTL_CCK_EN 0x0001 /* CCK enable */
+#define B43_PHY_HT_CLASS_CTL_OFDM_EN 0x0002 /* OFDM enable */
+#define B43_PHY_HT_CLASS_CTL_WAITED_EN 0x0004 /* Waited enable */
+#define B43_PHY_HT_IQLOCAL_CMDGCTL 0x0C2 /* I/Q LO cal command G control */
+#define B43_PHY_HT_SAMP_CMD 0x0C3 /* Sample command */
+#define B43_PHY_HT_SAMP_CMD_STOP 0x0002 /* Stop */
+#define B43_PHY_HT_SAMP_LOOP_CNT 0x0C4 /* Sample loop count */
+#define B43_PHY_HT_SAMP_WAIT_CNT 0x0C5 /* Sample wait count */
+#define B43_PHY_HT_SAMP_DEP_CNT 0x0C6 /* Sample depth count */
+#define B43_PHY_HT_SAMP_STAT 0x0C7 /* Sample status */
+#define B43_PHY_HT_TSSIMODE 0x122 /* TSSI mode */
+#define B43_PHY_HT_TSSIMODE_EN 0x0001 /* TSSI enable */
+#define B43_PHY_HT_TSSIMODE_PDEN 0x0002 /* Power det enable */
#define B43_PHY_HT_BW1 0x1CE
#define B43_PHY_HT_BW2 0x1CF
#define B43_PHY_HT_BW3 0x1D0
#define B43_PHY_HT_BW4 0x1D1
#define B43_PHY_HT_BW5 0x1D2
#define B43_PHY_HT_BW6 0x1D3
+#define B43_PHY_HT_TXPCTL_CMD_C1 0x1E7 /* TX power control command */
+#define B43_PHY_HT_TXPCTL_CMD_C1_INIT 0x007F /* Init */
+#define B43_PHY_HT_TXPCTL_CMD_C1_COEFF 0x2000 /* Power control coefficients */
+#define B43_PHY_HT_TXPCTL_CMD_C1_HWPCTLEN 0x4000 /* Hardware TX power control enable */
+#define B43_PHY_HT_TXPCTL_CMD_C1_PCTLEN 0x8000 /* TX power control enable */
+#define B43_PHY_HT_TXPCTL_N 0x1E8 /* TX power control N num */
+#define B43_PHY_HT_TXPCTL_N_TSSID 0x00FF /* N TSSI delay */
+#define B43_PHY_HT_TXPCTL_N_TSSID_SHIFT 0
+#define B43_PHY_HT_TXPCTL_N_NPTIL2 0x0700 /* N PT integer log2 */
+#define B43_PHY_HT_TXPCTL_N_NPTIL2_SHIFT 8
+#define B43_PHY_HT_TXPCTL_IDLE_TSSI 0x1E9 /* TX power control idle TSSI */
+#define B43_PHY_HT_TXPCTL_IDLE_TSSI_C1 0x003F
+#define B43_PHY_HT_TXPCTL_IDLE_TSSI_C1_SHIFT 0
+#define B43_PHY_HT_TXPCTL_IDLE_TSSI_C2 0x3F00
+#define B43_PHY_HT_TXPCTL_IDLE_TSSI_C2_SHIFT 8
+#define B43_PHY_HT_TXPCTL_IDLE_TSSI_BINF 0x8000 /* Raw TSSI offset bin format */
+#define B43_PHY_HT_TXPCTL_TARG_PWR 0x1EA /* TX power control target power */
+#define B43_PHY_HT_TXPCTL_TARG_PWR_C1 0x00FF /* Power 0 */
+#define B43_PHY_HT_TXPCTL_TARG_PWR_C1_SHIFT 0
+#define B43_PHY_HT_TXPCTL_TARG_PWR_C2 0xFF00 /* Power 1 */
+#define B43_PHY_HT_TXPCTL_TARG_PWR_C2_SHIFT 8
+#define B43_PHY_HT_TXPCTL_CMD_C2 0x222
+#define B43_PHY_HT_TXPCTL_CMD_C2_INIT 0x007F
+#define B43_PHY_HT_RSSI_C1 0x219
+#define B43_PHY_HT_RSSI_C2 0x21A
+#define B43_PHY_HT_RSSI_C3 0x21B
#define B43_PHY_HT_C1_CLIP1THRES B43_PHY_OFDM(0x00E)
#define B43_PHY_HT_C2_CLIP1THRES B43_PHY_OFDM(0x04E)
#define B43_PHY_HT_C3_CLIP1THRES B43_PHY_OFDM(0x08E)
#define B43_PHY_HT_RF_SEQ_MODE B43_PHY_EXTG(0x000)
+#define B43_PHY_HT_RF_SEQ_MODE_CA_OVER 0x0001 /* Core active override */
+#define B43_PHY_HT_RF_SEQ_MODE_TR_OVER 0x0002 /* Trigger override */
#define B43_PHY_HT_RF_SEQ_TRIG B43_PHY_EXTG(0x003)
#define B43_PHY_HT_RF_SEQ_TRIG_RX2TX 0x0001 /* RX2TX */
#define B43_PHY_HT_RF_SEQ_TRIG_TX2RX 0x0002 /* TX2RX */
@@ -36,12 +78,27 @@
#define B43_PHY_HT_RF_CTL1 B43_PHY_EXTG(0x010)
-#define B43_PHY_HT_AFE_CTL1 B43_PHY_EXTG(0x110)
-#define B43_PHY_HT_AFE_CTL2 B43_PHY_EXTG(0x111)
-#define B43_PHY_HT_AFE_CTL3 B43_PHY_EXTG(0x114)
-#define B43_PHY_HT_AFE_CTL4 B43_PHY_EXTG(0x115)
-#define B43_PHY_HT_AFE_CTL5 B43_PHY_EXTG(0x118)
-#define B43_PHY_HT_AFE_CTL6 B43_PHY_EXTG(0x119)
+#define B43_PHY_HT_RF_CTL_INT_C1 B43_PHY_EXTG(0x04c)
+#define B43_PHY_HT_RF_CTL_INT_C2 B43_PHY_EXTG(0x06c)
+#define B43_PHY_HT_RF_CTL_INT_C3 B43_PHY_EXTG(0x08c)
+
+#define B43_PHY_HT_AFE_C1_OVER B43_PHY_EXTG(0x110)
+#define B43_PHY_HT_AFE_C1 B43_PHY_EXTG(0x111)
+#define B43_PHY_HT_AFE_C2_OVER B43_PHY_EXTG(0x114)
+#define B43_PHY_HT_AFE_C2 B43_PHY_EXTG(0x115)
+#define B43_PHY_HT_AFE_C3_OVER B43_PHY_EXTG(0x118)
+#define B43_PHY_HT_AFE_C3 B43_PHY_EXTG(0x119)
+
+#define B43_PHY_HT_TXPCTL_CMD_C3 B43_PHY_EXTG(0x164)
+#define B43_PHY_HT_TXPCTL_CMD_C3_INIT 0x007F
+#define B43_PHY_HT_TXPCTL_IDLE_TSSI2 B43_PHY_EXTG(0x165) /* TX power control idle TSSI */
+#define B43_PHY_HT_TXPCTL_IDLE_TSSI2_C3 0x003F
+#define B43_PHY_HT_TXPCTL_IDLE_TSSI2_C3_SHIFT 0
+#define B43_PHY_HT_TXPCTL_TARG_PWR2 B43_PHY_EXTG(0x166) /* TX power control target power */
+#define B43_PHY_HT_TXPCTL_TARG_PWR2_C3 0x00FF
+#define B43_PHY_HT_TXPCTL_TARG_PWR2_C3_SHIFT 0
+
+#define B43_PHY_HT_TEST B43_PHY_N_BMODE(0x00A)
/* Values for PHY registers used on channel switching */
@@ -56,6 +113,14 @@ struct b43_phy_ht_channeltab_e_phy {
struct b43_phy_ht {
+ u16 rf_ctl_int_save[3];
+
+ bool tx_pwr_ctl;
+ u8 tx_pwr_idx[3];
+
+ s32 bb_mult_save[3];
+
+ u8 idle_tssi[3];
};