aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRaju Lakkaraju <Raju.Lakkaraju@microsemi.com>2016-10-03 03:23:13 -0400
committerDavid S. Miller <davem@davemloft.net>2016-10-04 00:47:30 -0400
commita4cc96d1f0170b779c32c6b2cc58764f5d2cdef0 (patch)
tree1360a3ab54480f50ba3f6660e9eb8fdbe2af6ba4
parent277964e19e1416ca31301e113edb2580c81a8b66 (diff)
net: phy: Add Edge-rate driver for Microsemi PHYs.
Edge-rate: As system and networking speeds increase, a signal's output transition, also know as the edge rate or slew rate (V/ns), takes on greater importance because high-speed signals come with a price. That price is an assortment of interference problems like ringing on the line, signal overshoot and undershoot, extended signal settling times, crosstalk noise, transmission line reflections, false signal detection by the receiving device and electromagnetic interference (EMI) -- all of which can negate the potential gains designers are seeking when they try to increase system speeds through the use of higher performance logic devices. The fact is, faster signaling edge rates can cause a higher level of electrical noise or other type of interference that can actually lead to slower line speeds and lower maximum system frequencies. This parameter allow the board designers to change the driving strange, and thereby change the EMI behavioral. Edge-rate parameters (vddmac, edge-slowdown) get from Device Tree. Tested on Beaglebone Black with VSC 8531 PHY. Signed-off-by: Raju Lakkaraju <Raju.Lakkaraju@microsemi.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--Documentation/devicetree/bindings/net/mscc-phy-vsc8531.txt58
-rw-r--r--drivers/net/phy/mscc.c125
-rw-r--r--include/dt-bindings/net/mscc-phy-vsc8531.h21
3 files changed, 204 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/net/mscc-phy-vsc8531.txt b/Documentation/devicetree/bindings/net/mscc-phy-vsc8531.txt
new file mode 100644
index 000000000000..99c7eb0a00c8
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/mscc-phy-vsc8531.txt
@@ -0,0 +1,58 @@
1* Microsemi - vsc8531 Giga bit ethernet phy
2
3Required properties:
4- compatible : Should contain phy id as "ethernet-phy-idAAAA.BBBB"
5 The PHY device uses the binding described in
6 Documentation/devicetree/bindings/net/phy.txt
7
8Optional properties:
9- vsc8531,vddmac : The vddmac in mV.
10- vsc8531,edge-slowdown : % the edge should be slowed down relative to
11 the fastest possible edge time. Native sign
12 need not enter.
13 Edge rate sets the drive strength of the MAC
14 interface output signals. Changing the drive
15 strength will affect the edge rate of the output
16 signal. The goal of this setting is to help
17 reduce electrical emission (EMI) by being able
18 to reprogram drive strength and in effect slow
19 down the edge rate if desired. Table 1 shows the
20 impact to the edge rate per VDDMAC supply for each
21 drive strength setting.
22 Ref: Table:1 - Edge rate change below.
23
24Note: see dt-bindings/net/mscc-phy-vsc8531.h for applicable values
25
26Table: 1 - Edge rate change
27----------------------------------------------------------------|
28| Edge Rate Change (VDDMAC) |
29| |
30| 3300 mV 2500 mV 1800 mV 1500 mV |
31|---------------------------------------------------------------|
32| Default Deafult Default Default |
33| (Fastest) (recommended) (recommended) |
34|---------------------------------------------------------------|
35| -2% -3% -5% -6% |
36|---------------------------------------------------------------|
37| -4% -6% -9% -14% |
38|---------------------------------------------------------------|
39| -7% -10% -16% -21% |
40|(recommended) (recommended) |
41|---------------------------------------------------------------|
42| -10% -14% -23% -29% |
43|---------------------------------------------------------------|
44| -17% -23% -35% -42% |
45|---------------------------------------------------------------|
46| -29% -37% -52% -58% |
47|---------------------------------------------------------------|
48| -53% -63% -76% -77% |
49| (slowest) |
50|---------------------------------------------------------------|
51
52Example:
53
54 vsc8531_0: ethernet-phy@0 {
55 compatible = "ethernet-phy-id0007.0570";
56 vsc8531,vddmac = <3300>;
57 vsc8531,edge-slowdown = <21>;
58 };
diff --git a/drivers/net/phy/mscc.c b/drivers/net/phy/mscc.c
index d350debd174a..a17573e3bd8a 100644
--- a/drivers/net/phy/mscc.c
+++ b/drivers/net/phy/mscc.c
@@ -11,6 +11,8 @@
11#include <linux/mdio.h> 11#include <linux/mdio.h>
12#include <linux/mii.h> 12#include <linux/mii.h>
13#include <linux/phy.h> 13#include <linux/phy.h>
14#include <linux/of.h>
15#include <dt-bindings/net/mscc-phy-vsc8531.h>
14 16
15enum rgmii_rx_clock_delay { 17enum rgmii_rx_clock_delay {
16 RGMII_RX_CLK_DELAY_0_2_NS = 0, 18 RGMII_RX_CLK_DELAY_0_2_NS = 0,
@@ -37,6 +39,10 @@ enum rgmii_rx_clock_delay {
37#define MII_VSC85XX_INT_MASK_MASK 0xa000 39#define MII_VSC85XX_INT_MASK_MASK 0xa000
38#define MII_VSC85XX_INT_STATUS 26 40#define MII_VSC85XX_INT_STATUS 26
39 41
42#define MSCC_PHY_WOL_MAC_CONTROL 27
43#define EDGE_RATE_CNTL_POS 5
44#define EDGE_RATE_CNTL_MASK 0x00E0
45
40#define MSCC_EXT_PAGE_ACCESS 31 46#define MSCC_EXT_PAGE_ACCESS 31
41#define MSCC_PHY_PAGE_STANDARD 0x0000 /* Standard registers */ 47#define MSCC_PHY_PAGE_STANDARD 0x0000 /* Standard registers */
42#define MSCC_PHY_PAGE_EXTENDED_2 0x0002 /* Extended reg - page 2 */ 48#define MSCC_PHY_PAGE_EXTENDED_2 0x0002 /* Extended reg - page 2 */
@@ -50,6 +56,23 @@ enum rgmii_rx_clock_delay {
50#define PHY_ID_VSC8531 0x00070570 56#define PHY_ID_VSC8531 0x00070570
51#define PHY_ID_VSC8541 0x00070770 57#define PHY_ID_VSC8541 0x00070770
52 58
59struct edge_rate_table {
60 u16 vddmac;
61 int slowdown[MSCC_SLOWDOWN_MAX];
62};
63
64struct edge_rate_table edge_table[MSCC_VDDMAC_MAX] = {
65 {3300, { 0, -2, -4, -7, -10, -17, -29, -53} },
66 {2500, { 0, -3, -6, -10, -14, -23, -37, -63} },
67 {1800, { 0, -5, -9, -16, -23, -35, -52, -76} },
68 {1500, { 0, -6, -14, -21, -29, -42, -58, -77} },
69};
70
71struct vsc8531_private {
72 u8 edge_slowdown;
73 u16 vddmac;
74};
75
53static int vsc85xx_phy_page_set(struct phy_device *phydev, u8 page) 76static int vsc85xx_phy_page_set(struct phy_device *phydev, u8 page)
54{ 77{
55 int rc; 78 int rc;
@@ -58,6 +81,51 @@ static int vsc85xx_phy_page_set(struct phy_device *phydev, u8 page)
58 return rc; 81 return rc;
59} 82}
60 83
84static u8 edge_rate_magic_get(u16 vddmac,
85 int slowdown)
86{
87 int rc = (MSCC_SLOWDOWN_MAX - 1);
88 u8 vdd;
89 u8 sd;
90
91 for (vdd = 0; vdd < MSCC_VDDMAC_MAX; vdd++) {
92 if (edge_table[vdd].vddmac == vddmac) {
93 for (sd = 0; sd < MSCC_SLOWDOWN_MAX; sd++) {
94 if (edge_table[vdd].slowdown[sd] <= slowdown) {
95 rc = (MSCC_SLOWDOWN_MAX - sd - 1);
96 break;
97 }
98 }
99 }
100 }
101
102 return rc;
103}
104
105static int vsc85xx_edge_rate_cntl_set(struct phy_device *phydev,
106 u8 edge_rate)
107{
108 int rc;
109 u16 reg_val;
110
111 mutex_lock(&phydev->lock);
112 rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_EXTENDED_2);
113 if (rc != 0)
114 goto out_unlock;
115 reg_val = phy_read(phydev, MSCC_PHY_WOL_MAC_CONTROL);
116 reg_val &= ~(EDGE_RATE_CNTL_MASK);
117 reg_val |= (edge_rate << EDGE_RATE_CNTL_POS);
118 rc = phy_write(phydev, MSCC_PHY_WOL_MAC_CONTROL, reg_val);
119 if (rc != 0)
120 goto out_unlock;
121 rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_STANDARD);
122
123out_unlock:
124 mutex_unlock(&phydev->lock);
125
126 return rc;
127}
128
61static int vsc85xx_mac_if_set(struct phy_device *phydev, 129static int vsc85xx_mac_if_set(struct phy_device *phydev,
62 phy_interface_t interface) 130 phy_interface_t interface)
63{ 131{
@@ -116,9 +184,45 @@ out_unlock:
116 return rc; 184 return rc;
117} 185}
118 186
187#ifdef CONFIG_OF_MDIO
188static int vsc8531_of_init(struct phy_device *phydev)
189{
190 int rc;
191 struct vsc8531_private *vsc8531 = phydev->priv;
192 struct device *dev = &phydev->mdio.dev;
193 struct device_node *of_node = dev->of_node;
194
195 if (!of_node)
196 return -ENODEV;
197
198 rc = of_property_read_u16(of_node, "vsc8531,vddmac",
199 &vsc8531->vddmac);
200 if (rc == -EINVAL)
201 vsc8531->vddmac = MSCC_VDDMAC_3300;
202 rc = of_property_read_u8(of_node, "vsc8531,edge-slowdown",
203 &vsc8531->edge_slowdown);
204 if (rc == -EINVAL)
205 vsc8531->edge_slowdown = 0;
206
207 rc = 0;
208 return rc;
209}
210#else
211static int vsc8531_of_init(struct phy_device *phydev)
212{
213 return 0;
214}
215#endif /* CONFIG_OF_MDIO */
216
119static int vsc85xx_config_init(struct phy_device *phydev) 217static int vsc85xx_config_init(struct phy_device *phydev)
120{ 218{
121 int rc; 219 int rc;
220 struct vsc8531_private *vsc8531 = phydev->priv;
221 u8 edge_rate;
222
223 rc = vsc8531_of_init(phydev);
224 if (rc)
225 return rc;
122 226
123 rc = vsc85xx_default_config(phydev); 227 rc = vsc85xx_default_config(phydev);
124 if (rc) 228 if (rc)
@@ -128,6 +232,12 @@ static int vsc85xx_config_init(struct phy_device *phydev)
128 if (rc) 232 if (rc)
129 return rc; 233 return rc;
130 234
235 edge_rate = edge_rate_magic_get(vsc8531->vddmac,
236 -(int)vsc8531->edge_slowdown);
237 rc = vsc85xx_edge_rate_cntl_set(phydev, edge_rate);
238 if (rc)
239 return rc;
240
131 rc = genphy_config_init(phydev); 241 rc = genphy_config_init(phydev);
132 242
133 return rc; 243 return rc;
@@ -160,6 +270,19 @@ static int vsc85xx_config_intr(struct phy_device *phydev)
160 return rc; 270 return rc;
161} 271}
162 272
273static int vsc85xx_probe(struct phy_device *phydev)
274{
275 struct vsc8531_private *vsc8531;
276
277 vsc8531 = devm_kzalloc(&phydev->mdio.dev, sizeof(*vsc8531), GFP_KERNEL);
278 if (!vsc8531)
279 return -ENOMEM;
280
281 phydev->priv = vsc8531;
282
283 return 0;
284}
285
163/* Microsemi VSC85xx PHYs */ 286/* Microsemi VSC85xx PHYs */
164static struct phy_driver vsc85xx_driver[] = { 287static struct phy_driver vsc85xx_driver[] = {
165{ 288{
@@ -177,6 +300,7 @@ static struct phy_driver vsc85xx_driver[] = {
177 .config_intr = &vsc85xx_config_intr, 300 .config_intr = &vsc85xx_config_intr,
178 .suspend = &genphy_suspend, 301 .suspend = &genphy_suspend,
179 .resume = &genphy_resume, 302 .resume = &genphy_resume,
303 .probe = &vsc85xx_probe,
180}, 304},
181{ 305{
182 .phy_id = PHY_ID_VSC8541, 306 .phy_id = PHY_ID_VSC8541,
@@ -193,6 +317,7 @@ static struct phy_driver vsc85xx_driver[] = {
193 .config_intr = &vsc85xx_config_intr, 317 .config_intr = &vsc85xx_config_intr,
194 .suspend = &genphy_suspend, 318 .suspend = &genphy_suspend,
195 .resume = &genphy_resume, 319 .resume = &genphy_resume,
320 .probe = &vsc85xx_probe,
196} 321}
197 322
198}; 323};
diff --git a/include/dt-bindings/net/mscc-phy-vsc8531.h b/include/dt-bindings/net/mscc-phy-vsc8531.h
new file mode 100644
index 000000000000..2383dd20ff43
--- /dev/null
+++ b/include/dt-bindings/net/mscc-phy-vsc8531.h
@@ -0,0 +1,21 @@
1/*
2 * Device Tree constants for Microsemi VSC8531 PHY
3 *
4 * Author: Nagaraju Lakkaraju
5 *
6 * License: Dual MIT/GPL
7 * Copyright (c) 2016 Microsemi Corporation
8 */
9
10#ifndef _DT_BINDINGS_MSCC_VSC8531_H
11#define _DT_BINDINGS_MSCC_VSC8531_H
12
13/* MAC interface Edge rate control VDDMAC in milli Volts */
14#define MSCC_VDDMAC_3300 3300
15#define MSCC_VDDMAC_2500 2500
16#define MSCC_VDDMAC_1800 1800
17#define MSCC_VDDMAC_1500 1500
18#define MSCC_VDDMAC_MAX 4
19#define MSCC_SLOWDOWN_MAX 8
20
21#endif