Totally revamp the way that I program the synthesizer and baseband.

This commit is contained in:
dyoung 2004-07-15 07:19:46 +00:00
parent 3e1b8a977f
commit d1b1d2ead4
1 changed files with 135 additions and 133 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: atw.c,v 1.58 2004/07/15 07:13:44 dyoung Exp $ */
/* $NetBSD: atw.c,v 1.59 2004/07/15 07:19:46 dyoung Exp $ */
/*-
* Copyright (c) 1998, 1999, 2000, 2002, 2003, 2004 The NetBSD Foundation, Inc.
@ -41,7 +41,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: atw.c,v 1.58 2004/07/15 07:13:44 dyoung Exp $");
__KERNEL_RCSID(0, "$NetBSD: atw.c,v 1.59 2004/07/15 07:19:46 dyoung Exp $");
#include "bpfilter.h"
@ -135,15 +135,18 @@ __KERNEL_RCSID(0, "$NetBSD: atw.c,v 1.58 2004/07/15 07:13:44 dyoung Exp $");
*
*/
#define ATW_REFSLAVE /* slavishly do what the reference driver does */
#define VOODOO_DUR_11_ROUNDING 0x01 /* necessary */
#define VOODOO_DUR_2_4_SPECIALCASE 0x02 /* NOT necessary */
int atw_voodoo = VOODOO_DUR_11_ROUNDING;
int atw_rfio_enable_delay = 20 * 1000;
int atw_rfio_disable_delay = 2 * 1000;
int atw_writewep_delay = 5;
int atw_bbp_io_enable_delay = 20 * 1000;
int atw_bbp_io_disable_delay = 2 * 1000;
int atw_writewep_delay = 1000;
int atw_beacon_len_adjust = 4;
int atw_dwelltime = 200;
int atw_xindiv2 = 0;
#ifdef ATW_DEBUG
int atw_debug = 0;
@ -1266,15 +1269,15 @@ atw_init(struct ifnet *ifp)
* TBD support non-RFMD BBP, non-SiLabs synth.
*/
static void
atw_rfio_enable(struct atw_softc *sc, int enable)
atw_bbp_io_enable(struct atw_softc *sc, int enable)
{
if (enable) {
ATW_WRITE(sc, ATW_SYNRF,
ATW_SYNRF_SELRF|ATW_SYNRF_PE1|ATW_SYNRF_PHYRST);
DELAY(atw_rfio_enable_delay);
DELAY(atw_bbp_io_enable_delay);
} else {
ATW_WRITE(sc, ATW_SYNRF, 0);
DELAY(atw_rfio_disable_delay); /* shorter for some reason */
DELAY(atw_bbp_io_disable_delay); /* shorter for some reason */
}
}
@ -1282,8 +1285,7 @@ static int
atw_tune(struct atw_softc *sc)
{
int rc;
u_int32_t reg;
int chan;
u_int chan;
struct ieee80211com *ic = &sc->sc_ic;
chan = ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan);
@ -1298,16 +1300,14 @@ atw_tune(struct atw_softc *sc)
atw_idle(sc, ATW_NAR_SR|ATW_NAR_ST);
if ((rc = atw_si4126_tune(sc, chan)) != 0 ||
(rc = atw_rf3000_tune(sc, chan)) != 0)
atw_si4126_tune(sc, chan);
if ((rc = atw_rf3000_tune(sc, chan)) != 0)
printf("%s: failed to tune channel %d\n", sc->sc_dev.dv_xname,
chan);
reg = ATW_READ(sc, ATW_CAP0) & ~ATW_CAP0_CHN_MASK;
ATW_WRITE(sc, ATW_CAP0,
reg | LSHIFT(chan, ATW_CAP0_CHN_MASK));
ATW_WRITE(sc, ATW_NAR, sc->sc_opmode);
DELAY(20 * 1000);
ATW_WRITE(sc, ATW_RDR, 0x1);
if (rc == 0)
sc->sc_cur_chan = chan;
@ -1315,7 +1315,7 @@ atw_tune(struct atw_softc *sc)
return rc;
}
#ifdef ATW_DEBUG
#ifdef ATW_SYNDEBUG
static void
atw_si4126_print(struct atw_softc *sc)
{
@ -1334,7 +1334,7 @@ atw_si4126_print(struct atw_softc *sc)
printf("%05x\n", val);
}
}
#endif /* ATW_DEBUG */
#endif /* ATW_SYNDEBUG */
/* Tune to channel chan by adjusting the Si4126 RF/IF synthesizer.
*
@ -1353,18 +1353,17 @@ atw_si4126_print(struct atw_softc *sc)
* XINDIV2 = 1. I've tried this (it is necessary to double R) and it
* works, but I have still programmed for XINDIV2 = 1 to be safe.
*/
static int
atw_si4126_tune(struct atw_softc *sc, u_int8_t chan)
static void
atw_si4126_tune(struct atw_softc *sc, u_int chan)
{
int rc = 0;
u_int mhz;
u_int R;
u_int32_t reg;
u_int32_t gpio;
u_int16_t gain;
#ifdef ATW_DEBUG
#ifdef ATW_SYNDEBUG
atw_si4126_print(sc);
#endif /* ATW_DEBUG */
#endif /* ATW_SYNDEBUG */
if (chan == 14)
mhz = 2484;
@ -1380,94 +1379,101 @@ atw_si4126_tune(struct atw_softc *sc, u_int8_t chan)
* strictly necessary.
*/
R = 44;
atw_rfio_enable(sc, 1);
if (atw_xindiv2)
R = 44;
else
R = 88;
/* Power-up RF, IF synthesizers. */
if ((rc = atw_si4126_write(sc, SI4126_POWER,
SI4126_POWER_PDIB|SI4126_POWER_PDRB)) != 0)
goto out;
/* If RF2 N > 2047, then set KP2 to 1. */
gain = LSHIFT(((mhz - 374) > 2047) ? 1 : 0, SI4126_GAIN_KP2_MASK);
if ((rc = atw_si4126_write(sc, SI4126_GAIN, gain)) != 0)
goto out;
atw_si4126_write(sc, SI4126_POWER,
SI4126_POWER_PDIB|SI4126_POWER_PDRB);
/* set LPWR, too? */
if ((rc = atw_si4126_write(sc, SI4126_MAIN,
SI4126_MAIN_XINDIV2)) != 0)
goto out;
atw_si4126_write(sc, SI4126_MAIN,
(atw_xindiv2) ? SI4126_MAIN_XINDIV2 : 0);
/* We set XINDIV2 = 1, so IF = N/(2 * R) * XIN. XIN = 44MHz.
* I choose N = 1496, R = 44 so that 1496/(2 * 44) * 44MHz = 748MHz.
/* Set the phase-locked loop gain. If RF2 N > 2047, then
* set KP2 to 1.
*
* REFDIF This is different from the reference driver, which
* always sets SI4126_GAIN to 0.
*/
if ((rc = atw_si4126_write(sc, SI4126_IFN, 1496)) != 0)
goto out;
gain = LSHIFT(((mhz - 374) > 2047) ? 1 : 0, SI4126_GAIN_KP2_MASK);
if ((rc = atw_si4126_write(sc, SI4126_IFR, R)) != 0)
goto out;
atw_si4126_write(sc, SI4126_GAIN, gain);
/* XIN = 44MHz.
*
* If XINDIV2 = 1, IF = N/(2 * R) * XIN. I choose N = 1496,
* R = 44 so that 1496/(2 * 44) * 44MHz = 748MHz.
*
* If XINDIV2 = 0, IF = N/R * XIN. I choose N = 1496, R = 88
* so that 1496/88 * 44MHz = 748MHz.
*/
atw_si4126_write(sc, SI4126_IFN, 1496);
atw_si4126_write(sc, SI4126_IFR, R);
#ifndef ATW_REFSLAVE
/* Set RF1 arbitrarily. DO NOT configure RF1 after RF2, because
* then RF1 becomes the active RF synthesizer, even on the Si4126,
* which has no RF1!
*/
if ((rc = atw_si4126_write(sc, SI4126_RF1R, R)) != 0)
goto out;
atw_si4126_write(sc, SI4126_RF1R, R);
if ((rc = atw_si4126_write(sc, SI4126_RF1N, mhz - 374)) != 0)
goto out;
atw_si4126_write(sc, SI4126_RF1N, mhz - 374);
#endif
/* N/R * XIN = RF. XIN = 44MHz. We desire RF = mhz - IF,
* where IF = 374MHz. Let's divide XIN to 1MHz. So R = 44.
* Now let's multiply it to mhz. So mhz - IF = N.
*/
if ((rc = atw_si4126_write(sc, SI4126_RF2R, R)) != 0)
goto out;
atw_si4126_write(sc, SI4126_RF2R, R);
if ((rc = atw_si4126_write(sc, SI4126_RF2N, mhz - 374)) != 0)
goto out;
atw_si4126_write(sc, SI4126_RF2N, mhz - 374);
/* wait 100us from power-up for RF, IF to settle */
DELAY(100);
if ((sc->sc_if.if_flags & IFF_LINK1) == 0 || chan == 14) {
/* XXX there is a binary driver which sends
* ATW_GPIO_EN_MASK = 1, ATW_GPIO_O_MASK = 1. I had speculated
* that this enables the Si4126 by raising its PWDN#, but I
* think that it actually sets the Prism RF front-end
* to a special mode for channel 14.
gpio = ATW_READ(sc, ATW_GPIO);
gpio &= ~(ATW_GPIO_EN_MASK|ATW_GPIO_O_MASK|ATW_GPIO_I_MASK);
gpio |= LSHIFT(1, ATW_GPIO_EN_MASK);
if ((sc->sc_if.if_flags & IFF_LINK1) != 0 && chan != 14) {
/* Set a Prism RF front-end to a special mode for channel 14?
*
* Apparently the SMC2635W needs this, although I don't think
* it has a Prism RF.
*/
reg = ATW_READ(sc, ATW_GPIO);
reg &= ~(ATW_GPIO_EN_MASK|ATW_GPIO_O_MASK|ATW_GPIO_I_MASK);
reg |= LSHIFT(1, ATW_GPIO_EN_MASK) | LSHIFT(1, ATW_GPIO_O_MASK);
ATW_WRITE(sc, ATW_GPIO, reg);
gpio |= LSHIFT(1, ATW_GPIO_O_MASK);
}
ATW_WRITE(sc, ATW_GPIO, gpio);
#ifdef ATW_DEBUG
#ifdef ATW_SYNDEBUG
atw_si4126_print(sc);
#endif /* ATW_DEBUG */
out:
atw_rfio_enable(sc, 0);
return rc;
#endif /* ATW_SYNDEBUG */
}
/* Baseline initialization of RF3000 BBP: set CCA mode and enable antenna
* diversity.
*
* Call this w/ Tx/Rx suspended.
* !!!
* !!! Call this w/ Tx/Rx suspended, atw_idle(, ATW_NAR_ST|ATW_NAR_SR).
* !!!
*/
static int
atw_rf3000_init(struct atw_softc *sc)
{
int rc = 0;
atw_idle(sc, ATW_NAR_SR|ATW_NAR_ST);
atw_bbp_io_enable(sc, 1);
atw_rfio_enable(sc, 1);
/* CCA is acquisition sensitive */
rc = atw_rf3000_write(sc, RF3000_CCACTL,
LSHIFT(RF3000_CCACTL_MODE_BOTH, RF3000_CCACTL_MODE_MASK));
if (rc != 0)
goto out;
/* enable diversity */
rc = atw_rf3000_write(sc, RF3000_DIVCTL, RF3000_DIVCTL_ENABLE);
@ -1494,6 +1500,12 @@ atw_rf3000_init(struct atw_softc *sc)
if (rc != 0)
goto out;
/* XXX Reference driver remarks that Abocom sets this to 50.
* Meaning 0x50, I think.... 50 = 0x32, which would set a bit
* in the "reserved" area of register RF3000_OPTIONS1.
*
* EEPROMs for the ADM8211B contain a setting for this register.
*/
rc = atw_rf3000_write(sc, RF3000_OPTIONS1, 0x0);
if (rc != 0)
@ -1504,20 +1516,12 @@ atw_rf3000_init(struct atw_softc *sc)
if (rc != 0)
goto out;
/* CCA is acquisition sensitive */
rc = atw_rf3000_write(sc, RF3000_CCACTL,
LSHIFT(RF3000_CCACTL_MODE_ACQ, RF3000_CCACTL_MODE_MASK));
if (rc != 0)
goto out;
out:
atw_rfio_enable(sc, 0);
ATW_WRITE(sc, ATW_NAR, sc->sc_opmode);
atw_bbp_io_enable(sc, 0);
return rc;
}
#ifdef ATW_DEBUG
#ifdef ATW_BBPDEBUG
static void
atw_rf3000_print(struct atw_softc *sc)
{
@ -1536,11 +1540,11 @@ atw_rf3000_print(struct atw_softc *sc)
printf("%08x\n", val);
}
}
#endif /* ATW_DEBUG */
#endif /* ATW_BBPDEBUG */
/* Set the power settings on the BBP for channel `chan'. */
static int
atw_rf3000_tune(struct atw_softc *sc, u_int8_t chan)
atw_rf3000_tune(struct atw_softc *sc, u_int chan)
{
int rc = 0;
u_int32_t reg;
@ -1561,15 +1565,15 @@ atw_rf3000_tune(struct atw_softc *sc, u_int8_t chan)
lna_gs_thresh >>= 8;
}
#ifdef ATW_DEBUG
#ifdef ATW_BBPDEBUG
atw_rf3000_print(sc);
#endif /* ATW_DEBUG */
#endif /* ATW_BBPDEBUG */
DPRINTF(sc, ("%s: chan %d txpower %02x, lpf_cutoff %02x, "
"lna_gs_thresh %02x\n",
sc->sc_dev.dv_xname, chan, txpower, lpf_cutoff, lna_gs_thresh));
atw_rfio_enable(sc, 1);
atw_bbp_io_enable(sc, 1);
if ((rc = atw_rf3000_write(sc, RF3000_GAINCTL,
LSHIFT(txpower, RF3000_GAINCTL_TXVGC_MASK))) != 0)
@ -1581,19 +1585,30 @@ atw_rf3000_tune(struct atw_softc *sc, u_int8_t chan)
if ((rc = atw_rf3000_write(sc, RF3000_HIGAINCAL, lna_gs_thresh)) != 0)
goto out;
/* from a binary-only driver. */
rc = atw_rf3000_write(sc, RF3000_OPTIONS1, 0x0);
if (rc != 0)
goto out;
rc = atw_rf3000_write(sc, RF3000_OPTIONS2, RF3000_OPTIONS2_LNAGS_DELAY);
if (rc != 0)
goto out;
#ifdef ATW_BBPDEBUG
atw_rf3000_print(sc);
#endif /* ATW_BBPDEBUG */
out:
atw_bbp_io_enable(sc, 0);
/* set beacon, rts, atim transmit power */
reg = ATW_READ(sc, ATW_PLCPHD);
reg &= ~ATW_PLCPHD_SERVICE_MASK;
reg |= LSHIFT(LSHIFT(txpower, RF3000_GAINCTL_TXVGC_MASK),
ATW_PLCPHD_SERVICE_MASK);
ATW_WRITE(sc, ATW_PLCPHD, reg);
#ifdef ATW_DEBUG
atw_rf3000_print(sc);
#endif /* ATW_DEBUG */
out:
atw_rfio_enable(sc, 0);
DELAY(2 * 1000);
return rc;
}
@ -1640,7 +1655,7 @@ atw_rf3000_write(struct atw_softc *sc, u_int addr, u_int val)
* of the magic I have derived from a binary-only driver concerns
* the "chip address" (see the RF3000 manual).
*/
#ifdef ATW_DEBUG
#ifdef ATW_BBPDEBUG
static int
atw_rf3000_read(struct atw_softc *sc, u_int addr, u_int *val)
{
@ -1680,7 +1695,7 @@ atw_rf3000_read(struct atw_softc *sc, u_int addr, u_int *val)
*val = MASK_AND_RSHIFT(reg, ATW_BBPCTL_DATA_MASK);
return 0;
}
#endif /* ATW_DEBUG */
#endif /* ATW_BBPDEBUG */
/* Write a register on the Si4126 RF/IF synthesizer using the registers
* provided by the ADM8211 for that purpose.
@ -1689,49 +1704,36 @@ atw_rf3000_read(struct atw_softc *sc, u_int addr, u_int *val)
*
* Return 0 on success.
*/
static int
static void
atw_si4126_write(struct atw_softc *sc, u_int addr, u_int val)
{
u_int32_t bits, reg;
int i;
uint32_t bits, mask, reg;
const int nbits = 22;
KASSERT((addr & ~PRESHIFT(SI4126_TWI_ADDR_MASK)) == 0);
KASSERT((val & ~PRESHIFT(SI4126_TWI_DATA_MASK)) == 0);
for (i = 1000; --i >= 0; ) {
if (ATW_ISSET(sc, ATW_SYNCTL, ATW_SYNCTL_RD|ATW_SYNCTL_WR) == 0)
break;
DELAY(100);
}
if (i < 0) {
printf("%s: start atw_si4126_write, SYNCTL busy\n",
sc->sc_dev.dv_xname);
return ETIMEDOUT;
}
bits = LSHIFT(val, SI4126_TWI_DATA_MASK) |
LSHIFT(addr, SI4126_TWI_ADDR_MASK);
reg = sc->sc_synctl_wr | LSHIFT(bits, ATW_SYNCTL_DATA_MASK);
reg = ATW_SYNRF_SELSYN;
/* reference driver: reset Si4126 serial bus to initial
* conditions?
*/
ATW_WRITE(sc, ATW_SYNRF, reg | ATW_SYNRF_LEIF);
ATW_WRITE(sc, ATW_SYNRF, reg);
ATW_WRITE(sc, ATW_SYNCTL, reg);
for (i = 1000; --i >= 0; ) {
DELAY(100);
if (ATW_ISSET(sc, ATW_SYNCTL, ATW_SYNCTL_WR) == 0)
break;
for (mask = BIT(nbits - 1); mask != 0; mask >>= 1) {
if ((bits & mask) != 0)
reg |= ATW_SYNRF_SYNDATA;
else
reg &= ~ATW_SYNRF_SYNDATA;
ATW_WRITE(sc, ATW_SYNRF, reg);
ATW_WRITE(sc, ATW_SYNRF, reg | ATW_SYNRF_SYNCLK);
ATW_WRITE(sc, ATW_SYNRF, reg);
}
/* restore to acceptable starting condition */
ATW_CLR(sc, ATW_SYNCTL, ATW_SYNCTL_WR);
if (i < 0) {
printf("%s: atw_si4126_write wrote %08x, SYNCTL still busy\n",
sc->sc_dev.dv_xname, reg);
return ETIMEDOUT;
}
return 0;
ATW_WRITE(sc, ATW_SYNRF, reg | ATW_SYNRF_LEIF);
ATW_WRITE(sc, ATW_SYNRF, 0x0);
}
/* Read 18-bit data from the 4-bit address addr in Si4126
@ -1740,7 +1742,7 @@ atw_si4126_write(struct atw_softc *sc, u_int addr, u_int val)
* XXX This does not seem to work. The ADM8211 must require more or
* different magic to read the chip than to write it.
*/
#ifdef ATW_DEBUG
#ifdef ATW_SYNDEBUG
static int
atw_si4126_read(struct atw_softc *sc, u_int addr, u_int *val)
{
@ -1774,7 +1776,7 @@ atw_si4126_read(struct atw_softc *sc, u_int addr, u_int *val)
ATW_CLR(sc, ATW_SYNCTL, ATW_SYNCTL_RD);
if (i < 0) {
printf("%s: atw_si4126_read wrote %08x, SYNCTL still busy\n",
printf("%s: atw_si4126_read wrote %#08x, SYNCTL still busy\n",
sc->sc_dev.dv_xname, reg);
return ETIMEDOUT;
}
@ -1783,7 +1785,7 @@ atw_si4126_read(struct atw_softc *sc, u_int addr, u_int *val)
ATW_SYNCTL_DATA_MASK);
return 0;
}
#endif /* ATW_DEBUG */
#endif /* ATW_SYNDEBUG */
/* XXX is the endianness correct? test. */
#define atw_calchash(addr) \