Hello,

Thank you for implementing BCM4331 support!

I am not interested in running the wireless-testing kernel, so I hacked
together a patch to enable BCM4331 support on linux-3.1-rc5.  Since
others may be interested in this as well, I am posting it to this list.

The patch consists of the following patches posted to this list:

[PATCH 1/3] b43: rename TX header formats
[PATCH 2/3] b43: use enum for firmware header format
[PATCH 3/3] b43: support new TX header, noticed to be used by 598.314+ fw
[PATCH 4/3 V2] b43: support new RX header, noticed to be used in 598.314+ fw
[PATCH V2] bcma: implement BCM4331 workaround for external PA lines
[PATCH 1/2] b43: include HT-PHY in some common code
[PATCH 2/2] b43: make forcing clock common (HT-PHY also uses that)
[RFC][PATCH] b43: HT-PHY: allow writing longer tables with a single call
[PATCH 1/4] b43: HT-PHY: init: zero EXTG registers
[PATCH 2/4] b43: HT-PHY: init: implement few simple PHY writes
[PATCH 3/4] b43: HT-PHY: init: copy tables and reset CCA
[PATCH V2 4/4] b43: HT-PHY: init: init BPHY and upload 0x1a table
[PATCH 1/2] b43: HT-PHY: init: add missing PHY mask/set ops
[PATCH 2/2] b43: HT-PHY: init: add some AFE (Analog Frontend) operation
[PATCH] b43: HT-PHY: init: add missing small-tables writes
[PATCH 1/2] b43: HT-PHY: use separated function for forcing RF sequence
[PATCH 2/2] b43: HT-PHY: read clip state
[wireless-next][PATCH 1/3] b43: Relax requirement for descriptors to be
in the DMA zone
[wireless-next][PATCH 2/3] b43: use 8K buffers for 64-bit DMA to
workaround hardware bug
[wireless-next][PATCH 3/3] b43: make HT-PHY support experimental

The combined patch is attached.  I can confirm that wireless now works
on my MacBookPro8,2.  Please let me know if I missed anything important.

Also, I would be interested in testing any patches that make the driver
work with BCM4331 after being suspended to RAM.

Regards,


-- 
Benjamin Lee
http://www.b1c1l1.com/
diff -ruN linux-3.1-rc5.orig/drivers/bcma/driver_chipcommon_pmu.c linux-3.1-rc5/drivers/bcma/driver_chipcommon_pmu.c
--- linux-3.1-rc5.orig/drivers/bcma/driver_chipcommon_pmu.c	2011-09-04 15:45:10.000000000 -0700
+++ linux-3.1-rc5/drivers/bcma/driver_chipcommon_pmu.c	2011-09-11 16:44:25.595409713 -0700
@@ -83,6 +83,24 @@
 	}
 }
 
+/* Disable to allow reading SPROM. Don't know the adventages of enabling it. */
+void bcma_chipco_bcm4331_ext_pa_lines_ctl(struct bcma_drv_cc *cc, bool enable)
+{
+	struct bcma_bus *bus = cc->core->bus;
+	u32 val;
+
+	val = bcma_cc_read32(cc, BCMA_CC_CHIPCTL);
+	if (enable) {
+		val |= BCMA_CHIPCTL_4331_EXTPA_EN;
+		if (bus->chipinfo.pkg == 9 || bus->chipinfo.pkg == 11)
+			val |= BCMA_CHIPCTL_4331_EXTPA_ON_GPIO2_5;
+	} else {
+		val &= ~BCMA_CHIPCTL_4331_EXTPA_EN;
+		val &= ~BCMA_CHIPCTL_4331_EXTPA_ON_GPIO2_5;
+	}
+	bcma_cc_write32(cc, BCMA_CC_CHIPCTL, val);
+}
+
 void bcma_pmu_workarounds(struct bcma_drv_cc *cc)
 {
 	struct bcma_bus *bus = cc->core->bus;
@@ -92,7 +110,7 @@
 		bcma_chipco_chipctl_maskset(cc, 0, ~0, 0x7);
 		break;
 	case 0x4331:
-		pr_err("Enabling Ext PA lines not implemented\n");
+		/* BCM4331 workaround is SPROM-related, we put it in sprom.c */
 		break;
 	case 43224:
 		if (bus->chipinfo.rev == 0) {
diff -ruN linux-3.1-rc5.orig/drivers/bcma/sprom.c linux-3.1-rc5/drivers/bcma/sprom.c
--- linux-3.1-rc5.orig/drivers/bcma/sprom.c	2011-09-04 15:45:10.000000000 -0700
+++ linux-3.1-rc5/drivers/bcma/sprom.c	2011-09-11 16:44:25.595409713 -0700
@@ -152,6 +152,9 @@
 	if (!sprom)
 		return -ENOMEM;
 
+	if (bus->chipinfo.id == 0x4331)
+		bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, false);
+
 	/* Most cards have SPROM moved by additional offset 0x30 (48 dwords).
 	 * According to brcm80211 this applies to cards with PCIe rev >= 6
 	 * TODO: understand this condition and use it */
@@ -159,6 +162,9 @@
 		BCMA_CC_SPROM_PCIE6;
 	bcma_sprom_read(bus, offset, sprom);
 
+	if (bus->chipinfo.id == 0x4331)
+		bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, true);
+
 	err = bcma_sprom_valid(sprom);
 	if (err)
 		goto out;
diff -ruN linux-3.1-rc5.orig/drivers/net/wireless/b43/Kconfig linux-3.1-rc5/drivers/net/wireless/b43/Kconfig
--- linux-3.1-rc5.orig/drivers/net/wireless/b43/Kconfig	2011-09-04 15:45:10.000000000 -0700
+++ linux-3.1-rc5/drivers/net/wireless/b43/Kconfig	2011-09-11 16:45:07.004360152 -0700
@@ -124,12 +124,12 @@
 	  (802.11a support is optional, and currently disabled).
 
 config B43_PHY_HT
-	bool "Support for HT-PHY devices (BROKEN)"
-	depends on B43 && BROKEN
+	bool "Support for HT-PHY (high throughput) devices (EXPERIMENTAL)"
+	depends on B43 && EXPERIMENTAL
 	---help---
 	  Support for the HT-PHY.
 
-	  Say N, this is BROKEN and crashes driver.
+	  Enables support for BCM4331 and possibly other chipsets with that PHY.
 
 config B43_PHY_LCN
 	bool "Support for LCN-PHY devices (BROKEN)"
diff -ruN linux-3.1-rc5.orig/drivers/net/wireless/b43/b43.h linux-3.1-rc5/drivers/net/wireless/b43/b43.h
--- linux-3.1-rc5.orig/drivers/net/wireless/b43/b43.h	2011-09-04 15:45:10.000000000 -0700
+++ linux-3.1-rc5/drivers/net/wireless/b43/b43.h	2011-09-11 16:44:18.745583091 -0700
@@ -694,6 +694,12 @@
 	enum b43_firmware_file_type type;
 };
 
