19082eeacSAndy Fleming /* 29082eeacSAndy Fleming * RealTek PHY drivers 39082eeacSAndy Fleming * 41a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+ 59082eeacSAndy Fleming * 63cee1388SCodrin Ciubotariu * Copyright 2010-2011, 2015 Freescale Semiconductor, Inc. 79082eeacSAndy Fleming * author Andy Fleming 89082eeacSAndy Fleming */ 99082eeacSAndy Fleming #include <config.h> 109082eeacSAndy Fleming #include <common.h> 119082eeacSAndy Fleming #include <phy.h> 129082eeacSAndy Fleming 139082eeacSAndy Fleming #define PHY_AUTONEGOTIATE_TIMEOUT 5000 149082eeacSAndy Fleming 15c624d168SBhupesh Sharma /* RTL8211x PHY Status Register */ 16c624d168SBhupesh Sharma #define MIIM_RTL8211x_PHY_STATUS 0x11 17c624d168SBhupesh Sharma #define MIIM_RTL8211x_PHYSTAT_SPEED 0xc000 18c624d168SBhupesh Sharma #define MIIM_RTL8211x_PHYSTAT_GBIT 0x8000 19c624d168SBhupesh Sharma #define MIIM_RTL8211x_PHYSTAT_100 0x4000 20c624d168SBhupesh Sharma #define MIIM_RTL8211x_PHYSTAT_DUPLEX 0x2000 21c624d168SBhupesh Sharma #define MIIM_RTL8211x_PHYSTAT_SPDDONE 0x0800 22c624d168SBhupesh Sharma #define MIIM_RTL8211x_PHYSTAT_LINK 0x0400 239082eeacSAndy Fleming 243cee1388SCodrin Ciubotariu /* RTL8211x PHY Interrupt Enable Register */ 253cee1388SCodrin Ciubotariu #define MIIM_RTL8211x_PHY_INER 0x12 263cee1388SCodrin Ciubotariu #define MIIM_RTL8211x_PHY_INTR_ENA 0x9f01 273cee1388SCodrin Ciubotariu #define MIIM_RTL8211x_PHY_INTR_DIS 0x0000 283cee1388SCodrin Ciubotariu 293cee1388SCodrin Ciubotariu /* RTL8211x PHY Interrupt Status Register */ 303cee1388SCodrin Ciubotariu #define MIIM_RTL8211x_PHY_INSR 0x13 319082eeacSAndy Fleming 323d6af748SShengzhou Liu /* RTL8211F PHY Status Register */ 333d6af748SShengzhou Liu #define MIIM_RTL8211F_PHY_STATUS 0x1a 343d6af748SShengzhou Liu #define MIIM_RTL8211F_AUTONEG_ENABLE 0x1000 353d6af748SShengzhou Liu #define MIIM_RTL8211F_PHYSTAT_SPEED 0x0030 363d6af748SShengzhou Liu #define MIIM_RTL8211F_PHYSTAT_GBIT 0x0020 373d6af748SShengzhou Liu #define MIIM_RTL8211F_PHYSTAT_100 0x0010 383d6af748SShengzhou Liu #define MIIM_RTL8211F_PHYSTAT_DUPLEX 0x0008 393d6af748SShengzhou Liu #define MIIM_RTL8211F_PHYSTAT_SPDDONE 0x0800 403d6af748SShengzhou Liu #define MIIM_RTL8211F_PHYSTAT_LINK 0x0004 413d6af748SShengzhou Liu 423d6af748SShengzhou Liu #define MIIM_RTL8211F_PAGE_SELECT 0x1f 43*793ea947SShengzhou Liu #define MIIM_RTL8211F_TX_DELAY 0x100 443d6af748SShengzhou Liu 45c624d168SBhupesh Sharma /* RealTek RTL8211x */ 46c624d168SBhupesh Sharma static int rtl8211x_config(struct phy_device *phydev) 479082eeacSAndy Fleming { 489082eeacSAndy Fleming phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET); 499082eeacSAndy Fleming 503cee1388SCodrin Ciubotariu /* mask interrupt at init; if the interrupt is 513cee1388SCodrin Ciubotariu * needed indeed, it should be explicitly enabled 523cee1388SCodrin Ciubotariu */ 533cee1388SCodrin Ciubotariu phy_write(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211x_PHY_INER, 543cee1388SCodrin Ciubotariu MIIM_RTL8211x_PHY_INTR_DIS); 553cee1388SCodrin Ciubotariu 563cee1388SCodrin Ciubotariu /* read interrupt status just to clear it */ 573cee1388SCodrin Ciubotariu phy_read(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211x_PHY_INER); 583cee1388SCodrin Ciubotariu 599082eeacSAndy Fleming genphy_config_aneg(phydev); 609082eeacSAndy Fleming 619082eeacSAndy Fleming return 0; 629082eeacSAndy Fleming } 639082eeacSAndy Fleming 64*793ea947SShengzhou Liu static int rtl8211f_config(struct phy_device *phydev) 65*793ea947SShengzhou Liu { 66*793ea947SShengzhou Liu u16 reg; 67*793ea947SShengzhou Liu 68*793ea947SShengzhou Liu phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET); 69*793ea947SShengzhou Liu 70*793ea947SShengzhou Liu if (phydev->interface == PHY_INTERFACE_MODE_RGMII) { 71*793ea947SShengzhou Liu /* enable TXDLY */ 72*793ea947SShengzhou Liu phy_write(phydev, MDIO_DEVAD_NONE, 73*793ea947SShengzhou Liu MIIM_RTL8211F_PAGE_SELECT, 0xd08); 74*793ea947SShengzhou Liu reg = phy_read(phydev, MDIO_DEVAD_NONE, 0x11); 75*793ea947SShengzhou Liu reg |= MIIM_RTL8211F_TX_DELAY; 76*793ea947SShengzhou Liu phy_write(phydev, MDIO_DEVAD_NONE, 0x11, reg); 77*793ea947SShengzhou Liu /* restore to default page 0 */ 78*793ea947SShengzhou Liu phy_write(phydev, MDIO_DEVAD_NONE, 79*793ea947SShengzhou Liu MIIM_RTL8211F_PAGE_SELECT, 0x0); 80*793ea947SShengzhou Liu } 81*793ea947SShengzhou Liu 82*793ea947SShengzhou Liu genphy_config_aneg(phydev); 83*793ea947SShengzhou Liu 84*793ea947SShengzhou Liu return 0; 85*793ea947SShengzhou Liu } 86*793ea947SShengzhou Liu 87c624d168SBhupesh Sharma static int rtl8211x_parse_status(struct phy_device *phydev) 889082eeacSAndy Fleming { 899082eeacSAndy Fleming unsigned int speed; 909082eeacSAndy Fleming unsigned int mii_reg; 919082eeacSAndy Fleming 92c624d168SBhupesh Sharma mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211x_PHY_STATUS); 939082eeacSAndy Fleming 94c624d168SBhupesh Sharma if (!(mii_reg & MIIM_RTL8211x_PHYSTAT_SPDDONE)) { 959082eeacSAndy Fleming int i = 0; 969082eeacSAndy Fleming 979082eeacSAndy Fleming /* in case of timeout ->link is cleared */ 989082eeacSAndy Fleming phydev->link = 1; 999082eeacSAndy Fleming puts("Waiting for PHY realtime link"); 100c624d168SBhupesh Sharma while (!(mii_reg & MIIM_RTL8211x_PHYSTAT_SPDDONE)) { 1019082eeacSAndy Fleming /* Timeout reached ? */ 1029082eeacSAndy Fleming if (i > PHY_AUTONEGOTIATE_TIMEOUT) { 1039082eeacSAndy Fleming puts(" TIMEOUT !\n"); 1049082eeacSAndy Fleming phydev->link = 0; 1059082eeacSAndy Fleming break; 1069082eeacSAndy Fleming } 1079082eeacSAndy Fleming 1089082eeacSAndy Fleming if ((i++ % 1000) == 0) 1099082eeacSAndy Fleming putc('.'); 1109082eeacSAndy Fleming udelay(1000); /* 1 ms */ 1119082eeacSAndy Fleming mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, 112c624d168SBhupesh Sharma MIIM_RTL8211x_PHY_STATUS); 1139082eeacSAndy Fleming } 1149082eeacSAndy Fleming puts(" done\n"); 1159082eeacSAndy Fleming udelay(500000); /* another 500 ms (results in faster booting) */ 1169082eeacSAndy Fleming } else { 117c624d168SBhupesh Sharma if (mii_reg & MIIM_RTL8211x_PHYSTAT_LINK) 1189082eeacSAndy Fleming phydev->link = 1; 1199082eeacSAndy Fleming else 1209082eeacSAndy Fleming phydev->link = 0; 1219082eeacSAndy Fleming } 1229082eeacSAndy Fleming 123c624d168SBhupesh Sharma if (mii_reg & MIIM_RTL8211x_PHYSTAT_DUPLEX) 1249082eeacSAndy Fleming phydev->duplex = DUPLEX_FULL; 1259082eeacSAndy Fleming else 1269082eeacSAndy Fleming phydev->duplex = DUPLEX_HALF; 1279082eeacSAndy Fleming 128c624d168SBhupesh Sharma speed = (mii_reg & MIIM_RTL8211x_PHYSTAT_SPEED); 1299082eeacSAndy Fleming 1309082eeacSAndy Fleming switch (speed) { 131c624d168SBhupesh Sharma case MIIM_RTL8211x_PHYSTAT_GBIT: 1329082eeacSAndy Fleming phydev->speed = SPEED_1000; 1339082eeacSAndy Fleming break; 134c624d168SBhupesh Sharma case MIIM_RTL8211x_PHYSTAT_100: 1359082eeacSAndy Fleming phydev->speed = SPEED_100; 1369082eeacSAndy Fleming break; 1379082eeacSAndy Fleming default: 1389082eeacSAndy Fleming phydev->speed = SPEED_10; 1399082eeacSAndy Fleming } 1409082eeacSAndy Fleming 1419082eeacSAndy Fleming return 0; 1429082eeacSAndy Fleming } 1439082eeacSAndy Fleming 1443d6af748SShengzhou Liu static int rtl8211f_parse_status(struct phy_device *phydev) 1453d6af748SShengzhou Liu { 1463d6af748SShengzhou Liu unsigned int speed; 1473d6af748SShengzhou Liu unsigned int mii_reg; 1483d6af748SShengzhou Liu int i = 0; 1493d6af748SShengzhou Liu 1503d6af748SShengzhou Liu phy_write(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211F_PAGE_SELECT, 0xa43); 1513d6af748SShengzhou Liu mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211F_PHY_STATUS); 1523d6af748SShengzhou Liu 1533d6af748SShengzhou Liu phydev->link = 1; 1543d6af748SShengzhou Liu while (!(mii_reg & MIIM_RTL8211F_PHYSTAT_LINK)) { 1553d6af748SShengzhou Liu if (i > PHY_AUTONEGOTIATE_TIMEOUT) { 1563d6af748SShengzhou Liu puts(" TIMEOUT !\n"); 1573d6af748SShengzhou Liu phydev->link = 0; 1583d6af748SShengzhou Liu break; 1593d6af748SShengzhou Liu } 1603d6af748SShengzhou Liu 1613d6af748SShengzhou Liu if ((i++ % 1000) == 0) 1623d6af748SShengzhou Liu putc('.'); 1633d6af748SShengzhou Liu udelay(1000); 1643d6af748SShengzhou Liu mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, 1653d6af748SShengzhou Liu MIIM_RTL8211F_PHY_STATUS); 1663d6af748SShengzhou Liu } 1673d6af748SShengzhou Liu 1683d6af748SShengzhou Liu if (mii_reg & MIIM_RTL8211F_PHYSTAT_DUPLEX) 1693d6af748SShengzhou Liu phydev->duplex = DUPLEX_FULL; 1703d6af748SShengzhou Liu else 1713d6af748SShengzhou Liu phydev->duplex = DUPLEX_HALF; 1723d6af748SShengzhou Liu 1733d6af748SShengzhou Liu speed = (mii_reg & MIIM_RTL8211F_PHYSTAT_SPEED); 1743d6af748SShengzhou Liu 1753d6af748SShengzhou Liu switch (speed) { 1763d6af748SShengzhou Liu case MIIM_RTL8211F_PHYSTAT_GBIT: 1773d6af748SShengzhou Liu phydev->speed = SPEED_1000; 1783d6af748SShengzhou Liu break; 1793d6af748SShengzhou Liu case MIIM_RTL8211F_PHYSTAT_100: 1803d6af748SShengzhou Liu phydev->speed = SPEED_100; 1813d6af748SShengzhou Liu break; 1823d6af748SShengzhou Liu default: 1833d6af748SShengzhou Liu phydev->speed = SPEED_10; 1843d6af748SShengzhou Liu } 1853d6af748SShengzhou Liu 1863d6af748SShengzhou Liu return 0; 1873d6af748SShengzhou Liu } 1883d6af748SShengzhou Liu 189c624d168SBhupesh Sharma static int rtl8211x_startup(struct phy_device *phydev) 1909082eeacSAndy Fleming { 1919082eeacSAndy Fleming /* Read the Status (2x to make sure link is right) */ 1929082eeacSAndy Fleming genphy_update_link(phydev); 193c624d168SBhupesh Sharma rtl8211x_parse_status(phydev); 1949082eeacSAndy Fleming 1959082eeacSAndy Fleming return 0; 1969082eeacSAndy Fleming } 1979082eeacSAndy Fleming 1983d6af748SShengzhou Liu static int rtl8211f_startup(struct phy_device *phydev) 1993d6af748SShengzhou Liu { 2003d6af748SShengzhou Liu /* Read the Status (2x to make sure link is right) */ 2013d6af748SShengzhou Liu genphy_update_link(phydev); 2023d6af748SShengzhou Liu rtl8211f_parse_status(phydev); 2033d6af748SShengzhou Liu 2043d6af748SShengzhou Liu return 0; 2053d6af748SShengzhou Liu } 2063d6af748SShengzhou Liu 207c624d168SBhupesh Sharma /* Support for RTL8211B PHY */ 2089082eeacSAndy Fleming static struct phy_driver RTL8211B_driver = { 2099082eeacSAndy Fleming .name = "RealTek RTL8211B", 2109082eeacSAndy Fleming .uid = 0x1cc910, 21142205047SBhupesh Sharma .mask = 0xffffff, 2129082eeacSAndy Fleming .features = PHY_GBIT_FEATURES, 213c624d168SBhupesh Sharma .config = &rtl8211x_config, 214c624d168SBhupesh Sharma .startup = &rtl8211x_startup, 215c624d168SBhupesh Sharma .shutdown = &genphy_shutdown, 216c624d168SBhupesh Sharma }; 217c624d168SBhupesh Sharma 218c624d168SBhupesh Sharma /* Support for RTL8211E-VB-CG, RTL8211E-VL-CG and RTL8211EG-VB-CG PHYs */ 219c624d168SBhupesh Sharma static struct phy_driver RTL8211E_driver = { 220c624d168SBhupesh Sharma .name = "RealTek RTL8211E", 221c624d168SBhupesh Sharma .uid = 0x1cc915, 22242205047SBhupesh Sharma .mask = 0xffffff, 223c624d168SBhupesh Sharma .features = PHY_GBIT_FEATURES, 224c624d168SBhupesh Sharma .config = &rtl8211x_config, 225c624d168SBhupesh Sharma .startup = &rtl8211x_startup, 226c624d168SBhupesh Sharma .shutdown = &genphy_shutdown, 227c624d168SBhupesh Sharma }; 228c624d168SBhupesh Sharma 229c624d168SBhupesh Sharma /* Support for RTL8211DN PHY */ 230c624d168SBhupesh Sharma static struct phy_driver RTL8211DN_driver = { 231c624d168SBhupesh Sharma .name = "RealTek RTL8211DN", 232c624d168SBhupesh Sharma .uid = 0x1cc914, 23342205047SBhupesh Sharma .mask = 0xffffff, 234c624d168SBhupesh Sharma .features = PHY_GBIT_FEATURES, 235c624d168SBhupesh Sharma .config = &rtl8211x_config, 236c624d168SBhupesh Sharma .startup = &rtl8211x_startup, 2379082eeacSAndy Fleming .shutdown = &genphy_shutdown, 2389082eeacSAndy Fleming }; 2399082eeacSAndy Fleming 2403d6af748SShengzhou Liu /* Support for RTL8211F PHY */ 2413d6af748SShengzhou Liu static struct phy_driver RTL8211F_driver = { 2423d6af748SShengzhou Liu .name = "RealTek RTL8211F", 2433d6af748SShengzhou Liu .uid = 0x1cc916, 2443d6af748SShengzhou Liu .mask = 0xffffff, 2453d6af748SShengzhou Liu .features = PHY_GBIT_FEATURES, 246*793ea947SShengzhou Liu .config = &rtl8211f_config, 2473d6af748SShengzhou Liu .startup = &rtl8211f_startup, 2483d6af748SShengzhou Liu .shutdown = &genphy_shutdown, 2493d6af748SShengzhou Liu }; 2503d6af748SShengzhou Liu 2519082eeacSAndy Fleming int phy_realtek_init(void) 2529082eeacSAndy Fleming { 2539082eeacSAndy Fleming phy_register(&RTL8211B_driver); 254c624d168SBhupesh Sharma phy_register(&RTL8211E_driver); 2553d6af748SShengzhou Liu phy_register(&RTL8211F_driver); 256c624d168SBhupesh Sharma phy_register(&RTL8211DN_driver); 2579082eeacSAndy Fleming 2589082eeacSAndy Fleming return 0; 2599082eeacSAndy Fleming } 260