From eec386c5e9f5067dc7fdd3c86adae7de835e090a Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Fri, 25 Nov 2016 14:12:01 +0100 Subject: [PATCH] UPSTREAM: net: phy: realtek: fix enabling of the TX-delay for RTL8211F The old logic always enabled the TX-delay when the phy-mode was set to PHY_INTERFACE_MODE_RGMII. There are dedicated phy-modes which tell the PHY driver to enable the RX and/or TX delays: - PHY_INTERFACE_MODE_RGMII should disable the RX and TX delay in the PHY (if required, the MAC should add the delays in this case) - PHY_INTERFACE_MODE_RGMII_ID should enable RX and TX delay in the PHY - PHY_INTERFACE_MODE_RGMII_TXID should enable the TX delay in the PHY - PHY_INTERFACE_MODE_RGMII_RXID should enable the RX delay in the PHY (currently not supported by RTL8211F) With this patch we enable the TX delay for PHY_INTERFACE_MODE_RGMII_ID and PHY_INTERFACE_MODE_RGMII_TXID. Additionally we now explicity disable the TX-delay, which seems to be enabled automatically after a hard-reset of the PHY (by triggering it's reset pin) to get a consistent state (as defined by the phy-mode). This fixes a compatibility problem with some SoCs where the TX-delay was also added by the MAC. With the TX-delay being applied twice the TX clock was off and TX traffic was broken or very slow (<10Mbit/s) on 1000Mbit/s links. Signed-off-by: Martin Blumenstingl Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller (cherry picked from commit e3230494b57ece68750e3e32d3e53d6b00917058) --- drivers/net/phy/realtek.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c index 43ab691362d4..686f3b259dc0 100644 --- a/drivers/net/phy/realtek.c +++ b/drivers/net/phy/realtek.c @@ -102,15 +102,19 @@ static int rtl8211f_config_init(struct phy_device *phydev) if (ret < 0) return ret; - if (phydev->interface == PHY_INTERFACE_MODE_RGMII) { - /* enable TXDLY */ - phy_write(phydev, RTL8211F_PAGE_SELECT, 0xd08); - reg = phy_read(phydev, 0x11); + phy_write(phydev, RTL8211F_PAGE_SELECT, 0xd08); + reg = phy_read(phydev, 0x11); + + /* enable TX-delay for rgmii-id and rgmii-txid, otherwise disable it */ + if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID || + phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) reg |= RTL8211F_TX_DELAY; - phy_write(phydev, 0x11, reg); - /* restore to default page 0 */ - phy_write(phydev, RTL8211F_PAGE_SELECT, 0x0); - } + else + reg &= ~RTL8211F_TX_DELAY; + + phy_write(phydev, 0x11, reg); + /* restore to default page 0 */ + phy_write(phydev, RTL8211F_PAGE_SELECT, 0x0); return 0; } From e0a1654d1e79bea21f6397b6caa038c2dee25f97 Mon Sep 17 00:00:00 2001 From: Kunihiko Hayashi Date: Tue, 12 Sep 2017 18:54:35 +0900 Subject: [PATCH] UPSTREAM: net: phy: realtek: rename RTL8211F_PAGE_SELECT to RTL821x_PAGE_SELECT This renames the definition of page select register from RTL8211F_PAGE_SELECT to RTL821x_PAGE_SELECT to use it across models. Signed-off-by: Kunihiko Hayashi Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller (cherry picked from commit 013955a6556766a76f9f2cc31e740fc6db6ecff4) --- drivers/net/phy/realtek.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c index 686f3b259dc0..d58cc8f518ac 100644 --- a/drivers/net/phy/realtek.c +++ b/drivers/net/phy/realtek.c @@ -22,11 +22,11 @@ #define RTL821x_INER 0x12 #define RTL821x_INER_INIT 0x6400 #define RTL821x_INSR 0x13 +#define RTL821x_PAGE_SELECT 0x1f #define RTL8211E_INER_LINK_STATUS 0x400 #define RTL8211F_INER_LINK_STATUS 0x0010 #define RTL8211F_INSR 0x1d -#define RTL8211F_PAGE_SELECT 0x1f #define RTL8211F_TX_DELAY 0x100 MODULE_DESCRIPTION("Realtek PHY driver"); @@ -46,10 +46,10 @@ static int rtl8211f_ack_interrupt(struct phy_device *phydev) { int err; - phy_write(phydev, RTL8211F_PAGE_SELECT, 0xa43); + phy_write(phydev, RTL821x_PAGE_SELECT, 0xa43); err = phy_read(phydev, RTL8211F_INSR); /* restore to default page 0 */ - phy_write(phydev, RTL8211F_PAGE_SELECT, 0x0); + phy_write(phydev, RTL821x_PAGE_SELECT, 0x0); return (err < 0) ? err : 0; } @@ -102,7 +102,7 @@ static int rtl8211f_config_init(struct phy_device *phydev) if (ret < 0) return ret; - phy_write(phydev, RTL8211F_PAGE_SELECT, 0xd08); + phy_write(phydev, RTL821x_PAGE_SELECT, 0xd08); reg = phy_read(phydev, 0x11); /* enable TX-delay for rgmii-id and rgmii-txid, otherwise disable it */ @@ -114,7 +114,7 @@ static int rtl8211f_config_init(struct phy_device *phydev) phy_write(phydev, 0x11, reg); /* restore to default page 0 */ - phy_write(phydev, RTL8211F_PAGE_SELECT, 0x0); + phy_write(phydev, RTL821x_PAGE_SELECT, 0x0); return 0; } From 4ec70bc0ea714cc0129a4631dbda493ba706f40f Mon Sep 17 00:00:00 2001 From: Jassi Brar Date: Tue, 12 Sep 2017 18:54:36 +0900 Subject: [PATCH] UPSTREAM: net: phy: realtek: add RTL8201F phy-id and functions Add RTL8201F phy-id and the related functions to the driver. The original patch is as follows: https://patchwork.kernel.org/patch/2538341/ Signed-off-by: Jongsung Kim Signed-off-by: Jassi Brar Signed-off-by: Kunihiko Hayashi Reviewed-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller (cherry picked from commit 513588dd44b09bb5fdd5066a4fbc1e7443b86d1c) --- drivers/net/phy/realtek.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c index d58cc8f518ac..422cf1f6a60c 100644 --- a/drivers/net/phy/realtek.c +++ b/drivers/net/phy/realtek.c @@ -29,10 +29,22 @@ #define RTL8211F_INSR 0x1d #define RTL8211F_TX_DELAY 0x100 +#define RTL8201F_ISR 0x1e +#define RTL8201F_IER 0x13 + MODULE_DESCRIPTION("Realtek PHY driver"); MODULE_AUTHOR("Johnson Leung"); MODULE_LICENSE("GPL"); +static int rtl8201_ack_interrupt(struct phy_device *phydev) +{ + int err; + + err = phy_read(phydev, RTL8201F_ISR); + + return (err < 0) ? err : 0; +} + static int rtl821x_ack_interrupt(struct phy_device *phydev) { int err; @@ -54,6 +66,25 @@ static int rtl8211f_ack_interrupt(struct phy_device *phydev) return (err < 0) ? err : 0; } +static int rtl8201_config_intr(struct phy_device *phydev) +{ + int err; + + /* switch to page 7 */ + phy_write(phydev, RTL821x_PAGE_SELECT, 0x7); + + if (phydev->interrupts == PHY_INTERRUPT_ENABLED) + err = phy_write(phydev, RTL8201F_IER, + BIT(13) | BIT(12) | BIT(11)); + else + err = phy_write(phydev, RTL8201F_IER, 0); + + /* restore to default page 0 */ + phy_write(phydev, RTL821x_PAGE_SELECT, 0x0); + + return err; +} + static int rtl8211b_config_intr(struct phy_device *phydev) { int err; @@ -129,6 +160,18 @@ static struct phy_driver realtek_drvs[] = { .config_aneg = &genphy_config_aneg, .read_status = &genphy_read_status, .driver = { .owner = THIS_MODULE,}, + }, { + .phy_id = 0x001cc816, + .name = "RTL8201F 10/100Mbps Ethernet", + .phy_id_mask = 0x001fffff, + .features = PHY_BASIC_FEATURES, + .flags = PHY_HAS_INTERRUPT, + .config_aneg = &genphy_config_aneg, + .read_status = &genphy_read_status, + .ack_interrupt = &rtl8201_ack_interrupt, + .config_intr = &rtl8201_config_intr, + .suspend = genphy_suspend, + .resume = genphy_resume, }, { .phy_id = 0x001cc912, .name = "RTL8211B Gigabit Ethernet", @@ -186,6 +229,7 @@ static struct phy_driver realtek_drvs[] = { module_phy_driver(realtek_drvs); static struct mdio_device_id __maybe_unused realtek_tbl[] = { + { 0x001cc816, 0x001fffff }, { 0x001cc912, 0x001fffff }, { 0x001cc914, 0x001fffff }, { 0x001cc915, 0x001fffff }, From cd0c207d7747ac36c446099ff018682373999764 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sun, 12 Nov 2017 16:16:04 +0100 Subject: [PATCH] UPSTREAM: net: phy: realtek: fix RTL8211F interrupt mode After commit b94d22d94ad22 "ARM64: dts: meson-gx: add external PHY interrupt on some platforms" ethernet stopped working on my Odroid-C2 which has a RTL8211F phy. It turned out that no interrupts were triggered. Further analysis showed the register INER can't be altered on page 0. Because register INSR needs to be accessed via page 0xa43 I assumed that register INER needs to be accessed via some page too. Some brute force check resulted in page 0xa42 being the right one. With this patch the phy is working properly in interrupt mode. Fixes: 3447cf2e9a11 ("net/phy: Add support for Realtek RTL8211F") Signed-off-by: Heiner Kallweit Tested-by: Jerome Brunet Signed-off-by: David S. Miller (cherry picked from commit 3697d058b08d5b874f0253de173ef72e5d648f9a) --- drivers/net/phy/realtek.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c index 422cf1f6a60c..a30d0c08c63b 100644 --- a/drivers/net/phy/realtek.c +++ b/drivers/net/phy/realtek.c @@ -115,11 +115,13 @@ static int rtl8211f_config_intr(struct phy_device *phydev) { int err; + phy_write(phydev, RTL821x_PAGE_SELECT, 0xa42); if (phydev->interrupts == PHY_INTERRUPT_ENABLED) err = phy_write(phydev, RTL821x_INER, RTL8211F_INER_LINK_STATUS); else err = phy_write(phydev, RTL821x_INER, 0); + phy_write(phydev, RTL821x_PAGE_SELECT, 0); return err; } From df04368281177832f4dff078f0cc735ce651ded1 Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Sat, 2 Dec 2017 22:51:24 +0100 Subject: [PATCH] UPSTREAM: net: phy: realtek: use the BIT and GENMASK macros This makes it easier to compare the #defines with the datasheets. No functional changes. Signed-off-by: Martin Blumenstingl Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller (cherry picked from commit 8cc5baefbc0266b6d6c8e99cb8568f59be36a575) --- drivers/net/phy/realtek.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c index a30d0c08c63b..f8dc29a75828 100644 --- a/drivers/net/phy/realtek.c +++ b/drivers/net/phy/realtek.c @@ -13,21 +13,22 @@ * option) any later version. * */ +#include #include #include #define RTL821x_PHYSR 0x11 -#define RTL821x_PHYSR_DUPLEX 0x2000 -#define RTL821x_PHYSR_SPEED 0xc000 +#define RTL821x_PHYSR_DUPLEX BIT(13) +#define RTL821x_PHYSR_SPEED GENMASK(15, 14) #define RTL821x_INER 0x12 #define RTL821x_INER_INIT 0x6400 #define RTL821x_INSR 0x13 #define RTL821x_PAGE_SELECT 0x1f -#define RTL8211E_INER_LINK_STATUS 0x400 +#define RTL8211E_INER_LINK_STATUS BIT(10) -#define RTL8211F_INER_LINK_STATUS 0x0010 +#define RTL8211F_INER_LINK_STATUS BIT(4) #define RTL8211F_INSR 0x1d -#define RTL8211F_TX_DELAY 0x100 +#define RTL8211F_TX_DELAY BIT(8) #define RTL8201F_ISR 0x1e #define RTL8201F_IER 0x13 From c6479ba05b0013658491a86171df7e0110a0e85a Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Sat, 2 Dec 2017 22:51:25 +0100 Subject: [PATCH] UPSTREAM: net: phy: realtek: rename RTL821x_INER_INIT to RTL8211B_INER_INIT This macro is only used by the RTL8211B code. RTL8211E and RTL8211F both use other bits to initialize the RTL821x_INER register. No functional changes. Signed-off-by: Martin Blumenstingl Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller (cherry picked from commit 69021e32ec3ef02170482f6ed8130febaed27357) --- drivers/net/phy/realtek.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c index f8dc29a75828..89308eac4088 100644 --- a/drivers/net/phy/realtek.c +++ b/drivers/net/phy/realtek.c @@ -21,7 +21,7 @@ #define RTL821x_PHYSR_DUPLEX BIT(13) #define RTL821x_PHYSR_SPEED GENMASK(15, 14) #define RTL821x_INER 0x12 -#define RTL821x_INER_INIT 0x6400 +#define RTL8211B_INER_INIT 0x6400 #define RTL821x_INSR 0x13 #define RTL821x_PAGE_SELECT 0x1f #define RTL8211E_INER_LINK_STATUS BIT(10) @@ -92,7 +92,7 @@ static int rtl8211b_config_intr(struct phy_device *phydev) if (phydev->interrupts == PHY_INTERRUPT_ENABLED) err = phy_write(phydev, RTL821x_INER, - RTL821x_INER_INIT); + RTL8211B_INER_INIT); else err = phy_write(phydev, RTL821x_INER, 0); From c49b1806174ac4140a3fe90c626ef694992f7db6 Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Sat, 2 Dec 2017 22:51:26 +0100 Subject: [PATCH] UPSTREAM: net: phy: realtek: group all register bit #defines for RTL821x_INER This simply moves all register bit #defines which describe the (PHY specific) bits in the RTL821x_INER right below the RTL821x_INER register definition. This makes it easier to spot which registers and bits belong together. No functional changes. Signed-off-by: Martin Blumenstingl Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller (cherry picked from commit a82f266d240d87e6111878bbfe287024fb6857c1) --- drivers/net/phy/realtek.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c index 89308eac4088..df97d903d2bf 100644 --- a/drivers/net/phy/realtek.c +++ b/drivers/net/phy/realtek.c @@ -20,13 +20,16 @@ #define RTL821x_PHYSR 0x11 #define RTL821x_PHYSR_DUPLEX BIT(13) #define RTL821x_PHYSR_SPEED GENMASK(15, 14) + #define RTL821x_INER 0x12 #define RTL8211B_INER_INIT 0x6400 +#define RTL8211E_INER_LINK_STATUS BIT(10) +#define RTL8211F_INER_LINK_STATUS BIT(4) + #define RTL821x_INSR 0x13 + #define RTL821x_PAGE_SELECT 0x1f -#define RTL8211E_INER_LINK_STATUS BIT(10) -#define RTL8211F_INER_LINK_STATUS BIT(4) #define RTL8211F_INSR 0x1d #define RTL8211F_TX_DELAY BIT(8) From 3cd6e2f5de15c4c071d9ca9f02efcbd23b8435ad Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Sat, 2 Dec 2017 22:51:27 +0100 Subject: [PATCH] UPSTREAM: net: phy: realtek: use the same indentation for all #defines This simply makes the code easier to read. No functional changes. Signed-off-by: Martin Blumenstingl Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller (cherry picked from commit f609ab0ed8e7bef2cd61d230bf9e83e1ec5b9ddb) --- drivers/net/phy/realtek.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c index df97d903d2bf..701f34ad7d8d 100644 --- a/drivers/net/phy/realtek.c +++ b/drivers/net/phy/realtek.c @@ -17,24 +17,25 @@ #include #include -#define RTL821x_PHYSR 0x11 -#define RTL821x_PHYSR_DUPLEX BIT(13) -#define RTL821x_PHYSR_SPEED GENMASK(15, 14) +#define RTL821x_PHYSR 0x11 +#define RTL821x_PHYSR_DUPLEX BIT(13) +#define RTL821x_PHYSR_SPEED GENMASK(15, 14) -#define RTL821x_INER 0x12 -#define RTL8211B_INER_INIT 0x6400 -#define RTL8211E_INER_LINK_STATUS BIT(10) -#define RTL8211F_INER_LINK_STATUS BIT(4) +#define RTL821x_INER 0x12 +#define RTL8211B_INER_INIT 0x6400 +#define RTL8211E_INER_LINK_STATUS BIT(10) +#define RTL8211F_INER_LINK_STATUS BIT(4) -#define RTL821x_INSR 0x13 +#define RTL821x_INSR 0x13 -#define RTL821x_PAGE_SELECT 0x1f +#define RTL821x_PAGE_SELECT 0x1f -#define RTL8211F_INSR 0x1d -#define RTL8211F_TX_DELAY BIT(8) +#define RTL8211F_INSR 0x1d -#define RTL8201F_ISR 0x1e -#define RTL8201F_IER 0x13 +#define RTL8211F_TX_DELAY BIT(8) + +#define RTL8201F_ISR 0x1e +#define RTL8201F_IER 0x13 MODULE_DESCRIPTION("Realtek PHY driver"); MODULE_AUTHOR("Johnson Leung"); From 47e40b66fdafc0ce940090626759fe8418034a0e Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Sat, 2 Dec 2017 22:51:28 +0100 Subject: [PATCH] UPSTREAM: net: phy: realtek: add utility functions to read/write page addresses Realtek PHYs implement the concept of so-called "extension pages". The reason for this is probably because these PHYs expose more registers than available in the standard address range. After all read/write operations on such a page are done the driver should switch back to page 0 where the standard MII registers (such as MII_BMCR) are available. When referring to such a register the datasheets of RTL8211E and RTL8211F always specify: - the page / "ext. page" which has to be written to RTL821x_PAGE_SELECT - an address (sometimes also called reg) These new utility functions make the existing code easier to read since it removes some duplication (switching back to page 0 is done within the new helpers for example). No functional changes are intended. Signed-off-by: Martin Blumenstingl Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller (cherry picked from commit 136819a6e8df374e6b9b424586ff11c9e241a1cb) --- drivers/net/phy/realtek.c | 83 ++++++++++++++++++++++++++++++----------------- 1 file changed, 53 insertions(+), 30 deletions(-) diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c index 701f34ad7d8d..b1d52e61d91c 100644 --- a/drivers/net/phy/realtek.c +++ b/drivers/net/phy/realtek.c @@ -41,6 +41,39 @@ MODULE_DESCRIPTION("Realtek PHY driver"); MODULE_AUTHOR("Johnson Leung"); MODULE_LICENSE("GPL"); +static int rtl8211x_page_read(struct phy_device *phydev, u16 page, u16 address) +{ + int ret; + + ret = phy_write(phydev, RTL821x_PAGE_SELECT, page); + if (ret) + return ret; + + ret = phy_read(phydev, address); + + /* restore to default page 0 */ + phy_write(phydev, RTL821x_PAGE_SELECT, 0x0); + + return ret; +} + +static int rtl8211x_page_write(struct phy_device *phydev, u16 page, + u16 address, u16 val) +{ + int ret; + + ret = phy_write(phydev, RTL821x_PAGE_SELECT, page); + if (ret) + return ret; + + ret = phy_write(phydev, address, val); + + /* restore to default page 0 */ + phy_write(phydev, RTL821x_PAGE_SELECT, 0x0); + + return ret; +} + static int rtl8201_ack_interrupt(struct phy_device *phydev) { int err; @@ -63,31 +96,21 @@ static int rtl8211f_ack_interrupt(struct phy_device *phydev) { int err; - phy_write(phydev, RTL821x_PAGE_SELECT, 0xa43); - err = phy_read(phydev, RTL8211F_INSR); - /* restore to default page 0 */ - phy_write(phydev, RTL821x_PAGE_SELECT, 0x0); + err = rtl8211x_page_read(phydev, 0xa43, RTL8211F_INSR); return (err < 0) ? err : 0; } static int rtl8201_config_intr(struct phy_device *phydev) { - int err; - - /* switch to page 7 */ - phy_write(phydev, RTL821x_PAGE_SELECT, 0x7); + u16 val; if (phydev->interrupts == PHY_INTERRUPT_ENABLED) - err = phy_write(phydev, RTL8201F_IER, - BIT(13) | BIT(12) | BIT(11)); + val = BIT(13) | BIT(12) | BIT(11); else - err = phy_write(phydev, RTL8201F_IER, 0); + val = 0; - /* restore to default page 0 */ - phy_write(phydev, RTL821x_PAGE_SELECT, 0x0); - - return err; + return rtl8211x_page_write(phydev, 0x7, RTL8201F_IER, val); } static int rtl8211b_config_intr(struct phy_device *phydev) @@ -118,41 +141,41 @@ static int rtl8211e_config_intr(struct phy_device *phydev) static int rtl8211f_config_intr(struct phy_device *phydev) { - int err; + u16 val; - phy_write(phydev, RTL821x_PAGE_SELECT, 0xa42); if (phydev->interrupts == PHY_INTERRUPT_ENABLED) - err = phy_write(phydev, RTL821x_INER, - RTL8211F_INER_LINK_STATUS); + val = RTL8211F_INER_LINK_STATUS; else - err = phy_write(phydev, RTL821x_INER, 0); - phy_write(phydev, RTL821x_PAGE_SELECT, 0); + val = 0; - return err; + return rtl8211x_page_write(phydev, 0xa42, RTL821x_INER, val); } static int rtl8211f_config_init(struct phy_device *phydev) { int ret; - u16 reg; + u16 val; ret = genphy_config_init(phydev); if (ret < 0) return ret; - phy_write(phydev, RTL821x_PAGE_SELECT, 0xd08); - reg = phy_read(phydev, 0x11); + ret = rtl8211x_page_read(phydev, 0xd08, 0x11); + if (ret < 0) + return ret; + + val = ret & 0xffff; /* enable TX-delay for rgmii-id and rgmii-txid, otherwise disable it */ if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID || phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) - reg |= RTL8211F_TX_DELAY; + val |= RTL8211F_TX_DELAY; else - reg &= ~RTL8211F_TX_DELAY; + val &= ~RTL8211F_TX_DELAY; - phy_write(phydev, 0x11, reg); - /* restore to default page 0 */ - phy_write(phydev, RTL821x_PAGE_SELECT, 0x0); + ret = rtl8211x_page_write(phydev, 0xd08, 0x11, val); + if (ret) + return ret; return 0; } From b747e5d48f83fd4d3b824578f666ac136bc6de49 Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Sat, 2 Dec 2017 23:06:48 +0100 Subject: [PATCH] FROMLIST: net: phy: realtek: add support for configuring the RX delay on RTL8211F On RTL8211F the RX delay can also be enabled/disabled. The overall behavior of the RX delay is similar to the behavior of the TX delay, which was already supported by the driver. The RX delay (similar to the TX delay) may be enabled using hardware pin strapping. If the MAC already configures the RX delay (if required) then the RX delay generated by the RTL8211F PHY has to be turned off. While here, update the comment regarding the TX delay why it has to be enabled or disabled within the driver. Also avoid code-duplication by extracting the code to mask/unmask bits in a paged register into a new rtl8211x_page_mask_bits helper function. Signed-off-by: Martin Blumenstingl --- drivers/net/phy/realtek.c | 55 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 45 insertions(+), 10 deletions(-) diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c index b1d52e61d91c..890ea9d18d27 100644 --- a/drivers/net/phy/realtek.c +++ b/drivers/net/phy/realtek.c @@ -32,7 +32,10 @@ #define RTL8211F_INSR 0x1d -#define RTL8211F_TX_DELAY BIT(8) +#define RTL8211F_RX_DELAY_REG 0x15 +#define RTL8211F_RX_DELAY_EN BIT(3) +#define RTL8211F_TX_DELAY_REG 0x11 +#define RTL8211F_TX_DELAY_EN BIT(8) #define RTL8201F_ISR 0x1e #define RTL8201F_IER 0x13 @@ -74,6 +77,23 @@ static int rtl8211x_page_write(struct phy_device *phydev, u16 page, return ret; } +static int rtl8211x_page_mask_bits(struct phy_device *phydev, u16 page, + u16 address, u16 mask, u16 set) +{ + int ret; + u16 val; + + ret = rtl8211x_page_read(phydev, page, address); + if (ret < 0) + return ret; + + val = ret & 0xffff; + val &= ~mask; + val |= (set & mask); + + return rtl8211x_page_write(phydev, page, address, val); +} + static int rtl8201_ack_interrupt(struct phy_device *phydev) { int err; @@ -160,20 +180,35 @@ static int rtl8211f_config_init(struct phy_device *phydev) if (ret < 0) return ret; - ret = rtl8211x_page_read(phydev, 0xd08, 0x11); - if (ret < 0) - return ret; + /* + * enable TX-delay for rgmii-id and rgmii-txid, otherwise disable it. + * this is needed because it can be enabled by pin strapping and + * conflict with the TX-delay configured by the MAC. + */ + if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID || + phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) + val = RTL8211F_TX_DELAY_EN; + else + val = 0; - val = ret & 0xffff; + ret = rtl8211x_page_mask_bits(phydev, 0xd08, RTL8211F_TX_DELAY_REG, + RTL8211F_TX_DELAY_EN, val); + if (ret) + return ret; - /* enable TX-delay for rgmii-id and rgmii-txid, otherwise disable it */ + /* + * enable RX-delay for rgmii-id and rgmii-rxid, otherwise disable it. + * this is needed because it can be enabled by pin strapping and + * conflict with the RX-delay configured by the MAC. + */ if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID || - phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) - val |= RTL8211F_TX_DELAY; + phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) + val = RTL8211F_RX_DELAY_EN; else - val &= ~RTL8211F_TX_DELAY; + val = 0; - ret = rtl8211x_page_write(phydev, 0xd08, 0x11, val); + ret = rtl8211x_page_mask_bits(phydev, 0xd08, RTL8211F_RX_DELAY_REG, + RTL8211F_RX_DELAY_EN, val); if (ret) return ret; From 4264d7cd3670514648b2ef632097c80e210e5690 Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Sat, 2 Dec 2017 23:06:49 +0100 Subject: [PATCH] FROMLIST: net: phy: realtek: configure the INTB pin on RTL8211F The interrupt pin on the RTL8211F PHY can be used in two different modes: INTB - the default mode of the PHY - interrupts can be configured through page 0xa42 register RTL821x_INER - interrupts can be ACK'ed through RTL8211F_INSR - it acts as a level-interrupt which is active low - Wake-on-LAN "wakeup" status is available in RTL8211F_INSR bit 7 PMEB: - special mode for Wake-on-LAN - interrupts configured through page 0xa42 register RTL821x_INER are disabled - it supports a "pulse low" waveform for the interrupt For now we simply force the pin into INTB mode since the PHY driver does not support Wake-on-LAN yet. Signed-off-by: Martin Blumenstingl --- drivers/net/phy/realtek.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c index 890ea9d18d27..f307d220b49a 100644 --- a/drivers/net/phy/realtek.c +++ b/drivers/net/phy/realtek.c @@ -40,6 +40,9 @@ #define RTL8201F_ISR 0x1e #define RTL8201F_IER 0x13 +#define RTL8211F_INTBCR 0x16 +#define RTL8211F_INTBCR_INTB_PMEB BIT(5) + MODULE_DESCRIPTION("Realtek PHY driver"); MODULE_AUTHOR("Johnson Leung"); MODULE_LICENSE("GPL"); @@ -161,12 +164,32 @@ static int rtl8211e_config_intr(struct phy_device *phydev) static int rtl8211f_config_intr(struct phy_device *phydev) { + int err; u16 val; - if (phydev->interrupts == PHY_INTERRUPT_ENABLED) + if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { + /* + * The interrupt pin has two functions: + * 0: INTB: it acts as interrupt pin which can be configured + * through RTL821x_INER and the status can be read through + * RTL8211F_INSR + * 1: PMEB: a special "Power Management Event" mode for + * Wake-on-LAN operation (with support for a "pulse low" + * wave format). Interrupts configured through RTL821x_INER + * will not work in this mode + * + * select INTB mode in the "INTB pin control" register to + * ensure that the interrupt pin is in the correct mode. + */ + err = rtl8211x_page_mask_bits(phydev, 0xd40, RTL8211F_INTBCR, + RTL8211F_INTBCR_INTB_PMEB, 0); + if (err) + return err; + val = RTL8211F_INER_LINK_STATUS; - else + } else { val = 0; + } return rtl8211x_page_write(phydev, 0xa42, RTL821x_INER, val); } From 5f21ae02ffa16fafd12f635e7a5965842d7d492a Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Sat, 2 Dec 2017 23:06:50 +0100 Subject: [PATCH] FROMLIST: net: phy: realtek: add more interrupt bits for RTL8211E and RTL8211F This documents a few more bits in the RTL821x_INER register for RTL8211E and RTL8211F. These are added only to document them (as no public datasheets are available for these PHYs), they are currently not used. Signed-off-by: Martin Blumenstingl --- drivers/net/phy/realtek.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c index f307d220b49a..15d342eefd6d 100644 --- a/drivers/net/phy/realtek.c +++ b/drivers/net/phy/realtek.c @@ -24,7 +24,14 @@ #define RTL821x_INER 0x12 #define RTL8211B_INER_INIT 0x6400 #define RTL8211E_INER_LINK_STATUS BIT(10) +#define RTL8211E_INER_ANEG_COMPLETED BIT(11) +#define RTL8211E_INER_PAGE_RECEIVED BIT(12) +#define RTL8211E_INER_ANEG_ERROR BIT(15) #define RTL8211F_INER_LINK_STATUS BIT(4) +#define RTL8211F_INER_PHY_REGISTER_ACCESSIBLE BIT(5) +#define RTL8211F_INER_WOL_PME BIT(7) +#define RTL8211F_INER_ALDPS_STATE_CHANGE BIT(9) +#define RTL8211F_INER_JABBER BIT(10) #define RTL821x_INSR 0x13