+enum b43_firmware_hdr_format {
+	B43_FW_HDR_598,
+	B43_FW_HDR_410,
+	B43_FW_HDR_351,
+};
+
 /* Pointers to the firmware data and meta information about it. */
 struct b43_firmware {
 	/* Microcode */
@@ -710,6 +716,9 @@
 	/* Firmware patchlevel */
 	u16 patch;
 
+	/* Format of header used by firmware */
+	enum b43_firmware_hdr_format hdr_format;
+
 	/* Set to true, if we are using an opensource firmware.
 	 * Use this to check for proprietary vs opensource. */
 	bool opensource;
@@ -875,7 +884,7 @@
 	struct b43_leds leds;
 
 	/* Kmalloc'ed scratch space for PIO TX/RX. Protected by wl->mutex. */
-	u8 pio_scratchspace[110] __attribute__((__aligned__(8)));
+	u8 pio_scratchspace[118] __attribute__((__aligned__(8)));
 	u8 pio_tailspace[4] __attribute__((__aligned__(8)));
 };
 
diff -ruN linux-3.1-rc5.orig/drivers/net/wireless/b43/dma.c linux-3.1-rc5/drivers/net/wireless/b43/dma.c
--- linux-3.1-rc5.orig/drivers/net/wireless/b43/dma.c	2011-09-04 15:45:10.000000000 -0700
+++ linux-3.1-rc5/drivers/net/wireless/b43/dma.c	2011-09-11 16:45:02.524473816 -0700
@@ -389,33 +389,34 @@
 	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. Testing
-	 * has shown that 4K is sufficient for the latter as long as the buffer
-	 * does not cross an 8K boundary.
-	 *
-	 * For unknown reasons - possibly a hardware error - the BCM4311 rev
-	 * 02, which uses 64-bit DMA, needs the ring buffer in very low memory,
-	 * which accounts for the GFP_DMA flag below.
-	 *
-	 * The flags here must match the flags in free_ringmemory below!
+	 * alignment and 8K buffers for 64-bit DMA with 8K alignment.
+	 * In practice we could use smaller buffers for the latter, but the
+	 * alignment is really important because of the hardware bug. If bit
+	 * 0x00001000 is used in DMA address, some hardware (like BCM4331)
+	 * copies that bit into B43_DMA64_RXSTATUS and we get false values from
+	 * B43_DMA64_RXSTATDPTR. Let's just use 8K buffers even if we don't use
+	 * more than 256 slots for ring.
 	 */
-	if (ring->type == B43_DMA_64BIT)
-		flags |= GFP_DMA;
+	u16 ring_mem_size = (ring->type == B43_DMA_64BIT) ?
+				B43_DMA64_RINGMEMSIZE : B43_DMA32_RINGMEMSIZE;
+
 	ring->descbase = dma_alloc_coherent(ring->dev->dev->dma_dev,
-					    B43_DMA_RINGMEMSIZE,
-					    &(ring->dmabase), flags);
+					    ring_mem_size, &(ring->dmabase),
+					    flags);
 	if (!ring->descbase) {
 		b43err(ring->dev->wl, "DMA ringmemory allocation failed\n");
 		return -ENOMEM;
 	}
-	memset(ring->descbase, 0, B43_DMA_RINGMEMSIZE);
+	memset(ring->descbase, 0, ring_mem_size);
 
 	return 0;
 }
 
 static void free_ringmemory(struct b43_dmaring *ring)
 {
-	dma_free_coherent(ring->dev->dev->dma_dev, B43_DMA_RINGMEMSIZE,
+	u16 ring_mem_size = (ring->type == B43_DMA_64BIT) ?
+				B43_DMA64_RINGMEMSIZE : B43_DMA32_RINGMEMSIZE;
+	dma_free_coherent(ring->dev->dev->dma_dev, ring_mem_size,
 			  ring->descbase, ring->dmabase);
 }
 
@@ -872,8 +873,17 @@
 		ring->current_slot = -1;
 	} else {
 		if (ring->index == 0) {
-			ring->rx_buffersize = B43_DMA0_RX_BUFFERSIZE;
-			ring->frameoffset = B43_DMA0_RX_FRAMEOFFSET;
+			switch (dev->fw.hdr_format) {
+			case B43_FW_HDR_598:
+				ring->rx_buffersize = B43_DMA0_RX_FW598_BUFSIZE;
+				ring->frameoffset = B43_DMA0_RX_FW598_FO;
+				break;
+			case B43_FW_HDR_410:
+			case B43_FW_HDR_351:
+				ring->rx_buffersize = B43_DMA0_RX_FW351_BUFSIZE;
+				ring->frameoffset = B43_DMA0_RX_FW351_FO;
+				break;
+			}
 		} else
 			B43_WARN_ON(1);
 	}
diff -ruN linux-3.1-rc5.orig/drivers/net/wireless/b43/dma.h linux-3.1-rc5/drivers/net/wireless/b43/dma.h
--- linux-3.1-rc5.orig/drivers/net/wireless/b43/dma.h	2011-09-04 15:45:10.000000000 -0700
+++ linux-3.1-rc5/drivers/net/wireless/b43/dma.h	2011-09-11 16:45:02.524473816 -0700
@@ -161,13 +161,17 @@
 } __packed;
 
 /* Misc DMA constants */
-#define B43_DMA_RINGMEMSIZE		PAGE_SIZE
-#define B43_DMA0_RX_FRAMEOFFSET		30
+#define B43_DMA32_RINGMEMSIZE		4096
+#define B43_DMA64_RINGMEMSIZE		8192
+/* Offset of frame with actual data */
+#define B43_DMA0_RX_FW598_FO		38
+#define B43_DMA0_RX_FW351_FO		30
 
 /* DMA engine tuning knobs */
 #define B43_TXRING_SLOTS		256
 #define B43_RXRING_SLOTS		64
-#define B43_DMA0_RX_BUFFERSIZE		(B43_DMA0_RX_FRAMEOFFSET + IEEE80211_MAX_FRAME_LEN)
+#define B43_DMA0_RX_FW598_BUFSIZE	(B43_DMA0_RX_FW598_FO + IEEE80211_MAX_FRAME_LEN)
+#define B43_DMA0_RX_FW351_BUFSIZE	(B43_DMA0_RX_FW351_FO + IEEE80211_MAX_FRAME_LEN)
 
 /* Pointer poison */
 #define B43_DMA_PTR_POISON		((void *)ERR_PTR(-ENOMEM))
diff -ruN linux-3.1-rc5.orig/drivers/net/wireless/b43/main.c linux-3.1-rc5/drivers/net/wireless/b43/main.c
--- linux-3.1-rc5.orig/drivers/net/wireless/b43/main.c	2011-09-04 15:45:10.000000000 -0700
+++ linux-3.1-rc5/drivers/net/wireless/b43/main.c	2011-09-11 16:44:35.375162052 -0700
@@ -2510,6 +2510,12 @@
 	}
 	dev->fw.rev = fwrev;
 	dev->fw.patch = fwpatch;
+	if (dev->fw.rev >= 598)
+		dev->fw.hdr_format = B43_FW_HDR_598;
+	else if (dev->fw.rev >= 410)
+		dev->fw.hdr_format = B43_FW_HDR_410;
+	else
+		dev->fw.hdr_format = B43_FW_HDR_351;
 	dev->fw.opensource = (fwdate == 0xFFFF);
 
 	/* Default to use-all-queues. */
