xref: /freebsd/sys/dev/bwi/bwiphy.c (revision 685dc743dc3b5645e34836464128e1c0558b404b)
1*7282444bSPedro F. Giffuni /*-
2*7282444bSPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
3*7282444bSPedro F. Giffuni  *
412e36acbSWarner Losh  * Copyright (c) 2007 The DragonFly Project.  All rights reserved.
512e36acbSWarner Losh  *
612e36acbSWarner Losh  * This code is derived from software contributed to The DragonFly Project
712e36acbSWarner Losh  * by Sepherosa Ziehau <sepherosa@gmail.com>
812e36acbSWarner Losh  *
912e36acbSWarner Losh  * Redistribution and use in source and binary forms, with or without
1012e36acbSWarner Losh  * modification, are permitted provided that the following conditions
1112e36acbSWarner Losh  * are met:
1212e36acbSWarner Losh  *
1312e36acbSWarner Losh  * 1. Redistributions of source code must retain the above copyright
1412e36acbSWarner Losh  *    notice, this list of conditions and the following disclaimer.
1512e36acbSWarner Losh  * 2. Redistributions in binary form must reproduce the above copyright
1612e36acbSWarner Losh  *    notice, this list of conditions and the following disclaimer in
1712e36acbSWarner Losh  *    the documentation and/or other materials provided with the
1812e36acbSWarner Losh  *    distribution.
1912e36acbSWarner Losh  * 3. Neither the name of The DragonFly Project nor the names of its
2012e36acbSWarner Losh  *    contributors may be used to endorse or promote products derived
2112e36acbSWarner Losh  *    from this software without specific, prior written permission.
2212e36acbSWarner Losh  *
2312e36acbSWarner Losh  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2412e36acbSWarner Losh  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2512e36acbSWarner Losh  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
2612e36acbSWarner Losh  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
2712e36acbSWarner Losh  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
2812e36acbSWarner Losh  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
2912e36acbSWarner Losh  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
3012e36acbSWarner Losh  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
3112e36acbSWarner Losh  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
3212e36acbSWarner Losh  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
3312e36acbSWarner Losh  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3412e36acbSWarner Losh  * SUCH DAMAGE.
3512e36acbSWarner Losh  *
3612e36acbSWarner Losh  * $DragonFly: src/sys/dev/netif/bwi/bwiphy.c,v 1.5 2008/01/15 09:01:13 sephe Exp $
3712e36acbSWarner Losh  */
3812e36acbSWarner Losh 
3912e36acbSWarner Losh #include <sys/cdefs.h>
4012e36acbSWarner Losh #include "opt_inet.h"
4160807f5bSAdrian Chadd #include "opt_wlan.h"
4212e36acbSWarner Losh 
4312e36acbSWarner Losh #include <sys/param.h>
4412e36acbSWarner Losh #include <sys/endian.h>
4512e36acbSWarner Losh #include <sys/kernel.h>
4612e36acbSWarner Losh #include <sys/bus.h>
4712e36acbSWarner Losh #include <sys/malloc.h>
4812e36acbSWarner Losh #include <sys/proc.h>
4912e36acbSWarner Losh #include <sys/rman.h>
5012e36acbSWarner Losh #include <sys/socket.h>
5112e36acbSWarner Losh #include <sys/sockio.h>
5212e36acbSWarner Losh #include <sys/sysctl.h>
5312e36acbSWarner Losh #include <sys/systm.h>
5412e36acbSWarner Losh 
5512e36acbSWarner Losh #include <net/if.h>
5676039bc8SGleb Smirnoff #include <net/if_var.h>
5712e36acbSWarner Losh #include <net/if_dl.h>
5812e36acbSWarner Losh #include <net/if_media.h>
5912e36acbSWarner Losh #include <net/if_types.h>
6012e36acbSWarner Losh #include <net/if_arp.h>
6112e36acbSWarner Losh #include <net/ethernet.h>
6212e36acbSWarner Losh #include <net/if_llc.h>
6312e36acbSWarner Losh 
6412e36acbSWarner Losh #include <net80211/ieee80211_var.h>
6512e36acbSWarner Losh #include <net80211/ieee80211_radiotap.h>
6612e36acbSWarner Losh #include <net80211/ieee80211_amrr.h>
6712e36acbSWarner Losh 
6812e36acbSWarner Losh #include <machine/bus.h>
6912e36acbSWarner Losh 
7012e36acbSWarner Losh #include <dev/bwi/bitops.h>
7112e36acbSWarner Losh #include <dev/bwi/if_bwireg.h>
7212e36acbSWarner Losh #include <dev/bwi/if_bwivar.h>
7312e36acbSWarner Losh #include <dev/bwi/bwimac.h>
7412e36acbSWarner Losh #include <dev/bwi/bwirf.h>
7512e36acbSWarner Losh #include <dev/bwi/bwiphy.h>
7612e36acbSWarner Losh 
7712e36acbSWarner Losh static void	bwi_phy_init_11a(struct bwi_mac *);
7812e36acbSWarner Losh static void	bwi_phy_init_11g(struct bwi_mac *);
7912e36acbSWarner Losh static void	bwi_phy_init_11b_rev2(struct bwi_mac *);
8012e36acbSWarner Losh static void	bwi_phy_init_11b_rev4(struct bwi_mac *);
8112e36acbSWarner Losh static void	bwi_phy_init_11b_rev5(struct bwi_mac *);
8212e36acbSWarner Losh static void	bwi_phy_init_11b_rev6(struct bwi_mac *);
8312e36acbSWarner Losh 
8412e36acbSWarner Losh static void	bwi_phy_config_11g(struct bwi_mac *);
8512e36acbSWarner Losh static void	bwi_phy_config_agc(struct bwi_mac *);
8612e36acbSWarner Losh 
8712e36acbSWarner Losh static void	bwi_tbl_write_2(struct bwi_mac *mac, uint16_t, uint16_t);
8812e36acbSWarner Losh static void	bwi_tbl_write_4(struct bwi_mac *mac, uint16_t, uint32_t);
8912e36acbSWarner Losh #define SUP_BPHY(num)	{ .rev = num, .init = bwi_phy_init_11b_rev##num }
9012e36acbSWarner Losh 
9112e36acbSWarner Losh static const struct {
9212e36acbSWarner Losh 	uint8_t	rev;
9312e36acbSWarner Losh 	void	(*init)(struct bwi_mac *);
9412e36acbSWarner Losh } bwi_sup_bphy[] = {
9512e36acbSWarner Losh 	SUP_BPHY(2),
9612e36acbSWarner Losh 	SUP_BPHY(4),
9712e36acbSWarner Losh 	SUP_BPHY(5),
9812e36acbSWarner Losh 	SUP_BPHY(6)
9912e36acbSWarner Losh };
10012e36acbSWarner Losh 
10112e36acbSWarner Losh #undef SUP_BPHY
10212e36acbSWarner Losh 
10312e36acbSWarner Losh #define BWI_PHYTBL_WRSSI	0x1000
10412e36acbSWarner Losh #define BWI_PHYTBL_NOISE_SCALE	0x1400
10512e36acbSWarner Losh #define BWI_PHYTBL_NOISE	0x1800
10612e36acbSWarner Losh #define BWI_PHYTBL_ROTOR	0x2000
10712e36acbSWarner Losh #define BWI_PHYTBL_DELAY	0x2400
10812e36acbSWarner Losh #define BWI_PHYTBL_RSSI		0x4000
10912e36acbSWarner Losh #define BWI_PHYTBL_SIGMA_SQ	0x5000
11012e36acbSWarner Losh #define BWI_PHYTBL_WRSSI_REV1	0x5400
11112e36acbSWarner Losh #define BWI_PHYTBL_FREQ		0x5800
11212e36acbSWarner Losh 
11312e36acbSWarner Losh static const uint16_t	bwi_phy_freq_11g_rev1[] =
11412e36acbSWarner Losh 	{ BWI_PHY_FREQ_11G_REV1 };
11512e36acbSWarner Losh static const uint16_t	bwi_phy_noise_11g_rev1[] =
11612e36acbSWarner Losh 	{ BWI_PHY_NOISE_11G_REV1 };
11712e36acbSWarner Losh static const uint16_t	bwi_phy_noise_11g[] =
11812e36acbSWarner Losh 	{ BWI_PHY_NOISE_11G };
11912e36acbSWarner Losh static const uint32_t	bwi_phy_rotor_11g_rev1[] =
12012e36acbSWarner Losh 	{ BWI_PHY_ROTOR_11G_REV1 };
12112e36acbSWarner Losh static const uint16_t	bwi_phy_noise_scale_11g_rev2[] =
12212e36acbSWarner Losh 	{ BWI_PHY_NOISE_SCALE_11G_REV2 };
12312e36acbSWarner Losh static const uint16_t	bwi_phy_noise_scale_11g_rev7[] =
12412e36acbSWarner Losh 	{ BWI_PHY_NOISE_SCALE_11G_REV7 };
12512e36acbSWarner Losh static const uint16_t	bwi_phy_noise_scale_11g[] =
12612e36acbSWarner Losh 	{ BWI_PHY_NOISE_SCALE_11G };
12712e36acbSWarner Losh static const uint16_t	bwi_phy_sigma_sq_11g_rev2[] =
12812e36acbSWarner Losh 	{ BWI_PHY_SIGMA_SQ_11G_REV2 };
12912e36acbSWarner Losh static const uint16_t	bwi_phy_sigma_sq_11g_rev7[] =
13012e36acbSWarner Losh 	{ BWI_PHY_SIGMA_SQ_11G_REV7 };
13112e36acbSWarner Losh static const uint32_t	bwi_phy_delay_11g_rev1[] =
13212e36acbSWarner Losh 	{ BWI_PHY_DELAY_11G_REV1 };
13312e36acbSWarner Losh 
13412e36acbSWarner Losh void
bwi_phy_write(struct bwi_mac * mac,uint16_t ctrl,uint16_t data)13512e36acbSWarner Losh bwi_phy_write(struct bwi_mac *mac, uint16_t ctrl, uint16_t data)
13612e36acbSWarner Losh {
13712e36acbSWarner Losh 	struct bwi_softc *sc = mac->mac_sc;
13812e36acbSWarner Losh 
13912e36acbSWarner Losh 	CSR_WRITE_2(sc, BWI_PHY_CTRL, ctrl);
14012e36acbSWarner Losh 	CSR_WRITE_2(sc, BWI_PHY_DATA, data);
14112e36acbSWarner Losh }
14212e36acbSWarner Losh 
14312e36acbSWarner Losh uint16_t
bwi_phy_read(struct bwi_mac * mac,uint16_t ctrl)14412e36acbSWarner Losh bwi_phy_read(struct bwi_mac *mac, uint16_t ctrl)
14512e36acbSWarner Losh {
14612e36acbSWarner Losh 	struct bwi_softc *sc = mac->mac_sc;
14712e36acbSWarner Losh 
14812e36acbSWarner Losh 	CSR_WRITE_2(sc, BWI_PHY_CTRL, ctrl);
14912e36acbSWarner Losh 	return CSR_READ_2(sc, BWI_PHY_DATA);
15012e36acbSWarner Losh }
15112e36acbSWarner Losh 
15212e36acbSWarner Losh int
bwi_phy_attach(struct bwi_mac * mac)15312e36acbSWarner Losh bwi_phy_attach(struct bwi_mac *mac)
15412e36acbSWarner Losh {
15512e36acbSWarner Losh 	struct bwi_softc *sc = mac->mac_sc;
15612e36acbSWarner Losh 	struct bwi_phy *phy = &mac->mac_phy;
15712e36acbSWarner Losh 	uint8_t phyrev, phytype, phyver;
15812e36acbSWarner Losh 	uint16_t val;
15912e36acbSWarner Losh 	int i;
16012e36acbSWarner Losh 
16112e36acbSWarner Losh 	/* Get PHY type/revision/version */
16212e36acbSWarner Losh 	val = CSR_READ_2(sc, BWI_PHYINFO);
16312e36acbSWarner Losh 	phyrev = __SHIFTOUT(val, BWI_PHYINFO_REV_MASK);
16412e36acbSWarner Losh 	phytype = __SHIFTOUT(val, BWI_PHYINFO_TYPE_MASK);
16512e36acbSWarner Losh 	phyver = __SHIFTOUT(val, BWI_PHYINFO_VER_MASK);
16612e36acbSWarner Losh 	device_printf(sc->sc_dev, "PHY: type %d, rev %d, ver %d\n",
16712e36acbSWarner Losh 		      phytype, phyrev, phyver);
16812e36acbSWarner Losh 
16912e36acbSWarner Losh 	/*
17012e36acbSWarner Losh 	 * Verify whether the revision of the PHY type is supported
17112e36acbSWarner Losh 	 * Convert PHY type to ieee80211_phymode
17212e36acbSWarner Losh 	 */
17312e36acbSWarner Losh 	switch (phytype) {
17412e36acbSWarner Losh 	case BWI_PHYINFO_TYPE_11A:
17512e36acbSWarner Losh 		if (phyrev >= 4) {
17612e36acbSWarner Losh 			device_printf(sc->sc_dev, "unsupported 11A PHY, "
17712e36acbSWarner Losh 				      "rev %u\n", phyrev);
17812e36acbSWarner Losh 			return ENXIO;
17912e36acbSWarner Losh 		}
18012e36acbSWarner Losh 		phy->phy_init = bwi_phy_init_11a;
18112e36acbSWarner Losh 		phy->phy_mode = IEEE80211_MODE_11A;
18212e36acbSWarner Losh 		phy->phy_tbl_ctrl = BWI_PHYR_TBL_CTRL_11A;
18312e36acbSWarner Losh 		phy->phy_tbl_data_lo = BWI_PHYR_TBL_DATA_LO_11A;
18412e36acbSWarner Losh 		phy->phy_tbl_data_hi = BWI_PHYR_TBL_DATA_HI_11A;
18512e36acbSWarner Losh 		break;
18612e36acbSWarner Losh 	case BWI_PHYINFO_TYPE_11B:
187d6166defSAdrian Chadd 		for (i = 0; i < nitems(bwi_sup_bphy); ++i) {
18812e36acbSWarner Losh 			if (phyrev == bwi_sup_bphy[i].rev) {
18912e36acbSWarner Losh 				phy->phy_init = bwi_sup_bphy[i].init;
19012e36acbSWarner Losh 				break;
19112e36acbSWarner Losh 			}
19212e36acbSWarner Losh 		}
193d6166defSAdrian Chadd 		if (i == nitems(bwi_sup_bphy)) {
19412e36acbSWarner Losh 			device_printf(sc->sc_dev, "unsupported 11B PHY, "
19512e36acbSWarner Losh 				      "rev %u\n", phyrev);
19612e36acbSWarner Losh 			return ENXIO;
19712e36acbSWarner Losh 		}
19812e36acbSWarner Losh 		phy->phy_mode = IEEE80211_MODE_11B;
19912e36acbSWarner Losh 		break;
20012e36acbSWarner Losh 	case BWI_PHYINFO_TYPE_11G:
20112e36acbSWarner Losh 		if (phyrev > 8) {
20212e36acbSWarner Losh 			device_printf(sc->sc_dev, "unsupported 11G PHY, "
20312e36acbSWarner Losh 				      "rev %u\n", phyrev);
20412e36acbSWarner Losh 			return ENXIO;
20512e36acbSWarner Losh 		}
20612e36acbSWarner Losh 		phy->phy_init = bwi_phy_init_11g;
20712e36acbSWarner Losh 		phy->phy_mode = IEEE80211_MODE_11G;
20812e36acbSWarner Losh 		phy->phy_tbl_ctrl = BWI_PHYR_TBL_CTRL_11G;
20912e36acbSWarner Losh 		phy->phy_tbl_data_lo = BWI_PHYR_TBL_DATA_LO_11G;
21012e36acbSWarner Losh 		phy->phy_tbl_data_hi = BWI_PHYR_TBL_DATA_HI_11G;
21112e36acbSWarner Losh 		break;
21212e36acbSWarner Losh 	default:
21312e36acbSWarner Losh 		device_printf(sc->sc_dev, "unsupported PHY type %d\n",
21412e36acbSWarner Losh 			      phytype);
21512e36acbSWarner Losh 		return ENXIO;
21612e36acbSWarner Losh 	}
21712e36acbSWarner Losh 	phy->phy_rev = phyrev;
21812e36acbSWarner Losh 	phy->phy_version = phyver;
21912e36acbSWarner Losh 	return 0;
22012e36acbSWarner Losh }
22112e36acbSWarner Losh 
22212e36acbSWarner Losh void
bwi_phy_set_bbp_atten(struct bwi_mac * mac,uint16_t bbp_atten)22312e36acbSWarner Losh bwi_phy_set_bbp_atten(struct bwi_mac *mac, uint16_t bbp_atten)
22412e36acbSWarner Losh {
22512e36acbSWarner Losh 	struct bwi_phy *phy = &mac->mac_phy;
22612e36acbSWarner Losh 	uint16_t mask = __BITS(3, 0);
22712e36acbSWarner Losh 
22812e36acbSWarner Losh 	if (phy->phy_version == 0) {
22912e36acbSWarner Losh 		CSR_FILT_SETBITS_2(mac->mac_sc, BWI_BBP_ATTEN, ~mask,
23012e36acbSWarner Losh 				   __SHIFTIN(bbp_atten, mask));
23112e36acbSWarner Losh 	} else {
23212e36acbSWarner Losh 		if (phy->phy_version > 1)
23312e36acbSWarner Losh 			mask <<= 2;
23412e36acbSWarner Losh 		else
23512e36acbSWarner Losh 			mask <<= 3;
23612e36acbSWarner Losh 		PHY_FILT_SETBITS(mac, BWI_PHYR_BBP_ATTEN, ~mask,
23712e36acbSWarner Losh 				 __SHIFTIN(bbp_atten, mask));
23812e36acbSWarner Losh 	}
23912e36acbSWarner Losh }
24012e36acbSWarner Losh 
24112e36acbSWarner Losh int
bwi_phy_calibrate(struct bwi_mac * mac)24212e36acbSWarner Losh bwi_phy_calibrate(struct bwi_mac *mac)
24312e36acbSWarner Losh {
24412e36acbSWarner Losh 	struct bwi_phy *phy = &mac->mac_phy;
24512e36acbSWarner Losh 
24612e36acbSWarner Losh 	/* Dummy read */
24712e36acbSWarner Losh 	CSR_READ_4(mac->mac_sc, BWI_MAC_STATUS);
24812e36acbSWarner Losh 
24912e36acbSWarner Losh 	/* Don't re-init */
25012e36acbSWarner Losh 	if (phy->phy_flags & BWI_PHY_F_CALIBRATED)
25112e36acbSWarner Losh 		return 0;
25212e36acbSWarner Losh 
25312e36acbSWarner Losh 	if (phy->phy_mode == IEEE80211_MODE_11G && phy->phy_rev == 1) {
25412e36acbSWarner Losh 		bwi_mac_reset(mac, 0);
25512e36acbSWarner Losh 		bwi_phy_init_11g(mac);
25612e36acbSWarner Losh 		bwi_mac_reset(mac, 1);
25712e36acbSWarner Losh 	}
25812e36acbSWarner Losh 
25912e36acbSWarner Losh 	phy->phy_flags |= BWI_PHY_F_CALIBRATED;
26012e36acbSWarner Losh 	return 0;
26112e36acbSWarner Losh }
26212e36acbSWarner Losh 
26312e36acbSWarner Losh static void
bwi_tbl_write_2(struct bwi_mac * mac,uint16_t ofs,uint16_t data)26412e36acbSWarner Losh bwi_tbl_write_2(struct bwi_mac *mac, uint16_t ofs, uint16_t data)
26512e36acbSWarner Losh {
26612e36acbSWarner Losh 	struct bwi_phy *phy = &mac->mac_phy;
26712e36acbSWarner Losh 
26812e36acbSWarner Losh 	KASSERT(phy->phy_tbl_ctrl != 0 && phy->phy_tbl_data_lo != 0,
26912e36acbSWarner Losh 	   ("phy_tbl_ctrl %d phy_tbl_data_lo %d",
27012e36acbSWarner Losh 	     phy->phy_tbl_ctrl, phy->phy_tbl_data_lo));
27112e36acbSWarner Losh 	PHY_WRITE(mac, phy->phy_tbl_ctrl, ofs);
27212e36acbSWarner Losh 	PHY_WRITE(mac, phy->phy_tbl_data_lo, data);
27312e36acbSWarner Losh }
27412e36acbSWarner Losh 
27512e36acbSWarner Losh static void
bwi_tbl_write_4(struct bwi_mac * mac,uint16_t ofs,uint32_t data)27612e36acbSWarner Losh bwi_tbl_write_4(struct bwi_mac *mac, uint16_t ofs, uint32_t data)
27712e36acbSWarner Losh {
27812e36acbSWarner Losh 	struct bwi_phy *phy = &mac->mac_phy;
27912e36acbSWarner Losh 
28012e36acbSWarner Losh 	KASSERT(phy->phy_tbl_data_lo != 0 && phy->phy_tbl_data_hi != 0 &&
28112e36acbSWarner Losh 		 phy->phy_tbl_ctrl != 0,
28212e36acbSWarner Losh 	    ("phy_tbl_data_lo %d phy_tbl_data_hi %d phy_tbl_ctrl %d",
28312e36acbSWarner Losh 	      phy->phy_tbl_data_lo, phy->phy_tbl_data_hi, phy->phy_tbl_ctrl));
28412e36acbSWarner Losh 
28512e36acbSWarner Losh 	PHY_WRITE(mac, phy->phy_tbl_ctrl, ofs);
28612e36acbSWarner Losh 	PHY_WRITE(mac, phy->phy_tbl_data_hi, data >> 16);
28712e36acbSWarner Losh 	PHY_WRITE(mac, phy->phy_tbl_data_lo, data & 0xffff);
28812e36acbSWarner Losh }
28912e36acbSWarner Losh 
29012e36acbSWarner Losh void
bwi_nrssi_write(struct bwi_mac * mac,uint16_t ofs,int16_t data)29112e36acbSWarner Losh bwi_nrssi_write(struct bwi_mac *mac, uint16_t ofs, int16_t data)
29212e36acbSWarner Losh {
29312e36acbSWarner Losh 	PHY_WRITE(mac, BWI_PHYR_NRSSI_CTRL, ofs);
29412e36acbSWarner Losh 	PHY_WRITE(mac, BWI_PHYR_NRSSI_DATA, (uint16_t)data);
29512e36acbSWarner Losh }
29612e36acbSWarner Losh 
29712e36acbSWarner Losh int16_t
bwi_nrssi_read(struct bwi_mac * mac,uint16_t ofs)29812e36acbSWarner Losh bwi_nrssi_read(struct bwi_mac *mac, uint16_t ofs)
29912e36acbSWarner Losh {
30012e36acbSWarner Losh 	PHY_WRITE(mac, BWI_PHYR_NRSSI_CTRL, ofs);
30112e36acbSWarner Losh 	return (int16_t)PHY_READ(mac, BWI_PHYR_NRSSI_DATA);
30212e36acbSWarner Losh }
30312e36acbSWarner Losh 
30412e36acbSWarner Losh static void
bwi_phy_init_11a(struct bwi_mac * mac)30512e36acbSWarner Losh bwi_phy_init_11a(struct bwi_mac *mac)
30612e36acbSWarner Losh {
30712e36acbSWarner Losh 	/* TODO:11A */
30812e36acbSWarner Losh }
30912e36acbSWarner Losh 
31012e36acbSWarner Losh static void
bwi_phy_init_11g(struct bwi_mac * mac)31112e36acbSWarner Losh bwi_phy_init_11g(struct bwi_mac *mac)
31212e36acbSWarner Losh {
31312e36acbSWarner Losh 	struct bwi_softc *sc = mac->mac_sc;
31412e36acbSWarner Losh 	struct bwi_phy *phy = &mac->mac_phy;
31512e36acbSWarner Losh 	struct bwi_rf *rf = &mac->mac_rf;
31612e36acbSWarner Losh 	const struct bwi_tpctl *tpctl = &mac->mac_tpctl;
31712e36acbSWarner Losh 
31812e36acbSWarner Losh 	if (phy->phy_rev == 1)
31912e36acbSWarner Losh 		bwi_phy_init_11b_rev5(mac);
32012e36acbSWarner Losh 	else
32112e36acbSWarner Losh 		bwi_phy_init_11b_rev6(mac);
32212e36acbSWarner Losh 
32312e36acbSWarner Losh 	if (phy->phy_rev >= 2 || (phy->phy_flags & BWI_PHY_F_LINKED))
32412e36acbSWarner Losh 		bwi_phy_config_11g(mac);
32512e36acbSWarner Losh 
32612e36acbSWarner Losh 	if (phy->phy_rev >= 2) {
32712e36acbSWarner Losh 		PHY_WRITE(mac, 0x814, 0);
32812e36acbSWarner Losh 		PHY_WRITE(mac, 0x815, 0);
32912e36acbSWarner Losh 
33012e36acbSWarner Losh 		if (phy->phy_rev == 2) {
33112e36acbSWarner Losh 			PHY_WRITE(mac, 0x811, 0);
33212e36acbSWarner Losh 			PHY_WRITE(mac, 0x15, 0xc0);
33312e36acbSWarner Losh 		} else if (phy->phy_rev > 5) {
33412e36acbSWarner Losh 			PHY_WRITE(mac, 0x811, 0x400);
33512e36acbSWarner Losh 			PHY_WRITE(mac, 0x15, 0xc0);
33612e36acbSWarner Losh 		}
33712e36acbSWarner Losh 	}
33812e36acbSWarner Losh 
33912e36acbSWarner Losh 	if (phy->phy_rev >= 2 || (phy->phy_flags & BWI_PHY_F_LINKED)) {
34012e36acbSWarner Losh 		uint16_t val;
34112e36acbSWarner Losh 
34212e36acbSWarner Losh 		val = PHY_READ(mac, 0x400) & 0xff;
34312e36acbSWarner Losh 		if (val == 3 || val == 5) {
34412e36acbSWarner Losh 			PHY_WRITE(mac, 0x4c2, 0x1816);
34512e36acbSWarner Losh 			PHY_WRITE(mac, 0x4c3, 0x8006);
34612e36acbSWarner Losh 			if (val == 5) {
34712e36acbSWarner Losh 				PHY_FILT_SETBITS(mac, 0x4cc,
34812e36acbSWarner Losh 						 0xff, 0x1f00);
34912e36acbSWarner Losh 			}
35012e36acbSWarner Losh 		}
35112e36acbSWarner Losh 	}
35212e36acbSWarner Losh 
35312e36acbSWarner Losh 	if ((phy->phy_rev <= 2 && (phy->phy_flags & BWI_PHY_F_LINKED)) ||
35412e36acbSWarner Losh 	    phy->phy_rev >= 2)
35512e36acbSWarner Losh 		PHY_WRITE(mac, 0x47e, 0x78);
35612e36acbSWarner Losh 
35712e36acbSWarner Losh 	if (rf->rf_rev == 8) {
35812e36acbSWarner Losh 		PHY_SETBITS(mac, 0x801, 0x80);
35912e36acbSWarner Losh 		PHY_SETBITS(mac, 0x43e, 0x4);
36012e36acbSWarner Losh 	}
36112e36acbSWarner Losh 
36212e36acbSWarner Losh 	if (phy->phy_rev >= 2 && (phy->phy_flags & BWI_PHY_F_LINKED))
36312e36acbSWarner Losh 		bwi_rf_get_gains(mac);
36412e36acbSWarner Losh 
36512e36acbSWarner Losh 	if (rf->rf_rev != 8)
36612e36acbSWarner Losh 		bwi_rf_init(mac);
36712e36acbSWarner Losh 
36812e36acbSWarner Losh 	if (tpctl->tp_ctrl2 == 0xffff) {
36912e36acbSWarner Losh 		bwi_rf_lo_update(mac);
37012e36acbSWarner Losh 	} else {
37112e36acbSWarner Losh 		if (rf->rf_type == BWI_RF_T_BCM2050 && rf->rf_rev == 8) {
37212e36acbSWarner Losh 			RF_WRITE(mac, 0x52,
37312e36acbSWarner Losh 				 (tpctl->tp_ctrl1 << 4) | tpctl->tp_ctrl2);
37412e36acbSWarner Losh 		} else {
375b16a8a58SWarner Losh 			RF_FILT_SETBITS(mac, 0x52, 0xfff0, tpctl->tp_ctrl2);
37612e36acbSWarner Losh 		}
37712e36acbSWarner Losh 
37812e36acbSWarner Losh 		if (phy->phy_rev >= 6) {
37912e36acbSWarner Losh 			PHY_FILT_SETBITS(mac, 0x36, 0xfff,
38012e36acbSWarner Losh 					 tpctl->tp_ctrl2 << 12);
38112e36acbSWarner Losh 		}
38212e36acbSWarner Losh 
38312e36acbSWarner Losh 		if (sc->sc_card_flags & BWI_CARD_F_PA_GPIO9)
38412e36acbSWarner Losh 			PHY_WRITE(mac, 0x2e, 0x8075);
38512e36acbSWarner Losh 		else
38612e36acbSWarner Losh 			PHY_WRITE(mac, 0x2e, 0x807f);
38712e36acbSWarner Losh 
38812e36acbSWarner Losh 		if (phy->phy_rev < 2)
38912e36acbSWarner Losh 			PHY_WRITE(mac, 0x2f, 0x101);
39012e36acbSWarner Losh 		else
39112e36acbSWarner Losh 			PHY_WRITE(mac, 0x2f, 0x202);
39212e36acbSWarner Losh 	}
39312e36acbSWarner Losh 
39412e36acbSWarner Losh 	if ((phy->phy_flags & BWI_PHY_F_LINKED) || phy->phy_rev >= 2) {
39512e36acbSWarner Losh 		bwi_rf_lo_adjust(mac, tpctl);
39612e36acbSWarner Losh 		PHY_WRITE(mac, 0x80f, 0x8078);
39712e36acbSWarner Losh 	}
39812e36acbSWarner Losh 
39912e36acbSWarner Losh 	if ((sc->sc_card_flags & BWI_CARD_F_SW_NRSSI) == 0) {
40012e36acbSWarner Losh 		bwi_rf_init_hw_nrssi_table(mac, 0xffff /* XXX */);
40112e36acbSWarner Losh 		bwi_rf_set_nrssi_thr(mac);
40212e36acbSWarner Losh 	} else if ((phy->phy_flags & BWI_PHY_F_LINKED) || phy->phy_rev >= 2) {
40312e36acbSWarner Losh 		if (rf->rf_nrssi[0] == BWI_INVALID_NRSSI) {
40412e36acbSWarner Losh 			KASSERT(rf->rf_nrssi[1] == BWI_INVALID_NRSSI,
40512e36acbSWarner Losh 			    ("rf_nrssi[1] %d", rf->rf_nrssi[1]));
40612e36acbSWarner Losh 			bwi_rf_calc_nrssi_slope(mac);
40712e36acbSWarner Losh 		} else {
40812e36acbSWarner Losh 			KASSERT(rf->rf_nrssi[1] != BWI_INVALID_NRSSI,
40912e36acbSWarner Losh 			    ("rf_nrssi[1] %d", rf->rf_nrssi[1]));
41012e36acbSWarner Losh 			bwi_rf_set_nrssi_thr(mac);
41112e36acbSWarner Losh 		}
41212e36acbSWarner Losh 	}
41312e36acbSWarner Losh 
41412e36acbSWarner Losh 	if (rf->rf_rev == 8)
41512e36acbSWarner Losh 		PHY_WRITE(mac, 0x805, 0x3230);
41612e36acbSWarner Losh 
41712e36acbSWarner Losh 	bwi_mac_init_tpctl_11bg(mac);
41812e36acbSWarner Losh 
41912e36acbSWarner Losh 	if (sc->sc_bbp_id == BWI_BBPID_BCM4306 && sc->sc_bbp_pkg == 2) {
42012e36acbSWarner Losh 		PHY_CLRBITS(mac, 0x429, 0x4000);
42112e36acbSWarner Losh 		PHY_CLRBITS(mac, 0x4c3, 0x8000);
42212e36acbSWarner Losh 	}
42312e36acbSWarner Losh }
42412e36acbSWarner Losh 
42512e36acbSWarner Losh static void
bwi_phy_init_11b_rev2(struct bwi_mac * mac)42612e36acbSWarner Losh bwi_phy_init_11b_rev2(struct bwi_mac *mac)
42712e36acbSWarner Losh {
42812e36acbSWarner Losh 	/* TODO:11B */
4297a79cebfSGleb Smirnoff 	device_printf(mac->mac_sc->sc_dev,
43012e36acbSWarner Losh 		  "%s is not implemented yet\n", __func__);
43112e36acbSWarner Losh }
43212e36acbSWarner Losh 
43312e36acbSWarner Losh static void
bwi_phy_init_11b_rev4(struct bwi_mac * mac)43412e36acbSWarner Losh bwi_phy_init_11b_rev4(struct bwi_mac *mac)
43512e36acbSWarner Losh {
43612e36acbSWarner Losh 	struct bwi_softc *sc = mac->mac_sc;
43712e36acbSWarner Losh 	struct bwi_rf *rf = &mac->mac_rf;
43812e36acbSWarner Losh 	uint16_t val, ofs;
43912e36acbSWarner Losh 	u_int chan;
44012e36acbSWarner Losh 
44112e36acbSWarner Losh 	CSR_WRITE_2(sc, BWI_BPHY_CTRL, BWI_BPHY_CTRL_INIT);
44212e36acbSWarner Losh 
44312e36acbSWarner Losh 	PHY_WRITE(mac, 0x20, 0x301c);
44412e36acbSWarner Losh 	PHY_WRITE(mac, 0x26, 0);
44512e36acbSWarner Losh 	PHY_WRITE(mac, 0x30, 0xc6);
44612e36acbSWarner Losh 	PHY_WRITE(mac, 0x88, 0x3e00);
44712e36acbSWarner Losh 
44812e36acbSWarner Losh 	for (ofs = 0, val = 0x3c3d; ofs < 30; ++ofs, val -= 0x202)
44912e36acbSWarner Losh 		PHY_WRITE(mac, 0x89 + ofs, val);
45012e36acbSWarner Losh 
45112e36acbSWarner Losh 	CSR_WRITE_2(sc, BWI_PHY_MAGIC_REG1, BWI_PHY_MAGIC_REG1_VAL1);
45212e36acbSWarner Losh 
45312e36acbSWarner Losh 	chan = rf->rf_curchan;
45412e36acbSWarner Losh 	if (chan == IEEE80211_CHAN_ANY)
45512e36acbSWarner Losh 		chan = 6;	/* Force to channel 6 */
45612e36acbSWarner Losh 	bwi_rf_set_chan(mac, chan, 0);
45712e36acbSWarner Losh 
45812e36acbSWarner Losh 	if (rf->rf_type != BWI_RF_T_BCM2050) {
45912e36acbSWarner Losh 		RF_WRITE(mac, 0x75, 0x80);
46012e36acbSWarner Losh 		RF_WRITE(mac, 0x79, 0x81);
46112e36acbSWarner Losh 	}
46212e36acbSWarner Losh 
46312e36acbSWarner Losh 	RF_WRITE(mac, 0x50, 0x20);
46412e36acbSWarner Losh 	RF_WRITE(mac, 0x50, 0x23);
46512e36acbSWarner Losh 
46612e36acbSWarner Losh 	if (rf->rf_type == BWI_RF_T_BCM2050) {
46712e36acbSWarner Losh 		RF_WRITE(mac, 0x50, 0x20);
46812e36acbSWarner Losh 		RF_WRITE(mac, 0x5a, 0x70);
46912e36acbSWarner Losh 		RF_WRITE(mac, 0x5b, 0x7b);
47012e36acbSWarner Losh 		RF_WRITE(mac, 0x5c, 0xb0);
47112e36acbSWarner Losh 		RF_WRITE(mac, 0x7a, 0xf);
47212e36acbSWarner Losh 		PHY_WRITE(mac, 0x38, 0x677);
47312e36acbSWarner Losh 		bwi_rf_init_bcm2050(mac);
47412e36acbSWarner Losh 	}
47512e36acbSWarner Losh 
47612e36acbSWarner Losh 	PHY_WRITE(mac, 0x14, 0x80);
47712e36acbSWarner Losh 	PHY_WRITE(mac, 0x32, 0xca);
47812e36acbSWarner Losh 	if (rf->rf_type == BWI_RF_T_BCM2050)
47912e36acbSWarner Losh 		PHY_WRITE(mac, 0x32, 0xe0);
48012e36acbSWarner Losh 	PHY_WRITE(mac, 0x35, 0x7c2);
48112e36acbSWarner Losh 
48212e36acbSWarner Losh 	bwi_rf_lo_update(mac);
48312e36acbSWarner Losh 
48412e36acbSWarner Losh 	PHY_WRITE(mac, 0x26, 0xcc00);
48512e36acbSWarner Losh 	if (rf->rf_type == BWI_RF_T_BCM2050)
48612e36acbSWarner Losh 		PHY_WRITE(mac, 0x26, 0xce00);
48712e36acbSWarner Losh 
48812e36acbSWarner Losh 	CSR_WRITE_2(sc, BWI_RF_CHAN_EX, 0x1100);
48912e36acbSWarner Losh 
49012e36acbSWarner Losh 	PHY_WRITE(mac, 0x2a, 0x88a3);
49112e36acbSWarner Losh 	if (rf->rf_type == BWI_RF_T_BCM2050)
49212e36acbSWarner Losh 		PHY_WRITE(mac, 0x2a, 0x88c2);
49312e36acbSWarner Losh 
49412e36acbSWarner Losh 	bwi_mac_set_tpctl_11bg(mac, NULL);
49512e36acbSWarner Losh 	if (sc->sc_card_flags & BWI_CARD_F_SW_NRSSI) {
49612e36acbSWarner Losh 		bwi_rf_calc_nrssi_slope(mac);
49712e36acbSWarner Losh 		bwi_rf_set_nrssi_thr(mac);
49812e36acbSWarner Losh 	}
49912e36acbSWarner Losh 	bwi_mac_init_tpctl_11bg(mac);
50012e36acbSWarner Losh }
50112e36acbSWarner Losh 
50212e36acbSWarner Losh static void
bwi_phy_init_11b_rev5(struct bwi_mac * mac)50312e36acbSWarner Losh bwi_phy_init_11b_rev5(struct bwi_mac *mac)
50412e36acbSWarner Losh {
50512e36acbSWarner Losh 	struct bwi_softc *sc = mac->mac_sc;
50612e36acbSWarner Losh 	struct bwi_rf *rf = &mac->mac_rf;
50712e36acbSWarner Losh 	struct bwi_phy *phy = &mac->mac_phy;
50812e36acbSWarner Losh 	u_int orig_chan;
50912e36acbSWarner Losh 
51012e36acbSWarner Losh 	if (phy->phy_version == 1)
51112e36acbSWarner Losh 		RF_SETBITS(mac, 0x7a, 0x50);
51212e36acbSWarner Losh 
51312e36acbSWarner Losh 	if (sc->sc_pci_subvid != PCI_VENDOR_BROADCOM &&
51412e36acbSWarner Losh 	    sc->sc_pci_subdid != BWI_PCI_SUBDEVICE_BU4306) {
51512e36acbSWarner Losh 		uint16_t ofs, val;
51612e36acbSWarner Losh 
51712e36acbSWarner Losh 		val = 0x2120;
51812e36acbSWarner Losh 		for (ofs = 0xa8; ofs < 0xc7; ++ofs) {
51912e36acbSWarner Losh 			PHY_WRITE(mac, ofs, val);
52012e36acbSWarner Losh 			val += 0x202;
52112e36acbSWarner Losh 		}
52212e36acbSWarner Losh 	}
52312e36acbSWarner Losh 
52412e36acbSWarner Losh 	PHY_FILT_SETBITS(mac, 0x35, 0xf0ff, 0x700);
52512e36acbSWarner Losh 
52612e36acbSWarner Losh 	if (rf->rf_type == BWI_RF_T_BCM2050)
52712e36acbSWarner Losh 		PHY_WRITE(mac, 0x38, 0x667);
52812e36acbSWarner Losh 
52912e36acbSWarner Losh 	if ((phy->phy_flags & BWI_PHY_F_LINKED) || phy->phy_rev >= 2) {
53012e36acbSWarner Losh 		if (rf->rf_type == BWI_RF_T_BCM2050) {
53112e36acbSWarner Losh 			RF_SETBITS(mac, 0x7a, 0x20);
53212e36acbSWarner Losh 			RF_SETBITS(mac, 0x51, 0x4);
53312e36acbSWarner Losh 		}
53412e36acbSWarner Losh 
53512e36acbSWarner Losh 		CSR_WRITE_2(sc, BWI_RF_ANTDIV, 0);
53612e36acbSWarner Losh 
53712e36acbSWarner Losh 		PHY_SETBITS(mac, 0x802, 0x100);
53812e36acbSWarner Losh 		PHY_SETBITS(mac, 0x42b, 0x2000);
53912e36acbSWarner Losh 		PHY_WRITE(mac, 0x1c, 0x186a);
54012e36acbSWarner Losh 
54112e36acbSWarner Losh 		PHY_FILT_SETBITS(mac, 0x13, 0xff, 0x1900);
54212e36acbSWarner Losh 		PHY_FILT_SETBITS(mac, 0x35, 0xffc0, 0x64);
54312e36acbSWarner Losh 		PHY_FILT_SETBITS(mac, 0x5d, 0xff80, 0xa);
54412e36acbSWarner Losh 	}
54512e36acbSWarner Losh 
54612e36acbSWarner Losh 	/* TODO: bad_frame_preempt? */
54712e36acbSWarner Losh 
54812e36acbSWarner Losh 	if (phy->phy_version == 1) {
54912e36acbSWarner Losh 	    	PHY_WRITE(mac, 0x26, 0xce00);
55012e36acbSWarner Losh 		PHY_WRITE(mac, 0x21, 0x3763);
55112e36acbSWarner Losh 		PHY_WRITE(mac, 0x22, 0x1bc3);
55212e36acbSWarner Losh 		PHY_WRITE(mac, 0x23, 0x6f9);
55312e36acbSWarner Losh 		PHY_WRITE(mac, 0x24, 0x37e);
55412e36acbSWarner Losh 	} else {
55512e36acbSWarner Losh 		PHY_WRITE(mac, 0x26, 0xcc00);
55612e36acbSWarner Losh 	}
55712e36acbSWarner Losh 	PHY_WRITE(mac, 0x30, 0xc6);
55812e36acbSWarner Losh 
55912e36acbSWarner Losh 	CSR_WRITE_2(sc, BWI_BPHY_CTRL, BWI_BPHY_CTRL_INIT);
56012e36acbSWarner Losh 
56112e36acbSWarner Losh 	if (phy->phy_version == 1)
56212e36acbSWarner Losh 		PHY_WRITE(mac, 0x20, 0x3e1c);
56312e36acbSWarner Losh 	else
56412e36acbSWarner Losh 		PHY_WRITE(mac, 0x20, 0x301c);
56512e36acbSWarner Losh 
56612e36acbSWarner Losh 	if (phy->phy_version == 0)
56712e36acbSWarner Losh 		CSR_WRITE_2(sc, BWI_PHY_MAGIC_REG1, BWI_PHY_MAGIC_REG1_VAL1);
56812e36acbSWarner Losh 
56912e36acbSWarner Losh 	/* Force to channel 7 */
57012e36acbSWarner Losh 	orig_chan = rf->rf_curchan;
57112e36acbSWarner Losh 	bwi_rf_set_chan(mac, 7, 0);
57212e36acbSWarner Losh 
57312e36acbSWarner Losh 	if (rf->rf_type != BWI_RF_T_BCM2050) {
57412e36acbSWarner Losh 		RF_WRITE(mac, 0x75, 0x80);
57512e36acbSWarner Losh 		RF_WRITE(mac, 0x79, 0x81);
57612e36acbSWarner Losh 	}
57712e36acbSWarner Losh 
57812e36acbSWarner Losh 	RF_WRITE(mac, 0x50, 0x20);
57912e36acbSWarner Losh 	RF_WRITE(mac, 0x50, 0x23);
58012e36acbSWarner Losh 
58112e36acbSWarner Losh 	if (rf->rf_type == BWI_RF_T_BCM2050) {
58212e36acbSWarner Losh 		RF_WRITE(mac, 0x50, 0x20);
58312e36acbSWarner Losh 		RF_WRITE(mac, 0x5a, 0x70);
58412e36acbSWarner Losh 	}
58512e36acbSWarner Losh 
58612e36acbSWarner Losh 	RF_WRITE(mac, 0x5b, 0x7b);
58712e36acbSWarner Losh 	RF_WRITE(mac, 0x5c, 0xb0);
58812e36acbSWarner Losh 	RF_SETBITS(mac, 0x7a, 0x7);
58912e36acbSWarner Losh 
59012e36acbSWarner Losh 	bwi_rf_set_chan(mac, orig_chan, 0);
59112e36acbSWarner Losh 
59212e36acbSWarner Losh 	PHY_WRITE(mac, 0x14, 0x80);
59312e36acbSWarner Losh 	PHY_WRITE(mac, 0x32, 0xca);
59412e36acbSWarner Losh 	PHY_WRITE(mac, 0x2a, 0x88a3);
59512e36acbSWarner Losh 
59612e36acbSWarner Losh 	bwi_mac_set_tpctl_11bg(mac, NULL);
59712e36acbSWarner Losh 
59812e36acbSWarner Losh 	if (rf->rf_type == BWI_RF_T_BCM2050)
59912e36acbSWarner Losh 		RF_WRITE(mac, 0x5d, 0xd);
60012e36acbSWarner Losh 
60112e36acbSWarner Losh 	CSR_FILT_SETBITS_2(sc, BWI_PHY_MAGIC_REG1, 0xffc0, 0x4);
60212e36acbSWarner Losh }
60312e36acbSWarner Losh 
60412e36acbSWarner Losh static void
bwi_phy_init_11b_rev6(struct bwi_mac * mac)60512e36acbSWarner Losh bwi_phy_init_11b_rev6(struct bwi_mac *mac)
60612e36acbSWarner Losh {
60712e36acbSWarner Losh 	struct bwi_softc *sc = mac->mac_sc;
60812e36acbSWarner Losh 	struct bwi_rf *rf = &mac->mac_rf;
60912e36acbSWarner Losh 	struct bwi_phy *phy = &mac->mac_phy;
61012e36acbSWarner Losh 	uint16_t val, ofs;
61112e36acbSWarner Losh 	u_int orig_chan;
61212e36acbSWarner Losh 
61312e36acbSWarner Losh 	PHY_WRITE(mac, 0x3e, 0x817a);
61412e36acbSWarner Losh 	RF_SETBITS(mac, 0x7a, 0x58);
61512e36acbSWarner Losh 
61612e36acbSWarner Losh 	if (rf->rf_rev == 4 || rf->rf_rev == 5) {
61712e36acbSWarner Losh 		RF_WRITE(mac, 0x51, 0x37);
61812e36acbSWarner Losh 		RF_WRITE(mac, 0x52, 0x70);
61912e36acbSWarner Losh 		RF_WRITE(mac, 0x53, 0xb3);
62012e36acbSWarner Losh 		RF_WRITE(mac, 0x54, 0x9b);
62112e36acbSWarner Losh 		RF_WRITE(mac, 0x5a, 0x88);
62212e36acbSWarner Losh 		RF_WRITE(mac, 0x5b, 0x88);
62312e36acbSWarner Losh 		RF_WRITE(mac, 0x5d, 0x88);
62412e36acbSWarner Losh 		RF_WRITE(mac, 0x5e, 0x88);
62512e36acbSWarner Losh 		RF_WRITE(mac, 0x7d, 0x88);
62612e36acbSWarner Losh 		HFLAGS_SETBITS(mac, BWI_HFLAG_MAGIC1);
62712e36acbSWarner Losh 	} else if (rf->rf_rev == 8) {
62812e36acbSWarner Losh 		RF_WRITE(mac, 0x51, 0);
62912e36acbSWarner Losh 		RF_WRITE(mac, 0x52, 0x40);
63012e36acbSWarner Losh 		RF_WRITE(mac, 0x53, 0xb7);
63112e36acbSWarner Losh 		RF_WRITE(mac, 0x54, 0x98);
63212e36acbSWarner Losh 		RF_WRITE(mac, 0x5a, 0x88);
63312e36acbSWarner Losh 		RF_WRITE(mac, 0x5b, 0x6b);
63412e36acbSWarner Losh 		RF_WRITE(mac, 0x5c, 0xf);
63512e36acbSWarner Losh 		if (sc->sc_card_flags & BWI_CARD_F_ALT_IQ) {
63612e36acbSWarner Losh 			RF_WRITE(mac, 0x5d, 0xfa);
63712e36acbSWarner Losh 			RF_WRITE(mac, 0x5e, 0xd8);
63812e36acbSWarner Losh 		} else {
63912e36acbSWarner Losh 			RF_WRITE(mac, 0x5d, 0xf5);
64012e36acbSWarner Losh 			RF_WRITE(mac, 0x5e, 0xb8);
64112e36acbSWarner Losh 		}
64212e36acbSWarner Losh 		RF_WRITE(mac, 0x73, 0x3);
64312e36acbSWarner Losh 		RF_WRITE(mac, 0x7d, 0xa8);
64412e36acbSWarner Losh 		RF_WRITE(mac, 0x7c, 0x1);
64512e36acbSWarner Losh 		RF_WRITE(mac, 0x7e, 0x8);
64612e36acbSWarner Losh 	}
64712e36acbSWarner Losh 
64812e36acbSWarner Losh 	val = 0x1e1f;
64912e36acbSWarner Losh 	for (ofs = 0x88; ofs < 0x98; ++ofs) {
65012e36acbSWarner Losh 		PHY_WRITE(mac, ofs, val);
65112e36acbSWarner Losh 		val -= 0x202;
65212e36acbSWarner Losh 	}
65312e36acbSWarner Losh 
65412e36acbSWarner Losh 	val = 0x3e3f;
65512e36acbSWarner Losh 	for (ofs = 0x98; ofs < 0xa8; ++ofs) {
65612e36acbSWarner Losh 		PHY_WRITE(mac, ofs, val);
65712e36acbSWarner Losh 		val -= 0x202;
65812e36acbSWarner Losh 	}
65912e36acbSWarner Losh 
66012e36acbSWarner Losh 	val = 0x2120;
66112e36acbSWarner Losh 	for (ofs = 0xa8; ofs < 0xc8; ++ofs) {
66212e36acbSWarner Losh 		PHY_WRITE(mac, ofs, (val & 0x3f3f));
66312e36acbSWarner Losh 		val += 0x202;
6648553eea5SNathan Whitehorn 
6658553eea5SNathan Whitehorn 		/* XXX: delay 10 us to avoid PCI parity errors with BCM4318 */
6660a594d9eSNathan Whitehorn 		DELAY(10);
66712e36acbSWarner Losh 	}
66812e36acbSWarner Losh 
66912e36acbSWarner Losh 	if (phy->phy_mode == IEEE80211_MODE_11G) {
67012e36acbSWarner Losh 		RF_SETBITS(mac, 0x7a, 0x20);
67112e36acbSWarner Losh 		RF_SETBITS(mac, 0x51, 0x4);
67212e36acbSWarner Losh 		PHY_SETBITS(mac, 0x802, 0x100);
67312e36acbSWarner Losh 		PHY_SETBITS(mac, 0x42b, 0x2000);
67412e36acbSWarner Losh 		PHY_WRITE(mac, 0x5b, 0);
67512e36acbSWarner Losh 		PHY_WRITE(mac, 0x5c, 0);
67612e36acbSWarner Losh 	}
67712e36acbSWarner Losh 
67812e36acbSWarner Losh 	/* Force to channel 7 */
67912e36acbSWarner Losh 	orig_chan = rf->rf_curchan;
68012e36acbSWarner Losh 	if (orig_chan >= 8)
68112e36acbSWarner Losh 		bwi_rf_set_chan(mac, 1, 0);
68212e36acbSWarner Losh 	else
68312e36acbSWarner Losh 		bwi_rf_set_chan(mac, 13, 0);
68412e36acbSWarner Losh 
68512e36acbSWarner Losh 	RF_WRITE(mac, 0x50, 0x20);
68612e36acbSWarner Losh 	RF_WRITE(mac, 0x50, 0x23);
68712e36acbSWarner Losh 
68812e36acbSWarner Losh 	DELAY(40);
68912e36acbSWarner Losh 
69012e36acbSWarner Losh 	if (rf->rf_rev < 6 || rf->rf_rev == 8) {
69112e36acbSWarner Losh 		RF_SETBITS(mac, 0x7c, 0x2);
69212e36acbSWarner Losh 		RF_WRITE(mac, 0x50, 0x20);
69312e36acbSWarner Losh 	}
69412e36acbSWarner Losh 	if (rf->rf_rev <= 2) {
69512e36acbSWarner Losh 		RF_WRITE(mac, 0x7c, 0x20);
69612e36acbSWarner Losh 		RF_WRITE(mac, 0x5a, 0x70);
69712e36acbSWarner Losh 		RF_WRITE(mac, 0x5b, 0x7b);
69812e36acbSWarner Losh 		RF_WRITE(mac, 0x5c, 0xb0);
69912e36acbSWarner Losh 	}
70012e36acbSWarner Losh 
70112e36acbSWarner Losh 	RF_FILT_SETBITS(mac, 0x7a, 0xf8, 0x7);
70212e36acbSWarner Losh 
70312e36acbSWarner Losh 	bwi_rf_set_chan(mac, orig_chan, 0);
70412e36acbSWarner Losh 
70512e36acbSWarner Losh 	PHY_WRITE(mac, 0x14, 0x200);
70612e36acbSWarner Losh 	if (rf->rf_rev >= 6)
70712e36acbSWarner Losh 		PHY_WRITE(mac, 0x2a, 0x88c2);
70812e36acbSWarner Losh 	else
70912e36acbSWarner Losh 		PHY_WRITE(mac, 0x2a, 0x8ac0);
71012e36acbSWarner Losh 	PHY_WRITE(mac, 0x38, 0x668);
71112e36acbSWarner Losh 
71212e36acbSWarner Losh 	bwi_mac_set_tpctl_11bg(mac, NULL);
71312e36acbSWarner Losh 
71412e36acbSWarner Losh 	if (rf->rf_rev <= 5) {
71512e36acbSWarner Losh 		PHY_FILT_SETBITS(mac, 0x5d, 0xff80, 0x3);
71612e36acbSWarner Losh 		if (rf->rf_rev <= 2)
71712e36acbSWarner Losh 			RF_WRITE(mac, 0x5d, 0xd);
71812e36acbSWarner Losh 	}
71912e36acbSWarner Losh 
72012e36acbSWarner Losh 	if (phy->phy_version == 4) {
72112e36acbSWarner Losh 		CSR_WRITE_2(sc, BWI_PHY_MAGIC_REG1, BWI_PHY_MAGIC_REG1_VAL2);
72212e36acbSWarner Losh 		PHY_CLRBITS(mac, 0x61, 0xf000);
72312e36acbSWarner Losh 	} else {
72412e36acbSWarner Losh 		PHY_FILT_SETBITS(mac, 0x2, 0xffc0, 0x4);
72512e36acbSWarner Losh 	}
72612e36acbSWarner Losh 
72712e36acbSWarner Losh 	if (phy->phy_mode == IEEE80211_MODE_11B) {
72812e36acbSWarner Losh 		CSR_WRITE_2(sc, BWI_BBP_ATTEN, BWI_BBP_ATTEN_MAGIC2);
72912e36acbSWarner Losh 		PHY_WRITE(mac, 0x16, 0x410);
73012e36acbSWarner Losh 		PHY_WRITE(mac, 0x17, 0x820);
73112e36acbSWarner Losh 		PHY_WRITE(mac, 0x62, 0x7);
73212e36acbSWarner Losh 
73312e36acbSWarner Losh 		bwi_rf_init_bcm2050(mac);
73412e36acbSWarner Losh 		bwi_rf_lo_update(mac);
73512e36acbSWarner Losh 		if (sc->sc_card_flags & BWI_CARD_F_SW_NRSSI) {
73612e36acbSWarner Losh 			bwi_rf_calc_nrssi_slope(mac);
73712e36acbSWarner Losh 			bwi_rf_set_nrssi_thr(mac);
73812e36acbSWarner Losh 		}
73912e36acbSWarner Losh 		bwi_mac_init_tpctl_11bg(mac);
74012e36acbSWarner Losh 	} else {
74112e36acbSWarner Losh 		CSR_WRITE_2(sc, BWI_BBP_ATTEN, 0);
74212e36acbSWarner Losh 	}
74312e36acbSWarner Losh }
74412e36acbSWarner Losh 
74512e36acbSWarner Losh static void
bwi_phy_config_11g(struct bwi_mac * mac)74612e36acbSWarner Losh bwi_phy_config_11g(struct bwi_mac *mac)
74712e36acbSWarner Losh {
74812e36acbSWarner Losh 	struct bwi_softc *sc = mac->mac_sc;
74912e36acbSWarner Losh 	struct bwi_phy *phy = &mac->mac_phy;
75012e36acbSWarner Losh 	const uint16_t *tbl;
75112e36acbSWarner Losh 	uint16_t wrd_ofs1, wrd_ofs2;
75212e36acbSWarner Losh 	int i, n;
75312e36acbSWarner Losh 
75412e36acbSWarner Losh 	if (phy->phy_rev == 1) {
75512e36acbSWarner Losh 		PHY_WRITE(mac, 0x406, 0x4f19);
75612e36acbSWarner Losh 		PHY_FILT_SETBITS(mac, 0x429, 0xfc3f, 0x340);
75712e36acbSWarner Losh 		PHY_WRITE(mac, 0x42c, 0x5a);
75812e36acbSWarner Losh 		PHY_WRITE(mac, 0x427, 0x1a);
75912e36acbSWarner Losh 
76012e36acbSWarner Losh 		/* Fill frequency table */
761d6166defSAdrian Chadd 		for (i = 0; i < nitems(bwi_phy_freq_11g_rev1); ++i) {
76212e36acbSWarner Losh 			bwi_tbl_write_2(mac, BWI_PHYTBL_FREQ + i,
76312e36acbSWarner Losh 					bwi_phy_freq_11g_rev1[i]);
76412e36acbSWarner Losh 		}
76512e36acbSWarner Losh 
76612e36acbSWarner Losh 		/* Fill noise table */
767d6166defSAdrian Chadd 		for (i = 0; i < nitems(bwi_phy_noise_11g_rev1); ++i) {
76812e36acbSWarner Losh 			bwi_tbl_write_2(mac, BWI_PHYTBL_NOISE + i,
76912e36acbSWarner Losh 					bwi_phy_noise_11g_rev1[i]);
77012e36acbSWarner Losh 		}
77112e36acbSWarner Losh 
77212e36acbSWarner Losh 		/* Fill rotor table */
773d6166defSAdrian Chadd 		for (i = 0; i < nitems(bwi_phy_rotor_11g_rev1); ++i) {
77412e36acbSWarner Losh 			/* NB: data length is 4 bytes */
77512e36acbSWarner Losh 			bwi_tbl_write_4(mac, BWI_PHYTBL_ROTOR + i,
77612e36acbSWarner Losh 					bwi_phy_rotor_11g_rev1[i]);
77712e36acbSWarner Losh 		}
77812e36acbSWarner Losh 	} else {
77912e36acbSWarner Losh 		bwi_nrssi_write(mac, 0xba98, (int16_t)0x7654); /* XXX */
78012e36acbSWarner Losh 
78112e36acbSWarner Losh 		if (phy->phy_rev == 2) {
78212e36acbSWarner Losh 			PHY_WRITE(mac, 0x4c0, 0x1861);
78312e36acbSWarner Losh 			PHY_WRITE(mac, 0x4c1, 0x271);
78412e36acbSWarner Losh 		} else if (phy->phy_rev > 2) {
78512e36acbSWarner Losh 			PHY_WRITE(mac, 0x4c0, 0x98);
78612e36acbSWarner Losh 			PHY_WRITE(mac, 0x4c1, 0x70);
78712e36acbSWarner Losh 			PHY_WRITE(mac, 0x4c9, 0x80);
78812e36acbSWarner Losh 		}
78912e36acbSWarner Losh 		PHY_SETBITS(mac, 0x42b, 0x800);
79012e36acbSWarner Losh 
79112e36acbSWarner Losh 		/* Fill RSSI table */
79212e36acbSWarner Losh 		for (i = 0; i < 64; ++i)
79312e36acbSWarner Losh 			bwi_tbl_write_2(mac, BWI_PHYTBL_RSSI + i, i);
79412e36acbSWarner Losh 
79512e36acbSWarner Losh 		/* Fill noise table */
796d6166defSAdrian Chadd 		for (i = 0; i < nitems(bwi_phy_noise_11g); ++i) {
79712e36acbSWarner Losh 			bwi_tbl_write_2(mac, BWI_PHYTBL_NOISE + i,
79812e36acbSWarner Losh 					bwi_phy_noise_11g[i]);
79912e36acbSWarner Losh 		}
80012e36acbSWarner Losh 	}
80112e36acbSWarner Losh 
80212e36acbSWarner Losh 	/*
80312e36acbSWarner Losh 	 * Fill noise scale table
80412e36acbSWarner Losh 	 */
80512e36acbSWarner Losh 	if (phy->phy_rev <= 2) {
80612e36acbSWarner Losh 		tbl = bwi_phy_noise_scale_11g_rev2;
807d6166defSAdrian Chadd 		n = nitems(bwi_phy_noise_scale_11g_rev2);
80812e36acbSWarner Losh 	} else if (phy->phy_rev >= 7 && (PHY_READ(mac, 0x449) & 0x200)) {
80912e36acbSWarner Losh 		tbl = bwi_phy_noise_scale_11g_rev7;
810d6166defSAdrian Chadd 		n = nitems(bwi_phy_noise_scale_11g_rev7);
81112e36acbSWarner Losh 	} else {
81212e36acbSWarner Losh 		tbl = bwi_phy_noise_scale_11g;
813d6166defSAdrian Chadd 		n = nitems(bwi_phy_noise_scale_11g);
81412e36acbSWarner Losh 	}
81512e36acbSWarner Losh 	for (i = 0; i < n; ++i)
81612e36acbSWarner Losh 		bwi_tbl_write_2(mac, BWI_PHYTBL_NOISE_SCALE + i, tbl[i]);
81712e36acbSWarner Losh 
81812e36acbSWarner Losh 	/*
81912e36acbSWarner Losh 	 * Fill sigma square table
82012e36acbSWarner Losh 	 */
82112e36acbSWarner Losh 	if (phy->phy_rev == 2) {
82212e36acbSWarner Losh 		tbl = bwi_phy_sigma_sq_11g_rev2;
823d6166defSAdrian Chadd 		n = nitems(bwi_phy_sigma_sq_11g_rev2);
82412e36acbSWarner Losh 	} else if (phy->phy_rev > 2 && phy->phy_rev <= 8) {
82512e36acbSWarner Losh 		tbl = bwi_phy_sigma_sq_11g_rev7;
826d6166defSAdrian Chadd 		n = nitems(bwi_phy_sigma_sq_11g_rev7);
82712e36acbSWarner Losh 	} else {
82812e36acbSWarner Losh 		tbl = NULL;
82912e36acbSWarner Losh 		n = 0;
83012e36acbSWarner Losh 	}
83112e36acbSWarner Losh 	for (i = 0; i < n; ++i)
83212e36acbSWarner Losh 		bwi_tbl_write_2(mac, BWI_PHYTBL_SIGMA_SQ + i, tbl[i]);
83312e36acbSWarner Losh 
83412e36acbSWarner Losh 	if (phy->phy_rev == 1) {
83512e36acbSWarner Losh 		/* Fill delay table */
836d6166defSAdrian Chadd 		for (i = 0; i < nitems(bwi_phy_delay_11g_rev1); ++i) {
83712e36acbSWarner Losh 			bwi_tbl_write_4(mac, BWI_PHYTBL_DELAY + i,
83812e36acbSWarner Losh 					bwi_phy_delay_11g_rev1[i]);
83912e36acbSWarner Losh 		}
84012e36acbSWarner Losh 
84112e36acbSWarner Losh 		/* Fill WRSSI (Wide-Band RSSI) table */
84212e36acbSWarner Losh 		for (i = 4; i < 20; ++i)
84312e36acbSWarner Losh 			bwi_tbl_write_2(mac, BWI_PHYTBL_WRSSI_REV1 + i, 0x20);
84412e36acbSWarner Losh 
84512e36acbSWarner Losh 		bwi_phy_config_agc(mac);
84612e36acbSWarner Losh 
84712e36acbSWarner Losh 		wrd_ofs1 = 0x5001;
84812e36acbSWarner Losh 		wrd_ofs2 = 0x5002;
84912e36acbSWarner Losh 	} else {
85012e36acbSWarner Losh 		/* Fill WRSSI (Wide-Band RSSI) table */
85112e36acbSWarner Losh 		for (i = 0; i < 0x20; ++i)
85212e36acbSWarner Losh 			bwi_tbl_write_2(mac, BWI_PHYTBL_WRSSI + i, 0x820);
85312e36acbSWarner Losh 
85412e36acbSWarner Losh 		bwi_phy_config_agc(mac);
85512e36acbSWarner Losh 
85612e36acbSWarner Losh 		PHY_READ(mac, 0x400);	/* Dummy read */
85712e36acbSWarner Losh 		PHY_WRITE(mac, 0x403, 0x1000);
85812e36acbSWarner Losh 		bwi_tbl_write_2(mac, 0x3c02, 0xf);
85912e36acbSWarner Losh 		bwi_tbl_write_2(mac, 0x3c03, 0x14);
86012e36acbSWarner Losh 
86112e36acbSWarner Losh 		wrd_ofs1 = 0x401;
86212e36acbSWarner Losh 		wrd_ofs2 = 0x402;
86312e36acbSWarner Losh 	}
86412e36acbSWarner Losh 
86512e36acbSWarner Losh 	if (!(BWI_IS_BRCM_BU4306(sc) && sc->sc_pci_revid == 0x17)) {
86612e36acbSWarner Losh 		bwi_tbl_write_2(mac, wrd_ofs1, 0x2);
86712e36acbSWarner Losh 		bwi_tbl_write_2(mac, wrd_ofs2, 0x1);
86812e36acbSWarner Losh 	}
86912e36acbSWarner Losh 
87012e36acbSWarner Losh 	/* phy->phy_flags & BWI_PHY_F_LINKED ? */
87112e36acbSWarner Losh 	if (sc->sc_card_flags & BWI_CARD_F_PA_GPIO9)
87212e36acbSWarner Losh 		PHY_WRITE(mac, 0x46e, 0x3cf);
87312e36acbSWarner Losh }
87412e36acbSWarner Losh 
87512e36acbSWarner Losh /*
87612e36acbSWarner Losh  * Configure Automatic Gain Controller
87712e36acbSWarner Losh  */
87812e36acbSWarner Losh static void
bwi_phy_config_agc(struct bwi_mac * mac)87912e36acbSWarner Losh bwi_phy_config_agc(struct bwi_mac *mac)
88012e36acbSWarner Losh {
88112e36acbSWarner Losh 	struct bwi_phy *phy = &mac->mac_phy;
88212e36acbSWarner Losh 	uint16_t ofs;
88312e36acbSWarner Losh 
88412e36acbSWarner Losh 	ofs = phy->phy_rev == 1 ? 0x4c00 : 0;
88512e36acbSWarner Losh 
88612e36acbSWarner Losh 	bwi_tbl_write_2(mac, ofs, 0xfe);
88712e36acbSWarner Losh 	bwi_tbl_write_2(mac, ofs + 1, 0xd);
88812e36acbSWarner Losh 	bwi_tbl_write_2(mac, ofs + 2, 0x13);
88912e36acbSWarner Losh 	bwi_tbl_write_2(mac, ofs + 3, 0x19);
89012e36acbSWarner Losh 
89112e36acbSWarner Losh 	if (phy->phy_rev == 1) {
89212e36acbSWarner Losh 		bwi_tbl_write_2(mac, 0x1800, 0x2710);
89312e36acbSWarner Losh 		bwi_tbl_write_2(mac, 0x1801, 0x9b83);
89412e36acbSWarner Losh 		bwi_tbl_write_2(mac, 0x1802, 0x9b83);
89512e36acbSWarner Losh 		bwi_tbl_write_2(mac, 0x1803, 0xf8d);
89612e36acbSWarner Losh 		PHY_WRITE(mac, 0x455, 0x4);
89712e36acbSWarner Losh 	}
89812e36acbSWarner Losh 
89912e36acbSWarner Losh 	PHY_FILT_SETBITS(mac, 0x4a5, 0xff, 0x5700);
90012e36acbSWarner Losh 	PHY_FILT_SETBITS(mac, 0x41a, 0xff80, 0xf);
90112e36acbSWarner Losh 	PHY_FILT_SETBITS(mac, 0x41a, 0xc07f, 0x2b80);
90212e36acbSWarner Losh 	PHY_FILT_SETBITS(mac, 0x48c, 0xf0ff, 0x300);
90312e36acbSWarner Losh 
90412e36acbSWarner Losh 	RF_SETBITS(mac, 0x7a, 0x8);
90512e36acbSWarner Losh 
90612e36acbSWarner Losh 	PHY_FILT_SETBITS(mac, 0x4a0, 0xfff0, 0x8);
90712e36acbSWarner Losh 	PHY_FILT_SETBITS(mac, 0x4a1, 0xf0ff, 0x600);
90812e36acbSWarner Losh 	PHY_FILT_SETBITS(mac, 0x4a2, 0xf0ff, 0x700);
90912e36acbSWarner Losh 	PHY_FILT_SETBITS(mac, 0x4a0, 0xf0ff, 0x100);
91012e36acbSWarner Losh 
91112e36acbSWarner Losh 	if (phy->phy_rev == 1)
91212e36acbSWarner Losh 		PHY_FILT_SETBITS(mac, 0x4a2, 0xfff0, 0x7);
91312e36acbSWarner Losh 
91412e36acbSWarner Losh 	PHY_FILT_SETBITS(mac, 0x488, 0xff00, 0x1c);
91512e36acbSWarner Losh 	PHY_FILT_SETBITS(mac, 0x488, 0xc0ff, 0x200);
91612e36acbSWarner Losh 	PHY_FILT_SETBITS(mac, 0x496, 0xff00, 0x1c);
91712e36acbSWarner Losh 	PHY_FILT_SETBITS(mac, 0x489, 0xff00, 0x20);
91812e36acbSWarner Losh 	PHY_FILT_SETBITS(mac, 0x489, 0xc0ff, 0x200);
91912e36acbSWarner Losh 	PHY_FILT_SETBITS(mac, 0x482, 0xff00, 0x2e);
92012e36acbSWarner Losh 	PHY_FILT_SETBITS(mac, 0x496, 0xff, 0x1a00);
92112e36acbSWarner Losh 	PHY_FILT_SETBITS(mac, 0x481, 0xff00, 0x28);
92212e36acbSWarner Losh 	PHY_FILT_SETBITS(mac, 0x481, 0xff, 0x2c00);
92312e36acbSWarner Losh 
92412e36acbSWarner Losh 	if (phy->phy_rev == 1) {
92512e36acbSWarner Losh 		PHY_WRITE(mac, 0x430, 0x92b);
92612e36acbSWarner Losh 		PHY_FILT_SETBITS(mac, 0x41b, 0xffe1, 0x2);
92712e36acbSWarner Losh 	} else {
92812e36acbSWarner Losh 		PHY_CLRBITS(mac, 0x41b, 0x1e);
92912e36acbSWarner Losh 		PHY_WRITE(mac, 0x41f, 0x287a);
93012e36acbSWarner Losh 		PHY_FILT_SETBITS(mac, 0x420, 0xfff0, 0x4);
93112e36acbSWarner Losh 
93212e36acbSWarner Losh 		if (phy->phy_rev >= 6) {
93312e36acbSWarner Losh 			PHY_WRITE(mac, 0x422, 0x287a);
93412e36acbSWarner Losh 			PHY_FILT_SETBITS(mac, 0x420, 0xfff, 0x3000);
93512e36acbSWarner Losh 		}
93612e36acbSWarner Losh 	}
93712e36acbSWarner Losh 
93812e36acbSWarner Losh 	PHY_FILT_SETBITS(mac, 0x4a8, 0x8080, 0x7874);
93912e36acbSWarner Losh 	PHY_WRITE(mac, 0x48e, 0x1c00);
94012e36acbSWarner Losh 
94112e36acbSWarner Losh 	if (phy->phy_rev == 1) {
94212e36acbSWarner Losh 		PHY_FILT_SETBITS(mac, 0x4ab, 0xf0ff, 0x600);
94312e36acbSWarner Losh 		PHY_WRITE(mac, 0x48b, 0x5e);
94412e36acbSWarner Losh 		PHY_FILT_SETBITS(mac, 0x48c, 0xff00, 0x1e);
94512e36acbSWarner Losh 		PHY_WRITE(mac, 0x48d, 0x2);
94612e36acbSWarner Losh 	}
94712e36acbSWarner Losh 
94812e36acbSWarner Losh 	bwi_tbl_write_2(mac, ofs + 0x800, 0);
94912e36acbSWarner Losh 	bwi_tbl_write_2(mac, ofs + 0x801, 7);
95012e36acbSWarner Losh 	bwi_tbl_write_2(mac, ofs + 0x802, 16);
95112e36acbSWarner Losh 	bwi_tbl_write_2(mac, ofs + 0x803, 28);
95212e36acbSWarner Losh 
95312e36acbSWarner Losh 	if (phy->phy_rev >= 6) {
95412e36acbSWarner Losh 		PHY_CLRBITS(mac, 0x426, 0x3);
95512e36acbSWarner Losh 		PHY_CLRBITS(mac, 0x426, 0x1000);
95612e36acbSWarner Losh 	}
95712e36acbSWarner Losh }
95812e36acbSWarner Losh 
95912e36acbSWarner Losh void
bwi_set_gains(struct bwi_mac * mac,const struct bwi_gains * gains)96012e36acbSWarner Losh bwi_set_gains(struct bwi_mac *mac, const struct bwi_gains *gains)
96112e36acbSWarner Losh {
96212e36acbSWarner Losh 	struct bwi_phy *phy = &mac->mac_phy;
96312e36acbSWarner Losh 	uint16_t tbl_gain_ofs1, tbl_gain_ofs2, tbl_gain;
96412e36acbSWarner Losh 	int i;
96512e36acbSWarner Losh 
96612e36acbSWarner Losh 	if (phy->phy_rev <= 1) {
96712e36acbSWarner Losh 		tbl_gain_ofs1 = 0x5000;
96812e36acbSWarner Losh 		tbl_gain_ofs2 = tbl_gain_ofs1 + 16;
96912e36acbSWarner Losh 	} else {
97012e36acbSWarner Losh 		tbl_gain_ofs1 = 0x400;
97112e36acbSWarner Losh 		tbl_gain_ofs2 = tbl_gain_ofs1 + 8;
97212e36acbSWarner Losh 	}
97312e36acbSWarner Losh 
97412e36acbSWarner Losh 	for (i = 0; i < 4; ++i) {
97512e36acbSWarner Losh 		if (gains != NULL) {
97612e36acbSWarner Losh 			tbl_gain = gains->tbl_gain1;
97712e36acbSWarner Losh 		} else {
97812e36acbSWarner Losh 			/* Bit swap */
97912e36acbSWarner Losh 			tbl_gain = (i & 0x1) << 1;
98012e36acbSWarner Losh 			tbl_gain |= (i & 0x2) >> 1;
98112e36acbSWarner Losh 		}
98212e36acbSWarner Losh 		bwi_tbl_write_2(mac, tbl_gain_ofs1 + i, tbl_gain);
98312e36acbSWarner Losh 	}
98412e36acbSWarner Losh 
98512e36acbSWarner Losh 	for (i = 0; i < 16; ++i) {
98612e36acbSWarner Losh 		if (gains != NULL)
98712e36acbSWarner Losh 			tbl_gain = gains->tbl_gain2;
98812e36acbSWarner Losh 		else
98912e36acbSWarner Losh 			tbl_gain = i;
99012e36acbSWarner Losh 		bwi_tbl_write_2(mac, tbl_gain_ofs2 + i, tbl_gain);
99112e36acbSWarner Losh 	}
99212e36acbSWarner Losh 
99312e36acbSWarner Losh 	if (gains == NULL || (gains != NULL && gains->phy_gain != -1)) {
99412e36acbSWarner Losh 		uint16_t phy_gain1, phy_gain2;
99512e36acbSWarner Losh 
99612e36acbSWarner Losh 		if (gains != NULL) {
99712e36acbSWarner Losh 			phy_gain1 =
99812e36acbSWarner Losh 			((uint16_t)gains->phy_gain << 14) |
99912e36acbSWarner Losh 			((uint16_t)gains->phy_gain << 6);
100012e36acbSWarner Losh 			phy_gain2 = phy_gain1;
100112e36acbSWarner Losh 		} else {
100212e36acbSWarner Losh 			phy_gain1 = 0x4040;
100312e36acbSWarner Losh 			phy_gain2 = 0x4000;
100412e36acbSWarner Losh 		}
100512e36acbSWarner Losh 		PHY_FILT_SETBITS(mac, 0x4a0, 0xbfbf, phy_gain1);
100612e36acbSWarner Losh 		PHY_FILT_SETBITS(mac, 0x4a1, 0xbfbf, phy_gain1);
100712e36acbSWarner Losh 		PHY_FILT_SETBITS(mac, 0x4a2, 0xbfbf, phy_gain2);
100812e36acbSWarner Losh 	}
100912e36acbSWarner Losh 	bwi_mac_dummy_xmit(mac);
101012e36acbSWarner Losh }
101112e36acbSWarner Losh 
101212e36acbSWarner Losh void
bwi_phy_clear_state(struct bwi_phy * phy)101312e36acbSWarner Losh bwi_phy_clear_state(struct bwi_phy *phy)
101412e36acbSWarner Losh {
101512e36acbSWarner Losh 	phy->phy_flags &= ~BWI_CLEAR_PHY_FLAGS;
101612e36acbSWarner Losh }
1017