]> rtime.felk.cvut.cz Git - zynq/linux.git/blob - drivers/net/phy/xilinx_phy.c
2f864cc67ee60589ba68ee16999a7dbe712ad98c
[zynq/linux.git] / drivers / net / phy / xilinx_phy.c
1 /* Xilinx PCS/PMA Core phy driver
2  *
3  * Copyright (C) 2015 Xilinx, Inc.
4  *
5  * Description:
6  * This driver is developed for PCS/PMA Core.
7  *
8  * This program is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  */
18
19 #include <linux/kernel.h>
20 #include <linux/module.h>
21 #include <linux/mii.h>
22 #include <linux/phy.h>
23 #include <linux/of.h>
24 #include <linux/xilinx_phy.h>
25
26 #define MII_PHY_STATUS_SPD_MASK         0x0C00
27 #define MII_PHY_STATUS_FULLDUPLEX       0x1000
28 #define MII_PHY_STATUS_1000             0x0800
29 #define MII_PHY_STATUS_100              0x0400
30 #define XPCSPMA_PHY_CTRL_ISOLATE_DISABLE 0xFBFF
31
32 static int xilinxphy_read_status(struct phy_device *phydev)
33 {
34         int err;
35         int status = 0;
36
37         /* Update the link, but return if there
38          * was an error
39          */
40         err = genphy_update_link(phydev);
41         if (err)
42                 return err;
43
44         if (AUTONEG_ENABLE == phydev->autoneg) {
45                 status = phy_read(phydev, MII_LPA);
46                 status = status & MII_PHY_STATUS_SPD_MASK;
47
48                 if (status & MII_PHY_STATUS_FULLDUPLEX)
49                         phydev->duplex = DUPLEX_FULL;
50                 else
51                         phydev->duplex = DUPLEX_HALF;
52
53                 switch (status) {
54                 case MII_PHY_STATUS_1000:
55                         phydev->speed = SPEED_1000;
56                         break;
57
58                 case MII_PHY_STATUS_100:
59                         phydev->speed = SPEED_100;
60                         break;
61
62                 default:
63                         phydev->speed = SPEED_10;
64                         break;
65                 }
66         } else {
67                 int bmcr = phy_read(phydev, MII_BMCR);
68
69                 if (bmcr < 0)
70                         return bmcr;
71
72                 if (bmcr & BMCR_FULLDPLX)
73                         phydev->duplex = DUPLEX_FULL;
74                 else
75                         phydev->duplex = DUPLEX_HALF;
76
77                 if (bmcr & BMCR_SPEED1000)
78                         phydev->speed = SPEED_1000;
79                 else if (bmcr & BMCR_SPEED100)
80                         phydev->speed = SPEED_100;
81                 else
82                         phydev->speed = SPEED_10;
83         }
84
85         /* For 1000BASE-X Phy Mode the speed/duplex will always be
86          * 1000Mbps/fullduplex
87          */
88         if (phydev->dev_flags == XAE_PHY_TYPE_1000BASE_X) {
89                 phydev->duplex = DUPLEX_FULL;
90                 phydev->speed = SPEED_1000;
91         }
92
93         return 0;
94 }
95
96 static int xilinxphy_config_init(struct phy_device *phydev)
97 {
98         int temp;
99
100         temp = phy_read(phydev, MII_BMCR);
101         temp &= XPCSPMA_PHY_CTRL_ISOLATE_DISABLE;
102         phy_write(phydev, MII_BMCR, temp);
103
104         return 0;
105 }
106
107 static struct phy_driver xilinx_drivers[] = {
108         {
109                 .phy_id = XILINX_PHY_ID,
110                 .phy_id_mask = XILINX_PHY_ID_MASK,
111                 .name = "Xilinx PCS/PMA PHY",
112                 .features = PHY_GBIT_FEATURES,
113                 .config_init = &xilinxphy_config_init,
114                 .config_aneg = &genphy_config_aneg,
115                 .read_status = &xilinxphy_read_status,
116                 .resume = &genphy_resume,
117                 .suspend = &genphy_suspend,
118                 .driver = { .owner = THIS_MODULE },
119         },
120 };
121
122 module_phy_driver(xilinx_drivers);
123
124 static struct mdio_device_id __maybe_unused xilinx_tbl[] = {
125         { XILINX_PHY_ID, XILINX_PHY_ID_MASK },
126         { }
127 };
128
129 MODULE_DEVICE_TABLE(mdio, xilinx_tbl);
130 MODULE_DESCRIPTION("Xilinx PCS/PMA PHY driver");
131 MODULE_LICENSE("GPL");