1c3ff77de56b47a682f40dac055212e1d5e89da0
[releases.git] / marvell-88q2xxx.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Marvell 88Q2XXX automotive 100BASE-T1/1000BASE-T1 PHY driver
4  */
5 #include <linux/ethtool_netlink.h>
6 #include <linux/marvell_phy.h>
7 #include <linux/phy.h>
8
9 #define MDIO_MMD_AN_MV_STAT                     32769
10 #define MDIO_MMD_AN_MV_STAT_ANEG                0x0100
11 #define MDIO_MMD_AN_MV_STAT_LOCAL_RX            0x1000
12 #define MDIO_MMD_AN_MV_STAT_REMOTE_RX           0x2000
13 #define MDIO_MMD_AN_MV_STAT_LOCAL_MASTER        0x4000
14 #define MDIO_MMD_AN_MV_STAT_MS_CONF_FAULT       0x8000
15
16 #define MDIO_MMD_PCS_MV_100BT1_STAT1                    33032
17 #define MDIO_MMD_PCS_MV_100BT1_STAT1_IDLE_ERROR 0x00FF
18 #define MDIO_MMD_PCS_MV_100BT1_STAT1_JABBER             0x0100
19 #define MDIO_MMD_PCS_MV_100BT1_STAT1_LINK               0x0200
20 #define MDIO_MMD_PCS_MV_100BT1_STAT1_LOCAL_RX           0x1000
21 #define MDIO_MMD_PCS_MV_100BT1_STAT1_REMOTE_RX          0x2000
22 #define MDIO_MMD_PCS_MV_100BT1_STAT1_LOCAL_MASTER       0x4000
23
24 #define MDIO_MMD_PCS_MV_100BT1_STAT2            33033
25 #define MDIO_MMD_PCS_MV_100BT1_STAT2_JABBER     0x0001
26 #define MDIO_MMD_PCS_MV_100BT1_STAT2_POL        0x0002
27 #define MDIO_MMD_PCS_MV_100BT1_STAT2_LINK       0x0004
28 #define MDIO_MMD_PCS_MV_100BT1_STAT2_ANGE       0x0008
29
30 static int mv88q2xxx_soft_reset(struct phy_device *phydev)
31 {
32         int ret;
33         int val;
34
35         ret = phy_write_mmd(phydev, MDIO_MMD_PCS,
36                             MDIO_PCS_1000BT1_CTRL, MDIO_PCS_1000BT1_CTRL_RESET);
37         if (ret < 0)
38                 return ret;
39
40         return phy_read_mmd_poll_timeout(phydev, MDIO_MMD_PCS,
41                                          MDIO_PCS_1000BT1_CTRL, val,
42                                          !(val & MDIO_PCS_1000BT1_CTRL_RESET),
43                                          50000, 600000, true);
44 }
45
46 static int mv88q2xxx_read_link_gbit(struct phy_device *phydev)
47 {
48         int ret;
49         bool link = false;
50
51         /* Read vendor specific Auto-Negotiation status register to get local
52          * and remote receiver status according to software initialization
53          * guide.
54          */
55         ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_MMD_AN_MV_STAT);
56         if (ret < 0) {
57                 return ret;
58         } else if ((ret & MDIO_MMD_AN_MV_STAT_LOCAL_RX) &&
59                    (ret & MDIO_MMD_AN_MV_STAT_REMOTE_RX)) {
60                 /* The link state is latched low so that momentary link
61                  * drops can be detected. Do not double-read the status
62                  * in polling mode to detect such short link drops except
63                  * the link was already down.
64                  */
65                 if (!phy_polling_mode(phydev) || !phydev->link) {
66                         ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_PCS_1000BT1_STAT);
67                         if (ret < 0)
68                                 return ret;
69                         else if (ret & MDIO_PCS_1000BT1_STAT_LINK)
70                                 link = true;
71                 }
72
73                 if (!link) {
74                         ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_PCS_1000BT1_STAT);
75                         if (ret < 0)
76                                 return ret;
77                         else if (ret & MDIO_PCS_1000BT1_STAT_LINK)
78                                 link = true;
79                 }
80         }
81
82         phydev->link = link;
83
84         return 0;
85 }
86
87 static int mv88q2xxx_read_link_100m(struct phy_device *phydev)
88 {
89         int ret;
90
91         /* The link state is latched low so that momentary link
92          * drops can be detected. Do not double-read the status
93          * in polling mode to detect such short link drops except
94          * the link was already down. In case we are not polling,
95          * we always read the realtime status.
96          */
97         if (!phy_polling_mode(phydev) || !phydev->link) {
98                 ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_MMD_PCS_MV_100BT1_STAT1);
99                 if (ret < 0)
100                         return ret;
101                 else if (ret & MDIO_MMD_PCS_MV_100BT1_STAT1_LINK)
102                         goto out;
103         }
104
105         ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_MMD_PCS_MV_100BT1_STAT1);
106         if (ret < 0)
107                 return ret;
108
109 out:
110         /* Check if we have link and if the remote and local receiver are ok */
111         if ((ret & MDIO_MMD_PCS_MV_100BT1_STAT1_LINK) &&
112             (ret & MDIO_MMD_PCS_MV_100BT1_STAT1_LOCAL_RX) &&
113             (ret & MDIO_MMD_PCS_MV_100BT1_STAT1_REMOTE_RX))
114                 phydev->link = true;
115         else
116                 phydev->link = false;
117
118         return 0;
119 }
120
121 static int mv88q2xxx_read_link(struct phy_device *phydev)
122 {
123         int ret;
124
125         /* The 88Q2XXX PHYs do not have the PMA/PMD status register available,
126          * therefore we need to read the link status from the vendor specific
127          * registers depending on the speed.
128          */
129         if (phydev->speed == SPEED_1000)
130                 ret = mv88q2xxx_read_link_gbit(phydev);
131         else
132                 ret = mv88q2xxx_read_link_100m(phydev);
133
134         return ret;
135 }
136
137 static int mv88q2xxx_read_status(struct phy_device *phydev)
138 {
139         int ret;
140
141         ret = mv88q2xxx_read_link(phydev);
142         if (ret < 0)
143                 return ret;
144
145         return genphy_c45_read_pma(phydev);
146 }
147
148 static int mv88q2xxx_get_features(struct phy_device *phydev)
149 {
150         int ret;
151
152         ret = genphy_c45_pma_read_abilities(phydev);
153         if (ret)
154                 return ret;
155
156         /* We need to read the baset1 extended abilities manually because the
157          * PHY does not signalize it has the extended abilities register
158          * available.
159          */
160         ret = genphy_c45_pma_baset1_read_abilities(phydev);
161         if (ret)
162                 return ret;
163
164         /* The PHY signalizes it supports autonegotiation. Unfortunately, so
165          * far it was not possible to get a link even when following the init
166          * sequence provided by Marvell. Disable it for now until a proper
167          * workaround is found or a new PHY revision is released.
168          */
169         linkmode_clear_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, phydev->supported);
170
171         return 0;
172 }
173
174 static int mv88q2xxx_config_aneg(struct phy_device *phydev)
175 {
176         int ret;
177
178         ret = genphy_c45_config_aneg(phydev);
179         if (ret)
180                 return ret;
181
182         return mv88q2xxx_soft_reset(phydev);
183 }
184
185 static int mv88q2xxx_config_init(struct phy_device *phydev)
186 {
187         int ret;
188
189         /* The 88Q2XXX PHYs do have the extended ability register available, but
190          * register MDIO_PMA_EXTABLE where they should signalize it does not
191          * work according to specification. Therefore, we force it here.
192          */
193         phydev->pma_extable = MDIO_PMA_EXTABLE_BT1;
194
195         /* Read the current PHY configuration */
196         ret = genphy_c45_read_pma(phydev);
197         if (ret)
198                 return ret;
199
200         return mv88q2xxx_config_aneg(phydev);
201 }
202
203 static int mv88q2xxxx_get_sqi(struct phy_device *phydev)
204 {
205         int ret;
206
207         if (phydev->speed == SPEED_100) {
208                 /* Read the SQI from the vendor specific receiver status
209                  * register
210                  */
211                 ret = phy_read_mmd(phydev, MDIO_MMD_PCS, 0x8230);
212                 if (ret < 0)
213                         return ret;
214
215                 ret = ret >> 12;
216         } else {
217                 /* Read from vendor specific registers, they are not documented
218                  * but can be found in the Software Initialization Guide. Only
219                  * revisions >= A0 are supported.
220                  */
221                 ret = phy_modify_mmd(phydev, MDIO_MMD_PCS, 0xFC5D, 0x00FF, 0x00AC);
222                 if (ret < 0)
223                         return ret;
224
225                 ret = phy_read_mmd(phydev, MDIO_MMD_PCS, 0xfc88);
226                 if (ret < 0)
227                         return ret;
228         }
229
230         return ret & 0x0F;
231 }
232
233 static int mv88q2xxxx_get_sqi_max(struct phy_device *phydev)
234 {
235         return 15;
236 }
237
238 static struct phy_driver mv88q2xxx_driver[] = {
239         {
240                 .phy_id                 = MARVELL_PHY_ID_88Q2110,
241                 .phy_id_mask            = MARVELL_PHY_ID_MASK,
242                 .name                   = "mv88q2110",
243                 .get_features           = mv88q2xxx_get_features,
244                 .config_aneg            = mv88q2xxx_config_aneg,
245                 .config_init            = mv88q2xxx_config_init,
246                 .read_status            = mv88q2xxx_read_status,
247                 .soft_reset             = mv88q2xxx_soft_reset,
248                 .set_loopback           = genphy_c45_loopback,
249                 .get_sqi                = mv88q2xxxx_get_sqi,
250                 .get_sqi_max            = mv88q2xxxx_get_sqi_max,
251         },
252 };
253
254 module_phy_driver(mv88q2xxx_driver);
255
256 static struct mdio_device_id __maybe_unused mv88q2xxx_tbl[] = {
257         { MARVELL_PHY_ID_88Q2110, MARVELL_PHY_ID_MASK },
258         { /*sentinel*/ }
259 };
260 MODULE_DEVICE_TABLE(mdio, mv88q2xxx_tbl);
261
262 MODULE_DESCRIPTION("Marvell 88Q2XXX 100/1000BASE-T1 Automotive Ethernet PHY driver");
263 MODULE_LICENSE("GPL");