1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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
32static int xilinxphy_read_status(struct phy_device *phydev)
33{
34 int err;
35 int status = 0;
36
37
38
39
40 err = genphy_update_link(phydev);
41 if (err)
42 return err;
43
44 if (phydev->autoneg == AUTONEG_ENABLE) {
45 status = phy_read(phydev, MII_LPA);
46
47 if (status & MII_PHY_STATUS_FULLDUPLEX)
48 phydev->duplex = DUPLEX_FULL;
49 else
50 phydev->duplex = DUPLEX_HALF;
51
52 switch (status & MII_PHY_STATUS_SPD_MASK) {
53 case MII_PHY_STATUS_1000:
54 phydev->speed = SPEED_1000;
55 break;
56
57 case MII_PHY_STATUS_100:
58 phydev->speed = SPEED_100;
59 break;
60
61 default:
62 phydev->speed = SPEED_10;
63 break;
64 }
65 } else {
66 int bmcr = phy_read(phydev, MII_BMCR);
67
68 if (bmcr < 0)
69 return bmcr;
70
71 if (bmcr & BMCR_FULLDPLX)
72 phydev->duplex = DUPLEX_FULL;
73 else
74 phydev->duplex = DUPLEX_HALF;
75
76 if (bmcr & BMCR_SPEED1000)
77 phydev->speed = SPEED_1000;
78 else if (bmcr & BMCR_SPEED100)
79 phydev->speed = SPEED_100;
80 else
81 phydev->speed = SPEED_10;
82 }
83
84
85
86
87 if (phydev->dev_flags == XAE_PHY_TYPE_1000BASE_X) {
88 phydev->duplex = DUPLEX_FULL;
89 phydev->speed = SPEED_1000;
90 }
91
92
93
94
95 if (phydev->dev_flags == XAE_PHY_TYPE_2500) {
96 phydev->duplex = DUPLEX_FULL;
97 phydev->speed = SPEED_2500;
98 }
99
100 return 0;
101}
102
103static int xilinxphy_of_init(struct phy_device *phydev)
104{
105 struct device *dev = &phydev->mdio.dev;
106 struct device_node *of_node = dev->of_node;
107 u32 phytype;
108
109 if (!IS_ENABLED(CONFIG_OF_MDIO))
110 return 0;
111
112 if (!of_node)
113 return -ENODEV;
114
115 if (!of_property_read_u32(of_node, "xlnx,phy-type", &phytype)) {
116 if (phytype == XAE_PHY_TYPE_1000BASE_X)
117 phydev->dev_flags |= XAE_PHY_TYPE_1000BASE_X;
118 if (phytype == XAE_PHY_TYPE_2500)
119 phydev->dev_flags |= XAE_PHY_TYPE_2500;
120 }
121
122 return 0;
123}
124
125static int xilinxphy_config_init(struct phy_device *phydev)
126{
127 int temp;
128
129 xilinxphy_of_init(phydev);
130 temp = phy_read(phydev, MII_BMCR);
131 temp &= XPCSPMA_PHY_CTRL_ISOLATE_DISABLE;
132 phy_write(phydev, MII_BMCR, temp);
133
134 return 0;
135}
136
137static struct phy_driver xilinx_drivers[] = {
138 {
139 .phy_id = XILINX_PHY_ID,
140 .phy_id_mask = XILINX_PHY_ID_MASK,
141 .name = "Xilinx PCS/PMA PHY",
142 .features = PHY_GBIT_FEATURES,
143 .config_init = &xilinxphy_config_init,
144 .config_aneg = &genphy_config_aneg,
145 .read_status = &xilinxphy_read_status,
146 .resume = &genphy_resume,
147 .suspend = &genphy_suspend,
148 },
149};
150
151module_phy_driver(xilinx_drivers);
152
153static struct mdio_device_id __maybe_unused xilinx_tbl[] = {
154 { XILINX_PHY_ID, XILINX_PHY_ID_MASK },
155 { }
156};
157
158MODULE_DEVICE_TABLE(mdio, xilinx_tbl);
159MODULE_DESCRIPTION("Xilinx PCS/PMA PHY driver");
160MODULE_LICENSE("GPL");
161