Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3a5c393e authored by Larry Finger's avatar Larry Finger Committed by Jeff Garzik
Browse files

[PATCH] bcm43xx: Change initialization for 2050 radios



This patch implements the changes in the specifications for
2050radio_init that were recently posted.

Signed-off-by: default avatarLarry Finger <Larry.Finger@lwfinger.net>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent b1fc1fa9
Loading
Loading
Loading
Loading
+10 −5
Original line number Original line Diff line number Diff line
@@ -300,16 +300,20 @@ static void bcm43xx_phy_agcsetup(struct bcm43xx_private *bcm)


	if (phy->rev > 2) {
	if (phy->rev > 2) {
		bcm43xx_phy_write(bcm, 0x0422, 0x287A);
		bcm43xx_phy_write(bcm, 0x0422, 0x287A);
		bcm43xx_phy_write(bcm, 0x0420, (bcm43xx_phy_read(bcm, 0x0420) & 0x0FFF) | 0x3000); 
		bcm43xx_phy_write(bcm, 0x0420, (bcm43xx_phy_read(bcm, 0x0420)
				  & 0x0FFF) | 0x3000);
	}
	}
		
		
	bcm43xx_phy_write(bcm, 0x04A8, (bcm43xx_phy_read(bcm, 0x04A8) & 0x8080) | 0x7874);
	bcm43xx_phy_write(bcm, 0x04A8, (bcm43xx_phy_read(bcm, 0x04A8) & 0x8080)
					| 0x7874);
	bcm43xx_phy_write(bcm, 0x048E, 0x1C00);
	bcm43xx_phy_write(bcm, 0x048E, 0x1C00);


	if (phy->rev == 1) {
	if (phy->rev == 1) {
		bcm43xx_phy_write(bcm, 0x04AB, (bcm43xx_phy_read(bcm, 0x04AB) & 0xF0FF) | 0x0600);
		bcm43xx_phy_write(bcm, 0x04AB, (bcm43xx_phy_read(bcm, 0x04AB)
				  & 0xF0FF) | 0x0600);
		bcm43xx_phy_write(bcm, 0x048B, 0x005E);
		bcm43xx_phy_write(bcm, 0x048B, 0x005E);
		bcm43xx_phy_write(bcm, 0x048C, (bcm43xx_phy_read(bcm, 0x048C) & 0xFF00) | 0x001E);
		bcm43xx_phy_write(bcm, 0x048C, (bcm43xx_phy_read(bcm, 0x048C)
				  & 0xFF00) | 0x001E);
		bcm43xx_phy_write(bcm, 0x048D, 0x0002);
		bcm43xx_phy_write(bcm, 0x048D, 0x0002);
	}
	}


@@ -335,7 +339,8 @@ static void bcm43xx_phy_setupg(struct bcm43xx_private *bcm)
	if (phy->rev == 1) {
	if (phy->rev == 1) {
		bcm43xx_phy_write(bcm, 0x0406, 0x4F19);
		bcm43xx_phy_write(bcm, 0x0406, 0x4F19);
		bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS,
		bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS,
				  (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0xFC3F) | 0x0340);
				  (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS)
				  & 0xFC3F) | 0x0340);
		bcm43xx_phy_write(bcm, 0x042C, 0x005A);
		bcm43xx_phy_write(bcm, 0x042C, 0x005A);
		bcm43xx_phy_write(bcm, 0x0427, 0x001A);
		bcm43xx_phy_write(bcm, 0x0427, 0x001A);


+4 −0
Original line number Original line Diff line number Diff line
@@ -48,6 +48,10 @@ void bcm43xx_raw_phy_unlock(struct bcm43xx_private *bcm);
		local_irq_restore(flags);	\
		local_irq_restore(flags);	\
	} while (0)
	} while (0)


/* Card uses the loopback gain stuff */
#define has_loopback_gain(phy) \
        (((phy)->rev > 1) || ((phy)->connected))

u16 bcm43xx_phy_read(struct bcm43xx_private *bcm, u16 offset);
u16 bcm43xx_phy_read(struct bcm43xx_private *bcm, u16 offset);
void bcm43xx_phy_write(struct bcm43xx_private *bcm, u16 offset, u16 val);
void bcm43xx_phy_write(struct bcm43xx_private *bcm, u16 offset, u16 val);


