summaryrefslogtreecommitdiff
path: root/sys/dev/ic
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/ic')
-rw-r--r--sys/dev/ic/bcw.c361
-rw-r--r--sys/dev/ic/bcwreg.h3
-rw-r--r--sys/dev/ic/bcwvar.h8
3 files changed, 345 insertions, 27 deletions
diff --git a/sys/dev/ic/bcw.c b/sys/dev/ic/bcw.c
index 659a2e436c6..096f8babd01 100644
--- a/sys/dev/ic/bcw.c
+++ b/sys/dev/ic/bcw.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: bcw.c,v 1.37 2007/02/18 00:05:39 mglocker Exp $ */
+/* $OpenBSD: bcw.c,v 1.38 2007/02/18 09:37:21 mglocker Exp $ */
/*
* Copyright (c) 2006 Jon Simola <jsimola@gmail.com>
@@ -117,6 +117,11 @@ int bcw_load_initvals(struct bcw_softc *);
void bcw_leds_switch_all(struct bcw_softc *, int);
int bcw_gpio_init(struct bcw_softc *);
+int bcw_phy_init(struct bcw_softc *);
+void bcw_phy_initg(struct bcw_softc *);
+void bcw_phy_initb5(struct bcw_softc *);
+void bcw_phy_initb6(struct bcw_softc *);
+
struct cfdriver bcw_cd = {
NULL, "bcw", DV_IFNET
};
@@ -164,12 +169,12 @@ bcw_radio_read16(struct bcw_softc *sc, uint16_t offset)
offset |= 0x0040;
break;
case BCW_PHY_TYPEB:
- if (sc->sc_radiotype == 0x2053) {
+ if (sc->sc_radio_ver == 0x2053) {
if (offset < 0x70)
offset += 0x80;
else if (offset < 0x80)
offset += 0x70;
- } else if (sc->sc_radiotype == 0x2050)
+ } else if (sc->sc_radio_ver == 0x2050)
offset |= 0x80;
else
return (0);
@@ -446,26 +451,26 @@ bcw_attach(struct bcw_softc *sc)
sbval = BCW_READ16(sc, BCW_RADIO_DATAHIGH);
sbval <<= 16;
BCW_WRITE16(sc, BCW_RADIO_CONTROL, BCW_RADIO_ID);
- sc->sc_radioid = sbval | BCW_READ16(sc, BCW_RADIO_DATALOW);
+ sc->sc_radio_mnf = sbval | BCW_READ16(sc, BCW_RADIO_DATALOW);
} else {
switch (sc->sc_chiprev) {
case 0:
- sc->sc_radioid = 0x3205017F;
+ sc->sc_radio_mnf = 0x3205017F;
break;
case 1:
- sc->sc_radioid = 0x4205017f;
+ sc->sc_radio_mnf = 0x4205017f;
break;
default:
- sc->sc_radioid = 0x5205017f;
+ sc->sc_radio_mnf = 0x5205017f;
}
}
- sc->sc_radiorev = (sc->sc_radioid & 0xf0000000) >> 28;
- sc->sc_radiotype = (sc->sc_radioid & 0x0ffff000) >> 12;
+ sc->sc_radio_rev = (sc->sc_radio_mnf & 0xf0000000) >> 28;
+ sc->sc_radio_ver = (sc->sc_radio_mnf & 0x0ffff000) >> 12;
DPRINTF(("%s: Radio Rev %d, Ver 0x%x, Manuf 0x%x\n",
- sc->sc_dev.dv_xname, sc->sc_radiorev, sc->sc_radiotype,
- sc->sc_radioid & 0xfff));
+ sc->sc_dev.dv_xname, sc->sc_radio_rev, sc->sc_radio_ver,
+ sc->sc_radio_mnf & 0xfff));
error = bcw_validatechipaccess(sc);
if (error) {
@@ -519,21 +524,21 @@ bcw_attach(struct bcw_softc *sc)
/* test for valid radio revisions */
if ((sc->sc_phy_type == BCW_PHY_TYPEA) &
- (sc->sc_radiotype != 0x2060)) {
+ (sc->sc_radio_ver != 0x2060)) {
printf("%s: invalid PHY A radio 0x%x\n",
- sc->sc_dev.dv_xname, sc->sc_radiotype);
+ sc->sc_dev.dv_xname, sc->sc_radio_ver);
return;
}
if ((sc->sc_phy_type == BCW_PHY_TYPEB) &
- ((sc->sc_radiotype & 0xfff0) != 0x2050)) {
+ ((sc->sc_radio_ver & 0xfff0) != 0x2050)) {
printf("%s: invalid PHY B radio 0x%x\n",
- sc->sc_dev.dv_xname, sc->sc_radiotype);
+ sc->sc_dev.dv_xname, sc->sc_radio_ver);
return;
}
if ((sc->sc_phy_type == BCW_PHY_TYPEG) &
- (sc->sc_radiotype != 0x2050)) {
+ (sc->sc_radio_ver != 0x2050)) {
printf("%s: invalid PHY G radio 0x%x\n",
- sc->sc_dev.dv_xname, sc->sc_radiotype);
+ sc->sc_dev.dv_xname, sc->sc_radio_ver);
return;
}
@@ -590,8 +595,8 @@ bcw_attach(struct bcw_softc *sc)
sbval |= 0x400;
if (sc->sc_phy_type == BCW_PHY_TYPEB)
sbval |= 0x4;
- if ((sc->sc_radiotype == 0x2050) &&
- (sc->sc_radiorev <= 5))
+ if ((sc->sc_radio_ver == 0x2050) &&
+ (sc->sc_radio_rev <= 5))
sbval |= 0x40000;
/*
* XXX If the device isn't up and this is a PCI bus with revision
@@ -1225,6 +1230,8 @@ bcw_init(struct ifnet *ifp)
bcw_radio_on(sc);
BCW_WRITE16(sc, 0x03e6, 0);
+ //if ((error = bcw_phy_init(sc)))
+ //return (error);
return (0);
@@ -2216,8 +2223,8 @@ bcw_radio_channel(struct bcw_softc *sc, uint8_t channel, int spw)
if (freq >= 4920 && freq <= 5500)
r8 = 3 * freq / 116;
- if (sc->sc_radioid == 0x17f && sc->sc_radiotype == 0x2060 &&
- sc->sc_radiorev == 1) {
+ if (sc->sc_radio_mnf == 0x17f && sc->sc_radio_ver == 0x2060 &&
+ sc->sc_radio_rev == 1) {
bcw_radio_write16(sc, 0x0007, (r8 << 4) | r8);
bcw_radio_write16(sc, 0x0020, (r8 << 4) | r8);
bcw_radio_write16(sc, 0x0021, (r8 << 4) | r8);
@@ -2262,7 +2269,7 @@ bcw_radio_channel(struct bcw_softc *sc, uint8_t channel, int spw)
void
bcw_spw(struct bcw_softc *sc, uint8_t channel)
{
- if (sc->sc_radiotype != 0x2050 || sc->sc_radiorev >= 6)
+ if (sc->sc_radio_ver != 0x2050 || sc->sc_radio_rev >= 6)
/* we do not need the workaround */
return;
@@ -2740,3 +2747,313 @@ bcw_gpio_init(struct bcw_softc *sc)
return (0);
}
+
+/*
+ * PHY
+ */
+int
+bcw_phy_init(struct bcw_softc *sc)
+{
+ int error = ENODEV;
+
+ switch (sc->sc_phy_type) {
+ case BCW_PHY_TYPEA:
+ if (sc->sc_phy_rev == 2 || sc->sc_phy_rev == 3) {
+ error = 0;
+ }
+ break;
+ case BCW_PHY_TYPEB:
+ switch (sc->sc_phy_rev) {
+ case 2:
+ // bcw_phy_initb2(sc);
+ error = 0;
+ break;
+ case 4:
+ // bcw_phy_initb4(sc);
+ error = 0;
+ break;
+ case 5:
+ // bcw_phy_initb5(sc);
+ error = 0;
+ break;
+ case 6:
+ // bcw_phy_initb6(sc);
+ error = 0;
+ break;
+ }
+ break;
+ case BCW_PHY_TYPEG:
+ // bcw_phy_initg(sc);
+ error = 0;
+ break;
+ }
+
+ if (error)
+ printf("%s: Unknown PHYTYPE found!\n", sc->sc_dev.dv_xname);
+
+ return (error);
+}
+
+void
+bcw_phy_initg(struct bcw_softc *sc)
+{
+ if (sc->sc_phy_rev == 1)
+ bcw_phy_initb5(sc);
+ else
+ bcw_phy_initb6(sc);
+}
+
+void
+bcw_phy_initb5(struct bcw_softc *sc)
+{
+ uint16_t offset;
+
+ if (sc->sc_phy_rev == 1 && sc->sc_radio_rev == 0x2050)
+ bcw_radio_write16(sc, 0x007a, bcw_radio_read16(sc, 0x007a) |
+ 0x0050);
+
+ if (1) { /* XXX bcw->board_vendor */
+ for (offset = 0x00a8; offset < 0x00c7; offset++)
+ bcw_phy_write16(sc, offset,
+ (bcw_phy_read16(sc, offset) + 0x02020) & 0x3f3f);
+ }
+
+ bcw_phy_write16(sc, 0x0035, (bcw_phy_read16(sc, 0x0035) & 0xf0ff) |
+ 0x0700);
+
+ if (sc->sc_radio_rev == 0x2050)
+ bcw_phy_write16(sc, 0x0038, 0x0667);
+
+ if (1) { /* XXX phy->connected */
+ if (sc->sc_radio_rev == 0x2050) {
+ bcw_radio_write16(sc, 0x007a,
+ bcw_radio_read16(sc, 0x007a) | 0x0020);
+ bcw_radio_write16(sc, 0x0051,
+ bcw_radio_read16(sc, 0x0051) | 0x0004);
+ }
+ BCW_WRITE16(sc, BCW_MMIO_PHY_RADIO, 0);
+ bcw_phy_write16(sc, 0x0802, bcw_phy_read16(sc, 0x0802) |
+ 0x0100);
+ bcw_phy_write16(sc, 0x042b, bcw_phy_read16(sc, 0x042b) |
+ 0x2000);
+ bcw_phy_write16(sc, 0x001c, 0x186a);
+ bcw_phy_write16(sc, 0x0013,
+ (bcw_phy_read16(sc, 0x0013) & 0x00ff) | 0x1900);
+ bcw_phy_write16(sc, 0x0035,
+ (bcw_phy_read16(sc, 0x0035) & 0xffc0) | 0x0064);
+ bcw_phy_write16(sc, 0x005d,
+ (bcw_phy_read16(sc, 0x005d) & 0xff80) | 0x000a);
+ }
+
+ if (sc->sc_phy_rev == 1 && sc->sc_radio_rev == 0x2050) {
+ bcw_phy_write16(sc, 0x0026, 0xce00);
+ bcw_phy_write16(sc, 0x0021, 0x3763);
+ bcw_phy_write16(sc, 0x0022, 0x1bc3);
+ bcw_phy_write16(sc, 0x0023, 0x06f9);
+ bcw_phy_write16(sc, 0x0024, 0x037e);
+ } else
+ bcw_phy_write16(sc, 0x0026, 0xcc00);
+ bcw_phy_write16(sc, 0x0030, 0x00c6);
+ BCW_WRITE16(sc, 0x3ec, 0x3f22);
+
+ if (sc->sc_phy_rev == 1 && sc->sc_radio_rev == 0x2050)
+ bcw_phy_write16(sc, 0x0020, 0x3e1c);
+ else
+ bcw_phy_write16(sc, 0x0020, 0x301c);
+
+ if (sc->sc_phy_rev == 0)
+ BCW_WRITE16(sc, 0x03e4, 0x3000);
+
+ /* force to channel 7, even if not supported */
+ bcw_radio_channel(sc, 7, 0);
+
+ if (sc->sc_radio_rev != 0x2050) {
+ bcw_radio_write16(sc, 0x0075, 0x0080);
+ bcw_radio_write16(sc, 0x0079, 0x0081);
+ }
+
+ bcw_radio_write16(sc, 0x0050, 0x0020);
+ bcw_radio_write16(sc, 0x0050, 0x0023);
+
+ if (sc->sc_radio_rev == 0x2050) {
+ bcw_radio_write16(sc, 0x0050, 0x0020);
+ bcw_radio_write16(sc, 0x005a, 0x0070);
+ }
+
+ bcw_radio_write16(sc, 0x005b, 0x007b);
+ bcw_radio_write16(sc, 0x005c, 0x00b0);
+
+ bcw_radio_write16(sc, 0x007a, bcw_radio_read16(sc, 0x007a) | 0x0007);
+
+ bcw_radio_channel(sc, BCW_RADIO_DEFAULT_CHANNEL, 0);
+
+ bcw_phy_write16(sc, 0x0014, 0x0080);
+ bcw_phy_write16(sc, 0x0032, 0x00ca);
+ bcw_phy_write16(sc, 0x88a3, 0x002a);
+
+ /* TODO bcw_radio_set_tx_power() */
+
+ if (sc->sc_radio_rev == 0x2050)
+ bcw_radio_write16(sc, 0x005d, 0x000d);
+
+ BCW_WRITE16(sc, 0x03e4, (BCW_READ16(sc, 0x03e4) & 0xffc0) | 0x0004);
+}
+
+void
+bcw_phy_initb6(struct bcw_softc *sc)
+{
+ uint16_t offset, val;
+
+ bcw_phy_write16(sc, 0x003e, 0x817a);
+ bcw_radio_write16(sc, 0x007a, (bcw_radio_read16(sc, 0x007a) | 0x0058));
+
+ if (sc->sc_radio_mnf == 0x17f && sc->sc_radio_ver == 0x2050 &&
+ (sc->sc_radio_rev == 3 || sc->sc_radio_rev == 4 ||
+ sc->sc_radio_rev == 5)) {
+ bcw_radio_write16(sc, 0x0051, 0x001f);
+ bcw_radio_write16(sc, 0x0052, 0x0040);
+ bcw_radio_write16(sc, 0x0053, 0x005b);
+ bcw_radio_write16(sc, 0x0054, 0x0098);
+ bcw_radio_write16(sc, 0x005a, 0x0088);
+ bcw_radio_write16(sc, 0x005b, 0x0088);
+ bcw_radio_write16(sc, 0x005d, 0x0088);
+ bcw_radio_write16(sc, 0x005e, 0x0088);
+ bcw_radio_write16(sc, 0x007d, 0x0088);
+ }
+
+ if (sc->sc_radio_mnf == 0x17f && sc->sc_radio_ver == 0x2050 &&
+ sc->sc_radio_rev == 6) {
+ bcw_radio_write16(sc, 0x0051, 0);
+ bcw_radio_write16(sc, 0x0052, 0x0040);
+ bcw_radio_write16(sc, 0x0053, 0x00b7);
+ bcw_radio_write16(sc, 0x0054, 0x0098);
+ bcw_radio_write16(sc, 0x005a, 0x0088);
+ bcw_radio_write16(sc, 0x005b, 0x008b);
+ bcw_radio_write16(sc, 0x005c, 0x00b5);
+ bcw_radio_write16(sc, 0x005d, 0x0088);
+ bcw_radio_write16(sc, 0x005e, 0x0088);
+ bcw_radio_write16(sc, 0x007d, 0x0088);
+ bcw_radio_write16(sc, 0x007c, 0x0001);
+ bcw_radio_write16(sc, 0x007e, 0x0008);
+ }
+
+ if (sc->sc_radio_mnf == 0x017f && sc->sc_radio_ver == 0x2050 &&
+ sc->sc_radio_rev == 7) {
+ bcw_radio_write16(sc, 0x0051, 0);
+ bcw_radio_write16(sc, 0x0052, 0x0040);
+ bcw_radio_write16(sc, 0x0053, 0x00b7);
+ bcw_radio_write16(sc, 0x0054, 0x0098);
+ bcw_radio_write16(sc, 0x005a, 0x0088);
+ bcw_radio_write16(sc, 0x005b, 0x00a8);
+ bcw_radio_write16(sc, 0x005c, 0x0075);
+ bcw_radio_write16(sc, 0x005d, 0x00f5);
+ bcw_radio_write16(sc, 0x005e, 0x00b8);
+ bcw_radio_write16(sc, 0x007d, 0x00e8);
+ bcw_radio_write16(sc, 0x007c, 0x0001);
+ bcw_radio_write16(sc, 0x007e, 0x0008);
+ bcw_radio_write16(sc, 0x007b, 0);
+ }
+
+ if (sc->sc_radio_mnf == 0x17f && sc->sc_radio_ver == 0x2050 &&
+ sc->sc_radio_rev == 8) {
+ bcw_radio_write16(sc, 0x0051, 0);
+ bcw_radio_write16(sc, 0x0052, 0x0040);
+ bcw_radio_write16(sc, 0x0053, 0x00b7);
+ bcw_radio_write16(sc, 0x0054, 0x0098);
+ bcw_radio_write16(sc, 0x005a, 0x0088);
+ bcw_radio_write16(sc, 0x005b, 0x006b);
+ bcw_radio_write16(sc, 0x005c, 0x000f);
+ if (sc->sc_boardflags & 0x8000) {
+ bcw_radio_write16(sc, 0x005d, 0x00fa);
+ bcw_radio_write16(sc, 0x005e, 0x00d8);
+ } else {
+ bcw_radio_write16(sc, 0x005d, 0x00f5);
+ bcw_radio_write16(sc, 0x005e, 0x00b8);
+ }
+ bcw_radio_write16(sc, 0x0073, 0x0003);
+ bcw_radio_write16(sc, 0x007d, 0x00a8);
+ bcw_radio_write16(sc, 0x007c, 0x0001);
+ bcw_radio_write16(sc, 0x007e, 0x0008);
+ }
+
+ val = 0x1e1f;
+ for (offset = 0x0088; offset < 0x0098; offset++) {
+ bcw_phy_write16(sc, offset, val);
+ val -= 0x0202;
+ }
+ val = 0x3e3f;
+ for (offset = 0x0098; offset < 0x00a8; offset++) {
+ bcw_phy_write16(sc, offset, val);
+ val -= 0x0202;
+ }
+ val = 0x2120;
+ for (offset = 0x00a8; offset < 0x00c8; offset++) {
+ bcw_phy_write16(sc, offset, (val & 0x3f3f));
+ val += 0x0202;
+ }
+
+ if (sc->sc_phy_type == BCW_PHY_TYPEG) {
+ bcw_radio_write16(sc, 0x007a, bcw_radio_read16(sc, 0x007a) |
+ 0x0020);
+ bcw_radio_write16(sc, 0x0051, bcw_radio_read16(sc, 0x0051) |
+ 0x0004);
+ bcw_phy_write16(sc, 0x0802, bcw_phy_read16(sc, 0x0802) |
+ 0x0100);
+ bcw_phy_write16(sc, 0x042b, bcw_phy_read16(sc, 0x042b) |
+ 0x2000);
+ }
+
+ /* force to channel 7, even if not supported */
+ bcw_radio_channel(sc, 7, 0);
+
+ bcw_radio_write16(sc, 0x0050, 0x0020);
+ bcw_radio_write16(sc, 0x0050, 0x0023);
+ delay(40);
+ bcw_radio_write16(sc, 0x007c, (bcw_radio_read16(sc, 0x007c) |
+ 0x0002));
+ bcw_radio_write16(sc, 0x0050, 0x0020);
+ if (sc->sc_radio_mnf == 0x17f && sc->sc_radio_ver == 0x2050 &&
+ sc->sc_radio_rev <= 2) {
+ bcw_radio_write16(sc, 0x0050, 0x0020);
+ bcw_radio_write16(sc, 0x005a, 0x0070);
+ bcw_radio_write16(sc, 0x005b, 0x007b);
+ bcw_radio_write16(sc, 0x005c, 0x00b0);
+ }
+ bcw_radio_write16(sc, 0x007a, (bcw_radio_read16(sc, 0x007a) & 0x00f8) |
+ 0x0007);
+
+ bcw_radio_channel(sc, BCW_RADIO_DEFAULT_CHANNEL, 0);
+
+ bcw_phy_write16(sc, 0x0014, 0x0200);
+ if (sc->sc_radio_ver == 0x2050) {
+ if (sc->sc_radio_rev == 3 || sc->sc_radio_rev == 4 ||
+ sc->sc_radio_rev == 5)
+ bcw_phy_write16(sc, 0x002a, 0x8ac0);
+ else
+ bcw_phy_write16(sc, 0x002a, 0x88c2);
+ }
+ bcw_phy_write16(sc, 0x0038, 0x0668);
+ /* TODO bcw_radio_set_tx_power() */
+ if (sc->sc_radio_ver == 0x2050) {
+ if (sc->sc_radio_rev == 3 || sc->sc_radio_rev == 4 ||
+ sc->sc_radio_rev == 5)
+ bcw_phy_write16(sc, 0x005d,
+ bcw_phy_read16(sc, 0x005d) | 0x0003);
+ else if (sc->sc_radio_rev <= 2)
+ bcw_phy_write16(sc, 0x005d, 0x000d);
+ }
+
+ if (sc->sc_phy_rev == 4)
+ bcw_phy_write16(sc, 0x0002, (bcw_phy_read16(sc, 0x0002) &
+ 0xffc0) | 0x0004);
+ else
+ BCW_WRITE16(sc, 0x03e4, 0x0009);
+ if (sc->sc_phy_type == BCW_PHY_TYPEG) {
+ BCW_WRITE16(sc, 0x03e6, 0x8140);
+ bcw_phy_write16(sc, 0x0016, 0x0410);
+ bcw_phy_write16(sc, 0x0017, 0x0820);
+ bcw_phy_write16(sc, 0x0062, 0x0007);
+ /* TODO */
+ } else
+ BCW_WRITE16(sc, 0x03e6, 0);
+}
diff --git a/sys/dev/ic/bcwreg.h b/sys/dev/ic/bcwreg.h
index aae2d3ca578..5cae7c380a9 100644
--- a/sys/dev/ic/bcwreg.h
+++ b/sys/dev/ic/bcwreg.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: bcwreg.h,v 1.11 2007/02/18 00:05:39 mglocker Exp $ */
+/* $OpenBSD: bcwreg.h,v 1.12 2007/02/18 09:37:21 mglocker Exp $ */
/*
* Copyright (c) 2006 Jon Simola <jsimola@gmail.com>
@@ -338,6 +338,7 @@
#define BCW_GPIO_MASK 0x49e
#define BCW_GPIO_CTRL 0x6c
+#define BCW_MMIO_PHY_RADIO 0x3e2
#define BCW_MMIO_CHANNEL 0x3f0
/* LEDS */
diff --git a/sys/dev/ic/bcwvar.h b/sys/dev/ic/bcwvar.h
index 792a0004498..6d5acaedf5b 100644
--- a/sys/dev/ic/bcwvar.h
+++ b/sys/dev/ic/bcwvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: bcwvar.h,v 1.14 2007/02/18 00:05:39 mglocker Exp $ */
+/* $OpenBSD: bcwvar.h,v 1.15 2007/02/18 09:37:21 mglocker Exp $ */
/*
* Copyright (c) 2006 Jon Simola <jsimola@gmail.com>
@@ -213,9 +213,9 @@ struct bcw_softc {
uint16_t sc_phy_type;
uint16_t sc_phy_rev;
// uint16_t sc_corerev;
- uint32_t sc_radioid;
- uint16_t sc_radiorev;
- uint16_t sc_radiotype;
+ uint32_t sc_radio_mnf;
+ uint16_t sc_radio_rev;
+ uint16_t sc_radio_ver;
uint32_t sc_phyinfo;
uint16_t sc_numcores;
uint16_t sc_havecommon;