aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/brcm2708/patches-4.14/950-0443-net-lan78xx-Support-auto-downshift-to-100Mb-s.patch
blob: 203a6e6eaa96e271ab28a6ccc59766874758f82c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
From 68502f802a66b68a6b5fefb52e709807a702a94b Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Mon, 26 Nov 2018 19:46:58 +0000
Subject: [PATCH 443/454] net: lan78xx: Support auto-downshift to 100Mb/s

Ethernet cables with faulty or missing pairs (specifically pairs C and
D) allow auto-negotiation to 1000Mbs, but do not support the successful
establishment of a link. Add a DT property, "microchip,downshift-after",
to configure the number of auto-negotiation failures after which it
falls back to 100Mbs. Valid values are 2, 3, 4, 5 and 0, where 0 means
never downshift.

Signed-off-by: Phil Elwell <phil@raspberrypi.org>
---
 drivers/net/phy/microchip.c  | 33 +++++++++++++++++++++++++++++++++
 drivers/net/usb/lan78xx.c    |  8 ++++++--
 include/linux/microchipphy.h | 11 +++++++++++
 3 files changed, 50 insertions(+), 2 deletions(-)

--- a/drivers/net/phy/microchip.c
+++ b/drivers/net/phy/microchip.c
@@ -21,6 +21,7 @@
 #include <linux/phy.h>
 #include <linux/microchipphy.h>
 #include <linux/delay.h>
+#include <linux/of.h>
 
 #define DRIVER_AUTHOR	"WOOJUNG HUH <woojung.huh@microchip.com>"
 #define DRIVER_DESC	"Microchip LAN88XX PHY driver"
@@ -225,6 +226,7 @@ static int lan88xx_probe(struct phy_devi
 {
 	struct device *dev = &phydev->mdio.dev;
 	struct lan88xx_priv *priv;
+	u32 downshift_after = 0;
 
 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
 	if (!priv)
@@ -232,6 +234,37 @@ static int lan88xx_probe(struct phy_devi
 
 	priv->wolopts = 0;
 
+	if (!of_property_read_u32(dev->of_node,
+				  "microchip,downshift-after",
+				  &downshift_after)) {
+		u32 mask = LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_MASK;
+		u32 val = LAN78XX_PHY_CTRL3_AUTO_DOWNSHIFT;
+
+		switch (downshift_after) {
+		case 2:
+			val |= LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_2;
+			break;
+		case 3:
+			val |= LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_3;
+			break;
+		case 4:
+			val |= LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_4;
+			break;
+		case 5:
+			val |= LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_5;
+			break;
+		case 0:
+			/* Disable completely */
+			mask = LAN78XX_PHY_CTRL3_AUTO_DOWNSHIFT;
+			val = 0;
+			break;
+		default:
+			return -EINVAL;
+		}
+		(void)phy_modify_paged(phydev, 1, LAN78XX_PHY_CTRL3,
+				       mask, val);
+	}
+
 	/* these values can be used to identify internal PHY */
 	priv->chip_id = phy_read_mmd(phydev, 3, LAN88XX_MMD3_CHIP_ID);
 	priv->chip_rev = phy_read_mmd(phydev, 3, LAN88XX_MMD3_CHIP_REV);
--- a/drivers/net/usb/lan78xx.c
+++ b/drivers/net/usb/lan78xx.c
@@ -36,7 +36,8 @@
 #include <linux/irq.h>
 #include <linux/irqchip/chained_irq.h>
 #include <linux/microchipphy.h>
-#include <linux/phy.h>
+#include <linux/phy_fixed.h>
+#include <linux/of_mdio.h>
 #include <linux/of_net.h>
 #include "lan78xx.h"
 
@@ -1763,6 +1764,7 @@ done:
 
 static int lan78xx_mdio_init(struct lan78xx_net *dev)
 {
+	struct device_node *node;
 	int ret;
 
 	dev->mdiobus = mdiobus_alloc();
@@ -1792,7 +1794,9 @@ static int lan78xx_mdio_init(struct lan7
 		break;
 	}
 
-	ret = mdiobus_register(dev->mdiobus);
+	node = of_get_child_by_name(dev->udev->dev.of_node, "mdio");
+	ret = of_mdiobus_register(dev->mdiobus, node);
+	of_node_put(node);
 	if (ret) {
 		netdev_err(dev->net, "can't register MDIO bus\n");
 		goto exit1;
--- a/include/linux/microchipphy.h
+++ b/include/linux/microchipphy.h
@@ -70,6 +70,17 @@
 #define	LAN88XX_MMD3_CHIP_ID			(32877)
 #define	LAN88XX_MMD3_CHIP_REV			(32878)
 
+/* Registers specific to the LAN7800/LAN7850 embedded phy */
+#define LAN78XX_PHY_LED_MODE_SELECT		(0x1D)
+
+#define LAN78XX_PHY_CTRL3			(0x14)
+#define LAN78XX_PHY_CTRL3_AUTO_DOWNSHIFT	(0x0010)
+#define LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_MASK	(0x000c)
+#define LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_2	(0x0000)
+#define LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_3	(0x0004)
+#define LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_4	(0x0008)
+#define LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_5	(0x000c)
+
 /* DSP registers */
 #define PHY_ARDENNES_MMD_DEV_3_PHY_CFG		(0x806A)
 #define PHY_ARDENNES_MMD_DEV_3_PHY_CFG_ZD_DLY_EN_	(0x2000)