Add a structure holding required operations for each device such as device
initialization, PHY port read or write, a checker whether PHY interface is
supported on a certain port, MAC port setup for either bus pad or a
specific PHY interface.

The patch is done for ready adding a new hardware MT7531, and keep the
same setup logic of existing hardware.

Signed-off-by: Landen Chao <landen.c...@mediatek.com>
Signed-off-by: Sean Wang <sean.w...@mediatek.com>
---
 drivers/net/dsa/mt7530.c | 271 ++++++++++++++++++++++++++++-----------
 drivers/net/dsa/mt7530.h |  37 +++++-
 2 files changed, 234 insertions(+), 74 deletions(-)

diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c
index 238417db26f9..9c6f80b3e5f5 100644
--- a/drivers/net/dsa/mt7530.c
+++ b/drivers/net/dsa/mt7530.c
@@ -372,8 +372,9 @@ mt7530_fdb_write(struct mt7530_priv *priv, u16 vid,
                mt7530_write(priv, MT7530_ATA1 + (i * 4), reg[i]);
 }
 
+/* Setup TX circuit including relevant PAD and driving */
 static int
-mt7530_pad_clk_setup(struct dsa_switch *ds, int mode)
+mt7530_pad_clk_setup(struct dsa_switch *ds, phy_interface_t interface)
 {
        struct mt7530_priv *priv = ds->priv;
        u32 ncpo1, ssc_delta, trgint, i, xtal;
@@ -387,7 +388,7 @@ mt7530_pad_clk_setup(struct dsa_switch *ds, int mode)
                return -EINVAL;
        }
 
-       switch (mode) {
+       switch (interface) {
        case PHY_INTERFACE_MODE_RGMII:
                trgint = 0;
                /* PLL frequency: 125MHz */
@@ -409,7 +410,8 @@ mt7530_pad_clk_setup(struct dsa_switch *ds, int mode)
                }
                break;
        default:
-               dev_err(priv->dev, "xMII mode %d not supported\n", mode);
+               dev_err(priv->dev, "xMII interface %d not supported\n",
+                       interface);
                return -EINVAL;
        }
 
@@ -1349,47 +1351,116 @@ mt7530_setup(struct dsa_switch *ds)
        return 0;
 }
 