@@ -2557,7 +2563,7 @@
 			dev->fw.rev, dev->fw.patch);
 	wiphy->hw_version = dev->dev->core_id;
 
-	if (b43_is_old_txhdr_format(dev)) {
+	if (dev->fw.hdr_format == B43_FW_HDR_351) {
 		/* We're over the deadline, but we keep support for old fw
 		 * until it turns out to be in major conflict with something new. */
 		b43warn(dev->wl, "You are using an old firmware image. "
@@ -2943,6 +2949,7 @@
 	case B43_PHYTYPE_G:
 	case B43_PHYTYPE_N:
 	case B43_PHYTYPE_LP:
+	case B43_PHYTYPE_HT:
 		b43_rate_memory_write(dev, B43_OFDM_RATE_6MB, 1);
 		b43_rate_memory_write(dev, B43_OFDM_RATE_12MB, 1);
 		b43_rate_memory_write(dev, B43_OFDM_RATE_18MB, 1);
diff -ruN linux-3.1-rc5.orig/drivers/net/wireless/b43/phy_common.c linux-3.1-rc5/drivers/net/wireless/b43/phy_common.c
--- linux-3.1-rc5.orig/drivers/net/wireless/b43/phy_common.c	2011-09-04 15:45:10.000000000 -0700
+++ linux-3.1-rc5/drivers/net/wireless/b43/phy_common.c	2011-09-11 16:44:37.435109868 -0700
@@ -448,6 +448,38 @@
 		channel_type == NL80211_CHAN_HT40PLUS);
 }
 
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/BmacPhyClkFgc */
+void b43_phy_force_clock(struct b43_wldev *dev, bool force)
+{
+	u32 tmp;
+
+	WARN_ON(dev->phy.type != B43_PHYTYPE_N &&
+		dev->phy.type != B43_PHYTYPE_HT);
+
+	switch (dev->dev->bus_type) {
+#ifdef CONFIG_B43_BCMA
+	case B43_BUS_BCMA:
+		tmp = bcma_aread32(dev->dev->bdev, BCMA_IOCTL);
+		if (force)
+			tmp |= BCMA_IOCTL_FGC;
+		else
+			tmp &= ~BCMA_IOCTL_FGC;
+		bcma_awrite32(dev->dev->bdev, BCMA_IOCTL, tmp);
+		break;
+#endif
+#ifdef CONFIG_B43_SSB
+	case B43_BUS_SSB:
+		tmp = ssb_read32(dev->dev->sdev, SSB_TMSLOW);
+		if (force)
+			tmp |= SSB_TMSLOW_FGC;
+		else
+			tmp &= ~SSB_TMSLOW_FGC;
+		ssb_write32(dev->dev->sdev, SSB_TMSLOW, tmp);
+		break;
+#endif
+	}
+}
+
 /* http://bcm-v4.sipsolutions.net/802.11/PHY/Cordic */
 struct b43_c32 b43_cordic(int theta)
 {
diff -ruN linux-3.1-rc5.orig/drivers/net/wireless/b43/phy_common.h linux-3.1-rc5/drivers/net/wireless/b43/phy_common.h
--- linux-3.1-rc5.orig/drivers/net/wireless/b43/phy_common.h	2011-09-04 15:45:10.000000000 -0700
+++ linux-3.1-rc5/drivers/net/wireless/b43/phy_common.h	2011-09-11 16:44:37.435109868 -0700
@@ -444,6 +444,8 @@
 
 bool b43_channel_type_is_40mhz(enum nl80211_channel_type channel_type);
 
+void b43_phy_force_clock(struct b43_wldev *dev, bool force);
+
 struct b43_c32 b43_cordic(int theta);
 
 #endif /* LINUX_B43_PHY_COMMON_H_ */
diff -ruN linux-3.1-rc5.orig/drivers/net/wireless/b43/phy_ht.c linux-3.1-rc5/drivers/net/wireless/b43/phy_ht.c
--- linux-3.1-rc5.orig/drivers/net/wireless/b43/phy_ht.c	2011-09-04 15:45:10.000000000 -0700
+++ linux-3.1-rc5/drivers/net/wireless/b43/phy_ht.c	2011-09-11 16:59:36.266832596 -0700
@@ -152,6 +152,92 @@
 }
 
 /**************************************************
+ * Various PHY ops
+ **************************************************/
+
+static void b43_phy_ht_zero_extg(struct b43_wldev *dev)
+{
+	u8 i, j;
+	u16 base[] = { 0x40, 0x60, 0x80 };
+
+	for (i = 0; i < ARRAY_SIZE(base); i++) {
+		for (j = 0; j < 4; j++)
+			b43_phy_write(dev, B43_PHY_EXTG(base[i] + j), 0);
+	}
+
+	for (i = 0; i < ARRAY_SIZE(base); i++)
+		b43_phy_write(dev, B43_PHY_EXTG(base[i] + 0xc), 0);
+}
+
+/* Some unknown AFE (Analog Frondned) op */
+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},
+	};
+
+	for (i = 0; i < 3; i++) {
+		/* TODO: verify masks&sets */
+		b43_phy_set(dev, ctl_regs[i][1], 0x4);
+		b43_phy_set(dev, ctl_regs[i][0], 0x4);
+		b43_phy_mask(dev, ctl_regs[i][1], ~0x1);
+		b43_phy_set(dev, ctl_regs[i][0], 0x1);
+		b43_httab_write(dev, B43_HTTAB16(8, 5 + (i * 0x10)), 0);
+		b43_phy_mask(dev, ctl_regs[i][0], ~0x4);
+	}
+}
+
+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);
+	clip_st[1] = b43_phy_read(dev, B43_PHY_HT_C2_CLIP1THRES);
+	clip_st[2] = b43_phy_read(dev, B43_PHY_HT_C3_CLIP1THRES);
+}
+
+static void b43_phy_ht_bphy_init(struct b43_wldev *dev)
+{
+	unsigned int i;
+	u16 val;
+
+	val = 0x1E1F;
+	for (i = 0; i < 16; i++) {
+		b43_phy_write(dev, B43_PHY_N_BMODE(0x88 + i), val);
+		val -= 0x202;
+	}
+	val = 0x3E3F;
+	for (i = 0; i < 16; i++) {
+		b43_phy_write(dev, B43_PHY_N_BMODE(0x98 + i), val);
+		val -= 0x202;
+	}
+	b43_phy_write(dev, B43_PHY_N_BMODE(0x38), 0x668);
+}
+
+/**************************************************
  * Channel switching ops.
  **************************************************/
 