+170 −26
Original line number Original line Diff line number Diff line
@@ -1343,11 +1343,110 @@ u16 bcm43xx_radio_calibrationvalue(struct bcm43xx_private *bcm)
	return ret;
	return ret;
}
}


#define LPD(L, P, D)    (((L) << 2) | ((P) << 1) | ((D) << 0))
static u16 bcm43xx_get_812_value(struct bcm43xx_private *bcm, u8 lpd)
{
	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
	u16 loop_or = 0;
	u16 adj_loopback_gain = phy->loopback_gain[0];
	u8 loop;
	u16 extern_lna_control;

	if (!phy->connected)
		return 0;
	if (!has_loopback_gain(phy)) {
		if (phy->rev < 7 || !(bcm->sprom.boardflags
		    & BCM43xx_BFL_EXTLNA)) {
			switch (lpd) {
			case LPD(0, 1, 1):
				return 0x0FB2;
			case LPD(0, 0, 1):
				return 0x00B2;
			case LPD(1, 0, 1):
				return 0x30B2;
			case LPD(1, 0, 0):
				return 0x30B3;
			default:
				assert(0);
			}
		} else {
			switch (lpd) {
			case LPD(0, 1, 1):
				return 0x8FB2;
			case LPD(0, 0, 1):
				return 0x80B2;
			case LPD(1, 0, 1):
				return 0x20B2;
			case LPD(1, 0, 0):
				return 0x20B3;
			default:
				assert(0);
			}
		}
	} else {
		if (radio->revision == 8)
			adj_loopback_gain += 0x003E;
		else
			adj_loopback_gain += 0x0026;
		if (adj_loopback_gain >= 0x46) {
			adj_loopback_gain -= 0x46;
			extern_lna_control = 0x3000;
		} else if (adj_loopback_gain >= 0x3A) {
			adj_loopback_gain -= 0x3A;
			extern_lna_control = 0x2000;
		} else if (adj_loopback_gain >= 0x2E) {
			adj_loopback_gain -= 0x2E;
			extern_lna_control = 0x1000;
		} else {
			adj_loopback_gain -= 0x10;
			extern_lna_control = 0x0000;
		}
		for (loop = 0; loop < 16; loop++) {
			u16 tmp = adj_loopback_gain - 6 * loop;
			if (tmp < 6)
				break;
		}

		loop_or = (loop << 8) | extern_lna_control;
		if (phy->rev >= 7 && bcm->sprom.boardflags
		    & BCM43xx_BFL_EXTLNA) {
			if (extern_lna_control)
				loop_or |= 0x8000;
			switch (lpd) {
			case LPD(0, 1, 1):
				return 0x8F92;
			case LPD(0, 0, 1):
				return (0x8092 | loop_or);
			case LPD(1, 0, 1):
				return (0x2092 | loop_or);
			case LPD(1, 0, 0):
				return (0x2093 | loop_or);
			default:
				assert(0);
			}
		} else {
			switch (lpd) {
			case LPD(0, 1, 1):
				return 0x0F92;
			case LPD(0, 0, 1):
			case LPD(1, 0, 1):
				return (0x0092 | loop_or);
			case LPD(1, 0, 0):
				return (0x0093 | loop_or);
			default:
				assert(0);
			}
		}
	}
	return 0;
}

