net: mv88e61xx: Add support for fixed links

On some boards these switches are wired directly into a SERDES
interface on another Ethernet MAC. Add the ability to specify
these kinds of boards using CONFIG_MV88E61XX_FIXED_PORTS which defines
a bit mask of these fixed ports.

Signed-off-by: Chris Packham <judge.packham@gmail.com>
Acked-by: Joe Hershberger <joe.hershberger@ni.com>
diff --git a/drivers/net/phy/mv88e61xx.c b/drivers/net/phy/mv88e61xx.c
index 7385848..a2fd168 100644
--- a/drivers/net/phy/mv88e61xx.c
+++ b/drivers/net/phy/mv88e61xx.c
@@ -103,8 +103,16 @@
 #define PORT_REG_STATUS_CMODE_1000BASE_X	0x9
 #define PORT_REG_STATUS_CMODE_SGMII		0xa
 
+#define PORT_REG_PHYS_CTRL_PCS_AN_EN	BIT(10)
+#define PORT_REG_PHYS_CTRL_PCS_AN_RST	BIT(9)
+#define PORT_REG_PHYS_CTRL_FC_VALUE	BIT(7)
+#define PORT_REG_PHYS_CTRL_FC_FORCE	BIT(6)
 #define PORT_REG_PHYS_CTRL_LINK_VALUE	BIT(5)
 #define PORT_REG_PHYS_CTRL_LINK_FORCE	BIT(4)
+#define PORT_REG_PHYS_CTRL_DUPLEX_VALUE	BIT(3)
+#define PORT_REG_PHYS_CTRL_DUPLEX_FORCE	BIT(2)
+#define PORT_REG_PHYS_CTRL_SPD1000	BIT(1)
+#define PORT_REG_PHYS_CTRL_SPD_MASK	(BIT(1) | BIT(0))
 
 #define PORT_REG_CTRL_PSTATE_SHIFT	0
 #define PORT_REG_CTRL_PSTATE_WIDTH	2
@@ -166,6 +174,14 @@
 #error Define CONFIG_MV88E61XX_CPU_PORT to the port the CPU is attached to
 #endif
 
+/*
+ *  These are ports without PHYs that may be wired directly
+ * to other serdes interfaces
+ */
+#ifndef CONFIG_MV88E61XX_FIXED_PORTS
+#define CONFIG_MV88E61XX_FIXED_PORTS 0
+#endif
+
 /* ID register values for different switch models */
 #define PORT_SWITCH_ID_6096		0x0980
 #define PORT_SWITCH_ID_6097		0x0990
@@ -793,6 +809,27 @@
 	return 0;
 }
 
+static int mv88e61xx_fixed_port_setup(struct phy_device *phydev, u8 port)
+{
+	int val;
+
+	val = mv88e61xx_port_read(phydev, port, PORT_REG_PHYS_CTRL);
+	if (val < 0)
+		return val;
+
+	val &= ~(PORT_REG_PHYS_CTRL_SPD_MASK |
+		 PORT_REG_PHYS_CTRL_FC_VALUE);
+	val |= PORT_REG_PHYS_CTRL_PCS_AN_EN |
+	       PORT_REG_PHYS_CTRL_PCS_AN_RST |
+	       PORT_REG_PHYS_CTRL_FC_FORCE |
+	       PORT_REG_PHYS_CTRL_DUPLEX_VALUE |
+	       PORT_REG_PHYS_CTRL_DUPLEX_FORCE |
+	       PORT_REG_PHYS_CTRL_SPD1000;
+
+	return mv88e61xx_port_write(phydev, port, PORT_REG_PHYS_CTRL,
+				   val);
+}
+
 static int mv88e61xx_phy_config_port(struct phy_device *phydev, u8 phy)
 {
 	int val;
@@ -911,6 +948,12 @@
 
 			/* Return success if any PHY succeeds */
 			ret = 0;
+		} else if ((1 << i) & CONFIG_MV88E61XX_FIXED_PORTS) {
+			res = mv88e61xx_fixed_port_setup(phydev, i);
+			if (res < 0) {
+				printf("Error configuring port %i\n", i);
+				continue;
+			}
 		}
 	}