ath25: switch default kernel to 5.15
[openwrt/staging/wigyori.git] / target / linux / realtek / files-5.10 / drivers / net / phy / rtl83xx-phy.c
index 252389489106c70d046269d9bdcf48f16808662e..491ceb48b6a0a39a899b01467c3e5d22940f5b48 100644 (file)
@@ -6,10 +6,12 @@
 
 #include <linux/module.h>
 #include <linux/delay.h>
+#include <linux/of.h>
 #include <linux/phy.h>
 #include <linux/netdevice.h>
 #include <linux/firmware.h>
 #include <linux/crc32.h>
+#include <linux/sfp.h>
 
 #include <asm/mach-rtl838x/mach-rtl83xx.h>
 #include "rtl83xx-phy.h"
@@ -934,78 +936,96 @@ static int rtl8218b_ext_match_phy_device(struct phy_device *phydev)
                return phydev->phy_id == PHY_ID_RTL8218B_E;
 }
 
-static void rtl8380_rtl8214fc_media_set(struct phy_device *phydev, bool set_fibre)
+static bool rtl8214fc_media_is_fibre(struct phy_device *phydev)
 {
        int mac = phydev->mdio.addr;
 
        static int reg[] = {16, 19, 20, 21};
-       int val, media, power;
+       u32 val;
 
-       pr_info("%s: port %d, set_fibre: %d\n", __func__, mac, set_fibre);
        phy_package_write_paged(phydev, RTL83XX_PAGE_RAW, RTL821XINT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_INTERNAL);
        val = phy_package_read_paged(phydev, RTL821X_PAGE_PORT, reg[mac % 4]);
+       phy_package_write_paged(phydev, RTL83XX_PAGE_RAW, RTL821XINT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_AUTO);
 
-       media = (val >> 10) & 0x3;
-       pr_info("Current media %x\n", media);
-       if (media & 0x2) {
-               pr_info("Powering off COPPER\n");
-               phy_write_paged(phydev, RTL83XX_PAGE_RAW, RTL821XINT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_COPPER);
-               /* Ensure power is off */
-               power = phy_read_paged(phydev, RTL821X_PAGE_POWER, 0x10);
-               if (!(power & (1 << 11)))
-                       phy_write_paged(phydev, RTL821X_PAGE_POWER, 0x10, power | (1 << 11));
-       } else {
-               pr_info("Powering off FIBRE\n");
+       if (val & BIT(11))
+               return false;
+
+       return true;
+}
+
+static void rtl8214fc_power_set(struct phy_device *phydev, int port, bool on)
+{
+       char *state = on ? "on" : "off";
+
+       if (port == PORT_FIBRE) {
+               pr_info("%s: Powering %s FIBRE (port %d)\n", __func__, state, phydev->mdio.addr);
                phy_write_paged(phydev, RTL83XX_PAGE_RAW, RTL821XINT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_FIBRE);
-               /* Ensure power is off */
-               power = phy_read_paged(phydev, RTL821X_PAGE_POWER, 0x10);
-               if (!(power & (1 << 11)))
-                       phy_write_paged(phydev, RTL821X_PAGE_POWER, 0x10, power | (1 << 11));
+       } else {
+               pr_info("%s: Powering %s COPPER (port %d)\n", __func__, state, phydev->mdio.addr);
+               phy_write_paged(phydev, RTL83XX_PAGE_RAW, RTL821XINT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_COPPER);
        }
-       phy_write_paged(phydev, RTL83XX_PAGE_RAW, RTL821XINT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_AUTO);
 
-       if (set_fibre) {
-               val |= 1 << 10;
-               val &= ~(1 << 11);
+       if (on) {
+               phy_modify_paged(phydev, RTL821X_PAGE_POWER, 0x10, BIT(11), 0);
        } else {
-               val |= 1 << 10;
-               val |= 1 << 11;
+               phy_modify_paged(phydev, RTL821X_PAGE_POWER, 0x10, 0, BIT(11));
        }
-       phy_package_write_paged(phydev, RTL83XX_PAGE_RAW, RTL821XINT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_INTERNAL);
-       phy_package_write_paged(phydev, RTL821X_PAGE_PORT, reg[mac % 4], val);
-       phy_package_write_paged(phydev, RTL83XX_PAGE_RAW, RTL821XINT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_AUTO);
 
-       if (set_fibre) {
-               pr_info("Powering on FIBRE\n");
-               phy_write_paged(phydev, RTL83XX_PAGE_RAW, RTL821XINT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_FIBRE);
-               /* Ensure power is off */
-               power = phy_read_paged(phydev, RTL821X_PAGE_POWER, 0x10);
-               if (power & (1 << 11))
-                       phy_write_paged(phydev, RTL821X_PAGE_POWER, 0x10, power & ~(1 << 11));
+       phy_write_paged(phydev, RTL83XX_PAGE_RAW, RTL821XINT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_AUTO);
+}
+
+static int rtl8214fc_suspend(struct phy_device *phydev)
+{
+       rtl8214fc_power_set(phydev, PORT_MII, false);
+       rtl8214fc_power_set(phydev, PORT_FIBRE, false);
+
+       return 0;
+}
+
+static int rtl8214fc_resume(struct phy_device *phydev)
+{
+       if (rtl8214fc_media_is_fibre(phydev)) {
+               rtl8214fc_power_set(phydev, PORT_MII, false);
+               rtl8214fc_power_set(phydev, PORT_FIBRE, true);
        } else {
-               pr_info("Powering on COPPER\n");
-               phy_write_paged(phydev, RTL83XX_PAGE_RAW, RTL821XINT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_COPPER);
-               /* Ensure power is off */
-               power = phy_read_paged(phydev, RTL821X_PAGE_POWER, 0x10);
-               if (power & (1 << 11))
-                       phy_write_paged(phydev, RTL821X_PAGE_POWER, 0x10, power & ~(1 << 11));
+               rtl8214fc_power_set(phydev, PORT_FIBRE, false);
+               rtl8214fc_power_set(phydev, PORT_MII, true);
        }
-       phy_write_paged(phydev, RTL83XX_PAGE_RAW, RTL821XINT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_AUTO);
+
+       return 0;
 }
 
-static bool rtl8380_rtl8214fc_media_is_fibre(struct phy_device *phydev)
+static void rtl8214fc_media_set(struct phy_device *phydev, bool set_fibre)
 {
        int mac = phydev->mdio.addr;
 
        static int reg[] = {16, 19, 20, 21};
-       u32 val;
+       int val;
 
+       pr_info("%s: port %d, set_fibre: %d\n", __func__, mac, set_fibre);
        phy_package_write_paged(phydev, RTL83XX_PAGE_RAW, RTL821XINT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_INTERNAL);
        val = phy_package_read_paged(phydev, RTL821X_PAGE_PORT, reg[mac % 4]);
+
+       val |= BIT(10);
+       if (set_fibre) {
+               val &= ~BIT(11);
+       } else {
+               val |= BIT(11);
+       }
+
+       phy_package_write_paged(phydev, RTL83XX_PAGE_RAW, RTL821XINT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_INTERNAL);
+       phy_package_write_paged(phydev, RTL821X_PAGE_PORT, reg[mac % 4], val);
        phy_package_write_paged(phydev, RTL83XX_PAGE_RAW, RTL821XINT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_AUTO);
-       if (val & (1 << 11))
-               return false;
-       return true;
+
+       if (!phydev->suspended) {
+               if (set_fibre) {
+                       rtl8214fc_power_set(phydev, PORT_MII, false);
+                       rtl8214fc_power_set(phydev, PORT_FIBRE, true);
+               } else {
+                       rtl8214fc_power_set(phydev, PORT_FIBRE, false);
+                       rtl8214fc_power_set(phydev, PORT_MII, true);
+               }
+       }
 }
 
 static int rtl8214fc_set_port(struct phy_device *phydev, int port)
@@ -1015,7 +1035,7 @@ static int rtl8214fc_set_port(struct phy_device *phydev, int port)
 
        pr_debug("%s port %d to %d\n", __func__, addr, port);
 
-       rtl8380_rtl8214fc_media_set(phydev, is_fibre);
+       rtl8214fc_media_set(phydev, is_fibre);
        return 0;
 }
 
@@ -1024,7 +1044,7 @@ static int rtl8214fc_get_port(struct phy_device *phydev)
        int addr = phydev->mdio.addr;
 
        pr_debug("%s: port %d\n", __func__, addr);
-       if (rtl8380_rtl8214fc_media_is_fibre(phydev))
+       if (rtl8214fc_media_is_fibre(phydev))
                return PORT_FIBRE;
        return PORT_MII;
 }
@@ -1131,7 +1151,7 @@ static int rtl8214fc_set_eee(struct phy_device *phydev,
 
        pr_debug("In %s port %d, enabled %d\n", __func__, port, e->eee_enabled);
 
-       if (rtl8380_rtl8214fc_media_is_fibre(phydev)) {
+       if (rtl8214fc_media_is_fibre(phydev)) {
                netdev_err(phydev->attached_dev, "Port %d configured for FIBRE", port);
                return -ENOTSUPP;
        }
@@ -1184,7 +1204,7 @@ static int rtl8214fc_get_eee(struct phy_device *phydev,
        int addr = phydev->mdio.addr;
 
        pr_debug("In %s port %d, enabled %d\n", __func__, addr, e->eee_enabled);
-       if (rtl8380_rtl8214fc_media_is_fibre(phydev)) {
+       if (rtl8214fc_media_is_fibre(phydev)) {
                netdev_err(phydev->attached_dev, "Port %d configured for FIBRE", addr);
                return -ENOTSUPP;
        }
@@ -1678,7 +1698,6 @@ void rtl9300_force_sds_mode(int sds, phy_interface_t phy_if)
        u32 v, cr_0, cr_1, cr_2;
        u32 m_bit, l_bit;
 
-       pr_info("%s --------------------- serdes %d forcing to %x ...\n", __func__, sds, sds_mode);
        pr_info("%s: SDS: %d, mode %d\n", __func__, sds, phy_if);
        switch (phy_if) {
        case PHY_INTERFACE_MODE_SGMII:
@@ -1721,7 +1740,7 @@ void rtl9300_force_sds_mode(int sds, phy_interface_t phy_if)
                return;
        }
 
-       pr_info("%s: SDS mode %x\n", __func__, sds_mode);
+       pr_info("%s --------------------- serdes %d forcing to %x ...\n", __func__, sds, sds_mode);
        // Power down SerDes
        rtl9300_sds_field_w(sds, 0x20, 0, 7, 6, 0x3);
        if (sds == 5) pr_info("%s after %x\n", __func__, rtl930x_read_sds_phy(sds, 0x20, 0));
@@ -3658,6 +3677,29 @@ int rtl931x_link_sts_get(u32 sds)
        return sts1;
 }
 
+static int rtl8214fc_sfp_insert(void *upstream, const struct sfp_eeprom_id *id)
+{
+       struct phy_device *phydev = upstream;
+
+       rtl8214fc_media_set(phydev, true);
+
+       return 0;
+}
+
+static void rtl8214fc_sfp_remove(void *upstream)
+{
+       struct phy_device *phydev = upstream;
+
+       rtl8214fc_media_set(phydev, false);
+}
+
+static const struct sfp_upstream_ops rtl8214fc_sfp_ops = {
+       .attach = phy_sfp_attach,
+       .detach = phy_sfp_detach,
+       .module_insert = rtl8214fc_sfp_insert,
+       .module_remove = rtl8214fc_sfp_remove,
+};
+
 static int rtl8214fc_phy_probe(struct phy_device *phydev)
 {
        struct device *dev = &phydev->mdio.dev;
@@ -3681,7 +3723,7 @@ static int rtl8214fc_phy_probe(struct phy_device *phydev)
                        return ret;
        }
 
-       return 0;
+       return phy_sfp_probe(phydev, &rtl8214fc_sfp_ops);
 }
 
 static int rtl8214c_phy_probe(struct phy_device *phydev)
@@ -3842,8 +3884,8 @@ static struct phy_driver rtl83xx_phy_driver[] = {
                .flags          = PHY_HAS_REALTEK_PAGES,
                .match_phy_device = rtl8214fc_match_phy_device,
                .probe          = rtl8214fc_phy_probe,
-               .suspend        = genphy_suspend,
-               .resume         = genphy_resume,
+               .suspend        = rtl8214fc_suspend,
+               .resume         = rtl8214fc_resume,
                .set_loopback   = genphy_loopback,
                .set_port       = rtl8214fc_set_port,
                .get_port       = rtl8214fc_get_port,