@@ -255,8 +341,125 @@
 
 static int b43_phy_ht_op_init(struct b43_wldev *dev)
 {
+	u16 tmp;
+	u16 clip_state[3];
+
 	b43_phy_ht_tables_init(dev);
 
+	b43_phy_mask(dev, 0x0be, ~0x2);
+	b43_phy_set(dev, 0x23f, 0x7ff);
+	b43_phy_set(dev, 0x240, 0x7ff);
+	b43_phy_set(dev, 0x241, 0x7ff);
+
+	b43_phy_ht_zero_extg(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_EXTG(0x103), 0x20);
+	b43_phy_write(dev, B43_PHY_EXTG(0x101), 0x20);
+	b43_phy_write(dev, 0x20d, 0xb8);
+	b43_phy_write(dev, B43_PHY_EXTG(0x14f), 0xc8);
+	b43_phy_write(dev, 0x70, 0x50);
+	b43_phy_write(dev, 0x1ff, 0x30);
+
+	if (0) /* TODO: condition */
+		; /* TODO: PHY op on reg 0x217 */
+
+	b43_phy_read(dev, 0xb0); /* TODO: what for? */
+	b43_phy_set(dev, 0xb0, 0x1);
+
+	b43_phy_set(dev, 0xb1, 0x91);
+	b43_phy_write(dev, 0x32f, 0x0003);
+	b43_phy_write(dev, 0x077, 0x0010);
+	b43_phy_write(dev, 0x0b4, 0x0258);
+	b43_phy_mask(dev, 0x17e, ~0x4000);
+
+	b43_phy_write(dev, 0x0b9, 0x0072);
+
+	b43_httab_write_few(dev, B43_HTTAB16(7, 0x14e), 2, 0x010f, 0x010f);
+	b43_httab_write_few(dev, B43_HTTAB16(7, 0x15e), 2, 0x010f, 0x010f);
+	b43_httab_write_few(dev, B43_HTTAB16(7, 0x16e), 2, 0x010f, 0x010f);
+
+	b43_phy_ht_afe_unk1(dev);
+
+	b43_httab_write_few(dev, B43_HTTAB16(7, 0x130), 9, 0x777, 0x111, 0x111,
+			    0x777, 0x111, 0x111, 0x777, 0x111, 0x111);
+
+	b43_httab_write(dev, B43_HTTAB16(7, 0x120), 0x0777);
+	b43_httab_write(dev, B43_HTTAB16(7, 0x124), 0x0777);
+
+	b43_httab_write(dev, B43_HTTAB16(8, 0x00), 0x02);
+	b43_httab_write(dev, B43_HTTAB16(8, 0x10), 0x02);
+	b43_httab_write(dev, B43_HTTAB16(8, 0x20), 0x02);
+
+	b43_httab_write_few(dev, B43_HTTAB16(8, 0x08), 4,
+			    0x8e, 0x96, 0x96, 0x96);
+	b43_httab_write_few(dev, B43_HTTAB16(8, 0x18), 4,
+			    0x8f, 0x9f, 0x9f, 0x9f);
+	b43_httab_write_few(dev, B43_HTTAB16(8, 0x28), 4,
+			    0x8f, 0x9f, 0x9f, 0x9f);
+
+	b43_httab_write_few(dev, B43_HTTAB16(8, 0x0c), 4, 0x2, 0x2, 0x2, 0x2);
+	b43_httab_write_few(dev, B43_HTTAB16(8, 0x1c), 4, 0x2, 0x2, 0x2, 0x2);
+	b43_httab_write_few(dev, B43_HTTAB16(8, 0x2c), 4, 0x2, 0x2, 0x2, 0x2);
+
+	b43_phy_maskset(dev, 0x0280, 0xff00, 0x3e);
+	b43_phy_maskset(dev, 0x0283, 0xff00, 0x3e);
+	b43_phy_maskset(dev, B43_PHY_OFDM(0x0141), 0xff00, 0x46);
+	b43_phy_maskset(dev, 0x0283, 0xff00, 0x40);
+
+	b43_httab_write_few(dev, B43_HTTAB16(00, 0x8), 4,
+			    0x09, 0x0e, 0x13, 0x18);
+	b43_httab_write_few(dev, B43_HTTAB16(01, 0x8), 4,
+			    0x09, 0x0e, 0x13, 0x18);
+	/* TODO: Did wl mean 2 instead of 40? */
+	b43_httab_write_few(dev, B43_HTTAB16(40, 0x8), 4,
+			    0x09, 0x0e, 0x13, 0x18);
+
+	b43_phy_maskset(dev, B43_PHY_OFDM(0x24), 0x3f, 0xd);
+	b43_phy_maskset(dev, B43_PHY_OFDM(0x64), 0x3f, 0xd);
+	b43_phy_maskset(dev, B43_PHY_OFDM(0xa4), 0x3f, 0xd);
+
+	b43_phy_set(dev, B43_PHY_EXTG(0x060), 0x1);
+	b43_phy_set(dev, B43_PHY_EXTG(0x064), 0x1);
+	b43_phy_set(dev, B43_PHY_EXTG(0x080), 0x1);
+	b43_phy_set(dev, B43_PHY_EXTG(0x084), 0x1);
+
+	/* Copy some tables entries */
+	tmp = b43_httab_read(dev, B43_HTTAB16(7, 0x144));
+	b43_httab_write(dev, B43_HTTAB16(7, 0x14a), tmp);
+	tmp = b43_httab_read(dev, B43_HTTAB16(7, 0x154));
+	b43_httab_write(dev, B43_HTTAB16(7, 0x15a), tmp);
+	tmp = b43_httab_read(dev, B43_HTTAB16(7, 0x164));
+	b43_httab_write(dev, B43_HTTAB16(7, 0x16a), tmp);
+
+	/* Reset CCA */
+	b43_phy_force_clock(dev, true);
+	tmp = b43_phy_read(dev, B43_PHY_HT_BBCFG);
+	b43_phy_write(dev, B43_PHY_HT_BBCFG, tmp | B43_PHY_HT_BBCFG_RSTCCA);
+	b43_phy_write(dev, B43_PHY_HT_BBCFG, tmp & ~B43_PHY_HT_BBCFG_RSTCCA);
+	b43_phy_force_clock(dev, false);
+
+	b43_mac_phy_clock_set(dev, true);
+
+	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 */
+
+	/* TODO: Should we restore it? Or store it in global PHY info? */
+	b43_phy_ht_read_clip_detection(dev, clip_state);
+
+	if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
+		b43_phy_ht_bphy_init(dev);
+
+	b43_httab_write_bulk(dev, B43_HTTAB32(0x1a, 0xc0),
+			B43_HTTAB_1A_C0_LATE_SIZE, b43_httab_0x1a_0xc0_late);
+
 	return 0;
 }
 
diff -ruN linux-3.1-rc5.orig/drivers/net/wireless/b43/phy_ht.h linux-3.1-rc5/drivers/net/wireless/b43/phy_ht.h
--- linux-3.1-rc5.orig/drivers/net/wireless/b43/phy_ht.h	2011-09-04 15:45:10.000000000 -0700
+++ linux-3.1-rc5/drivers/net/wireless/b43/phy_ht.h	2011-09-11 16:59:36.266832596 -0700
@@ -4,7 +4,11 @@
 #include "phy_common.h"
 
 
+#define B43_PHY_HT_BBCFG			0x001 /* BB config */
+#define  B43_PHY_HT_BBCFG_RSTCCA		0x4000 /* Reset CCA */
+#define  B43_PHY_HT_BBCFG_RSTRX			0x8000 /* Reset RX */
 #define B43_PHY_HT_BANDCTL			0x009 /* Band control */
+#define  B43_PHY_HT_BANDCTL_5GHZ		0x0001 /* Use the 5GHz band */
 #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 */