u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm)
u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm)
{
{
	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
	u16 backup[19] = { 0 };
	u16 backup[21] = { 0 };
	u16 ret;
	u16 ret;
	u16 i, j;
	u16 i, j;
	u32 tmp1 = 0, tmp2 = 0;
	u32 tmp1 = 0, tmp2 = 0;
@@ -1373,19 +1472,36 @@ u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm)
			backup[8] = bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS);
			backup[8] = bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS);
			backup[9] = bcm43xx_phy_read(bcm, 0x0802);
			backup[9] = bcm43xx_phy_read(bcm, 0x0802);
			bcm43xx_phy_write(bcm, 0x0814,
			bcm43xx_phy_write(bcm, 0x0814,
			                  (bcm43xx_phy_read(bcm, 0x0814) | 0x0003));
			                  (bcm43xx_phy_read(bcm, 0x0814)
					  | 0x0003));
			bcm43xx_phy_write(bcm, 0x0815,
			bcm43xx_phy_write(bcm, 0x0815,
			                  (bcm43xx_phy_read(bcm, 0x0815) & 0xFFFC));	
			                  (bcm43xx_phy_read(bcm, 0x0815)
					  & 0xFFFC));
			bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS,
			bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS,
			                  (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0x7FFF));
			                  (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS)
					  & 0x7FFF));
			bcm43xx_phy_write(bcm, 0x0802,
			bcm43xx_phy_write(bcm, 0x0802,
			                  (bcm43xx_phy_read(bcm, 0x0802) & 0xFFFC));
			                  (bcm43xx_phy_read(bcm, 0x0802) & 0xFFFC));
			if (phy->rev > 1) { /* loopback gain enabled */
				backup[19] = bcm43xx_phy_read(bcm, 0x080F);
				backup[20] = bcm43xx_phy_read(bcm, 0x0810);
				if (phy->rev >= 3)
					bcm43xx_phy_write(bcm, 0x080F, 0xC020);
				else
					bcm43xx_phy_write(bcm, 0x080F, 0x8020);
				bcm43xx_phy_write(bcm, 0x0810, 0x0000);
			}
			bcm43xx_phy_write(bcm, 0x0812,
					  bcm43xx_get_812_value(bcm, LPD(0, 1, 1)));
			if (phy->rev < 7 || !(bcm->sprom.boardflags
			    & BCM43xx_BFL_EXTLNA))
				bcm43xx_phy_write(bcm, 0x0811, 0x01B3);
				bcm43xx_phy_write(bcm, 0x0811, 0x01B3);
			bcm43xx_phy_write(bcm, 0x0812, 0x0FB2);
			else
				bcm43xx_phy_write(bcm, 0x0811, 0x09B3);
		}
	}
	}
	bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO,
	bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO,
	                (bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_RADIO) | 0x8000));
	                (bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_RADIO) | 0x8000));
	}
	backup[10] = bcm43xx_phy_read(bcm, 0x0035);
	backup[10] = bcm43xx_phy_read(bcm, 0x0035);
	bcm43xx_phy_write(bcm, 0x0035,
	bcm43xx_phy_write(bcm, 0x0035,
	                  (bcm43xx_phy_read(bcm, 0x0035) & 0xFF7F));
	                  (bcm43xx_phy_read(bcm, 0x0035) & 0xFF7F));
@@ -1397,10 +1513,12 @@ u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm)
		bcm43xx_write16(bcm, 0x03E6, 0x0122);
		bcm43xx_write16(bcm, 0x03E6, 0x0122);
	} else {
	} else {
		if (phy->analog >= 2)
		if (phy->analog >= 2)
			bcm43xx_phy_write(bcm, 0x0003, (bcm43xx_phy_read(bcm, 0x0003)
			bcm43xx_phy_write(bcm, 0x0003,
					  (bcm43xx_phy_read(bcm, 0x0003)
					  & 0xFFBF) | 0x0040);
					  & 0xFFBF) | 0x0040);
		bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT,
		bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT,
		                (bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT) | 0x2000));
		                (bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT)
				| 0x2000));
	}
	}


	ret = bcm43xx_radio_calibrationvalue(bcm);
	ret = bcm43xx_radio_calibrationvalue(bcm);
