Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0+
2 : : /*
3 : : * Copyright (C) 2015 Microchip Technology
4 : : */
5 : : #include <linux/kernel.h>
6 : : #include <linux/module.h>
7 : : #include <linux/mii.h>
8 : : #include <linux/ethtool.h>
9 : : #include <linux/phy.h>
10 : : #include <linux/microchipphy.h>
11 : : #include <linux/delay.h>
12 : : #include <linux/of.h>
13 : : #include <dt-bindings/net/microchip-lan78xx.h>
14 : :
15 : : #define DRIVER_AUTHOR "WOOJUNG HUH <woojung.huh@microchip.com>"
16 : : #define DRIVER_DESC "Microchip LAN88XX PHY driver"
17 : :
18 : : struct lan88xx_priv {
19 : : int chip_id;
20 : : int chip_rev;
21 : : __u32 wolopts;
22 : : };
23 : :
24 : 0 : static int lan88xx_read_page(struct phy_device *phydev)
25 : : {
26 : 0 : return __phy_read(phydev, LAN88XX_EXT_PAGE_ACCESS);
27 : : }
28 : :
29 : 0 : static int lan88xx_write_page(struct phy_device *phydev, int page)
30 : : {
31 : 0 : return __phy_write(phydev, LAN88XX_EXT_PAGE_ACCESS, page);
32 : : }
33 : :
34 : 0 : static int lan88xx_phy_config_intr(struct phy_device *phydev)
35 : : {
36 : : int rc;
37 : :
38 [ # # ]: 0 : if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
39 : : /* unmask all source and clear them before enable */
40 : : rc = phy_write(phydev, LAN88XX_INT_MASK, 0x7FFF);
41 : : rc = phy_read(phydev, LAN88XX_INT_STS);
42 : : rc = phy_write(phydev, LAN88XX_INT_MASK,
43 : : LAN88XX_INT_MASK_MDINTPIN_EN_ |
44 : : LAN88XX_INT_MASK_LINK_CHANGE_);
45 : : } else {
46 : : rc = phy_write(phydev, LAN88XX_INT_MASK, 0);
47 : : }
48 : :
49 : 0 : return rc < 0 ? rc : 0;
50 : : }
51 : :
52 : 0 : static int lan88xx_phy_ack_interrupt(struct phy_device *phydev)
53 : : {
54 : : int rc = phy_read(phydev, LAN88XX_INT_STS);
55 : :
56 : 0 : return rc < 0 ? rc : 0;
57 : : }
58 : :
59 : 0 : static int lan88xx_suspend(struct phy_device *phydev)
60 : : {
61 : 0 : struct lan88xx_priv *priv = phydev->priv;
62 : :
63 : : /* do not power down PHY when WOL is enabled */
64 [ # # ]: 0 : if (!priv->wolopts)
65 : 0 : genphy_suspend(phydev);
66 : :
67 : 0 : return 0;
68 : : }
69 : :
70 : 0 : static int lan88xx_TR_reg_set(struct phy_device *phydev, u16 regaddr,
71 : : u32 data)
72 : : {
73 : : int val, save_page, ret = 0;
74 : : u16 buf;
75 : :
76 : : /* Save current page */
77 : 0 : save_page = phy_save_page(phydev);
78 [ # # ]: 0 : if (save_page < 0) {
79 : 0 : phydev_warn(phydev, "Failed to get current page\n");
80 : 0 : goto err;
81 : : }
82 : :
83 : : /* Switch to TR page */
84 : : lan88xx_write_page(phydev, LAN88XX_EXT_PAGE_ACCESS_TR);
85 : :
86 : 0 : ret = __phy_write(phydev, LAN88XX_EXT_PAGE_TR_LOW_DATA,
87 : : (data & 0xFFFF));
88 [ # # ]: 0 : if (ret < 0) {
89 : 0 : phydev_warn(phydev, "Failed to write TR low data\n");
90 : 0 : goto err;
91 : : }
92 : :
93 : 0 : ret = __phy_write(phydev, LAN88XX_EXT_PAGE_TR_HIGH_DATA,
94 : 0 : (data & 0x00FF0000) >> 16);
95 [ # # ]: 0 : if (ret < 0) {
96 : 0 : phydev_warn(phydev, "Failed to write TR high data\n");
97 : 0 : goto err;
98 : : }
99 : :
100 : : /* Config control bits [15:13] of register */
101 : 0 : buf = (regaddr & ~(0x3 << 13));/* Clr [14:13] to write data in reg */
102 : 0 : buf |= 0x8000; /* Set [15] to Packet transmit */
103 : :
104 : : ret = __phy_write(phydev, LAN88XX_EXT_PAGE_TR_CR, buf);
105 [ # # ]: 0 : if (ret < 0) {
106 : 0 : phydev_warn(phydev, "Failed to write data in reg\n");
107 : 0 : goto err;
108 : : }
109 : :
110 : 0 : usleep_range(1000, 2000);/* Wait for Data to be written */
111 : : val = __phy_read(phydev, LAN88XX_EXT_PAGE_TR_CR);
112 [ # # ]: 0 : if (!(val & 0x8000))
113 : 0 : phydev_warn(phydev, "TR Register[0x%X] configuration failed\n",
114 : : regaddr);
115 : : err:
116 : 0 : return phy_restore_page(phydev, save_page, ret);
117 : : }
118 : :
119 : 0 : static void lan88xx_config_TR_regs(struct phy_device *phydev)
120 : : {
121 : : int err;
122 : :
123 : : /* Get access to Channel 0x1, Node 0xF , Register 0x01.
124 : : * Write 24-bit value 0x12B00A to register. Setting MrvlTrFix1000Kf,
125 : : * MrvlTrFix1000Kp, MasterEnableTR bits.
126 : : */
127 : 0 : err = lan88xx_TR_reg_set(phydev, 0x0F82, 0x12B00A);
128 [ # # ]: 0 : if (err < 0)
129 : 0 : phydev_warn(phydev, "Failed to Set Register[0x0F82]\n");
130 : :
131 : : /* Get access to Channel b'10, Node b'1101, Register 0x06.
132 : : * Write 24-bit value 0xD2C46F to register. Setting SSTrKf1000Slv,
133 : : * SSTrKp1000Mas bits.
134 : : */
135 : 0 : err = lan88xx_TR_reg_set(phydev, 0x168C, 0xD2C46F);
136 [ # # ]: 0 : if (err < 0)
137 : 0 : phydev_warn(phydev, "Failed to Set Register[0x168C]\n");
138 : :
139 : : /* Get access to Channel b'10, Node b'1111, Register 0x11.
140 : : * Write 24-bit value 0x620 to register. Setting rem_upd_done_thresh
141 : : * bits
142 : : */
143 : 0 : err = lan88xx_TR_reg_set(phydev, 0x17A2, 0x620);
144 [ # # ]: 0 : if (err < 0)
145 : 0 : phydev_warn(phydev, "Failed to Set Register[0x17A2]\n");
146 : :
147 : : /* Get access to Channel b'10, Node b'1101, Register 0x10.
148 : : * Write 24-bit value 0xEEFFDD to register. Setting
149 : : * eee_TrKp1Long_1000, eee_TrKp2Long_1000, eee_TrKp3Long_1000,
150 : : * eee_TrKp1Short_1000,eee_TrKp2Short_1000, eee_TrKp3Short_1000 bits.
151 : : */
152 : 0 : err = lan88xx_TR_reg_set(phydev, 0x16A0, 0xEEFFDD);
153 [ # # ]: 0 : if (err < 0)
154 : 0 : phydev_warn(phydev, "Failed to Set Register[0x16A0]\n");
155 : :
156 : : /* Get access to Channel b'10, Node b'1101, Register 0x13.
157 : : * Write 24-bit value 0x071448 to register. Setting
158 : : * slv_lpi_tr_tmr_val1, slv_lpi_tr_tmr_val2 bits.
159 : : */
160 : 0 : err = lan88xx_TR_reg_set(phydev, 0x16A6, 0x071448);
161 [ # # ]: 0 : if (err < 0)
162 : 0 : phydev_warn(phydev, "Failed to Set Register[0x16A6]\n");
163 : :
164 : : /* Get access to Channel b'10, Node b'1101, Register 0x12.
165 : : * Write 24-bit value 0x13132F to register. Setting
166 : : * slv_sigdet_timer_val1, slv_sigdet_timer_val2 bits.
167 : : */
168 : 0 : err = lan88xx_TR_reg_set(phydev, 0x16A4, 0x13132F);
169 [ # # ]: 0 : if (err < 0)
170 : 0 : phydev_warn(phydev, "Failed to Set Register[0x16A4]\n");
171 : :
172 : : /* Get access to Channel b'10, Node b'1101, Register 0x14.
173 : : * Write 24-bit value 0x0 to register. Setting eee_3level_delay,
174 : : * eee_TrKf_freeze_delay bits.
175 : : */
176 : 0 : err = lan88xx_TR_reg_set(phydev, 0x16A8, 0x0);
177 [ # # ]: 0 : if (err < 0)
178 : 0 : phydev_warn(phydev, "Failed to Set Register[0x16A8]\n");
179 : :
180 : : /* Get access to Channel b'01, Node b'1111, Register 0x34.
181 : : * Write 24-bit value 0x91B06C to register. Setting
182 : : * FastMseSearchThreshLong1000, FastMseSearchThreshShort1000,
183 : : * FastMseSearchUpdGain1000 bits.
184 : : */
185 : 0 : err = lan88xx_TR_reg_set(phydev, 0x0FE8, 0x91B06C);
186 [ # # ]: 0 : if (err < 0)
187 : 0 : phydev_warn(phydev, "Failed to Set Register[0x0FE8]\n");
188 : :
189 : : /* Get access to Channel b'01, Node b'1111, Register 0x3E.
190 : : * Write 24-bit value 0xC0A028 to register. Setting
191 : : * FastMseKp2ThreshLong1000, FastMseKp2ThreshShort1000,
192 : : * FastMseKp2UpdGain1000, FastMseKp2ExitEn1000 bits.
193 : : */
194 : 0 : err = lan88xx_TR_reg_set(phydev, 0x0FFC, 0xC0A028);
195 [ # # ]: 0 : if (err < 0)
196 : 0 : phydev_warn(phydev, "Failed to Set Register[0x0FFC]\n");
197 : :
198 : : /* Get access to Channel b'01, Node b'1111, Register 0x35.
199 : : * Write 24-bit value 0x041600 to register. Setting
200 : : * FastMseSearchPhShNum1000, FastMseSearchClksPerPh1000,
201 : : * FastMsePhChangeDelay1000 bits.
202 : : */
203 : 0 : err = lan88xx_TR_reg_set(phydev, 0x0FEA, 0x041600);
204 [ # # ]: 0 : if (err < 0)
205 : 0 : phydev_warn(phydev, "Failed to Set Register[0x0FEA]\n");
206 : :
207 : : /* Get access to Channel b'10, Node b'1101, Register 0x03.
208 : : * Write 24-bit value 0x000004 to register. Setting TrFreeze bits.
209 : : */
210 : 0 : err = lan88xx_TR_reg_set(phydev, 0x1686, 0x000004);
211 [ # # ]: 0 : if (err < 0)
212 : 0 : phydev_warn(phydev, "Failed to Set Register[0x1686]\n");
213 : 0 : }
214 : :
215 : 0 : static int lan88xx_probe(struct phy_device *phydev)
216 : : {
217 : 0 : struct device *dev = &phydev->mdio.dev;
218 : : struct lan88xx_priv *priv;
219 : : u32 led_modes[4];
220 : 0 : u32 downshift_after = 0;
221 : : int len;
222 : :
223 : : priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
224 [ # # ]: 0 : if (!priv)
225 : : return -ENOMEM;
226 : :
227 : 0 : priv->wolopts = 0;
228 : :
229 : 0 : len = of_property_read_variable_u32_array(dev->of_node,
230 : : "microchip,led-modes",
231 : : led_modes,
232 : : 0,
233 : : ARRAY_SIZE(led_modes));
234 [ # # ]: 0 : if (len >= 0) {
235 : : u32 reg = 0;
236 : : int i;
237 : :
238 [ # # ]: 0 : for (i = 0; i < len; i++) {
239 [ # # ]: 0 : if (led_modes[i] > 15)
240 : : return -EINVAL;
241 : 0 : reg |= led_modes[i] << (i * 4);
242 : : }
243 [ # # ]: 0 : for (; i < ARRAY_SIZE(led_modes); i++)
244 : 0 : reg |= LAN78XX_FORCE_LED_OFF << (i * 4);
245 : 0 : (void)phy_write(phydev, LAN78XX_PHY_LED_MODE_SELECT, reg);
246 [ # # ]: 0 : } else if (len == -EOVERFLOW) {
247 : : return -EINVAL;
248 : : }
249 : :
250 [ # # ]: 0 : if (!of_property_read_u32(dev->of_node,
251 : : "microchip,downshift-after",
252 : : &downshift_after)) {
253 : : u32 mask = LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_MASK;
254 : : u32 val= LAN78XX_PHY_CTRL3_AUTO_DOWNSHIFT;
255 : :
256 [ # # # # : 0 : switch (downshift_after) {
# # ]
257 : : case 2: val |= LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_2;
258 : : break;
259 : : case 3: val |= LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_3;
260 : 0 : break;
261 : : case 4: val |= LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_4;
262 : 0 : break;
263 : : case 5: val |= LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_5;
264 : 0 : break;
265 : : case 0: // Disable completely
266 : : mask = LAN78XX_PHY_CTRL3_AUTO_DOWNSHIFT;
267 : : val = 0;
268 : 0 : break;
269 : : default:
270 : : return -EINVAL;
271 : : }
272 : 0 : (void)phy_modify_paged(phydev, 1, LAN78XX_PHY_CTRL3,
273 : : mask, val);
274 : : }
275 : :
276 : : /* these values can be used to identify internal PHY */
277 : 0 : priv->chip_id = phy_read_mmd(phydev, 3, LAN88XX_MMD3_CHIP_ID);
278 : 0 : priv->chip_rev = phy_read_mmd(phydev, 3, LAN88XX_MMD3_CHIP_REV);
279 : :
280 : 0 : phydev->priv = priv;
281 : :
282 : 0 : return 0;
283 : : }
284 : :
285 : 0 : static void lan88xx_remove(struct phy_device *phydev)
286 : : {
287 : 0 : struct device *dev = &phydev->mdio.dev;
288 : 0 : struct lan88xx_priv *priv = phydev->priv;
289 : :
290 [ # # ]: 0 : if (priv)
291 : 0 : devm_kfree(dev, priv);
292 : 0 : }
293 : :
294 : 0 : static int lan88xx_set_wol(struct phy_device *phydev,
295 : : struct ethtool_wolinfo *wol)
296 : : {
297 : 0 : struct lan88xx_priv *priv = phydev->priv;
298 : :
299 : 0 : priv->wolopts = wol->wolopts;
300 : :
301 : 0 : return 0;
302 : : }
303 : :
304 : 0 : static void lan88xx_set_mdix(struct phy_device *phydev)
305 : : {
306 : : int buf;
307 : : int val;
308 : :
309 [ # # # # ]: 0 : switch (phydev->mdix_ctrl) {
310 : : case ETH_TP_MDI:
311 : : val = LAN88XX_EXT_MODE_CTRL_MDI_;
312 : : break;
313 : : case ETH_TP_MDI_X:
314 : : val = LAN88XX_EXT_MODE_CTRL_MDI_X_;
315 : 0 : break;
316 : : case ETH_TP_MDI_AUTO:
317 : : val = LAN88XX_EXT_MODE_CTRL_AUTO_MDIX_;
318 : 0 : break;
319 : : default:
320 : 0 : return;
321 : : }
322 : :
323 : : phy_write(phydev, LAN88XX_EXT_PAGE_ACCESS, LAN88XX_EXT_PAGE_SPACE_1);
324 : : buf = phy_read(phydev, LAN88XX_EXT_MODE_CTRL);
325 : 0 : buf &= ~LAN88XX_EXT_MODE_CTRL_MDIX_MASK_;
326 : 0 : buf |= val;
327 : 0 : phy_write(phydev, LAN88XX_EXT_MODE_CTRL, buf);
328 : : phy_write(phydev, LAN88XX_EXT_PAGE_ACCESS, LAN88XX_EXT_PAGE_SPACE_0);
329 : : }
330 : :
331 : 0 : static int lan88xx_config_init(struct phy_device *phydev)
332 : : {
333 : : int val;
334 : :
335 : : /*Zerodetect delay enable */
336 : 0 : val = phy_read_mmd(phydev, MDIO_MMD_PCS,
337 : : PHY_ARDENNES_MMD_DEV_3_PHY_CFG);
338 : 0 : val |= PHY_ARDENNES_MMD_DEV_3_PHY_CFG_ZD_DLY_EN_;
339 : :
340 : 0 : phy_write_mmd(phydev, MDIO_MMD_PCS, PHY_ARDENNES_MMD_DEV_3_PHY_CFG,
341 : : val);
342 : :
343 : : /* Config DSP registers */
344 : 0 : lan88xx_config_TR_regs(phydev);
345 : :
346 : 0 : return 0;
347 : : }
348 : :
349 : 0 : static int lan88xx_config_aneg(struct phy_device *phydev)
350 : : {
351 : 0 : lan88xx_set_mdix(phydev);
352 : :
353 : 0 : return genphy_config_aneg(phydev);
354 : : }
355 : :
356 : : static struct phy_driver microchip_phy_driver[] = {
357 : : {
358 : : .phy_id = 0x0007c130,
359 : : .phy_id_mask = 0xfffffff0,
360 : : .name = "Microchip LAN88xx",
361 : :
362 : : /* PHY_GBIT_FEATURES */
363 : :
364 : : .probe = lan88xx_probe,
365 : : .remove = lan88xx_remove,
366 : :
367 : : .config_init = lan88xx_config_init,
368 : : .config_aneg = lan88xx_config_aneg,
369 : :
370 : : .ack_interrupt = lan88xx_phy_ack_interrupt,
371 : : .config_intr = lan88xx_phy_config_intr,
372 : :
373 : : .suspend = lan88xx_suspend,
374 : : .resume = genphy_resume,
375 : : .set_wol = lan88xx_set_wol,
376 : : .read_page = lan88xx_read_page,
377 : : .write_page = lan88xx_write_page,
378 : : } };
379 : :
380 : 404 : module_phy_driver(microchip_phy_driver);
381 : :
382 : : static struct mdio_device_id __maybe_unused microchip_tbl[] = {
383 : : { 0x0007c130, 0xfffffff0 },
384 : : { }
385 : : };
386 : :
387 : : MODULE_DEVICE_TABLE(mdio, microchip_tbl);
388 : :
389 : : MODULE_AUTHOR(DRIVER_AUTHOR);
390 : : MODULE_DESCRIPTION(DRIVER_DESC);
391 : : MODULE_LICENSE("GPL");
|