提交 ef1a628d 编写于 作者: M Michael Buesch 提交者: John W. Linville

b43: Implement dynamic PHY API

This patch implements a dynamic "ops" based PHY API.
This is needed in order to conveniently support future PHY types
to avoid the "switch"-hell.

This patch does not change any functionality. It just moves lots
of code from one place to another and adjusts it for the changed
data structures.
Signed-off-by: NMichael Buesch <mb@bu3sch.de>
Signed-off-by: NJohn W. Linville <linville@tuxdriver.com>
上级 35e032d8
b43-y += main.o
b43-y += tables.o
b43-$(CONFIG_B43_NPHY) += tables_nphy.o
b43-y += phy.o
b43-y += phy_common.o
b43-y += phy_g.o
b43-y += phy_a.o
b43-$(CONFIG_B43_NPHY) += nphy.o
b43-y += sysfs.o
b43-y += xmit.o
......
......@@ -12,7 +12,7 @@
#include "leds.h"
#include "rfkill.h"
#include "lo.h"
#include "phy.h"
#include "phy_common.h"
/* The unique identifier of the firmware that's officially supported by
......@@ -508,122 +508,6 @@ struct b43_iv {
} __attribute__((__packed__));
struct b43_phy {
/* Band support flags. */
bool supports_2ghz;
bool supports_5ghz;
/* GMODE bit enabled? */
bool gmode;
/* Analog Type */
u8 analog;
/* B43_PHYTYPE_ */
u8 type;
/* PHY revision number. */
u8 rev;
/* Radio versioning */
u16 radio_manuf; /* Radio manufacturer */
u16 radio_ver; /* Radio version */
u8 radio_rev; /* Radio revision */
bool dyn_tssi_tbl; /* tssi2dbm is kmalloc()ed. */
/* ACI (adjacent channel interference) flags. */
bool aci_enable;
bool aci_wlan_automatic;
bool aci_hw_rssi;
/* Radio switched on/off */
bool radio_on;
struct {
/* Values saved when turning the radio off.
* They are needed when turning it on again. */
bool valid;
u16 rfover;
u16 rfoverval;
} radio_off_context;
u16 minlowsig[2];
u16 minlowsigpos[2];
/* TSSI to dBm table in use */
const s8 *tssi2dbm;
/* Target idle TSSI */
int tgt_idle_tssi;
/* Current idle TSSI */
int cur_idle_tssi;
/* LocalOscillator control values. */
struct b43_txpower_lo_control *lo_control;
/* Values from b43_calc_loopback_gain() */
s16 max_lb_gain; /* Maximum Loopback gain in hdB */
s16 trsw_rx_gain; /* TRSW RX gain in hdB */
s16 lna_lod_gain; /* LNA lod */
s16 lna_gain; /* LNA */
s16 pga_gain; /* PGA */
/* Desired TX power level (in dBm).
* This is set by the user and adjusted in b43_phy_xmitpower(). */
u8 power_level;
/* A-PHY TX Power control value. */
u16 txpwr_offset;
/* Current TX power level attenuation control values */
struct b43_bbatt bbatt;
struct b43_rfatt rfatt;
u8 tx_control; /* B43_TXCTL_XXX */
/* Hardware Power Control enabled? */
bool hardware_power_control;
/* Current Interference Mitigation mode */
int interfmode;
/* Stack of saved values from the Interference Mitigation code.
* Each value in the stack is layed out as follows:
* bit 0-11: offset
* bit 12-15: register ID
* bit 16-32: value
* register ID is: 0x1 PHY, 0x2 Radio, 0x3 ILT
*/
#define B43_INTERFSTACK_SIZE 26
u32 interfstack[B43_INTERFSTACK_SIZE]; //FIXME: use a data structure
/* Saved values from the NRSSI Slope calculation */
s16 nrssi[2];
s32 nrssislope;
/* In memory nrssi lookup table. */
s8 nrssi_lt[64];
/* current channel */
u8 channel;
u16 lofcal;
u16 initval; //FIXME rename?
/* PHY TX errors counter. */
atomic_t txerr_cnt;
/* The device does address auto increment for the OFDM tables.
* We cache the previously used address here and omit the address
* write on the next table access, if possible. */
u16 ofdmtab_addr; /* The address currently set in hardware. */
enum { /* The last data flow direction. */
B43_OFDMTAB_DIRECTION_UNKNOWN = 0,
B43_OFDMTAB_DIRECTION_READ,
B43_OFDMTAB_DIRECTION_WRITE,
} ofdmtab_addr_direction;
#if B43_DEBUG
/* Manual TX-power control enabled? */
bool manual_txpower_control;
/* PHY registers locked by b43_phy_lock()? */
bool phy_locked;
#endif /* B43_DEBUG */
};
/* Data structures for DMA transmission, per 80211 core. */
struct b43_dma {
struct b43_dmaring *tx_ring_AC_BK; /* Background */
......@@ -908,6 +792,15 @@ static inline int b43_is_mode(struct b43_wl *wl, int type)
return (wl->operating && wl->if_type == type);
}
/**
* b43_current_band - Returns the currently used band.
* Returns one of IEEE80211_BAND_2GHZ and IEEE80211_BAND_5GHZ.
*/
static inline enum ieee80211_band b43_current_band(struct b43_wl *wl)
{
return wl->hw->conf.channel->band;
}
static inline u16 b43_read16(struct b43_wldev *dev, u16 offset)
{
return ssb_read16(dev->dev, offset);
......
......@@ -443,76 +443,6 @@ static ssize_t txstat_read_file(struct b43_wldev *dev,
return count;
}
static ssize_t txpower_g_read_file(struct b43_wldev *dev,
char *buf, size_t bufsize)
{
ssize_t count = 0;
if (dev->phy.type != B43_PHYTYPE_G) {
fappend("Device is not a G-PHY\n");
goto out;
}
fappend("Control: %s\n", dev->phy.manual_txpower_control ?
"MANUAL" : "AUTOMATIC");
fappend("Baseband attenuation: %u\n", dev->phy.bbatt.att);
fappend("Radio attenuation: %u\n", dev->phy.rfatt.att);
fappend("TX Mixer Gain: %s\n",
(dev->phy.tx_control & B43_TXCTL_TXMIX) ? "ON" : "OFF");
fappend("PA Gain 2dB: %s\n",
(dev->phy.tx_control & B43_TXCTL_PA2DB) ? "ON" : "OFF");
fappend("PA Gain 3dB: %s\n",
(dev->phy.tx_control & B43_TXCTL_PA3DB) ? "ON" : "OFF");
fappend("\n\n");
fappend("You can write to this file:\n");
fappend("Writing \"auto\" enables automatic txpower control.\n");
fappend
("Writing the attenuation values as \"bbatt rfatt txmix pa2db pa3db\" "
"enables manual txpower control.\n");
fappend("Example: 5 4 0 0 1\n");
fappend("Enables manual control with Baseband attenuation 5, "
"Radio attenuation 4, No TX Mixer Gain, "
"No PA Gain 2dB, With PA Gain 3dB.\n");
out:
return count;
}
static int txpower_g_write_file(struct b43_wldev *dev,
const char *buf, size_t count)
{
if (dev->phy.type != B43_PHYTYPE_G)
return -ENODEV;
if ((count >= 4) && (memcmp(buf, "auto", 4) == 0)) {
/* Automatic control */
dev->phy.manual_txpower_control = 0;
b43_phy_xmitpower(dev);
} else {
int bbatt = 0, rfatt = 0, txmix = 0, pa2db = 0, pa3db = 0;
/* Manual control */
if (sscanf(buf, "%d %d %d %d %d", &bbatt, &rfatt,
&txmix, &pa2db, &pa3db) != 5)
return -EINVAL;
b43_put_attenuation_into_ranges(dev, &bbatt, &rfatt);
dev->phy.manual_txpower_control = 1;
dev->phy.bbatt.att = bbatt;
dev->phy.rfatt.att = rfatt;
dev->phy.tx_control = 0;
if (txmix)
dev->phy.tx_control |= B43_TXCTL_TXMIX;
if (pa2db)
dev->phy.tx_control |= B43_TXCTL_PA2DB;
if (pa3db)
dev->phy.tx_control |= B43_TXCTL_PA3DB;
b43_phy_lock(dev);
b43_radio_lock(dev);
b43_set_txpower_g(dev, &dev->phy.bbatt,
&dev->phy.rfatt, dev->phy.tx_control);
b43_radio_unlock(dev);
b43_phy_unlock(dev);
}
return 0;
}
/* wl->irq_lock is locked */
static int restart_write_file(struct b43_wldev *dev,
const char *buf, size_t count)
......@@ -560,7 +490,7 @@ static ssize_t loctls_read_file(struct b43_wldev *dev,
err = -ENODEV;
goto out;
}
lo = phy->lo_control;
lo = phy->g->lo_control;
fappend("-- Local Oscillator calibration data --\n\n");
fappend("HW-power-control enabled: %d\n",
dev->phy.hardware_power_control);
......@@ -578,8 +508,8 @@ static ssize_t loctls_read_file(struct b43_wldev *dev,
list_for_each_entry(cal, &lo->calib_list, list) {
bool active;
active = (b43_compare_bbatt(&cal->bbatt, &phy->bbatt) &&
b43_compare_rfatt(&cal->rfatt, &phy->rfatt));
active = (b43_compare_bbatt(&cal->bbatt, &phy->g->bbatt) &&
b43_compare_rfatt(&cal->rfatt, &phy->g->rfatt));
fappend("BB(%d), RF(%d,%d) -> I=%d, Q=%d "
"(expires in %lu sec)%s\n",
cal->bbatt.att,
......@@ -763,7 +693,6 @@ B43_DEBUGFS_FOPS(mmio32read, mmio32read__read_file, mmio32read__write_file, 1);
B43_DEBUGFS_FOPS(mmio32write, NULL, mmio32write__write_file, 1);
B43_DEBUGFS_FOPS(tsf, tsf_read_file, tsf_write_file, 1);
B43_DEBUGFS_FOPS(txstat, txstat_read_file, NULL, 0);
B43_DEBUGFS_FOPS(txpower_g, txpower_g_read_file, txpower_g_write_file, 0);
B43_DEBUGFS_FOPS(restart, NULL, restart_write_file, 1);
B43_DEBUGFS_FOPS(loctls, loctls_read_file, NULL, 0);
......@@ -877,7 +806,6 @@ void b43_debugfs_add_device(struct b43_wldev *dev)
ADD_FILE(mmio32write, 0200);
ADD_FILE(tsf, 0600);
ADD_FILE(txstat, 0400);
ADD_FILE(txpower_g, 0600);
ADD_FILE(restart, 0200);
ADD_FILE(loctls, 0400);
......@@ -907,7 +835,6 @@ void b43_debugfs_remove_device(struct b43_wldev *dev)
debugfs_remove(e->file_mmio32write.dentry);
debugfs_remove(e->file_tsf.dentry);
debugfs_remove(e->file_txstat.dentry);
debugfs_remove(e->file_txpower_g.dentry);
debugfs_remove(e->file_restart.dentry);
debugfs_remove(e->file_loctls.dentry);
......
......@@ -29,7 +29,7 @@
#include "b43.h"
#include "lo.h"
#include "phy.h"
#include "phy_g.h"
#include "main.h"
#include <linux/delay.h>
......@@ -174,7 +174,8 @@ static u16 lo_txctl_register_table(struct b43_wldev *dev,
static void lo_measure_txctl_values(struct b43_wldev *dev)
{
struct b43_phy *phy = &dev->phy;
struct b43_txpower_lo_control *lo = phy->lo_control;
struct b43_phy_g *gphy = phy->g;
struct b43_txpower_lo_control *lo = gphy->lo_control;
u16 reg, mask;
u16 trsw_rx, pga;
u16 radio_pctl_reg;
......@@ -195,7 +196,7 @@ static void lo_measure_txctl_values(struct b43_wldev *dev)
int lb_gain; /* Loopback gain (in dB) */
trsw_rx = 0;
lb_gain = phy->max_lb_gain / 2;
lb_gain = gphy->max_lb_gain / 2;
if (lb_gain > 10) {
radio_pctl_reg = 0;
pga = abs(10 - lb_gain) / 6;
......@@ -226,7 +227,7 @@ static void lo_measure_txctl_values(struct b43_wldev *dev)
}
b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43)
& 0xFFF0) | radio_pctl_reg);
b43_phy_set_baseband_attenuation(dev, 2);
b43_gphy_set_baseband_attenuation(dev, 2);
reg = lo_txctl_register_table(dev, &mask, NULL);
mask = ~mask;
......@@ -277,7 +278,8 @@ static void lo_measure_txctl_values(struct b43_wldev *dev)
static void lo_read_power_vector(struct b43_wldev *dev)
{
struct b43_phy *phy = &dev->phy;
struct b43_txpower_lo_control *lo = phy->lo_control;
struct b43_phy_g *gphy = phy->g;
struct b43_txpower_lo_control *lo = gphy->lo_control;
int i;
u64 tmp;
u64 power_vector = 0;
......@@ -298,6 +300,7 @@ static void lo_measure_gain_values(struct b43_wldev *dev,
s16 max_rx_gain, int use_trsw_rx)
{
struct b43_phy *phy = &dev->phy;
struct b43_phy_g *gphy = phy->g;
u16 tmp;
if (max_rx_gain < 0)
......@@ -308,7 +311,7 @@ static void lo_measure_gain_values(struct b43_wldev *dev,
int trsw_rx_gain;
if (use_trsw_rx) {
trsw_rx_gain = phy->trsw_rx_gain / 2;
trsw_rx_gain = gphy->trsw_rx_gain / 2;
if (max_rx_gain >= trsw_rx_gain) {
trsw_rx_gain = max_rx_gain - trsw_rx_gain;
trsw_rx = 0x20;
......@@ -316,38 +319,38 @@ static void lo_measure_gain_values(struct b43_wldev *dev,
} else
trsw_rx_gain = max_rx_gain;
if (trsw_rx_gain < 9) {
phy->lna_lod_gain = 0;
gphy->lna_lod_gain = 0;
} else {
phy->lna_lod_gain = 1;
gphy->lna_lod_gain = 1;
trsw_rx_gain -= 8;
}
trsw_rx_gain = clamp_val(trsw_rx_gain, 0, 0x2D);
phy->pga_gain = trsw_rx_gain / 3;
if (phy->pga_gain >= 5) {
phy->pga_gain -= 5;
phy->lna_gain = 2;
gphy->pga_gain = trsw_rx_gain / 3;
if (gphy->pga_gain >= 5) {
gphy->pga_gain -= 5;
gphy->lna_gain = 2;
} else
phy->lna_gain = 0;
gphy->lna_gain = 0;
} else {
phy->lna_gain = 0;
phy->trsw_rx_gain = 0x20;
gphy->lna_gain = 0;
gphy->trsw_rx_gain = 0x20;
if (max_rx_gain >= 0x14) {
phy->lna_lod_gain = 1;
phy->pga_gain = 2;
gphy->lna_lod_gain = 1;
gphy->pga_gain = 2;
} else if (max_rx_gain >= 0x12) {
phy->lna_lod_gain = 1;
phy->pga_gain = 1;
gphy->lna_lod_gain = 1;
gphy->pga_gain = 1;
} else if (max_rx_gain >= 0xF) {
phy->lna_lod_gain = 1;
phy->pga_gain = 0;
gphy->lna_lod_gain = 1;
gphy->pga_gain = 0;
} else {
phy->lna_lod_gain = 0;
phy->pga_gain = 0;
gphy->lna_lod_gain = 0;
gphy->pga_gain = 0;
}
}
tmp = b43_radio_read16(dev, 0x7A);
if (phy->lna_lod_gain == 0)
if (gphy->lna_lod_gain == 0)
tmp &= ~0x0008;
else
tmp |= 0x0008;
......@@ -392,10 +395,11 @@ static void lo_measure_setup(struct b43_wldev *dev,
{
struct ssb_sprom *sprom = &dev->dev->bus->sprom;
struct b43_phy *phy = &dev->phy;
struct b43_txpower_lo_control *lo = phy->lo_control;
struct b43_phy_g *gphy = phy->g;
struct b43_txpower_lo_control *lo = gphy->lo_control;
u16 tmp;
if (b43_has_hardware_pctl(phy)) {
if (b43_has_hardware_pctl(dev)) {
sav->phy_lo_mask = b43_phy_read(dev, B43_PHY_LO_MASK);
sav->phy_extg_01 = b43_phy_read(dev, B43_PHY_EXTG(0x01));
sav->phy_dacctl_hwpctl = b43_phy_read(dev, B43_PHY_DACCTL);
......@@ -496,7 +500,7 @@ static void lo_measure_setup(struct b43_wldev *dev,
b43_phy_write(dev, B43_PHY_CCK(0x2B), 0x0802);
if (phy->rev >= 2)
b43_dummy_transmission(dev);
b43_radio_selectchannel(dev, 6, 0);
b43_gphy_channel_switch(dev, 6, 0);
b43_radio_read16(dev, 0x51); /* dummy read */
if (phy->type == B43_PHYTYPE_G)
b43_phy_write(dev, B43_PHY_CCK(0x2F), 0);
......@@ -520,18 +524,19 @@ static void lo_measure_restore(struct b43_wldev *dev,
struct lo_g_saved_values *sav)
{
struct b43_phy *phy = &dev->phy;
struct b43_phy_g *gphy = phy->g;
u16 tmp;
if (phy->rev >= 2) {
b43_phy_write(dev, B43_PHY_PGACTL, 0xE300);
tmp = (phy->pga_gain << 8);
tmp = (gphy->pga_gain << 8);
b43_phy_write(dev, B43_PHY_RFOVERVAL, tmp | 0xA0);
udelay(5);
b43_phy_write(dev, B43_PHY_RFOVERVAL, tmp | 0xA2);
udelay(2);
b43_phy_write(dev, B43_PHY_RFOVERVAL, tmp | 0xA3);
} else {
tmp = (phy->pga_gain | 0xEFA0);
tmp = (gphy->pga_gain | 0xEFA0);
b43_phy_write(dev, B43_PHY_PGACTL, tmp);
}
if (phy->type == B43_PHYTYPE_G) {
......@@ -572,7 +577,7 @@ static void lo_measure_restore(struct b43_wldev *dev,
b43_phy_write(dev, B43_PHY_CCK(0x3E), sav->phy_cck_3E);
b43_phy_write(dev, B43_PHY_CRS0, sav->phy_crs0);
}
if (b43_has_hardware_pctl(phy)) {
if (b43_has_hardware_pctl(dev)) {
tmp = (sav->phy_lo_mask & 0xBFFF);
b43_phy_write(dev, B43_PHY_LO_MASK, tmp);
b43_phy_write(dev, B43_PHY_EXTG(0x01), sav->phy_extg_01);
......@@ -580,7 +585,7 @@ static void lo_measure_restore(struct b43_wldev *dev,
b43_phy_write(dev, B43_PHY_CCK(0x14), sav->phy_cck_14);
b43_phy_write(dev, B43_PHY_HPWR_TSSICTL, sav->phy_hpwr_tssictl);
}
b43_radio_selectchannel(dev, sav->old_channel, 1);
b43_gphy_channel_switch(dev, sav->old_channel, 1);
}
struct b43_lo_g_statemachine {
......@@ -597,6 +602,7 @@ static int lo_probe_possible_loctls(struct b43_wldev *dev,
struct b43_lo_g_statemachine *d)
{
struct b43_phy *phy = &dev->phy;
struct b43_phy_g *gphy = phy->g;
struct b43_loctl test_loctl;
struct b43_loctl orig_loctl;
struct b43_loctl prev_loctl = {
......@@ -646,9 +652,9 @@ static int lo_probe_possible_loctls(struct b43_wldev *dev,
test_loctl.q != prev_loctl.q) &&
(abs(test_loctl.i) <= 16 && abs(test_loctl.q) <= 16)) {
b43_lo_write(dev, &test_loctl);
feedth = lo_measure_feedthrough(dev, phy->lna_gain,
phy->pga_gain,
phy->trsw_rx_gain);
feedth = lo_measure_feedthrough(dev, gphy->lna_gain,
gphy->pga_gain,
gphy->trsw_rx_gain);
if (feedth < d->lowest_feedth) {
memcpy(probe_loctl, &test_loctl,
sizeof(struct b43_loctl));
......@@ -677,6 +683,7 @@ static void lo_probe_loctls_statemachine(struct b43_wldev *dev,
int *max_rx_gain)
{
struct b43_phy *phy = &dev->phy;
struct b43_phy_g *gphy = phy->g;
struct b43_lo_g_statemachine d;
u16 feedth;
int found_lower;
......@@ -693,17 +700,17 @@ static void lo_probe_loctls_statemachine(struct b43_wldev *dev,
max_repeat = 4;
do {
b43_lo_write(dev, &d.min_loctl);
feedth = lo_measure_feedthrough(dev, phy->lna_gain,
phy->pga_gain,
phy->trsw_rx_gain);
feedth = lo_measure_feedthrough(dev, gphy->lna_gain,
gphy->pga_gain,
gphy->trsw_rx_gain);
if (feedth < 0x258) {
if (feedth >= 0x12C)
*max_rx_gain += 6;
else
*max_rx_gain += 3;
feedth = lo_measure_feedthrough(dev, phy->lna_gain,
phy->pga_gain,
phy->trsw_rx_gain);
feedth = lo_measure_feedthrough(dev, gphy->lna_gain,
gphy->pga_gain,
gphy->trsw_rx_gain);
}
d.lowest_feedth = feedth;
......@@ -752,6 +759,7 @@ struct b43_lo_calib * b43_calibrate_lo_setting(struct b43_wldev *dev,
const struct b43_rfatt *rfatt)
{
struct b43_phy *phy = &dev->phy;
struct b43_phy_g *gphy = phy->g;
struct b43_loctl loctl = {
.i = 0,
.q = 0,
......@@ -782,11 +790,11 @@ struct b43_lo_calib * b43_calibrate_lo_setting(struct b43_wldev *dev,
if (rfatt->with_padmix)
max_rx_gain -= pad_mix_gain;
if (has_loopback_gain(phy))
max_rx_gain += phy->max_lb_gain;
max_rx_gain += gphy->max_lb_gain;
lo_measure_gain_values(dev, max_rx_gain,
has_loopback_gain(phy));
b43_phy_set_baseband_attenuation(dev, bbatt->att);
b43_gphy_set_baseband_attenuation(dev, bbatt->att);
lo_probe_loctls_statemachine(dev, &loctl, &max_rx_gain);
lo_measure_restore(dev, &saved_regs);
......@@ -820,7 +828,7 @@ struct b43_lo_calib * b43_get_calib_lo_settings(struct b43_wldev *dev,
const struct b43_bbatt *bbatt,
const struct b43_rfatt *rfatt)
{
struct b43_txpower_lo_control *lo = dev->phy.lo_control;
struct b43_txpower_lo_control *lo = dev->phy.g->lo_control;
struct b43_lo_calib *c;
c = b43_find_lo_calib(lo, bbatt, rfatt);
......@@ -839,7 +847,8 @@ struct b43_lo_calib * b43_get_calib_lo_settings(struct b43_wldev *dev,
void b43_gphy_dc_lt_init(struct b43_wldev *dev, bool update_all)
{
struct b43_phy *phy = &dev->phy;
struct b43_txpower_lo_control *lo = phy->lo_control;
struct b43_phy_g *gphy = phy->g;
struct b43_txpower_lo_control *lo = gphy->lo_control;
int i;
int rf_offset, bb_offset;
const struct b43_rfatt *rfatt;
......@@ -917,14 +926,14 @@ static inline void b43_lo_fixup_rfatt(struct b43_rfatt *rf)
void b43_lo_g_adjust(struct b43_wldev *dev)
{
struct b43_phy *phy = &dev->phy;
struct b43_phy_g *gphy = dev->phy.g;
struct b43_lo_calib *cal;
struct b43_rfatt rf;
memcpy(&rf, &phy->rfatt, sizeof(rf));
memcpy(&rf, &gphy->rfatt, sizeof(rf));
b43_lo_fixup_rfatt(&rf);
cal = b43_get_calib_lo_settings(dev, &phy->bbatt, &rf);
cal = b43_get_calib_lo_settings(dev, &gphy->bbatt, &rf);
if (!cal)
return;
b43_lo_write(dev, &cal->ctl);
......@@ -952,7 +961,8 @@ void b43_lo_g_adjust_to(struct b43_wldev *dev,
void b43_lo_g_maintanance_work(struct b43_wldev *dev)
{
struct b43_phy *phy = &dev->phy;
struct b43_txpower_lo_control *lo = phy->lo_control;
struct b43_phy_g *gphy = phy->g;
struct b43_txpower_lo_control *lo = gphy->lo_control;
unsigned long now;
unsigned long expire;
struct b43_lo_calib *cal, *tmp;
......@@ -962,7 +972,7 @@ void b43_lo_g_maintanance_work(struct b43_wldev *dev)
if (!lo)
return;
now = jiffies;
hwpctl = b43_has_hardware_pctl(phy);
hwpctl = b43_has_hardware_pctl(dev);
if (hwpctl) {
/* Read the power vector and update it, if needed. */
......@@ -983,8 +993,8 @@ void b43_lo_g_maintanance_work(struct b43_wldev *dev)
if (!time_before(cal->calib_time, expire))
continue;
/* This item expired. */
if (b43_compare_bbatt(&cal->bbatt, &phy->bbatt) &&
b43_compare_rfatt(&cal->rfatt, &phy->rfatt)) {
if (b43_compare_bbatt(&cal->bbatt, &gphy->bbatt) &&
b43_compare_rfatt(&cal->rfatt, &gphy->rfatt)) {
B43_WARN_ON(current_item_expired);
current_item_expired = 1;
}
......@@ -1002,7 +1012,7 @@ void b43_lo_g_maintanance_work(struct b43_wldev *dev)
/* Recalibrate currently used LO setting. */
if (b43_debug(dev, B43_DBG_LO))
b43dbg(dev->wl, "LO: Recalibrating current LO setting\n");
cal = b43_calibrate_lo_setting(dev, &phy->bbatt, &phy->rfatt);
cal = b43_calibrate_lo_setting(dev, &gphy->bbatt, &gphy->rfatt);
if (cal) {
list_add(&cal->list, &lo->calib_list);
b43_lo_write(dev, &cal->ctl);
......@@ -1013,7 +1023,7 @@ void b43_lo_g_maintanance_work(struct b43_wldev *dev)
void b43_lo_g_cleanup(struct b43_wldev *dev)
{
struct b43_txpower_lo_control *lo = dev->phy.lo_control;
struct b43_txpower_lo_control *lo = dev->phy.g->lo_control;
struct b43_lo_calib *cal, *tmp;
if (!lo)
......@@ -1027,9 +1037,7 @@ void b43_lo_g_cleanup(struct b43_wldev *dev)
/* LO Initialization */
void b43_lo_g_init(struct b43_wldev *dev)
{
struct b43_phy *phy = &dev->phy;
if (b43_has_hardware_pctl(phy)) {
if (b43_has_hardware_pctl(dev)) {
lo_read_power_vector(dev);
b43_gphy_dc_lt_init(dev, 1);
}
......
#ifndef B43_LO_H_
#define B43_LO_H_
#include "phy.h"
/* G-PHY Local Oscillator */
#include "phy_g.h"
struct b43_wldev;
......
......@@ -44,7 +44,8 @@
#include "b43.h"
#include "main.h"
#include "debugfs.h"
#include "phy.h"
#include "phy_common.h"
#include "phy_g.h"
#include "nphy.h"
#include "dma.h"
#include "pio.h"
......@@ -1174,6 +1175,8 @@ static void b43_calculate_link_quality(struct b43_wldev *dev)
{
/* Top half of Link Quality calculation. */
if (dev->phy.type != B43_PHYTYPE_G)
return;
if (dev->noisecalc.calculation_running)
return;
dev->noisecalc.calculation_running = 1;
......@@ -1184,7 +1187,7 @@ static void b43_calculate_link_quality(struct b43_wldev *dev)
static void handle_irq_noise(struct b43_wldev *dev)
{
struct b43_phy *phy = &dev->phy;
struct b43_phy_g *phy = dev->phy.g;
u16 tmp;
u8 noise[4];
u8 i, j;
......@@ -1192,6 +1195,9 @@ static void handle_irq_noise(struct b43_wldev *dev)
/* Bottom half of Link Quality calculation. */
if (dev->phy.type != B43_PHYTYPE_G)
return;
/* Possible race condition: It might be possible that the user
* changed to a different channel in the meantime since we
* started the calculation. We ignore that fact, since it's
......@@ -2688,9 +2694,7 @@ static void b43_mgmtframe_txantenna(struct b43_wldev *dev, int antenna)
/* This is the opposite of b43_chip_init() */
static void b43_chip_exit(struct b43_wldev *dev)
{
b43_radio_turn_off(dev, 1);
b43_gpio_cleanup(dev);
b43_lo_g_cleanup(dev);
/* firmware is released later */
}
......@@ -2700,7 +2704,7 @@ static void b43_chip_exit(struct b43_wldev *dev)
static int b43_chip_init(struct b43_wldev *dev)
{
struct b43_phy *phy = &dev->phy;
int err, tmp;
int err;
u32 value32, macctl;
u16 value16;
......@@ -2725,19 +2729,19 @@ static int b43_chip_init(struct b43_wldev *dev)
err = b43_upload_initvals(dev);
if (err)
goto err_gpio_clean;
b43_radio_turn_on(dev);
b43_write16(dev, 0x03E6, 0x0000);
err = b43_phy_init(dev);
if (err)
goto err_radio_off;
goto err_gpio_clean;
/* Select initial Interference Mitigation. */
tmp = phy->interfmode;
phy->interfmode = B43_INTERFMODE_NONE;
b43_radio_set_interference_mitigation(dev, tmp);
/* Disable Interference Mitigation. */
if (phy->ops->interf_mitigation)
phy->ops->interf_mitigation(dev, B43_INTERFMODE_NONE);
b43_set_rx_antenna(dev, B43_ANTENNA_DEFAULT);
/* Select the antennae */
if (phy->ops->set_rx_antenna)
phy->ops->set_rx_antenna(dev, B43_ANTENNA_DEFAULT);
b43_mgmtframe_txantenna(dev, B43_ANTENNA_DEFAULT);
if (phy->type == B43_PHYTYPE_B) {
......@@ -2790,8 +2794,6 @@ static int b43_chip_init(struct b43_wldev *dev)
out:
return err;
err_radio_off:
b43_radio_turn_off(dev, 1);
err_gpio_clean:
b43_gpio_cleanup(dev);
return err;
......@@ -2799,25 +2801,10 @@ static int b43_chip_init(struct b43_wldev *dev)
static void b43_periodic_every60sec(struct b43_wldev *dev)
{
struct b43_phy *phy = &dev->phy;
const struct b43_phy_operations *ops = dev->phy.ops;
if (phy->type != B43_PHYTYPE_G)
return;
if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI) {
b43_mac_suspend(dev);
b43_calc_nrssi_slope(dev);
if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 8)) {
u8 old_chan = phy->channel;
/* VCO Calibration */
if (old_chan >= 8)
b43_radio_selectchannel(dev, 1, 0);
else
b43_radio_selectchannel(dev, 13, 0);
b43_radio_selectchannel(dev, old_chan, 0);
}
b43_mac_enable(dev);
}
if (ops->pwork_60sec)
ops->pwork_60sec(dev);
}
static void b43_periodic_every30sec(struct b43_wldev *dev)
......@@ -2845,32 +2832,10 @@ static void b43_periodic_every15sec(struct b43_wldev *dev)
}
}
if (phy->type == B43_PHYTYPE_G) {
//TODO: update_aci_moving_average
if (phy->aci_enable && phy->aci_wlan_automatic) {
b43_mac_suspend(dev);
if (!phy->aci_enable && 1 /*TODO: not scanning? */ ) {
if (0 /*TODO: bunch of conditions */ ) {
b43_radio_set_interference_mitigation
(dev, B43_INTERFMODE_MANUALWLAN);
}
} else if (1 /*TODO*/) {
/*
if ((aci_average > 1000) && !(b43_radio_aci_scan(dev))) {
b43_radio_set_interference_mitigation(dev,
B43_INTERFMODE_NONE);
}
*/
}
b43_mac_enable(dev);
} else if (phy->interfmode == B43_INTERFMODE_NONWLAN &&
phy->rev == 1) {
//TODO: implement rev1 workaround
}
}
b43_phy_xmitpower(dev); //FIXME: unless scanning?
b43_lo_g_maintanance_work(dev);
//TODO for APHY (temperature?)
if (phy->ops->pwork_15sec)
phy->ops->pwork_15sec(dev);
phy->ops->xmitpower(dev);
atomic_set(&phy->txerr_cnt, B43_PHY_TX_BADNESS_LIMIT);
wmb();
......@@ -3401,7 +3366,7 @@ static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
/* Switch to the requested channel.
* The firmware takes care of races with the TX handler. */
if (conf->channel->hw_value != phy->channel)
b43_radio_selectchannel(dev, conf->channel->hw_value, 0);
b43_switch_channel(dev, conf->channel->hw_value);
/* Enable/Disable ShortSlot timing. */
if ((!!(conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME)) !=
......@@ -3419,7 +3384,7 @@ static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
if (conf->power_level != 0) {
if (conf->power_level != phy->power_level) {
phy->power_level = conf->power_level;
b43_phy_xmitpower(dev);
phy->ops->xmitpower(dev);
}
}
......@@ -3427,7 +3392,8 @@ static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
antenna = b43_antenna_from_ieee80211(dev, conf->antenna_sel_tx);
b43_mgmtframe_txantenna(dev, antenna);
antenna = b43_antenna_from_ieee80211(dev, conf->antenna_sel_rx);
b43_set_rx_antenna(dev, antenna);
if (phy->ops->set_rx_antenna)
phy->ops->set_rx_antenna(dev, antenna);
/* Update templates for AP/mesh mode. */
if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP) ||
......@@ -3436,7 +3402,7 @@ static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
if (!!conf->radio_enabled != phy->radio_on) {
if (conf->radio_enabled) {
b43_radio_turn_on(dev);
b43_software_rfkill(dev, RFKILL_STATE_UNBLOCKED);
b43info(dev->wl, "Radio turned on by software\n");
if (!dev->radio_hw_enable) {
b43info(dev->wl, "The hardware RF-kill button "
......@@ -3444,7 +3410,7 @@ static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
"Press the button to turn it on.\n");
}
} else {
b43_radio_turn_off(dev, 0);
b43_software_rfkill(dev, RFKILL_STATE_SOFT_BLOCKED);
b43info(dev->wl, "Radio turned off by software\n");
}
}
......@@ -3818,48 +3784,9 @@ static int b43_phy_versioning(struct b43_wldev *dev)
static void setup_struct_phy_for_init(struct b43_wldev *dev,
struct b43_phy *phy)
{
struct b43_txpower_lo_control *lo;
int i;
memset(phy->minlowsig, 0xFF, sizeof(phy->minlowsig));
memset(phy->minlowsigpos, 0, sizeof(phy->minlowsigpos));
phy->aci_enable = 0;
phy->aci_wlan_automatic = 0;
phy->aci_hw_rssi = 0;
phy->radio_off_context.valid = 0;
lo = phy->lo_control;
if (lo) {
memset(lo, 0, sizeof(*(phy->lo_control)));
lo->tx_bias = 0xFF;
INIT_LIST_HEAD(&lo->calib_list);
}
phy->max_lb_gain = 0;
phy->trsw_rx_gain = 0;
phy->txpwr_offset = 0;
/* NRSSI */
phy->nrssislope = 0;
for (i = 0; i < ARRAY_SIZE(phy->nrssi); i++)
phy->nrssi[i] = -1000;
for (i = 0; i < ARRAY_SIZE(phy->nrssi_lt); i++)
phy->nrssi_lt[i] = i;
phy->lofcal = 0xFFFF;
phy->initval = 0xFFFF;
phy->interfmode = B43_INTERFMODE_NONE;
phy->channel = 0xFF;
phy->hardware_power_control = !!modparam_hwpctl;
/* PHY TX errors counter. */
atomic_set(&phy->txerr_cnt, B43_PHY_TX_BADNESS_LIMIT);
/* OFDM-table address caching. */
phy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_UNKNOWN;
}
static void setup_struct_wldev_for_init(struct b43_wldev *dev)
......@@ -3995,7 +3922,6 @@ static void b43_set_pretbtt(struct b43_wldev *dev)
/* Locking: wl->mutex */
static void b43_wireless_core_exit(struct b43_wldev *dev)
{
struct b43_phy *phy = &dev->phy;
u32 macctl;
B43_WARN_ON(b43_status(dev) > B43_STAT_INITIALIZED);
......@@ -4016,16 +3942,12 @@ static void b43_wireless_core_exit(struct b43_wldev *dev)
b43_dma_free(dev);
b43_pio_free(dev);
b43_chip_exit(dev);
b43_radio_turn_off(dev, 1);
b43_switch_analog(dev, 0);
if (phy->dyn_tssi_tbl)
kfree(phy->tssi2dbm);
kfree(phy->lo_control);
phy->lo_control = NULL;
if (dev->wl->current_beacon) {
dev_kfree_skb_any(dev->wl->current_beacon);
dev->wl->current_beacon = NULL;
}
b43_phy_exit(dev);
ssb_device_disable(dev->dev, 0);
ssb_bus_may_powerdown(dev->dev->bus);
......@@ -4052,29 +3974,24 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
b43_wireless_core_reset(dev, tmp);
}
if ((phy->type == B43_PHYTYPE_B) || (phy->type == B43_PHYTYPE_G)) {
phy->lo_control =
kzalloc(sizeof(*(phy->lo_control)), GFP_KERNEL);
if (!phy->lo_control) {
err = -ENOMEM;
goto err_busdown;
}
}
setup_struct_wldev_for_init(dev);
err = b43_phy_init_tssi2dbm_table(dev);
err = b43_phy_operations_setup(dev);
if (err)
goto err_kfree_lo_control;
goto err_busdown;
/* Enable IRQ routing to this device. */
ssb_pcicore_dev_irqvecs_enable(&bus->pcicore, dev->dev);
b43_imcfglo_timeouts_workaround(dev);
b43_bluetooth_coext_disable(dev);
b43_phy_early_init(dev);
if (phy->ops->prepare) {
err = phy->ops->prepare(dev);
if (err)
goto err_phy_exit;
}
err = b43_chip_init(dev);
if (err)
goto err_kfree_tssitbl;
goto err_phy_exit;
b43_shm_write16(dev, B43_SHM_SHARED,
B43_SHM_SH_WLCOREREV, dev->dev->id.revision);
hf = b43_hf_read(dev);
......@@ -4140,15 +4057,11 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
out:
return err;
err_chip_exit:
err_chip_exit:
b43_chip_exit(dev);
err_kfree_tssitbl:
if (phy->dyn_tssi_tbl)
kfree(phy->tssi2dbm);
err_kfree_lo_control:
kfree(phy->lo_control);
phy->lo_control = NULL;
err_busdown:
err_phy_exit:
b43_phy_exit(dev);
err_busdown:
ssb_bus_may_powerdown(bus);
B43_WARN_ON(b43_status(dev) != B43_STAT_UNINIT);
return err;
......@@ -4511,7 +4424,6 @@ static int b43_wireless_core_attach(struct b43_wldev *dev)
wl->current_dev = dev;
INIT_WORK(&dev->restart_work, b43_chip_reset);
b43_radio_turn_off(dev, 1);
b43_switch_analog(dev, 0);
ssb_device_disable(dev->dev, 0);
ssb_bus_may_powerdown(bus);
......
......@@ -81,9 +81,8 @@ static void b43_nphy_tx_power_fix(struct b43_wldev *dev)
//TODO
}
/* Tune the hardware to a new channel. Don't call this directly.
* Use b43_radio_selectchannel() */
int b43_nphy_selectchannel(struct b43_wldev *dev, u8 channel)
/* Tune the hardware to a new channel. */
static int nphy_channel_switch(struct b43_wldev *dev, unsigned int channel)
{
const struct b43_nphy_channeltab_entry *tabent;
......@@ -162,7 +161,7 @@ static void b43_radio_init2055_post(struct b43_wldev *dev)
msleep(1);
b43_radio_mask(dev, B2055_CAL_LPOCTL, 0xFF7F);
msleep(1);
b43_radio_selectchannel(dev, dev->phy.channel, 0);
nphy_channel_switch(dev, dev->phy.channel);
b43_radio_write16(dev, B2055_C1_RX_BB_LPF, 0x9);
b43_radio_write16(dev, B2055_C2_RX_BB_LPF, 0x9);
b43_radio_write16(dev, B2055_C1_RX_BB_MIDACHP, 0x83);
......@@ -484,3 +483,139 @@ int b43_phy_initn(struct b43_wldev *dev)
b43err(dev->wl, "IEEE 802.11n devices are not supported, yet.\n");
return 0;
}
static int b43_nphy_op_allocate(struct b43_wldev *dev)
{
struct b43_phy_n *nphy;
nphy = kzalloc(sizeof(*nphy), GFP_KERNEL);
if (!nphy)
return -ENOMEM;
dev->phy.n = nphy;
//TODO init struct b43_phy_n
return 0;
}
static int b43_nphy_op_init(struct b43_wldev *dev)
{
struct b43_phy_n *nphy = dev->phy.n;
int err;
err = b43_phy_initn(dev);
if (err)
return err;
nphy->initialised = 1;
return 0;
}
static void b43_nphy_op_exit(struct b43_wldev *dev)
{
struct b43_phy_n *nphy = dev->phy.n;
if (nphy->initialised) {
//TODO
nphy->initialised = 0;
}
//TODO
kfree(nphy);
dev->phy.n = NULL;
}
static inline void check_phyreg(struct b43_wldev *dev, u16 offset)
{
#if B43_DEBUG
if ((offset & B43_PHYROUTE) == B43_PHYROUTE_OFDM_GPHY) {
/* OFDM registers are onnly available on A/G-PHYs */
b43err(dev->wl, "Invalid OFDM PHY access at "
"0x%04X on N-PHY\n", offset);
dump_stack();
}
if ((offset & B43_PHYROUTE) == B43_PHYROUTE_EXT_GPHY) {
/* Ext-G registers are only available on G-PHYs */
b43err(dev->wl, "Invalid EXT-G PHY access at "
"0x%04X on N-PHY\n", offset);
dump_stack();
}
#endif /* B43_DEBUG */
}
static u16 b43_nphy_op_read(struct b43_wldev *dev, u16 reg)
{
check_phyreg(dev, reg);
b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
return b43_read16(dev, B43_MMIO_PHY_DATA);
}
static void b43_nphy_op_write(struct b43_wldev *dev, u16 reg, u16 value)
{
check_phyreg(dev, reg);
b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
b43_write16(dev, B43_MMIO_PHY_DATA, value);
}
static u16 b43_nphy_op_radio_read(struct b43_wldev *dev, u16 reg)
{
/* Register 1 is a 32-bit register. */
B43_WARN_ON(reg == 1);
/* N-PHY needs 0x100 for read access */
reg |= 0x100;
b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg);
return b43_read16(dev, B43_MMIO_RADIO_DATA_LOW);
}
static void b43_nphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value)
{
/* Register 1 is a 32-bit register. */
B43_WARN_ON(reg == 1);
b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg);
b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, value);
}
static void b43_nphy_op_software_rfkill(struct b43_wldev *dev,
enum rfkill_state state)
{//TODO
}
static int b43_nphy_op_switch_channel(struct b43_wldev *dev,
unsigned int new_channel)
{
if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
if ((new_channel < 1) || (new_channel > 14))
return -EINVAL;
} else {
if (new_channel > 200)
return -EINVAL;
}
return nphy_channel_switch(dev, new_channel);
}
static unsigned int b43_nphy_op_get_default_chan(struct b43_wldev *dev)
{
if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
return 1;
return 36;
}
static void b43_nphy_op_xmitpower(struct b43_wldev *dev)
{//TODO
}
const struct b43_phy_operations b43_phyops_n = {
.allocate = b43_nphy_op_allocate,
.init = b43_nphy_op_init,
.exit = b43_nphy_op_exit,
.phy_read = b43_nphy_op_read,
.phy_write = b43_nphy_op_write,
.radio_read = b43_nphy_op_radio_read,
.radio_write = b43_nphy_op_radio_write,
.software_rfkill = b43_nphy_op_software_rfkill,
.switch_channel = b43_nphy_op_switch_channel,
.get_default_chan = b43_nphy_op_get_default_chan,
.xmitpower = b43_nphy_op_xmitpower,
};
#ifndef B43_NPHY_H_
#define B43_NPHY_H_
#include "phy.h"
#include "phy_common.h"
/* N-PHY registers. */
......@@ -919,54 +919,14 @@
struct b43_wldev;
struct b43_phy_n {
bool initialised;
#ifdef CONFIG_B43_NPHY
/* N-PHY support enabled */
//TODO lots of missing stuff
};
int b43_phy_initn(struct b43_wldev *dev);
void b43_nphy_radio_turn_on(struct b43_wldev *dev);
void b43_nphy_radio_turn_off(struct b43_wldev *dev);
struct b43_phy_operations;
extern const struct b43_phy_operations b43_phyops_n;
int b43_nphy_selectchannel(struct b43_wldev *dev, u8 channel);
void b43_nphy_xmitpower(struct b43_wldev *dev);
void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna);
#else /* CONFIG_B43_NPHY */
/* N-PHY support disabled */
static inline
int b43_phy_initn(struct b43_wldev *dev)
{
return -EOPNOTSUPP;
}
static inline
void b43_nphy_radio_turn_on(struct b43_wldev *dev)
{
}
static inline
void b43_nphy_radio_turn_off(struct b43_wldev *dev)
{
}
static inline
int b43_nphy_selectchannel(struct b43_wldev *dev, u8 channel)
{
return -ENOSYS;
}
static inline
void b43_nphy_xmitpower(struct b43_wldev *dev)
{
}
static inline
void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna)
{
}
#endif /* CONFIG_B43_NPHY */
#endif /* B43_NPHY_H_ */
此差异已折叠。
/*
Broadcom B43 wireless driver
IEEE 802.11a PHY driver
Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
Copyright (c) 2005-2007 Stefano Brivio <stefano.brivio@polimi.it>
Copyright (c) 2005-2008 Michael Buesch <mb@bu3sch.de>
Copyright (c) 2005, 2006 Danny van Dyk <kugelfang@gentoo.org>
Copyright (c) 2005, 2006 Andreas Jaggi <andreas.jaggi@waterwave.ch>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "b43.h"
#include "phy_a.h"
#include "phy_common.h"
#include "wa.h"
#include "tables.h"
#include "main.h"
/* Get the freq, as it has to be written to the device. */
static inline u16 channel2freq_a(u8 channel)
{
B43_WARN_ON(channel > 200);
return (5000 + 5 * channel);
}
static inline u16 freq_r3A_value(u16 frequency)
{
u16 value;
if (frequency < 5091)
value = 0x0040;
else if (frequency < 5321)
value = 0x0000;
else if (frequency < 5806)
value = 0x0080;
else
value = 0x0040;
return value;
}
void b43_radio_set_tx_iq(struct b43_wldev *dev)
{
static const u8 data_high[5] = { 0x00, 0x40, 0x80, 0x90, 0xD0 };
static const u8 data_low[5] = { 0x00, 0x01, 0x05, 0x06, 0x0A };
u16 tmp = b43_radio_read16(dev, 0x001E);
int i, j;
for (i = 0; i < 5; i++) {
for (j = 0; j < 5; j++) {
if (tmp == (data_high[i] << 4 | data_low[j])) {
b43_phy_write(dev, 0x0069,
(i - j) << 8 | 0x00C0);
return;
}
}
}
}
static void aphy_channel_switch(struct b43_wldev *dev, unsigned int channel)
{
u16 freq, r8, tmp;
freq = channel2freq_a(channel);
r8 = b43_radio_read16(dev, 0x0008);
b43_write16(dev, 0x03F0, freq);
b43_radio_write16(dev, 0x0008, r8);
//TODO: write max channel TX power? to Radio 0x2D
tmp = b43_radio_read16(dev, 0x002E);
tmp &= 0x0080;
//TODO: OR tmp with the Power out estimation for this channel?
b43_radio_write16(dev, 0x002E, tmp);
if (freq >= 4920 && freq <= 5500) {
/*
* r8 = (((freq * 15 * 0xE1FC780F) >> 32) / 29) & 0x0F;
* = (freq * 0.025862069
*/
r8 = 3 * freq / 116; /* is equal to r8 = freq * 0.025862 */
}
b43_radio_write16(dev, 0x0007, (r8 << 4) | r8);
b43_radio_write16(dev, 0x0020, (r8 << 4) | r8);
b43_radio_write16(dev, 0x0021, (r8 << 4) | r8);
b43_radio_write16(dev, 0x0022, (b43_radio_read16(dev, 0x0022)
& 0x000F) | (r8 << 4));
b43_radio_write16(dev, 0x002A, (r8 << 4));
b43_radio_write16(dev, 0x002B, (r8 << 4));
b43_radio_write16(dev, 0x0008, (b43_radio_read16(dev, 0x0008)
& 0x00F0) | (r8 << 4));
b43_radio_write16(dev, 0x0029, (b43_radio_read16(dev, 0x0029)
& 0xFF0F) | 0x00B0);
b43_radio_write16(dev, 0x0035, 0x00AA);
b43_radio_write16(dev, 0x0036, 0x0085);
b43_radio_write16(dev, 0x003A, (b43_radio_read16(dev, 0x003A)
& 0xFF20) |
freq_r3A_value(freq));
b43_radio_write16(dev, 0x003D,
b43_radio_read16(dev, 0x003D) & 0x00FF);
b43_radio_write16(dev, 0x0081, (b43_radio_read16(dev, 0x0081)
& 0xFF7F) | 0x0080);
b43_radio_write16(dev, 0x0035,
b43_radio_read16(dev, 0x0035) & 0xFFEF);
b43_radio_write16(dev, 0x0035, (b43_radio_read16(dev, 0x0035)
& 0xFFEF) | 0x0010);
b43_radio_set_tx_iq(dev);
//TODO: TSSI2dbm workaround
//FIXME b43_phy_xmitpower(dev);
}
void b43_radio_init2060(struct b43_wldev *dev)
{
b43_radio_write16(dev, 0x0004, 0x00C0);
b43_radio_write16(dev, 0x0005, 0x0008);
b43_radio_write16(dev, 0x0009, 0x0040);
b43_radio_write16(dev, 0x0005, 0x00AA);
b43_radio_write16(dev, 0x0032, 0x008F);
b43_radio_write16(dev, 0x0006, 0x008F);
b43_radio_write16(dev, 0x0034, 0x008F);
b43_radio_write16(dev, 0x002C, 0x0007);
b43_radio_write16(dev, 0x0082, 0x0080);
b43_radio_write16(dev, 0x0080, 0x0000);
b43_radio_write16(dev, 0x003F, 0x00DA);
b43_radio_write16(dev, 0x0005, b43_radio_read16(dev, 0x0005) & ~0x0008);
b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0010);
b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0020);
b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0020);
msleep(1); /* delay 400usec */
b43_radio_write16(dev, 0x0081,
(b43_radio_read16(dev, 0x0081) & ~0x0020) | 0x0010);
msleep(1); /* delay 400usec */
b43_radio_write16(dev, 0x0005,
(b43_radio_read16(dev, 0x0005) & ~0x0008) | 0x0008);
b43_radio_write16(dev, 0x0085, b43_radio_read16(dev, 0x0085) & ~0x0010);
b43_radio_write16(dev, 0x0005, b43_radio_read16(dev, 0x0005) & ~0x0008);
b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0040);
b43_radio_write16(dev, 0x0081,
(b43_radio_read16(dev, 0x0081) & ~0x0040) | 0x0040);
b43_radio_write16(dev, 0x0005,
(b43_radio_read16(dev, 0x0081) & ~0x0008) | 0x0008);
b43_phy_write(dev, 0x0063, 0xDDC6);
b43_phy_write(dev, 0x0069, 0x07BE);
b43_phy_write(dev, 0x006A, 0x0000);
aphy_channel_switch(dev, dev->phy.ops->get_default_chan(dev));
msleep(1);
}
static void b43_phy_rssiagc(struct b43_wldev *dev, u8 enable)
{
int i;
if (dev->phy.rev < 3) {
if (enable)
for (i = 0; i < B43_TAB_RSSIAGC1_SIZE; i++) {
b43_ofdmtab_write16(dev,
B43_OFDMTAB_LNAHPFGAIN1, i, 0xFFF8);
b43_ofdmtab_write16(dev,
B43_OFDMTAB_WRSSI, i, 0xFFF8);
}
else
for (i = 0; i < B43_TAB_RSSIAGC1_SIZE; i++) {
b43_ofdmtab_write16(dev,
B43_OFDMTAB_LNAHPFGAIN1, i, b43_tab_rssiagc1[i]);
b43_ofdmtab_write16(dev,
B43_OFDMTAB_WRSSI, i, b43_tab_rssiagc1[i]);
}
} else {
if (enable)
for (i = 0; i < B43_TAB_RSSIAGC1_SIZE; i++)
b43_ofdmtab_write16(dev,
B43_OFDMTAB_WRSSI, i, 0x0820);
else
for (i = 0; i < B43_TAB_RSSIAGC2_SIZE; i++)
b43_ofdmtab_write16(dev,
B43_OFDMTAB_WRSSI, i, b43_tab_rssiagc2[i]);
}
}
static void b43_phy_ww(struct b43_wldev *dev)
{
u16 b, curr_s, best_s = 0xFFFF;
int i;
b43_phy_write(dev, B43_PHY_CRS0,
b43_phy_read(dev, B43_PHY_CRS0) & ~B43_PHY_CRS0_EN);
b43_phy_write(dev, B43_PHY_OFDM(0x1B),
b43_phy_read(dev, B43_PHY_OFDM(0x1B)) | 0x1000);
b43_phy_write(dev, B43_PHY_OFDM(0x82),
(b43_phy_read(dev, B43_PHY_OFDM(0x82)) & 0xF0FF) | 0x0300);
b43_radio_write16(dev, 0x0009,
b43_radio_read16(dev, 0x0009) | 0x0080);
b43_radio_write16(dev, 0x0012,
(b43_radio_read16(dev, 0x0012) & 0xFFFC) | 0x0002);
b43_wa_initgains(dev);
b43_phy_write(dev, B43_PHY_OFDM(0xBA), 0x3ED5);
b = b43_phy_read(dev, B43_PHY_PWRDOWN);
b43_phy_write(dev, B43_PHY_PWRDOWN, (b & 0xFFF8) | 0x0005);
b43_radio_write16(dev, 0x0004,
b43_radio_read16(dev, 0x0004) | 0x0004);
for (i = 0x10; i <= 0x20; i++) {
b43_radio_write16(dev, 0x0013, i);
curr_s = b43_phy_read(dev, B43_PHY_OTABLEQ) & 0x00FF;
if (!curr_s) {
best_s = 0x0000;
break;
} else if (curr_s >= 0x0080)
curr_s = 0x0100 - curr_s;
if (curr_s < best_s)
best_s = curr_s;
}
b43_phy_write(dev, B43_PHY_PWRDOWN, b);
b43_radio_write16(dev, 0x0004,
b43_radio_read16(dev, 0x0004) & 0xFFFB);
b43_radio_write16(dev, 0x0013, best_s);
b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1_R1, 0, 0xFFEC);
b43_phy_write(dev, B43_PHY_OFDM(0xB7), 0x1E80);
b43_phy_write(dev, B43_PHY_OFDM(0xB6), 0x1C00);
b43_phy_write(dev, B43_PHY_OFDM(0xB5), 0x0EC0);
b43_phy_write(dev, B43_PHY_OFDM(0xB2), 0x00C0);
b43_phy_write(dev, B43_PHY_OFDM(0xB9), 0x1FFF);
b43_phy_write(dev, B43_PHY_OFDM(0xBB),
(b43_phy_read(dev, B43_PHY_OFDM(0xBB)) & 0xF000) | 0x0053);
b43_phy_write(dev, B43_PHY_OFDM61,
(b43_phy_read(dev, B43_PHY_OFDM61) & 0xFE1F) | 0x0120);
b43_phy_write(dev, B43_PHY_OFDM(0x13),
(b43_phy_read(dev, B43_PHY_OFDM(0x13)) & 0x0FFF) | 0x3000);
b43_phy_write(dev, B43_PHY_OFDM(0x14),
(b43_phy_read(dev, B43_PHY_OFDM(0x14)) & 0x0FFF) | 0x3000);
b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 6, 0x0017);
for (i = 0; i < 6; i++)
b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, i, 0x000F);
b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0x0D, 0x000E);
b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0x0E, 0x0011);
b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0x0F, 0x0013);
b43_phy_write(dev, B43_PHY_OFDM(0x33), 0x5030);
b43_phy_write(dev, B43_PHY_CRS0,
b43_phy_read(dev, B43_PHY_CRS0) | B43_PHY_CRS0_EN);
}
static void hardware_pctl_init_aphy(struct b43_wldev *dev)
{
//TODO
}
void b43_phy_inita(struct b43_wldev *dev)
{
struct ssb_bus *bus = dev->dev->bus;
struct b43_phy *phy = &dev->phy;
/* This lowlevel A-PHY init is also called from G-PHY init.
* So we must not access phy->a, if called from G-PHY code.
*/
B43_WARN_ON((phy->type != B43_PHYTYPE_A) &&
(phy->type != B43_PHYTYPE_G));
might_sleep();
if (phy->rev >= 6) {
if (phy->type == B43_PHYTYPE_A)
b43_phy_write(dev, B43_PHY_OFDM(0x1B),
b43_phy_read(dev, B43_PHY_OFDM(0x1B)) & ~0x1000);
if (b43_phy_read(dev, B43_PHY_ENCORE) & B43_PHY_ENCORE_EN)
b43_phy_write(dev, B43_PHY_ENCORE,
b43_phy_read(dev, B43_PHY_ENCORE) | 0x0010);
else
b43_phy_write(dev, B43_PHY_ENCORE,
b43_phy_read(dev, B43_PHY_ENCORE) & ~0x1010);
}
b43_wa_all(dev);
if (phy->type == B43_PHYTYPE_A) {
if (phy->gmode && (phy->rev < 3))
b43_phy_write(dev, 0x0034,
b43_phy_read(dev, 0x0034) | 0x0001);
b43_phy_rssiagc(dev, 0);
b43_phy_write(dev, B43_PHY_CRS0,
b43_phy_read(dev, B43_PHY_CRS0) | B43_PHY_CRS0_EN);
b43_radio_init2060(dev);
if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) &&
((bus->boardinfo.type == SSB_BOARD_BU4306) ||
(bus->boardinfo.type == SSB_BOARD_BU4309))) {
; //TODO: A PHY LO
}
if (phy->rev >= 3)
b43_phy_ww(dev);
hardware_pctl_init_aphy(dev);
//TODO: radar detection
}
if ((phy->type == B43_PHYTYPE_G) &&
(dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL)) {
b43_phy_write(dev, B43_PHY_OFDM(0x6E),
(b43_phy_read(dev, B43_PHY_OFDM(0x6E))
& 0xE000) | 0x3CF);
}
}
static int b43_aphy_op_allocate(struct b43_wldev *dev)
{
struct b43_phy_a *aphy;
aphy = kzalloc(sizeof(*aphy), GFP_KERNEL);
if (!aphy)
return -ENOMEM;
dev->phy.a = aphy;
//TODO init struct b43_phy_a
return 0;
}
static int b43_aphy_op_init(struct b43_wldev *dev)
{
struct b43_phy_a *aphy = dev->phy.a;
b43_phy_inita(dev);
aphy->initialised = 1;
return 0;
}
static void b43_aphy_op_exit(struct b43_wldev *dev)
{
struct b43_phy_a *aphy = dev->phy.a;
if (aphy->initialised) {
//TODO
aphy->initialised = 0;
}
//TODO
kfree(aphy);
dev->phy.a = NULL;
}
static inline u16 adjust_phyreg(struct b43_wldev *dev, u16 offset)
{
/* OFDM registers are base-registers for the A-PHY. */
if ((offset & B43_PHYROUTE) == B43_PHYROUTE_OFDM_GPHY) {
offset &= ~B43_PHYROUTE;
offset |= B43_PHYROUTE_BASE;
}
#if B43_DEBUG
if ((offset & B43_PHYROUTE) == B43_PHYROUTE_EXT_GPHY) {
/* Ext-G registers are only available on G-PHYs */
b43err(dev->wl, "Invalid EXT-G PHY access at "
"0x%04X on A-PHY\n", offset);
dump_stack();
}
if ((offset & B43_PHYROUTE) == B43_PHYROUTE_N_BMODE) {
/* N-BMODE registers are only available on N-PHYs */
b43err(dev->wl, "Invalid N-BMODE PHY access at "
"0x%04X on A-PHY\n", offset);
dump_stack();
}
#endif /* B43_DEBUG */
return offset;
}
static u16 b43_aphy_op_read(struct b43_wldev *dev, u16 reg)
{
reg = adjust_phyreg(dev, reg);
b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
return b43_read16(dev, B43_MMIO_PHY_DATA);
}
static void b43_aphy_op_write(struct b43_wldev *dev, u16 reg, u16 value)
{
reg = adjust_phyreg(dev, reg);
b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
b43_write16(dev, B43_MMIO_PHY_DATA, value);
}
static u16 b43_aphy_op_radio_read(struct b43_wldev *dev, u16 reg)
{
/* Register 1 is a 32-bit register. */
B43_WARN_ON(reg == 1);
/* A-PHY needs 0x40 for read access */
reg |= 0x40;
b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg);
return b43_read16(dev, B43_MMIO_RADIO_DATA_LOW);
}
static void b43_aphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value)
{
/* Register 1 is a 32-bit register. */
B43_WARN_ON(reg == 1);
b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg);
b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, value);
}
static bool b43_aphy_op_supports_hwpctl(struct b43_wldev *dev)
{
return (dev->phy.rev >= 5);
}
static void b43_aphy_op_software_rfkill(struct b43_wldev *dev,
enum rfkill_state state)
{//TODO
}
static int b43_aphy_op_switch_channel(struct b43_wldev *dev,
unsigned int new_channel)
{
if (new_channel > 200)
return -EINVAL;
aphy_channel_switch(dev, new_channel);
return 0;
}
static unsigned int b43_aphy_op_get_default_chan(struct b43_wldev *dev)
{
return 36; /* Default to channel 36 */
}
static void b43_aphy_op_set_rx_antenna(struct b43_wldev *dev, int antenna)
{//TODO
struct b43_phy *phy = &dev->phy;
u64 hf;
u16 tmp;
int autodiv = 0;
if (antenna == B43_ANTENNA_AUTO0 || antenna == B43_ANTENNA_AUTO1)
autodiv = 1;
hf = b43_hf_read(dev);
hf &= ~B43_HF_ANTDIVHELP;
b43_hf_write(dev, hf);
tmp = b43_phy_read(dev, B43_PHY_BBANDCFG);
tmp &= ~B43_PHY_BBANDCFG_RXANT;
tmp |= (autodiv ? B43_ANTENNA_AUTO0 : antenna)
<< B43_PHY_BBANDCFG_RXANT_SHIFT;
b43_phy_write(dev, B43_PHY_BBANDCFG, tmp);
if (autodiv) {
tmp = b43_phy_read(dev, B43_PHY_ANTDWELL);
if (antenna == B43_ANTENNA_AUTO0)
tmp &= ~B43_PHY_ANTDWELL_AUTODIV1;
else
tmp |= B43_PHY_ANTDWELL_AUTODIV1;
b43_phy_write(dev, B43_PHY_ANTDWELL, tmp);
}
if (phy->rev < 3) {
tmp = b43_phy_read(dev, B43_PHY_ANTDWELL);
tmp = (tmp & 0xFF00) | 0x24;
b43_phy_write(dev, B43_PHY_ANTDWELL, tmp);
} else {
tmp = b43_phy_read(dev, B43_PHY_OFDM61);
tmp |= 0x10;
b43_phy_write(dev, B43_PHY_OFDM61, tmp);
if (phy->analog == 3) {
b43_phy_write(dev, B43_PHY_CLIPPWRDOWNT,
0x1D);
b43_phy_write(dev, B43_PHY_ADIVRELATED,
8);
} else {
b43_phy_write(dev, B43_PHY_CLIPPWRDOWNT,
0x3A);
tmp =
b43_phy_read(dev,
B43_PHY_ADIVRELATED);
tmp = (tmp & 0xFF00) | 8;
b43_phy_write(dev, B43_PHY_ADIVRELATED,
tmp);
}
}
hf |= B43_HF_ANTDIVHELP;
b43_hf_write(dev, hf);
}
static void b43_aphy_op_xmitpower(struct b43_wldev *dev)
{//TODO
}
static void b43_aphy_op_pwork_15sec(struct b43_wldev *dev)
{//TODO
}
static void b43_aphy_op_pwork_60sec(struct b43_wldev *dev)
{//TODO
}
const struct b43_phy_operations b43_phyops_a = {
.allocate = b43_aphy_op_allocate,
.init = b43_aphy_op_init,
.exit = b43_aphy_op_exit,
.phy_read = b43_aphy_op_read,
.phy_write = b43_aphy_op_write,
.radio_read = b43_aphy_op_radio_read,
.radio_write = b43_aphy_op_radio_write,
.supports_hwpctl = b43_aphy_op_supports_hwpctl,
.software_rfkill = b43_aphy_op_software_rfkill,
.switch_channel = b43_aphy_op_switch_channel,
.get_default_chan = b43_aphy_op_get_default_chan,
.set_rx_antenna = b43_aphy_op_set_rx_antenna,
.xmitpower = b43_aphy_op_xmitpower,
.pwork_15sec = b43_aphy_op_pwork_15sec,
.pwork_60sec = b43_aphy_op_pwork_60sec,
};
#ifndef B43_PHY_H_
#define B43_PHY_H_
#ifndef LINUX_B43_PHY_A_H_
#define LINUX_B43_PHY_A_H_
#include <linux/types.h>
#include "phy_common.h"
struct b43_wldev;
struct b43_phy;
/*** PHY Registers ***/
/* Routing */
#define B43_PHYROUTE 0x0C00 /* PHY register routing bits mask */
#define B43_PHYROUTE_BASE 0x0000 /* Base registers */
#define B43_PHYROUTE_OFDM_GPHY 0x0400 /* OFDM register routing for G-PHYs */
#define B43_PHYROUTE_EXT_GPHY 0x0800 /* Extended G-PHY registers */
#define B43_PHYROUTE_N_BMODE 0x0C00 /* N-PHY BMODE registers */
/* CCK (B-PHY) registers. */
#define B43_PHY_CCK(reg) ((reg) | B43_PHYROUTE_BASE)
/* N-PHY registers. */
#define B43_PHY_N(reg) ((reg) | B43_PHYROUTE_BASE)
/* N-PHY BMODE registers. */
#define B43_PHY_N_BMODE(reg) ((reg) | B43_PHYROUTE_N_BMODE)
/* OFDM (A-PHY) registers. */
#define B43_PHY_OFDM(reg) ((reg) | B43_PHYROUTE_OFDM_GPHY)
/* Extended G-PHY registers. */
#define B43_PHY_EXTG(reg) ((reg) | B43_PHYROUTE_EXT_GPHY)
/* OFDM (A) PHY Registers */
#define B43_PHY_VERSION_OFDM B43_PHY_OFDM(0x00) /* Versioning register for A-PHY */
......@@ -82,46 +60,6 @@ struct b43_phy;
#define B43_PHY_DC_LTBASE B43_PHY_OFDM(0x3A0) /* DC lookup table base */
#define B43_PHY_GAIN_LTBASE B43_PHY_OFDM(0x3C0) /* Gain lookup table base */
/* CCK (B) PHY Registers */
#define B43_PHY_VERSION_CCK B43_PHY_CCK(0x00) /* Versioning register for B-PHY */
#define B43_PHY_CCKBBANDCFG B43_PHY_CCK(0x01) /* Contains antenna 0/1 control bit */
#define B43_PHY_PGACTL B43_PHY_CCK(0x15) /* PGA control */
#define B43_PHY_PGACTL_LPF 0x1000 /* Low pass filter (?) */
#define B43_PHY_PGACTL_LOWBANDW 0x0040 /* Low bandwidth flag */
#define B43_PHY_PGACTL_UNKNOWN 0xEFA0
#define B43_PHY_FBCTL1 B43_PHY_CCK(0x18) /* Frequency bandwidth control 1 */
#define B43_PHY_ITSSI B43_PHY_CCK(0x29) /* Idle TSSI */
#define B43_PHY_LO_LEAKAGE B43_PHY_CCK(0x2D) /* Measured LO leakage */
#define B43_PHY_ENERGY B43_PHY_CCK(0x33) /* Energy */
#define B43_PHY_SYNCCTL B43_PHY_CCK(0x35)
#define B43_PHY_FBCTL2 B43_PHY_CCK(0x38) /* Frequency bandwidth control 2 */
#define B43_PHY_DACCTL B43_PHY_CCK(0x60) /* DAC control */
#define B43_PHY_RCCALOVER B43_PHY_CCK(0x78) /* RC calibration override */
/* Extended G-PHY Registers */
#define B43_PHY_CLASSCTL B43_PHY_EXTG(0x02) /* Classify control */
#define B43_PHY_GTABCTL B43_PHY_EXTG(0x03) /* G-PHY table control (see below) */
#define B43_PHY_GTABOFF 0x03FF /* G-PHY table offset (see below) */
#define B43_PHY_GTABNR 0xFC00 /* G-PHY table number (see below) */
#define B43_PHY_GTABNR_SHIFT 10
#define B43_PHY_GTABDATA B43_PHY_EXTG(0x04) /* G-PHY table data */
#define B43_PHY_LO_MASK B43_PHY_EXTG(0x0F) /* Local Oscillator control mask */
#define B43_PHY_LO_CTL B43_PHY_EXTG(0x10) /* Local Oscillator control */
#define B43_PHY_RFOVER B43_PHY_EXTG(0x11) /* RF override */
#define B43_PHY_RFOVERVAL B43_PHY_EXTG(0x12) /* RF override value */
#define B43_PHY_RFOVERVAL_EXTLNA 0x8000
#define B43_PHY_RFOVERVAL_LNA 0x7000
#define B43_PHY_RFOVERVAL_LNA_SHIFT 12
#define B43_PHY_RFOVERVAL_PGA 0x0F00
#define B43_PHY_RFOVERVAL_PGA_SHIFT 8
#define B43_PHY_RFOVERVAL_UNK 0x0010 /* Unknown, always set. */
#define B43_PHY_RFOVERVAL_TRSWRX 0x00E0
#define B43_PHY_RFOVERVAL_BW 0x0003 /* Bandwidth flags */
#define B43_PHY_RFOVERVAL_BW_LPF 0x0001 /* Low Pass Filter */
#define B43_PHY_RFOVERVAL_BW_LBW 0x0002 /* Low Bandwidth (when set), high when unset */
#define B43_PHY_ANALOGOVER B43_PHY_EXTG(0x14) /* Analog override */
#define B43_PHY_ANALOGOVERVAL B43_PHY_EXTG(0x15) /* Analog override value */
/*** OFDM table numbers ***/
#define B43_OFDMTAB(number, offset) (((number) << B43_PHY_OTABLENR_SHIFT) | (offset))
#define B43_OFDMTAB_AGC1 B43_OFDMTAB(0x00, 0)
......@@ -163,178 +101,24 @@ u32 b43_ofdmtab_read32(struct b43_wldev *dev, u16 table, u16 offset);
void b43_ofdmtab_write32(struct b43_wldev *dev, u16 table,
u16 offset, u32 value);
/*** G-PHY table numbers */
#define B43_GTAB(number, offset) (((number) << B43_PHY_GTABNR_SHIFT) | (offset))
#define B43_GTAB_NRSSI B43_GTAB(0x00, 0)
#define B43_GTAB_TRFEMW B43_GTAB(0x0C, 0x120)
#define B43_GTAB_ORIGTR B43_GTAB(0x2E, 0x298)
u16 b43_gtab_read(struct b43_wldev *dev, u16 table, u16 offset); //TODO implement
void b43_gtab_write(struct b43_wldev *dev, u16 table, u16 offset, u16 value); //TODO implement
#define B43_DEFAULT_CHANNEL_A 36
#define B43_DEFAULT_CHANNEL_BG 6
enum {
B43_ANTENNA0, /* Antenna 0 */
B43_ANTENNA1, /* Antenna 0 */
B43_ANTENNA_AUTO1, /* Automatic, starting with antenna 1 */
B43_ANTENNA_AUTO0, /* Automatic, starting with antenna 0 */
B43_ANTENNA2,
B43_ANTENNA3 = 8,
B43_ANTENNA_AUTO = B43_ANTENNA_AUTO0,
B43_ANTENNA_DEFAULT = B43_ANTENNA_AUTO,
};
enum {
B43_INTERFMODE_NONE,
B43_INTERFMODE_NONWLAN,
B43_INTERFMODE_MANUALWLAN,
B43_INTERFMODE_AUTOWLAN,
};
/* Masks for the different PHY versioning registers. */
#define B43_PHYVER_ANALOG 0xF000
#define B43_PHYVER_ANALOG_SHIFT 12
#define B43_PHYVER_TYPE 0x0F00
#define B43_PHYVER_TYPE_SHIFT 8
#define B43_PHYVER_VERSION 0x00FF
void b43_phy_lock(struct b43_wldev *dev);
void b43_phy_unlock(struct b43_wldev *dev);
/* Read a value from a PHY register */
u16 b43_phy_read(struct b43_wldev *dev, u16 offset);
/* Write a value to a PHY register */
void b43_phy_write(struct b43_wldev *dev, u16 offset, u16 val);
/* Mask a PHY register with a mask */
void b43_phy_mask(struct b43_wldev *dev, u16 offset, u16 mask);
/* OR a PHY register with a bitmap */
void b43_phy_set(struct b43_wldev *dev, u16 offset, u16 set);
/* Mask and OR a PHY register with a mask and bitmap */
void b43_phy_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set);
int b43_phy_init_tssi2dbm_table(struct b43_wldev *dev);
void b43_phy_early_init(struct b43_wldev *dev);
int b43_phy_init(struct b43_wldev *dev);
void b43_set_rx_antenna(struct b43_wldev *dev, int antenna);
void b43_phy_xmitpower(struct b43_wldev *dev);
struct b43_phy_a {
bool initialised;
/* Returns the boolean whether the board has HardwarePowerControl */
bool b43_has_hardware_pctl(struct b43_phy *phy);
/* Returns the boolean whether "TX Magnification" is enabled. */
#define has_tx_magnification(phy) \
(((phy)->rev >= 2) && \
((phy)->radio_ver == 0x2050) && \
((phy)->radio_rev == 8))
/* Card uses the loopback gain stuff */
#define has_loopback_gain(phy) \
(((phy)->rev > 1) || ((phy)->gmode))
/* A-PHY TX Power control value. */
u16 txpwr_offset;
/* Radio Attenuation (RF Attenuation) */
struct b43_rfatt {
u8 att; /* Attenuation value */
bool with_padmix; /* Flag, PAD Mixer enabled. */
//TODO lots of missing stuff
};
struct b43_rfatt_list {
/* Attenuation values list */
const struct b43_rfatt *list;
u8 len;
/* Minimum/Maximum attenuation values */
u8 min_val;
u8 max_val;
};
/* Returns true, if the values are the same. */
static inline bool b43_compare_rfatt(const struct b43_rfatt *a,
const struct b43_rfatt *b)
{
return ((a->att == b->att) &&
(a->with_padmix == b->with_padmix));
}
/* Baseband Attenuation */
struct b43_bbatt {
u8 att; /* Attenuation value */
};
struct b43_bbatt_list {
/* Attenuation values list */
const struct b43_bbatt *list;
u8 len;
/* Minimum/Maximum attenuation values */
u8 min_val;
u8 max_val;
};
/* Returns true, if the values are the same. */
static inline bool b43_compare_bbatt(const struct b43_bbatt *a,
const struct b43_bbatt *b)
{
return (a->att == b->att);
}
/* tx_control bits. */
#define B43_TXCTL_PA3DB 0x40 /* PA Gain 3dB */
#define B43_TXCTL_PA2DB 0x20 /* PA Gain 2dB */
#define B43_TXCTL_TXMIX 0x10 /* TX Mixer Gain */
/* Write BasebandAttenuation value to the device. */
void b43_phy_set_baseband_attenuation(struct b43_wldev *dev,
u16 baseband_attenuation);
extern const u8 b43_radio_channel_codes_bg[];
void b43_radio_lock(struct b43_wldev *dev);
void b43_radio_unlock(struct b43_wldev *dev);
/* Read a value from a 16bit radio register */
u16 b43_radio_read16(struct b43_wldev *dev, u16 offset);
/* Write a value to a 16bit radio register */
void b43_radio_write16(struct b43_wldev *dev, u16 offset, u16 val);
/* Mask a 16bit radio register with a mask */
void b43_radio_mask(struct b43_wldev *dev, u16 offset, u16 mask);
/* OR a 16bit radio register with a bitmap */
void b43_radio_set(struct b43_wldev *dev, u16 offset, u16 set);
/* Mask and OR a PHY register with a mask and bitmap */
void b43_radio_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set);
u16 b43_radio_init2050(struct b43_wldev *dev);
void b43_radio_init2060(struct b43_wldev *dev);
void b43_radio_turn_on(struct b43_wldev *dev);
void b43_radio_turn_off(struct b43_wldev *dev, bool force);
int b43_radio_selectchannel(struct b43_wldev *dev, u8 channel,
int synthetic_pu_workaround);
u8 b43_radio_aci_detect(struct b43_wldev *dev, u8 channel);
u8 b43_radio_aci_scan(struct b43_wldev *dev);
int b43_radio_set_interference_mitigation(struct b43_wldev *dev, int mode);
void b43_calc_nrssi_slope(struct b43_wldev *dev);
void b43_calc_nrssi_threshold(struct b43_wldev *dev);
s16 b43_nrssi_hw_read(struct b43_wldev *dev, u16 offset);
void b43_nrssi_hw_write(struct b43_wldev *dev, u16 offset, s16 val);
void b43_nrssi_hw_update(struct b43_wldev *dev, u16 val);
void b43_nrssi_mem_update(struct b43_wldev *dev);
void b43_radio_set_tx_iq(struct b43_wldev *dev);
u16 b43_radio_calibrationvalue(struct b43_wldev *dev);
/**
* b43_phy_inita - Lowlevel A-PHY init routine.
* This is _only_ used by the G-PHY code.
*/
void b43_phy_inita(struct b43_wldev *dev);
void b43_put_attenuation_into_ranges(struct b43_wldev *dev,
int *_bbatt, int *_rfatt);
void b43_set_txpower_g(struct b43_wldev *dev,
const struct b43_bbatt *bbatt,
const struct b43_rfatt *rfatt, u8 tx_control);
struct b43_phy_operations;
extern const struct b43_phy_operations b43_phyops_a;
#endif /* B43_PHY_H_ */
#endif /* LINUX_B43_PHY_A_H_ */
/*
Broadcom B43 wireless driver
Common PHY routines
Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
Copyright (c) 2005-2007 Stefano Brivio <stefano.brivio@polimi.it>
Copyright (c) 2005-2008 Michael Buesch <mb@bu3sch.de>
Copyright (c) 2005, 2006 Danny van Dyk <kugelfang@gentoo.org>
Copyright (c) 2005, 2006 Andreas Jaggi <andreas.jaggi@waterwave.ch>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "phy_common.h"
#include "phy_g.h"
#include "phy_a.h"
#include "nphy.h"
#include "b43.h"
#include "main.h"
int b43_phy_operations_setup(struct b43_wldev *dev)
{
struct b43_phy *phy = &(dev->phy);
int err;
phy->ops = NULL;
switch (phy->type) {
case B43_PHYTYPE_A:
phy->ops = &b43_phyops_a;
break;
case B43_PHYTYPE_G:
phy->ops = &b43_phyops_g;
break;
case B43_PHYTYPE_N:
#ifdef CONFIG_B43_NPHY
phy->ops = &b43_phyops_n;
#endif
break;
case B43_PHYTYPE_LP:
/* FIXME: Not yet */
break;
}
if (B43_WARN_ON(!phy->ops))
return -ENODEV;
err = phy->ops->allocate(dev);
if (err)
phy->ops = NULL;
return err;
}
int b43_phy_init(struct b43_wldev *dev)
{
struct b43_phy *phy = &dev->phy;
const struct b43_phy_operations *ops = phy->ops;
int err;
phy->channel = ops->get_default_chan(dev);
ops->software_rfkill(dev, RFKILL_STATE_UNBLOCKED);
err = ops->init(dev);
if (err) {
b43err(dev->wl, "PHY init failed\n");
goto err_block_rf;
}
/* Make sure to switch hardware and firmware (SHM) to
* the default channel. */
err = b43_switch_channel(dev, ops->get_default_chan(dev));
if (err) {
b43err(dev->wl, "PHY init: Channel switch to default failed\n");
goto err_phy_exit;
}
return 0;
err_phy_exit:
if (ops->exit)
ops->exit(dev);
err_block_rf:
ops->software_rfkill(dev, RFKILL_STATE_SOFT_BLOCKED);
return err;
}
void b43_phy_exit(struct b43_wldev *dev)
{
const struct b43_phy_operations *ops = dev->phy.ops;
ops->software_rfkill(dev, RFKILL_STATE_SOFT_BLOCKED);
if (ops->exit)
ops->exit(dev);
}
bool b43_has_hardware_pctl(struct b43_wldev *dev)
{
if (!dev->phy.hardware_power_control)
return 0;
if (!dev->phy.ops->supports_hwpctl)
return 0;
return dev->phy.ops->supports_hwpctl(dev);
}
void b43_radio_lock(struct b43_wldev *dev)
{
u32 macctl;
macctl = b43_read32(dev, B43_MMIO_MACCTL);
B43_WARN_ON(macctl & B43_MACCTL_RADIOLOCK);
macctl |= B43_MACCTL_RADIOLOCK;
b43_write32(dev, B43_MMIO_MACCTL, macctl);
/* Commit the write and wait for the device
* to exit any radio register access. */
b43_read32(dev, B43_MMIO_MACCTL);
udelay(10);
}
void b43_radio_unlock(struct b43_wldev *dev)
{
u32 macctl;
/* Commit any write */
b43_read16(dev, B43_MMIO_PHY_VER);
/* unlock */
macctl = b43_read32(dev, B43_MMIO_MACCTL);
B43_WARN_ON(!(macctl & B43_MACCTL_RADIOLOCK));
macctl &= ~B43_MACCTL_RADIOLOCK;
b43_write32(dev, B43_MMIO_MACCTL, macctl);
}
void b43_phy_lock(struct b43_wldev *dev)
{
#if B43_DEBUG
B43_WARN_ON(dev->phy.phy_locked);
dev->phy.phy_locked = 1;
#endif
B43_WARN_ON(dev->dev->id.revision < 3);
if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP))
b43_power_saving_ctl_bits(dev, B43_PS_AWAKE);
}
void b43_phy_unlock(struct b43_wldev *dev)
{
#if B43_DEBUG
B43_WARN_ON(!dev->phy.phy_locked);
dev->phy.phy_locked = 0;
#endif
B43_WARN_ON(dev->dev->id.revision < 3);
if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP))
b43_power_saving_ctl_bits(dev, 0);
}
u16 b43_radio_read(struct b43_wldev *dev, u16 reg)
{
return dev->phy.ops->radio_read(dev, reg);
}
void b43_radio_write(struct b43_wldev *dev, u16 reg, u16 value)
{
dev->phy.ops->radio_write(dev, reg, value);
}
void b43_radio_mask(struct b43_wldev *dev, u16 offset, u16 mask)
{
b43_radio_write16(dev, offset,
b43_radio_read16(dev, offset) & mask);
}
void b43_radio_set(struct b43_wldev *dev, u16 offset, u16 set)
{
b43_radio_write16(dev, offset,
b43_radio_read16(dev, offset) | set);
}
void b43_radio_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set)
{
b43_radio_write16(dev, offset,
(b43_radio_read16(dev, offset) & mask) | set);
}
u16 b43_phy_read(struct b43_wldev *dev, u16 reg)
{
return dev->phy.ops->phy_read(dev, reg);
}
void b43_phy_write(struct b43_wldev *dev, u16 reg, u16 value)
{
dev->phy.ops->phy_write(dev, reg, value);
}
void b43_phy_mask(struct b43_wldev *dev, u16 offset, u16 mask)
{
b43_phy_write(dev, offset,
b43_phy_read(dev, offset) & mask);
}
void b43_phy_set(struct b43_wldev *dev, u16 offset, u16 set)
{
b43_phy_write(dev, offset,
b43_phy_read(dev, offset) | set);
}
void b43_phy_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set)
{
b43_phy_write(dev, offset,
(b43_phy_read(dev, offset) & mask) | set);
}
int b43_switch_channel(struct b43_wldev *dev, unsigned int new_channel)
{
struct b43_phy *phy = &(dev->phy);
u16 channelcookie, savedcookie;
int err;
if (new_channel == B43_DEFAULT_CHANNEL)
new_channel = phy->ops->get_default_chan(dev);
/* First we set the channel radio code to prevent the
* firmware from sending ghost packets.
*/
channelcookie = new_channel;
if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ)
channelcookie |= 0x100;
//FIXME set 40Mhz flag if required
savedcookie = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_CHAN);
b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_CHAN, channelcookie);
/* Now try to switch the PHY hardware channel. */
err = phy->ops->switch_channel(dev, new_channel);
if (err)
goto err_restore_cookie;
dev->phy.channel = new_channel;
/* Wait for the radio to tune to the channel and stabilize. */
msleep(8);
return 0;
err_restore_cookie:
b43_shm_write16(dev, B43_SHM_SHARED,
B43_SHM_SH_CHAN, savedcookie);
return err;
}
void b43_software_rfkill(struct b43_wldev *dev, enum rfkill_state state)
{
struct b43_phy *phy = &dev->phy;
if (state == RFKILL_STATE_HARD_BLOCKED) {
/* We cannot hardware-block the device */
state = RFKILL_STATE_SOFT_BLOCKED;
}
phy->ops->software_rfkill(dev, state);
phy->radio_on = (state == RFKILL_STATE_UNBLOCKED);
}
#ifndef LINUX_B43_PHY_COMMON_H_
#define LINUX_B43_PHY_COMMON_H_
#include <linux/rfkill.h>
struct b43_wldev;
/* PHY register routing bits */
#define B43_PHYROUTE 0x0C00 /* PHY register routing bits mask */
#define B43_PHYROUTE_BASE 0x0000 /* Base registers */
#define B43_PHYROUTE_OFDM_GPHY 0x0400 /* OFDM register routing for G-PHYs */
#define B43_PHYROUTE_EXT_GPHY 0x0800 /* Extended G-PHY registers */
#define B43_PHYROUTE_N_BMODE 0x0C00 /* N-PHY BMODE registers */
/* CCK (B-PHY) registers. */
#define B43_PHY_CCK(reg) ((reg) | B43_PHYROUTE_BASE)
/* N-PHY registers. */
#define B43_PHY_N(reg) ((reg) | B43_PHYROUTE_BASE)
/* N-PHY BMODE registers. */
#define B43_PHY_N_BMODE(reg) ((reg) | B43_PHYROUTE_N_BMODE)
/* OFDM (A-PHY) registers. */
#define B43_PHY_OFDM(reg) ((reg) | B43_PHYROUTE_OFDM_GPHY)
/* Extended G-PHY registers. */
#define B43_PHY_EXTG(reg) ((reg) | B43_PHYROUTE_EXT_GPHY)
/* Masks for the PHY versioning registers. */
#define B43_PHYVER_ANALOG 0xF000
#define B43_PHYVER_ANALOG_SHIFT 12
#define B43_PHYVER_TYPE 0x0F00
#define B43_PHYVER_TYPE_SHIFT 8
#define B43_PHYVER_VERSION 0x00FF
/**
* enum b43_interference_mitigation - Interference Mitigation mode
*
* @B43_INTERFMODE_NONE: Disabled
* @B43_INTERFMODE_NONWLAN: Non-WLAN Interference Mitigation
* @B43_INTERFMODE_MANUALWLAN: WLAN Interference Mitigation
* @B43_INTERFMODE_AUTOWLAN: Automatic WLAN Interference Mitigation
*/
enum b43_interference_mitigation {
B43_INTERFMODE_NONE,
B43_INTERFMODE_NONWLAN,
B43_INTERFMODE_MANUALWLAN,
B43_INTERFMODE_AUTOWLAN,
};
/* Antenna identifiers */
enum {
B43_ANTENNA0, /* Antenna 0 */
B43_ANTENNA1, /* Antenna 0 */
B43_ANTENNA_AUTO1, /* Automatic, starting with antenna 1 */
B43_ANTENNA_AUTO0, /* Automatic, starting with antenna 0 */
B43_ANTENNA2,
B43_ANTENNA3 = 8,
B43_ANTENNA_AUTO = B43_ANTENNA_AUTO0,
B43_ANTENNA_DEFAULT = B43_ANTENNA_AUTO,
};
/**
* struct b43_phy_operations - Function pointers for PHY ops.
*
* @prepare: Prepare the PHY. This is called before @init.
* Can be NULL, if not required.
* @init: Initialize the PHY.
* Must not be NULL.
* @exit: Shutdown the PHY and free all data structures.
* Can be NULL, if not required.
*
* @phy_read: Read from a PHY register.
* Must not be NULL.
* @phy_write: Write to a PHY register.
* Must not be NULL.
* @radio_read: Read from a Radio register.
* Must not be NULL.
* @radio_write: Write to a Radio register.
* Must not be NULL.
*
* @supports_hwpctl: Returns a boolean whether Hardware Power Control
* is supported or not.
* If NULL, hwpctl is assumed to be never supported.
* @software_rfkill: Turn the radio ON or OFF.
* Possible state values are
* RFKILL_STATE_SOFT_BLOCKED or
* RFKILL_STATE_UNBLOCKED
* Must not be NULL.
* @switch_channel: Switch the radio to another channel.
* Must not be NULL.
* @get_default_chan: Just returns the default channel number.
* Must not be NULL.
* @set_rx_antenna: Set the antenna used for RX.
* Can be NULL, if not supported.
* @interf_mitigation: Switch the Interference Mitigation mode.
* Can be NULL, if not supported.
*
* @xmitpower: FIXME REMOVEME
* Must not be NULL.
*
* @pwork_15sec: Periodic work. Called every 15 seconds.
* Can be NULL, if not required.
* @pwork_60sec: Periodic work. Called every 60 seconds.
* Can be NULL, if not required.
*/
struct b43_phy_operations {
/* Initialisation */
int (*allocate)(struct b43_wldev *dev);
int (*prepare)(struct b43_wldev *dev);
int (*init)(struct b43_wldev *dev);
void (*exit)(struct b43_wldev *dev);
/* Register access */
u16 (*phy_read)(struct b43_wldev *dev, u16 reg);
void (*phy_write)(struct b43_wldev *dev, u16 reg, u16 value);
u16 (*radio_read)(struct b43_wldev *dev, u16 reg);
void (*radio_write)(struct b43_wldev *dev, u16 reg, u16 value);
/* Radio */
bool (*supports_hwpctl)(struct b43_wldev *dev);
void (*software_rfkill)(struct b43_wldev *dev, enum rfkill_state state);
int (*switch_channel)(struct b43_wldev *dev, unsigned int new_channel);
unsigned int (*get_default_chan)(struct b43_wldev *dev);
void (*set_rx_antenna)(struct b43_wldev *dev, int antenna);
int (*interf_mitigation)(struct b43_wldev *dev,
enum b43_interference_mitigation new_mode);
/* Transmission power adjustment */
void (*xmitpower)(struct b43_wldev *dev);
/* Misc */
void (*pwork_15sec)(struct b43_wldev *dev);
void (*pwork_60sec)(struct b43_wldev *dev);
};
struct b43_phy_a;
struct b43_phy_g;
struct b43_phy_n;
struct b43_phy {
/* Hardware operation callbacks. */
const struct b43_phy_operations *ops;
/* Most hardware context information is stored in the standard-
* specific data structures pointed to by the pointers below.
* Only one of them is valid (the currently enabled PHY). */
#ifdef CONFIG_B43_DEBUG
/* No union for debug build to force NULL derefs in buggy code. */
struct {
#else
union {
#endif
/* A-PHY specific information */
struct b43_phy_a *a;
/* G-PHY specific information */
struct b43_phy_g *g;
/* N-PHY specific information */
struct b43_phy_n *n;
};
/* Band support flags. */
bool supports_2ghz;
bool supports_5ghz;
/* GMODE bit enabled? */
bool gmode;
/* Analog Type */
u8 analog;
/* B43_PHYTYPE_ */
u8 type;
/* PHY revision number. */
u8 rev;
/* Radio versioning */
u16 radio_manuf; /* Radio manufacturer */
u16 radio_ver; /* Radio version */
u8 radio_rev; /* Radio revision */
/* Software state of the radio */
bool radio_on;
/* Desired TX power level (in dBm).
* This is set by the user and adjusted in b43_phy_xmitpower(). */
u8 power_level;
/* Hardware Power Control enabled? */
bool hardware_power_control;
/* current channel */
unsigned int channel;
/* PHY TX errors counter. */
atomic_t txerr_cnt;
#ifdef CONFIG_B43_DEBUG
/* PHY registers locked by b43_phy_lock()? */
bool phy_locked;
#endif /* B43_DEBUG */
};
/**
* b43_phy_operations_setup - Initialize the PHY operations datastructure
* based on the current PHY type.
*/
int b43_phy_operations_setup(struct b43_wldev *dev);
/**
* b43_phy_init - Initialise the PHY
*/
int b43_phy_init(struct b43_wldev *dev);
/**
* b43_phy_exit - Cleanup PHY
*/
void b43_phy_exit(struct b43_wldev *dev);
/**
* b43_has_hardware_pctl - Hardware Power Control supported?
* Returns a boolean, whether hardware power control is supported.
*/
bool b43_has_hardware_pctl(struct b43_wldev *dev);
/**
* b43_phy_read - 16bit PHY register read access
*/
u16 b43_phy_read(struct b43_wldev *dev, u16 reg);
/**
* b43_phy_write - 16bit PHY register write access
*/
void b43_phy_write(struct b43_wldev *dev, u16 reg, u16 value);
/**
* b43_phy_mask - Mask a PHY register with a mask
*/
void b43_phy_mask(struct b43_wldev *dev, u16 offset, u16 mask);
/**
* b43_phy_set - OR a PHY register with a bitmap
*/
void b43_phy_set(struct b43_wldev *dev, u16 offset, u16 set);
/**
* b43_phy_maskset - Mask and OR a PHY register with a mask and bitmap
*/
void b43_phy_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set);
/**
* b43_radio_read - 16bit Radio register read access
*/
u16 b43_radio_read(struct b43_wldev *dev, u16 reg);
#define b43_radio_read16 b43_radio_read /* DEPRECATED */
/**
* b43_radio_write - 16bit Radio register write access
*/
void b43_radio_write(struct b43_wldev *dev, u16 reg, u16 value);
#define b43_radio_write16 b43_radio_write /* DEPRECATED */
/**
* b43_radio_mask - Mask a 16bit radio register with a mask
*/
void b43_radio_mask(struct b43_wldev *dev, u16 offset, u16 mask);
/**
* b43_radio_set - OR a 16bit radio register with a bitmap
*/
void b43_radio_set(struct b43_wldev *dev, u16 offset, u16 set);
/**
* b43_radio_maskset - Mask and OR a radio register with a mask and bitmap
*/
void b43_radio_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set);
/**
* b43_radio_lock - Lock firmware radio register access
*/
void b43_radio_lock(struct b43_wldev *dev);
/**
* b43_radio_unlock - Unlock firmware radio register access
*/
void b43_radio_unlock(struct b43_wldev *dev);
/**
* b43_phy_lock - Lock firmware PHY register access
*/
void b43_phy_lock(struct b43_wldev *dev);
/**
* b43_phy_unlock - Unlock firmware PHY register access
*/
void b43_phy_unlock(struct b43_wldev *dev);
/**
* b43_switch_channel - Switch to another channel
*/
int b43_switch_channel(struct b43_wldev *dev, unsigned int new_channel);
/**
* B43_DEFAULT_CHANNEL - Switch to the default channel.
*/
#define B43_DEFAULT_CHANNEL UINT_MAX
/**
* b43_software_rfkill - Turn the radio ON or OFF in software.
*/
void b43_software_rfkill(struct b43_wldev *dev, enum rfkill_state state);
#endif /* LINUX_B43_PHY_COMMON_H_ */
此差异已折叠。
#ifndef LINUX_B43_PHY_G_H_
#define LINUX_B43_PHY_G_H_
/* OFDM PHY registers are defined in the A-PHY header. */
#include "phy_a.h"
/* CCK (B) PHY Registers */
#define B43_PHY_VERSION_CCK B43_PHY_CCK(0x00) /* Versioning register for B-PHY */
#define B43_PHY_CCKBBANDCFG B43_PHY_CCK(0x01) /* Contains antenna 0/1 control bit */
#define B43_PHY_PGACTL B43_PHY_CCK(0x15) /* PGA control */
#define B43_PHY_PGACTL_LPF 0x1000 /* Low pass filter (?) */
#define B43_PHY_PGACTL_LOWBANDW 0x0040 /* Low bandwidth flag */
#define B43_PHY_PGACTL_UNKNOWN 0xEFA0
#define B43_PHY_FBCTL1 B43_PHY_CCK(0x18) /* Frequency bandwidth control 1 */
#define B43_PHY_ITSSI B43_PHY_CCK(0x29) /* Idle TSSI */
#define B43_PHY_LO_LEAKAGE B43_PHY_CCK(0x2D) /* Measured LO leakage */
#define B43_PHY_ENERGY B43_PHY_CCK(0x33) /* Energy */
#define B43_PHY_SYNCCTL B43_PHY_CCK(0x35)
#define B43_PHY_FBCTL2 B43_PHY_CCK(0x38) /* Frequency bandwidth control 2 */
#define B43_PHY_DACCTL B43_PHY_CCK(0x60) /* DAC control */
#define B43_PHY_RCCALOVER B43_PHY_CCK(0x78) /* RC calibration override */
/* Extended G-PHY Registers */
#define B43_PHY_CLASSCTL B43_PHY_EXTG(0x02) /* Classify control */
#define B43_PHY_GTABCTL B43_PHY_EXTG(0x03) /* G-PHY table control (see below) */
#define B43_PHY_GTABOFF 0x03FF /* G-PHY table offset (see below) */
#define B43_PHY_GTABNR 0xFC00 /* G-PHY table number (see below) */
#define B43_PHY_GTABNR_SHIFT 10
#define B43_PHY_GTABDATA B43_PHY_EXTG(0x04) /* G-PHY table data */
#define B43_PHY_LO_MASK B43_PHY_EXTG(0x0F) /* Local Oscillator control mask */
#define B43_PHY_LO_CTL B43_PHY_EXTG(0x10) /* Local Oscillator control */
#define B43_PHY_RFOVER B43_PHY_EXTG(0x11) /* RF override */
#define B43_PHY_RFOVERVAL B43_PHY_EXTG(0x12) /* RF override value */
#define B43_PHY_RFOVERVAL_EXTLNA 0x8000
#define B43_PHY_RFOVERVAL_LNA 0x7000
#define B43_PHY_RFOVERVAL_LNA_SHIFT 12
#define B43_PHY_RFOVERVAL_PGA 0x0F00
#define B43_PHY_RFOVERVAL_PGA_SHIFT 8
#define B43_PHY_RFOVERVAL_UNK 0x0010 /* Unknown, always set. */
#define B43_PHY_RFOVERVAL_TRSWRX 0x00E0
#define B43_PHY_RFOVERVAL_BW 0x0003 /* Bandwidth flags */
#define B43_PHY_RFOVERVAL_BW_LPF 0x0001 /* Low Pass Filter */
#define B43_PHY_RFOVERVAL_BW_LBW 0x0002 /* Low Bandwidth (when set), high when unset */
#define B43_PHY_ANALOGOVER B43_PHY_EXTG(0x14) /* Analog override */
#define B43_PHY_ANALOGOVERVAL B43_PHY_EXTG(0x15) /* Analog override value */
/*** G-PHY table numbers */
#define B43_GTAB(number, offset) (((number) << B43_PHY_GTABNR_SHIFT) | (offset))
#define B43_GTAB_NRSSI B43_GTAB(0x00, 0)
#define B43_GTAB_TRFEMW B43_GTAB(0x0C, 0x120)
#define B43_GTAB_ORIGTR B43_GTAB(0x2E, 0x298)
u16 b43_gtab_read(struct b43_wldev *dev, u16 table, u16 offset);
void b43_gtab_write(struct b43_wldev *dev, u16 table, u16 offset, u16 value);
/* Returns the boolean whether "TX Magnification" is enabled. */
#define has_tx_magnification(phy) \
(((phy)->rev >= 2) && \
((phy)->radio_ver == 0x2050) && \
((phy)->radio_rev == 8))
/* Card uses the loopback gain stuff */
#define has_loopback_gain(phy) \
(((phy)->rev > 1) || ((phy)->gmode))
/* Radio Attenuation (RF Attenuation) */
struct b43_rfatt {
u8 att; /* Attenuation value */
bool with_padmix; /* Flag, PAD Mixer enabled. */
};
struct b43_rfatt_list {
/* Attenuation values list */
const struct b43_rfatt *list;
u8 len;
/* Minimum/Maximum attenuation values */
u8 min_val;
u8 max_val;
};
/* Returns true, if the values are the same. */
static inline bool b43_compare_rfatt(const struct b43_rfatt *a,
const struct b43_rfatt *b)
{
return ((a->att == b->att) &&
(a->with_padmix == b->with_padmix));
}
/* Baseband Attenuation */
struct b43_bbatt {
u8 att; /* Attenuation value */
};
struct b43_bbatt_list {
/* Attenuation values list */
const struct b43_bbatt *list;
u8 len;
/* Minimum/Maximum attenuation values */
u8 min_val;
u8 max_val;
};
/* Returns true, if the values are the same. */
static inline bool b43_compare_bbatt(const struct b43_bbatt *a,
const struct b43_bbatt *b)
{
return (a->att == b->att);
}
/* tx_control bits. */
#define B43_TXCTL_PA3DB 0x40 /* PA Gain 3dB */
#define B43_TXCTL_PA2DB 0x20 /* PA Gain 2dB */
#define B43_TXCTL_TXMIX 0x10 /* TX Mixer Gain */
struct b43_txpower_lo_control;
struct b43_phy_g {
bool initialised;
bool dyn_tssi_tbl; /* tssi2dbm is kmalloc()ed. */
/* ACI (adjacent channel interference) flags. */
bool aci_enable;
bool aci_wlan_automatic;
bool aci_hw_rssi;
/* Radio switched on/off */
bool radio_on;
struct {
/* Values saved when turning the radio off.
* They are needed when turning it on again. */
bool valid;
u16 rfover;
u16 rfoverval;
} radio_off_context;
u16 minlowsig[2];
u16 minlowsigpos[2];
/* TSSI to dBm table in use */
const s8 *tssi2dbm;
/* Target idle TSSI */
int tgt_idle_tssi;
/* Current idle TSSI */
int cur_idle_tssi;
/* LocalOscillator control values. */
struct b43_txpower_lo_control *lo_control;
/* Values from b43_calc_loopback_gain() */
s16 max_lb_gain; /* Maximum Loopback gain in hdB */
s16 trsw_rx_gain; /* TRSW RX gain in hdB */
s16 lna_lod_gain; /* LNA lod */
s16 lna_gain; /* LNA */
s16 pga_gain; /* PGA */
/* Current TX power level attenuation control values */
struct b43_bbatt bbatt;
struct b43_rfatt rfatt;
u8 tx_control; /* B43_TXCTL_XXX */
/* Current Interference Mitigation mode */
int interfmode;
/* Stack of saved values from the Interference Mitigation code.
* Each value in the stack is layed out as follows:
* bit 0-11: offset
* bit 12-15: register ID
* bit 16-32: value
* register ID is: 0x1 PHY, 0x2 Radio, 0x3 ILT
*/
#define B43_INTERFSTACK_SIZE 26
u32 interfstack[B43_INTERFSTACK_SIZE]; //FIXME: use a data structure
/* Saved values from the NRSSI Slope calculation */
s16 nrssi[2];
s32 nrssislope;
/* In memory nrssi lookup table. */
s8 nrssi_lt[64];
u16 lofcal;
u16 initval; //FIXME rename?
/* The device does address auto increment for the OFDM tables.
* We cache the previously used address here and omit the address
* write on the next table access, if possible. */
u16 ofdmtab_addr; /* The address currently set in hardware. */
enum { /* The last data flow direction. */
B43_OFDMTAB_DIRECTION_UNKNOWN = 0,
B43_OFDMTAB_DIRECTION_READ,
B43_OFDMTAB_DIRECTION_WRITE,
} ofdmtab_addr_direction;
};
void b43_gphy_set_baseband_attenuation(struct b43_wldev *dev,
u16 baseband_attenuation);
void b43_gphy_channel_switch(struct b43_wldev *dev,
unsigned int channel,
bool synthetic_pu_workaround);
struct b43_phy_operations;
extern const struct b43_phy_operations b43_phyops_g;
#endif /* LINUX_B43_PHY_G_H_ */
......@@ -24,6 +24,7 @@
#include "rfkill.h"
#include "b43.h"
#include "phy_common.h"
#include <linux/kmod.h>
......@@ -114,11 +115,11 @@ static int b43_rfkill_soft_toggle(void *data, enum rfkill_state state)
goto out_unlock;
}
if (!dev->phy.radio_on)
b43_radio_turn_on(dev);
b43_software_rfkill(dev, state);
break;
case RFKILL_STATE_SOFT_BLOCKED:
if (dev->phy.radio_on)
b43_radio_turn_off(dev, 0);
b43_software_rfkill(dev, state);
break;
default:
b43warn(wl, "Received unexpected rfkill state %d.\n", state);
......
......@@ -29,7 +29,7 @@
#include "b43.h"
#include "sysfs.h"
#include "main.h"
#include "phy.h"
#include "phy_common.h"
#define GENERIC_FILESIZE 64
......@@ -59,7 +59,12 @@ static ssize_t b43_attr_interfmode_show(struct device *dev,
mutex_lock(&wldev->wl->mutex);
switch (wldev->phy.interfmode) {
if (wldev->phy.type != B43_PHYTYPE_G) {
mutex_unlock(&wldev->wl->mutex);
return -ENOSYS;
}
switch (wldev->phy.g->interfmode) {
case B43_INTERFMODE_NONE:
count =
snprintf(buf, PAGE_SIZE,
......@@ -117,11 +122,15 @@ static ssize_t b43_attr_interfmode_store(struct device *dev,
mutex_lock(&wldev->wl->mutex);
spin_lock_irqsave(&wldev->wl->irq_lock, flags);
err = b43_radio_set_interference_mitigation(wldev, mode);
if (err) {
b43err(wldev->wl, "Interference Mitigation not "
"supported by device\n");
}
if (wldev->phy.ops->interf_mitigation) {
err = wldev->phy.ops->interf_mitigation(wldev, mode);
if (err) {
b43err(wldev->wl, "Interference Mitigation not "
"supported by device\n");
}
} else
err = -ENOSYS;
mmiowb();
spin_unlock_irqrestore(&wldev->wl->irq_lock, flags);
mutex_unlock(&wldev->wl->mutex);
......
......@@ -27,7 +27,8 @@
#include "b43.h"
#include "tables.h"
#include "phy.h"
#include "phy_g.h"
const u32 b43_tab_rotor[] = {
0xFEB93FFD, 0xFEC63FFD, /* 0 */
......@@ -377,17 +378,17 @@ static inline void assert_sizes(void)
u16 b43_ofdmtab_read16(struct b43_wldev *dev, u16 table, u16 offset)
{
struct b43_phy *phy = &dev->phy;
struct b43_phy_g *gphy = dev->phy.g;
u16 addr;
addr = table + offset;
if ((phy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_READ) ||
(addr - 1 != phy->ofdmtab_addr)) {
if ((gphy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_READ) ||
(addr - 1 != gphy->ofdmtab_addr)) {
/* The hardware has a different address in memory. Update it. */
b43_phy_write(dev, B43_PHY_OTABLECTL, addr);
phy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_READ;
gphy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_READ;
}
phy->ofdmtab_addr = addr;
gphy->ofdmtab_addr = addr;
return b43_phy_read(dev, B43_PHY_OTABLEI);
......@@ -398,34 +399,34 @@ u16 b43_ofdmtab_read16(struct b43_wldev *dev, u16 table, u16 offset)
void b43_ofdmtab_write16(struct b43_wldev *dev, u16 table,
u16 offset, u16 value)
{
struct b43_phy *phy = &dev->phy;
struct b43_phy_g *gphy = dev->phy.g;
u16 addr;
addr = table + offset;
if ((phy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_WRITE) ||
(addr - 1 != phy->ofdmtab_addr)) {
if ((gphy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_WRITE) ||
(addr - 1 != gphy->ofdmtab_addr)) {
/* The hardware has a different address in memory. Update it. */
b43_phy_write(dev, B43_PHY_OTABLECTL, addr);
phy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_WRITE;
gphy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_WRITE;
}
phy->ofdmtab_addr = addr;
gphy->ofdmtab_addr = addr;
b43_phy_write(dev, B43_PHY_OTABLEI, value);
}
u32 b43_ofdmtab_read32(struct b43_wldev *dev, u16 table, u16 offset)
{
struct b43_phy *phy = &dev->phy;
struct b43_phy_g *gphy = dev->phy.g;
u32 ret;
u16 addr;
addr = table + offset;
if ((phy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_READ) ||
(addr - 1 != phy->ofdmtab_addr)) {
if ((gphy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_READ) ||
(addr - 1 != gphy->ofdmtab_addr)) {
/* The hardware has a different address in memory. Update it. */
b43_phy_write(dev, B43_PHY_OTABLECTL, addr);
phy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_READ;
gphy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_READ;
}
phy->ofdmtab_addr = addr;
gphy->ofdmtab_addr = addr;
ret = b43_phy_read(dev, B43_PHY_OTABLEQ);
ret <<= 16;
ret |= b43_phy_read(dev, B43_PHY_OTABLEI);
......@@ -436,17 +437,17 @@ u32 b43_ofdmtab_read32(struct b43_wldev *dev, u16 table, u16 offset)
void b43_ofdmtab_write32(struct b43_wldev *dev, u16 table,
u16 offset, u32 value)
{
struct b43_phy *phy = &dev->phy;
struct b43_phy_g *gphy = dev->phy.g;
u16 addr;
addr = table + offset;
if ((phy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_WRITE) ||
(addr - 1 != phy->ofdmtab_addr)) {
if ((gphy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_WRITE) ||
(addr - 1 != gphy->ofdmtab_addr)) {
/* The hardware has a different address in memory. Update it. */
b43_phy_write(dev, B43_PHY_OTABLECTL, addr);
phy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_WRITE;
gphy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_WRITE;
}
phy->ofdmtab_addr = addr;
gphy->ofdmtab_addr = addr;
b43_phy_write(dev, B43_PHY_OTABLEI, value);
b43_phy_write(dev, B43_PHY_OTABLEQ, (value >> 16));
......
......@@ -24,7 +24,7 @@
#include "b43.h"
#include "tables_nphy.h"
#include "phy.h"
#include "phy_common.h"
#include "nphy.h"
......
......@@ -27,7 +27,7 @@
#include "b43.h"
#include "main.h"
#include "tables.h"
#include "phy.h"
#include "phy_common.h"
#include "wa.h"
static void b43_wa_papd(struct b43_wldev *dev)
......
......@@ -28,7 +28,7 @@
*/
#include "xmit.h"
#include "phy.h"
#include "phy_common.h"
#include "dma.h"
#include "pio.h"
......@@ -431,6 +431,7 @@ static s8 b43_rssi_postprocess(struct b43_wldev *dev,
int adjust_2053, int adjust_2050)
{
struct b43_phy *phy = &dev->phy;
struct b43_phy_g *gphy = phy->g;
s32 tmp;
switch (phy->radio_ver) {
......@@ -450,7 +451,8 @@ static s8 b43_rssi_postprocess(struct b43_wldev *dev,
boardflags_lo & B43_BFL_RSSI) {
if (in_rssi > 63)
in_rssi = 63;
tmp = phy->nrssi_lt[in_rssi];
B43_WARN_ON(phy->type != B43_PHYTYPE_G);
tmp = gphy->nrssi_lt[in_rssi];
tmp = 31 - tmp;
tmp *= -131;
tmp /= 128;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册