diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 8a3bc2c58a81..4111a4626001 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -1434,6 +1434,232 @@ static void b43_nphy_restore_cal(struct b43_wldev *dev) b43_nphy_rx_iq_coeffs(dev, true, rxcal_coeffs); } +/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/CalTxIqlo */ +static int b43_nphy_cal_tx_iq_lo(struct b43_wldev *dev, + struct nphy_txgains target, + bool full, bool mphase) +{ + struct b43_phy_n *nphy = dev->phy.n; + int i; + int error = 0; + int freq; + bool avoid = false; + u8 length; + u16 tmp, core, type, count, max, numb, last, cmd; + const u16 *table; + bool phy6or5x; + + u16 buffer[11]; + u16 diq_start = 0; + u16 save[2]; + u16 gain[2]; + struct nphy_iqcal_params params[2]; + bool updated[2] = { }; + + b43_nphy_stay_in_carrier_search(dev, true); + + if (dev->phy.rev >= 4) { + avoid = nphy->hang_avoid; + nphy->hang_avoid = 0; + } + + /* TODO: Read an N PHY Table with ID 7, length 2, offset 0x110, + width 16, and data pointer save */ + + for (i = 0; i < 2; i++) { + b43_nphy_iq_cal_gain_params(dev, i, target, ¶ms[i]); + gain[i] = params[i].cal_gain; + } + /* TODO: Write an N PHY Table with ID 7, length 2, offset 0x110, + width 16, and data pointer gain */ + + b43_nphy_tx_cal_radio_setup(dev); + /* TODO: Call N PHY TX Cal PHY Setup */ + + phy6or5x = dev->phy.rev >= 6 || + (dev->phy.rev == 5 && nphy->ipa2g_on && + b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ); + if (phy6or5x) { + /* TODO */ + } + + b43_phy_write(dev, B43_NPHY_IQLOCAL_CMDGCTL, 0x8AA9); + + if (1 /* FIXME: the band width is 20 MHz */) + 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 */ + else + ;/* TODO: Call N PHY TX Tone with freq, 250, 1, 0 as arguments + and save result as error */ + + if (error == 0) { + if (nphy->mphase_cal_phase_id > 2) { + table = nphy->mphase_txcal_bestcoeffs; + length = 11; + if (dev->phy.rev < 3) + length -= 2; + } else { + if (!full && nphy->txiqlocal_coeffsvalid) { + table = nphy->txiqlocal_bestc; + length = 11; + if (dev->phy.rev < 3) + length -= 2; + } else { + full = true; + if (dev->phy.rev >= 3) { + table = tbl_tx_iqlo_cal_startcoefs_nphyrev3; + length = B43_NTAB_TX_IQLO_CAL_STARTCOEFS_REV3; + } else { + table = tbl_tx_iqlo_cal_startcoefs; + length = B43_NTAB_TX_IQLO_CAL_STARTCOEFS; + } + } + } + + /* TODO: Write an N PHY Table with ID 15, length from above, + offset 64, width 16, and the data pointer from above */ + + if (full) { + if (dev->phy.rev >= 3) + max = B43_NTAB_TX_IQLO_CAL_CMDS_FULLCAL_REV3; + else + max = B43_NTAB_TX_IQLO_CAL_CMDS_FULLCAL; + } else { + if (dev->phy.rev >= 3) + max = B43_NTAB_TX_IQLO_CAL_CMDS_RECAL_REV3; + else + max = B43_NTAB_TX_IQLO_CAL_CMDS_RECAL; + } + + if (mphase) { + count = nphy->mphase_txcal_cmdidx; + numb = min(max, + (u16)(count + nphy->mphase_txcal_numcmds)); + } else { + count = 0; + numb = max; + } + + for (; count < numb; count++) { + if (full) { + if (dev->phy.rev >= 3) + cmd = tbl_tx_iqlo_cal_cmds_fullcal_nphyrev3[count]; + else + cmd = tbl_tx_iqlo_cal_cmds_fullcal[count]; + } else { + if (dev->phy.rev >= 3) + cmd = tbl_tx_iqlo_cal_cmds_recal_nphyrev3[count]; + else + cmd = tbl_tx_iqlo_cal_cmds_recal[count]; + } + + core = (cmd & 0x3000) >> 12; + type = (cmd & 0x0F00) >> 8; + + if (phy6or5x && updated[core] == 0) { + b43_nphy_update_tx_cal_ladder(dev, core); + updated[core] = 1; + } + + tmp = (params[core].ncorr[type] << 8) | 0x66; + b43_phy_write(dev, B43_NPHY_IQLOCAL_CMDNNUM, tmp); + + if (type == 1 || type == 3 || type == 4) { + /* TODO: Read an N PHY Table with ID 15, + length 1, offset 69 + core, + width 16, and data pointer buffer */ + diq_start = buffer[0]; + buffer[0] = 0; + /* TODO: Write an N PHY Table with ID 15, + length 1, offset 69 + core, width 16, + and data of 0 */ + } + + b43_phy_write(dev, B43_NPHY_IQLOCAL_CMD, cmd); + for (i = 0; i < 2000; i++) { + tmp = b43_phy_read(dev, B43_NPHY_IQLOCAL_CMD); + if (tmp & 0xC000) + break; + udelay(10); + } + + /* TODO: Read an N PHY Table with ID 15, + length table_length, offset 96, width 16, + and data pointer buffer */ + /* TODO: Write an N PHY Table with ID 15, + length table_length, offset 64, width 16, + and data pointer buffer */ + + if (type == 1 || type == 3 || type == 4) + buffer[0] = diq_start; + } + + if (mphase) + nphy->mphase_txcal_cmdidx = (numb >= max) ? 0 : numb; + + last = (dev->phy.rev < 3) ? 6 : 7; + + if (!mphase || nphy->mphase_cal_phase_id == last) { + /* TODO: Write an N PHY Table with ID 15, length 4, + offset 96, width 16, and data pointer buffer */ + /* TODO: Read an N PHY Table with ID 15, length 4, + offset 80, width 16, and data pointer buffer */ + if (dev->phy.rev < 3) { + buffer[0] = 0; + buffer[1] = 0; + buffer[2] = 0; + buffer[3] = 0; + } + /* TODO: Write an N PHY Table with ID 15, length 4, + offset 88, width 16, and data pointer buffer */ + /* TODO: Read an N PHY Table with ID 15, length 2, + offset 101, width 16, and data pointer buffer*/ + /* TODO: Write an N PHY Table with ID 15, length 2, + offset 85, width 16, and data pointer buffer */ + /* TODO: Write an N PHY Table with ID 15, length 2, + offset 93, width 16, and data pointer buffer */ + length = 11; + if (dev->phy.rev < 3) + length -= 2; + /* TODO: Read an N PHY Table with ID 15, length length, + offset 96, width 16, and data pointer + nphy->txiqlocal_bestc */ + nphy->txiqlocal_coeffsvalid = true; + /* TODO: Set nphy->txiqlocal_chanspec to + the current channel */ + } else { + length = 11; + if (dev->phy.rev < 3) + length -= 2; + /* TODO: Read an N PHY Table with ID 5, length length, + offset 96, width 16, and data pointer + nphy->mphase_txcal_bestcoeffs */ + } + + /* TODO: Call N PHY Stop Playback */ + b43_phy_write(dev, B43_NPHY_IQLOCAL_CMDGCTL, 0); + } + + /* TODO: Call N PHY TX Cal PHY Cleanup */ + /* TODO: Write an N PHY Table with ID 7, length 2, offset 0x110, + width 16, and data from save */ + + if (dev->phy.rev < 2 && (!mphase || nphy->mphase_cal_phase_id == last)) + b43_nphy_tx_iq_workaround(dev); + + if (dev->phy.rev >= 4) + nphy->hang_avoid = avoid; + + b43_nphy_stay_in_carrier_search(dev, false); + + return error; +} + /* * Init N-PHY * http://bcm-v4.sipsolutions.net/802.11/PHY/Init/N