From fc40fabe0bbb94f864b04e00beab30eb318412c5 Mon Sep 17 00:00:00 2001 From: sobomax Date: Fri, 28 Apr 2006 03:17:37 +0000 Subject: [PATCH] Add some incomplete support for Marvell Yukon EC controllers based on OpenBSD changes. With these changes, PHY part of the driver becomes functional (it senses media changes and negotiates speed just fine), previously it just hang with no PHY message, but no data goes through interface (error message is "can not stop transfer of Tx/Rx descriptor). Hopefully somebody with more clue/free time will be able to pick up after me. --- sys/dev/sk/if_sk.c | 124 ++++++++++++++++++++++++++++++++++++------ sys/dev/sk/if_skreg.h | 30 +++++++++- 2 files changed, 134 insertions(+), 20 deletions(-) diff --git a/sys/dev/sk/if_sk.c b/sys/dev/sk/if_sk.c index 8a5dbf2ac9f3..0f70832bf4e2 100644 --- a/sys/dev/sk/if_sk.c +++ b/sys/dev/sk/if_sk.c @@ -159,6 +159,21 @@ static struct sk_type sk_devs[] = { DEVICEID_SK_V2, "Marvell Gigabit Ethernet" }, + { + VENDORID_MARVELL, + DEVICEID_MRVL_4360, + "Marvell 88E8052 Gigabit Ethernet Controller" + }, + { + VENDORID_MARVELL, + DEVICEID_MRVL_4361, + "Marvell 88E8050 Gigabit Ethernet Controller" + }, + { + VENDORID_MARVELL, + DEVICEID_MRVL_4362, + "Marvell 88E8053 Gigabit Ethernet Controller" + }, { VENDORID_MARVELL, DEVICEID_BELKIN_5005, @@ -571,6 +586,7 @@ sk_miibus_readreg(dev, phy, reg) case SK_YUKON: case SK_YUKON_LITE: case SK_YUKON_LP: + case SK_YUKON_EC: v = sk_marv_miibus_readreg(sc_if, phy, reg); break; default: @@ -600,6 +616,7 @@ sk_miibus_writereg(dev, phy, reg, val) case SK_YUKON: case SK_YUKON_LITE: case SK_YUKON_LP: + case SK_YUKON_EC: v = sk_marv_miibus_writereg(sc_if, phy, reg, val); break; default: @@ -627,6 +644,7 @@ sk_miibus_statchg(dev) case SK_YUKON: case SK_YUKON_LITE: case SK_YUKON_LP: + case SK_YUKON_EC: sk_marv_miibus_statchg(sc_if); break; } @@ -852,6 +870,7 @@ sk_setmulti(sc_if) case SK_YUKON: case SK_YUKON_LITE: case SK_YUKON_LP: + case SK_YUKON_EC: SK_YU_WRITE_2(sc_if, YUKON_MCAH1, 0); SK_YU_WRITE_2(sc_if, YUKON_MCAH2, 0); SK_YU_WRITE_2(sc_if, YUKON_MCAH3, 0); @@ -893,6 +912,7 @@ sk_setmulti(sc_if) case SK_YUKON: case SK_YUKON_LITE: case SK_YUKON_LP: + case SK_YUKON_EC: bcopy(LLADDR( (struct sockaddr_dl *)ifma->ifma_addr), maddr, ETHER_ADDR_LEN); @@ -917,6 +937,7 @@ sk_setmulti(sc_if) case SK_YUKON: case SK_YUKON_LITE: case SK_YUKON_LP: + case SK_YUKON_EC: SK_YU_WRITE_2(sc_if, YUKON_MCAH1, hashes[0] & 0xffff); SK_YU_WRITE_2(sc_if, YUKON_MCAH2, (hashes[0] >> 16) & 0xffff); SK_YU_WRITE_2(sc_if, YUKON_MCAH3, hashes[1] & 0xffff); @@ -947,6 +968,7 @@ sk_setpromisc(sc_if) case SK_YUKON: case SK_YUKON_LITE: case SK_YUKON_LP: + case SK_YUKON_EC: if (ifp->if_flags & IFF_PROMISC) { SK_YU_CLRBIT_2(sc_if, YUKON_RCR, YU_RCR_UFLEN | YU_RCR_MUFLEN); @@ -1395,6 +1417,9 @@ sk_reset(sc) case SK_GENESIS: sc->sk_int_ticks = SK_IMTIMER_TICKS_GENESIS; break; + case SK_YUKON_EC: + sc->sk_int_ticks = SK_IMTIMER_TICKS_YUKON_EC; + break; default: sc->sk_int_ticks = SK_IMTIMER_TICKS_YUKON; break; @@ -1432,6 +1457,7 @@ sk_probe(dev) case SK_YUKON: case SK_YUKON_LITE: case SK_YUKON_LP: + case SK_YUKON_EC: device_set_desc(dev, "Marvell Semiconductor, Inc. Yukon"); break; } @@ -1527,8 +1553,12 @@ sk_attach(dev) * receiver and b) between the two XMACs, if this is a * dual port NIC. Our algotithm is to divide up the memory * evenly so that everyone gets a fair share. + * + * Just to be contrary, Yukon2 appears to have separate memory + * for each MAC. */ - if (sk_win_read_1(sc, SK_CONFIG) & SK_CONFIG_SINGLEMAC) { + if (SK_IS_YUKON2(sc) || + sk_win_read_1(sc, SK_CONFIG) & SK_CONFIG_SINGLEMAC) { u_int32_t chunk, val; chunk = sc->sk_ramsize / 2; @@ -1555,22 +1585,32 @@ sk_attach(dev) /* Read and save PHY type and set PHY address */ sc_if->sk_phytype = sk_win_read_1(sc, SK_EPROM1) & 0xF; - switch(sc_if->sk_phytype) { - case SK_PHYTYPE_XMAC: - sc_if->sk_phyaddr = SK_PHYADDR_XMAC; - break; - case SK_PHYTYPE_BCOM: - sc_if->sk_phyaddr = SK_PHYADDR_BCOM; - break; - case SK_PHYTYPE_MARV_COPPER: + if (!SK_YUKON_FAMILY(sc->sk_type)) { + switch(sc_if->sk_phytype) { + case SK_PHYTYPE_XMAC: + sc_if->sk_phyaddr = SK_PHYADDR_XMAC; + break; + case SK_PHYTYPE_BCOM: + sc_if->sk_phyaddr = SK_PHYADDR_BCOM; + break; + default: + device_printf(sc->sk_dev, "unsupported PHY type: %d\n", + sc_if->sk_phytype); + error = ENODEV; + SK_IF_UNLOCK(sc_if); + goto fail; + } + } else { + if (sc_if->sk_phytype < SK_PHYTYPE_MARV_COPPER && + sc->sk_pmd == IFM_1000_T) { + /* not initialized, punt */ + sc_if->sk_phytype = SK_PHYTYPE_MARV_COPPER; + } + sc_if->sk_phyaddr = SK_PHYADDR_MARV; - break; - default: - device_printf(sc->sk_dev, "unsupported PHY type: %d\n", - sc_if->sk_phytype); - error = ENODEV; - SK_IF_UNLOCK(sc_if); - goto fail; + + if (sc->sk_pmd != IFM_1000_T && sc->sk_pmd != IFM_1000_CX) + sc_if->sk_phytype = SK_PHYTYPE_MARV_FIBER; } /* @@ -1605,6 +1645,7 @@ sk_attach(dev) case SK_YUKON: case SK_YUKON_LITE: case SK_YUKON_LP: + case SK_YUKON_EC: sk_init_yukon(sc_if); break; } @@ -1637,7 +1678,7 @@ skc_attach(dev) device_t dev; { struct sk_softc *sc; - int error = 0, rid, *port; + int error = 0, rid, *port, sk_macs; uint8_t skrs; char *pname, *revstr; @@ -1759,6 +1800,12 @@ skc_attach(dev) sc->sk_pmd = IFM_1000_T; break; default: + if (SK_YUKON_FAMILY(sc->sk_type) && (sk_win_read_1(sc, SK_EPROM1) + & 0xF) < SK_PHYTYPE_MARV_COPPER) { + /* not initialized, punt */ + sc->sk_pmd = IFM_1000_T; + break; + } device_printf(dev, "unknown media type: 0x%x\n", sk_win_read_1(sc, SK_PMDTYPE)); error = ENXIO; @@ -1777,6 +1824,9 @@ skc_attach(dev) pname = sc->sk_vpd_prodname; break; case DEVICEID_SK_V2: + case DEVICEID_MRVL_4360: + case DEVICEID_MRVL_4361: + case DEVICEID_MRVL_4362: /* YUKON VPD PN might bear no resemblance to reality. */ switch (sc->sk_type) { case SK_GENESIS: @@ -1792,6 +1842,9 @@ skc_attach(dev) case SK_YUKON_LP: pname = "Marvell Yukon LP Gigabit Ethernet"; break; + case SK_YUKON_EC: + pname = "Marvell Yukon-2 EC Gigabit Ethernet"; + break; default: pname = "Marvell Yukon (Unknown) Gigabit Ethernet"; break; @@ -1841,6 +1894,21 @@ skc_attach(dev) revstr = ""; break; } + } else if (sc->sk_type == SK_YUKON_EC) { + switch (sc->sk_rev) { + case SK_YUKON_EC_REV_A1: + revstr = "A1"; + break; + case SK_YUKON_EC_REV_A2: + revstr = "A2"; + break; + case SK_YUKON_EC_REV_A3: + revstr = "A3"; + break; + default: + revstr = ""; + break; + } } else { revstr = ""; } @@ -1899,7 +1967,23 @@ skc_attach(dev) *port = SK_PORT_A; device_set_ivars(sc->sk_devs[SK_PORT_A], port); - if (!(sk_win_read_1(sc, SK_CONFIG) & SK_CONFIG_SINGLEMAC)) { + sk_macs = 1; + + if (SK_IS_YUKON2(sc)) { + u_int8_t hw; + + hw = sk_win_read_1(sc, SK_Y2_HWRES); + if ((hw & SK_Y2_HWRES_LINK_MASK) == SK_Y2_HWRES_LINK_DUAL) { + if ((sk_win_read_1(sc, SK_Y2_CLKGATE) & + SK_Y2_CLKGATE_LINK2_INACTIVE) == 0) + sk_macs++; + } + } else { + if (!(sk_win_read_1(sc, SK_CONFIG) & SK_CONFIG_SINGLEMAC)) + sk_macs++; + } + + if (sk_macs > 1) { sc->sk_devs[SK_PORT_B] = device_add_child(dev, "sk", -1); if (sc->sk_devs[SK_PORT_B] == NULL) { device_printf(dev, "failed to add child for PORT_B\n"); @@ -3813,6 +3897,7 @@ sk_init_locked(sc_if) case SK_YUKON: case SK_YUKON_LITE: case SK_YUKON_LP: + case SK_YUKON_EC: sk_init_yukon(sc_if); break; } @@ -3916,6 +4001,7 @@ sk_init_locked(sc_if) case SK_YUKON: case SK_YUKON_LITE: case SK_YUKON_LP: + case SK_YUKON_EC: reg = SK_YU_READ_2(sc_if, YUKON_GPCR); reg |= YU_GPCR_TXEN | YU_GPCR_RXEN; #if 0 @@ -3937,6 +4023,7 @@ sk_init_locked(sc_if) case SK_YUKON: case SK_YUKON_LITE: case SK_YUKON_LP: + case SK_YUKON_EC: callout_reset(&sc_if->sk_tick_ch, hz, sk_yukon_tick, sc_if); break; } @@ -4010,6 +4097,7 @@ sk_stop(sc_if) case SK_YUKON: case SK_YUKON_LITE: case SK_YUKON_LP: + case SK_YUKON_EC: SK_IF_WRITE_1(sc_if,0, SK_RXMF1_CTRL_TEST, SK_RFCTL_RESET_SET); SK_IF_WRITE_1(sc_if,0, SK_TXMF1_CTRL_TEST, SK_TFCTL_RESET_SET); break; diff --git a/sys/dev/sk/if_skreg.h b/sys/dev/sk/if_skreg.h index 8b1952352760..507f93aa3e66 100644 --- a/sys/dev/sk/if_skreg.h +++ b/sys/dev/sk/if_skreg.h @@ -55,13 +55,23 @@ #define SK_YUKON 0xB0 #define SK_YUKON_LITE 0xB1 #define SK_YUKON_LP 0xB2 +#define SK_YUKON_XL 0xB3 +#define SK_YUKON_EC_U 0xB4 +#define SK_YUKON_EC 0xB6 +#define SK_YUKON_FE 0xB7 #define SK_YUKON_FAMILY(x) ((x) & 0xB0) +#define SK_IS_YUKON2(sc) \ + ((sc)->sk_type >= SK_YUKON_XL && (sc)->sk_type <= SK_YUKON_FE) /* Known revisions in SK_CONFIG. */ #define SK_YUKON_LITE_REV_A0 0x0 /* invented, see test in skc_attach. */ #define SK_YUKON_LITE_REV_A1 0x3 #define SK_YUKON_LITE_REV_A3 0x7 +#define SK_YUKON_EC_REV_A1 0x0 +#define SK_YUKON_EC_REV_A2 0x1 +#define SK_YUKON_EC_REV_A3 0x2 + /* * SysKonnect PCI vendor ID */ @@ -78,6 +88,13 @@ #define DEVICEID_SK_V1 0x4300 #define DEVICEID_SK_V2 0x4320 +/* + * Marvell gigabit ethernet device IDs + */ +#define DEVICEID_MRVL_4360 0x4360 +#define DEVICEID_MRVL_4361 0x4361 +#define DEVICEID_MRVL_4362 0x4362 + /* * Belkin F5D5005 */ @@ -345,8 +362,10 @@ #define SK_CONFIG 0x011A #define SK_CHIPVER 0x011B #define SK_EPROM0 0x011C -#define SK_EPROM1 0x011D -#define SK_EPROM2 0x011E +#define SK_EPROM1 0x011D /* yukon/genesis */ +#define SK_Y2_CLKGATE 0x011D /* yukon 2 */ +#define SK_EPROM2 0x011E /* yukon/genesis */ +#define SK_Y2_HWRES 0x011E /* yukon 2 */ #define SK_EPROM3 0x011F #define SK_EP_ADDR 0x0120 #define SK_EP_DATA 0x0124 @@ -452,6 +471,13 @@ #define SK_GPIO_DIR8 0x01000000 #define SK_GPIO_DIR9 0x02000000 +#define SK_Y2_CLKGATE_LINK2_INACTIVE 0x80 /* port 2 inactive */ + +#define SK_Y2_HWRES_LINK_1 0x01 +#define SK_Y2_HWRES_LINK_2 0x02 +#define SK_Y2_HWRES_LINK_MASK (SK_Y2_HWRES_LINK_1 | SK_Y2_HWRES_LINK_2) +#define SK_Y2_HWRES_LINK_DUAL (SK_Y2_HWRES_LINK_1 | SK_Y2_HWRES_LINK_2) + /* Block 3 Ram interface and MAC arbiter registers */ #define SK_RAMADDR 0x0180 #define SK_RAMDATA0 0x0184