mvsw61xx: reset phys on probe to enable switch ports on clearfog pro
[openwrt/staging/rmilecki.git] / target / linux / generic / files / drivers / net / phy / mvsw61xx.c
index 4d6dfc52cd2fb547f2ae9e8da61c309b896529a9..e6074e35f308863b961aafdbfa9bf0bcfb855b84 100644 (file)
@@ -147,6 +147,31 @@ mvsw61xx_wait_mask_s(struct switch_dev *dev, int addr,
        return -ETIMEDOUT;
 }
 
+static int
+mvsw61xx_mdio_read(struct switch_dev *dev, int addr, int reg)
+{
+       sw16(dev, MV_GLOBAL2REG(SMI_OP),
+            MV_INDIRECT_READ | (addr << MV_INDIRECT_ADDR_S) | reg);
+
+       if (mvsw61xx_wait_mask_s(dev,  MV_GLOBAL2REG(SMI_OP),
+                                MV_INDIRECT_INPROGRESS, 0) < 0)
+               return -ETIMEDOUT;
+
+       return sr16(dev, MV_GLOBAL2REG(SMI_DATA));
+}
+
+static int
+mvsw61xx_mdio_write(struct switch_dev *dev, int addr, int reg, u16 val)
+{
+       sw16(dev, MV_GLOBAL2REG(SMI_DATA), val);
+
+       sw16(dev, MV_GLOBAL2REG(SMI_OP),
+            MV_INDIRECT_WRITE | (addr << MV_INDIRECT_ADDR_S) | reg);
+
+       return mvsw61xx_wait_mask_s(dev,  MV_GLOBAL2REG(SMI_OP),
+                                   MV_INDIRECT_INPROGRESS, 0) < 0;
+}
+
 static int
 mvsw61xx_get_port_mask(struct switch_dev *dev,
                const struct switch_attr *attr, struct switch_val *val)
@@ -566,7 +591,7 @@ static int mvsw61xx_apply(struct switch_dev *dev)
        return mvsw61xx_update_state(dev);
 }
 
-static int mvsw61xx_reset(struct switch_dev *dev)
+static int _mvsw61xx_reset(struct switch_dev *dev, bool full)
 {
        struct mvsw61xx_state *state = get_state(dev);
        int i;
@@ -599,6 +624,17 @@ static int mvsw61xx_reset(struct switch_dev *dev)
 
                /* Set port association vector */
                sw16(dev, MV_PORTREG(ASSOC, i), (1 << i));
+
+               /* power up phys */
+               if (full && i < 5) {
+                       mvsw61xx_mdio_write(dev, i, MII_MV_SPEC_CTRL,
+                                           MV_SPEC_MDI_CROSS_AUTO |
+                                           MV_SPEC_ENERGY_DETECT |
+                                           MV_SPEC_DOWNSHIFT_COUNTER);
+                       mvsw61xx_mdio_write(dev, i, MII_BMCR, BMCR_RESET |
+                                           BMCR_ANENABLE | BMCR_FULLDPLX |
+                                           BMCR_SPEED1000);
+               }
        }
 
        for (i = 0; i < dev->vlans; i++) {
@@ -623,6 +659,11 @@ static int mvsw61xx_reset(struct switch_dev *dev)
        return 0;
 }
 
+static int mvsw61xx_reset(struct switch_dev *dev)
+{
+       return _mvsw61xx_reset(dev, false);
+}
+
 enum {
        MVSW61XX_ENABLE_VLAN,
 };
@@ -798,6 +839,8 @@ static int mvsw61xx_probe(struct platform_device *pdev)
        state->dev.ops = &mvsw61xx_ops;
        state->dev.alias = dev_name(&pdev->dev);
 
+       _mvsw61xx_reset(&state->dev, true);
+
        err = register_switch(&state->dev, NULL);
        if (err < 0)
                goto out_err;