[PATCH] bcm43xx: set default attenuation values.

Signed-off-by: Michael Buesch <mbuesch@freenet.de>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h
index 8820012..1fca1f9c 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx.h
@@ -507,14 +507,23 @@
 	u16 version;
 	u8 revision;
 
-	/* 0: baseband attenuation,
-	 * 1: radio attenuation, 
-	 * 2: tx_CTL1
-	 * 3: tx_CTL2
-	 */
-	u16 txpower[4];
 	/* Desired TX power in dBm Q5.2 */
 	u16 txpower_desired;
+	/* TX Power control values. */
+	union {
+		/* B/G PHY */
+		struct {
+			u16 baseband_atten;
+			u16 radio_atten;
+			u16 txctl1;
+			u16 txctl2;
+		};
+		/* A PHY */
+		struct {
+			u16 txpwr_offset;
+		};
+	};
+
 	/* Current Interference Mitigation mode */
 	int interfmode;
 	/* Stack of saved values from the Interference Mitigation code */
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
index 12c93d2..e680d2a 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
@@ -560,12 +560,9 @@
 	radio->revision = revision;
 
 	/* Set default attenuation values. */
-	radio->txpower[0] = 2;
-	radio->txpower[1] = 2;
-	if (revision == 1)
-		radio->txpower[2] = 3;
-	else
-		radio->txpower[2] = 0;
+	radio->baseband_atten = bcm43xx_default_baseband_attenuation(bcm);
+	radio->radio_atten = bcm43xx_default_radio_attenuation(bcm);
+	radio->txctl1 = bcm43xx_default_txctl1(bcm);
 	if (phy->type == BCM43xx_PHYTYPE_A)
 		radio->txpower_desired = bcm->sprom.maxpower_aphy;
 	else
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
index 1ce9a45..054c64e 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
@@ -220,9 +220,9 @@
 		bcm43xx_radio_write16(bcm, 0x0076,
 				      bcm43xx_radio_read16(bcm, 0x0076) | 0x0084);
 	} else {
-		saved_batt = radio->txpower[0];
-		saved_ratt = radio->txpower[1];
-		saved_txctl1 = radio->txpower[2];
+		saved_batt = radio->baseband_atten;
+		saved_ratt = radio->radio_atten;
+		saved_txctl1 = radio->txctl1;
 		if ((radio->revision >= 6) && (radio->revision <= 8)
 		    && /*FIXME: incomplete specs for 5 < revision < 9 */ 0)
 			bcm43xx_radio_set_txpower_bg(bcm, 0xB, 0x1F, 0);
@@ -1039,7 +1039,7 @@
 		bcm43xx_radio_write16(bcm, 0x0078, radio->initval);
 		bcm43xx_radio_write16(bcm, 0x0052,
 				      (bcm43xx_radio_read16(bcm, 0x0052) & 0xFFF0)
-				      | radio->txpower[3]);
+				      | radio->txctl2);
 	}
 
 	if (phy->connected) {
@@ -1259,7 +1259,6 @@
 	if (baseband_attenuation > 6)
 		baseband_attenuation = 6;
 	assert(radio_attenuation < 10);
-	assert(tx == 0 || tx == 3);
 
 	if (tx == 3) {
 		return bcm43xx_get_lopair(phy,
@@ -1275,9 +1274,9 @@
 	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
 
 	return bcm43xx_find_lopair(bcm,
-				   radio->txpower[0],
-				   radio->txpower[1],
-				   radio->txpower[2]);
+				   radio->baseband_atten,
+				   radio->radio_atten,
+				   radio->txctl1);
 }
 
 /* Adjust B/G LO */
@@ -1311,7 +1310,7 @@
 			txctl2 = i;
 		}
 	}
-	radio->txpower[3] = txctl2;
+	radio->txctl2 = txctl2;
 }
 
 static
@@ -1530,8 +1529,7 @@
 				r31 = 0;
 			}
 			bcm43xx_radio_write16(bcm, 0x43, i);
-			bcm43xx_radio_write16(bcm, 0x52,
-					      radio->txpower[3]);
+			bcm43xx_radio_write16(bcm, 0x52, radio->txctl2);
 			udelay(10);
 
 			bcm43xx_phy_set_baseband_attenuation(bcm, j * 2);
@@ -1573,7 +1571,7 @@
 			}
 			bcm43xx_radio_write16(bcm, 0x43, i - 9);
 			bcm43xx_radio_write16(bcm, 0x52,
-					      radio->txpower[3]
+					      radio->txctl2
 					      | (3/*txctl1*/ << 4));//FIXME: shouldn't txctl1 be zero here and 3 in the loop above?
 			udelay(10);
 
@@ -1780,9 +1778,9 @@
 		}
 
 		/* Calculate the new attenuation values. */
-		baseband_attenuation = radio->txpower[0];
+		baseband_attenuation = radio->baseband_atten;
 		baseband_attenuation += baseband_att_delta;
