summaryrefslogtreecommitdiff
path: root/drivers/net/phy
diff options
context:
space:
mode:
authorShengzhou Liu <Shengzhou.Liu@freescale.com>2015-01-30 09:51:55 (GMT)
committerHonghua Yin <Hong-Hua.Yin@freescale.com>2015-03-25 08:19:16 (GMT)
commitce7468ae28590b496f78cb2678a289097f0c1804 (patch)
tree07f627430753a0cd2ad8a1d8faf934fe5a487e91 /drivers/net/phy
parent31be9b970697911e7c7ebfe000f0f0e2abc9779f (diff)
downloadlinux-fsl-qoriq-ce7468ae28590b496f78cb2678a289097f0c1804.tar.xz
net/phy: update Realtek PHY driver to support RTL8211F
This patch updates Realtek PHY driver to add RTL8211F support. RTL8211F has different register definitions from RTL8211E. Tested with RTL8211F(RGMII, SGMII) on Freescale T1023RDB board. Signed-off-by: Shengzhou Liu <Shengzhou.Liu@freescale.com> Change-Id: I5251bf757888e8cbef5cf3c6f851f68824e2cd8e Reviewed-on: http://git.am.freescale.net:8181/33250 Tested-by: Review Code-CDREVIEW <CDREVIEW@freescale.com> Reviewed-by: Xiaobo Xie <X.Xie@freescale.com> Reviewed-by: Honghua Yin <Hong-Hua.Yin@freescale.com>
Diffstat (limited to 'drivers/net/phy')
-rw-r--r--drivers/net/phy/realtek.c168
1 files changed, 132 insertions, 36 deletions
diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c
index 138de83..67dd764 100644
--- a/drivers/net/phy/realtek.c
+++ b/drivers/net/phy/realtek.c
@@ -23,7 +23,18 @@
#define RTL821x_INER_INIT 0x6400
#define RTL821x_INSR 0x13
-#define RTL8211E_INER_LINK_STATUS 0x400
+#define RTL8211E_INER_LINK_STATUS 0x0400
+#define RTL8211F_INER_LINK_STATUS 0x0010
+#define RTL8211F_INSR 0x1d
+#define RTL8211F_PAGE_SELECT 0x1f
+#define RTL8211F_PHY_STATUS 0x1a
+#define RTL8211F_PHYSTAT_SPEED 0x0030
+#define RTL8211F_PHYSTAT_GBIT 0x0020
+#define RTL8211F_PHYSTAT_100 0x0010
+#define RTL8211F_PHYSTAT_DUPLEX 0x0008
+#define RTL8211F_PHYSTAT_SPDDONE 0x0800
+#define RTL8211F_PHYSTAT_LINK 0x0004
+#define PHY_AUTONEGOTIATE_TIMEOUT 50000
MODULE_DESCRIPTION("Realtek PHY driver");
MODULE_AUTHOR("Johnson Leung");
@@ -38,6 +49,18 @@ static int rtl821x_ack_interrupt(struct phy_device *phydev)
return (err < 0) ? err : 0;
}
+static int rtl8211f_ack_interrupt(struct phy_device *phydev)
+{
+ int err;
+
+ phy_write(phydev, RTL8211F_PAGE_SELECT, 0xa43);
+ err = phy_read(phydev, RTL8211F_INSR);
+ /* restore to default page 0 */
+ phy_write(phydev, RTL8211F_PAGE_SELECT, 0x0);
+
+ return (err < 0) ? err : 0;
+}
+
static int rtl8211b_config_intr(struct phy_device *phydev)
{
int err;
@@ -64,50 +87,122 @@ static int rtl8211e_config_intr(struct phy_device *phydev)
return err;
}
-/* RTL8211B */
-static struct phy_driver rtl8211b_driver = {
- .phy_id = 0x001cc912,
- .name = "RTL8211B Gigabit Ethernet",
- .phy_id_mask = 0x001fffff,
- .features = PHY_GBIT_FEATURES,
- .flags = PHY_HAS_INTERRUPT,
- .config_aneg = &genphy_config_aneg,
- .read_status = &genphy_read_status,
- .ack_interrupt = &rtl821x_ack_interrupt,
- .config_intr = &rtl8211b_config_intr,
- .driver = { .owner = THIS_MODULE,},
-};
+static int rtl8211f_config_intr(struct phy_device *phydev)
+{
+ int err;
-/* RTL8211E */
-static struct phy_driver rtl8211e_driver = {
- .phy_id = 0x001cc915,
- .name = "RTL8211E Gigabit Ethernet",
- .phy_id_mask = 0x001fffff,
- .features = PHY_GBIT_FEATURES,
- .flags = PHY_HAS_INTERRUPT,
- .config_aneg = &genphy_config_aneg,
- .read_status = &genphy_read_status,
- .ack_interrupt = &rtl821x_ack_interrupt,
- .config_intr = &rtl8211e_config_intr,
- .suspend = genphy_suspend,
- .resume = genphy_resume,
- .driver = { .owner = THIS_MODULE,},
+ if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
+ err = phy_write(phydev, RTL821x_INER,
+ RTL8211F_INER_LINK_STATUS);
+ else
+ err = phy_write(phydev, RTL821x_INER, 0);
+
+ return err;
+}
+
+static int rtl8211f_config_init(struct phy_device *phydev)
+{
+ unsigned int speed, mii_reg;
+ int i = 0;
+
+ phy_write(phydev, RTL8211F_PAGE_SELECT, 0xa43);
+ mii_reg = phy_read(phydev, RTL8211F_PHY_STATUS);
+ phydev->link = 1;
+ while (!(mii_reg & RTL8211F_PHYSTAT_LINK)) {
+ if (i > PHY_AUTONEGOTIATE_TIMEOUT) {
+ pr_warn("RTL8211F LINK TIMEOUT\n");
+ phydev->link = 0;
+ break;
+ }
+ udelay(1000);
+ mii_reg = phy_read(phydev, RTL8211F_PHY_STATUS);
+ }
+
+ if (mii_reg & RTL8211F_PHYSTAT_DUPLEX)
+ phydev->duplex = DUPLEX_FULL;
+ else
+ phydev->duplex = DUPLEX_HALF;
+
+ speed = (mii_reg & RTL8211F_PHYSTAT_SPEED);
+
+ switch (speed) {
+ case RTL8211F_PHYSTAT_GBIT:
+ phydev->speed = SPEED_1000;
+ break;
+ case RTL8211F_PHYSTAT_100:
+ phydev->speed = SPEED_100;
+ break;
+ default:
+ phydev->speed = SPEED_10;
+ }
+
+ if (phydev->interface == PHY_INTERFACE_MODE_RGMII) {
+ udelay(2000);
+ /* enable TXDLY */
+ phy_write(phydev, RTL8211F_PAGE_SELECT, 0xd08);
+ udelay(2000);
+ phy_write(phydev, 0x11, 0x109);
+ /* restore to default page 0 */
+ phy_write(phydev, RTL8211F_PAGE_SELECT, 0x0);
+ }
+
+ return 0;
+}
+
+static struct phy_driver realtek_drivers[] = {
+ { /* RTL8211B */
+ .phy_id = 0x001cc912,
+ .name = "RTL8211B Gigabit Ethernet",
+ .phy_id_mask = 0x001fffff,
+ .features = PHY_GBIT_FEATURES,
+ .flags = PHY_HAS_INTERRUPT,
+ .config_aneg = &genphy_config_aneg,
+ .read_status = &genphy_read_status,
+ .ack_interrupt = &rtl821x_ack_interrupt,
+ .config_intr = &rtl8211b_config_intr,
+ .driver = { .owner = THIS_MODULE },
+ },
+ { /* RTL8211E */
+ .phy_id = 0x001cc915,
+ .name = "RTL8211E Gigabit Ethernet",
+ .phy_id_mask = 0x001fffff,
+ .features = PHY_GBIT_FEATURES,
+ .flags = PHY_HAS_INTERRUPT,
+ .config_aneg = &genphy_config_aneg,
+ .read_status = &genphy_read_status,
+ .ack_interrupt = &rtl821x_ack_interrupt,
+ .config_intr = &rtl8211e_config_intr,
+ .suspend = genphy_suspend,
+ .resume = genphy_resume,
+ .driver = { .owner = THIS_MODULE },
+ },
+ { /* RTL8211F */
+ .phy_id = 0x001cc916,
+ .name = "RTL8211F Gigabit Ethernet",
+ .phy_id_mask = 0x001fffff,
+ .features = PHY_GBIT_FEATURES,
+ .flags = PHY_HAS_INTERRUPT,
+ .config_aneg = &genphy_config_aneg,
+ .config_init = &rtl8211f_config_init,
+ .read_status = &genphy_read_status,
+ .ack_interrupt = &rtl8211f_ack_interrupt,
+ .config_intr = &rtl8211f_config_intr,
+ .suspend = genphy_suspend,
+ .resume = genphy_resume,
+ .driver = { .owner = THIS_MODULE },
+ },
};
static int __init realtek_init(void)
{
- int ret;
-
- ret = phy_driver_register(&rtl8211b_driver);
- if (ret < 0)
- return -ENODEV;
- return phy_driver_register(&rtl8211e_driver);
+ return phy_drivers_register(realtek_drivers,
+ ARRAY_SIZE(realtek_drivers));
}
static void __exit realtek_exit(void)
{
- phy_driver_unregister(&rtl8211b_driver);
- phy_driver_unregister(&rtl8211e_driver);
+ phy_drivers_unregister(realtek_drivers,
+ ARRAY_SIZE(realtek_drivers));
}
module_init(realtek_init);
@@ -116,6 +211,7 @@ module_exit(realtek_exit);
static struct mdio_device_id __maybe_unused realtek_tbl[] = {
{ 0x001cc912, 0x001fffff },
{ 0x001cc915, 0x001fffff },
+ { 0x001cc916, 0x001fffff },
{ }
};