-static void mt7530_phylink_mac_config(struct dsa_switch *ds, int port,
-                                     unsigned int mode,
-                                     const struct phylink_link_state *state)
+static bool
+mt7530_phy_mode_supported(struct dsa_switch *ds, int port,
+                         const struct phylink_link_state *state)
 {
        struct mt7530_priv *priv = ds->priv;
-       u32 mcr_cur, mcr_new;
 
        switch (port) {
-       case 0: /* Internal phy */
-       case 1:
-       case 2:
-       case 3:
-       case 4:
+       case 0 ... 4: /* Internal phy */
                if (state->interface != PHY_INTERFACE_MODE_GMII)
-                       return;
+                       return false;
                break;
        case 5: /* 2nd cpu port with phy of port 0 or 4 / external phy */
-               if (priv->p5_interface == state->interface)
-                       break;
                if (!phy_interface_mode_is_rgmii(state->interface) &&
                    state->interface != PHY_INTERFACE_MODE_MII &&
                    state->interface != PHY_INTERFACE_MODE_GMII)
-                       return;
+                       return false;
+               break;
+       case 6: /* 1st cpu port */
+               if (state->interface != PHY_INTERFACE_MODE_RGMII &&
+                   state->interface != PHY_INTERFACE_MODE_TRGMII)
+                       return false;
+               break;
+       default:
+               dev_err(priv->dev, "%s: unsupported port: %i\n", __func__,
+                       port);
+               return false;
+       }
+
+       return true;
+}
+
+static bool
+mt753x_phy_mode_supported(struct dsa_switch *ds, int port,
+                         const struct phylink_link_state *state)
+{
+       struct mt7530_priv *priv = ds->priv;
+
+       return priv->info->phy_mode_supported(ds, port, state);
+}
+
+static int
+mt753x_pad_setup(struct dsa_switch *ds, const struct phylink_link_state *state)
+{
+       struct mt7530_priv *priv = ds->priv;
+
+       return priv->info->pad_setup(ds, state->interface);
+}
+
+static int
+mt7530_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
+                 phy_interface_t interface)
+{
+       struct mt7530_priv *priv = ds->priv;
+
+       /* Only need to setup port5. */
+       if (port != 5)
+               return 0;
+
+       mt7530_setup_port5(priv->ds, interface);
+
+       return 0;
+}
+
+static int
+mt753x_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
+                 const struct phylink_link_state *state)
+{
+       struct mt7530_priv *priv = ds->priv;
+
+       return priv->info->mac_port_config(ds, port, mode, state->interface);
+}
+
+static void
+mt753x_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
+                         const struct phylink_link_state *state)
+{
+       struct mt7530_priv *priv = ds->priv;
+       u32 mcr_cur, mcr_new;
+
+       if (!mt753x_phy_mode_supported(ds, port, state))
+               goto unsupported;
+
+       switch (port) {
+       case 0 ... 4: /* Internal phy */
+               if (state->interface != PHY_INTERFACE_MODE_GMII)
+                       goto unsupported;
+               break;
+       case 5: /* 2nd cpu port with phy of port 0 or 4 / external phy */
+               if (priv->p5_interface == state->interface)
+                       break;
+
+               if (mt753x_mac_config(ds, port, mode, state) < 0)
+                       goto unsupported;
 
-               mt7530_setup_port5(ds, state->interface);
                break;
        case 6: /* 1st cpu port */
                if (priv->p6_interface == state->interface)
                        break;
 
-               if (state->interface != PHY_INTERFACE_MODE_RGMII &&
-                   state->interface != PHY_INTERFACE_MODE_TRGMII)
-                       return;
+               mt753x_pad_setup(ds, state);
 
-               /* Setup TX circuit incluing relevant PAD and driving */
-               mt7530_pad_clk_setup(ds, state->interface);
+               if (mt753x_mac_config(ds, port, mode, state) < 0)
+                       goto unsupported;
 
                priv->p6_interface = state->interface;
                break;
        default:
-               dev_err(ds->dev, "%s: unsupported port: %i\n", __func__, port);
+unsupported:
+               dev_err(ds->dev, "%s: unsupported %s port: %i\n",
+                       __func__, phy_modes(state->interface), port);
                return;
        }
 
@@ -1453,61 +1524,44 @@ static void mt7530_phylink_mac_link_up(struct 
dsa_switch *ds, int port,
        mt7530_set(priv, MT7530_PMCR_P(port), mcr);
 }
 
-static void mt7530_phylink_validate(struct dsa_switch *ds, int port,
-                                   unsigned long *supported,
-                                   struct phylink_link_state *state)
+static void
+mt7530_mac_port_validate(struct dsa_switch *ds, int port,
+                        unsigned long *supported)
+{
+       if (port == 5)
+               phylink_set(supported, 1000baseX_Full);
+}
+
+static void
+mt753x_phylink_validate(struct dsa_switch *ds, int port,
+                       unsigned long *supported,
+                       struct phylink_link_state *state)
 {
        __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
+       struct mt7530_priv *priv = ds->priv;
 
-       switch (port) {
-       case 0: /* Internal phy */
-       case 1:
-       case 2:
-       case 3:
-       case 4:
-               if (state->interface != PHY_INTERFACE_MODE_NA &&
-                   state->interface != PHY_INTERFACE_MODE_GMII)
-                       goto unsupported;
-               break;
-       case 5: /* 2nd cpu port with phy of port 0 or 4 / external phy */
-               if (state->interface != PHY_INTERFACE_MODE_NA &&
-                   !phy_interface_mode_is_rgmii(state->interface) &&
-                   state->interface != PHY_INTERFACE_MODE_MII &&
-                   state->interface != PHY_INTERFACE_MODE_GMII)
-                       goto unsupported;
-               break;
-       case 6: /* 1st cpu port */
-               if (state->interface != PHY_INTERFACE_MODE_NA &&
-                   state->interface != PHY_INTERFACE_MODE_RGMII &&
-                   state->interface != PHY_INTERFACE_MODE_TRGMII)
-                       goto unsupported;
-               break;
-       default:
-               dev_err(ds->dev, "%s: unsupported port: %i\n", __func__, port);
-unsupported:
+       if (state->interface != PHY_INTERFACE_MODE_NA &&
+           !mt753x_phy_mode_supported(ds, port, state)) {
                linkmode_zero(supported);
                return;
        }
 
        phylink_set_port_modes(mask);
-       phylink_set(mask, Autoneg);
 
-       if (state->interface == PHY_INTERFACE_MODE_TRGMII) {
-               phylink_set(mask, 1000baseT_Full);
-       } else {
+       if (state->interface != PHY_INTERFACE_MODE_TRGMII) {
                phylink_set(mask, 10baseT_Half);
                phylink_set(mask, 10baseT_Full);
                phylink_set(mask, 100baseT_Half);
                phylink_set(mask, 100baseT_Full);
-
-               if (state->interface != PHY_INTERFACE_MODE_MII) {
-                       /* This switch only supports 1G full-duplex. */
-                       phylink_set(mask, 1000baseT_Full);
-                       if (port == 5)
-                               phylink_set(mask, 1000baseX_Full);
-               }
+               phylink_set(mask, Autoneg);
        }
 
+       /* This switch only supports 1G full-duplex. */
+       if (state->interface != PHY_INTERFACE_MODE_MII)
+               phylink_set(mask, 1000baseT_Full);
+
+       priv->info->mac_port_validate(ds, port, mask);
+
        phylink_set(mask, Pause);
        phylink_set(mask, Asym_Pause);
 
@@ -1555,12 +1609,45 @@ mt7530_phylink_mac_link_state(struct dsa_switch *ds, 
int port,
        return 1;
 }
 
+static int
+mt753x_phylink_mac_link_state(struct dsa_switch *ds, int port,
+                             struct phylink_link_state *state)
+{
+       struct mt7530_priv *priv = ds->priv;
+
+       return priv->info->mac_port_get_state(ds, port, state);
+}
+
+static int
+mt753x_setup(struct dsa_switch *ds)
+{
+       struct mt7530_priv *priv = ds->priv;
+
+       return priv->info->sw_setup(ds);
+}
+
+static int
+mt753x_phy_read(struct dsa_switch *ds, int port, int regnum)
+{
+       struct mt7530_priv *priv = ds->priv;
+
+       return priv->info->phy_read(ds, port, regnum);
+}
+
+static int
+mt753x_phy_write(struct dsa_switch *ds, int port, int regnum, u16 val)
+{
+       struct mt7530_priv *priv = ds->priv;
+
+       return priv->info->phy_write(ds, port, regnum, val);
+}
+
 static const struct dsa_switch_ops mt7530_switch_ops = {
        .get_tag_protocol       = mtk_get_tag_protocol,
-       .setup                  = mt7530_setup,
+       .setup                  = mt753x_setup,
        .get_strings            = mt7530_get_strings,
-       .phy_read               = mt7530_phy_read,
-       .phy_write              = mt7530_phy_write,
+       .phy_read               = mt753x_phy_read,
+       .phy_write              = mt753x_phy_write,
        .get_ethtool_stats      = mt7530_get_ethtool_stats,
        .get_sset_count         = mt7530_get_sset_count,
        .port_enable            = mt7530_port_enable,
@@ -1577,16 +1664,41 @@ static const struct dsa_switch_ops mt7530_switch_ops = {
        .port_vlan_del          = mt7530_port_vlan_del,
        .port_mirror_add        = mt7530_port_mirror_add,
        .port_mirror_del        = mt7530_port_mirror_del,
-       .phylink_validate       = mt7530_phylink_validate,
-       .phylink_mac_link_state = mt7530_phylink_mac_link_state,
-       .phylink_mac_config     = mt7530_phylink_mac_config,
+       .phylink_validate       = mt753x_phylink_validate,
+       .phylink_mac_link_state = mt753x_phylink_mac_link_state,
+       .phylink_mac_config     = mt753x_phylink_mac_config,
        .phylink_mac_link_down  = mt7530_phylink_mac_link_down,
        .phylink_mac_link_up    = mt7530_phylink_mac_link_up,
 };
 
+static const struct mt753x_info mt753x_table[] = {
+       [ID_MT7621] = {
+               .id = ID_MT7621,
+               .sw_setup = mt7530_setup,
+               .phy_read = mt7530_phy_read,
+               .phy_write = mt7530_phy_write,
+               .pad_setup = mt7530_pad_clk_setup,
+               .phy_mode_supported = mt7530_phy_mode_supported,
+               .mac_port_validate = mt7530_mac_port_validate,
+               .mac_port_get_state = mt7530_phylink_mac_link_state,
+               .mac_port_config = mt7530_mac_config,
+       },
+       [ID_MT7530] = {
+               .id = ID_MT7530,
+               .sw_setup = mt7530_setup,
+               .phy_read = mt7530_phy_read,
+               .phy_write = mt7530_phy_write,
+               .pad_setup = mt7530_pad_clk_setup,
+               .phy_mode_supported = mt7530_phy_mode_supported,
+               .mac_port_validate = mt7530_mac_port_validate,
+               .mac_port_get_state = mt7530_phylink_mac_link_state,
+               .mac_port_config = mt7530_mac_config,
+       },
+};
+
 static const struct of_device_id mt7530_of_match[] = {
-       { .compatible = "mediatek,mt7621", .data = (void *)ID_MT7621, },
-       { .compatible = "mediatek,mt7530", .data = (void *)ID_MT7530, },
+       { .compatible = "mediatek,mt7621", .data = &mt753x_table[ID_MT7621], },
+       { .compatible = "mediatek,mt7530", .data = &mt753x_table[ID_MT7530], },
        { /* sentinel */ },
 };
 MODULE_DEVICE_TABLE(of, mt7530_of_match);
@@ -1627,8 +1739,21 @@ mt7530_probe(struct mdio_device *mdiodev)
        /* Get the hardware identifier from the devicetree node.
         * We will need it for some of the clock and regulator setup.
         */
-       priv->id = (unsigned int)(unsigned long)
-               of_device_get_match_data(&mdiodev->dev);
+       priv->info = of_device_get_match_data(&mdiodev->dev);
+       if (!priv->info)
+               return -EINVAL;
+
+       /* Sanity check if these required device operations are filled
+        * properly.
+        */
+       if (!priv->info->sw_setup || !priv->info->pad_setup ||
+           !priv->info->phy_read || !priv->info->phy_write ||
+           !priv->info->phy_mode_supported ||
+           !priv->info->mac_port_validate ||
+           !priv->info->mac_port_get_state || !priv->info->mac_port_config)
+               return -EINVAL;
+
+       priv->id = priv->info->id;
 
        if (priv->id == ID_MT7530) {
                priv->core_pwr = devm_regulator_get(&mdiodev->dev, "core");
diff --git a/drivers/net/dsa/mt7530.h b/drivers/net/dsa/mt7530.h
index 14de60d0b9ca..44ac55433089 100644
--- a/drivers/net/dsa/mt7530.h
+++ b/drivers/net/dsa/mt7530.h
@@ -11,7 +11,7 @@
 #define MT7530_NUM_FDB_RECORDS         2048
 #define MT7530_ALL_MEMBERS             0xff
 
-enum {
+enum mt753x_id {
        ID_MT7530 = 0,
        ID_MT7621 = 1,
 };
@@ -443,6 +443,40 @@ static const char *p5_intf_modes(unsigned int p5_interface)
        }
 }
 
+/* struct mt753x_info -        This is the main data structure for holding the 
specific
+ *                     part for each supported device
+ * @sw_setup:          Holding the handler to a device initialization
+ * @phy_read:          Holding the way reading PHY port
+ * @phy_write:         Holding the way writing PHY port
+ * @pad_setup:         Holding the way setting up the bus pad for a certain
+ *                     MAC port
+ * @phy_mode_supported:        Check if the PHY type is being supported on a 
certain
+ *                     port
+ * @mac_port_validate: Holding the way to set addition validate type for a
+ *                     certan MAC port
+ * @mac_port_get_state: Holding the way getting the MAC/PCS state for a certain
+ *                     MAC port
+ * @mac_port_config:   Holding the way setting up the PHY attribute to a
+ *                     certain MAC port
+ */
+struct mt753x_info {
+       enum mt753x_id id;
+
+       int (*sw_setup)(struct dsa_switch *ds);
+       int (*phy_read)(struct dsa_switch *ds, int port, int regnum);
+       int (*phy_write)(struct dsa_switch *ds, int port, int regnum, u16 val);
+       int (*pad_setup)(struct dsa_switch *ds, phy_interface_t interface);
+       bool (*phy_mode_supported)(struct dsa_switch *ds, int port,
+                                  const struct phylink_link_state *state);
+       void (*mac_port_validate)(struct dsa_switch *ds, int port,
+                                 unsigned long *supported);
+       int (*mac_port_get_state)(struct dsa_switch *ds, int port,
+                                 struct phylink_link_state *state);
+       int (*mac_port_config)(struct dsa_switch *ds, int port,
+                              unsigned int mode,
+                              phy_interface_t interface);
+};
+
 /* struct mt7530_priv -        This is the main data structure for holding the 
state
  *                     of the driver
  * @dev:               The device pointer
@@ -468,6 +502,7 @@ struct mt7530_priv {
        struct regulator        *core_pwr;
        struct regulator        *io_pwr;
        struct gpio_desc        *reset;
+       const struct mt753x_info *info;
        unsigned int            id;
        bool                    mcm;
        phy_interface_t         p6_interface;
-- 
2.17.1

Reply via email to