The bootloader on the WD My Net N750 disables the ports on it's internal
AR8327N switch by powering them down. The stock firmware then brings the
ports back up again by starting the auto negotiation process on each
port.

There is one big disadvantage of this approach: In tests I noticed that
PHYs on this platform that are powered down can be written but not read.
As a result the scan on the mdio bus fails to detect the ports on the
switch.

This workaround adds an option to the mdio bus platform data that
enables toggling of an early reset of all available PHYs before the mdio
bus scan is performed. On the test platform this brings the PHYs back to
life in time to be detected by the mdio bus scan.

Signed-off-by: Felix Kaechele <hef...@fedoraproject.org>
---
 .../linux/ar71xx/files/arch/mips/ath79/dev-eth.c   |  4 +--
 .../linux/ar71xx/files/arch/mips/ath79/dev-eth.h   |  2 ++
 .../mips/include/asm/mach-ath79/ag71xx_platform.h  |  1 +
 .../net/ethernet/atheros/ag71xx/ag71xx_mdio.c      | 30 ++++++++++++++--------
 4 files changed, 24 insertions(+), 13 deletions(-)

diff --git a/target/linux/ar71xx/files/arch/mips/ath79/dev-eth.c 
b/target/linux/ar71xx/files/arch/mips/ath79/dev-eth.c
index 4a2b1db..742218b 100644
--- a/target/linux/ar71xx/files/arch/mips/ath79/dev-eth.c
+++ b/target/linux/ar71xx/files/arch/mips/ath79/dev-eth.c
@@ -39,7 +39,7 @@ static struct resource ath79_mdio0_resources[] = {
        }
 };
 
-static struct ag71xx_mdio_platform_data ath79_mdio0_data;
+struct ag71xx_mdio_platform_data ath79_mdio0_data;
 
 struct platform_device ath79_mdio0_device = {
        .name           = "ag71xx-mdio",
@@ -60,7 +60,7 @@ static struct resource ath79_mdio1_resources[] = {
        }
 };
 
-static struct ag71xx_mdio_platform_data ath79_mdio1_data;
+struct ag71xx_mdio_platform_data ath79_mdio1_data;
 
 struct platform_device ath79_mdio1_device = {
        .name           = "ag71xx-mdio",
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/dev-eth.h 
b/target/linux/ar71xx/files/arch/mips/ath79/dev-eth.h
index bc608da..08a59ef 100644
--- a/target/linux/ar71xx/files/arch/mips/ath79/dev-eth.h
+++ b/target/linux/ar71xx/files/arch/mips/ath79/dev-eth.h
@@ -39,6 +39,8 @@ void ath79_register_eth(unsigned int id);
 
 extern struct ag71xx_switch_platform_data ath79_switch_data;
 
+extern struct ag71xx_mdio_platform_data ath79_mdio0_data;
+extern struct ag71xx_mdio_platform_data ath79_mdio0_data;
 extern struct platform_device ath79_mdio0_device;
 extern struct platform_device ath79_mdio1_device;
 void ath79_register_mdio(unsigned int id, u32 phy_mask);
diff --git 
a/target/linux/ar71xx/files/arch/mips/include/asm/mach-ath79/ag71xx_platform.h 
b/target/linux/ar71xx/files/arch/mips/include/asm/mach-ath79/ag71xx_platform.h
index 656a6ef..333daa9 100644
--- 
a/target/linux/ar71xx/files/arch/mips/include/asm/mach-ath79/ag71xx_platform.h
+++ 
b/target/linux/ar71xx/files/arch/mips/include/asm/mach-ath79/ag71xx_platform.h
@@ -53,6 +53,7 @@ struct ag71xx_mdio_platform_data {
        u8              is_ar7240:1;
        u8              is_ar9330:1;
        u8              is_ar934x:1;
+       u8              wake_phys:1;
        unsigned long   mdio_clock;
        unsigned long   ref_clock;
 };
diff --git 
a/target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_mdio.c 
b/target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_mdio.c
index ec88233..0f3ed63 100644
--- 
a/target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_mdio.c
+++ 
b/target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_mdio.c
@@ -156,10 +156,22 @@ static int ag71xx_mdio_get_divider(struct ag71xx_mdio 
*am, u32 *div)
        return -ENOENT;
 }
 
+static int ag71xx_mdio_write(struct mii_bus *bus, int addr, int reg, u16 val)
+{
+       struct ag71xx_mdio *am = bus->priv;
+
+       if (am->pdata->builtin_switch)
+               ar7240sw_phy_write(bus, addr, reg, val);
+       else
+               ag71xx_mdio_mii_write(am, addr, reg, val);
+       return 0;
+}
+
 static int ag71xx_mdio_reset(struct mii_bus *bus)
 {
        struct ag71xx_mdio *am = bus->priv;
        u32 t;
+       int i;
        int err;
 
        err = ag71xx_mdio_get_divider(am, &t);
@@ -181,6 +193,13 @@ static int ag71xx_mdio_reset(struct mii_bus *bus)
        ag71xx_mdio_wr(am, AG71XX_REG_MII_CFG, t);
        udelay(100);
 
+       if(am->pdata->wake_phys) {
+               for (i = 0; i < PHY_MAX_ADDR; i++)
+                       ag71xx_mdio_write(bus, i, MII_BMCR, (BMCR_RESET |
+                                       BMCR_ANENABLE | BMCR_SPEED1000));
+               msleep(1000);
+       }
+
        return 0;
 }
 
@@ -194,17 +213,6 @@ static int ag71xx_mdio_read(struct mii_bus *bus, int addr, 
int reg)
                return ag71xx_mdio_mii_read(am, addr, reg);
 }
 
-static int ag71xx_mdio_write(struct mii_bus *bus, int addr, int reg, u16 val)
-{
-       struct ag71xx_mdio *am = bus->priv;
-
-       if (am->pdata->builtin_switch)
-               ar7240sw_phy_write(bus, addr, reg, val);
-       else
-               ag71xx_mdio_mii_write(am, addr, reg, val);
-       return 0;
-}
-
 static int ag71xx_mdio_probe(struct platform_device *pdev)
 {
        struct ag71xx_mdio_platform_data *pdata;
-- 
1.8.4.2
_______________________________________________
openwrt-devel mailing list
openwrt-devel@lists.openwrt.org
https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel

Reply via email to