summaryrefslogtreecommitdiff
path: root/target/linux/imx6/patches-4.4/202-net-igb-add-i210-i211-support-for-phy-read-write.patch
blob: 6bc23c520690a119d37a6a2d6ee9237aa24ea86f (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
127
128
129
Author: Tim Harvey <tharvey@gateworks.com>
Date:   Thu May 15 00:12:26 2014 -0700

    net: igb: add i210/i211 support for phy read/write
    
    The i210/i211 uses the MDICNFG register for the phy address instead of the
    MDIC register.
    
    Signed-off-by: Tim Harvey <tharvey@gateworks.com>

--- a/drivers/net/ethernet/intel/igb/e1000_phy.c
+++ b/drivers/net/ethernet/intel/igb/e1000_phy.c
@@ -129,7 +129,7 @@ out:
 s32 igb_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data)
 {
 	struct e1000_phy_info *phy = &hw->phy;
-	u32 i, mdic = 0;
+	u32 i, mdicnfg, mdic = 0;
 	s32 ret_val = 0;
 
 	if (offset > MAX_PHY_REG_ADDRESS) {
@@ -142,11 +142,25 @@ s32 igb_read_phy_reg_mdic(struct e1000_h
 	 * Control register.  The MAC will take care of interfacing with the
 	 * PHY to retrieve the desired data.
 	 */
-	mdic = ((offset << E1000_MDIC_REG_SHIFT) |
-		(phy->addr << E1000_MDIC_PHY_SHIFT) |
-		(E1000_MDIC_OP_READ));
+	switch (hw->mac.type) {
+	case e1000_i210:
+	case e1000_i211:
+		mdicnfg = rd32(E1000_MDICNFG);
+		mdicnfg &= ~(E1000_MDICNFG_PHY_MASK);
+		mdicnfg |= (phy->addr << E1000_MDICNFG_PHY_SHIFT);
+		wr32(E1000_MDICNFG, mdicnfg);
+		mdic = ((offset << E1000_MDIC_REG_SHIFT) |
+			(E1000_MDIC_OP_READ));
+		break;
+	default:
+		mdic = ((offset << E1000_MDIC_REG_SHIFT) |
+			(phy->addr << E1000_MDIC_PHY_SHIFT) |
+			(E1000_MDIC_OP_READ));
+		break;
+	}
 
 	wr32(E1000_MDIC, mdic);
+	wrfl();
 
 	/* Poll the ready bit to see if the MDI read completed
 	 * Increasing the time out as testing showed failures with
@@ -171,6 +185,18 @@ s32 igb_read_phy_reg_mdic(struct e1000_h
 	*data = (u16) mdic;
 
 out:
+	switch (hw->mac.type) {
+		/* restore MDICNFG to have phy's addr */
+		case e1000_i210:
+		case e1000_i211:
+			mdicnfg = rd32(E1000_MDICNFG);
+			mdicnfg &= ~(E1000_MDICNFG_PHY_MASK);
+			mdicnfg |= (hw->phy.addr << E1000_MDICNFG_PHY_SHIFT);
+			wr32(E1000_MDICNFG, mdicnfg);
+			break;
+		default:
+			break;
+	}
 	return ret_val;
 }
 
@@ -185,7 +211,7 @@ out:
 s32 igb_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data)
 {
 	struct e1000_phy_info *phy = &hw->phy;
-	u32 i, mdic = 0;
+	u32 i, mdicnfg, mdic = 0;
 	s32 ret_val = 0;
 
 	if (offset > MAX_PHY_REG_ADDRESS) {
@@ -198,12 +224,27 @@ s32 igb_write_phy_reg_mdic(struct e1000_
 	 * Control register.  The MAC will take care of interfacing with the
 	 * PHY to retrieve the desired data.
 	 */
-	mdic = (((u32)data) |
-		(offset << E1000_MDIC_REG_SHIFT) |
-		(phy->addr << E1000_MDIC_PHY_SHIFT) |
-		(E1000_MDIC_OP_WRITE));
+	switch (hw->mac.type) {
+		case e1000_i210:
+		case e1000_i211:
+			mdicnfg = rd32(E1000_MDICNFG);
+			mdicnfg &= ~(E1000_MDICNFG_PHY_MASK);
+			mdicnfg |= (phy->addr << E1000_MDICNFG_PHY_SHIFT);
+			wr32(E1000_MDICNFG, mdicnfg);
+			mdic = (((u32)data) |
+				(offset << E1000_MDIC_REG_SHIFT) |
+				(E1000_MDIC_OP_WRITE));
+			break;
+		default:
+			mdic = (((u32)data) |
+				(offset << E1000_MDIC_REG_SHIFT) |
+				(phy->addr << E1000_MDIC_PHY_SHIFT) |
+				(E1000_MDIC_OP_WRITE));
+			break;
+	}
 
 	wr32(E1000_MDIC, mdic);
+	wrfl();
 
 	/* Poll the ready bit to see if the MDI read completed
 	 * Increasing the time out as testing showed failures with
@@ -227,6 +268,18 @@ s32 igb_write_phy_reg_mdic(struct e1000_
 	}
 
 out:
+	switch (hw->mac.type) {
+		/* restore MDICNFG to have phy's addr */
+		case e1000_i210:
+		case e1000_i211:
+			mdicnfg = rd32(E1000_MDICNFG);
+			mdicnfg &= ~(E1000_MDICNFG_PHY_MASK);
+			mdicnfg |= (hw->phy.addr << E1000_MDICNFG_PHY_SHIFT);
+			wr32(E1000_MDICNFG, mdicnfg);
+			break;
+		default:
+			break;
+	}
 	return ret_val;
 }