@@ -1408,16 +1526,25 @@ u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm)
	if (phy->type == BCM43xx_PHYTYPE_B)
	if (phy->type == BCM43xx_PHYTYPE_B)
		bcm43xx_radio_write16(bcm, 0x0078, 0x0026);
		bcm43xx_radio_write16(bcm, 0x0078, 0x0026);


	if (phy->connected)
		bcm43xx_phy_write(bcm, 0x0812,
				  bcm43xx_get_812_value(bcm, LPD(0, 1, 1)));
	bcm43xx_phy_write(bcm, 0x0015, 0xBFAF);
	bcm43xx_phy_write(bcm, 0x0015, 0xBFAF);
	bcm43xx_phy_write(bcm, 0x002B, 0x1403);
	bcm43xx_phy_write(bcm, 0x002B, 0x1403);
	if (phy->connected)
	if (phy->connected)
		bcm43xx_phy_write(bcm, 0x0812, 0x00B2);
		bcm43xx_phy_write(bcm, 0x0812,
				  bcm43xx_get_812_value(bcm, LPD(0, 0, 1)));
	bcm43xx_phy_write(bcm, 0x0015, 0xBFA0);
	bcm43xx_phy_write(bcm, 0x0015, 0xBFA0);
	bcm43xx_radio_write16(bcm, 0x0051,
	bcm43xx_radio_write16(bcm, 0x0051,
	                      (bcm43xx_radio_read16(bcm, 0x0051) | 0x0004));
	                      (bcm43xx_radio_read16(bcm, 0x0051) | 0x0004));
	if (radio->revision == 8)
		bcm43xx_radio_write16(bcm, 0x0043, 0x001F);
	else {
		bcm43xx_radio_write16(bcm, 0x0052, 0x0000);
		bcm43xx_radio_write16(bcm, 0x0052, 0x0000);
		bcm43xx_radio_write16(bcm, 0x0043,
		bcm43xx_radio_write16(bcm, 0x0043,
			      (bcm43xx_radio_read16(bcm, 0x0043) & 0xFFF0) | 0x0009);
				      (bcm43xx_radio_read16(bcm, 0x0043) & 0xFFF0)
				      | 0x0009);
	}
	bcm43xx_phy_write(bcm, 0x0058, 0x0000);
	bcm43xx_phy_write(bcm, 0x0058, 0x0000);


	for (i = 0; i < 16; i++) {
	for (i = 0; i < 16; i++) {
@@ -1425,21 +1552,25 @@ u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm)
		bcm43xx_phy_write(bcm, 0x0059, 0xC810);
		bcm43xx_phy_write(bcm, 0x0059, 0xC810);
		bcm43xx_phy_write(bcm, 0x0058, 0x000D);
		bcm43xx_phy_write(bcm, 0x0058, 0x000D);
		if (phy->connected)
		if (phy->connected)
			bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
			bcm43xx_phy_write(bcm, 0x0812,
					  bcm43xx_get_812_value(bcm, LPD(1, 0, 1)));
		bcm43xx_phy_write(bcm, 0x0015, 0xAFB0);
		bcm43xx_phy_write(bcm, 0x0015, 0xAFB0);
		udelay(10);
		udelay(10);
		if (phy->connected)
		if (phy->connected)
			bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
			bcm43xx_phy_write(bcm, 0x0812,
					  bcm43xx_get_812_value(bcm, LPD(1, 0, 1)));
		bcm43xx_phy_write(bcm, 0x0015, 0xEFB0);
		bcm43xx_phy_write(bcm, 0x0015, 0xEFB0);
		udelay(10);
		udelay(10);
		if (phy->connected)
		if (phy->connected)
			bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
			bcm43xx_phy_write(bcm, 0x0812,
					  bcm43xx_get_812_value(bcm, LPD(1, 0, 0)));
		bcm43xx_phy_write(bcm, 0x0015, 0xFFF0);
		bcm43xx_phy_write(bcm, 0x0015, 0xFFF0);
		udelay(10);
		udelay(20);
		tmp1 += bcm43xx_phy_read(bcm, 0x002D);
		tmp1 += bcm43xx_phy_read(bcm, 0x002D);
		bcm43xx_phy_write(bcm, 0x0058, 0x0000);
		bcm43xx_phy_write(bcm, 0x0058, 0x0000);
		if (phy->connected)
		if (phy->connected)
			bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
			bcm43xx_phy_write(bcm, 0x0812,
					  bcm43xx_get_812_value(bcm, LPD(1, 0, 1)));
		bcm43xx_phy_write(bcm, 0x0015, 0xAFB0);
		bcm43xx_phy_write(bcm, 0x0015, 0xAFB0);
	}
	}