@@ -15,6 +19,21 @@
 #define B43_PHY_HT_BW5				0x1D2
 #define B43_PHY_HT_BW6				0x1D3
 
+#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_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 */
+#define  B43_PHY_HT_RF_SEQ_TRIG_UPGH		0x0004 /* Update gain H */
+#define  B43_PHY_HT_RF_SEQ_TRIG_UPGL		0x0008 /* Update gain L */
+#define  B43_PHY_HT_RF_SEQ_TRIG_UPGU		0x0010 /* Update gain U */
+#define  B43_PHY_HT_RF_SEQ_TRIG_RST2RX		0x0020 /* Reset to RX */
+#define B43_PHY_HT_RF_SEQ_STATUS		B43_PHY_EXTG(0x004)
+/* Values for the status are the same as for the trigger */
+
 #define B43_PHY_HT_RF_CTL1			B43_PHY_EXTG(0x010)
 
 #define B43_PHY_HT_AFE_CTL1			B43_PHY_EXTG(0x110)
diff -ruN linux-3.1-rc5.orig/drivers/net/wireless/b43/phy_n.c linux-3.1-rc5/drivers/net/wireless/b43/phy_n.c
--- linux-3.1-rc5.orig/drivers/net/wireless/b43/phy_n.c	2011-09-04 15:45:10.000000000 -0700
+++ linux-3.1-rc5/drivers/net/wireless/b43/phy_n.c	2011-09-11 16:44:37.435109868 -0700
@@ -600,49 +600,17 @@
 	}
 }
 
-/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/BmacPhyClkFgc */
-static void b43_nphy_bmac_clock_fgc(struct b43_wldev *dev, bool force)
-{
-	u32 tmp;
-
-	if (dev->phy.type != B43_PHYTYPE_N)
-		return;
-
-	switch (dev->dev->bus_type) {
-#ifdef CONFIG_B43_BCMA
-	case B43_BUS_BCMA:
-		tmp = bcma_aread32(dev->dev->bdev, BCMA_IOCTL);
-		if (force)
-			tmp |= BCMA_IOCTL_FGC;
-		else
-			tmp &= ~BCMA_IOCTL_FGC;
-		bcma_awrite32(dev->dev->bdev, BCMA_IOCTL, tmp);
-		break;
-#endif
-#ifdef CONFIG_B43_SSB
-	case B43_BUS_SSB:
-		tmp = ssb_read32(dev->dev->sdev, SSB_TMSLOW);
-		if (force)
-			tmp |= SSB_TMSLOW_FGC;
-		else
-			tmp &= ~SSB_TMSLOW_FGC;
-		ssb_write32(dev->dev->sdev, SSB_TMSLOW, tmp);
-		break;
-#endif
-	}
-}
-
 /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/CCA */
 static void b43_nphy_reset_cca(struct b43_wldev *dev)
 {
 	u16 bbcfg;
 
-	b43_nphy_bmac_clock_fgc(dev, 1);
+	b43_phy_force_clock(dev, 1);
 	bbcfg = b43_phy_read(dev, B43_NPHY_BBCFG);
 	b43_phy_write(dev, B43_NPHY_BBCFG, bbcfg | B43_NPHY_BBCFG_RSTCCA);
 	udelay(1);
 	b43_phy_write(dev, B43_NPHY_BBCFG, bbcfg & ~B43_NPHY_BBCFG_RSTCCA);
-	b43_nphy_bmac_clock_fgc(dev, 0);
+	b43_phy_force_clock(dev, 0);
 	b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX);
 }
 
@@ -3715,11 +3683,11 @@
 	b43_nphy_workarounds(dev);
 
 	/* Reset CCA, in init code it differs a little from standard way */
-	b43_nphy_bmac_clock_fgc(dev, 1);
+	b43_phy_force_clock(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_phy_force_clock(dev, 0);
 
 	b43_mac_phy_clock_set(dev, true);
 
diff -ruN linux-3.1-rc5.orig/drivers/net/wireless/b43/pio.c linux-3.1-rc5/drivers/net/wireless/b43/pio.c
--- linux-3.1-rc5.orig/drivers/net/wireless/b43/pio.c	2011-09-04 15:45:10.000000000 -0700
+++ linux-3.1-rc5/drivers/net/wireless/b43/pio.c	2011-09-11 16:44:23.725457051 -0700
@@ -676,7 +676,15 @@
 		goto rx_error;
 	}
 
-	macstat = le32_to_cpu(rxhdr->mac_status);
+	switch (dev->fw.hdr_format) {
+	case B43_FW_HDR_598:
+		macstat = le32_to_cpu(rxhdr->format_598.mac_status);
+		break;
+	case B43_FW_HDR_410:
+	case B43_FW_HDR_351:
+		macstat = le32_to_cpu(rxhdr->format_351.mac_status);
+		break;
+	}
 	if (macstat & B43_RX_MAC_FCSERR) {
 		if (!(q->dev->wl->filter_flags & FIF_FCSFAIL)) {
 			/* Drop frames with failed FCS. */
diff -ruN linux-3.1-rc5.orig/drivers/net/wireless/b43/tables_phy_ht.c linux-3.1-rc5/drivers/net/wireless/b43/tables_phy_ht.c
--- linux-3.1-rc5.orig/drivers/net/wireless/b43/tables_phy_ht.c	2011-09-04 15:45:10.000000000 -0700
+++ linux-3.1-rc5/drivers/net/wireless/b43/tables_phy_ht.c	2011-09-11 16:44:48.854820469 -0700
@@ -574,6 +574,42 @@
 	0x005d0582, 0x005805d6, 0x0053062e, 0x004e068c,
 };
 
+/* Some late-init table */
+const u32 b43_httab_0x1a_0xc0_late[] = {
+	0x10f90040, 0x10e10040, 0x10e1003c, 0x10c9003d,
+	0x10b9003c, 0x10a9003d, 0x10a1003c, 0x1099003b,
+	0x1091003b, 0x1089003a, 0x1081003a, 0x10790039,
+	0x10710039, 0x1069003a, 0x1061003b, 0x1059003d,
+	0x1051003f, 0x10490042, 0x1049003e, 0x1049003b,
+	0x1041003e, 0x1041003b, 0x1039003e, 0x1039003b,
+	0x10390038, 0x10390035, 0x1031003a, 0x10310036,
+	0x10310033, 0x1029003a, 0x10290037, 0x10290034,
+	0x10290031, 0x10210039, 0x10210036, 0x10210033,
+	0x10210030, 0x1019003c, 0x10190039, 0x10190036,
+	0x10190033, 0x10190030, 0x1019002d, 0x1019002b,
+	0x10190028, 0x1011003a, 0x10110036, 0x10110033,
+	0x10110030, 0x1011002e, 0x1011002b, 0x10110029,
+	0x10110027, 0x10110024, 0x10110022, 0x10110020,
+	0x1011001f, 0x1011001d, 0x1009003a, 0x10090037,
+	0x10090034, 0x10090031, 0x1009002e, 0x1009002c,
+	0x10090029, 0x10090027, 0x10090025, 0x10090023,
+	0x10090021, 0x1009001f, 0x1009001d, 0x1009001b,
+	0x1009001a, 0x10090018, 0x10090017, 0x10090016,
+	0x10090015, 0x10090013, 0x10090012, 0x10090011,
+	0x10090010, 0x1009000f, 0x1009000f, 0x1009000e,
+	0x1009000d, 0x1009000c, 0x1009000c, 0x1009000b,
+	0x1009000a, 0x1009000a, 0x10090009, 0x10090009,
+	0x10090008, 0x10090008, 0x10090007, 0x10090007,
+	0x10090007, 0x10090006, 0x10090006, 0x10090005,
+	0x10090005, 0x10090005, 0x10090005, 0x10090004,
+	0x10090004, 0x10090004, 0x10090004, 0x10090003,
+	0x10090003, 0x10090003, 0x10090003, 0x10090003,
+	0x10090003, 0x10090002, 0x10090002, 0x10090002,
+	0x10090002, 0x10090002, 0x10090002, 0x10090002,
+	0x10090002, 0x10090002, 0x10090001, 0x10090001,
+	0x10090001, 0x10090001, 0x10090001, 0x10090001,
+};
+
 /**************************************************
  * R/W ops.
  **************************************************/
@@ -674,6 +710,51 @@
 	return;
 }
 
