.. | .. |
---|
1 | | -/* |
---|
2 | | - * drivers/net/phy/realtek.c |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0+ |
---|
| 2 | +/* drivers/net/phy/realtek.c |
---|
3 | 3 | * |
---|
4 | 4 | * Driver for Realtek PHYs |
---|
5 | 5 | * |
---|
6 | 6 | * Author: Johnson Leung <r58129@freescale.com> |
---|
7 | 7 | * |
---|
8 | 8 | * Copyright (c) 2004 Freescale Semiconductor, Inc. |
---|
9 | | - * |
---|
10 | | - * This program is free software; you can redistribute it and/or modify it |
---|
11 | | - * under the terms of the GNU General Public License as published by the |
---|
12 | | - * Free Software Foundation; either version 2 of the License, or (at your |
---|
13 | | - * option) any later version. |
---|
14 | | - * |
---|
15 | 9 | */ |
---|
16 | 10 | #include <linux/bitops.h> |
---|
17 | 11 | #include <linux/phy.h> |
---|
18 | 12 | #include <linux/module.h> |
---|
| 13 | +#include <linux/delay.h> |
---|
19 | 14 | |
---|
20 | 15 | #define RTL821x_PHYSR 0x11 |
---|
21 | 16 | #define RTL821x_PHYSR_DUPLEX BIT(13) |
---|
.. | .. |
---|
28 | 23 | |
---|
29 | 24 | #define RTL821x_INSR 0x13 |
---|
30 | 25 | |
---|
| 26 | +#define RTL821x_EXT_PAGE_SELECT 0x1e |
---|
31 | 27 | #define RTL821x_PAGE_SELECT 0x1f |
---|
32 | 28 | |
---|
| 29 | +#define RTL8211F_PHYCR1 0x18 |
---|
33 | 30 | #define RTL8211F_INSR 0x1d |
---|
34 | 31 | |
---|
35 | 32 | #define RTL8211F_TX_DELAY BIT(8) |
---|
| 33 | +#define RTL8211F_RX_DELAY BIT(3) |
---|
| 34 | + |
---|
| 35 | +#define RTL8211F_ALDPS_PLL_OFF BIT(1) |
---|
| 36 | +#define RTL8211F_ALDPS_ENABLE BIT(2) |
---|
| 37 | +#define RTL8211F_ALDPS_XTAL_OFF BIT(12) |
---|
| 38 | + |
---|
| 39 | +#define RTL8211E_CTRL_DELAY BIT(13) |
---|
| 40 | +#define RTL8211E_TX_DELAY BIT(12) |
---|
| 41 | +#define RTL8211E_RX_DELAY BIT(11) |
---|
36 | 42 | |
---|
37 | 43 | #define RTL8201F_ISR 0x1e |
---|
38 | 44 | #define RTL8201F_IER 0x13 |
---|
39 | 45 | |
---|
40 | 46 | #define RTL8366RB_POWER_SAVE 0x15 |
---|
41 | 47 | #define RTL8366RB_POWER_SAVE_ON BIT(12) |
---|
| 48 | + |
---|
| 49 | +#define RTL_SUPPORTS_5000FULL BIT(14) |
---|
| 50 | +#define RTL_SUPPORTS_2500FULL BIT(13) |
---|
| 51 | +#define RTL_SUPPORTS_10000FULL BIT(0) |
---|
| 52 | +#define RTL_ADV_2500FULL BIT(7) |
---|
| 53 | +#define RTL_LPADV_10000FULL BIT(11) |
---|
| 54 | +#define RTL_LPADV_5000FULL BIT(6) |
---|
| 55 | +#define RTL_LPADV_2500FULL BIT(5) |
---|
| 56 | + |
---|
| 57 | +#define RTLGEN_SPEED_MASK 0x0630 |
---|
| 58 | + |
---|
| 59 | +#define RTL_GENERIC_PHYID 0x001cc800 |
---|
42 | 60 | |
---|
43 | 61 | MODULE_DESCRIPTION("Realtek PHY driver"); |
---|
44 | 62 | MODULE_AUTHOR("Johnson Leung"); |
---|
.. | .. |
---|
156 | 174 | static int rtl8211c_config_init(struct phy_device *phydev) |
---|
157 | 175 | { |
---|
158 | 176 | /* RTL8211C has an issue when operating in Gigabit slave mode */ |
---|
159 | | - phy_set_bits(phydev, MII_CTRL1000, |
---|
160 | | - CTL1000_ENABLE_MASTER | CTL1000_AS_MASTER); |
---|
161 | | - |
---|
162 | | - return genphy_config_init(phydev); |
---|
| 177 | + return phy_set_bits(phydev, MII_CTRL1000, |
---|
| 178 | + CTL1000_ENABLE_MASTER | CTL1000_AS_MASTER); |
---|
163 | 179 | } |
---|
164 | 180 | |
---|
165 | 181 | static int rtl8211f_config_init(struct phy_device *phydev) |
---|
166 | 182 | { |
---|
| 183 | + struct device *dev = &phydev->mdio.dev; |
---|
| 184 | + u16 val_txdly, val_rxdly; |
---|
| 185 | + u16 val; |
---|
167 | 186 | int ret; |
---|
168 | | - u16 val = 0; |
---|
169 | 187 | |
---|
170 | | - ret = genphy_config_init(phydev); |
---|
| 188 | + val = RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_XTAL_OFF; |
---|
| 189 | + phy_modify_paged_changed(phydev, 0xa43, RTL8211F_PHYCR1, val, val); |
---|
| 190 | + |
---|
| 191 | + switch (phydev->interface) { |
---|
| 192 | + case PHY_INTERFACE_MODE_RGMII: |
---|
| 193 | + val_txdly = 0; |
---|
| 194 | + val_rxdly = 0; |
---|
| 195 | + break; |
---|
| 196 | + |
---|
| 197 | + case PHY_INTERFACE_MODE_RGMII_RXID: |
---|
| 198 | + val_txdly = 0; |
---|
| 199 | + val_rxdly = RTL8211F_RX_DELAY; |
---|
| 200 | + break; |
---|
| 201 | + |
---|
| 202 | + case PHY_INTERFACE_MODE_RGMII_TXID: |
---|
| 203 | + val_txdly = RTL8211F_TX_DELAY; |
---|
| 204 | + val_rxdly = 0; |
---|
| 205 | + break; |
---|
| 206 | + |
---|
| 207 | + case PHY_INTERFACE_MODE_RGMII_ID: |
---|
| 208 | + val_txdly = RTL8211F_TX_DELAY; |
---|
| 209 | + val_rxdly = RTL8211F_RX_DELAY; |
---|
| 210 | + break; |
---|
| 211 | + |
---|
| 212 | + default: /* the rest of the modes imply leaving delay as is. */ |
---|
| 213 | + return 0; |
---|
| 214 | + } |
---|
| 215 | + |
---|
| 216 | + ret = phy_modify_paged_changed(phydev, 0xd08, 0x11, RTL8211F_TX_DELAY, |
---|
| 217 | + val_txdly); |
---|
| 218 | + if (ret < 0) { |
---|
| 219 | + dev_err(dev, "Failed to update the TX delay register\n"); |
---|
| 220 | + return ret; |
---|
| 221 | + } else if (ret) { |
---|
| 222 | + dev_dbg(dev, |
---|
| 223 | + "%s 2ns TX delay (and changing the value from pin-strapping RXD1 or the bootloader)\n", |
---|
| 224 | + val_txdly ? "Enabling" : "Disabling"); |
---|
| 225 | + } else { |
---|
| 226 | + dev_dbg(dev, |
---|
| 227 | + "2ns TX delay was already %s (by pin-strapping RXD1 or bootloader configuration)\n", |
---|
| 228 | + val_txdly ? "enabled" : "disabled"); |
---|
| 229 | + } |
---|
| 230 | + |
---|
| 231 | + ret = phy_modify_paged_changed(phydev, 0xd08, 0x15, RTL8211F_RX_DELAY, |
---|
| 232 | + val_rxdly); |
---|
| 233 | + if (ret < 0) { |
---|
| 234 | + dev_err(dev, "Failed to update the RX delay register\n"); |
---|
| 235 | + return ret; |
---|
| 236 | + } else if (ret) { |
---|
| 237 | + dev_dbg(dev, |
---|
| 238 | + "%s 2ns RX delay (and changing the value from pin-strapping RXD0 or the bootloader)\n", |
---|
| 239 | + val_rxdly ? "Enabling" : "Disabling"); |
---|
| 240 | + } else { |
---|
| 241 | + dev_dbg(dev, |
---|
| 242 | + "2ns RX delay was already %s (by pin-strapping RXD0 or bootloader configuration)\n", |
---|
| 243 | + val_rxdly ? "enabled" : "disabled"); |
---|
| 244 | + } |
---|
| 245 | + |
---|
| 246 | + return 0; |
---|
| 247 | +} |
---|
| 248 | + |
---|
| 249 | +static int rtl821x_resume(struct phy_device *phydev) |
---|
| 250 | +{ |
---|
| 251 | + int ret; |
---|
| 252 | + |
---|
| 253 | + ret = genphy_resume(phydev); |
---|
171 | 254 | if (ret < 0) |
---|
172 | 255 | return ret; |
---|
173 | 256 | |
---|
174 | | - /* enable TX-delay for rgmii-id and rgmii-txid, otherwise disable it */ |
---|
175 | | - if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID || |
---|
176 | | - phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) |
---|
177 | | - val = RTL8211F_TX_DELAY; |
---|
| 257 | + msleep(20); |
---|
178 | 258 | |
---|
179 | | - return phy_modify_paged(phydev, 0xd08, 0x11, RTL8211F_TX_DELAY, val); |
---|
| 259 | + return 0; |
---|
| 260 | +} |
---|
| 261 | + |
---|
| 262 | +static int rtl8211e_config_init(struct phy_device *phydev) |
---|
| 263 | +{ |
---|
| 264 | + int ret = 0, oldpage; |
---|
| 265 | + u16 val; |
---|
| 266 | + |
---|
| 267 | + /* enable TX/RX delay for rgmii-* modes, and disable them for rgmii. */ |
---|
| 268 | + switch (phydev->interface) { |
---|
| 269 | + case PHY_INTERFACE_MODE_RGMII: |
---|
| 270 | + val = RTL8211E_CTRL_DELAY | 0; |
---|
| 271 | + break; |
---|
| 272 | + case PHY_INTERFACE_MODE_RGMII_ID: |
---|
| 273 | + val = RTL8211E_CTRL_DELAY | RTL8211E_TX_DELAY | RTL8211E_RX_DELAY; |
---|
| 274 | + break; |
---|
| 275 | + case PHY_INTERFACE_MODE_RGMII_RXID: |
---|
| 276 | + val = RTL8211E_CTRL_DELAY | RTL8211E_RX_DELAY; |
---|
| 277 | + break; |
---|
| 278 | + case PHY_INTERFACE_MODE_RGMII_TXID: |
---|
| 279 | + val = RTL8211E_CTRL_DELAY | RTL8211E_TX_DELAY; |
---|
| 280 | + break; |
---|
| 281 | + default: /* the rest of the modes imply leaving delays as is. */ |
---|
| 282 | + return 0; |
---|
| 283 | + } |
---|
| 284 | + |
---|
| 285 | + /* According to a sample driver there is a 0x1c config register on the |
---|
| 286 | + * 0xa4 extension page (0x7) layout. It can be used to disable/enable |
---|
| 287 | + * the RX/TX delays otherwise controlled by RXDLY/TXDLY pins. |
---|
| 288 | + * The configuration register definition: |
---|
| 289 | + * 14 = reserved |
---|
| 290 | + * 13 = Force Tx RX Delay controlled by bit12 bit11, |
---|
| 291 | + * 12 = RX Delay, 11 = TX Delay |
---|
| 292 | + * 10:0 = Test && debug settings reserved by realtek |
---|
| 293 | + */ |
---|
| 294 | + oldpage = phy_select_page(phydev, 0x7); |
---|
| 295 | + if (oldpage < 0) |
---|
| 296 | + goto err_restore_page; |
---|
| 297 | + |
---|
| 298 | + ret = __phy_write(phydev, RTL821x_EXT_PAGE_SELECT, 0xa4); |
---|
| 299 | + if (ret) |
---|
| 300 | + goto err_restore_page; |
---|
| 301 | + |
---|
| 302 | + ret = __phy_modify(phydev, 0x1c, RTL8211E_CTRL_DELAY |
---|
| 303 | + | RTL8211E_TX_DELAY | RTL8211E_RX_DELAY, |
---|
| 304 | + val); |
---|
| 305 | + |
---|
| 306 | +err_restore_page: |
---|
| 307 | + return phy_restore_page(phydev, oldpage, ret); |
---|
180 | 308 | } |
---|
181 | 309 | |
---|
182 | 310 | static int rtl8211b_suspend(struct phy_device *phydev) |
---|
.. | .. |
---|
197 | 325 | { |
---|
198 | 326 | int ret; |
---|
199 | 327 | |
---|
200 | | - ret = genphy_config_init(phydev); |
---|
201 | | - if (ret < 0) |
---|
202 | | - return ret; |
---|
203 | | - |
---|
204 | 328 | ret = phy_set_bits(phydev, RTL8366RB_POWER_SAVE, |
---|
205 | 329 | RTL8366RB_POWER_SAVE_ON); |
---|
206 | 330 | if (ret) { |
---|
.. | .. |
---|
211 | 335 | return ret; |
---|
212 | 336 | } |
---|
213 | 337 | |
---|
| 338 | +/* get actual speed to cover the downshift case */ |
---|
| 339 | +static int rtlgen_get_speed(struct phy_device *phydev) |
---|
| 340 | +{ |
---|
| 341 | + int val; |
---|
| 342 | + |
---|
| 343 | + if (!phydev->link) |
---|
| 344 | + return 0; |
---|
| 345 | + |
---|
| 346 | + val = phy_read_paged(phydev, 0xa43, 0x12); |
---|
| 347 | + if (val < 0) |
---|
| 348 | + return val; |
---|
| 349 | + |
---|
| 350 | + switch (val & RTLGEN_SPEED_MASK) { |
---|
| 351 | + case 0x0000: |
---|
| 352 | + phydev->speed = SPEED_10; |
---|
| 353 | + break; |
---|
| 354 | + case 0x0010: |
---|
| 355 | + phydev->speed = SPEED_100; |
---|
| 356 | + break; |
---|
| 357 | + case 0x0020: |
---|
| 358 | + phydev->speed = SPEED_1000; |
---|
| 359 | + break; |
---|
| 360 | + case 0x0200: |
---|
| 361 | + phydev->speed = SPEED_10000; |
---|
| 362 | + break; |
---|
| 363 | + case 0x0210: |
---|
| 364 | + phydev->speed = SPEED_2500; |
---|
| 365 | + break; |
---|
| 366 | + case 0x0220: |
---|
| 367 | + phydev->speed = SPEED_5000; |
---|
| 368 | + break; |
---|
| 369 | + default: |
---|
| 370 | + break; |
---|
| 371 | + } |
---|
| 372 | + |
---|
| 373 | + return 0; |
---|
| 374 | +} |
---|
| 375 | + |
---|
| 376 | +static int rtlgen_read_status(struct phy_device *phydev) |
---|
| 377 | +{ |
---|
| 378 | + int ret; |
---|
| 379 | + |
---|
| 380 | + ret = genphy_read_status(phydev); |
---|
| 381 | + if (ret < 0) |
---|
| 382 | + return ret; |
---|
| 383 | + |
---|
| 384 | + return rtlgen_get_speed(phydev); |
---|
| 385 | +} |
---|
| 386 | + |
---|
| 387 | +static int rtlgen_read_mmd(struct phy_device *phydev, int devnum, u16 regnum) |
---|
| 388 | +{ |
---|
| 389 | + int ret; |
---|
| 390 | + |
---|
| 391 | + if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE) { |
---|
| 392 | + rtl821x_write_page(phydev, 0xa5c); |
---|
| 393 | + ret = __phy_read(phydev, 0x12); |
---|
| 394 | + rtl821x_write_page(phydev, 0); |
---|
| 395 | + } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) { |
---|
| 396 | + rtl821x_write_page(phydev, 0xa5d); |
---|
| 397 | + ret = __phy_read(phydev, 0x10); |
---|
| 398 | + rtl821x_write_page(phydev, 0); |
---|
| 399 | + } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_LPABLE) { |
---|
| 400 | + rtl821x_write_page(phydev, 0xa5d); |
---|
| 401 | + ret = __phy_read(phydev, 0x11); |
---|
| 402 | + rtl821x_write_page(phydev, 0); |
---|
| 403 | + } else { |
---|
| 404 | + ret = -EOPNOTSUPP; |
---|
| 405 | + } |
---|
| 406 | + |
---|
| 407 | + return ret; |
---|
| 408 | +} |
---|
| 409 | + |
---|
| 410 | +static int rtlgen_write_mmd(struct phy_device *phydev, int devnum, u16 regnum, |
---|
| 411 | + u16 val) |
---|
| 412 | +{ |
---|
| 413 | + int ret; |
---|
| 414 | + |
---|
| 415 | + if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) { |
---|
| 416 | + rtl821x_write_page(phydev, 0xa5d); |
---|
| 417 | + ret = __phy_write(phydev, 0x10, val); |
---|
| 418 | + rtl821x_write_page(phydev, 0); |
---|
| 419 | + } else { |
---|
| 420 | + ret = -EOPNOTSUPP; |
---|
| 421 | + } |
---|
| 422 | + |
---|
| 423 | + return ret; |
---|
| 424 | +} |
---|
| 425 | + |
---|
| 426 | +static int rtl822x_read_mmd(struct phy_device *phydev, int devnum, u16 regnum) |
---|
| 427 | +{ |
---|
| 428 | + int ret = rtlgen_read_mmd(phydev, devnum, regnum); |
---|
| 429 | + |
---|
| 430 | + if (ret != -EOPNOTSUPP) |
---|
| 431 | + return ret; |
---|
| 432 | + |
---|
| 433 | + if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE2) { |
---|
| 434 | + rtl821x_write_page(phydev, 0xa6e); |
---|
| 435 | + ret = __phy_read(phydev, 0x16); |
---|
| 436 | + rtl821x_write_page(phydev, 0); |
---|
| 437 | + } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV2) { |
---|
| 438 | + rtl821x_write_page(phydev, 0xa6d); |
---|
| 439 | + ret = __phy_read(phydev, 0x12); |
---|
| 440 | + rtl821x_write_page(phydev, 0); |
---|
| 441 | + } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_LPABLE2) { |
---|
| 442 | + rtl821x_write_page(phydev, 0xa6d); |
---|
| 443 | + ret = __phy_read(phydev, 0x10); |
---|
| 444 | + rtl821x_write_page(phydev, 0); |
---|
| 445 | + } |
---|
| 446 | + |
---|
| 447 | + return ret; |
---|
| 448 | +} |
---|
| 449 | + |
---|
| 450 | +static int rtl822x_write_mmd(struct phy_device *phydev, int devnum, u16 regnum, |
---|
| 451 | + u16 val) |
---|
| 452 | +{ |
---|
| 453 | + int ret = rtlgen_write_mmd(phydev, devnum, regnum, val); |
---|
| 454 | + |
---|
| 455 | + if (ret != -EOPNOTSUPP) |
---|
| 456 | + return ret; |
---|
| 457 | + |
---|
| 458 | + if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV2) { |
---|
| 459 | + rtl821x_write_page(phydev, 0xa6d); |
---|
| 460 | + ret = __phy_write(phydev, 0x12, val); |
---|
| 461 | + rtl821x_write_page(phydev, 0); |
---|
| 462 | + } |
---|
| 463 | + |
---|
| 464 | + return ret; |
---|
| 465 | +} |
---|
| 466 | + |
---|
| 467 | +static int rtl822x_get_features(struct phy_device *phydev) |
---|
| 468 | +{ |
---|
| 469 | + int val; |
---|
| 470 | + |
---|
| 471 | + val = phy_read_paged(phydev, 0xa61, 0x13); |
---|
| 472 | + if (val < 0) |
---|
| 473 | + return val; |
---|
| 474 | + |
---|
| 475 | + linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, |
---|
| 476 | + phydev->supported, val & RTL_SUPPORTS_2500FULL); |
---|
| 477 | + linkmode_mod_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT, |
---|
| 478 | + phydev->supported, val & RTL_SUPPORTS_5000FULL); |
---|
| 479 | + linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT, |
---|
| 480 | + phydev->supported, val & RTL_SUPPORTS_10000FULL); |
---|
| 481 | + |
---|
| 482 | + return genphy_read_abilities(phydev); |
---|
| 483 | +} |
---|
| 484 | + |
---|
| 485 | +static int rtl822x_config_aneg(struct phy_device *phydev) |
---|
| 486 | +{ |
---|
| 487 | + int ret = 0; |
---|
| 488 | + |
---|
| 489 | + if (phydev->autoneg == AUTONEG_ENABLE) { |
---|
| 490 | + u16 adv2500 = 0; |
---|
| 491 | + |
---|
| 492 | + if (linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, |
---|
| 493 | + phydev->advertising)) |
---|
| 494 | + adv2500 = RTL_ADV_2500FULL; |
---|
| 495 | + |
---|
| 496 | + ret = phy_modify_paged_changed(phydev, 0xa5d, 0x12, |
---|
| 497 | + RTL_ADV_2500FULL, adv2500); |
---|
| 498 | + if (ret < 0) |
---|
| 499 | + return ret; |
---|
| 500 | + } |
---|
| 501 | + |
---|
| 502 | + return __genphy_config_aneg(phydev, ret); |
---|
| 503 | +} |
---|
| 504 | + |
---|
| 505 | +static int rtl822x_read_status(struct phy_device *phydev) |
---|
| 506 | +{ |
---|
| 507 | + int ret; |
---|
| 508 | + |
---|
| 509 | + if (phydev->autoneg == AUTONEG_ENABLE) { |
---|
| 510 | + int lpadv = phy_read_paged(phydev, 0xa5d, 0x13); |
---|
| 511 | + |
---|
| 512 | + if (lpadv < 0) |
---|
| 513 | + return lpadv; |
---|
| 514 | + |
---|
| 515 | + linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT, |
---|
| 516 | + phydev->lp_advertising, lpadv & RTL_LPADV_10000FULL); |
---|
| 517 | + linkmode_mod_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT, |
---|
| 518 | + phydev->lp_advertising, lpadv & RTL_LPADV_5000FULL); |
---|
| 519 | + linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, |
---|
| 520 | + phydev->lp_advertising, lpadv & RTL_LPADV_2500FULL); |
---|
| 521 | + } |
---|
| 522 | + |
---|
| 523 | + ret = genphy_read_status(phydev); |
---|
| 524 | + if (ret < 0) |
---|
| 525 | + return ret; |
---|
| 526 | + |
---|
| 527 | + return rtlgen_get_speed(phydev); |
---|
| 528 | +} |
---|
| 529 | + |
---|
| 530 | +static bool rtlgen_supports_2_5gbps(struct phy_device *phydev) |
---|
| 531 | +{ |
---|
| 532 | + int val; |
---|
| 533 | + |
---|
| 534 | + phy_write(phydev, RTL821x_PAGE_SELECT, 0xa61); |
---|
| 535 | + val = phy_read(phydev, 0x13); |
---|
| 536 | + phy_write(phydev, RTL821x_PAGE_SELECT, 0); |
---|
| 537 | + |
---|
| 538 | + return val >= 0 && val & RTL_SUPPORTS_2500FULL; |
---|
| 539 | +} |
---|
| 540 | + |
---|
| 541 | +static int rtlgen_match_phy_device(struct phy_device *phydev) |
---|
| 542 | +{ |
---|
| 543 | + return phydev->phy_id == RTL_GENERIC_PHYID && |
---|
| 544 | + !rtlgen_supports_2_5gbps(phydev); |
---|
| 545 | +} |
---|
| 546 | + |
---|
| 547 | +static int rtl8226_match_phy_device(struct phy_device *phydev) |
---|
| 548 | +{ |
---|
| 549 | + return phydev->phy_id == RTL_GENERIC_PHYID && |
---|
| 550 | + rtlgen_supports_2_5gbps(phydev); |
---|
| 551 | +} |
---|
| 552 | + |
---|
| 553 | +static int rtlgen_resume(struct phy_device *phydev) |
---|
| 554 | +{ |
---|
| 555 | + int ret = genphy_resume(phydev); |
---|
| 556 | + |
---|
| 557 | + /* Internal PHY's from RTL8168h up may not be instantly ready */ |
---|
| 558 | + msleep(20); |
---|
| 559 | + |
---|
| 560 | + return ret; |
---|
| 561 | +} |
---|
| 562 | + |
---|
| 563 | +static int rtl9010a_config_init(struct phy_device *phydev) |
---|
| 564 | +{ |
---|
| 565 | + phydev->autoneg = AUTONEG_DISABLE; |
---|
| 566 | + phydev->speed = SPEED_1000; |
---|
| 567 | + phydev->duplex = DUPLEX_FULL; |
---|
| 568 | + |
---|
| 569 | + return 0; |
---|
| 570 | +} |
---|
| 571 | + |
---|
| 572 | +static int rtl9010a_config_aneg(struct phy_device *phydev) |
---|
| 573 | +{ |
---|
| 574 | + return 0; |
---|
| 575 | +} |
---|
| 576 | + |
---|
| 577 | +static int rtl9010a_get_features(struct phy_device *phydev) |
---|
| 578 | +{ |
---|
| 579 | + linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT1_Full_BIT, |
---|
| 580 | + phydev->supported); |
---|
| 581 | + linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT1_Full_BIT, |
---|
| 582 | + phydev->supported); |
---|
| 583 | + |
---|
| 584 | + return 0; |
---|
| 585 | +} |
---|
| 586 | + |
---|
| 587 | +static int rtl9010a_read_status(struct phy_device *phydev) |
---|
| 588 | +{ |
---|
| 589 | + int ret; |
---|
| 590 | + u16 val; |
---|
| 591 | + int link_status, local_status, remote_status; |
---|
| 592 | + |
---|
| 593 | + ret = genphy_read_status(phydev); |
---|
| 594 | + if (ret < 0) |
---|
| 595 | + return ret; |
---|
| 596 | + |
---|
| 597 | + val = phy_read(phydev, 0x01); |
---|
| 598 | + val = phy_read(phydev, 0x01); |
---|
| 599 | + link_status = val & 0x0004 ? 1 : 0; |
---|
| 600 | + |
---|
| 601 | + if (phydev->speed == SPEED_1000) { |
---|
| 602 | + val = phy_read(phydev, 0x0a); |
---|
| 603 | + local_status = val & 0x2000 ? 1 : 0; |
---|
| 604 | + remote_status = val & 0x1000 ? 1 : 0; |
---|
| 605 | + } else { |
---|
| 606 | + phy_write(phydev, 0x1f, 0xa64); |
---|
| 607 | + val = phy_read(phydev, 0x17); |
---|
| 608 | + local_status = val & 0x0004 ? 1 : 0; |
---|
| 609 | + remote_status = val & 0x0400 ? 1 : 0; |
---|
| 610 | + } |
---|
| 611 | + |
---|
| 612 | + if (link_status && local_status && remote_status) |
---|
| 613 | + phydev->link = 1; |
---|
| 614 | + else |
---|
| 615 | + phydev->link = 0; |
---|
| 616 | + |
---|
| 617 | + return 0; |
---|
| 618 | +} |
---|
| 619 | + |
---|
214 | 620 | static struct phy_driver realtek_drvs[] = { |
---|
215 | 621 | { |
---|
216 | | - .phy_id = 0x00008201, |
---|
| 622 | + PHY_ID_MATCH_EXACT(0x00008201), |
---|
217 | 623 | .name = "RTL8201CP Ethernet", |
---|
218 | | - .phy_id_mask = 0x0000ffff, |
---|
219 | | - .features = PHY_BASIC_FEATURES, |
---|
220 | | - .flags = PHY_HAS_INTERRUPT, |
---|
| 624 | + .read_page = rtl821x_read_page, |
---|
| 625 | + .write_page = rtl821x_write_page, |
---|
221 | 626 | }, { |
---|
222 | | - .phy_id = 0x001cc816, |
---|
| 627 | + PHY_ID_MATCH_EXACT(0x001cc816), |
---|
223 | 628 | .name = "RTL8201F Fast Ethernet", |
---|
224 | | - .phy_id_mask = 0x001fffff, |
---|
225 | | - .features = PHY_BASIC_FEATURES, |
---|
226 | | - .flags = PHY_HAS_INTERRUPT, |
---|
227 | 629 | .ack_interrupt = &rtl8201_ack_interrupt, |
---|
228 | 630 | .config_intr = &rtl8201_config_intr, |
---|
229 | 631 | .suspend = genphy_suspend, |
---|
.. | .. |
---|
231 | 633 | .read_page = rtl821x_read_page, |
---|
232 | 634 | .write_page = rtl821x_write_page, |
---|
233 | 635 | }, { |
---|
234 | | - .phy_id = 0x001cc910, |
---|
| 636 | + PHY_ID_MATCH_MODEL(0x001cc880), |
---|
| 637 | + .name = "RTL8208 Fast Ethernet", |
---|
| 638 | + .read_mmd = genphy_read_mmd_unsupported, |
---|
| 639 | + .write_mmd = genphy_write_mmd_unsupported, |
---|
| 640 | + .suspend = genphy_suspend, |
---|
| 641 | + .resume = genphy_resume, |
---|
| 642 | + .read_page = rtl821x_read_page, |
---|
| 643 | + .write_page = rtl821x_write_page, |
---|
| 644 | + }, { |
---|
| 645 | + PHY_ID_MATCH_EXACT(0x001cc910), |
---|
235 | 646 | .name = "RTL8211 Gigabit Ethernet", |
---|
236 | | - .phy_id_mask = 0x001fffff, |
---|
237 | | - .features = PHY_GBIT_FEATURES, |
---|
238 | 647 | .config_aneg = rtl8211_config_aneg, |
---|
239 | 648 | .read_mmd = &genphy_read_mmd_unsupported, |
---|
240 | 649 | .write_mmd = &genphy_write_mmd_unsupported, |
---|
| 650 | + .read_page = rtl821x_read_page, |
---|
| 651 | + .write_page = rtl821x_write_page, |
---|
241 | 652 | }, { |
---|
242 | | - .phy_id = 0x001cc912, |
---|
| 653 | + PHY_ID_MATCH_EXACT(0x001cc912), |
---|
243 | 654 | .name = "RTL8211B Gigabit Ethernet", |
---|
244 | | - .phy_id_mask = 0x001fffff, |
---|
245 | | - .features = PHY_GBIT_FEATURES, |
---|
246 | | - .flags = PHY_HAS_INTERRUPT, |
---|
247 | 655 | .ack_interrupt = &rtl821x_ack_interrupt, |
---|
248 | 656 | .config_intr = &rtl8211b_config_intr, |
---|
249 | 657 | .read_mmd = &genphy_read_mmd_unsupported, |
---|
250 | 658 | .write_mmd = &genphy_write_mmd_unsupported, |
---|
251 | 659 | .suspend = rtl8211b_suspend, |
---|
252 | 660 | .resume = rtl8211b_resume, |
---|
| 661 | + .read_page = rtl821x_read_page, |
---|
| 662 | + .write_page = rtl821x_write_page, |
---|
253 | 663 | }, { |
---|
254 | | - .phy_id = 0x001cc913, |
---|
| 664 | + PHY_ID_MATCH_EXACT(0x001cc913), |
---|
255 | 665 | .name = "RTL8211C Gigabit Ethernet", |
---|
256 | | - .phy_id_mask = 0x001fffff, |
---|
257 | | - .features = PHY_GBIT_FEATURES, |
---|
258 | 666 | .config_init = rtl8211c_config_init, |
---|
259 | 667 | .read_mmd = &genphy_read_mmd_unsupported, |
---|
260 | 668 | .write_mmd = &genphy_write_mmd_unsupported, |
---|
| 669 | + .read_page = rtl821x_read_page, |
---|
| 670 | + .write_page = rtl821x_write_page, |
---|
261 | 671 | }, { |
---|
262 | | - .phy_id = 0x001cc914, |
---|
| 672 | + PHY_ID_MATCH_EXACT(0x001cc914), |
---|
263 | 673 | .name = "RTL8211DN Gigabit Ethernet", |
---|
264 | | - .phy_id_mask = 0x001fffff, |
---|
265 | | - .features = PHY_GBIT_FEATURES, |
---|
266 | | - .flags = PHY_HAS_INTERRUPT, |
---|
267 | 674 | .ack_interrupt = rtl821x_ack_interrupt, |
---|
268 | 675 | .config_intr = rtl8211e_config_intr, |
---|
269 | | - .suspend = genphy_suspend, |
---|
270 | | - .resume = genphy_resume, |
---|
271 | | - }, { |
---|
272 | | - .phy_id = 0x001cc915, |
---|
273 | | - .name = "RTL8211E Gigabit Ethernet", |
---|
274 | | - .phy_id_mask = 0x001fffff, |
---|
275 | | - .features = PHY_GBIT_FEATURES, |
---|
276 | | - .flags = PHY_HAS_INTERRUPT, |
---|
277 | | - .ack_interrupt = &rtl821x_ack_interrupt, |
---|
278 | | - .config_intr = &rtl8211e_config_intr, |
---|
279 | | - .suspend = genphy_suspend, |
---|
280 | | - .resume = genphy_resume, |
---|
281 | | - }, { |
---|
282 | | - .phy_id = 0x001cc916, |
---|
283 | | - .name = "RTL8211F Gigabit Ethernet", |
---|
284 | | - .phy_id_mask = 0x001fffff, |
---|
285 | | - .features = PHY_GBIT_FEATURES, |
---|
286 | | - .flags = PHY_HAS_INTERRUPT, |
---|
287 | | - .config_init = &rtl8211f_config_init, |
---|
288 | | - .ack_interrupt = &rtl8211f_ack_interrupt, |
---|
289 | | - .config_intr = &rtl8211f_config_intr, |
---|
290 | 676 | .suspend = genphy_suspend, |
---|
291 | 677 | .resume = genphy_resume, |
---|
292 | 678 | .read_page = rtl821x_read_page, |
---|
293 | 679 | .write_page = rtl821x_write_page, |
---|
294 | 680 | }, { |
---|
295 | | - .phy_id = 0x001cc961, |
---|
296 | | - .name = "RTL8366RB Gigabit Ethernet", |
---|
297 | | - .phy_id_mask = 0x001fffff, |
---|
298 | | - .features = PHY_GBIT_FEATURES, |
---|
299 | | - .flags = PHY_HAS_INTERRUPT, |
---|
300 | | - .config_init = &rtl8366rb_config_init, |
---|
| 681 | + PHY_ID_MATCH_EXACT(0x001cc915), |
---|
| 682 | + .name = "RTL8211E Gigabit Ethernet", |
---|
| 683 | + .config_init = &rtl8211e_config_init, |
---|
| 684 | + .ack_interrupt = &rtl821x_ack_interrupt, |
---|
| 685 | + .config_intr = &rtl8211e_config_intr, |
---|
301 | 686 | .suspend = genphy_suspend, |
---|
302 | 687 | .resume = genphy_resume, |
---|
| 688 | + .read_page = rtl821x_read_page, |
---|
| 689 | + .write_page = rtl821x_write_page, |
---|
| 690 | + }, { |
---|
| 691 | + PHY_ID_MATCH_EXACT(0x001cc916), |
---|
| 692 | + .name = "RTL8211F Gigabit Ethernet", |
---|
| 693 | + .config_init = &rtl8211f_config_init, |
---|
| 694 | + .ack_interrupt = &rtl8211f_ack_interrupt, |
---|
| 695 | + .config_intr = &rtl8211f_config_intr, |
---|
| 696 | + .suspend = genphy_suspend, |
---|
| 697 | + .resume = rtl821x_resume, |
---|
| 698 | + .read_page = rtl821x_read_page, |
---|
| 699 | + .write_page = rtl821x_write_page, |
---|
| 700 | + }, { |
---|
| 701 | + .name = "Generic FE-GE Realtek PHY", |
---|
| 702 | + .match_phy_device = rtlgen_match_phy_device, |
---|
| 703 | + .read_status = rtlgen_read_status, |
---|
| 704 | + .suspend = genphy_suspend, |
---|
| 705 | + .resume = rtlgen_resume, |
---|
| 706 | + .read_page = rtl821x_read_page, |
---|
| 707 | + .write_page = rtl821x_write_page, |
---|
| 708 | + .read_mmd = rtlgen_read_mmd, |
---|
| 709 | + .write_mmd = rtlgen_write_mmd, |
---|
| 710 | + }, { |
---|
| 711 | + .name = "RTL8226 2.5Gbps PHY", |
---|
| 712 | + .match_phy_device = rtl8226_match_phy_device, |
---|
| 713 | + .get_features = rtl822x_get_features, |
---|
| 714 | + .config_aneg = rtl822x_config_aneg, |
---|
| 715 | + .read_status = rtl822x_read_status, |
---|
| 716 | + .suspend = genphy_suspend, |
---|
| 717 | + .resume = rtlgen_resume, |
---|
| 718 | + .read_page = rtl821x_read_page, |
---|
| 719 | + .write_page = rtl821x_write_page, |
---|
| 720 | + .read_mmd = rtl822x_read_mmd, |
---|
| 721 | + .write_mmd = rtl822x_write_mmd, |
---|
| 722 | + }, { |
---|
| 723 | + PHY_ID_MATCH_EXACT(0x001cc840), |
---|
| 724 | + .name = "RTL8226B_RTL8221B 2.5Gbps PHY", |
---|
| 725 | + .get_features = rtl822x_get_features, |
---|
| 726 | + .config_aneg = rtl822x_config_aneg, |
---|
| 727 | + .read_status = rtl822x_read_status, |
---|
| 728 | + .suspend = genphy_suspend, |
---|
| 729 | + .resume = rtlgen_resume, |
---|
| 730 | + .read_page = rtl821x_read_page, |
---|
| 731 | + .write_page = rtl821x_write_page, |
---|
| 732 | + .read_mmd = rtl822x_read_mmd, |
---|
| 733 | + .write_mmd = rtl822x_write_mmd, |
---|
| 734 | + }, { |
---|
| 735 | + PHY_ID_MATCH_EXACT(0x001cc961), |
---|
| 736 | + .name = "RTL8366RB Gigabit Ethernet", |
---|
| 737 | + .config_init = &rtl8366rb_config_init, |
---|
| 738 | + /* These interrupts are handled by the irq controller |
---|
| 739 | + * embedded inside the RTL8366RB, they get unmasked when the |
---|
| 740 | + * irq is requested and ACKed by reading the status register, |
---|
| 741 | + * which is done by the irqchip code. |
---|
| 742 | + */ |
---|
| 743 | + .ack_interrupt = genphy_no_ack_interrupt, |
---|
| 744 | + .config_intr = genphy_no_config_intr, |
---|
| 745 | + .suspend = genphy_suspend, |
---|
| 746 | + .resume = genphy_resume, |
---|
| 747 | + }, { |
---|
| 748 | + PHY_ID_MATCH_EXACT(0x001ccb30), |
---|
| 749 | + .name = "RTL9010AA_RTL9010AR_RTL9010AS Ethernet", |
---|
| 750 | + .config_init = rtl9010a_config_init, |
---|
| 751 | + .config_aneg = rtl9010a_config_aneg, |
---|
| 752 | + .read_status = rtl9010a_read_status, |
---|
| 753 | + .get_features = rtl9010a_get_features, |
---|
| 754 | + .suspend = genphy_suspend, |
---|
| 755 | + .resume = genphy_resume, |
---|
| 756 | + .read_page = rtl821x_read_page, |
---|
| 757 | + .write_page = rtl821x_write_page, |
---|
303 | 758 | }, |
---|
304 | 759 | }; |
---|
305 | 760 | |
---|
306 | 761 | module_phy_driver(realtek_drvs); |
---|
307 | 762 | |
---|
308 | | -static struct mdio_device_id __maybe_unused realtek_tbl[] = { |
---|
309 | | - { 0x001cc816, 0x001fffff }, |
---|
310 | | - { 0x001cc910, 0x001fffff }, |
---|
311 | | - { 0x001cc912, 0x001fffff }, |
---|
312 | | - { 0x001cc913, 0x001fffff }, |
---|
313 | | - { 0x001cc914, 0x001fffff }, |
---|
314 | | - { 0x001cc915, 0x001fffff }, |
---|
315 | | - { 0x001cc916, 0x001fffff }, |
---|
316 | | - { 0x001cc961, 0x001fffff }, |
---|
| 763 | +static const struct mdio_device_id __maybe_unused realtek_tbl[] = { |
---|
| 764 | + { PHY_ID_MATCH_VENDOR(0x001cc800) }, |
---|
| 765 | + { PHY_ID_MATCH_VENDOR(0x001ccb30) }, |
---|
317 | 766 | { } |
---|
318 | 767 | }; |
---|
319 | 768 | |
---|