1 /* 2 * RealTek PHY drivers 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License as 6 * published by the Free Software Foundation; either version 2 of 7 * the License, or (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 17 * MA 02111-1307 USA 18 * 19 * Copyright 2010-2011 Freescale Semiconductor, Inc. 20 * author Andy Fleming 21 * 22 */ 23 #include <config.h> 24 #include <common.h> 25 #include <phy.h> 26 27 #define PHY_AUTONEGOTIATE_TIMEOUT 5000 28 29 /* RTL8211B PHY Status Register */ 30 #define MIIM_RTL8211B_PHY_STATUS 0x11 31 #define MIIM_RTL8211B_PHYSTAT_SPEED 0xc000 32 #define MIIM_RTL8211B_PHYSTAT_GBIT 0x8000 33 #define MIIM_RTL8211B_PHYSTAT_100 0x4000 34 #define MIIM_RTL8211B_PHYSTAT_DUPLEX 0x2000 35 #define MIIM_RTL8211B_PHYSTAT_SPDDONE 0x0800 36 #define MIIM_RTL8211B_PHYSTAT_LINK 0x0400 37 38 39 /* RealTek RTL8211B */ 40 static int rtl8211b_config(struct phy_device *phydev) 41 { 42 phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET); 43 44 genphy_config_aneg(phydev); 45 46 return 0; 47 } 48 49 static int rtl8211b_parse_status(struct phy_device *phydev) 50 { 51 unsigned int speed; 52 unsigned int mii_reg; 53 54 mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211B_PHY_STATUS); 55 56 if (!(mii_reg & MIIM_RTL8211B_PHYSTAT_SPDDONE)) { 57 int i = 0; 58 59 /* in case of timeout ->link is cleared */ 60 phydev->link = 1; 61 puts("Waiting for PHY realtime link"); 62 while (!(mii_reg & MIIM_RTL8211B_PHYSTAT_SPDDONE)) { 63 /* Timeout reached ? */ 64 if (i > PHY_AUTONEGOTIATE_TIMEOUT) { 65 puts(" TIMEOUT !\n"); 66 phydev->link = 0; 67 break; 68 } 69 70 if ((i++ % 1000) == 0) 71 putc('.'); 72 udelay(1000); /* 1 ms */ 73 mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, 74 MIIM_RTL8211B_PHY_STATUS); 75 } 76 puts(" done\n"); 77 udelay(500000); /* another 500 ms (results in faster booting) */ 78 } else { 79 if (mii_reg & MIIM_RTL8211B_PHYSTAT_LINK) 80 phydev->link = 1; 81 else 82 phydev->link = 0; 83 } 84 85 if (mii_reg & MIIM_RTL8211B_PHYSTAT_DUPLEX) 86 phydev->duplex = DUPLEX_FULL; 87 else 88 phydev->duplex = DUPLEX_HALF; 89 90 speed = (mii_reg & MIIM_RTL8211B_PHYSTAT_SPEED); 91 92 switch (speed) { 93 case MIIM_RTL8211B_PHYSTAT_GBIT: 94 phydev->speed = SPEED_1000; 95 break; 96 case MIIM_RTL8211B_PHYSTAT_100: 97 phydev->speed = SPEED_100; 98 break; 99 default: 100 phydev->speed = SPEED_10; 101 } 102 103 return 0; 104 } 105 106 static int rtl8211b_startup(struct phy_device *phydev) 107 { 108 /* Read the Status (2x to make sure link is right) */ 109 genphy_update_link(phydev); 110 rtl8211b_parse_status(phydev); 111 112 return 0; 113 } 114 115 static struct phy_driver RTL8211B_driver = { 116 .name = "RealTek RTL8211B", 117 .uid = 0x1cc910, 118 .mask = 0xfffff0, 119 .features = PHY_GBIT_FEATURES, 120 .config = &rtl8211b_config, 121 .startup = &rtl8211b_startup, 122 .shutdown = &genphy_shutdown, 123 }; 124 125 int phy_realtek_init(void) 126 { 127 phy_register(&RTL8211B_driver); 128 129 return 0; 130 } 131