| .. | .. |
|---|
| 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 | |
|---|