diff --git a/sys/dev/ic/atw.c b/sys/dev/ic/atw.c index b98942c941f8..111061bc0c34 100644 --- a/sys/dev/ic/atw.c +++ b/sys/dev/ic/atw.c @@ -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 -__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) \