Subject: Re: Hardware
To: Frank van der Linden <frank@wins.uva.nl>
From: Matthias Drochner <drochner@zel459.zel.kfa-juelich.de>
List: port-i386
Date: 07/28/1999 14:18:59
frank@wins.uva.nl said:
> The 3com docs mention that Broadcomm PHYs may be used on their cards. 

Good. I can't identify a separate phy chip on the card however,
so it is probably the on-chip phy which has this ID.

[Linux code]
> But you did manage to get it to probe, right? Could you send me  a
> diff? 

I'll append it. It is slightly obfuscated... hard to extract
useful information from a Linux driver...
The dummy read of phy 24 reg 1 is taken from Linux too - perhaps
it can be left out - didn't try yet.
It might be better to use the FreeBSD driver as reference, but I had
tested the card in a Linux box and knew that the code works.

> -FX cards probably don't have an MII interface, but are wrongly
> marked as such in if_ex_pci.c.
> [...]
> You're probably getting some random values back by accident,
> hence the weird PHY output.

There is at least no use for a mii phy, but it might be present
in the chip - perhaps 3com has only 1 ASIC version, and the cards
are differentiated by external circuity and EEPROM contents only.
The register values look too consistent for random values.
For the -FX cards, removing of the EX_CONF_MII works (didn't I mention
this already in another mail?), but I don't think we can get away that
easily in the general case. There is a 905b-combo card which has
AUI and BNC in addition to 100TX, and here probably neither the
"no MII" nor the "all MII" version will dtrt. (I don't have such
a card.)

best regards
Matthias


Index: elinkxl.c
===================================================================
RCS file: /cvsroot/syssrc/sys/dev/ic/elinkxl.c,v
retrieving revision 1.13
diff -c -2 -r1.13 elinkxl.c
*** elinkxl.c	1999/05/18 23:52:55	1.13
--- elinkxl.c	1999/07/28 11:38:27
***************
*** 380,383 ****
--- 380,384 ----
  
  	if (sc->ex_conf & EX_CONF_MII) {
+ (void)ex_mii_readreg((struct device *)sc, 24, 1);
  		/*
  		 * Find PHY, extract media information from it.
***************
*** 1685,1688 ****
--- 1686,1753 ----
  }
  
+ #define mdio_delay() bus_space_read_4(sc->sc_iot, sc->sc_ioh, 
ELINK_W4_PHYSMGMT)
+ 
+ #define MDIO_SHIFT_CLK	0x01
+ #define MDIO_DIR_WRITE	0x04
+ #define MDIO_DATA_WRITE0 (0x00 | MDIO_DIR_WRITE)
+ #define MDIO_DATA_WRITE1 (0x02 | MDIO_DIR_WRITE)
+ #define MDIO_DATA_READ	0x02
+ #define MDIO_ENB_IN		0x00
+ 
+ /* Generate the preamble required for initial synchronization and
+    a few older transceivers. */
+ static void mdio_sync(struct ex_softc *sc, int bits)
+ {
+ 
+ 	/* Establish sync by sending at least 32 logic ones. */
+ 	while (-- bits >= 0) {
+ 		bus_space_write_2(sc->sc_iot, sc->sc_ioh, ELINK_W4_PHYSMGMT,
+ 				  MDIO_DATA_WRITE1);
+ 		mdio_delay();
+ 		bus_space_write_2(sc->sc_iot, sc->sc_ioh, ELINK_W4_PHYSMGMT,
+ 				  MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK);
+ 		mdio_delay();
+ 	}
+ }
+ 
+ #define mii_preamble_required 1
+ 
+ static int mdio_read(struct ex_softc *sc, int phy_id, int location)
+ {
+ 	int i;
+ 	int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;
+ 	unsigned int retval = 0;
+ 
+ 	if (mii_preamble_required)
+ 		mdio_sync(sc, 32);
+ 
+ 	/* Shift the read command bits out. */
+ 	for (i = 14; i >= 0; i--) {
+ 		int dataval = (read_cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
+ 		bus_space_write_2(sc->sc_iot, sc->sc_ioh, ELINK_W4_PHYSMGMT,
+ 				  dataval);
+ 		mdio_delay();
+ 		bus_space_write_2(sc->sc_iot, sc->sc_ioh, ELINK_W4_PHYSMGMT,
+ 				  dataval | MDIO_SHIFT_CLK);
+ 		mdio_delay();
+ 	}
+ 	/* Read the two transition, 16 data, and wire-idle bits. */
+ 	for (i = 19; i > 0; i--) {
+ 		bus_space_write_2(sc->sc_iot, sc->sc_ioh, ELINK_W4_PHYSMGMT,
+ 				  MDIO_ENB_IN);
+ 		mdio_delay();
+ 		retval = (retval << 1) | ((bus_space_read_2(sc->sc_iot, sc->sc_ioh, 
ELINK_W4_PHYSMGMT) & MDIO_DATA_READ) ? 1 : 0);
+ 		bus_space_write_2(sc->sc_iot, sc->sc_ioh, ELINK_W4_PHYSMGMT,
+ 				  MDIO_ENB_IN | MDIO_SHIFT_CLK);
+ 		mdio_delay();
+ 	}
+ #if 0
+ 	return (retval>>1) & 0x1ffff;
+ #else
+ 	return retval & 0x20000 ? 0xffff : retval>>1 & 0xffff;
+ #endif
+ }
+ 
+ 
  /*
   * The reason why all this stuff below is here, is that we need a special
***************
*** 1700,1703 ****
--- 1765,1769 ----
  {
  	struct ex_softc *sc = (struct ex_softc *)v;
+ #if 0
  	int val = 0;
  	int err =0;
***************
*** 1742,1745 ****
--- 1808,1822 ----
  
  	return (err ? 0 : val);
+ #else
+ 	int val;
+ 
+ 	if ((sc->ex_conf & EX_CONF_INTPHY) && phy != ELINK_INTPHY_ID)
+ 		return 0;
+ 
+ 	GO_WINDOW(4);
+ 	val = mdio_read(sc, phy, reg);
+ 	GO_WINDOW(1);
+ 	return (val);
+ #endif
  }