diff options
Diffstat (limited to 'common/miiphybb.c')
-rw-r--r-- | common/miiphybb.c | 231 |
1 files changed, 231 insertions, 0 deletions
diff --git a/common/miiphybb.c b/common/miiphybb.c new file mode 100644 index 0000000..dfc1992 --- /dev/null +++ b/common/miiphybb.c @@ -0,0 +1,231 @@ +/* + * (C) Copyright 2001 + * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * This provides a bit-banged interface to the ethernet MII management + * channel. + */ + +#include <common.h> +#include <ioports.h> +#include <ppc_asm.tmpl> + +#ifdef CONFIG_BITBANGMII + + +/***************************************************************************** + * + * Utility to send the preamble, address, and register (common to read + * and write). + */ +static void miiphy_pre(char read, + unsigned char addr, + unsigned char reg) +{ + int j; /* counter */ + volatile ioport_t *iop = ioport_addr((immap_t *)CFG_IMMR, MDIO_PORT); + + /* + * Send a 32 bit preamble ('1's) with an extra '1' bit for good measure. + * The IEEE spec says this is a PHY optional requirement. The AMD + * 79C874 requires one after power up and one after a MII communications + * error. This means that we are doing more preambles than we need, + * but it is safer and will be much more robust. + */ + + MDIO_ACTIVE; + MDIO(1); + for(j = 0; j < 32; j++) + { + MDC(0); + MIIDELAY; + MDC(1); + MIIDELAY; + } + + /* send the start bit (01) and the read opcode (10) or write (10) */ + MDC(0); MDIO(0); MIIDELAY; MDC(1); MIIDELAY; + MDC(0); MDIO(1); MIIDELAY; MDC(1); MIIDELAY; + MDC(0); MDIO(read); MIIDELAY; MDC(1); MIIDELAY; + MDC(0); MDIO(!read); MIIDELAY; MDC(1); MIIDELAY; + + /* send the PHY address */ + for(j = 0; j < 5; j++) + { + MDC(0); + if((addr & 0x10) == 0) + { + MDIO(0); + } + else + { + MDIO(1); + } + MIIDELAY; + MDC(1); + MIIDELAY; + addr <<= 1; + } + + /* send the register address */ + for(j = 0; j < 5; j++) + { + MDC(0); + if((reg & 0x10) == 0) + { + MDIO(0); + } + else + { + MDIO(1); + } + MIIDELAY; + MDC(1); + MIIDELAY; + reg <<= 1; + } +} + + +/***************************************************************************** + * + * Read a MII PHY register. + * + * Returns: + * 0 on success + */ +int miiphy_read(unsigned char addr, + unsigned char reg, + unsigned short *value) +{ + short rdreg; /* register working value */ + int j; /* counter */ + volatile ioport_t *iop = ioport_addr((immap_t *)CFG_IMMR, MDIO_PORT); + + miiphy_pre(1, addr, reg); + + /* tri-state our MDIO I/O pin so we can read */ + MDC(0); + MDIO_TRISTATE; + MIIDELAY; + MDC(1); + MIIDELAY; + + /* check the turnaround bit: the PHY should be driving it to zero */ + if(MDIO_READ != 0) + { + /* printf("PHY didn't drive TA low\n"); */ + for(j = 0; j < 32; j++) + { + MDC(0); + MIIDELAY; + MDC(1); + MIIDELAY; + } + return(-1); + } + + MDC(0); + MIIDELAY; + + /* read 16 bits of register data, MSB first */ + rdreg = 0; + for(j = 0; j < 16; j++) + { + MDC(1); + MIIDELAY; + rdreg <<= 1; + rdreg |= MDIO_READ; + MDC(0); + MIIDELAY; + } + + MDC(1); + MIIDELAY; + MDC(0); + MIIDELAY; + MDC(1); + MIIDELAY; + + *value = rdreg; + +#ifdef DEBUG + printf ("miiphy_read(0x%x) @ 0x%x = 0x%04x\n", reg, addr, *value); +#endif + + return 0; +} + + +/***************************************************************************** + * + * Write a MII PHY register. + * + * Returns: + * 0 on success + */ +int miiphy_write(unsigned char addr, + unsigned char reg, + unsigned short value) +{ + int j; /* counter */ + volatile ioport_t *iop = ioport_addr((immap_t *)CFG_IMMR, MDIO_PORT); + + miiphy_pre(0, addr, reg); + + /* send the turnaround (10) */ + MDC(0); MDIO(1); MIIDELAY; MDC(1); MIIDELAY; + MDC(0); MDIO(0); MIIDELAY; MDC(1); MIIDELAY; + + /* write 16 bits of register data, MSB first */ + for(j = 0; j < 16; j++) + { + MDC(0); + if((value & 0x00008000) == 0) + { + MDIO(0); + } + else + { + MDIO(1); + } + MIIDELAY; + MDC(1); + MIIDELAY; + value <<= 1; + } + + /* + * Tri-state the MDIO line. + */ + MDIO_TRISTATE; + MDC(0); + MIIDELAY; + MDC(1); + MIIDELAY; + + return 0; +} + +#endif /* CONFIG_BITBANGMII */ + |