generic: ar8216: add ar8xxx_create{,mii} helpers
[librecmc/librecmc.git] / target / linux / generic / files / drivers / net / phy / ar8216.c
index e6a460734fe207f16c1e780ebbc986a3845c99e8..f7fbf4e498e745a18656438b53e9d9558dbbbeb1 100644 (file)
@@ -788,7 +788,7 @@ ar8316_hw_init(struct ar8216_priv *priv)
        u32 val, newval;
        struct mii_bus *bus;
 
-       val = priv->read(priv, 0x8);
+       val = priv->read(priv, AR8316_REG_POSTRIP);
 
        if (priv->phy->interface == PHY_INTERFACE_MODE_RGMII) {
                if (priv->port4_phy) {
@@ -812,7 +812,7 @@ ar8316_hw_init(struct ar8216_priv *priv)
        if (val == newval)
                goto out;
 
-       priv->write(priv, 0x8, newval);
+       priv->write(priv, AR8316_REG_POSTRIP, newval);
 
        /* Initialize the ports */
        bus = priv->mii_bus;
@@ -833,9 +833,10 @@ ar8316_hw_init(struct ar8216_priv *priv)
                        ADVERTISE_ALL | ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM);
                mdiobus_write(bus, i, MII_CTRL1000, ADVERTISE_1000FULL);
                mdiobus_write(bus, i, MII_BMCR, BMCR_RESET | BMCR_ANENABLE);
-               msleep(1000);
        }
 
+       msleep(1000);
+
 out:
        priv->initialized = true;
        return 0;
@@ -1741,9 +1742,6 @@ ar8xxx_mib_init(struct ar8216_priv *priv)
        if (!priv->mib_stats)
                return -ENOMEM;
 
-       mutex_init(&priv->mib_lock);
-       INIT_DELAYED_WORK(&priv->mib_work, ar8xxx_mib_work_func);
-
        return 0;
 }
 
@@ -1767,6 +1765,37 @@ ar8xxx_mib_cleanup(struct ar8216_priv *priv)
        kfree(priv->mib_stats);
 }
 
+static struct ar8216_priv *
+ar8xxx_create(void)
+{
+       struct ar8216_priv *priv;
+
+       priv = kzalloc(sizeof(struct ar8216_priv), GFP_KERNEL);
+       if (priv == NULL)
+               return NULL;
+
+       mutex_init(&priv->reg_mutex);
+       mutex_init(&priv->mib_lock);
+       INIT_DELAYED_WORK(&priv->mib_work, ar8xxx_mib_work_func);
+
+       return priv;
+}
+
+static struct ar8216_priv *
+ar8xxx_create_mii(struct mii_bus *bus)
+{
+       struct ar8216_priv *priv;
+
+       priv = ar8xxx_create();
+       if (priv) {
+               priv->mii_bus = bus;
+               priv->read = ar8216_mii_read;
+               priv->write = ar8216_mii_write;
+       }
+
+       return priv;
+}
+
 static int
 ar8216_config_init(struct phy_device *pdev)
 {
@@ -1776,21 +1805,17 @@ ar8216_config_init(struct phy_device *pdev)
        int ret;
 
        if (!priv) {
-               priv = kzalloc(sizeof(struct ar8216_priv), GFP_KERNEL);
+               priv = ar8xxx_create_mii(pdev->bus);
                if (priv == NULL)
                        return -ENOMEM;
-       }
 
-       priv->mii_bus = pdev->bus;
-       priv->read = ar8216_mii_read;
-       priv->write = ar8216_mii_write;
+               ret = ar8216_id_chip(priv);
+               if (ret)
+                       goto err_free_priv;
+       }
 
        priv->phy = pdev;
 
-       ret = ar8216_id_chip(priv);
-       if (ret)
-               goto err_free_priv;
-
        if (ar8xxx_has_gige(priv))
                pdev->supported = SUPPORTED_1000baseT_Full;
        else
@@ -1828,8 +1853,6 @@ ar8216_config_init(struct phy_device *pdev)
                return 0;
        }
 
-       mutex_init(&priv->reg_mutex);
-
        pdev->priv = priv;
 
        swdev = &priv->dev;
@@ -1879,10 +1902,9 @@ ar8216_config_init(struct phy_device *pdev)
        if (ret)
                goto err_unregister_switch;
 
-       dev->phy_ptr = priv;
-
        /* VID fixup only needed on ar8216 */
-       if (chip_is_ar8216(priv) && pdev->addr == 0) {
+       if (chip_is_ar8216(priv)) {
+               dev->phy_ptr = priv;
                dev->priv_flags |= IFF_NO_IP_ALIGN;
                dev->eth_mangle_rx = ar8216_mangle_rx;
                dev->eth_mangle_tx = ar8216_mangle_tx;
@@ -1955,19 +1977,61 @@ ar8216_config_aneg(struct phy_device *phydev)
        return genphy_config_aneg(phydev);
 }
 
+static const u32 ar8xxx_phy_ids[] = {
+       0x004dd033,
+       0x004dd041,
+       0x004dd042,
+};
+
+static bool
+ar8xxx_phy_match(u32 phy_id)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(ar8xxx_phy_ids); i++)
+               if (phy_id == ar8xxx_phy_ids[i])
+                       return true;
+
+       return false;
+}
+
+static bool
+ar8xxx_is_possible(struct mii_bus *bus)
+{
+       unsigned i;
+
+       for (i = 0; i < 4; i++) {
+               u32 phy_id;
+
+               phy_id = mdiobus_read(bus, i, MII_PHYSID1) << 16;
+               phy_id |= mdiobus_read(bus, i, MII_PHYSID2);
+               if (!ar8xxx_phy_match(phy_id)) {
+                       pr_debug("ar8xxx: unknown PHY at %s:%02x id:%08x\n",
+                                dev_name(&bus->dev), i, phy_id);
+                       return false;
+               }
+       }
+
+       return true;
+}
+
 static int
 ar8216_probe(struct phy_device *pdev)
 {
        struct ar8216_priv *priv;
        int ret;
 
-       priv = kzalloc(sizeof(struct ar8216_priv), GFP_KERNEL);
+       /* skip PHYs at unused adresses */
+       if (pdev->addr != 0 && pdev->addr != 4)
+               return -ENODEV;
+
+       if (!ar8xxx_is_possible(pdev->bus))
+               return -ENODEV;
+
+       priv = ar8xxx_create_mii(pdev->bus);
        if (priv == NULL)
                return -ENOMEM;
 
-       priv->mii_bus = pdev->bus;
-       priv->read = ar8216_mii_read;
-       priv->write = ar8216_mii_write;
        priv->phy = pdev;
 
        ret = ar8216_id_chip(priv);