Skip to content
Snippets Groups Projects
phy_n.c 94.3 KiB
Newer Older
  • Learn to ignore specific revisions
  • int b43_phy_initn(struct b43_wldev *dev)
    {
    
    	struct ssb_bus *bus = dev->dev->bus;
    
    	struct b43_phy *phy = &dev->phy;
    
    	struct b43_phy_n *nphy = phy->n;
    	u8 tx_pwr_state;
    	struct nphy_txgains target;
    
    	u16 tmp;
    
    	enum ieee80211_band tmp2;
    	bool do_rssi_cal;
    
    	u16 clip[2];
    	bool do_cal = false;
    
    	if ((dev->phy.rev >= 3) &&
    	   (bus->sprom.boardflags_lo & B43_BFL_EXTLNA) &&
    	   (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)) {
    		chipco_set32(&dev->dev->bus->chipco, SSB_CHIPCO_CHIPCTL, 0x40);
    	}
    	nphy->deaf_count = 0;
    
    	b43_nphy_tables_init(dev);
    
    	nphy->crsminpwr_adjusted = false;
    	nphy->noisevars_adjusted = false;
    
    
    	/* Clear all overrides */
    
    	if (dev->phy.rev >= 3) {
    		b43_phy_write(dev, B43_NPHY_TXF_40CO_B1S1, 0);
    		b43_phy_write(dev, B43_NPHY_RFCTL_OVER, 0);
    		b43_phy_write(dev, B43_NPHY_TXF_40CO_B1S0, 0);
    		b43_phy_write(dev, B43_NPHY_TXF_40CO_B32S1, 0);
    	} else {
    		b43_phy_write(dev, B43_NPHY_RFCTL_OVER, 0);
    	}
    
    	b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, 0);
    	b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, 0);
    
    	if (dev->phy.rev < 6) {
    		b43_phy_write(dev, B43_NPHY_RFCTL_INTC3, 0);
    		b43_phy_write(dev, B43_NPHY_RFCTL_INTC4, 0);
    	}
    
    	b43_phy_mask(dev, B43_NPHY_RFSEQMODE,
    		     ~(B43_NPHY_RFSEQMODE_CAOVER |
    		       B43_NPHY_RFSEQMODE_TROVER));
    
    	if (dev->phy.rev >= 3)
    		b43_phy_write(dev, B43_NPHY_AFECTL_OVER1, 0);
    
    	b43_phy_write(dev, B43_NPHY_AFECTL_OVER, 0);
    
    
    	if (dev->phy.rev <= 2) {
    		tmp = (dev->phy.rev == 2) ? 0x3B : 0x40;
    		b43_phy_maskset(dev, B43_NPHY_BPHY_CTL3,
    				~B43_NPHY_BPHY_CTL3_SCALE,
    				tmp << B43_NPHY_BPHY_CTL3_SCALE_SHIFT);
    	}
    
    	b43_phy_write(dev, B43_NPHY_AFESEQ_TX2RX_PUD_20M, 0x20);
    	b43_phy_write(dev, B43_NPHY_AFESEQ_TX2RX_PUD_40M, 0x20);
    
    
    	if (bus->sprom.boardflags2_lo & 0x100 ||
    	    (bus->boardinfo.vendor == PCI_VENDOR_ID_APPLE &&
    	     bus->boardinfo.type == 0x8B))
    		b43_phy_write(dev, B43_NPHY_TXREALFD, 0xA0);
    	else
    		b43_phy_write(dev, B43_NPHY_TXREALFD, 0xB8);
    	b43_phy_write(dev, B43_NPHY_MIMO_CRSTXEXT, 0xC8);
    	b43_phy_write(dev, B43_NPHY_PLOAD_CSENSE_EXTLEN, 0x50);
    	b43_phy_write(dev, B43_NPHY_TXRIFS_FRDEL, 0x30);
    
    	b43_nphy_update_mimo_config(dev, nphy->preamble_override);
    
    	b43_nphy_update_txrx_chain(dev);
    
    
    	if (phy->rev < 2) {
    		b43_phy_write(dev, B43_NPHY_DUP40_GFBL, 0xAA8);
    		b43_phy_write(dev, B43_NPHY_DUP40_BL, 0x9A4);
    	}
    
    
    	tmp2 = b43_current_band(dev->wl);
    	if ((nphy->ipa2g_on && tmp2 == IEEE80211_BAND_2GHZ) ||
    	    (nphy->ipa5g_on && tmp2 == IEEE80211_BAND_5GHZ)) {
    		b43_phy_set(dev, B43_NPHY_PAPD_EN0, 0x1);
    		b43_phy_maskset(dev, B43_NPHY_EPS_TABLE_ADJ0, 0x007F,
    				nphy->papd_epsilon_offset[0] << 7);
    		b43_phy_set(dev, B43_NPHY_PAPD_EN1, 0x1);
    		b43_phy_maskset(dev, B43_NPHY_EPS_TABLE_ADJ1, 0x007F,
    				nphy->papd_epsilon_offset[1] << 7);
    
    		b43_nphy_int_pa_set_tx_dig_filters(dev);
    
    	} else if (phy->rev >= 5) {
    
    		b43_nphy_ext_pa_set_tx_dig_filters(dev);
    
    	b43_nphy_workarounds(dev);
    
    
    	/* Reset CCA, in init code it differs a little from standard way */
    
    	b43_nphy_bmac_clock_fgc(dev, 1);
    
    	tmp = b43_phy_read(dev, B43_NPHY_BBCFG);
    	b43_phy_write(dev, B43_NPHY_BBCFG, tmp | B43_NPHY_BBCFG_RSTCCA);
    	b43_phy_write(dev, B43_NPHY_BBCFG, tmp & ~B43_NPHY_BBCFG_RSTCCA);
    
    	b43_nphy_bmac_clock_fgc(dev, 0);
    
    
    	/* TODO N PHY MAC PHY Clock Set with argument 1 */
    
    
    	b43_nphy_pa_override(dev, false);
    
    	b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RX2TX);
    	b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX);
    
    	b43_nphy_pa_override(dev, true);
    
    	b43_nphy_classifier(dev, 0, 0);
    	b43_nphy_read_clip_detection(dev, clip);
    
    	tx_pwr_state = nphy->txpwrctrl;
    	/* TODO N PHY TX power control with argument 0
    		(turning off power control) */
    	/* TODO Fix the TX Power Settings */
    	/* TODO N PHY TX Power Control Idle TSSI */
    	/* TODO N PHY TX Power Control Setup */
    
    	if (phy->rev >= 3) {
    		/* TODO */
    	} else {
    
    		b43_ntab_write_bulk(dev, B43_NTAB32(26, 192), 128,
    					b43_ntab_tx_gain_rev0_1_2);
    		b43_ntab_write_bulk(dev, B43_NTAB32(27, 192), 128,
    					b43_ntab_tx_gain_rev0_1_2);
    
    	if (nphy->phyrxchain != 3)
    		;/* TODO N PHY RX Core Set State with phyrxchain as argument */
    	if (nphy->mphase_cal_phase_id > 0)
    		;/* TODO PHY Periodic Calibration Multi-Phase Restart */
    
    	do_rssi_cal = false;
    	if (phy->rev >= 3) {
    		if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
    			do_rssi_cal = (nphy->rssical_chanspec_2G == 0);
    		else
    			do_rssi_cal = (nphy->rssical_chanspec_5G == 0);
    
    		if (do_rssi_cal)
    
    			b43_nphy_restore_rssi_cal(dev);
    
    	}
    
    	if (!((nphy->measure_hold & 0x6) != 0)) {
    		if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
    			do_cal = (nphy->iqcal_chanspec_2G == 0);
    		else
    			do_cal = (nphy->iqcal_chanspec_5G == 0);
    
    		if (nphy->mute)
    			do_cal = false;
    
    		if (do_cal) {
    
    			target = b43_nphy_get_tx_gains(dev);
    
    				b43_nphy_superswitch_init(dev, true);
    
    			if (nphy->perical != 2) {
    
    				b43_nphy_rssi_cal(dev);
    
    				if (phy->rev >= 3) {
    					nphy->cal_orig_pwr_idx[0] =
    					    nphy->txpwrindex[0].index_internal;
    					nphy->cal_orig_pwr_idx[1] =
    					    nphy->txpwrindex[1].index_internal;
    					/* TODO N PHY Pre Calibrate TX Gain */
    
    					target = b43_nphy_get_tx_gains(dev);
    
    				}
    			}
    		}
    	}
    
    	if (!b43_nphy_cal_tx_iq_lo(dev, target, true, false)) {
    		if (b43_nphy_cal_rx_iq(dev, target, 2, 0) == 0)
    
    			b43_nphy_save_cal(dev);
    
    		else if (nphy->mphase_cal_phase_id == 0)
    
    			;/* N PHY Periodic Calibration with argument 3 */
    
    	b43_nphy_tx_pwr_ctrl_coef_setup(dev);
    
    	/* TODO N PHY TX Power Control Enable with argument tx_pwr_state */
    	b43_phy_write(dev, B43_NPHY_TXMACIF_HOLDOFF, 0x0015);
    	b43_phy_write(dev, B43_NPHY_TXMACDELAY, 0x0320);
    	if (phy->rev >= 3 && phy->rev <= 6)
    		b43_phy_write(dev, B43_NPHY_PLOAD_CSENSE_EXTLEN, 0x0014);
    
    	b43_nphy_tx_lp_fbw(dev);
    
    	if (phy->rev >= 3)
    		b43_nphy_spur_workaround(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;
    
    	return 0;
    }
    
    
    static void b43_nphy_op_prepare_structs(struct b43_wldev *dev)
    
    	struct b43_phy *phy = &dev->phy;
    	struct b43_phy_n *nphy = phy->n;
    
    	memset(nphy, 0, sizeof(*nphy));
    
    	//TODO init struct b43_phy_n
    
    static void b43_nphy_op_free(struct b43_wldev *dev)
    
    	struct b43_phy *phy = &dev->phy;
    	struct b43_phy_n *nphy = phy->n;
    
    	phy->n = NULL;
    }
    
    static int b43_nphy_op_init(struct b43_wldev *dev)
    {
    	return b43_phy_initn(dev);
    
    }
    
    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);
    }
    
    
    /* http://bcm-v4.sipsolutions.net/802.11/Radio/Switch%20Radio */
    
    static void b43_nphy_op_software_rfkill(struct b43_wldev *dev,
    
    Johannes Berg's avatar
    Johannes Berg committed
    					bool blocked)
    
    {
    	if (b43_read32(dev, B43_MMIO_MACCTL) & B43_MACCTL_ENABLED)
    		b43err(dev->wl, "MAC not suspended\n");
    
    	if (blocked) {
    		b43_phy_mask(dev, B43_NPHY_RFCTL_CMD,
    				~B43_NPHY_RFCTL_CMD_CHIP0PU);
    		if (dev->phy.rev >= 3) {
    			b43_radio_mask(dev, 0x09, ~0x2);
    
    			b43_radio_write(dev, 0x204D, 0);
    			b43_radio_write(dev, 0x2053, 0);
    			b43_radio_write(dev, 0x2058, 0);
    			b43_radio_write(dev, 0x205E, 0);
    			b43_radio_mask(dev, 0x2062, ~0xF0);
    			b43_radio_write(dev, 0x2064, 0);
    
    			b43_radio_write(dev, 0x304D, 0);
    			b43_radio_write(dev, 0x3053, 0);
    			b43_radio_write(dev, 0x3058, 0);
    			b43_radio_write(dev, 0x305E, 0);
    			b43_radio_mask(dev, 0x3062, ~0xF0);
    			b43_radio_write(dev, 0x3064, 0);
    		}
    	} else {
    		if (dev->phy.rev >= 3) {
    			/* TODO: b43_radio_init2056(dev); */
    			/* TODO: PHY Set Channel Spec (dev, radio_chanspec) */
    		} else {
    			b43_radio_init2055(dev);
    		}
    	}
    
    static void b43_nphy_op_switch_analog(struct b43_wldev *dev, bool on)
    {
    	b43_phy_write(dev, B43_NPHY_AFECTL_OVER,
    		      on ? 0 : 0x7FFF);
    }
    
    
    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;
    }
    
    const struct b43_phy_operations b43_phyops_n = {
    	.allocate		= b43_nphy_op_allocate,
    
    	.free			= b43_nphy_op_free,
    	.prepare_structs	= b43_nphy_op_prepare_structs,
    
    	.init			= b43_nphy_op_init,
    	.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_analog		= b43_nphy_op_switch_analog,
    
    	.switch_channel		= b43_nphy_op_switch_channel,
    	.get_default_chan	= b43_nphy_op_get_default_chan,
    
    	.recalc_txpower		= b43_nphy_op_recalc_txpower,
    	.adjust_txpower		= b43_nphy_op_adjust_txpower,