net: phy: dp83848: add dp83822 PHY support
[cascardo/linux.git] / drivers / net / phy / mscc.c
1 /*
2  * Driver for Microsemi VSC85xx PHYs
3  *
4  * Author: Nagaraju Lakkaraju
5  * License: Dual MIT/GPL
6  * Copyright (c) 2016 Microsemi Corporation
7  */
8
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>
14 #include <linux/of.h>
15 #include <dt-bindings/net/mscc-phy-vsc8531.h>
16 #include <linux/netdevice.h>
17
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
27 };
28
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
38
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
43
44 #define MSCC_PHY_WOL_MAC_CONTROL          27
45 #define EDGE_RATE_CNTL_POS                5
46 #define EDGE_RATE_CNTL_MASK               0x00E0
47
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 */
51
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
56
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
63
64 #define MSCC_PHY_WOL_MAC_CONTROL          27
65 #define SECURE_ON_ENABLE                  0x8000
66 #define SECURE_ON_PASSWD_LEN_4            0x4000
67
68 /* Microsemi PHY ID's */
69 #define PHY_ID_VSC8531                    0x00070570
70 #define PHY_ID_VSC8541                    0x00070770
71
72 struct edge_rate_table {
73         u16 vddmac;
74         int slowdown[MSCC_SLOWDOWN_MAX];
75 };
76
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} },
82 };
83
84 struct vsc8531_private {
85         u8 edge_slowdown;
86         u16 vddmac;
87 };
88
89 static int vsc85xx_phy_page_set(struct phy_device *phydev, u8 page)
90 {
91         int rc;
92
93         rc = phy_write(phydev, MSCC_EXT_PAGE_ACCESS, page);
94         return rc;
95 }
96
97 static int vsc85xx_wol_set(struct phy_device *phydev,
98                            struct ethtool_wolinfo *wol)
99 {
100         int rc;
101         u16 reg_val;
102         u8  i;
103         u16 pwd[3] = {0, 0, 0};
104         struct ethtool_wolinfo *wol_conf = wol;
105         u8 *mac_addr = phydev->attached_dev->dev_addr;
106
107         mutex_lock(&phydev->lock);
108         rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_EXTENDED_2);
109         if (rc != 0)
110                 goto out_unlock;
111
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 |
116                                  mac_addr[5 - i * 2];
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]);
120         } else {
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);
124         }
125
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]);
133         } else {
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);
137         }
138
139         reg_val = phy_read(phydev, MSCC_PHY_WOL_MAC_CONTROL);
140         if (wol_conf->wolopts & WAKE_MAGICSECURE)
141                 reg_val |= SECURE_ON_ENABLE;
142         else
143                 reg_val &= ~SECURE_ON_ENABLE;
144         phy_write(phydev, MSCC_PHY_WOL_MAC_CONTROL, reg_val);
145
146         rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_STANDARD);
147         if (rc != 0)
148                 goto out_unlock;
149
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);
155                 if (rc != 0)
156                         goto out_unlock;
157         } else {
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);
162                 if (rc != 0)
163                         goto out_unlock;
164         }
165         /* Clear WOL iterrupt status */
166         reg_val = phy_read(phydev, MII_VSC85XX_INT_STATUS);
167
168 out_unlock:
169         mutex_unlock(&phydev->lock);
170
171         return rc;
172 }
173
174 static void vsc85xx_wol_get(struct phy_device *phydev,
175                             struct ethtool_wolinfo *wol)
176 {
177         int rc;
178         u16 reg_val;
179         u8  i;
180         u16 pwd[3] = {0, 0, 0};
181         struct ethtool_wolinfo *wol_conf = wol;
182
183         mutex_lock(&phydev->lock);
184         rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_EXTENDED_2);
185         if (rc != 0)
186                 goto out_unlock;
187
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)
198                                                             >> 8;
199                 }
200         }
201
202         rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_STANDARD);
203
204 out_unlock:
205         mutex_unlock(&phydev->lock);
206 }
207
208 static u8 edge_rate_magic_get(u16 vddmac,
209                               int slowdown)
210 {
211         int rc = (MSCC_SLOWDOWN_MAX - 1);
212         u8 vdd;
213         u8 sd;
214
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);
220                                         break;
221                                 }
222                         }
223                 }
224         }
225
226         return rc;
227 }
228
229 static int vsc85xx_edge_rate_cntl_set(struct phy_device *phydev,
230                                       u8 edge_rate)
231 {
232         int rc;
233         u16 reg_val;
234
235         mutex_lock(&phydev->lock);
236         rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_EXTENDED_2);
237         if (rc != 0)
238                 goto out_unlock;
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);
243         if (rc != 0)
244                 goto out_unlock;
245         rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_STANDARD);
246
247 out_unlock:
248         mutex_unlock(&phydev->lock);
249
250         return rc;
251 }
252
253 static int vsc85xx_mac_if_set(struct phy_device *phydev,
254                               phy_interface_t interface)
255 {
256         int rc;
257         u16 reg_val;
258
259         mutex_lock(&phydev->lock);
260         reg_val = phy_read(phydev, MSCC_PHY_EXT_PHY_CNTL_1);
261         reg_val &= ~(MAC_IF_SELECTION_MASK);
262         switch (interface) {
263         case PHY_INTERFACE_MODE_RGMII:
264                 reg_val |= (MAC_IF_SELECTION_RGMII << MAC_IF_SELECTION_POS);
265                 break;
266         case PHY_INTERFACE_MODE_RMII:
267                 reg_val |= (MAC_IF_SELECTION_RMII << MAC_IF_SELECTION_POS);
268                 break;
269         case PHY_INTERFACE_MODE_MII:
270         case PHY_INTERFACE_MODE_GMII:
271                 reg_val |= (MAC_IF_SELECTION_GMII << MAC_IF_SELECTION_POS);
272                 break;
273         default:
274                 rc = -EINVAL;
275                 goto out_unlock;
276         }
277         rc = phy_write(phydev, MSCC_PHY_EXT_PHY_CNTL_1, reg_val);
278         if (rc != 0)
279                 goto out_unlock;
280
281         rc = genphy_soft_reset(phydev);
282
283 out_unlock:
284         mutex_unlock(&phydev->lock);
285
286         return rc;
287 }
288
289 static int vsc85xx_default_config(struct phy_device *phydev)
290 {
291         int rc;
292         u16 reg_val;
293
294         mutex_lock(&phydev->lock);
295         rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_EXTENDED_2);
296         if (rc != 0)
297                 goto out_unlock;
298
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);
304
305 out_unlock:
306         mutex_unlock(&phydev->lock);
307
308         return rc;
309 }
310
311 #ifdef CONFIG_OF_MDIO
312 static int vsc8531_of_init(struct phy_device *phydev)
313 {
314         int rc;
315         struct vsc8531_private *vsc8531 = phydev->priv;
316         struct device *dev = &phydev->mdio.dev;
317         struct device_node *of_node = dev->of_node;
318
319         if (!of_node)
320                 return -ENODEV;
321
322         rc = of_property_read_u16(of_node, "vsc8531,vddmac",
323                                   &vsc8531->vddmac);
324         if (rc == -EINVAL)
325                 vsc8531->vddmac = MSCC_VDDMAC_3300;
326         rc = of_property_read_u8(of_node, "vsc8531,edge-slowdown",
327                                  &vsc8531->edge_slowdown);
328         if (rc == -EINVAL)
329                 vsc8531->edge_slowdown = 0;
330
331         rc = 0;
332         return rc;
333 }
334 #else
335 static int vsc8531_of_init(struct phy_device *phydev)
336 {
337         return 0;
338 }
339 #endif /* CONFIG_OF_MDIO */
340
341 static int vsc85xx_config_init(struct phy_device *phydev)
342 {
343         int rc;
344         struct vsc8531_private *vsc8531 = phydev->priv;
345         u8 edge_rate;
346
347         rc = vsc8531_of_init(phydev);
348         if (rc)
349                 return rc;
350
351         rc = vsc85xx_default_config(phydev);
352         if (rc)
353                 return rc;
354
355         rc = vsc85xx_mac_if_set(phydev, phydev->interface);
356         if (rc)
357                 return rc;
358
359         edge_rate = edge_rate_magic_get(vsc8531->vddmac,
360                                         -(int)vsc8531->edge_slowdown);
361         rc = vsc85xx_edge_rate_cntl_set(phydev, edge_rate);
362         if (rc)
363                 return rc;
364
365         rc = genphy_config_init(phydev);
366
367         return rc;
368 }
369
370 static int vsc85xx_ack_interrupt(struct phy_device *phydev)
371 {
372         int rc = 0;
373
374         if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
375                 rc = phy_read(phydev, MII_VSC85XX_INT_STATUS);
376
377         return (rc < 0) ? rc : 0;
378 }
379
380 static int vsc85xx_config_intr(struct phy_device *phydev)
381 {
382         int rc;
383
384         if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
385                 rc = phy_write(phydev, MII_VSC85XX_INT_MASK,
386                                MII_VSC85XX_INT_MASK_MASK);
387         } else {
388                 rc = phy_write(phydev, MII_VSC85XX_INT_MASK, 0);
389                 if (rc < 0)
390                         return rc;
391                 rc = phy_read(phydev, MII_VSC85XX_INT_STATUS);
392         }
393
394         return rc;
395 }
396
397 static int vsc85xx_probe(struct phy_device *phydev)
398 {
399         struct vsc8531_private *vsc8531;
400
401         vsc8531 = devm_kzalloc(&phydev->mdio.dev, sizeof(*vsc8531), GFP_KERNEL);
402         if (!vsc8531)
403                 return -ENOMEM;
404
405         phydev->priv = vsc8531;
406
407         return 0;
408 }
409
410 /* Microsemi VSC85xx PHYs */
411 static struct phy_driver vsc85xx_driver[] = {
412 {
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,
430 },
431 {
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,
449 }
450
451 };
452
453 module_phy_driver(vsc85xx_driver);
454
455 static struct mdio_device_id __maybe_unused vsc85xx_tbl[] = {
456         { PHY_ID_VSC8531, 0xfffffff0, },
457         { PHY_ID_VSC8541, 0xfffffff0, },
458         { }
459 };
460
461 MODULE_DEVICE_TABLE(mdio, vsc85xx_tbl);
462
463 MODULE_DESCRIPTION("Microsemi VSC85xx PHY driver");
464 MODULE_AUTHOR("Nagaraju Lakkaraju");
465 MODULE_LICENSE("Dual MIT/GPL");