b43: N-PHY: split RSSI selection into two per-PHY-revision functions
[sfrench/cifs-2.6.git] / drivers / net / wireless / b43 / phy_n.c
index 1359267a35ff80ea259c171bf744d1361d6e6bbf..558d3c052d9569a40146192f74de0b84ae2685ba 100644 (file)
@@ -246,110 +246,6 @@ static void b43_nphy_tables_init(struct b43_wldev *dev)
                b43_nphy_rev3plus_tables_init(dev);
 }
 
-static void b43_nphy_workarounds(struct b43_wldev *dev)
-{
-       struct b43_phy *phy = &dev->phy;
-       unsigned int i;
-
-       b43_phy_set(dev, B43_NPHY_IQFLIP,
-                   B43_NPHY_IQFLIP_ADC1 | B43_NPHY_IQFLIP_ADC2);
-       if (1 /* FIXME band is 2.4GHz */) {
-               b43_phy_set(dev, B43_NPHY_CLASSCTL,
-                           B43_NPHY_CLASSCTL_CCKEN);
-       } else {
-               b43_phy_mask(dev, B43_NPHY_CLASSCTL,
-                            ~B43_NPHY_CLASSCTL_CCKEN);
-       }
-       b43_radio_set(dev, B2055_C1_TX_RF_SPARE, 0x8);
-       b43_phy_write(dev, B43_NPHY_TXFRAMEDELAY, 8);
-
-       /* Fixup some tables */
-       b43_ntab_write(dev, B43_NTAB16(8, 0x00), 0xA);
-       b43_ntab_write(dev, B43_NTAB16(8, 0x10), 0xA);
-       b43_ntab_write(dev, B43_NTAB16(8, 0x02), 0xCDAA);
-       b43_ntab_write(dev, B43_NTAB16(8, 0x12), 0xCDAA);
-       b43_ntab_write(dev, B43_NTAB16(8, 0x08), 0);
-       b43_ntab_write(dev, B43_NTAB16(8, 0x18), 0);
-       b43_ntab_write(dev, B43_NTAB16(8, 0x07), 0x7AAB);
-       b43_ntab_write(dev, B43_NTAB16(8, 0x17), 0x7AAB);
-       b43_ntab_write(dev, B43_NTAB16(8, 0x06), 0x800);
-       b43_ntab_write(dev, B43_NTAB16(8, 0x16), 0x800);
-
-       b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_LO1, 0x2D8);
-       b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP1, 0x301);
-       b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_LO2, 0x2D8);
-       b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP2, 0x301);
-
-       //TODO set RF sequence
-
-       /* Set narrowband clip threshold */
-       b43_phy_write(dev, B43_NPHY_C1_NBCLIPTHRES, 66);
-       b43_phy_write(dev, B43_NPHY_C2_NBCLIPTHRES, 66);
-
-       /* Set wideband clip 2 threshold */
-       b43_phy_maskset(dev, B43_NPHY_C1_CLIPWBTHRES,
-                       ~B43_NPHY_C1_CLIPWBTHRES_CLIP2,
-                       21 << B43_NPHY_C1_CLIPWBTHRES_CLIP2_SHIFT);
-       b43_phy_maskset(dev, B43_NPHY_C2_CLIPWBTHRES,
-                       ~B43_NPHY_C2_CLIPWBTHRES_CLIP2,
-                       21 << B43_NPHY_C2_CLIPWBTHRES_CLIP2_SHIFT);
-
-       /* Set Clip 2 detect */
-       b43_phy_set(dev, B43_NPHY_C1_CGAINI,
-                   B43_NPHY_C1_CGAINI_CL2DETECT);
-       b43_phy_set(dev, B43_NPHY_C2_CGAINI,
-                   B43_NPHY_C2_CGAINI_CL2DETECT);
-
-       if (0 /*FIXME*/) {
-               /* Set dwell lengths */
-               b43_phy_write(dev, B43_NPHY_CLIP1_NBDWELL_LEN, 43);
-               b43_phy_write(dev, B43_NPHY_CLIP2_NBDWELL_LEN, 43);
-               b43_phy_write(dev, B43_NPHY_W1CLIP1_DWELL_LEN, 9);
-               b43_phy_write(dev, B43_NPHY_W1CLIP2_DWELL_LEN, 9);
-
-               /* Set gain backoff */
-               b43_phy_maskset(dev, B43_NPHY_C1_CGAINI,
-                               ~B43_NPHY_C1_CGAINI_GAINBKOFF,
-                               1 << B43_NPHY_C1_CGAINI_GAINBKOFF_SHIFT);
-               b43_phy_maskset(dev, B43_NPHY_C2_CGAINI,
-                               ~B43_NPHY_C2_CGAINI_GAINBKOFF,
-                               1 << B43_NPHY_C2_CGAINI_GAINBKOFF_SHIFT);
-
-               /* Set HPVGA2 index */
-               b43_phy_maskset(dev, B43_NPHY_C1_INITGAIN,
-                               ~B43_NPHY_C1_INITGAIN_HPVGA2,
-                               6 << B43_NPHY_C1_INITGAIN_HPVGA2_SHIFT);
-               b43_phy_maskset(dev, B43_NPHY_C2_INITGAIN,
-                               ~B43_NPHY_C2_INITGAIN_HPVGA2,
-                               6 << B43_NPHY_C2_INITGAIN_HPVGA2_SHIFT);
-
-               //FIXME verify that the specs really mean to use autoinc here.
-               for (i = 0; i < 3; i++)
-                       b43_ntab_write(dev, B43_NTAB16(7, 0x106) + i, 0x673);
-       }
-
-       /* Set minimum gain value */
-       b43_phy_maskset(dev, B43_NPHY_C1_MINMAX_GAIN,
-                       ~B43_NPHY_C1_MINGAIN,
-                       23 << B43_NPHY_C1_MINGAIN_SHIFT);
-       b43_phy_maskset(dev, B43_NPHY_C2_MINMAX_GAIN,
-                       ~B43_NPHY_C2_MINGAIN,
-                       23 << B43_NPHY_C2_MINGAIN_SHIFT);
-
-       if (phy->rev < 2) {
-               b43_phy_mask(dev, B43_NPHY_SCRAM_SIGCTL,
-                            ~B43_NPHY_SCRAM_SIGCTL_SCM);
-       }
-
-       /* Set phase track alpha and beta */
-       b43_phy_write(dev, B43_NPHY_PHASETR_A0, 0x125);
-       b43_phy_write(dev, B43_NPHY_PHASETR_A1, 0x1B3);
-       b43_phy_write(dev, B43_NPHY_PHASETR_A2, 0x105);
-       b43_phy_write(dev, B43_NPHY_PHASETR_B0, 0x16E);
-       b43_phy_write(dev, B43_NPHY_PHASETR_B1, 0xCD);
-       b43_phy_write(dev, B43_NPHY_PHASETR_B2, 0x20);
-}
-
 /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/PA%20override */
 static void b43_nphy_pa_override(struct b43_wldev *dev, bool enable)
 {
@@ -816,6 +712,359 @@ static void b43_nphy_stop_playback(struct b43_wldev *dev)
                b43_nphy_stay_in_carrier_search(dev, 0);
 }
 
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/WorkaroundsGainCtrl */
+static void b43_nphy_gain_crtl_workarounds(struct b43_wldev *dev)
+{
+       struct b43_phy_n *nphy = dev->phy.n;
+       u8 i, j;
+       u8 code;
+
+       /* TODO: for PHY >= 3
+       s8 *lna1_gain, *lna2_gain;
+       u8 *gain_db, *gain_bits;
+       u16 *rfseq_init;
+       u8 lpf_gain[6] = { 0x00, 0x06, 0x0C, 0x12, 0x12, 0x12 };
+       u8 lpf_bits[6] = { 0, 1, 2, 3, 3, 3 };
+       */
+
+       u8 rfseq_events[3] = { 6, 8, 7 };
+       u8 rfseq_delays[3] = { 10, 30, 1 };
+
+       if (dev->phy.rev >= 3) {
+               /* TODO */
+       } else {
+               /* Set Clip 2 detect */
+               b43_phy_set(dev, B43_NPHY_C1_CGAINI,
+                               B43_NPHY_C1_CGAINI_CL2DETECT);
+               b43_phy_set(dev, B43_NPHY_C2_CGAINI,
+                               B43_NPHY_C2_CGAINI_CL2DETECT);
+
+               /* Set narrowband clip threshold */
+               b43_phy_set(dev, B43_NPHY_C1_NBCLIPTHRES, 0x84);
+               b43_phy_set(dev, B43_NPHY_C2_NBCLIPTHRES, 0x84);
+
+               if (!dev->phy.is_40mhz) {
+                       /* Set dwell lengths */
+                       b43_phy_set(dev, B43_NPHY_CLIP1_NBDWELL_LEN, 0x002B);
+                       b43_phy_set(dev, B43_NPHY_CLIP2_NBDWELL_LEN, 0x002B);
+                       b43_phy_set(dev, B43_NPHY_W1CLIP1_DWELL_LEN, 0x0009);
+                       b43_phy_set(dev, B43_NPHY_W1CLIP2_DWELL_LEN, 0x0009);
+               }
+
+               /* Set wideband clip 2 threshold */
+               b43_phy_maskset(dev, B43_NPHY_C1_CLIPWBTHRES,
+                               ~B43_NPHY_C1_CLIPWBTHRES_CLIP2,
+                               21);
+               b43_phy_maskset(dev, B43_NPHY_C2_CLIPWBTHRES,
+                               ~B43_NPHY_C2_CLIPWBTHRES_CLIP2,
+                               21);
+
+               if (!dev->phy.is_40mhz) {
+                       b43_phy_maskset(dev, B43_NPHY_C1_CGAINI,
+                               ~B43_NPHY_C1_CGAINI_GAINBKOFF, 0x1);
+                       b43_phy_maskset(dev, B43_NPHY_C2_CGAINI,
+                               ~B43_NPHY_C2_CGAINI_GAINBKOFF, 0x1);
+                       b43_phy_maskset(dev, B43_NPHY_C1_CCK_CGAINI,
+                               ~B43_NPHY_C1_CCK_CGAINI_GAINBKOFF, 0x1);
+                       b43_phy_maskset(dev, B43_NPHY_C2_CCK_CGAINI,
+                               ~B43_NPHY_C2_CCK_CGAINI_GAINBKOFF, 0x1);
+               }
+
+               b43_phy_set(dev, B43_NPHY_CCK_SHIFTB_REF, 0x809C);
+
+               if (nphy->gain_boost) {
+                       if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ &&
+                           dev->phy.is_40mhz)
+                               code = 4;
+                       else
+                               code = 5;
+               } else {
+                       code = dev->phy.is_40mhz ? 6 : 7;
+               }
+
+               /* Set HPVGA2 index */
+               b43_phy_maskset(dev, B43_NPHY_C1_INITGAIN,
+                               ~B43_NPHY_C1_INITGAIN_HPVGA2,
+                               code << B43_NPHY_C1_INITGAIN_HPVGA2_SHIFT);
+               b43_phy_maskset(dev, B43_NPHY_C2_INITGAIN,
+                               ~B43_NPHY_C2_INITGAIN_HPVGA2,
+                               code << B43_NPHY_C2_INITGAIN_HPVGA2_SHIFT);
+
+               b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x1D06);
+               b43_phy_write(dev, B43_NPHY_TABLE_DATALO,
+                                       (code << 8 | 0x7C));
+               b43_phy_write(dev, B43_NPHY_TABLE_DATALO,
+                                       (code << 8 | 0x7C));
+
+               /* TODO: b43_nphy_adjust_lna_gain_table(dev); */
+
+               if (nphy->elna_gain_config) {
+                       b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x0808);
+                       b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x0);
+                       b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x1);
+                       b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x1);
+                       b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x1);
+
+                       b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x0C08);
+                       b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x0);
+                       b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x1);
+                       b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x1);
+                       b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x1);
+
+                       b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x1D06);
+                       b43_phy_write(dev, B43_NPHY_TABLE_DATALO,
+                                       (code << 8 | 0x74));
+                       b43_phy_write(dev, B43_NPHY_TABLE_DATALO,
+                                       (code << 8 | 0x74));
+               }
+
+               if (dev->phy.rev == 2) {
+                       for (i = 0; i < 4; i++) {
+                               b43_phy_write(dev, B43_NPHY_TABLE_ADDR,
+                                               (0x0400 * i) + 0x0020);
+                               for (j = 0; j < 21; j++)
+                                       b43_phy_write(dev,
+                                               B43_NPHY_TABLE_DATALO, 3 * j);
+                       }
+
+                       /* TODO: b43_nphy_set_rf_sequence(dev, 5,
+                                       rfseq_events, rfseq_delays, 3);*/
+                       b43_phy_maskset(dev, B43_NPHY_OVER_DGAIN1,
+                               (u16)~B43_NPHY_OVER_DGAIN_CCKDGECV,
+                               0x5A << B43_NPHY_OVER_DGAIN_CCKDGECV_SHIFT);
+
+                       if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
+                               b43_phy_maskset(dev, B43_PHY_N(0xC5D),
+                                               0xFF80, 4);
+               }
+       }
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/Workarounds */
+static void b43_nphy_workarounds(struct b43_wldev *dev)
+{
+       struct ssb_bus *bus = dev->dev->bus;
+       struct b43_phy *phy = &dev->phy;
+       struct b43_phy_n *nphy = phy->n;
+
+       u8 events1[7] = { 0x0, 0x1, 0x2, 0x8, 0x4, 0x5, 0x3 };
+       u8 delays1[7] = { 0x8, 0x6, 0x6, 0x2, 0x4, 0x3C, 0x1 };
+
+       u8 events2[7] = { 0x0, 0x3, 0x5, 0x4, 0x2, 0x1, 0x8 };
+       u8 delays2[7] = { 0x8, 0x6, 0x2, 0x4, 0x4, 0x6, 0x1 };
+
+       if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
+               b43_nphy_classifier(dev, 1, 0);
+       else
+               b43_nphy_classifier(dev, 1, 1);
+
+       if (nphy->hang_avoid)
+               b43_nphy_stay_in_carrier_search(dev, 1);
+
+       b43_phy_set(dev, B43_NPHY_IQFLIP,
+                   B43_NPHY_IQFLIP_ADC1 | B43_NPHY_IQFLIP_ADC2);
+
+       if (dev->phy.rev >= 3) {
+               /* TODO */
+       } else {
+               if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ &&
+                   nphy->band5g_pwrgain) {
+                       b43_radio_mask(dev, B2055_C1_TX_RF_SPARE, ~0x8);
+                       b43_radio_mask(dev, B2055_C2_TX_RF_SPARE, ~0x8);
+               } else {
+                       b43_radio_set(dev, B2055_C1_TX_RF_SPARE, 0x8);
+                       b43_radio_set(dev, B2055_C2_TX_RF_SPARE, 0x8);
+               }
+
+               /* TODO: convert to b43_ntab_write? */
+               b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x2000);
+               b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x000A);
+               b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x2010);
+               b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x000A);
+               b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x2002);
+               b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0xCDAA);
+               b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x2012);
+               b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0xCDAA);
+
+               if (dev->phy.rev < 2) {
+                       b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x2008);
+                       b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x0000);
+                       b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x2018);
+                       b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x0000);
+                       b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x2007);
+                       b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x7AAB);
+                       b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x2017);
+                       b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x7AAB);
+                       b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x2006);
+                       b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x0800);
+                       b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x2016);
+                       b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x0800);
+               }
+
+               b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_LO1, 0x2D8);
+               b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP1, 0x301);
+               b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_LO2, 0x2D8);
+               b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP2, 0x301);
+
+               if (bus->sprom.boardflags2_lo & 0x100 &&
+                   bus->boardinfo.type == 0x8B) {
+                       delays1[0] = 0x1;
+                       delays1[5] = 0x14;
+               }
+               /*TODO:b43_nphy_set_rf_sequence(dev, 0, events1, delays1, 7);*/
+               /*TODO:b43_nphy_set_rf_sequence(dev, 1, events2, delays2, 7);*/
+
+               b43_nphy_gain_crtl_workarounds(dev);
+
+               if (dev->phy.rev < 2) {
+                       if (b43_phy_read(dev, B43_NPHY_RXCTL) & 0x2)
+                               ; /*TODO: b43_mhf(dev, 2, 0x0010, 0x0010, 3);*/
+               } else if (dev->phy.rev == 2) {
+                       b43_phy_write(dev, B43_NPHY_CRSCHECK2, 0);
+                       b43_phy_write(dev, B43_NPHY_CRSCHECK3, 0);
+               }
+
+               if (dev->phy.rev < 2)
+                       b43_phy_mask(dev, B43_NPHY_SCRAM_SIGCTL,
+                                       ~B43_NPHY_SCRAM_SIGCTL_SCM);
+
+               /* Set phase track alpha and beta */
+               b43_phy_write(dev, B43_NPHY_PHASETR_A0, 0x125);
+               b43_phy_write(dev, B43_NPHY_PHASETR_A1, 0x1B3);
+               b43_phy_write(dev, B43_NPHY_PHASETR_A2, 0x105);
+               b43_phy_write(dev, B43_NPHY_PHASETR_B0, 0x16E);
+               b43_phy_write(dev, B43_NPHY_PHASETR_B1, 0xCD);
+               b43_phy_write(dev, B43_NPHY_PHASETR_B2, 0x20);
+
+               b43_phy_mask(dev, B43_NPHY_PIL_DW1,
+                               (u16)~B43_NPHY_PIL_DW_64QAM);
+               b43_phy_write(dev, B43_NPHY_TXF_20CO_S2B1, 0xB5);
+               b43_phy_write(dev, B43_NPHY_TXF_20CO_S2B2, 0xA4);
+               b43_phy_write(dev, B43_NPHY_TXF_20CO_S2B3, 0x00);
+
+               if (dev->phy.rev == 2)
+                       b43_phy_set(dev, B43_NPHY_FINERX2_CGC,
+                                       B43_NPHY_FINERX2_CGC_DECGC);
+       }
+
+       if (nphy->hang_avoid)
+               b43_nphy_stay_in_carrier_search(dev, 0);
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/GenLoadSamples */
+static u16 b43_nphy_gen_load_samples(struct b43_wldev *dev, u32 freq, u16 max,
+                                       bool test)
+{
+       int i;
+       u16 bw, len, rot, angle;
+       struct b43_c32 *samples;
+
+
+       bw = (dev->phy.is_40mhz) ? 40 : 20;
+       len = bw << 3;
+
+       if (test) {
+               if (b43_phy_read(dev, B43_NPHY_BBCFG) & B43_NPHY_BBCFG_RSTRX)
+                       bw = 82;
+               else
+                       bw = 80;
+
+               if (dev->phy.is_40mhz)
+                       bw <<= 1;
+
+               len = bw << 1;
+       }
+
+       samples = kzalloc(len * sizeof(struct b43_c32), GFP_KERNEL);
+       rot = (((freq * 36) / bw) << 16) / 100;
+       angle = 0;
+
+       for (i = 0; i < len; i++) {
+               samples[i] = b43_cordic(angle);
+               angle += rot;
+               samples[i].q = CORDIC_CONVERT(samples[i].q * max);
+               samples[i].i = CORDIC_CONVERT(samples[i].i * max);
+       }
+
+       /* TODO: Call N PHY Load Sample Table with buffer, len as arguments */
+       kfree(samples);
+       return len;
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RunSamples */
+static void b43_nphy_run_samples(struct b43_wldev *dev, u16 samps, u16 loops,
+                                       u16 wait, bool iqmode, bool dac_test)
+{
+       struct b43_phy_n *nphy = dev->phy.n;
+       int i;
+       u16 seq_mode;
+       u32 tmp;
+
+       if (nphy->hang_avoid)
+               b43_nphy_stay_in_carrier_search(dev, true);
+
+       if ((nphy->bb_mult_save & 0x80000000) == 0) {
+               tmp = b43_ntab_read(dev, B43_NTAB16(15, 87));
+               nphy->bb_mult_save = (tmp & 0xFFFF) | 0x80000000;
+       }
+
+       if (!dev->phy.is_40mhz)
+               tmp = 0x6464;
+       else
+               tmp = 0x4747;
+       b43_ntab_write(dev, B43_NTAB16(15, 87), tmp);
+
+       if (nphy->hang_avoid)
+               b43_nphy_stay_in_carrier_search(dev, false);
+
+       b43_phy_write(dev, B43_NPHY_SAMP_DEPCNT, (samps - 1));
+
+       if (loops != 0xFFFF)
+               b43_phy_write(dev, B43_NPHY_SAMP_LOOPCNT, (loops - 1));
+       else
+               b43_phy_write(dev, B43_NPHY_SAMP_LOOPCNT, loops);
+
+       b43_phy_write(dev, B43_NPHY_SAMP_WAITCNT, wait);
+
+       seq_mode = b43_phy_read(dev, B43_NPHY_RFSEQMODE);
+
+       b43_phy_set(dev, B43_NPHY_RFSEQMODE, B43_NPHY_RFSEQMODE_CAOVER);
+       if (iqmode) {
+               b43_phy_mask(dev, B43_NPHY_IQLOCAL_CMDGCTL, 0x7FFF);
+               b43_phy_set(dev, B43_NPHY_IQLOCAL_CMDGCTL, 0x8000);
+       } else {
+               if (dac_test)
+                       b43_phy_write(dev, B43_NPHY_SAMP_CMD, 5);
+               else
+                       b43_phy_write(dev, B43_NPHY_SAMP_CMD, 1);
+       }
+       for (i = 0; i < 100; i++) {
+               if (b43_phy_read(dev, B43_NPHY_RFSEQST) & 1) {
+                       i = 0;
+                       break;
+               }
+               udelay(10);
+       }
+       if (i)
+               b43err(dev->wl, "run samples timeout\n");
+
+       b43_phy_write(dev, B43_NPHY_RFSEQMODE, seq_mode);
+}
+
+/*
+ * Transmits a known value for LO calibration
+ * http://bcm-v4.sipsolutions.net/802.11/PHY/N/TXTone
+ */
+static int b43_nphy_tx_tone(struct b43_wldev *dev, u32 freq, u16 max_val,
+                               bool iqmode, bool dac_test)
+{
+       u16 samp = b43_nphy_gen_load_samples(dev, freq, max_val, dac_test);
+       if (samp == 0)
+               return -1;
+       b43_nphy_run_samples(dev, samp, 0xFFFF, 0, iqmode, dac_test);
+       return 0;
+}
+
 /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxPwrCtrlCoefSetup */
 static void b43_nphy_tx_pwr_ctrl_coef_setup(struct b43_wldev *dev)
 {
@@ -912,6 +1161,82 @@ ok:
        b43_phy_write(dev, B43_NPHY_RFSEQMODE, seq_mode);
 }
 
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RFCtrlOverride */
+static void b43_nphy_rf_control_override(struct b43_wldev *dev, u16 field,
+                                               u16 value, u8 core, bool off)
+{
+       int i;
+       u8 index = fls(field);
+       u8 addr, en_addr, val_addr;
+       /* we expect only one bit set */
+       B43_WARN_ON(field & (~(1 << (index - 1))));
+
+       if (dev->phy.rev >= 3) {
+               const struct nphy_rf_control_override_rev3 *rf_ctrl;
+               for (i = 0; i < 2; i++) {
+                       if (index == 0 || index == 16) {
+                               b43err(dev->wl,
+                                       "Unsupported RF Ctrl Override call\n");
+                               return;
+                       }
+
+                       rf_ctrl = &tbl_rf_control_override_rev3[index - 1];
+                       en_addr = B43_PHY_N((i == 0) ?
+                               rf_ctrl->en_addr0 : rf_ctrl->en_addr1);
+                       val_addr = B43_PHY_N((i == 0) ?
+                               rf_ctrl->val_addr0 : rf_ctrl->val_addr1);
+
+                       if (off) {
+                               b43_phy_mask(dev, en_addr, ~(field));
+                               b43_phy_mask(dev, val_addr,
+                                               ~(rf_ctrl->val_mask));
+                       } else {
+                               if (core == 0 || ((1 << core) & i) != 0) {
+                                       b43_phy_set(dev, en_addr, field);
+                                       b43_phy_maskset(dev, val_addr,
+                                               ~(rf_ctrl->val_mask),
+                                               (value << rf_ctrl->val_shift));
+                               }
+                       }
+               }
+       } else {
+               const struct nphy_rf_control_override_rev2 *rf_ctrl;
+               if (off) {
+                       b43_phy_mask(dev, B43_NPHY_RFCTL_OVER, ~(field));
+                       value = 0;
+               } else {
+                       b43_phy_set(dev, B43_NPHY_RFCTL_OVER, field);
+               }
+
+               for (i = 0; i < 2; i++) {
+                       if (index <= 1 || index == 16) {
+                               b43err(dev->wl,
+                                       "Unsupported RF Ctrl Override call\n");
+                               return;
+                       }
+
+                       if (index == 2 || index == 10 ||
+                           (index >= 13 && index <= 15)) {
+                               core = 1;
+                       }
+
+                       rf_ctrl = &tbl_rf_control_override_rev2[index - 2];
+                       addr = B43_PHY_N((i == 0) ?
+                               rf_ctrl->addr0 : rf_ctrl->addr1);
+
+                       if ((core & (1 << i)) != 0)
+                               b43_phy_maskset(dev, addr, ~(rf_ctrl->bmask),
+                                               (value << rf_ctrl->shift));
+
+                       b43_phy_set(dev, B43_NPHY_RFCTL_OVER, 0x1);
+                       b43_phy_set(dev, B43_NPHY_RFCTL_CMD,
+                                       B43_NPHY_RFCTL_CMD_START);
+                       udelay(1);
+                       b43_phy_mask(dev, B43_NPHY_RFCTL_OVER, 0xFFFE);
+               }
+       }
+}
+
 static void b43_nphy_bphy_init(struct b43_wldev *dev)
 {
        unsigned int i;
@@ -991,66 +1316,69 @@ static void b43_nphy_scale_offset_rssi(struct b43_wldev *dev, u16 scale,
                b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_TSSI, tmp);
 }
 
-/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSISel */
-static void b43_nphy_rssi_select(struct b43_wldev *dev, u8 code, u8 type)
+static void b43_nphy_rev2_rssi_select(struct b43_wldev *dev, u8 code, u8 type)
 {
        u16 val;
 
-       if (dev->phy.rev >= 3) {
-               /* TODO */
-       } else {
-               if (type < 3)
-                       val = 0;
-               else if (type == 6)
-                       val = 1;
-               else if (type == 3)
-                       val = 2;
-               else
-                       val = 3;
+       if (type < 3)
+               val = 0;
+       else if (type == 6)
+               val = 1;
+       else if (type == 3)
+               val = 2;
+       else
+               val = 3;
 
-               val = (val << 12) | (val << 14);
-               b43_phy_maskset(dev, B43_NPHY_AFECTL_C1, 0x0FFF, val);
-               b43_phy_maskset(dev, B43_NPHY_AFECTL_C2, 0x0FFF, val);
+       val = (val << 12) | (val << 14);
+       b43_phy_maskset(dev, B43_NPHY_AFECTL_C1, 0x0FFF, val);
+       b43_phy_maskset(dev, B43_NPHY_AFECTL_C2, 0x0FFF, val);
 
+       if (type < 3) {
+               b43_phy_maskset(dev, B43_NPHY_RFCTL_RSSIO1, 0xFFCF,
+                               (type + 1) << 4);
+               b43_phy_maskset(dev, B43_NPHY_RFCTL_RSSIO2, 0xFFCF,
+                               (type + 1) << 4);
+       }
+
+       /* TODO use some definitions */
+       if (code == 0) {
+               b43_phy_maskset(dev, B43_NPHY_AFECTL_OVER, 0xCFFF, 0);
                if (type < 3) {
-                       b43_phy_maskset(dev, B43_NPHY_RFCTL_RSSIO1, 0xFFCF,
-                                       (type + 1) << 4);
-                       b43_phy_maskset(dev, B43_NPHY_RFCTL_RSSIO2, 0xFFCF,
-                                       (type + 1) << 4);
+                       b43_phy_maskset(dev, B43_NPHY_RFCTL_CMD, 0xFEC7, 0);
+                       b43_phy_maskset(dev, B43_NPHY_RFCTL_OVER, 0xEFDC, 0);
+                       b43_phy_maskset(dev, B43_NPHY_RFCTL_CMD, 0xFFFE, 0);
+                       udelay(20);
+                       b43_phy_maskset(dev, B43_NPHY_RFCTL_OVER, 0xFFFE, 0);
                }
-
-               /* TODO use some definitions */
-               if (code == 0) {
-                       b43_phy_maskset(dev, B43_NPHY_AFECTL_OVER, 0xCFFF, 0);
-                       if (type < 3) {
-                               b43_phy_maskset(dev, B43_NPHY_RFCTL_CMD,
-                                               0xFEC7, 0);
-                               b43_phy_maskset(dev, B43_NPHY_RFCTL_OVER,
-                                               0xEFDC, 0);
-                               b43_phy_maskset(dev, B43_NPHY_RFCTL_CMD,
-                                               0xFFFE, 0);
-                               udelay(20);
-                               b43_phy_maskset(dev, B43_NPHY_RFCTL_OVER,
-                                               0xFFFE, 0);
-                       }
-               } else {
-                       b43_phy_maskset(dev, B43_NPHY_AFECTL_OVER, 0xCFFF,
-                                       0x3000);
-                       if (type < 3) {
-                               b43_phy_maskset(dev, B43_NPHY_RFCTL_CMD,
-                                               0xFEC7, 0x0180);
-                               b43_phy_maskset(dev, B43_NPHY_RFCTL_OVER,
-                                               0xEFDC, (code << 1 | 0x1021));
-                               b43_phy_maskset(dev, B43_NPHY_RFCTL_CMD,
-                                               0xFFFE, 0x0001);
-                               udelay(20);
-                               b43_phy_maskset(dev, B43_NPHY_RFCTL_OVER,
-                                               0xFFFE, 0);
-                       }
+       } else {
+               b43_phy_maskset(dev, B43_NPHY_AFECTL_OVER, 0xCFFF,
+                               0x3000);
+               if (type < 3) {
+                       b43_phy_maskset(dev, B43_NPHY_RFCTL_CMD,
+                                       0xFEC7, 0x0180);
+                       b43_phy_maskset(dev, B43_NPHY_RFCTL_OVER,
+                                       0xEFDC, (code << 1 | 0x1021));
+                       b43_phy_maskset(dev, B43_NPHY_RFCTL_CMD, 0xFFFE, 0x1);
+                       udelay(20);
+                       b43_phy_maskset(dev, B43_NPHY_RFCTL_OVER, 0xFFFE, 0);
                }
        }
 }
 
+static void b43_nphy_rev3_rssi_select(struct b43_wldev *dev, u8 code, u8 type)
+{
+       /* TODO */
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSISel */
+static void b43_nphy_rssi_select(struct b43_wldev *dev, u8 code, u8 type)
+{
+       if (dev->phy.rev >= 3)
+               b43_nphy_rev3_rssi_select(dev, code, type);
+       else
+               b43_nphy_rev2_rssi_select(dev, code, type);
+}
+
 /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/SetRssi2055Vcm */
 static void b43_nphy_set_rssi_2055_vcm(struct b43_wldev *dev, u8 type, u8 *buf)
 {
@@ -1492,6 +1820,43 @@ static void b43_nphy_update_tx_cal_ladder(struct b43_wldev *dev, u16 core)
        }
 }
 
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/ExtPaSetTxDigiFilts */
+static void b43_nphy_ext_pa_set_tx_dig_filters(struct b43_wldev *dev)
+{
+       int i;
+       for (i = 0; i < 15; i++)
+               b43_phy_write(dev, B43_PHY_N(0x2C5 + i),
+                               tbl_tx_filter_coef_rev4[2][i]);
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/IpaSetTxDigiFilts */
+static void b43_nphy_int_pa_set_tx_dig_filters(struct b43_wldev *dev)
+{
+       int i, j;
+       /* B43_NPHY_TXF_20CO_S0A1, B43_NPHY_TXF_40CO_S0A1, unknown */
+       u16 offset[] = { 0x186, 0x195, 0x2C5 };
+
+       for (i = 0; i < 3; i++)
+               for (j = 0; j < 15; j++)
+                       b43_phy_write(dev, B43_PHY_N(offset[i] + j),
+                                       tbl_tx_filter_coef_rev4[i][j]);
+
+       if (dev->phy.is_40mhz) {
+               for (j = 0; j < 15; j++)
+                       b43_phy_write(dev, B43_PHY_N(offset[0] + j),
+                                       tbl_tx_filter_coef_rev4[3][j]);
+       } else if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) {
+               for (j = 0; j < 15; j++)
+                       b43_phy_write(dev, B43_PHY_N(offset[0] + j),
+                                       tbl_tx_filter_coef_rev4[5][j]);
+       }
+
+       if (dev->phy.channel == 14)
+               for (j = 0; j < 15; j++)
+                       b43_phy_write(dev, B43_PHY_N(offset[0] + j),
+                                       tbl_tx_filter_coef_rev4[6][j]);
+}
+
 /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/GetTxGain */
 static struct nphy_txgains b43_nphy_get_tx_gains(struct b43_wldev *dev)
 {
@@ -1624,7 +1989,7 @@ static void b43_nphy_tx_cal_phy_setup(struct b43_wldev *dev)
                b43_phy_write(dev, B43_NPHY_AFECTL_OVER, tmp | 0x0600);
 
                regs[4] = b43_phy_read(dev, B43_NPHY_BBCFG);
-               b43_phy_mask(dev, B43_NPHY_BBCFG, ~B43_NPHY_BBCFG_RSTRX);
+               b43_phy_mask(dev, B43_NPHY_BBCFG, (u16)~B43_NPHY_BBCFG_RSTRX);
 
                tmp = b43_ntab_read(dev, B43_NTAB16(8, 3));
                regs[5] = tmp;
@@ -1787,17 +2152,16 @@ static int b43_nphy_cal_tx_iq_lo(struct b43_wldev *dev,
 
        b43_phy_write(dev, B43_NPHY_IQLOCAL_CMDGCTL, 0x8AA9);
 
-       if (1 /* FIXME: the band width is 20 MHz */)
+       if (!dev->phy.is_40mhz)
                freq = 2500;
        else
                freq = 5000;
 
        if (nphy->mphase_cal_phase_id > 2)
-               ;/* TODO: Call N PHY Run Samples with (band width * 8),
-                       0xFFFF, 0, 1, 0 as arguments */
+               b43_nphy_run_samples(dev, (dev->phy.is_40mhz ? 40 : 20) * 8,
+                                       0xFFFF, 0, true, false);
        else
-               ;/* TODO: Call N PHY TX Tone with freq, 250, 1, 0 as arguments
-                       and save result as error */
+               error = b43_nphy_tx_tone(dev, freq, 250, true, false);
 
        if (error == 0) {
                if (nphy->mphase_cal_phase_id > 2) {
@@ -1970,7 +2334,7 @@ static int b43_nphy_rev2_cal_rx_iq(struct b43_wldev *dev,
        u16 lna[3] = { 3, 3, 1 };
        u16 hpf1[3] = { 7, 2, 0 };
        u16 hpf2[3] = { 2, 0, 0 };
-       u32 power[3];
+       u32 power[3] = { };
        u16 gain_save[2];
        u16 cal_gain[2];
        struct nphy_iqcal_params cal_params[2];
@@ -2075,19 +2439,19 @@ static int b43_nphy_rev2_cal_rx_iq(struct b43_wldev *dev,
 
                        tmp[0] = ((cur_hpf2 << 8) | (cur_hpf1 << 4) |
                                        (cur_lna << 2));
-                       /* TODO:Call N PHY RF Ctrl Override with 0x400, tmp[0],
-                               3, 0 as arguments */
-                       /* TODO: Call N PHY Force RF Seq with 2 as argument */
+                       b43_nphy_rf_control_override(dev, 0x400, tmp[0], 3,
+                                                                       false);
+                       b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX);
                        b43_nphy_stop_playback(dev);
 
                        if (playtone) {
-                               /* TODO: Call N PHY TX Tone with 4000,
-                                       (nphy_rxcalparams & 0xffff), 0, 0
-                                       as arguments and save result as ret */
+                               ret = b43_nphy_tx_tone(dev, 4000,
+                                               (nphy->rxcalparams & 0xFFFF),
+                                               false, false);
                                playtone = false;
                        } else {
-                               /* TODO: Call N PHY Run Samples with 160,
-                                       0xFFFF, 0, 0, 0 as arguments */
+                               b43_nphy_run_samples(dev, 160, 0xFFFF, 0,
+                                                       false, false);
                        }
 
                        if (ret == 0) {
@@ -2124,7 +2488,7 @@ static int b43_nphy_rev2_cal_rx_iq(struct b43_wldev *dev,
                        break;
        }
 
-       /* TODO: Call N PHY RF Ctrl Override with 0x400, 0, 3, 1 as arguments*/
+       b43_nphy_rf_control_override(dev, 0x400, 0, 3, true);
        b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX);
        b43_ntab_write_bulk(dev, B43_NTAB16(7, 0x110), 2, gain_save);
 
@@ -2235,9 +2599,9 @@ int b43_phy_initn(struct b43_wldev *dev)
                b43_phy_set(dev, B43_NPHY_PAPD_EN1, 0x1);
                b43_phy_maskset(dev, B43_NPHY_EPS_TABLE_ADJ1, 0x007F,
                                nphy->papd_epsilon_offset[1] << 7);
-               /* TODO N PHY IPA Set TX Dig Filters */
+               b43_nphy_int_pa_set_tx_dig_filters(dev);
        } else if (phy->rev >= 5) {
-               /* TODO N PHY Ext PA Set TX Dig Filters */
+               b43_nphy_ext_pa_set_tx_dig_filters(dev);
        }
 
        b43_nphy_workarounds(dev);