@@ -1457,21 +1588,29 @@ u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm)
			bcm43xx_phy_write(bcm, 0x0059, 0xC810);
			bcm43xx_phy_write(bcm, 0x0059, 0xC810);
			bcm43xx_phy_write(bcm, 0x0058, 0x000D);
			bcm43xx_phy_write(bcm, 0x0058, 0x000D);
			if (phy->connected)
			if (phy->connected)
				bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
				bcm43xx_phy_write(bcm, 0x0812,
						  bcm43xx_get_812_value(bcm,
						  LPD(1, 0, 1)));
			bcm43xx_phy_write(bcm, 0x0015, 0xAFB0);
			bcm43xx_phy_write(bcm, 0x0015, 0xAFB0);
			udelay(10);
			udelay(10);
			if (phy->connected)
			if (phy->connected)
				bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
				bcm43xx_phy_write(bcm, 0x0812,
						  bcm43xx_get_812_value(bcm,
						  LPD(1, 0, 1)));
			bcm43xx_phy_write(bcm, 0x0015, 0xEFB0);
			bcm43xx_phy_write(bcm, 0x0015, 0xEFB0);
			udelay(10);
			udelay(10);
			if (phy->connected)
			if (phy->connected)
				bcm43xx_phy_write(bcm, 0x0812, 0x30B3); /* 0x30B3 is not a typo */
				bcm43xx_phy_write(bcm, 0x0812,
						  bcm43xx_get_812_value(bcm,
						  LPD(1, 0, 0)));
			bcm43xx_phy_write(bcm, 0x0015, 0xFFF0);
			bcm43xx_phy_write(bcm, 0x0015, 0xFFF0);
			udelay(10);
			udelay(10);
			tmp2 += bcm43xx_phy_read(bcm, 0x002D);
			tmp2 += bcm43xx_phy_read(bcm, 0x002D);
			bcm43xx_phy_write(bcm, 0x0058, 0x0000);
			bcm43xx_phy_write(bcm, 0x0058, 0x0000);
			if (phy->connected)
			if (phy->connected)
				bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
				bcm43xx_phy_write(bcm, 0x0812,
						  bcm43xx_get_812_value(bcm,
						  LPD(1, 0, 1)));
			bcm43xx_phy_write(bcm, 0x0015, 0xAFB0);
			bcm43xx_phy_write(bcm, 0x0015, 0xAFB0);
		}
		}
		tmp2++;
		tmp2++;
@@ -1497,15 +1636,20 @@ u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm)
		bcm43xx_phy_write(bcm, 0x0030, backup[2]);
		bcm43xx_phy_write(bcm, 0x0030, backup[2]);
		bcm43xx_write16(bcm, 0x03EC, backup[3]);
		bcm43xx_write16(bcm, 0x03EC, backup[3]);
	} else {
	} else {
		bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO,
				(bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_RADIO) & 0x7FFF));
		if (phy->connected) {
		if (phy->connected) {
			bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO,
					(bcm43xx_read16(bcm,
					BCM43xx_MMIO_PHY_RADIO) & 0x7FFF));
			bcm43xx_phy_write(bcm, 0x0811, backup[4]);
			bcm43xx_phy_write(bcm, 0x0811, backup[4]);
			bcm43xx_phy_write(bcm, 0x0812, backup[5]);
			bcm43xx_phy_write(bcm, 0x0812, backup[5]);
			bcm43xx_phy_write(bcm, 0x0814, backup[6]);
			bcm43xx_phy_write(bcm, 0x0814, backup[6]);
			bcm43xx_phy_write(bcm, 0x0815, backup[7]);
			bcm43xx_phy_write(bcm, 0x0815, backup[7]);
			bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, backup[8]);
			bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, backup[8]);
			bcm43xx_phy_write(bcm, 0x0802, backup[9]);
			bcm43xx_phy_write(bcm, 0x0802, backup[9]);
			if (phy->rev > 1) {
				bcm43xx_phy_write(bcm, 0x080F, backup[19]);
				bcm43xx_phy_write(bcm, 0x0810, backup[20]);
			}
		}
		}
	}
	}
	if (i >= 15)
	if (i >= 15)