2 * Driver for Microsemi VSC85xx PHYs
4 * Author: Nagaraju Lakkaraju
5 * License: Dual MIT/GPL
6 * Copyright (c) 2016 Microsemi Corporation
9 #include <linux/kernel.h>
10 #include <linux/module.h>
11 #include <linux/mdio.h>
12 #include <linux/mii.h>
13 #include <linux/phy.h>
15 #include <dt-bindings/net/mscc-phy-vsc8531.h>
16 #include <linux/netdevice.h>
18 enum rgmii_rx_clock_delay
{
19 RGMII_RX_CLK_DELAY_0_2_NS
= 0,
20 RGMII_RX_CLK_DELAY_0_8_NS
= 1,
21 RGMII_RX_CLK_DELAY_1_1_NS
= 2,
22 RGMII_RX_CLK_DELAY_1_7_NS
= 3,
23 RGMII_RX_CLK_DELAY_2_0_NS
= 4,
24 RGMII_RX_CLK_DELAY_2_3_NS
= 5,
25 RGMII_RX_CLK_DELAY_2_6_NS
= 6,
26 RGMII_RX_CLK_DELAY_3_4_NS
= 7
29 /* Microsemi VSC85xx PHY registers */
30 /* IEEE 802. Std Registers */
31 #define MSCC_PHY_EXT_PHY_CNTL_1 23
32 #define MAC_IF_SELECTION_MASK 0x1800
33 #define MAC_IF_SELECTION_GMII 0
34 #define MAC_IF_SELECTION_RMII 1
35 #define MAC_IF_SELECTION_RGMII 2
36 #define MAC_IF_SELECTION_POS 11
37 #define FAR_END_LOOPBACK_MODE_MASK 0x0008
39 #define MII_VSC85XX_INT_MASK 25
40 #define MII_VSC85XX_INT_MASK_MASK 0xa000
41 #define MII_VSC85XX_INT_MASK_WOL 0x0040
42 #define MII_VSC85XX_INT_STATUS 26
44 #define MSCC_PHY_WOL_MAC_CONTROL 27
45 #define EDGE_RATE_CNTL_POS 5
46 #define EDGE_RATE_CNTL_MASK 0x00E0
48 #define MSCC_EXT_PAGE_ACCESS 31
49 #define MSCC_PHY_PAGE_STANDARD 0x0000 /* Standard registers */
50 #define MSCC_PHY_PAGE_EXTENDED_2 0x0002 /* Extended reg - page 2 */
52 /* Extended Page 2 Registers */
53 #define MSCC_PHY_RGMII_CNTL 20
54 #define RGMII_RX_CLK_DELAY_MASK 0x0070
55 #define RGMII_RX_CLK_DELAY_POS 4
57 #define MSCC_PHY_WOL_LOWER_MAC_ADDR 21
58 #define MSCC_PHY_WOL_MID_MAC_ADDR 22
59 #define MSCC_PHY_WOL_UPPER_MAC_ADDR 23
60 #define MSCC_PHY_WOL_LOWER_PASSWD 24
61 #define MSCC_PHY_WOL_MID_PASSWD 25
62 #define MSCC_PHY_WOL_UPPER_PASSWD 26
64 #define MSCC_PHY_WOL_MAC_CONTROL 27
65 #define SECURE_ON_ENABLE 0x8000
66 #define SECURE_ON_PASSWD_LEN_4 0x4000
68 /* Microsemi PHY ID's */
69 #define PHY_ID_VSC8531 0x00070570
70 #define PHY_ID_VSC8541 0x00070770
72 struct edge_rate_table
{
74 int slowdown
[MSCC_SLOWDOWN_MAX
];
77 struct edge_rate_table edge_table
[MSCC_VDDMAC_MAX
] = {
78 {3300, { 0, -2, -4, -7, -10, -17, -29, -53} },
79 {2500, { 0, -3, -6, -10, -14, -23, -37, -63} },
80 {1800, { 0, -5, -9, -16, -23, -35, -52, -76} },
81 {1500, { 0, -6, -14, -21, -29, -42, -58, -77} },
84 struct vsc8531_private
{
89 static int vsc85xx_phy_page_set(struct phy_device
*phydev
, u8 page
)
93 rc
= phy_write(phydev
, MSCC_EXT_PAGE_ACCESS
, page
);
97 static int vsc85xx_wol_set(struct phy_device
*phydev
,
98 struct ethtool_wolinfo
*wol
)
103 u16 pwd
[3] = {0, 0, 0};
104 struct ethtool_wolinfo
*wol_conf
= wol
;
105 u8
*mac_addr
= phydev
->attached_dev
->dev_addr
;
107 mutex_lock(&phydev
->lock
);
108 rc
= vsc85xx_phy_page_set(phydev
, MSCC_PHY_PAGE_EXTENDED_2
);
112 if (wol
->wolopts
& WAKE_MAGIC
) {
113 /* Store the device address for the magic packet */
114 for (i
= 0; i
< ARRAY_SIZE(pwd
); i
++)
115 pwd
[i
] = mac_addr
[5 - (i
* 2 + 1)] << 8 |
117 phy_write(phydev
, MSCC_PHY_WOL_LOWER_MAC_ADDR
, pwd
[0]);
118 phy_write(phydev
, MSCC_PHY_WOL_MID_MAC_ADDR
, pwd
[1]);
119 phy_write(phydev
, MSCC_PHY_WOL_UPPER_MAC_ADDR
, pwd
[2]);
121 phy_write(phydev
, MSCC_PHY_WOL_LOWER_MAC_ADDR
, 0);
122 phy_write(phydev
, MSCC_PHY_WOL_MID_MAC_ADDR
, 0);
123 phy_write(phydev
, MSCC_PHY_WOL_UPPER_MAC_ADDR
, 0);
126 if (wol_conf
->wolopts
& WAKE_MAGICSECURE
) {
127 for (i
= 0; i
< ARRAY_SIZE(pwd
); i
++)
128 pwd
[i
] = wol_conf
->sopass
[5 - (i
* 2 + 1)] << 8 |
129 wol_conf
->sopass
[5 - i
* 2];
130 phy_write(phydev
, MSCC_PHY_WOL_LOWER_PASSWD
, pwd
[0]);
131 phy_write(phydev
, MSCC_PHY_WOL_MID_PASSWD
, pwd
[1]);
132 phy_write(phydev
, MSCC_PHY_WOL_UPPER_PASSWD
, pwd
[2]);
134 phy_write(phydev
, MSCC_PHY_WOL_LOWER_PASSWD
, 0);
135 phy_write(phydev
, MSCC_PHY_WOL_MID_PASSWD
, 0);
136 phy_write(phydev
, MSCC_PHY_WOL_UPPER_PASSWD
, 0);
139 reg_val
= phy_read(phydev
, MSCC_PHY_WOL_MAC_CONTROL
);
140 if (wol_conf
->wolopts
& WAKE_MAGICSECURE
)
141 reg_val
|= SECURE_ON_ENABLE
;
143 reg_val
&= ~SECURE_ON_ENABLE
;
144 phy_write(phydev
, MSCC_PHY_WOL_MAC_CONTROL
, reg_val
);
146 rc
= vsc85xx_phy_page_set(phydev
, MSCC_PHY_PAGE_STANDARD
);
150 if (wol
->wolopts
& WAKE_MAGIC
) {
151 /* Enable the WOL interrupt */
152 reg_val
= phy_read(phydev
, MII_VSC85XX_INT_MASK
);
153 reg_val
|= MII_VSC85XX_INT_MASK_WOL
;
154 rc
= phy_write(phydev
, MII_VSC85XX_INT_MASK
, reg_val
);
158 /* Disable the WOL interrupt */
159 reg_val
= phy_read(phydev
, MII_VSC85XX_INT_MASK
);
160 reg_val
&= (~MII_VSC85XX_INT_MASK_WOL
);
161 rc
= phy_write(phydev
, MII_VSC85XX_INT_MASK
, reg_val
);
165 /* Clear WOL iterrupt status */
166 reg_val
= phy_read(phydev
, MII_VSC85XX_INT_STATUS
);
169 mutex_unlock(&phydev
->lock
);
174 static void vsc85xx_wol_get(struct phy_device
*phydev
,
175 struct ethtool_wolinfo
*wol
)
180 u16 pwd
[3] = {0, 0, 0};
181 struct ethtool_wolinfo
*wol_conf
= wol
;
183 mutex_lock(&phydev
->lock
);
184 rc
= vsc85xx_phy_page_set(phydev
, MSCC_PHY_PAGE_EXTENDED_2
);
188 reg_val
= phy_read(phydev
, MSCC_PHY_WOL_MAC_CONTROL
);
189 if (reg_val
& SECURE_ON_ENABLE
)
190 wol_conf
->wolopts
|= WAKE_MAGICSECURE
;
191 if (wol_conf
->wolopts
& WAKE_MAGICSECURE
) {
192 pwd
[0] = phy_read(phydev
, MSCC_PHY_WOL_LOWER_PASSWD
);
193 pwd
[1] = phy_read(phydev
, MSCC_PHY_WOL_MID_PASSWD
);
194 pwd
[2] = phy_read(phydev
, MSCC_PHY_WOL_UPPER_PASSWD
);
195 for (i
= 0; i
< ARRAY_SIZE(pwd
); i
++) {
196 wol_conf
->sopass
[5 - i
* 2] = pwd
[i
] & 0x00ff;
197 wol_conf
->sopass
[5 - (i
* 2 + 1)] = (pwd
[i
] & 0xff00)
202 rc
= vsc85xx_phy_page_set(phydev
, MSCC_PHY_PAGE_STANDARD
);
205 mutex_unlock(&phydev
->lock
);
208 static u8
edge_rate_magic_get(u16 vddmac
,
211 int rc
= (MSCC_SLOWDOWN_MAX
- 1);
215 for (vdd
= 0; vdd
< MSCC_VDDMAC_MAX
; vdd
++) {
216 if (edge_table
[vdd
].vddmac
== vddmac
) {
217 for (sd
= 0; sd
< MSCC_SLOWDOWN_MAX
; sd
++) {
218 if (edge_table
[vdd
].slowdown
[sd
] <= slowdown
) {
219 rc
= (MSCC_SLOWDOWN_MAX
- sd
- 1);
229 static int vsc85xx_edge_rate_cntl_set(struct phy_device
*phydev
,
235 mutex_lock(&phydev
->lock
);
236 rc
= vsc85xx_phy_page_set(phydev
, MSCC_PHY_PAGE_EXTENDED_2
);
239 reg_val
= phy_read(phydev
, MSCC_PHY_WOL_MAC_CONTROL
);
240 reg_val
&= ~(EDGE_RATE_CNTL_MASK
);
241 reg_val
|= (edge_rate
<< EDGE_RATE_CNTL_POS
);
242 rc
= phy_write(phydev
, MSCC_PHY_WOL_MAC_CONTROL
, reg_val
);
245 rc
= vsc85xx_phy_page_set(phydev
, MSCC_PHY_PAGE_STANDARD
);
248 mutex_unlock(&phydev
->lock
);
253 static int vsc85xx_mac_if_set(struct phy_device
*phydev
,
254 phy_interface_t interface
)
259 mutex_lock(&phydev
->lock
);
260 reg_val
= phy_read(phydev
, MSCC_PHY_EXT_PHY_CNTL_1
);
261 reg_val
&= ~(MAC_IF_SELECTION_MASK
);
263 case PHY_INTERFACE_MODE_RGMII
:
264 reg_val
|= (MAC_IF_SELECTION_RGMII
<< MAC_IF_SELECTION_POS
);
266 case PHY_INTERFACE_MODE_RMII
:
267 reg_val
|= (MAC_IF_SELECTION_RMII
<< MAC_IF_SELECTION_POS
);
269 case PHY_INTERFACE_MODE_MII
:
270 case PHY_INTERFACE_MODE_GMII
:
271 reg_val
|= (MAC_IF_SELECTION_GMII
<< MAC_IF_SELECTION_POS
);
277 rc
= phy_write(phydev
, MSCC_PHY_EXT_PHY_CNTL_1
, reg_val
);
281 rc
= genphy_soft_reset(phydev
);
284 mutex_unlock(&phydev
->lock
);
289 static int vsc85xx_default_config(struct phy_device
*phydev
)
294 mutex_lock(&phydev
->lock
);
295 rc
= vsc85xx_phy_page_set(phydev
, MSCC_PHY_PAGE_EXTENDED_2
);
299 reg_val
= phy_read(phydev
, MSCC_PHY_RGMII_CNTL
);
300 reg_val
&= ~(RGMII_RX_CLK_DELAY_MASK
);
301 reg_val
|= (RGMII_RX_CLK_DELAY_1_1_NS
<< RGMII_RX_CLK_DELAY_POS
);
302 phy_write(phydev
, MSCC_PHY_RGMII_CNTL
, reg_val
);
303 rc
= vsc85xx_phy_page_set(phydev
, MSCC_PHY_PAGE_STANDARD
);
306 mutex_unlock(&phydev
->lock
);
311 #ifdef CONFIG_OF_MDIO
312 static int vsc8531_of_init(struct phy_device
*phydev
)
315 struct vsc8531_private
*vsc8531
= phydev
->priv
;
316 struct device
*dev
= &phydev
->mdio
.dev
;
317 struct device_node
*of_node
= dev
->of_node
;
322 rc
= of_property_read_u16(of_node
, "vsc8531,vddmac",
325 vsc8531
->vddmac
= MSCC_VDDMAC_3300
;
326 rc
= of_property_read_u8(of_node
, "vsc8531,edge-slowdown",
327 &vsc8531
->edge_slowdown
);
329 vsc8531
->edge_slowdown
= 0;
335 static int vsc8531_of_init(struct phy_device
*phydev
)
339 #endif /* CONFIG_OF_MDIO */
341 static int vsc85xx_config_init(struct phy_device
*phydev
)
344 struct vsc8531_private
*vsc8531
= phydev
->priv
;
347 rc
= vsc8531_of_init(phydev
);
351 rc
= vsc85xx_default_config(phydev
);
355 rc
= vsc85xx_mac_if_set(phydev
, phydev
->interface
);
359 edge_rate
= edge_rate_magic_get(vsc8531
->vddmac
,
360 -(int)vsc8531
->edge_slowdown
);
361 rc
= vsc85xx_edge_rate_cntl_set(phydev
, edge_rate
);
365 rc
= genphy_config_init(phydev
);
370 static int vsc85xx_ack_interrupt(struct phy_device
*phydev
)
374 if (phydev
->interrupts
== PHY_INTERRUPT_ENABLED
)
375 rc
= phy_read(phydev
, MII_VSC85XX_INT_STATUS
);
377 return (rc
< 0) ? rc
: 0;
380 static int vsc85xx_config_intr(struct phy_device
*phydev
)
384 if (phydev
->interrupts
== PHY_INTERRUPT_ENABLED
) {
385 rc
= phy_write(phydev
, MII_VSC85XX_INT_MASK
,
386 MII_VSC85XX_INT_MASK_MASK
);
388 rc
= phy_write(phydev
, MII_VSC85XX_INT_MASK
, 0);
391 rc
= phy_read(phydev
, MII_VSC85XX_INT_STATUS
);
397 static int vsc85xx_probe(struct phy_device
*phydev
)
399 struct vsc8531_private
*vsc8531
;
401 vsc8531
= devm_kzalloc(&phydev
->mdio
.dev
, sizeof(*vsc8531
), GFP_KERNEL
);
405 phydev
->priv
= vsc8531
;
410 /* Microsemi VSC85xx PHYs */
411 static struct phy_driver vsc85xx_driver
[] = {
413 .phy_id
= PHY_ID_VSC8531
,
414 .name
= "Microsemi VSC8531",
415 .phy_id_mask
= 0xfffffff0,
416 .features
= PHY_GBIT_FEATURES
,
417 .flags
= PHY_HAS_INTERRUPT
,
418 .soft_reset
= &genphy_soft_reset
,
419 .config_init
= &vsc85xx_config_init
,
420 .config_aneg
= &genphy_config_aneg
,
421 .aneg_done
= &genphy_aneg_done
,
422 .read_status
= &genphy_read_status
,
423 .ack_interrupt
= &vsc85xx_ack_interrupt
,
424 .config_intr
= &vsc85xx_config_intr
,
425 .suspend
= &genphy_suspend
,
426 .resume
= &genphy_resume
,
427 .probe
= &vsc85xx_probe
,
428 .set_wol
= &vsc85xx_wol_set
,
429 .get_wol
= &vsc85xx_wol_get
,
432 .phy_id
= PHY_ID_VSC8541
,
433 .name
= "Microsemi VSC8541 SyncE",
434 .phy_id_mask
= 0xfffffff0,
435 .features
= PHY_GBIT_FEATURES
,
436 .flags
= PHY_HAS_INTERRUPT
,
437 .soft_reset
= &genphy_soft_reset
,
438 .config_init
= &vsc85xx_config_init
,
439 .config_aneg
= &genphy_config_aneg
,
440 .aneg_done
= &genphy_aneg_done
,
441 .read_status
= &genphy_read_status
,
442 .ack_interrupt
= &vsc85xx_ack_interrupt
,
443 .config_intr
= &vsc85xx_config_intr
,
444 .suspend
= &genphy_suspend
,
445 .resume
= &genphy_resume
,
446 .probe
= &vsc85xx_probe
,
447 .set_wol
= &vsc85xx_wol_set
,
448 .get_wol
= &vsc85xx_wol_get
,
453 module_phy_driver(vsc85xx_driver
);
455 static struct mdio_device_id __maybe_unused vsc85xx_tbl
[] = {
456 { PHY_ID_VSC8531
, 0xfffffff0, },
457 { PHY_ID_VSC8541
, 0xfffffff0, },
461 MODULE_DEVICE_TABLE(mdio
, vsc85xx_tbl
);
463 MODULE_DESCRIPTION("Microsemi VSC85xx PHY driver");
464 MODULE_AUTHOR("Nagaraju Lakkaraju");
465 MODULE_LICENSE("Dual MIT/GPL");