+void b43_httab_write_few(struct b43_wldev *dev, u32 offset, size_t num, ...)
+{
+	va_list args;
+	u32 type, value;
+	unsigned int i;
+
+	type = offset & B43_HTTAB_TYPEMASK;
+	offset &= 0xFFFF;
+
+	va_start(args, num);
+	switch (type) {
+	case B43_HTTAB_8BIT:
+		b43_phy_write(dev, B43_PHY_HT_TABLE_ADDR, offset);
+		for (i = 0; i < num; i++) {
+			value = va_arg(args, int);
+			B43_WARN_ON(value & ~0xFF);
+			b43_phy_write(dev, B43_PHY_HT_TABLE_DATALO, value);
+		}
+		break;
+	case B43_HTTAB_16BIT:
+		b43_phy_write(dev, B43_PHY_HT_TABLE_ADDR, offset);
+		for (i = 0; i < num; i++) {
+			value = va_arg(args, int);
+			B43_WARN_ON(value & ~0xFFFF);
+			b43_phy_write(dev, B43_PHY_HT_TABLE_DATALO, value);
+		}
+		break;
+	case B43_HTTAB_32BIT:
+		b43_phy_write(dev, B43_PHY_HT_TABLE_ADDR, offset);
+		for (i = 0; i < num; i++) {
+			value = va_arg(args, int);
+			b43_phy_write(dev, B43_PHY_HT_TABLE_DATAHI,
+				      value >> 16);
+			b43_phy_write(dev, B43_PHY_HT_TABLE_DATALO,
+				      value & 0xFFFF);
+		}
+		break;
+	default:
+		B43_WARN_ON(1);
+	}
+	va_end(args);
+
+	return;
+}
+
 void b43_httab_write_bulk(struct b43_wldev *dev, u32 offset,
 			  unsigned int nr_elements, const void *_data)
 {
@@ -723,6 +804,9 @@
 	} while (0)
 void b43_phy_ht_tables_init(struct b43_wldev *dev)
 {
+	BUILD_BUG_ON(ARRAY_SIZE(b43_httab_0x1a_0xc0_late) !=
+			B43_HTTAB_1A_C0_LATE_SIZE);
+
 	httab_upload(dev, B43_HTTAB16(0x12, 0), b43_httab_0x12);
 	httab_upload(dev, B43_HTTAB16(0x27, 0), b43_httab_0x27);
 	httab_upload(dev, B43_HTTAB16(0x26, 0), b43_httab_0x26);
diff -ruN linux-3.1-rc5.orig/drivers/net/wireless/b43/tables_phy_ht.h linux-3.1-rc5/drivers/net/wireless/b43/tables_phy_ht.h
--- linux-3.1-rc5.orig/drivers/net/wireless/b43/tables_phy_ht.h	2011-09-04 15:45:10.000000000 -0700
+++ linux-3.1-rc5/drivers/net/wireless/b43/tables_phy_ht.h	2011-09-11 16:44:48.854820469 -0700
@@ -14,9 +14,13 @@
 void b43_httab_read_bulk(struct b43_wldev *dev, u32 offset,
 			 unsigned int nr_elements, void *_data);
 void b43_httab_write(struct b43_wldev *dev, u32 offset, u32 value);
+void b43_httab_write_few(struct b43_wldev *dev, u32 offset, size_t num, ...);
 void b43_httab_write_bulk(struct b43_wldev *dev, u32 offset,
 			  unsigned int nr_elements, const void *_data);
 
 void b43_phy_ht_tables_init(struct b43_wldev *dev);
 
+#define B43_HTTAB_1A_C0_LATE_SIZE		128
+extern const u32 b43_httab_0x1a_0xc0_late[];
+
 #endif /* B43_TABLES_PHY_HT_H_ */
diff -ruN linux-3.1-rc5.orig/drivers/net/wireless/b43/xmit.c linux-3.1-rc5/drivers/net/wireless/b43/xmit.c
--- linux-3.1-rc5.orig/drivers/net/wireless/b43/xmit.c	2011-09-04 15:45:10.000000000 -0700
+++ linux-3.1-rc5/drivers/net/wireless/b43/xmit.c	2011-09-11 16:44:35.375162052 -0700
@@ -337,12 +337,19 @@
 			memcpy(txhdr->iv, ((u8 *) wlhdr) + wlhdr_len, iv_len);
 		}
 	}
-	if (b43_is_old_txhdr_format(dev)) {
-		b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->old_format.plcp),
+	switch (dev->fw.hdr_format) {
+	case B43_FW_HDR_598:
+		b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->format_598.plcp),
 				      plcp_fragment_len, rate);
-	} else {
-		b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->new_format.plcp),
+		break;
+	case B43_FW_HDR_351:
+		b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->format_351.plcp),
+				      plcp_fragment_len, rate);
+		break;
+	case B43_FW_HDR_410:
+		b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->format_410.plcp),
 				      plcp_fragment_len, rate);
+		break;
 	}
 	b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->plcp_fb),
 			      plcp_fragment_len, rate_fb);
