1 /* 2 * RealTek PHY drivers 3 * 4 * SPDX-License-Identifier: GPL-2.0+ 5 * 6 * Copyright 2010-2011, 2015 Freescale Semiconductor, Inc. 7 * author Andy Fleming 8 */ 9 #include <config.h> 10 #include <common.h> 11 #include <phy.h> 12 13 #define PHY_AUTONEGOTIATE_TIMEOUT 5000 14 15 /* RTL8211x PHY Status Register */ 16 #define MIIM_RTL8211x_PHY_STATUS 0x11 17 #define MIIM_RTL8211x_PHYSTAT_SPEED 0xc000 18 #define MIIM_RTL8211x_PHYSTAT_GBIT 0x8000 19 #define MIIM_RTL8211x_PHYSTAT_100 0x4000 20 #define MIIM_RTL8211x_PHYSTAT_DUPLEX 0x2000 21 #define MIIM_RTL8211x_PHYSTAT_SPDDONE 0x0800 22 #define MIIM_RTL8211x_PHYSTAT_LINK 0x0400 23 24 /* RTL8211x PHY Interrupt Enable Register */ 25 #define MIIM_RTL8211x_PHY_INER 0x12 26 #define MIIM_RTL8211x_PHY_INTR_ENA 0x9f01 27 #define MIIM_RTL8211x_PHY_INTR_DIS 0x0000 28 29 /* RTL8211x PHY Interrupt Status Register */ 30 #define MIIM_RTL8211x_PHY_INSR 0x13 31 32 /* RealTek RTL8211x */ 33 static int rtl8211x_config(struct phy_device *phydev) 34 { 35 phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET); 36 37 /* mask interrupt at init; if the interrupt is 38 * needed indeed, it should be explicitly enabled 39 */ 40 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211x_PHY_INER, 41 MIIM_RTL8211x_PHY_INTR_DIS); 42 43 /* read interrupt status just to clear it */ 44 phy_read(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211x_PHY_INER); 45 46 genphy_config_aneg(phydev); 47 48 return 0; 49 } 50 51 static int rtl8211x_parse_status(struct phy_device *phydev) 52 { 53 unsigned int speed; 54 unsigned int mii_reg; 55 56 mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211x_PHY_STATUS); 57 58 if (!(mii_reg & MIIM_RTL8211x_PHYSTAT_SPDDONE)) { 59 int i = 0; 60 61 /* in case of timeout ->link is cleared */ 62 phydev->link = 1; 63 puts("Waiting for PHY realtime link"); 64 while (!(mii_reg & MIIM_RTL8211x_PHYSTAT_SPDDONE)) { 65 /* Timeout reached ? */ 66 if (i > PHY_AUTONEGOTIATE_TIMEOUT) { 67 puts(" TIMEOUT !\n"); 68 phydev->link = 0; 69 break; 70 } 71 72 if ((i++ % 1000) == 0) 73 putc('.'); 74 udelay(1000); /* 1 ms */ 75 mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, 76 MIIM_RTL8211x_PHY_STATUS); 77 } 78 puts(" done\n"); 79 udelay(500000); /* another 500 ms (results in faster booting) */ 80 } else { 81 if (mii_reg & MIIM_RTL8211x_PHYSTAT_LINK) 82 phydev->link = 1; 83 else 84 phydev->link = 0; 85 } 86 87 if (mii_reg & MIIM_RTL8211x_PHYSTAT_DUPLEX) 88 phydev->duplex = DUPLEX_FULL; 89 else 90 phydev->duplex = DUPLEX_HALF; 91 92 speed = (mii_reg & MIIM_RTL8211x_PHYSTAT_SPEED); 93 94 switch (speed) { 95 case MIIM_RTL8211x_PHYSTAT_GBIT: 96 phydev->speed = SPEED_1000; 97 break; 98 case MIIM_RTL8211x_PHYSTAT_100: 99 phydev->speed = SPEED_100; 100 break; 101 default: 102 phydev->speed = SPEED_10; 103 } 104 105 return 0; 106 } 107 108 static int rtl8211x_startup(struct phy_device *phydev) 109 { 110 /* Read the Status (2x to make sure link is right) */ 111 genphy_update_link(phydev); 112 rtl8211x_parse_status(phydev); 113 114 return 0; 115 } 116 117 /* Support for RTL8211B PHY */ 118 static struct phy_driver RTL8211B_driver = { 119 .name = "RealTek RTL8211B", 120 .uid = 0x1cc910, 121 .mask = 0xffffff, 122 .features = PHY_GBIT_FEATURES, 123 .config = &rtl8211x_config, 124 .startup = &rtl8211x_startup, 125 .shutdown = &genphy_shutdown, 126 }; 127 128 /* Support for RTL8211E-VB-CG, RTL8211E-VL-CG and RTL8211EG-VB-CG PHYs */ 129 static struct phy_driver RTL8211E_driver = { 130 .name = "RealTek RTL8211E", 131 .uid = 0x1cc915, 132 .mask = 0xffffff, 133 .features = PHY_GBIT_FEATURES, 134 .config = &rtl8211x_config, 135 .startup = &rtl8211x_startup, 136 .shutdown = &genphy_shutdown, 137 }; 138 139 /* Support for RTL8211DN PHY */ 140 static struct phy_driver RTL8211DN_driver = { 141 .name = "RealTek RTL8211DN", 142 .uid = 0x1cc914, 143 .mask = 0xffffff, 144 .features = PHY_GBIT_FEATURES, 145 .config = &rtl8211x_config, 146 .startup = &rtl8211x_startup, 147 .shutdown = &genphy_shutdown, 148 }; 149 150 int phy_realtek_init(void) 151 { 152 phy_register(&RTL8211B_driver); 153 phy_register(&RTL8211E_driver); 154 phy_register(&RTL8211DN_driver); 155 156 return 0; 157 } 158