1 /* 2 * (C) Copyright 2001 3 * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com. 4 * 5 * See file CREDITS for list of people who contributed to this 6 * project. 7 * 8 * This program is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU General Public License as 10 * published by the Free Software Foundation; either version 2 of 11 * the License, or (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 21 * MA 02111-1307 USA 22 */ 23 24 /* 25 * This provides a bit-banged interface to the ethernet MII management 26 * channel. 27 */ 28 29 #include <common.h> 30 #include <miiphy.h> 31 32 #if defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII) 33 34 /***************************************************************************** 35 * 36 * Read the OUI, manufacture's model number, and revision number. 37 * 38 * OUI: 22 bits (unsigned int) 39 * Model: 6 bits (unsigned char) 40 * Revision: 4 bits (unsigned char) 41 * 42 * Returns: 43 * 0 on success 44 */ 45 int miiphy_info (unsigned char addr, 46 unsigned int *oui, 47 unsigned char *model, unsigned char *rev) 48 { 49 unsigned int reg = 0; 50 51 /* 52 * Trick: we are reading two 16 registers into a 32 bit variable 53 * so we do a 16 read into the high order bits of the variable (big 54 * endian, you know), shift it down 16 bits, and the read the rest. 55 */ 56 if (miiphy_read (addr, PHY_PHYIDR2, (unsigned short *) ®) != 0) { 57 #ifdef DEBUG 58 printf ("PHY ID register 2 read failed\n"); 59 #endif 60 return (-1); 61 } 62 reg >>= 16; 63 64 #ifdef DEBUG 65 printf ("PHY_PHYIDR2 @ 0x%x = 0x%04x\n", addr, reg); 66 #endif 67 if (reg == 0xFFFF) { 68 /* No physical device present at this address */ 69 return (-1); 70 } 71 72 if (miiphy_read (addr, PHY_PHYIDR1, (unsigned short *) ®) != 0) { 73 #ifdef DEBUG 74 printf ("PHY ID register 1 read failed\n"); 75 #endif 76 return (-1); 77 } 78 #ifdef DEBUG 79 printf ("PHY_PHYIDR[1,2] @ 0x%x = 0x%08x\n", addr, reg); 80 #endif 81 *oui = ( reg >> 10); 82 *model = (unsigned char) ((reg >> 4) & 0x0000003F); 83 *rev = (unsigned char) ( reg & 0x0000000F); 84 return (0); 85 } 86 87 88 /***************************************************************************** 89 * 90 * Reset the PHY. 91 * Returns: 92 * 0 on success 93 */ 94 int miiphy_reset (unsigned char addr) 95 { 96 unsigned short reg; 97 int loop_cnt; 98 99 if (miiphy_write (addr, PHY_BMCR, 0x8000) != 0) { 100 #ifdef DEBUG 101 printf ("PHY reset failed\n"); 102 #endif 103 return (-1); 104 } 105 106 /* 107 * Poll the control register for the reset bit to go to 0 (it is 108 * auto-clearing). This should happen within 0.5 seconds per the 109 * IEEE spec. 110 */ 111 loop_cnt = 0; 112 reg = 0x8000; 113 while (((reg & 0x8000) != 0) && (loop_cnt++ < 1000000)) { 114 if (miiphy_read (addr, PHY_BMCR, ®) != 0) { 115 # ifdef DEBUG 116 printf ("PHY status read failed\n"); 117 # endif 118 return (-1); 119 } 120 } 121 if ((reg & 0x8000) == 0) { 122 return (0); 123 } else { 124 printf ("PHY reset timed out\n"); 125 return (-1); 126 } 127 return (0); 128 } 129 130 131 /***************************************************************************** 132 * 133 * Determine the ethernet speed (10/100). 134 */ 135 int miiphy_speed (unsigned char addr) 136 { 137 unsigned short reg; 138 139 if (miiphy_read (addr, PHY_ANLPAR, ®)) { 140 printf ("PHY speed1 read failed, assuming 10bT\n"); 141 return (_10BASET); 142 } 143 144 if ((reg & PHY_ANLPAR_100) != 0) { 145 return (_100BASET); 146 } else { 147 return (_10BASET); 148 } 149 } 150 151 152 /***************************************************************************** 153 * 154 * Determine full/half duplex. 155 */ 156 int miiphy_duplex (unsigned char addr) 157 { 158 unsigned short reg; 159 160 if (miiphy_read (addr, PHY_ANLPAR, ®)) { 161 printf ("PHY duplex read failed, assuming half duplex\n"); 162 return (HALF); 163 } 164 165 if ((reg & (PHY_ANLPAR_10FD | PHY_ANLPAR_TXFD)) != 0) { 166 return (FULL); 167 } else { 168 return (HALF); 169 } 170 } 171 172 #endif /* CONFIG_MII || (CONFIG_COMMANDS & CFG_CMD_MII) */ 173