-		radio_attenuation = radio->txpower[1];
+		radio_attenuation = radio->radio_atten;
 		radio_attenuation += radio_att_delta;
 
 		/* Get baseband and radio attenuation values into their permitted ranges.
@@ -1807,7 +1805,7 @@
 		}
 		baseband_attenuation = limit_value(baseband_attenuation, 0, 11);
 
-		txpower = radio->txpower[2];
+		txpower = radio->txctl1;
 		if ((radio->version == 0x2050) && (radio->revision == 2)) {
 			if (radio_attenuation <= 1) {
 				if (txpower == 0) {
@@ -1829,7 +1827,7 @@
 				}
 			}
 		}
-		radio->txpower[2] = txpower;
+		radio->txctl1 = txpower;
 		baseband_attenuation = limit_value(baseband_attenuation, 0, 11);
 		radio_attenuation = limit_value(radio_attenuation, 0, 9);
 
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
index cac604b..4e8d8c9 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
@@ -1652,7 +1652,7 @@
 
 	bcm43xx_ilt_write(bcm, 0x3001, dac);
 
-	radio->txpower[0] = txpower;
+	radio->txpwr_offset = txpower;
 
 	TODO();
 	//TODO: FuncPlaceholder (Adjust BB loft cancel)
@@ -1666,17 +1666,14 @@
 	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
 
 	if (baseband_attenuation == 0xFFFF)
-		baseband_attenuation = radio->txpower[0];
-	else
-		radio->txpower[0] = baseband_attenuation;
+		baseband_attenuation = radio->baseband_atten;
 	if (radio_attenuation == 0xFFFF)
-		radio_attenuation = radio->txpower[1];
-	else
-		radio->txpower[1] = radio_attenuation;
+		radio_attenuation = radio->radio_atten;
 	if (txpower == 0xFFFF)
-		txpower = radio->txpower[2];
-	else
-		radio->txpower[2] = txpower;
+		txpower = radio->txctl1;
+	radio->baseband_atten = baseband_attenuation;
+	radio->radio_atten = radio_attenuation;
+	radio->txctl1 = txpower;
 
 	assert(/*baseband_attenuation >= 0 &&*/ baseband_attenuation <= 11);
 	if (radio->revision < 6)
@@ -1693,10 +1690,124 @@
 		                      (bcm43xx_radio_read16(bcm, 0x0052) & ~0x0070)
 				       | ((txpower << 4) & 0x0070));
 	}
+	//FIXME: The spec is very weird and unclear here.
 	if (phy->type == BCM43xx_PHYTYPE_G)
 		bcm43xx_phy_lo_adjust(bcm, 0);
 }
 
+u16 bcm43xx_default_baseband_attenuation(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+
+	if (radio->version == 0x2050 && radio->revision < 6)
+		return 0;
+	return 2;
+}
+
+u16 bcm43xx_default_radio_attenuation(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	u16 att = 0xFFFF;
+
+	if (phy->type == BCM43xx_PHYTYPE_A)
+		return 0x60;
+
+	switch (radio->version) {
+	case 0x2053:
+		switch (radio->revision) {
+		case 1:
+			att = 6;
+			break;
+		}
+		break;
+	case 0x2050:
+		switch (radio->revision) {
+		case 0:
+			att = 5;
+			break;
+		case 1:
+			if (phy->type == BCM43xx_PHYTYPE_G) {
+				if (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM &&
+				    bcm->board_type == 0x421 &&
+				    bcm->board_revision >= 30)
+					att = 3;
+				else if (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM &&
+					 bcm->board_type == 0x416)
+					att = 3;
+				else
+					att = 1;
+			} else {
+				if (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM &&
+				    bcm->board_type == 0x421 &&
+				    bcm->board_revision >= 30)
+					att = 7;
+				else
+					att = 6;
+			}
+			break;
+		case 2:
+			if (phy->type == BCM43xx_PHYTYPE_G) {
+				if (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM &&
+				    bcm->board_type == 0x421 &&
+				    bcm->board_revision >= 30)
+					att = 3;
+				else if (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM &&
+					 bcm->board_type == 0x416)
+					att = 5;
+				else if (bcm->chip_id == 0x4320)
+					att = 4;
+				else
+					att = 3;
+			} else
+				att = 6;
+			break;
+		case 3:
+			att = 5;
+			break;
+		case 4:
+		case 5:
+			att = 1;
+			break;
+		case 6:
+		case 7:
+			att = 5;
+			break;
+		case 8:
+			att = 0x1A;
+			break;
+		case 9:
+		default:
+			att = 5;
+		}
+	}
+	if (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM &&
+	    bcm->board_type == 0x421) {
+		if (bcm->board_revision < 0x43)
+			att = 2;
+		else if (bcm->board_revision < 0x51)
+			att = 3;
+	}
+	if (att == 0xFFFF)
+		att = 5;
+
+	return att;
+}
+
+u16 bcm43xx_default_txctl1(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+
+	if (radio->version != 0x2050)
+		return 0;
+	if (radio->revision == 1)
+		return 3;
+	if (radio->revision < 6)
+		return 2;
+	if (radio->revision == 8)
+		return 1;
+	return 0;
+}
 
 void bcm43xx_radio_turn_on(struct bcm43xx_private *bcm)
 {
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.h b/drivers/net/wireless/bcm43xx/bcm43xx_radio.h
index a5d2e10..9ed1803 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_radio.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.h
@@ -72,6 +72,11 @@
 void bcm43xx_radio_set_txpower_bg(struct bcm43xx_private *bcm,
                                u16 baseband_attenuation, u16 attenuation,
 			       u16 txpower);
+
+u16 bcm43xx_default_baseband_attenuation(struct bcm43xx_private *bcm);
+u16 bcm43xx_default_radio_attenuation(struct bcm43xx_private *bcm);
+u16 bcm43xx_default_txctl1(struct bcm43xx_private *bcm);
+
 void bcm43xx_radio_set_txantenna(struct bcm43xx_private *bcm, u32 val);
 
 void bcm43xx_radio_clear_tssi(struct bcm43xx_private *bcm);