📄 phy.c
字号:
/* Broadcom B43 wireless driver Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, Copyright (c) 2005, 2006 Stefano Brivio <st3@riseup.net> Copyright (c) 2005, 2006 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 <linux/delay.h>#include <linux/io.h>#include <linux/types.h>#include "b43.h"#include "phy.h"#include "main.h"#include "tables.h"#include "lo.h"static const s8 b43_tssi2dbm_b_table[] = { 0x4D, 0x4C, 0x4B, 0x4A, 0x4A, 0x49, 0x48, 0x47, 0x47, 0x46, 0x45, 0x45, 0x44, 0x43, 0x42, 0x42, 0x41, 0x40, 0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x32, 0x31, 0x30, 0x2F, 0x2D, 0x2C, 0x2B, 0x29, 0x28, 0x26, 0x25, 0x23, 0x21, 0x1F, 0x1D, 0x1A, 0x17, 0x14, 0x10, 0x0C, 0x06, 0x00, -7, -7, -7, -7, -7, -7, -7, -7, -7, -7, -7, -7,};static const s8 b43_tssi2dbm_g_table[] = { 77, 77, 77, 76, 76, 76, 75, 75, 74, 74, 73, 73, 73, 72, 72, 71, 71, 70, 70, 69, 68, 68, 67, 67, 66, 65, 65, 64, 63, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 50, 49, 47, 45, 43, 40, 37, 33, 28, 22, 14, 5, -7, -20, -20, -20, -20, -20, -20, -20, -20, -20, -20,};const u8 b43_radio_channel_codes_bg[] = { 12, 17, 22, 27, 32, 37, 42, 47, 52, 57, 62, 67, 72, 84,};static void b43_phy_initg(struct b43_wldev *dev);/* Reverse the bits of a 4bit value. * Example: 1101 is flipped 1011 */static u16 flip_4bit(u16 value){ u16 flipped = 0x0000; B43_WARN_ON(value & ~0x000F); flipped |= (value & 0x0001) << 3; flipped |= (value & 0x0002) << 1; flipped |= (value & 0x0004) >> 1; flipped |= (value & 0x0008) >> 3; return flipped;}static void generate_rfatt_list(struct b43_wldev *dev, struct b43_rfatt_list *list){ struct b43_phy *phy = &dev->phy; /* APHY.rev < 5 || GPHY.rev < 6 */ static const struct b43_rfatt rfatt_0[] = { {.att = 3,.with_padmix = 0,}, {.att = 1,.with_padmix = 0,}, {.att = 5,.with_padmix = 0,}, {.att = 7,.with_padmix = 0,}, {.att = 9,.with_padmix = 0,}, {.att = 2,.with_padmix = 0,}, {.att = 0,.with_padmix = 0,}, {.att = 4,.with_padmix = 0,}, {.att = 6,.with_padmix = 0,}, {.att = 8,.with_padmix = 0,}, {.att = 1,.with_padmix = 1,}, {.att = 2,.with_padmix = 1,}, {.att = 3,.with_padmix = 1,}, {.att = 4,.with_padmix = 1,}, }; /* Radio.rev == 8 && Radio.version == 0x2050 */ static const struct b43_rfatt rfatt_1[] = { {.att = 2,.with_padmix = 1,}, {.att = 4,.with_padmix = 1,}, {.att = 6,.with_padmix = 1,}, {.att = 8,.with_padmix = 1,}, {.att = 10,.with_padmix = 1,}, {.att = 12,.with_padmix = 1,}, {.att = 14,.with_padmix = 1,}, }; /* Otherwise */ static const struct b43_rfatt rfatt_2[] = { {.att = 0,.with_padmix = 1,}, {.att = 2,.with_padmix = 1,}, {.att = 4,.with_padmix = 1,}, {.att = 6,.with_padmix = 1,}, {.att = 8,.with_padmix = 1,}, {.att = 9,.with_padmix = 1,}, {.att = 9,.with_padmix = 1,}, }; if ((phy->type == B43_PHYTYPE_A && phy->rev < 5) || (phy->type == B43_PHYTYPE_G && phy->rev < 6)) { /* Software pctl */ list->list = rfatt_0; list->len = ARRAY_SIZE(rfatt_0); list->min_val = 0; list->max_val = 9; return; } if (phy->radio_ver == 0x2050 && phy->radio_rev == 8) { /* Hardware pctl */ list->list = rfatt_1; list->len = ARRAY_SIZE(rfatt_1); list->min_val = 2; list->max_val = 14; return; } /* Hardware pctl */ list->list = rfatt_2; list->len = ARRAY_SIZE(rfatt_2); list->min_val = 0; list->max_val = 9;}static void generate_bbatt_list(struct b43_wldev *dev, struct b43_bbatt_list *list){ static const struct b43_bbatt bbatt_0[] = { {.att = 0,}, {.att = 1,}, {.att = 2,}, {.att = 3,}, {.att = 4,}, {.att = 5,}, {.att = 6,}, {.att = 7,}, {.att = 8,}, }; list->list = bbatt_0; list->len = ARRAY_SIZE(bbatt_0); list->min_val = 0; list->max_val = 8;}bool b43_has_hardware_pctl(struct b43_phy *phy){ if (!phy->hardware_power_control) return 0; switch (phy->type) { case B43_PHYTYPE_A: if (phy->rev >= 5) return 1; break; case B43_PHYTYPE_G: if (phy->rev >= 6) return 1; break; default: B43_WARN_ON(1); } return 0;}static void b43_shm_clear_tssi(struct b43_wldev *dev){ struct b43_phy *phy = &dev->phy; switch (phy->type) { case B43_PHYTYPE_A: b43_shm_write16(dev, B43_SHM_SHARED, 0x0068, 0x7F7F); b43_shm_write16(dev, B43_SHM_SHARED, 0x006a, 0x7F7F); break; case B43_PHYTYPE_B: case B43_PHYTYPE_G: b43_shm_write16(dev, B43_SHM_SHARED, 0x0058, 0x7F7F); b43_shm_write16(dev, B43_SHM_SHARED, 0x005a, 0x7F7F); b43_shm_write16(dev, B43_SHM_SHARED, 0x0070, 0x7F7F); b43_shm_write16(dev, B43_SHM_SHARED, 0x0072, 0x7F7F); break; }}void b43_raw_phy_lock(struct b43_wldev *dev){ struct b43_phy *phy = &dev->phy; B43_WARN_ON(!irqs_disabled()); /* We had a check for MACCTL==0 here, but I think that doesn't * make sense, as MACCTL is never 0 when this is called. * --mb */ B43_WARN_ON(b43_read32(dev, B43_MMIO_MACCTL) == 0); if (dev->dev->id.revision < 3) { b43_mac_suspend(dev); spin_lock(&phy->lock); } else { if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) b43_power_saving_ctl_bits(dev, B43_PS_AWAKE); } phy->locked = 1;}void b43_raw_phy_unlock(struct b43_wldev *dev){ struct b43_phy *phy = &dev->phy; B43_WARN_ON(!irqs_disabled()); if (dev->dev->id.revision < 3) { if (phy->locked) { spin_unlock(&phy->lock); b43_mac_enable(dev); } } else { if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) b43_power_saving_ctl_bits(dev, 0); } phy->locked = 0;}/* Different PHYs require different register routing flags. * This adjusts (and does sanity checks on) the routing flags. */static inline u16 adjust_phyreg_for_phytype(struct b43_phy *phy, u16 offset, struct b43_wldev *dev){ if (phy->type == B43_PHYTYPE_A) { /* OFDM registers are base-registers for the A-PHY. */ offset &= ~B43_PHYROUTE_OFDM_GPHY; } if (offset & B43_PHYROUTE_EXT_GPHY) { /* Ext-G registers are only available on G-PHYs */ if (phy->type != B43_PHYTYPE_G) { b43dbg(dev->wl, "EXT-G PHY access at " "0x%04X on %u type PHY\n", offset, phy->type); } } return offset;}u16 b43_phy_read(struct b43_wldev * dev, u16 offset){ struct b43_phy *phy = &dev->phy; offset = adjust_phyreg_for_phytype(phy, offset, dev); b43_write16(dev, B43_MMIO_PHY_CONTROL, offset); return b43_read16(dev, B43_MMIO_PHY_DATA);}void b43_phy_write(struct b43_wldev *dev, u16 offset, u16 val){ struct b43_phy *phy = &dev->phy; offset = adjust_phyreg_for_phytype(phy, offset, dev); b43_write16(dev, B43_MMIO_PHY_CONTROL, offset); mmiowb(); b43_write16(dev, B43_MMIO_PHY_DATA, val);}static void b43_radio_set_txpower_a(struct b43_wldev *dev, u16 txpower);/* Adjust the transmission power output (G-PHY) */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 *phy = &dev->phy; struct b43_txpower_lo_control *lo = phy->lo_control; u16 bb, rf; u16 tx_bias, tx_magn; bb = bbatt->att; rf = rfatt->att; tx_bias = lo->tx_bias; tx_magn = lo->tx_magn; if (unlikely(tx_bias == 0xFF)) tx_bias = 0; /* Save the values for later */ phy->tx_control = tx_control; memcpy(&phy->rfatt, rfatt, sizeof(*rfatt)); memcpy(&phy->bbatt, bbatt, sizeof(*bbatt)); if (b43_debug(dev, B43_DBG_XMITPOWER)) { b43dbg(dev->wl, "Tuning TX-power to bbatt(%u), " "rfatt(%u), tx_control(0x%02X), " "tx_bias(0x%02X), tx_magn(0x%02X)\n", bb, rf, tx_control, tx_bias, tx_magn); } b43_phy_set_baseband_attenuation(dev, bb); b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_RFATT, rf); if (phy->radio_ver == 0x2050 && phy->radio_rev == 8) { b43_radio_write16(dev, 0x43, (rf & 0x000F) | (tx_control & 0x0070)); } else { b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43) & 0xFFF0) | (rf & 0x000F)); b43_radio_write16(dev, 0x52, (b43_radio_read16(dev, 0x52) & ~0x0070) | (tx_control & 0x0070)); } if (has_tx_magnification(phy)) { b43_radio_write16(dev, 0x52, tx_magn | tx_bias); } else { b43_radio_write16(dev, 0x52, (b43_radio_read16(dev, 0x52) & 0xFFF0) | (tx_bias & 0x000F)); } if (phy->type == B43_PHYTYPE_G) b43_lo_g_adjust(dev);}static void default_baseband_attenuation(struct b43_wldev *dev, struct b43_bbatt *bb){ struct b43_phy *phy = &dev->phy; if (phy->radio_ver == 0x2050 && phy->radio_rev < 6) bb->att = 0; else bb->att = 2;}static void default_radio_attenuation(struct b43_wldev *dev, struct b43_rfatt *rf){ struct ssb_bus *bus = dev->dev->bus; struct b43_phy *phy = &dev->phy; rf->with_padmix = 0; if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM && bus->boardinfo.type == SSB_BOARD_BCM4309G) { if (bus->boardinfo.rev < 0x43) { rf->att = 2; return; } else if (bus->boardinfo.rev < 0x51) { rf->att = 3; return; } } if (phy->type == B43_PHYTYPE_A) { rf->att = 0x60; return; } switch (phy->radio_ver) { case 0x2053: switch (phy->radio_rev) { case 1: rf->att = 6; return; } break; case 0x2050: switch (phy->radio_rev) { case 0: rf->att = 5; return; case 1: if (phy->type == B43_PHYTYPE_G) { if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM && bus->boardinfo.type == SSB_BOARD_BCM4309G && bus->boardinfo.rev >= 30) rf->att = 3; else if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM && bus->boardinfo.type == SSB_BOARD_BU4306) rf->att = 3; else rf->att = 1; } else { if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM && bus->boardinfo.type == SSB_BOARD_BCM4309G && bus->boardinfo.rev >= 30) rf->att = 7; else rf->att = 6; } return; case 2: if (phy->type == B43_PHYTYPE_G) { if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM && bus->boardinfo.type == SSB_BOARD_BCM4309G && bus->boardinfo.rev >= 30) rf->att = 3; else if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM && bus->boardinfo.type == SSB_BOARD_BU4306) rf->att = 5; else if (bus->chip_id == 0x4320) rf->att = 4; else rf->att = 3; } else rf->att = 6; return; case 3: rf->att = 5; return; case 4: case 5: rf->att = 1; return; case 6: case 7: rf->att = 5; return; case 8: rf->att = 0xA; rf->with_padmix = 1; return; case 9:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -