xref: /rk3399_rockchip-uboot/drivers/net/phy/realtek.c (revision 6a10bc5be8b809d43af7ddb66c45eeff7e622da1)
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
43793ea947SShengzhou Liu #define MIIM_RTL8211F_TX_DELAY		0x100
4490712741SShengzhou Liu #define MIIM_RTL8211F_LCR		0x10
453d6af748SShengzhou Liu 
46c624d168SBhupesh Sharma /* RealTek RTL8211x */
47c624d168SBhupesh Sharma static int rtl8211x_config(struct phy_device *phydev)
489082eeacSAndy Fleming {
499082eeacSAndy Fleming 	phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET);
509082eeacSAndy Fleming 
513cee1388SCodrin Ciubotariu 	/* mask interrupt at init; if the interrupt is
523cee1388SCodrin Ciubotariu 	 * needed indeed, it should be explicitly enabled
533cee1388SCodrin Ciubotariu 	 */
543cee1388SCodrin Ciubotariu 	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211x_PHY_INER,
553cee1388SCodrin Ciubotariu 		  MIIM_RTL8211x_PHY_INTR_DIS);
563cee1388SCodrin Ciubotariu 
573cee1388SCodrin Ciubotariu 	/* read interrupt status just to clear it */
583cee1388SCodrin Ciubotariu 	phy_read(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211x_PHY_INER);
593cee1388SCodrin Ciubotariu 
609082eeacSAndy Fleming 	genphy_config_aneg(phydev);
619082eeacSAndy Fleming 
629082eeacSAndy Fleming 	return 0;
639082eeacSAndy Fleming }
649082eeacSAndy Fleming 
65793ea947SShengzhou Liu static int rtl8211f_config(struct phy_device *phydev)
66793ea947SShengzhou Liu {
67793ea947SShengzhou Liu 	u16 reg;
68793ea947SShengzhou Liu 
69793ea947SShengzhou Liu 	phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET);
70793ea947SShengzhou Liu 
71793ea947SShengzhou Liu 	if (phydev->interface == PHY_INTERFACE_MODE_RGMII) {
72793ea947SShengzhou Liu 		/* enable TXDLY */
73793ea947SShengzhou Liu 		phy_write(phydev, MDIO_DEVAD_NONE,
74793ea947SShengzhou Liu 			  MIIM_RTL8211F_PAGE_SELECT, 0xd08);
75793ea947SShengzhou Liu 		reg = phy_read(phydev, MDIO_DEVAD_NONE, 0x11);
76793ea947SShengzhou Liu 		reg |= MIIM_RTL8211F_TX_DELAY;
77793ea947SShengzhou Liu 		phy_write(phydev, MDIO_DEVAD_NONE, 0x11, reg);
78793ea947SShengzhou Liu 		/* restore to default page 0 */
79793ea947SShengzhou Liu 		phy_write(phydev, MDIO_DEVAD_NONE,
80793ea947SShengzhou Liu 			  MIIM_RTL8211F_PAGE_SELECT, 0x0);
81793ea947SShengzhou Liu 	}
82793ea947SShengzhou Liu 
8390712741SShengzhou Liu 	/* Set green LED for Link, yellow LED for Active */
8490712741SShengzhou Liu 	phy_write(phydev, MDIO_DEVAD_NONE,
8590712741SShengzhou Liu 		  MIIM_RTL8211F_PAGE_SELECT, 0xd04);
8690712741SShengzhou Liu 	phy_write(phydev, MDIO_DEVAD_NONE, 0x10, 0x617f);
8790712741SShengzhou Liu 	phy_write(phydev, MDIO_DEVAD_NONE,
8890712741SShengzhou Liu 		  MIIM_RTL8211F_PAGE_SELECT, 0x0);
8990712741SShengzhou Liu 
90793ea947SShengzhou Liu 	genphy_config_aneg(phydev);
91793ea947SShengzhou Liu 
92793ea947SShengzhou Liu 	return 0;
93793ea947SShengzhou Liu }
94793ea947SShengzhou Liu 
95c624d168SBhupesh Sharma static int rtl8211x_parse_status(struct phy_device *phydev)
969082eeacSAndy Fleming {
979082eeacSAndy Fleming 	unsigned int speed;
989082eeacSAndy Fleming 	unsigned int mii_reg;
999082eeacSAndy Fleming 
100c624d168SBhupesh Sharma 	mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211x_PHY_STATUS);
1019082eeacSAndy Fleming 
102c624d168SBhupesh Sharma 	if (!(mii_reg & MIIM_RTL8211x_PHYSTAT_SPDDONE)) {
1039082eeacSAndy Fleming 		int i = 0;
1049082eeacSAndy Fleming 
1059082eeacSAndy Fleming 		/* in case of timeout ->link is cleared */
1069082eeacSAndy Fleming 		phydev->link = 1;
1079082eeacSAndy Fleming 		puts("Waiting for PHY realtime link");
108c624d168SBhupesh Sharma 		while (!(mii_reg & MIIM_RTL8211x_PHYSTAT_SPDDONE)) {
1099082eeacSAndy Fleming 			/* Timeout reached ? */
1109082eeacSAndy Fleming 			if (i > PHY_AUTONEGOTIATE_TIMEOUT) {
1119082eeacSAndy Fleming 				puts(" TIMEOUT !\n");
1129082eeacSAndy Fleming 				phydev->link = 0;
1139082eeacSAndy Fleming 				break;
1149082eeacSAndy Fleming 			}
1159082eeacSAndy Fleming 
1169082eeacSAndy Fleming 			if ((i++ % 1000) == 0)
1179082eeacSAndy Fleming 				putc('.');
1189082eeacSAndy Fleming 			udelay(1000);	/* 1 ms */
1199082eeacSAndy Fleming 			mii_reg = phy_read(phydev, MDIO_DEVAD_NONE,
120c624d168SBhupesh Sharma 					MIIM_RTL8211x_PHY_STATUS);
1219082eeacSAndy Fleming 		}
1229082eeacSAndy Fleming 		puts(" done\n");
1239082eeacSAndy Fleming 		udelay(500000);	/* another 500 ms (results in faster booting) */
1249082eeacSAndy Fleming 	} else {
125c624d168SBhupesh Sharma 		if (mii_reg & MIIM_RTL8211x_PHYSTAT_LINK)
1269082eeacSAndy Fleming 			phydev->link = 1;
1279082eeacSAndy Fleming 		else
1289082eeacSAndy Fleming 			phydev->link = 0;
1299082eeacSAndy Fleming 	}
1309082eeacSAndy Fleming 
131c624d168SBhupesh Sharma 	if (mii_reg & MIIM_RTL8211x_PHYSTAT_DUPLEX)
1329082eeacSAndy Fleming 		phydev->duplex = DUPLEX_FULL;
1339082eeacSAndy Fleming 	else
1349082eeacSAndy Fleming 		phydev->duplex = DUPLEX_HALF;
1359082eeacSAndy Fleming 
136c624d168SBhupesh Sharma 	speed = (mii_reg & MIIM_RTL8211x_PHYSTAT_SPEED);
1379082eeacSAndy Fleming 
1389082eeacSAndy Fleming 	switch (speed) {
139c624d168SBhupesh Sharma 	case MIIM_RTL8211x_PHYSTAT_GBIT:
1409082eeacSAndy Fleming 		phydev->speed = SPEED_1000;
1419082eeacSAndy Fleming 		break;
142c624d168SBhupesh Sharma 	case MIIM_RTL8211x_PHYSTAT_100:
1439082eeacSAndy Fleming 		phydev->speed = SPEED_100;
1449082eeacSAndy Fleming 		break;
1459082eeacSAndy Fleming 	default:
1469082eeacSAndy Fleming 		phydev->speed = SPEED_10;
1479082eeacSAndy Fleming 	}
1489082eeacSAndy Fleming 
1499082eeacSAndy Fleming 	return 0;
1509082eeacSAndy Fleming }
1519082eeacSAndy Fleming 
1523d6af748SShengzhou Liu static int rtl8211f_parse_status(struct phy_device *phydev)
1533d6af748SShengzhou Liu {
1543d6af748SShengzhou Liu 	unsigned int speed;
1553d6af748SShengzhou Liu 	unsigned int mii_reg;
1563d6af748SShengzhou Liu 	int i = 0;
1573d6af748SShengzhou Liu 
1583d6af748SShengzhou Liu 	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211F_PAGE_SELECT, 0xa43);
1593d6af748SShengzhou Liu 	mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211F_PHY_STATUS);
1603d6af748SShengzhou Liu 
1613d6af748SShengzhou Liu 	phydev->link = 1;
1623d6af748SShengzhou Liu 	while (!(mii_reg & MIIM_RTL8211F_PHYSTAT_LINK)) {
1633d6af748SShengzhou Liu 		if (i > PHY_AUTONEGOTIATE_TIMEOUT) {
1643d6af748SShengzhou Liu 			puts(" TIMEOUT !\n");
1653d6af748SShengzhou Liu 			phydev->link = 0;
1663d6af748SShengzhou Liu 			break;
1673d6af748SShengzhou Liu 		}
1683d6af748SShengzhou Liu 
1693d6af748SShengzhou Liu 		if ((i++ % 1000) == 0)
1703d6af748SShengzhou Liu 			putc('.');
1713d6af748SShengzhou Liu 		udelay(1000);
1723d6af748SShengzhou Liu 		mii_reg = phy_read(phydev, MDIO_DEVAD_NONE,
1733d6af748SShengzhou Liu 				   MIIM_RTL8211F_PHY_STATUS);
1743d6af748SShengzhou Liu 	}
1753d6af748SShengzhou Liu 
1763d6af748SShengzhou Liu 	if (mii_reg & MIIM_RTL8211F_PHYSTAT_DUPLEX)
1773d6af748SShengzhou Liu 		phydev->duplex = DUPLEX_FULL;
1783d6af748SShengzhou Liu 	else
1793d6af748SShengzhou Liu 		phydev->duplex = DUPLEX_HALF;
1803d6af748SShengzhou Liu 
1813d6af748SShengzhou Liu 	speed = (mii_reg & MIIM_RTL8211F_PHYSTAT_SPEED);
1823d6af748SShengzhou Liu 
1833d6af748SShengzhou Liu 	switch (speed) {
1843d6af748SShengzhou Liu 	case MIIM_RTL8211F_PHYSTAT_GBIT:
1853d6af748SShengzhou Liu 		phydev->speed = SPEED_1000;
1863d6af748SShengzhou Liu 		break;
1873d6af748SShengzhou Liu 	case MIIM_RTL8211F_PHYSTAT_100:
1883d6af748SShengzhou Liu 		phydev->speed = SPEED_100;
1893d6af748SShengzhou Liu 		break;
1903d6af748SShengzhou Liu 	default:
1913d6af748SShengzhou Liu 		phydev->speed = SPEED_10;
1923d6af748SShengzhou Liu 	}
1933d6af748SShengzhou Liu 
1943d6af748SShengzhou Liu 	return 0;
1953d6af748SShengzhou Liu }
1963d6af748SShengzhou Liu 
197c624d168SBhupesh Sharma static int rtl8211x_startup(struct phy_device *phydev)
1989082eeacSAndy Fleming {
1999082eeacSAndy Fleming 	/* Read the Status (2x to make sure link is right) */
2009082eeacSAndy Fleming 	genphy_update_link(phydev);
201c624d168SBhupesh Sharma 	rtl8211x_parse_status(phydev);
2029082eeacSAndy Fleming 
2039082eeacSAndy Fleming 	return 0;
2049082eeacSAndy Fleming }
2059082eeacSAndy Fleming 
206*6a10bc5bSMichal Simek static int rtl8211e_startup(struct phy_device *phydev)
207*6a10bc5bSMichal Simek {
208*6a10bc5bSMichal Simek 	genphy_update_link(phydev);
209*6a10bc5bSMichal Simek 	genphy_parse_link(phydev);
210*6a10bc5bSMichal Simek 
211*6a10bc5bSMichal Simek 	return 0;
212*6a10bc5bSMichal Simek }
213*6a10bc5bSMichal Simek 
2143d6af748SShengzhou Liu static int rtl8211f_startup(struct phy_device *phydev)
2153d6af748SShengzhou Liu {
2163d6af748SShengzhou Liu 	/* Read the Status (2x to make sure link is right) */
2173d6af748SShengzhou Liu 	genphy_update_link(phydev);
2183d6af748SShengzhou Liu 	rtl8211f_parse_status(phydev);
2193d6af748SShengzhou Liu 
2203d6af748SShengzhou Liu 	return 0;
2213d6af748SShengzhou Liu }
2223d6af748SShengzhou Liu 
223c624d168SBhupesh Sharma /* Support for RTL8211B PHY */
2249082eeacSAndy Fleming static struct phy_driver RTL8211B_driver = {
2259082eeacSAndy Fleming 	.name = "RealTek RTL8211B",
2269082eeacSAndy Fleming 	.uid = 0x1cc910,
22742205047SBhupesh Sharma 	.mask = 0xffffff,
2289082eeacSAndy Fleming 	.features = PHY_GBIT_FEATURES,
229c624d168SBhupesh Sharma 	.config = &rtl8211x_config,
230c624d168SBhupesh Sharma 	.startup = &rtl8211x_startup,
231c624d168SBhupesh Sharma 	.shutdown = &genphy_shutdown,
232c624d168SBhupesh Sharma };
233c624d168SBhupesh Sharma 
234c624d168SBhupesh Sharma /* Support for RTL8211E-VB-CG, RTL8211E-VL-CG and RTL8211EG-VB-CG PHYs */
235c624d168SBhupesh Sharma static struct phy_driver RTL8211E_driver = {
236c624d168SBhupesh Sharma 	.name = "RealTek RTL8211E",
237c624d168SBhupesh Sharma 	.uid = 0x1cc915,
23842205047SBhupesh Sharma 	.mask = 0xffffff,
239c624d168SBhupesh Sharma 	.features = PHY_GBIT_FEATURES,
240c624d168SBhupesh Sharma 	.config = &rtl8211x_config,
241*6a10bc5bSMichal Simek 	.startup = &rtl8211e_startup,
242c624d168SBhupesh Sharma 	.shutdown = &genphy_shutdown,
243c624d168SBhupesh Sharma };
244c624d168SBhupesh Sharma 
245c624d168SBhupesh Sharma /* Support for RTL8211DN PHY */
246c624d168SBhupesh Sharma static struct phy_driver RTL8211DN_driver = {
247c624d168SBhupesh Sharma 	.name = "RealTek RTL8211DN",
248c624d168SBhupesh Sharma 	.uid = 0x1cc914,
24942205047SBhupesh Sharma 	.mask = 0xffffff,
250c624d168SBhupesh Sharma 	.features = PHY_GBIT_FEATURES,
251c624d168SBhupesh Sharma 	.config = &rtl8211x_config,
252c624d168SBhupesh Sharma 	.startup = &rtl8211x_startup,
2539082eeacSAndy Fleming 	.shutdown = &genphy_shutdown,
2549082eeacSAndy Fleming };
2559082eeacSAndy Fleming 
2563d6af748SShengzhou Liu /* Support for RTL8211F PHY */
2573d6af748SShengzhou Liu static struct phy_driver RTL8211F_driver = {
2583d6af748SShengzhou Liu 	.name = "RealTek RTL8211F",
2593d6af748SShengzhou Liu 	.uid = 0x1cc916,
2603d6af748SShengzhou Liu 	.mask = 0xffffff,
2613d6af748SShengzhou Liu 	.features = PHY_GBIT_FEATURES,
262793ea947SShengzhou Liu 	.config = &rtl8211f_config,
2633d6af748SShengzhou Liu 	.startup = &rtl8211f_startup,
2643d6af748SShengzhou Liu 	.shutdown = &genphy_shutdown,
2653d6af748SShengzhou Liu };
2663d6af748SShengzhou Liu 
2679082eeacSAndy Fleming int phy_realtek_init(void)
2689082eeacSAndy Fleming {
2699082eeacSAndy Fleming 	phy_register(&RTL8211B_driver);
270c624d168SBhupesh Sharma 	phy_register(&RTL8211E_driver);
2713d6af748SShengzhou Liu 	phy_register(&RTL8211F_driver);
272c624d168SBhupesh Sharma 	phy_register(&RTL8211DN_driver);
2739082eeacSAndy Fleming 
2749082eeacSAndy Fleming 	return 0;
2759082eeacSAndy Fleming }
276