From b04138b335203b79ffe1b14750fa245a4dab7191 Mon Sep 17 00:00:00 2001
From: Hauke Mehrtens <hauke@hauke-m.de>
Date: Fri, 20 Dec 2013 02:16:13 +0100
Subject: [PATCH 208/208] b44: use fixed PHY device if we do not find any

The ADM6996L switch and some Broadcom switches with two MII interfaces
like the BCM5325F connected to two MACs on the SoC, used on some
routers do not return a valid value when reading the PHY id register
and Linux thinks there is no PHY at all, but that is wrong.
This patch registers a fixed phy in the arch code and then searches it
when there is no other phy in the Ethernet driver code.

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
 arch/mips/bcm47xx/setup.c           |   10 ++++++++++
 drivers/net/ethernet/broadcom/b44.c |   16 +++++++++++++++-
 drivers/net/ethernet/broadcom/b44.h |    3 +++
 3 files changed, 28 insertions(+), 1 deletion(-)

--- a/arch/mips/bcm47xx/setup.c
+++ b/arch/mips/bcm47xx/setup.c
@@ -30,6 +30,9 @@
 
 #include <linux/export.h>
 #include <linux/types.h>
+#include <linux/ethtool.h>
+#include <linux/phy.h>
+#include <linux/phy_fixed.h>
 #include <linux/ssb/ssb.h>
 #include <linux/ssb/ssb_embedded.h>
 #include <linux/bcma/bcma_soc.h>
@@ -257,6 +260,12 @@ static int __init bcm47xx_cpu_fixes(void
 }
 arch_initcall(bcm47xx_cpu_fixes);
 
+static struct fixed_phy_status bcm47xx_fixed_phy_status __initdata = {
+	.link	= 1,
+	.speed	= SPEED_100,
+	.duplex	= DUPLEX_FULL,
+};
+
 static int __init bcm47xx_register_bus_complete(void)
 {
 	switch (bcm47xx_bus_type) {
@@ -275,6 +284,7 @@ static int __init bcm47xx_register_bus_c
 	bcm47xx_buttons_register();
 	bcm47xx_leds_register();
 	bcm47xx_workarounds();
+	fixed_phy_add(PHY_POLL, 0, &bcm47xx_fixed_phy_status);
 
 	return 0;
 }
--- a/drivers/net/ethernet/broadcom/b44.c
+++ b/drivers/net/ethernet/broadcom/b44.c
@@ -2233,6 +2233,7 @@ static int b44_register_phy_one(struct b
 	struct ssb_device *sdev = bp->sdev;
 	struct phy_device *phydev;
 	char bus_id[MII_BUS_ID_SIZE + 3];
+	struct ssb_sprom *sprom = &sdev->bus->sprom;
 	int err;
 
 	mii_bus = mdiobus_alloc();
@@ -2266,7 +2267,20 @@ static int b44_register_phy_one(struct b
 		goto err_out_mdiobus_irq;
 	}
 
-	snprintf(bus_id, sizeof(bus_id), PHY_ID_FMT, mii_bus->id, bp->phy_addr);
+	if (!bp->mii_bus->phy_map[bp->phy_addr] &&
+	    (sprom->boardflags_lo & (B44_BOARDFLAG_ROBO | B44_BOARDFLAG_ADM))) {
+
+		dev_info(sdev->dev,
+			 "could not find PHY at %i, use fixed one\n",
+			 bp->phy_addr);
+
+		bp->phy_addr = 0;
+		snprintf(bus_id, sizeof(bus_id), PHY_ID_FMT, "fixed-0",
+			 bp->phy_addr);
+	} else {
+		snprintf(bus_id, sizeof(bus_id), PHY_ID_FMT, mii_bus->id,
+			 bp->phy_addr);
+	}
 
 	phydev = phy_connect(bp->dev, bus_id, &b44_adjust_link,
 			     PHY_INTERFACE_MODE_MII);
--- a/drivers/net/ethernet/broadcom/b44.h
+++ b/drivers/net/ethernet/broadcom/b44.h
@@ -345,6 +345,9 @@ B44_STAT_REG_DECLARE
 	struct u64_stats_sync	syncp;
 };
 
+#define	B44_BOARDFLAG_ROBO		0x0010  /* Board has robo switch */
+#define	B44_BOARDFLAG_ADM		0x0080  /* Board has ADMtek switch */
+
 struct ssb_device;
 
 struct b44 {
