net: renesas: rswitch: Add runtime speed change support
authorYoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Mon, 7 Aug 2023 00:32:30 +0000 (09:32 +0900)
committerJakub Kicinski <kuba@kernel.org>
Tue, 8 Aug 2023 22:31:52 +0000 (15:31 -0700)
The latest SoC version can support runtime speed change. So,
add detect SoC version by using soc_device_match() and then
reconfigure the hardware of this and SerDes if needed.

Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://lore.kernel.org/r/20230807003231.1552062-2-yoshihiro.shimoda.uh@renesas.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/renesas/rswitch.c
drivers/net/ethernet/renesas/rswitch.h

index 0ba7fb75d5893bb1d16c458de2277387f474a6cc..fd3668b958345cccfa1c8c2be551ff2a3e018a45 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/rtnetlink.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
+#include <linux/sys_soc.h>
 
 #include "rswitch.h"
 
@@ -1243,7 +1244,6 @@ static void rswitch_adjust_link(struct net_device *ndev)
        struct rswitch_device *rdev = netdev_priv(ndev);
        struct phy_device *phydev = ndev->phydev;
 
-       /* Current hardware has a restriction not to change speed at runtime */
        if (phydev->link != rdev->etha->link) {
                phy_print_status(phydev);
                if (phydev->link)
@@ -1252,13 +1252,23 @@ static void rswitch_adjust_link(struct net_device *ndev)
                        phy_power_off(rdev->serdes);
 
                rdev->etha->link = phydev->link;
+
+               if (!rdev->priv->etha_no_runtime_change &&
+                   phydev->speed != rdev->etha->speed) {
+                       rdev->etha->speed = phydev->speed;
+
+                       rswitch_etha_hw_init(rdev->etha, rdev->ndev->dev_addr);
+                       phy_set_speed(rdev->serdes, rdev->etha->speed);
+               }
        }
 }
 
 static void rswitch_phy_remove_link_mode(struct rswitch_device *rdev,
                                         struct phy_device *phydev)
 {
-       /* Current hardware has a restriction not to change speed at runtime */
+       if (!rdev->priv->etha_no_runtime_change)
+               return;
+
        switch (rdev->etha->speed) {
        case SPEED_2500:
                phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_1000baseT_Full_BIT);
@@ -1347,7 +1357,8 @@ static int rswitch_ether_port_init_one(struct rswitch_device *rdev)
                err = rswitch_etha_hw_init(rdev->etha, rdev->ndev->dev_addr);
                if (err < 0)
                        return err;
-               rdev->etha->operated = true;
+               if (rdev->priv->etha_no_runtime_change)
+                       rdev->etha->operated = true;
        }
 
        err = rswitch_mii_register(rdev);
@@ -1853,8 +1864,14 @@ err_ts_queue_alloc:
        return err;
 }
 
+static const struct soc_device_attribute rswitch_soc_no_speed_change[]  = {
+       { .soc_id = "r8a779f0", .revision = "ES1.0" },
+       { /* Sentinel */ }
+};
+
 static int renesas_eth_sw_probe(struct platform_device *pdev)
 {
+       const struct soc_device_attribute *attr;
        struct rswitch_private *priv;
        struct resource *res;
        int ret;
@@ -1869,6 +1886,10 @@ static int renesas_eth_sw_probe(struct platform_device *pdev)
        if (!priv)
                return -ENOMEM;
 
+       attr = soc_device_match(rswitch_soc_no_speed_change);
+       if (attr)
+               priv->etha_no_runtime_change = true;
+
        priv->ptp_priv = rcar_gen4_ptp_alloc(pdev);
        if (!priv->ptp_priv)
                return -ENOMEM;
index bb9ed971a97cace8159c0ccff03f7adef03bb4b0..54f397effbc6b1ee17f669f6411776634a4ff586 100644 (file)
@@ -1011,6 +1011,7 @@ struct rswitch_private {
        struct rswitch_etha etha[RSWITCH_NUM_PORTS];
        struct rswitch_mfwd mfwd;
 
+       bool etha_no_runtime_change;
        bool gwca_halt;
 };