freebsd-dev/sys/dev/bwi/bwiphy.c
Pedro F. Giffuni 7282444b10 sys/dev: further adoption of SPDX licensing ID tags.
Mainly focus on files that use BSD 3-Clause license.

The Software Package Data Exchange (SPDX) group provides a specification
to make it easier for automated tools to detect and summarize well known
opensource licenses. We are gradually adopting the specification, noting
that the tags are considered only advisory and do not, in any way,
superceed or replace the license texts.

Special thanks to Wind River for providing access to "The Duke of
Highlander" tool: an older (2014) run over FreeBSD tree was useful as a
starting point.
2017-11-20 19:36:21 +00:00

1020 lines
26 KiB
C

/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2007 The DragonFly Project. All rights reserved.
*
* This code is derived from software contributed to The DragonFly Project
* by Sepherosa Ziehau <sepherosa@gmail.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name of The DragonFly Project nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific, prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $DragonFly: src/sys/dev/netif/bwi/bwiphy.c,v 1.5 2008/01/15 09:01:13 sephe Exp $
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "opt_inet.h"
#include "opt_wlan.h"
#include <sys/param.h>
#include <sys/endian.h>
#include <sys/kernel.h>
#include <sys/bus.h>
#include <sys/malloc.h>
#include <sys/proc.h>
#include <sys/rman.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include <sys/sysctl.h>
#include <sys/systm.h>
#include <net/if.h>
#include <net/if_var.h>
#include <net/if_dl.h>
#include <net/if_media.h>
#include <net/if_types.h>
#include <net/if_arp.h>
#include <net/ethernet.h>
#include <net/if_llc.h>
#include <net80211/ieee80211_var.h>
#include <net80211/ieee80211_radiotap.h>
#include <net80211/ieee80211_amrr.h>
#include <machine/bus.h>
#include <dev/bwi/bitops.h>
#include <dev/bwi/if_bwireg.h>
#include <dev/bwi/if_bwivar.h>
#include <dev/bwi/bwimac.h>
#include <dev/bwi/bwirf.h>
#include <dev/bwi/bwiphy.h>
static void bwi_phy_init_11a(struct bwi_mac *);
static void bwi_phy_init_11g(struct bwi_mac *);
static void bwi_phy_init_11b_rev2(struct bwi_mac *);
static void bwi_phy_init_11b_rev4(struct bwi_mac *);
static void bwi_phy_init_11b_rev5(struct bwi_mac *);
static void bwi_phy_init_11b_rev6(struct bwi_mac *);
static void bwi_phy_config_11g(struct bwi_mac *);
static void bwi_phy_config_agc(struct bwi_mac *);
static void bwi_tbl_write_2(struct bwi_mac *mac, uint16_t, uint16_t);
static void bwi_tbl_write_4(struct bwi_mac *mac, uint16_t, uint32_t);
#define SUP_BPHY(num) { .rev = num, .init = bwi_phy_init_11b_rev##num }
static const struct {
uint8_t rev;
void (*init)(struct bwi_mac *);
} bwi_sup_bphy[] = {
SUP_BPHY(2),
SUP_BPHY(4),
SUP_BPHY(5),
SUP_BPHY(6)
};
#undef SUP_BPHY
#define BWI_PHYTBL_WRSSI 0x1000
#define BWI_PHYTBL_NOISE_SCALE 0x1400
#define BWI_PHYTBL_NOISE 0x1800
#define BWI_PHYTBL_ROTOR 0x2000
#define BWI_PHYTBL_DELAY 0x2400
#define BWI_PHYTBL_RSSI 0x4000
#define BWI_PHYTBL_SIGMA_SQ 0x5000
#define BWI_PHYTBL_WRSSI_REV1 0x5400
#define BWI_PHYTBL_FREQ 0x5800
static const uint16_t bwi_phy_freq_11g_rev1[] =
{ BWI_PHY_FREQ_11G_REV1 };
static const uint16_t bwi_phy_noise_11g_rev1[] =
{ BWI_PHY_NOISE_11G_REV1 };
static const uint16_t bwi_phy_noise_11g[] =
{ BWI_PHY_NOISE_11G };
static const uint32_t bwi_phy_rotor_11g_rev1[] =
{ BWI_PHY_ROTOR_11G_REV1 };
static const uint16_t bwi_phy_noise_scale_11g_rev2[] =
{ BWI_PHY_NOISE_SCALE_11G_REV2 };
static const uint16_t bwi_phy_noise_scale_11g_rev7[] =
{ BWI_PHY_NOISE_SCALE_11G_REV7 };
static const uint16_t bwi_phy_noise_scale_11g[] =
{ BWI_PHY_NOISE_SCALE_11G };
static const uint16_t bwi_phy_sigma_sq_11g_rev2[] =
{ BWI_PHY_SIGMA_SQ_11G_REV2 };
static const uint16_t bwi_phy_sigma_sq_11g_rev7[] =
{ BWI_PHY_SIGMA_SQ_11G_REV7 };
static const uint32_t bwi_phy_delay_11g_rev1[] =
{ BWI_PHY_DELAY_11G_REV1 };
void
bwi_phy_write(struct bwi_mac *mac, uint16_t ctrl, uint16_t data)
{
struct bwi_softc *sc = mac->mac_sc;
CSR_WRITE_2(sc, BWI_PHY_CTRL, ctrl);
CSR_WRITE_2(sc, BWI_PHY_DATA, data);
}
uint16_t
bwi_phy_read(struct bwi_mac *mac, uint16_t ctrl)
{
struct bwi_softc *sc = mac->mac_sc;
CSR_WRITE_2(sc, BWI_PHY_CTRL, ctrl);
return CSR_READ_2(sc, BWI_PHY_DATA);
}
int
bwi_phy_attach(struct bwi_mac *mac)
{
struct bwi_softc *sc = mac->mac_sc;
struct bwi_phy *phy = &mac->mac_phy;
uint8_t phyrev, phytype, phyver;
uint16_t val;
int i;
/* Get PHY type/revision/version */
val = CSR_READ_2(sc, BWI_PHYINFO);
phyrev = __SHIFTOUT(val, BWI_PHYINFO_REV_MASK);
phytype = __SHIFTOUT(val, BWI_PHYINFO_TYPE_MASK);
phyver = __SHIFTOUT(val, BWI_PHYINFO_VER_MASK);
device_printf(sc->sc_dev, "PHY: type %d, rev %d, ver %d\n",
phytype, phyrev, phyver);
/*
* Verify whether the revision of the PHY type is supported
* Convert PHY type to ieee80211_phymode
*/
switch (phytype) {
case BWI_PHYINFO_TYPE_11A:
if (phyrev >= 4) {
device_printf(sc->sc_dev, "unsupported 11A PHY, "
"rev %u\n", phyrev);
return ENXIO;
}
phy->phy_init = bwi_phy_init_11a;
phy->phy_mode = IEEE80211_MODE_11A;
phy->phy_tbl_ctrl = BWI_PHYR_TBL_CTRL_11A;
phy->phy_tbl_data_lo = BWI_PHYR_TBL_DATA_LO_11A;
phy->phy_tbl_data_hi = BWI_PHYR_TBL_DATA_HI_11A;
break;
case BWI_PHYINFO_TYPE_11B:
for (i = 0; i < nitems(bwi_sup_bphy); ++i) {
if (phyrev == bwi_sup_bphy[i].rev) {
phy->phy_init = bwi_sup_bphy[i].init;
break;
}
}
if (i == nitems(bwi_sup_bphy)) {
device_printf(sc->sc_dev, "unsupported 11B PHY, "
"rev %u\n", phyrev);
return ENXIO;
}
phy->phy_mode = IEEE80211_MODE_11B;
break;
case BWI_PHYINFO_TYPE_11G:
if (phyrev > 8) {
device_printf(sc->sc_dev, "unsupported 11G PHY, "
"rev %u\n", phyrev);
return ENXIO;
}
phy->phy_init = bwi_phy_init_11g;
phy->phy_mode = IEEE80211_MODE_11G;
phy->phy_tbl_ctrl = BWI_PHYR_TBL_CTRL_11G;
phy->phy_tbl_data_lo = BWI_PHYR_TBL_DATA_LO_11G;
phy->phy_tbl_data_hi = BWI_PHYR_TBL_DATA_HI_11G;
break;
default:
device_printf(sc->sc_dev, "unsupported PHY type %d\n",
phytype);
return ENXIO;
}
phy->phy_rev = phyrev;
phy->phy_version = phyver;
return 0;
}
void
bwi_phy_set_bbp_atten(struct bwi_mac *mac, uint16_t bbp_atten)
{
struct bwi_phy *phy = &mac->mac_phy;
uint16_t mask = __BITS(3, 0);
if (phy->phy_version == 0) {
CSR_FILT_SETBITS_2(mac->mac_sc, BWI_BBP_ATTEN, ~mask,
__SHIFTIN(bbp_atten, mask));
} else {
if (phy->phy_version > 1)
mask <<= 2;
else
mask <<= 3;
PHY_FILT_SETBITS(mac, BWI_PHYR_BBP_ATTEN, ~mask,
__SHIFTIN(bbp_atten, mask));
}
}
int
bwi_phy_calibrate(struct bwi_mac *mac)
{
struct bwi_phy *phy = &mac->mac_phy;
/* Dummy read */
CSR_READ_4(mac->mac_sc, BWI_MAC_STATUS);
/* Don't re-init */
if (phy->phy_flags & BWI_PHY_F_CALIBRATED)
return 0;
if (phy->phy_mode == IEEE80211_MODE_11G && phy->phy_rev == 1) {
bwi_mac_reset(mac, 0);
bwi_phy_init_11g(mac);
bwi_mac_reset(mac, 1);
}
phy->phy_flags |= BWI_PHY_F_CALIBRATED;
return 0;
}
static void
bwi_tbl_write_2(struct bwi_mac *mac, uint16_t ofs, uint16_t data)
{
struct bwi_phy *phy = &mac->mac_phy;
KASSERT(phy->phy_tbl_ctrl != 0 && phy->phy_tbl_data_lo != 0,
("phy_tbl_ctrl %d phy_tbl_data_lo %d",
phy->phy_tbl_ctrl, phy->phy_tbl_data_lo));
PHY_WRITE(mac, phy->phy_tbl_ctrl, ofs);
PHY_WRITE(mac, phy->phy_tbl_data_lo, data);
}
static void
bwi_tbl_write_4(struct bwi_mac *mac, uint16_t ofs, uint32_t data)
{
struct bwi_phy *phy = &mac->mac_phy;
KASSERT(phy->phy_tbl_data_lo != 0 && phy->phy_tbl_data_hi != 0 &&
phy->phy_tbl_ctrl != 0,
("phy_tbl_data_lo %d phy_tbl_data_hi %d phy_tbl_ctrl %d",
phy->phy_tbl_data_lo, phy->phy_tbl_data_hi, phy->phy_tbl_ctrl));
PHY_WRITE(mac, phy->phy_tbl_ctrl, ofs);
PHY_WRITE(mac, phy->phy_tbl_data_hi, data >> 16);
PHY_WRITE(mac, phy->phy_tbl_data_lo, data & 0xffff);
}
void
bwi_nrssi_write(struct bwi_mac *mac, uint16_t ofs, int16_t data)
{
PHY_WRITE(mac, BWI_PHYR_NRSSI_CTRL, ofs);
PHY_WRITE(mac, BWI_PHYR_NRSSI_DATA, (uint16_t)data);
}
int16_t
bwi_nrssi_read(struct bwi_mac *mac, uint16_t ofs)
{
PHY_WRITE(mac, BWI_PHYR_NRSSI_CTRL, ofs);
return (int16_t)PHY_READ(mac, BWI_PHYR_NRSSI_DATA);
}
static void
bwi_phy_init_11a(struct bwi_mac *mac)
{
/* TODO:11A */
}
static void
bwi_phy_init_11g(struct bwi_mac *mac)
{
struct bwi_softc *sc = mac->mac_sc;
struct bwi_phy *phy = &mac->mac_phy;
struct bwi_rf *rf = &mac->mac_rf;
const struct bwi_tpctl *tpctl = &mac->mac_tpctl;
if (phy->phy_rev == 1)
bwi_phy_init_11b_rev5(mac);
else
bwi_phy_init_11b_rev6(mac);
if (phy->phy_rev >= 2 || (phy->phy_flags & BWI_PHY_F_LINKED))
bwi_phy_config_11g(mac);
if (phy->phy_rev >= 2) {
PHY_WRITE(mac, 0x814, 0);
PHY_WRITE(mac, 0x815, 0);
if (phy->phy_rev == 2) {
PHY_WRITE(mac, 0x811, 0);
PHY_WRITE(mac, 0x15, 0xc0);
} else if (phy->phy_rev > 5) {
PHY_WRITE(mac, 0x811, 0x400);
PHY_WRITE(mac, 0x15, 0xc0);
}
}
if (phy->phy_rev >= 2 || (phy->phy_flags & BWI_PHY_F_LINKED)) {
uint16_t val;
val = PHY_READ(mac, 0x400) & 0xff;
if (val == 3 || val == 5) {
PHY_WRITE(mac, 0x4c2, 0x1816);
PHY_WRITE(mac, 0x4c3, 0x8006);
if (val == 5) {
PHY_FILT_SETBITS(mac, 0x4cc,
0xff, 0x1f00);
}
}
}
if ((phy->phy_rev <= 2 && (phy->phy_flags & BWI_PHY_F_LINKED)) ||
phy->phy_rev >= 2)
PHY_WRITE(mac, 0x47e, 0x78);
if (rf->rf_rev == 8) {
PHY_SETBITS(mac, 0x801, 0x80);
PHY_SETBITS(mac, 0x43e, 0x4);
}
if (phy->phy_rev >= 2 && (phy->phy_flags & BWI_PHY_F_LINKED))
bwi_rf_get_gains(mac);
if (rf->rf_rev != 8)
bwi_rf_init(mac);
if (tpctl->tp_ctrl2 == 0xffff) {
bwi_rf_lo_update(mac);
} else {
if (rf->rf_type == BWI_RF_T_BCM2050 && rf->rf_rev == 8) {
RF_WRITE(mac, 0x52,
(tpctl->tp_ctrl1 << 4) | tpctl->tp_ctrl2);
} else {
RF_FILT_SETBITS(mac, 0x52, 0xfff0, tpctl->tp_ctrl2);
}
if (phy->phy_rev >= 6) {
PHY_FILT_SETBITS(mac, 0x36, 0xfff,
tpctl->tp_ctrl2 << 12);
}
if (sc->sc_card_flags & BWI_CARD_F_PA_GPIO9)
PHY_WRITE(mac, 0x2e, 0x8075);
else
PHY_WRITE(mac, 0x2e, 0x807f);
if (phy->phy_rev < 2)
PHY_WRITE(mac, 0x2f, 0x101);
else
PHY_WRITE(mac, 0x2f, 0x202);
}
if ((phy->phy_flags & BWI_PHY_F_LINKED) || phy->phy_rev >= 2) {
bwi_rf_lo_adjust(mac, tpctl);
PHY_WRITE(mac, 0x80f, 0x8078);
}
if ((sc->sc_card_flags & BWI_CARD_F_SW_NRSSI) == 0) {
bwi_rf_init_hw_nrssi_table(mac, 0xffff /* XXX */);
bwi_rf_set_nrssi_thr(mac);
} else if ((phy->phy_flags & BWI_PHY_F_LINKED) || phy->phy_rev >= 2) {
if (rf->rf_nrssi[0] == BWI_INVALID_NRSSI) {
KASSERT(rf->rf_nrssi[1] == BWI_INVALID_NRSSI,
("rf_nrssi[1] %d", rf->rf_nrssi[1]));
bwi_rf_calc_nrssi_slope(mac);
} else {
KASSERT(rf->rf_nrssi[1] != BWI_INVALID_NRSSI,
("rf_nrssi[1] %d", rf->rf_nrssi[1]));
bwi_rf_set_nrssi_thr(mac);
}
}
if (rf->rf_rev == 8)
PHY_WRITE(mac, 0x805, 0x3230);
bwi_mac_init_tpctl_11bg(mac);
if (sc->sc_bbp_id == BWI_BBPID_BCM4306 && sc->sc_bbp_pkg == 2) {
PHY_CLRBITS(mac, 0x429, 0x4000);
PHY_CLRBITS(mac, 0x4c3, 0x8000);
}
}
static void
bwi_phy_init_11b_rev2(struct bwi_mac *mac)
{
/* TODO:11B */
device_printf(mac->mac_sc->sc_dev,
"%s is not implemented yet\n", __func__);
}
static void
bwi_phy_init_11b_rev4(struct bwi_mac *mac)
{
struct bwi_softc *sc = mac->mac_sc;
struct bwi_rf *rf = &mac->mac_rf;
uint16_t val, ofs;
u_int chan;
CSR_WRITE_2(sc, BWI_BPHY_CTRL, BWI_BPHY_CTRL_INIT);
PHY_WRITE(mac, 0x20, 0x301c);
PHY_WRITE(mac, 0x26, 0);
PHY_WRITE(mac, 0x30, 0xc6);
PHY_WRITE(mac, 0x88, 0x3e00);
for (ofs = 0, val = 0x3c3d; ofs < 30; ++ofs, val -= 0x202)
PHY_WRITE(mac, 0x89 + ofs, val);
CSR_WRITE_2(sc, BWI_PHY_MAGIC_REG1, BWI_PHY_MAGIC_REG1_VAL1);
chan = rf->rf_curchan;
if (chan == IEEE80211_CHAN_ANY)
chan = 6; /* Force to channel 6 */
bwi_rf_set_chan(mac, chan, 0);
if (rf->rf_type != BWI_RF_T_BCM2050) {
RF_WRITE(mac, 0x75, 0x80);
RF_WRITE(mac, 0x79, 0x81);
}
RF_WRITE(mac, 0x50, 0x20);
RF_WRITE(mac, 0x50, 0x23);
if (rf->rf_type == BWI_RF_T_BCM2050) {
RF_WRITE(mac, 0x50, 0x20);
RF_WRITE(mac, 0x5a, 0x70);
RF_WRITE(mac, 0x5b, 0x7b);
RF_WRITE(mac, 0x5c, 0xb0);
RF_WRITE(mac, 0x7a, 0xf);
PHY_WRITE(mac, 0x38, 0x677);
bwi_rf_init_bcm2050(mac);
}
PHY_WRITE(mac, 0x14, 0x80);
PHY_WRITE(mac, 0x32, 0xca);
if (rf->rf_type == BWI_RF_T_BCM2050)
PHY_WRITE(mac, 0x32, 0xe0);
PHY_WRITE(mac, 0x35, 0x7c2);
bwi_rf_lo_update(mac);
PHY_WRITE(mac, 0x26, 0xcc00);
if (rf->rf_type == BWI_RF_T_BCM2050)
PHY_WRITE(mac, 0x26, 0xce00);
CSR_WRITE_2(sc, BWI_RF_CHAN_EX, 0x1100);
PHY_WRITE(mac, 0x2a, 0x88a3);
if (rf->rf_type == BWI_RF_T_BCM2050)
PHY_WRITE(mac, 0x2a, 0x88c2);
bwi_mac_set_tpctl_11bg(mac, NULL);
if (sc->sc_card_flags & BWI_CARD_F_SW_NRSSI) {
bwi_rf_calc_nrssi_slope(mac);
bwi_rf_set_nrssi_thr(mac);
}
bwi_mac_init_tpctl_11bg(mac);
}
static void
bwi_phy_init_11b_rev5(struct bwi_mac *mac)
{
struct bwi_softc *sc = mac->mac_sc;
struct bwi_rf *rf = &mac->mac_rf;
struct bwi_phy *phy = &mac->mac_phy;
u_int orig_chan;
if (phy->phy_version == 1)
RF_SETBITS(mac, 0x7a, 0x50);
if (sc->sc_pci_subvid != PCI_VENDOR_BROADCOM &&
sc->sc_pci_subdid != BWI_PCI_SUBDEVICE_BU4306) {
uint16_t ofs, val;
val = 0x2120;
for (ofs = 0xa8; ofs < 0xc7; ++ofs) {
PHY_WRITE(mac, ofs, val);
val += 0x202;
}
}
PHY_FILT_SETBITS(mac, 0x35, 0xf0ff, 0x700);
if (rf->rf_type == BWI_RF_T_BCM2050)
PHY_WRITE(mac, 0x38, 0x667);
if ((phy->phy_flags & BWI_PHY_F_LINKED) || phy->phy_rev >= 2) {
if (rf->rf_type == BWI_RF_T_BCM2050) {
RF_SETBITS(mac, 0x7a, 0x20);
RF_SETBITS(mac, 0x51, 0x4);
}
CSR_WRITE_2(sc, BWI_RF_ANTDIV, 0);
PHY_SETBITS(mac, 0x802, 0x100);
PHY_SETBITS(mac, 0x42b, 0x2000);
PHY_WRITE(mac, 0x1c, 0x186a);
PHY_FILT_SETBITS(mac, 0x13, 0xff, 0x1900);
PHY_FILT_SETBITS(mac, 0x35, 0xffc0, 0x64);
PHY_FILT_SETBITS(mac, 0x5d, 0xff80, 0xa);
}
/* TODO: bad_frame_preempt? */
if (phy->phy_version == 1) {
PHY_WRITE(mac, 0x26, 0xce00);
PHY_WRITE(mac, 0x21, 0x3763);
PHY_WRITE(mac, 0x22, 0x1bc3);
PHY_WRITE(mac, 0x23, 0x6f9);
PHY_WRITE(mac, 0x24, 0x37e);
} else {
PHY_WRITE(mac, 0x26, 0xcc00);
}
PHY_WRITE(mac, 0x30, 0xc6);
CSR_WRITE_2(sc, BWI_BPHY_CTRL, BWI_BPHY_CTRL_INIT);
if (phy->phy_version == 1)
PHY_WRITE(mac, 0x20, 0x3e1c);
else
PHY_WRITE(mac, 0x20, 0x301c);
if (phy->phy_version == 0)
CSR_WRITE_2(sc, BWI_PHY_MAGIC_REG1, BWI_PHY_MAGIC_REG1_VAL1);
/* Force to channel 7 */
orig_chan = rf->rf_curchan;
bwi_rf_set_chan(mac, 7, 0);
if (rf->rf_type != BWI_RF_T_BCM2050) {
RF_WRITE(mac, 0x75, 0x80);
RF_WRITE(mac, 0x79, 0x81);
}
RF_WRITE(mac, 0x50, 0x20);
RF_WRITE(mac, 0x50, 0x23);
if (rf->rf_type == BWI_RF_T_BCM2050) {
RF_WRITE(mac, 0x50, 0x20);
RF_WRITE(mac, 0x5a, 0x70);
}
RF_WRITE(mac, 0x5b, 0x7b);
RF_WRITE(mac, 0x5c, 0xb0);
RF_SETBITS(mac, 0x7a, 0x7);
bwi_rf_set_chan(mac, orig_chan, 0);
PHY_WRITE(mac, 0x14, 0x80);
PHY_WRITE(mac, 0x32, 0xca);
PHY_WRITE(mac, 0x2a, 0x88a3);
bwi_mac_set_tpctl_11bg(mac, NULL);
if (rf->rf_type == BWI_RF_T_BCM2050)
RF_WRITE(mac, 0x5d, 0xd);
CSR_FILT_SETBITS_2(sc, BWI_PHY_MAGIC_REG1, 0xffc0, 0x4);
}
static void
bwi_phy_init_11b_rev6(struct bwi_mac *mac)
{
struct bwi_softc *sc = mac->mac_sc;
struct bwi_rf *rf = &mac->mac_rf;
struct bwi_phy *phy = &mac->mac_phy;
uint16_t val, ofs;
u_int orig_chan;
PHY_WRITE(mac, 0x3e, 0x817a);
RF_SETBITS(mac, 0x7a, 0x58);
if (rf->rf_rev == 4 || rf->rf_rev == 5) {
RF_WRITE(mac, 0x51, 0x37);
RF_WRITE(mac, 0x52, 0x70);
RF_WRITE(mac, 0x53, 0xb3);
RF_WRITE(mac, 0x54, 0x9b);
RF_WRITE(mac, 0x5a, 0x88);
RF_WRITE(mac, 0x5b, 0x88);
RF_WRITE(mac, 0x5d, 0x88);
RF_WRITE(mac, 0x5e, 0x88);
RF_WRITE(mac, 0x7d, 0x88);
HFLAGS_SETBITS(mac, BWI_HFLAG_MAGIC1);
} else if (rf->rf_rev == 8) {
RF_WRITE(mac, 0x51, 0);
RF_WRITE(mac, 0x52, 0x40);
RF_WRITE(mac, 0x53, 0xb7);
RF_WRITE(mac, 0x54, 0x98);
RF_WRITE(mac, 0x5a, 0x88);
RF_WRITE(mac, 0x5b, 0x6b);
RF_WRITE(mac, 0x5c, 0xf);
if (sc->sc_card_flags & BWI_CARD_F_ALT_IQ) {
RF_WRITE(mac, 0x5d, 0xfa);
RF_WRITE(mac, 0x5e, 0xd8);
} else {
RF_WRITE(mac, 0x5d, 0xf5);
RF_WRITE(mac, 0x5e, 0xb8);
}
RF_WRITE(mac, 0x73, 0x3);
RF_WRITE(mac, 0x7d, 0xa8);
RF_WRITE(mac, 0x7c, 0x1);
RF_WRITE(mac, 0x7e, 0x8);
}
val = 0x1e1f;
for (ofs = 0x88; ofs < 0x98; ++ofs) {
PHY_WRITE(mac, ofs, val);
val -= 0x202;
}
val = 0x3e3f;
for (ofs = 0x98; ofs < 0xa8; ++ofs) {
PHY_WRITE(mac, ofs, val);
val -= 0x202;
}
val = 0x2120;
for (ofs = 0xa8; ofs < 0xc8; ++ofs) {
PHY_WRITE(mac, ofs, (val & 0x3f3f));
val += 0x202;
/* XXX: delay 10 us to avoid PCI parity errors with BCM4318 */
DELAY(10);
}
if (phy->phy_mode == IEEE80211_MODE_11G) {
RF_SETBITS(mac, 0x7a, 0x20);
RF_SETBITS(mac, 0x51, 0x4);
PHY_SETBITS(mac, 0x802, 0x100);
PHY_SETBITS(mac, 0x42b, 0x2000);
PHY_WRITE(mac, 0x5b, 0);
PHY_WRITE(mac, 0x5c, 0);
}
/* Force to channel 7 */
orig_chan = rf->rf_curchan;
if (orig_chan >= 8)
bwi_rf_set_chan(mac, 1, 0);
else
bwi_rf_set_chan(mac, 13, 0);
RF_WRITE(mac, 0x50, 0x20);
RF_WRITE(mac, 0x50, 0x23);
DELAY(40);
if (rf->rf_rev < 6 || rf->rf_rev == 8) {
RF_SETBITS(mac, 0x7c, 0x2);
RF_WRITE(mac, 0x50, 0x20);
}
if (rf->rf_rev <= 2) {
RF_WRITE(mac, 0x7c, 0x20);
RF_WRITE(mac, 0x5a, 0x70);
RF_WRITE(mac, 0x5b, 0x7b);
RF_WRITE(mac, 0x5c, 0xb0);
}
RF_FILT_SETBITS(mac, 0x7a, 0xf8, 0x7);
bwi_rf_set_chan(mac, orig_chan, 0);
PHY_WRITE(mac, 0x14, 0x200);
if (rf->rf_rev >= 6)
PHY_WRITE(mac, 0x2a, 0x88c2);
else
PHY_WRITE(mac, 0x2a, 0x8ac0);
PHY_WRITE(mac, 0x38, 0x668);
bwi_mac_set_tpctl_11bg(mac, NULL);
if (rf->rf_rev <= 5) {
PHY_FILT_SETBITS(mac, 0x5d, 0xff80, 0x3);
if (rf->rf_rev <= 2)
RF_WRITE(mac, 0x5d, 0xd);
}
if (phy->phy_version == 4) {
CSR_WRITE_2(sc, BWI_PHY_MAGIC_REG1, BWI_PHY_MAGIC_REG1_VAL2);
PHY_CLRBITS(mac, 0x61, 0xf000);
} else {
PHY_FILT_SETBITS(mac, 0x2, 0xffc0, 0x4);
}
if (phy->phy_mode == IEEE80211_MODE_11B) {
CSR_WRITE_2(sc, BWI_BBP_ATTEN, BWI_BBP_ATTEN_MAGIC2);
PHY_WRITE(mac, 0x16, 0x410);
PHY_WRITE(mac, 0x17, 0x820);
PHY_WRITE(mac, 0x62, 0x7);
bwi_rf_init_bcm2050(mac);
bwi_rf_lo_update(mac);
if (sc->sc_card_flags & BWI_CARD_F_SW_NRSSI) {
bwi_rf_calc_nrssi_slope(mac);
bwi_rf_set_nrssi_thr(mac);
}
bwi_mac_init_tpctl_11bg(mac);
} else {
CSR_WRITE_2(sc, BWI_BBP_ATTEN, 0);
}
}
static void
bwi_phy_config_11g(struct bwi_mac *mac)
{
struct bwi_softc *sc = mac->mac_sc;
struct bwi_phy *phy = &mac->mac_phy;
const uint16_t *tbl;
uint16_t wrd_ofs1, wrd_ofs2;
int i, n;
if (phy->phy_rev == 1) {
PHY_WRITE(mac, 0x406, 0x4f19);
PHY_FILT_SETBITS(mac, 0x429, 0xfc3f, 0x340);
PHY_WRITE(mac, 0x42c, 0x5a);
PHY_WRITE(mac, 0x427, 0x1a);
/* Fill frequency table */
for (i = 0; i < nitems(bwi_phy_freq_11g_rev1); ++i) {
bwi_tbl_write_2(mac, BWI_PHYTBL_FREQ + i,
bwi_phy_freq_11g_rev1[i]);
}
/* Fill noise table */
for (i = 0; i < nitems(bwi_phy_noise_11g_rev1); ++i) {
bwi_tbl_write_2(mac, BWI_PHYTBL_NOISE + i,
bwi_phy_noise_11g_rev1[i]);
}
/* Fill rotor table */
for (i = 0; i < nitems(bwi_phy_rotor_11g_rev1); ++i) {
/* NB: data length is 4 bytes */
bwi_tbl_write_4(mac, BWI_PHYTBL_ROTOR + i,
bwi_phy_rotor_11g_rev1[i]);
}
} else {
bwi_nrssi_write(mac, 0xba98, (int16_t)0x7654); /* XXX */
if (phy->phy_rev == 2) {
PHY_WRITE(mac, 0x4c0, 0x1861);
PHY_WRITE(mac, 0x4c1, 0x271);
} else if (phy->phy_rev > 2) {
PHY_WRITE(mac, 0x4c0, 0x98);
PHY_WRITE(mac, 0x4c1, 0x70);
PHY_WRITE(mac, 0x4c9, 0x80);
}
PHY_SETBITS(mac, 0x42b, 0x800);
/* Fill RSSI table */
for (i = 0; i < 64; ++i)
bwi_tbl_write_2(mac, BWI_PHYTBL_RSSI + i, i);
/* Fill noise table */
for (i = 0; i < nitems(bwi_phy_noise_11g); ++i) {
bwi_tbl_write_2(mac, BWI_PHYTBL_NOISE + i,
bwi_phy_noise_11g[i]);
}
}
/*
* Fill noise scale table
*/
if (phy->phy_rev <= 2) {
tbl = bwi_phy_noise_scale_11g_rev2;
n = nitems(bwi_phy_noise_scale_11g_rev2);
} else if (phy->phy_rev >= 7 && (PHY_READ(mac, 0x449) & 0x200)) {
tbl = bwi_phy_noise_scale_11g_rev7;
n = nitems(bwi_phy_noise_scale_11g_rev7);
} else {
tbl = bwi_phy_noise_scale_11g;
n = nitems(bwi_phy_noise_scale_11g);
}
for (i = 0; i < n; ++i)
bwi_tbl_write_2(mac, BWI_PHYTBL_NOISE_SCALE + i, tbl[i]);
/*
* Fill sigma square table
*/
if (phy->phy_rev == 2) {
tbl = bwi_phy_sigma_sq_11g_rev2;
n = nitems(bwi_phy_sigma_sq_11g_rev2);
} else if (phy->phy_rev > 2 && phy->phy_rev <= 8) {
tbl = bwi_phy_sigma_sq_11g_rev7;
n = nitems(bwi_phy_sigma_sq_11g_rev7);
} else {
tbl = NULL;
n = 0;
}
for (i = 0; i < n; ++i)
bwi_tbl_write_2(mac, BWI_PHYTBL_SIGMA_SQ + i, tbl[i]);
if (phy->phy_rev == 1) {
/* Fill delay table */
for (i = 0; i < nitems(bwi_phy_delay_11g_rev1); ++i) {
bwi_tbl_write_4(mac, BWI_PHYTBL_DELAY + i,
bwi_phy_delay_11g_rev1[i]);
}
/* Fill WRSSI (Wide-Band RSSI) table */
for (i = 4; i < 20; ++i)
bwi_tbl_write_2(mac, BWI_PHYTBL_WRSSI_REV1 + i, 0x20);
bwi_phy_config_agc(mac);
wrd_ofs1 = 0x5001;
wrd_ofs2 = 0x5002;
} else {
/* Fill WRSSI (Wide-Band RSSI) table */
for (i = 0; i < 0x20; ++i)
bwi_tbl_write_2(mac, BWI_PHYTBL_WRSSI + i, 0x820);
bwi_phy_config_agc(mac);
PHY_READ(mac, 0x400); /* Dummy read */
PHY_WRITE(mac, 0x403, 0x1000);
bwi_tbl_write_2(mac, 0x3c02, 0xf);
bwi_tbl_write_2(mac, 0x3c03, 0x14);
wrd_ofs1 = 0x401;
wrd_ofs2 = 0x402;
}
if (!(BWI_IS_BRCM_BU4306(sc) && sc->sc_pci_revid == 0x17)) {
bwi_tbl_write_2(mac, wrd_ofs1, 0x2);
bwi_tbl_write_2(mac, wrd_ofs2, 0x1);
}
/* phy->phy_flags & BWI_PHY_F_LINKED ? */
if (sc->sc_card_flags & BWI_CARD_F_PA_GPIO9)
PHY_WRITE(mac, 0x46e, 0x3cf);
}
/*
* Configure Automatic Gain Controller
*/
static void
bwi_phy_config_agc(struct bwi_mac *mac)
{
struct bwi_phy *phy = &mac->mac_phy;
uint16_t ofs;
ofs = phy->phy_rev == 1 ? 0x4c00 : 0;
bwi_tbl_write_2(mac, ofs, 0xfe);
bwi_tbl_write_2(mac, ofs + 1, 0xd);
bwi_tbl_write_2(mac, ofs + 2, 0x13);
bwi_tbl_write_2(mac, ofs + 3, 0x19);
if (phy->phy_rev == 1) {
bwi_tbl_write_2(mac, 0x1800, 0x2710);
bwi_tbl_write_2(mac, 0x1801, 0x9b83);
bwi_tbl_write_2(mac, 0x1802, 0x9b83);
bwi_tbl_write_2(mac, 0x1803, 0xf8d);
PHY_WRITE(mac, 0x455, 0x4);
}
PHY_FILT_SETBITS(mac, 0x4a5, 0xff, 0x5700);
PHY_FILT_SETBITS(mac, 0x41a, 0xff80, 0xf);
PHY_FILT_SETBITS(mac, 0x41a, 0xc07f, 0x2b80);
PHY_FILT_SETBITS(mac, 0x48c, 0xf0ff, 0x300);
RF_SETBITS(mac, 0x7a, 0x8);
PHY_FILT_SETBITS(mac, 0x4a0, 0xfff0, 0x8);
PHY_FILT_SETBITS(mac, 0x4a1, 0xf0ff, 0x600);
PHY_FILT_SETBITS(mac, 0x4a2, 0xf0ff, 0x700);
PHY_FILT_SETBITS(mac, 0x4a0, 0xf0ff, 0x100);
if (phy->phy_rev == 1)
PHY_FILT_SETBITS(mac, 0x4a2, 0xfff0, 0x7);
PHY_FILT_SETBITS(mac, 0x488, 0xff00, 0x1c);
PHY_FILT_SETBITS(mac, 0x488, 0xc0ff, 0x200);
PHY_FILT_SETBITS(mac, 0x496, 0xff00, 0x1c);
PHY_FILT_SETBITS(mac, 0x489, 0xff00, 0x20);
PHY_FILT_SETBITS(mac, 0x489, 0xc0ff, 0x200);
PHY_FILT_SETBITS(mac, 0x482, 0xff00, 0x2e);
PHY_FILT_SETBITS(mac, 0x496, 0xff, 0x1a00);
PHY_FILT_SETBITS(mac, 0x481, 0xff00, 0x28);
PHY_FILT_SETBITS(mac, 0x481, 0xff, 0x2c00);
if (phy->phy_rev == 1) {
PHY_WRITE(mac, 0x430, 0x92b);
PHY_FILT_SETBITS(mac, 0x41b, 0xffe1, 0x2);
} else {
PHY_CLRBITS(mac, 0x41b, 0x1e);
PHY_WRITE(mac, 0x41f, 0x287a);
PHY_FILT_SETBITS(mac, 0x420, 0xfff0, 0x4);
if (phy->phy_rev >= 6) {
PHY_WRITE(mac, 0x422, 0x287a);
PHY_FILT_SETBITS(mac, 0x420, 0xfff, 0x3000);
}
}
PHY_FILT_SETBITS(mac, 0x4a8, 0x8080, 0x7874);
PHY_WRITE(mac, 0x48e, 0x1c00);
if (phy->phy_rev == 1) {
PHY_FILT_SETBITS(mac, 0x4ab, 0xf0ff, 0x600);
PHY_WRITE(mac, 0x48b, 0x5e);
PHY_FILT_SETBITS(mac, 0x48c, 0xff00, 0x1e);
PHY_WRITE(mac, 0x48d, 0x2);
}
bwi_tbl_write_2(mac, ofs + 0x800, 0);
bwi_tbl_write_2(mac, ofs + 0x801, 7);
bwi_tbl_write_2(mac, ofs + 0x802, 16);
bwi_tbl_write_2(mac, ofs + 0x803, 28);
if (phy->phy_rev >= 6) {
PHY_CLRBITS(mac, 0x426, 0x3);
PHY_CLRBITS(mac, 0x426, 0x1000);
}
}
void
bwi_set_gains(struct bwi_mac *mac, const struct bwi_gains *gains)
{
struct bwi_phy *phy = &mac->mac_phy;
uint16_t tbl_gain_ofs1, tbl_gain_ofs2, tbl_gain;
int i;
if (phy->phy_rev <= 1) {
tbl_gain_ofs1 = 0x5000;
tbl_gain_ofs2 = tbl_gain_ofs1 + 16;
} else {
tbl_gain_ofs1 = 0x400;
tbl_gain_ofs2 = tbl_gain_ofs1 + 8;
}
for (i = 0; i < 4; ++i) {
if (gains != NULL) {
tbl_gain = gains->tbl_gain1;
} else {
/* Bit swap */
tbl_gain = (i & 0x1) << 1;
tbl_gain |= (i & 0x2) >> 1;
}
bwi_tbl_write_2(mac, tbl_gain_ofs1 + i, tbl_gain);
}
for (i = 0; i < 16; ++i) {
if (gains != NULL)
tbl_gain = gains->tbl_gain2;
else
tbl_gain = i;
bwi_tbl_write_2(mac, tbl_gain_ofs2 + i, tbl_gain);
}
if (gains == NULL || (gains != NULL && gains->phy_gain != -1)) {
uint16_t phy_gain1, phy_gain2;
if (gains != NULL) {
phy_gain1 =
((uint16_t)gains->phy_gain << 14) |
((uint16_t)gains->phy_gain << 6);
phy_gain2 = phy_gain1;
} else {
phy_gain1 = 0x4040;
phy_gain2 = 0x4000;
}
PHY_FILT_SETBITS(mac, 0x4a0, 0xbfbf, phy_gain1);
PHY_FILT_SETBITS(mac, 0x4a1, 0xbfbf, phy_gain1);
PHY_FILT_SETBITS(mac, 0x4a2, 0xbfbf, phy_gain2);
}
bwi_mac_dummy_xmit(mac);
}
void
bwi_phy_clear_state(struct bwi_phy *phy)
{
phy->phy_flags &= ~BWI_CLEAR_PHY_FLAGS;
}