@@ -415,10 +422,10 @@
 	if ((rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) ||
 	    (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)) {
 		unsigned int len;
-		struct ieee80211_hdr *hdr;
+		struct ieee80211_hdr *uninitialized_var(hdr);
 		int rts_rate, rts_rate_fb;
 		int rts_rate_ofdm, rts_rate_fb_ofdm;
-		struct b43_plcp_hdr6 *plcp;
+		struct b43_plcp_hdr6 *uninitialized_var(plcp);
 		struct ieee80211_rate *rts_cts_rate;
 
 		rts_cts_rate = ieee80211_get_rts_cts_rate(dev->wl->hw, info);
@@ -429,14 +436,21 @@
 		rts_rate_fb_ofdm = b43_is_ofdm_rate(rts_rate_fb);
 
 		if (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
-			struct ieee80211_cts *cts;
+			struct ieee80211_cts *uninitialized_var(cts);
 
-			if (b43_is_old_txhdr_format(dev)) {
+			switch (dev->fw.hdr_format) {
+			case B43_FW_HDR_598:
 				cts = (struct ieee80211_cts *)
-					(txhdr->old_format.rts_frame);
-			} else {
+					(txhdr->format_598.rts_frame);
+				break;
+			case B43_FW_HDR_351:
 				cts = (struct ieee80211_cts *)
-					(txhdr->new_format.rts_frame);
+					(txhdr->format_351.rts_frame);
+				break;
+			case B43_FW_HDR_410:
+				cts = (struct ieee80211_cts *)
+					(txhdr->format_410.rts_frame);
+				break;
 			}
 			ieee80211_ctstoself_get(dev->wl->hw, info->control.vif,
 						fragment_data, fragment_len,
@@ -444,14 +458,21 @@
 			mac_ctl |= B43_TXH_MAC_SENDCTS;
 			len = sizeof(struct ieee80211_cts);
 		} else {
-			struct ieee80211_rts *rts;
+			struct ieee80211_rts *uninitialized_var(rts);
 
-			if (b43_is_old_txhdr_format(dev)) {
+			switch (dev->fw.hdr_format) {
+			case B43_FW_HDR_598:
 				rts = (struct ieee80211_rts *)
-					(txhdr->old_format.rts_frame);
-			} else {
+					(txhdr->format_598.rts_frame);
+				break;
+			case B43_FW_HDR_351:
+				rts = (struct ieee80211_rts *)
+					(txhdr->format_351.rts_frame);
+				break;
+			case B43_FW_HDR_410:
 				rts = (struct ieee80211_rts *)
-					(txhdr->new_format.rts_frame);
+					(txhdr->format_410.rts_frame);
+				break;
 			}
 			ieee80211_rts_get(dev->wl->hw, info->control.vif,
 					  fragment_data, fragment_len,
@@ -462,22 +483,36 @@
 		len += FCS_LEN;
 
 		/* Generate the PLCP headers for the RTS/CTS frame */
-		if (b43_is_old_txhdr_format(dev))
-			plcp = &txhdr->old_format.rts_plcp;
-		else
-			plcp = &txhdr->new_format.rts_plcp;
+		switch (dev->fw.hdr_format) {
+		case B43_FW_HDR_598:
+			plcp = &txhdr->format_598.rts_plcp;
+			break;
+		case B43_FW_HDR_351:
+			plcp = &txhdr->format_351.rts_plcp;
+			break;
+		case B43_FW_HDR_410:
+			plcp = &txhdr->format_410.rts_plcp;
+			break;
+		}
 		b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)plcp,
 				      len, rts_rate);
 		plcp = &txhdr->rts_plcp_fb;
 		b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)plcp,
 				      len, rts_rate_fb);
 
-		if (b43_is_old_txhdr_format(dev)) {
+		switch (dev->fw.hdr_format) {
+		case B43_FW_HDR_598:
 			hdr = (struct ieee80211_hdr *)
-				(&txhdr->old_format.rts_frame);
-		} else {
+				(&txhdr->format_598.rts_frame);
+			break;
+		case B43_FW_HDR_351:
+			hdr = (struct ieee80211_hdr *)
+				(&txhdr->format_351.rts_frame);
+			break;
+		case B43_FW_HDR_410:
 			hdr = (struct ieee80211_hdr *)
-				(&txhdr->new_format.rts_frame);
+				(&txhdr->format_410.rts_frame);
+			break;
 		}
 		txhdr->rts_dur_fb = hdr->duration_id;
 
@@ -505,10 +540,17 @@
 	}
 
 	/* Magic cookie */
-	if (b43_is_old_txhdr_format(dev))
-		txhdr->old_format.cookie = cpu_to_le16(cookie);
-	else
-		txhdr->new_format.cookie = cpu_to_le16(cookie);
+	switch (dev->fw.hdr_format) {
+	case B43_FW_HDR_598:
+		txhdr->format_598.cookie = cpu_to_le16(cookie);
+		break;
+	case B43_FW_HDR_351:
+		txhdr->format_351.cookie = cpu_to_le16(cookie);
+		break;
+	case B43_FW_HDR_410:
+		txhdr->format_410.cookie = cpu_to_le16(cookie);
+		break;
+	}
 
 	if (phy->type == B43_PHYTYPE_N) {
 		txhdr->phy_ctl1 =
@@ -611,8 +653,9 @@
 	struct ieee80211_hdr *wlhdr;
 	const struct b43_rxhdr_fw4 *rxhdr = _rxhdr;
 	__le16 fctl;
-	u16 phystat0, phystat3, chanstat, mactime;
-	u32 macstat;
+	u16 phystat0, phystat3;
+	u16 uninitialized_var(chanstat), uninitialized_var(mactime);
+	u32 uninitialized_var(macstat);
 	u16 chanid;
 	u16 phytype;
 	int padding;
@@ -622,9 +665,19 @@
 	/* Get metadata about the frame from the header. */
 	phystat0 = le16_to_cpu(rxhdr->phy_status0);
 	phystat3 = le16_to_cpu(rxhdr->phy_status3);
-	macstat = le32_to_cpu(rxhdr->mac_status);
-	mactime = le16_to_cpu(rxhdr->mac_time);
-	chanstat = le16_to_cpu(rxhdr->channel);
+	switch (dev->fw.hdr_format) {
+	case B43_FW_HDR_598:
+		macstat = le32_to_cpu(rxhdr->format_598.mac_status);
+		mactime = le16_to_cpu(rxhdr->format_598.mac_time);
+		chanstat = le16_to_cpu(rxhdr->format_598.channel);
+		break;
+	case B43_FW_HDR_410:
+	case B43_FW_HDR_351:
+		macstat = le32_to_cpu(rxhdr->format_351.mac_status);
+		mactime = le16_to_cpu(rxhdr->format_351.mac_time);
+		chanstat = le16_to_cpu(rxhdr->format_351.channel);
+		break;
+	}
 	phytype = chanstat & B43_RX_CHAN_PHYTYPE;
 
 	if (unlikely(macstat & B43_RX_MAC_FCSERR)) {
@@ -744,6 +797,7 @@
 		break;
 	case B43_PHYTYPE_N:
 	case B43_PHYTYPE_LP:
+	case B43_PHYTYPE_HT:
 		/* chanid is the SHM channel cookie. Which is the plain
 		 * channel number in b43. */
 		if (chanstat & B43_RX_CHAN_5GHZ) {
diff -ruN linux-3.1-rc5.orig/drivers/net/wireless/b43/xmit.h linux-3.1-rc5/drivers/net/wireless/b43/xmit.h
--- linux-3.1-rc5.orig/drivers/net/wireless/b43/xmit.h	2011-09-04 15:45:10.000000000 -0700
+++ linux-3.1-rc5/drivers/net/wireless/b43/xmit.h	2011-09-11 16:44:23.725457051 -0700
@@ -46,7 +46,24 @@
 	__le32 timeout;			/* Timeout */
 
 	union {
-		/* The new r410 format. */
+		/* Tested with 598.314, 644.1001 and 666.2 */
+		struct {
+			__le16 mimo_antenna;            /* MIMO antenna select */
+			__le16 preload_size;            /* Preload size */
+			PAD_BYTES(2);
+			__le16 cookie;                  /* TX frame cookie */
+			__le16 tx_status;               /* TX status */
+			__le16 max_n_mpdus;
+			__le16 max_a_bytes_mrt;
+			__le16 max_a_bytes_fbr;
+			__le16 min_m_bytes;
+			struct b43_plcp_hdr6 rts_plcp;  /* RTS PLCP header */
+			__u8 rts_frame[16];             /* The RTS frame (if used) */
+			PAD_BYTES(2);
+			struct b43_plcp_hdr6 plcp;      /* Main PLCP header */
+		} format_598 __packed;
+
+		/* Tested with 410.2160, 478.104 and 508.* */
 		struct {
 			__le16 mimo_antenna;		/* MIMO antenna select */
 			__le16 preload_size;		/* Preload size */
@@ -57,9 +74,9 @@
 			__u8 rts_frame[16];		/* The RTS frame (if used) */
 			PAD_BYTES(2);
 			struct b43_plcp_hdr6 plcp;	/* Main PLCP header */
-		} new_format __packed;
+		} format_410 __packed;
 
-		/* The old r351 format. */
+		/* Tested with 351.126 */
 		struct {
 			PAD_BYTES(2);
 			__le16 cookie;			/* TX frame cookie */
@@ -68,7 +85,7 @@
 			__u8 rts_frame[16];		/* The RTS frame (if used) */
 			PAD_BYTES(2);
 			struct b43_plcp_hdr6 plcp;	/* Main PLCP header */
-		} old_format __packed;
+		} format_351 __packed;
 
 	} __packed;
 } __packed;
@@ -166,19 +183,18 @@
 #define  B43_TXH_PHY1_MODUL_QAM256	0x2000 /* QAM256 */
 
 
-/* r351 firmware compatibility stuff. */
-static inline
-bool b43_is_old_txhdr_format(struct b43_wldev *dev)
-{
-	return (dev->fw.rev <= 351);
-}
-
 static inline
 size_t b43_txhdr_size(struct b43_wldev *dev)
 {
-	if (b43_is_old_txhdr_format(dev))
+	switch (dev->fw.hdr_format) {
+	case B43_FW_HDR_598:
+		return 112 + sizeof(struct b43_plcp_hdr6);
+	case B43_FW_HDR_410:
+		return 104 + sizeof(struct b43_plcp_hdr6);
+	case B43_FW_HDR_351:
 		return 100 + sizeof(struct b43_plcp_hdr6);
-	return 104 + sizeof(struct b43_plcp_hdr6);
+	}
+	return 0;
 }
 
 
@@ -234,9 +250,23 @@
 	} __packed;
 	__le16 phy_status2;	/* PHY RX Status 2 */
 	__le16 phy_status3;	/* PHY RX Status 3 */
-	__le32 mac_status;	/* MAC RX status */
-	__le16 mac_time;
-	__le16 channel;
+	union {
+		/* Tested with 598.314, 644.1001 and 666.2 */
+		struct {
+			__le16 phy_status4;	/* PHY RX Status 4 */
+			__le16 phy_status5;	/* PHY RX Status 5 */
+			__le32 mac_status;	/* MAC RX status */
+			__le16 mac_time;
+			__le16 channel;
+		} format_598 __packed;
+
+		/* Tested with 351.126, 410.2160, 478.104 and 508.* */
+		struct {
+			__le32 mac_status;	/* MAC RX status */
+			__le16 mac_time;
+			__le16 channel;
+		} format_351 __packed;
+	} __packed;
 } __packed;
 
 /* PHY RX Status 0 */
diff -ruN linux-3.1-rc5.orig/include/linux/bcma/bcma_driver_chipcommon.h linux-3.1-rc5/include/linux/bcma/bcma_driver_chipcommon.h
--- linux-3.1-rc5.orig/include/linux/bcma/bcma_driver_chipcommon.h	2011-09-04 15:45:10.000000000 -0700
+++ linux-3.1-rc5/include/linux/bcma/bcma_driver_chipcommon.h	2011-09-11 16:44:25.595409713 -0700
@@ -239,6 +239,22 @@
 #define BCMA_CC_SPROM			0x0800 /* SPROM beginning */
 #define BCMA_CC_SPROM_PCIE6		0x0830 /* SPROM beginning on PCIe rev >= 6 */
 
+/* BCM4331 ChipControl numbers. */
+#define BCMA_CHIPCTL_4331_BT_COEXIST		BIT(0)	/* 0 disable */
+#define BCMA_CHIPCTL_4331_SECI			BIT(1)	/* 0 SECI is disabled (JATG functional) */
+#define BCMA_CHIPCTL_4331_EXT_LNA		BIT(2)	/* 0 disable */
+#define BCMA_CHIPCTL_4331_SPROM_GPIO13_15	BIT(3)	/* sprom/gpio13-15 mux */
+#define BCMA_CHIPCTL_4331_EXTPA_EN		BIT(4)	/* 0 ext pa disable, 1 ext pa enabled */
+#define BCMA_CHIPCTL_4331_GPIOCLK_ON_SPROMCS	BIT(5)	/* set drive out GPIO_CLK on sprom_cs pin */
+#define BCMA_CHIPCTL_4331_PCIE_MDIO_ON_SPROMCS	BIT(6)	/* use sprom_cs pin as PCIE mdio interface */
+#define BCMA_CHIPCTL_4331_EXTPA_ON_GPIO2_5	BIT(7)	/* aband extpa will be at gpio2/5 and sprom_dout */
+#define BCMA_CHIPCTL_4331_OVR_PIPEAUXCLKEN	BIT(8)	/* override core control on pipe_AuxClkEnable */
+#define BCMA_CHIPCTL_4331_OVR_PIPEAUXPWRDOWN	BIT(9)	/* override core control on pipe_AuxPowerDown */
+#define BCMA_CHIPCTL_4331_PCIE_AUXCLKEN		BIT(10)	/* pcie_auxclkenable */
+#define BCMA_CHIPCTL_4331_PCIE_PIPE_PLLDOWN	BIT(11)	/* pcie_pipe_pllpowerdown */
+#define BCMA_CHIPCTL_4331_BT_SHD0_ON_GPIO4	BIT(16)	/* enable bt_shd0 at gpio4 */
+#define BCMA_CHIPCTL_4331_BT_SHD1_ON_GPIO5	BIT(17)	/* enable bt_shd1 at gpio5 */
+
 /* Data for the PMU, if available.
  * Check availability with ((struct bcma_chipcommon)->capabilities & BCMA_CC_CAP_PMU)
  */
@@ -275,6 +291,8 @@
 extern void bcma_chipco_suspend(struct bcma_drv_cc *cc);
 extern void bcma_chipco_resume(struct bcma_drv_cc *cc);
 
+void bcma_chipco_bcm4331_ext_pa_lines_ctl(struct bcma_drv_cc *cc, bool enable);
+
 extern void bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc,
 					  u32 ticks);
 

Attachment: signature.asc
Description: OpenPGP digital signature

_______________________________________________
b43-dev mailing list
b43-dev@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/b43-dev

Reply via email to