aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/bcm43xx/bcm43xx_radio.c')
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_radio.c229
1 files changed, 187 insertions, 42 deletions
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
index af19a07032a3..6a109f4a1b71 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
@@ -458,7 +458,7 @@ static void bcm43xx_calc_nrssi_offset(struct bcm43xx_private *bcm)
bcm43xx_phy_write(bcm, 0x005A, 0x0480);
bcm43xx_phy_write(bcm, 0x0059, 0x0810);
bcm43xx_phy_write(bcm, 0x0058, 0x000D);
- if (phy->rev == 0) {
+ if (phy->analog == 0) {
bcm43xx_phy_write(bcm, 0x0003, 0x0122);
} else {
bcm43xx_phy_write(bcm, 0x000A,
@@ -570,9 +570,9 @@ void bcm43xx_calc_nrssi_slope(struct bcm43xx_private *bcm)
nrssi0 = (s16)bcm43xx_phy_read(bcm, 0x0027);
bcm43xx_radio_write16(bcm, 0x007A,
bcm43xx_radio_read16(bcm, 0x007A) & 0x007F);
- if (phy->rev >= 2) {
+ if (phy->analog >= 2) {
bcm43xx_write16(bcm, 0x03E6, 0x0040);
- } else if (phy->rev == 0) {
+ } else if (phy->analog == 0) {
bcm43xx_write16(bcm, 0x03E6, 0x0122);
} else {
bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT,
@@ -596,7 +596,7 @@ void bcm43xx_calc_nrssi_slope(struct bcm43xx_private *bcm)
bcm43xx_phy_write(bcm, 0x0015, backup[5]);
bcm43xx_phy_write(bcm, 0x002A, backup[6]);
bcm43xx_synth_pu_workaround(bcm, radio->channel);
- if (phy->rev != 0)
+ if (phy->analog != 0)
bcm43xx_write16(bcm, 0x03F4, backup[13]);
bcm43xx_phy_write(bcm, 0x0020, backup[7]);
@@ -692,7 +692,7 @@ void bcm43xx_calc_nrssi_slope(struct bcm43xx_private *bcm)
bcm43xx_radio_write16(bcm, 0x007A,
bcm43xx_radio_read16(bcm, 0x007A) & 0x007F);
- if (phy->rev >= 2) {
+ if (phy->analog >= 2) {
bcm43xx_phy_write(bcm, 0x0003,
(bcm43xx_phy_read(bcm, 0x0003)
& 0xFF9F) | 0x0040);
@@ -882,10 +882,10 @@ static void _stack_save(u32 *_stackptr, size_t *stackidx,
{
u32 *stackptr = &(_stackptr[*stackidx]);
- assert((offset & 0xF000) == 0x0000);
- assert((id & 0xF0) == 0x00);
+ assert((offset & 0xE000) == 0x0000);
+ assert((id & 0xF8) == 0x00);
*stackptr = offset;
- *stackptr |= ((u32)id) << 12;
+ *stackptr |= ((u32)id) << 13;
*stackptr |= ((u32)value) << 16;
(*stackidx)++;
assert(*stackidx < BCM43xx_INTERFSTACK_SIZE);
@@ -896,12 +896,12 @@ static u16 _stack_restore(u32 *stackptr,
{
size_t i;
- assert((offset & 0xF000) == 0x0000);
- assert((id & 0xF0) == 0x00);
+ assert((offset & 0xE000) == 0x0000);
+ assert((id & 0xF8) == 0x00);
for (i = 0; i < BCM43xx_INTERFSTACK_SIZE; i++, stackptr++) {
- if ((*stackptr & 0x00000FFF) != offset)
+ if ((*stackptr & 0x00001FFF) != offset)
continue;
- if (((*stackptr & 0x0000F000) >> 12) != id)
+ if (((*stackptr & 0x00007000) >> 13) != id)
continue;
return ((*stackptr & 0xFFFF0000) >> 16);
}
@@ -1343,11 +1343,110 @@ u16 bcm43xx_radio_calibrationvalue(struct bcm43xx_private *bcm)
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)
{
struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
- u16 backup[19] = { 0 };
+ u16 backup[21] = { 0 };
u16 ret;
u16 i, j;
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[9] = bcm43xx_phy_read(bcm, 0x0802);
bcm43xx_phy_write(bcm, 0x0814,
- (bcm43xx_phy_read(bcm, 0x0814) | 0x0003));
+ (bcm43xx_phy_read(bcm, 0x0814)
+ | 0x0003));
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_read(bcm, BCM43xx_PHY_G_CRS) & 0x7FFF));
+ (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS)
+ & 0x7FFF));
bcm43xx_phy_write(bcm, 0x0802,
(bcm43xx_phy_read(bcm, 0x0802) & 0xFFFC));
- bcm43xx_phy_write(bcm, 0x0811, 0x01B3);
- bcm43xx_phy_write(bcm, 0x0812, 0x0FB2);
+ 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);
+ else
+ bcm43xx_phy_write(bcm, 0x0811, 0x09B3);
}
- bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO,
- (bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_RADIO) | 0x8000));
}
+ bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO,
+ (bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_RADIO) | 0x8000));
backup[10] = bcm43xx_phy_read(bcm, 0x0035);
bcm43xx_phy_write(bcm, 0x0035,
(bcm43xx_phy_read(bcm, 0x0035) & 0xFF7F));
@@ -1393,30 +1509,42 @@ u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm)
backup[12] = bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT);
// Initialization
- if (phy->version == 0) {
+ if (phy->analog == 0) {
bcm43xx_write16(bcm, 0x03E6, 0x0122);
} else {
- if (phy->version >= 2)
- bcm43xx_write16(bcm, 0x03E6, 0x0040);
+ if (phy->analog >= 2)
+ bcm43xx_phy_write(bcm, 0x0003,
+ (bcm43xx_phy_read(bcm, 0x0003)
+ & 0xFFBF) | 0x0040);
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);
if (phy->type == BCM43xx_PHYTYPE_B)
- bcm43xx_radio_write16(bcm, 0x0078, 0x0003);
+ 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, 0x002B, 0x1403);
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_radio_write16(bcm, 0x0051,
(bcm43xx_radio_read16(bcm, 0x0051) | 0x0004));
- bcm43xx_radio_write16(bcm, 0x0052, 0x0000);
- bcm43xx_radio_write16(bcm, 0x0043,
- bcm43xx_radio_read16(bcm, 0x0043) | 0x0009);
+ if (radio->revision == 8)
+ bcm43xx_radio_write16(bcm, 0x0043, 0x001F);
+ else {
+ bcm43xx_radio_write16(bcm, 0x0052, 0x0000);
+ bcm43xx_radio_write16(bcm, 0x0043,
+ (bcm43xx_radio_read16(bcm, 0x0043) & 0xFFF0)
+ | 0x0009);
+ }
bcm43xx_phy_write(bcm, 0x0058, 0x0000);
for (i = 0; i < 16; i++) {
@@ -1424,21 +1552,25 @@ u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm)
bcm43xx_phy_write(bcm, 0x0059, 0xC810);
bcm43xx_phy_write(bcm, 0x0058, 0x000D);
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);
udelay(10);
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);
udelay(10);
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);
- udelay(10);
+ udelay(20);
tmp1 += bcm43xx_phy_read(bcm, 0x002D);
bcm43xx_phy_write(bcm, 0x0058, 0x0000);
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);
}
@@ -1456,21 +1588,29 @@ u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm)
bcm43xx_phy_write(bcm, 0x0059, 0xC810);
bcm43xx_phy_write(bcm, 0x0058, 0x000D);
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);
udelay(10);
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);
udelay(10);
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);
udelay(10);
tmp2 += bcm43xx_phy_read(bcm, 0x002D);
bcm43xx_phy_write(bcm, 0x0058, 0x0000);
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);
}
tmp2++;
@@ -1488,7 +1628,7 @@ u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm)
bcm43xx_phy_write(bcm, 0x0059, backup[17]);
bcm43xx_phy_write(bcm, 0x0058, backup[18]);
bcm43xx_write16(bcm, 0x03E6, backup[11]);
- if (phy->version != 0)
+ if (phy->analog != 0)
bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, backup[12]);
bcm43xx_phy_write(bcm, 0x0035, backup[10]);
bcm43xx_radio_selectchannel(bcm, radio->channel, 1);
@@ -1496,15 +1636,20 @@ u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm)
bcm43xx_phy_write(bcm, 0x0030, backup[2]);
bcm43xx_write16(bcm, 0x03EC, backup[3]);
} else {
- bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO,
- (bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_RADIO) & 0x7FFF));
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, 0x0812, backup[5]);
bcm43xx_phy_write(bcm, 0x0814, backup[6]);
bcm43xx_phy_write(bcm, 0x0815, backup[7]);
bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, backup[8]);
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)
@@ -1578,7 +1723,7 @@ void bcm43xx_radio_set_tx_iq(struct bcm43xx_private *bcm)
for (i = 0; i < 5; i++) {
for (j = 0; j < 5; j++) {
- if (tmp == (data_high[i] << 4 | data_low[j])) {
+ if (tmp == (data_high[i] | data_low[j])) {
bcm43xx_phy_write(bcm, 0x0069, (i - j) << 8 | 0x00C0);
return;
}