linux/drivers/net/phy/realtek.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * drivers/net/phy/realtek.c
   4 *
   5 * Driver for Realtek PHYs
   6 *
   7 * Author: Johnson Leung <r58129@freescale.com>
   8 *
   9 * Copyright (c) 2004 Freescale Semiconductor, Inc.
  10 */
  11#include <linux/bitops.h>
  12#include <linux/phy.h>
  13#include <linux/module.h>
  14
  15#define RTL821x_PHYSR                           0x11
  16#define RTL821x_PHYSR_DUPLEX                    BIT(13)
  17#define RTL821x_PHYSR_SPEED                     GENMASK(15, 14)
  18
  19#define RTL821x_INER                            0x12
  20#define RTL8211B_INER_INIT                      0x6400
  21#define RTL8211E_INER_LINK_STATUS               BIT(10)
  22#define RTL8211F_INER_LINK_STATUS               BIT(4)
  23
  24#define RTL821x_INSR                            0x13
  25
  26#define RTL821x_EXT_PAGE_SELECT                 0x1e
  27#define RTL821x_PAGE_SELECT                     0x1f
  28
  29#define RTL8211F_INSR                           0x1d
  30
  31#define RTL8211F_TX_DELAY                       BIT(8)
  32#define RTL8211E_TX_DELAY                       BIT(1)
  33#define RTL8211E_RX_DELAY                       BIT(2)
  34#define RTL8211E_MODE_MII_GMII                  BIT(3)
  35
  36#define RTL8201F_ISR                            0x1e
  37#define RTL8201F_IER                            0x13
  38
  39#define RTL8366RB_POWER_SAVE                    0x15
  40#define RTL8366RB_POWER_SAVE_ON                 BIT(12)
  41
  42MODULE_DESCRIPTION("Realtek PHY driver");
  43MODULE_AUTHOR("Johnson Leung");
  44MODULE_LICENSE("GPL");
  45
  46static int rtl821x_read_page(struct phy_device *phydev)
  47{
  48        return __phy_read(phydev, RTL821x_PAGE_SELECT);
  49}
  50
  51static int rtl821x_write_page(struct phy_device *phydev, int page)
  52{
  53        return __phy_write(phydev, RTL821x_PAGE_SELECT, page);
  54}
  55
  56static int rtl8201_ack_interrupt(struct phy_device *phydev)
  57{
  58        int err;
  59
  60        err = phy_read(phydev, RTL8201F_ISR);
  61
  62        return (err < 0) ? err : 0;
  63}
  64
  65static int rtl821x_ack_interrupt(struct phy_device *phydev)
  66{
  67        int err;
  68
  69        err = phy_read(phydev, RTL821x_INSR);
  70
  71        return (err < 0) ? err : 0;
  72}
  73
  74static int rtl8211f_ack_interrupt(struct phy_device *phydev)
  75{
  76        int err;
  77
  78        err = phy_read_paged(phydev, 0xa43, RTL8211F_INSR);
  79
  80        return (err < 0) ? err : 0;
  81}
  82
  83static int rtl8201_config_intr(struct phy_device *phydev)
  84{
  85        u16 val;
  86
  87        if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
  88                val = BIT(13) | BIT(12) | BIT(11);
  89        else
  90                val = 0;
  91
  92        return phy_write_paged(phydev, 0x7, RTL8201F_IER, val);
  93}
  94
  95static int rtl8211b_config_intr(struct phy_device *phydev)
  96{
  97        int err;
  98
  99        if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
 100                err = phy_write(phydev, RTL821x_INER,
 101                                RTL8211B_INER_INIT);
 102        else
 103                err = phy_write(phydev, RTL821x_INER, 0);
 104
 105        return err;
 106}
 107
 108static int rtl8211e_config_intr(struct phy_device *phydev)
 109{
 110        int err;
 111
 112        if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
 113                err = phy_write(phydev, RTL821x_INER,
 114                                RTL8211E_INER_LINK_STATUS);
 115        else
 116                err = phy_write(phydev, RTL821x_INER, 0);
 117
 118        return err;
 119}
 120
 121static int rtl8211f_config_intr(struct phy_device *phydev)
 122{
 123        u16 val;
 124
 125        if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
 126                val = RTL8211F_INER_LINK_STATUS;
 127        else
 128                val = 0;
 129
 130        return phy_write_paged(phydev, 0xa42, RTL821x_INER, val);
 131}
 132
 133static int rtl8211_config_aneg(struct phy_device *phydev)
 134{
 135        int ret;
 136
 137        ret = genphy_config_aneg(phydev);
 138        if (ret < 0)
 139                return ret;
 140
 141        /* Quirk was copied from vendor driver. Unfortunately it includes no
 142         * description of the magic numbers.
 143         */
 144        if (phydev->speed == SPEED_100 && phydev->autoneg == AUTONEG_DISABLE) {
 145                phy_write(phydev, 0x17, 0x2138);
 146                phy_write(phydev, 0x0e, 0x0260);
 147        } else {
 148                phy_write(phydev, 0x17, 0x2108);
 149                phy_write(phydev, 0x0e, 0x0000);
 150        }
 151
 152        return 0;
 153}
 154
 155static int rtl8211c_config_init(struct phy_device *phydev)
 156{
 157        /* RTL8211C has an issue when operating in Gigabit slave mode */
 158        return phy_set_bits(phydev, MII_CTRL1000,
 159                            CTL1000_ENABLE_MASTER | CTL1000_AS_MASTER);
 160}
 161
 162static int rtl8211f_config_init(struct phy_device *phydev)
 163{
 164        u16 val;
 165
 166        /* enable TX-delay for rgmii-{id,txid}, and disable it for rgmii and
 167         * rgmii-rxid. The RX-delay can be enabled by the external RXDLY pin.
 168         */
 169        switch (phydev->interface) {
 170        case PHY_INTERFACE_MODE_RGMII:
 171        case PHY_INTERFACE_MODE_RGMII_RXID:
 172                val = 0;
 173                break;
 174        case PHY_INTERFACE_MODE_RGMII_ID:
 175        case PHY_INTERFACE_MODE_RGMII_TXID:
 176                val = RTL8211F_TX_DELAY;
 177                break;
 178        default: /* the rest of the modes imply leaving delay as is. */
 179                return 0;
 180        }
 181
 182        return phy_modify_paged(phydev, 0xd08, 0x11, RTL8211F_TX_DELAY, val);
 183}
 184
 185static int rtl8211e_config_init(struct phy_device *phydev)
 186{
 187        int ret = 0, oldpage;
 188        u16 val;
 189
 190        /* enable TX/RX delay for rgmii-* modes, and disable them for rgmii. */
 191        switch (phydev->interface) {
 192        case PHY_INTERFACE_MODE_RGMII:
 193                val = 0;
 194                break;
 195        case PHY_INTERFACE_MODE_RGMII_ID:
 196                val = RTL8211E_TX_DELAY | RTL8211E_RX_DELAY;
 197                break;
 198        case PHY_INTERFACE_MODE_RGMII_RXID:
 199                val = RTL8211E_RX_DELAY;
 200                break;
 201        case PHY_INTERFACE_MODE_RGMII_TXID:
 202                val = RTL8211E_TX_DELAY;
 203                break;
 204        default: /* the rest of the modes imply leaving delays as is. */
 205                return 0;
 206        }
 207
 208        /* According to a sample driver there is a 0x1c config register on the
 209         * 0xa4 extension page (0x7) layout. It can be used to disable/enable
 210         * the RX/TX delays otherwise controlled by RXDLY/TXDLY pins. It can
 211         * also be used to customize the whole configuration register:
 212         * 8:6 = PHY Address, 5:4 = Auto-Negotiation, 3 = Interface Mode Select,
 213         * 2 = RX Delay, 1 = TX Delay, 0 = SELRGV (see original PHY datasheet
 214         * for details).
 215         */
 216        oldpage = phy_select_page(phydev, 0x7);
 217        if (oldpage < 0)
 218                goto err_restore_page;
 219
 220        ret = __phy_write(phydev, RTL821x_EXT_PAGE_SELECT, 0xa4);
 221        if (ret)
 222                goto err_restore_page;
 223
 224        ret = __phy_modify(phydev, 0x1c, RTL8211E_TX_DELAY | RTL8211E_RX_DELAY,
 225                           val);
 226
 227err_restore_page:
 228        return phy_restore_page(phydev, oldpage, ret);
 229}
 230
 231static int rtl8211b_suspend(struct phy_device *phydev)
 232{
 233        phy_write(phydev, MII_MMD_DATA, BIT(9));
 234
 235        return genphy_suspend(phydev);
 236}
 237
 238static int rtl8211b_resume(struct phy_device *phydev)
 239{
 240        phy_write(phydev, MII_MMD_DATA, 0);
 241
 242        return genphy_resume(phydev);
 243}
 244
 245static int rtl8366rb_config_init(struct phy_device *phydev)
 246{
 247        int ret;
 248
 249        ret = phy_set_bits(phydev, RTL8366RB_POWER_SAVE,
 250                           RTL8366RB_POWER_SAVE_ON);
 251        if (ret) {
 252                dev_err(&phydev->mdio.dev,
 253                        "error enabling power management\n");
 254        }
 255
 256        return ret;
 257}
 258
 259static struct phy_driver realtek_drvs[] = {
 260        {
 261                PHY_ID_MATCH_EXACT(0x00008201),
 262                .name           = "RTL8201CP Ethernet",
 263        }, {
 264                PHY_ID_MATCH_EXACT(0x001cc816),
 265                .name           = "RTL8201F Fast Ethernet",
 266                .ack_interrupt  = &rtl8201_ack_interrupt,
 267                .config_intr    = &rtl8201_config_intr,
 268                .suspend        = genphy_suspend,
 269                .resume         = genphy_resume,
 270                .read_page      = rtl821x_read_page,
 271                .write_page     = rtl821x_write_page,
 272        }, {
 273                PHY_ID_MATCH_EXACT(0x001cc910),
 274                .name           = "RTL8211 Gigabit Ethernet",
 275                .config_aneg    = rtl8211_config_aneg,
 276                .read_mmd       = &genphy_read_mmd_unsupported,
 277                .write_mmd      = &genphy_write_mmd_unsupported,
 278                .read_page      = rtl821x_read_page,
 279                .write_page     = rtl821x_write_page,
 280        }, {
 281                PHY_ID_MATCH_EXACT(0x001cc912),
 282                .name           = "RTL8211B Gigabit Ethernet",
 283                .ack_interrupt  = &rtl821x_ack_interrupt,
 284                .config_intr    = &rtl8211b_config_intr,
 285                .read_mmd       = &genphy_read_mmd_unsupported,
 286                .write_mmd      = &genphy_write_mmd_unsupported,
 287                .suspend        = rtl8211b_suspend,
 288                .resume         = rtl8211b_resume,
 289                .read_page      = rtl821x_read_page,
 290                .write_page     = rtl821x_write_page,
 291        }, {
 292                PHY_ID_MATCH_EXACT(0x001cc913),
 293                .name           = "RTL8211C Gigabit Ethernet",
 294                .config_init    = rtl8211c_config_init,
 295                .read_mmd       = &genphy_read_mmd_unsupported,
 296                .write_mmd      = &genphy_write_mmd_unsupported,
 297                .read_page      = rtl821x_read_page,
 298                .write_page     = rtl821x_write_page,
 299        }, {
 300                PHY_ID_MATCH_EXACT(0x001cc914),
 301                .name           = "RTL8211DN Gigabit Ethernet",
 302                .ack_interrupt  = rtl821x_ack_interrupt,
 303                .config_intr    = rtl8211e_config_intr,
 304                .suspend        = genphy_suspend,
 305                .resume         = genphy_resume,
 306                .read_page      = rtl821x_read_page,
 307                .write_page     = rtl821x_write_page,
 308        }, {
 309                PHY_ID_MATCH_EXACT(0x001cc915),
 310                .name           = "RTL8211E Gigabit Ethernet",
 311                .config_init    = &rtl8211e_config_init,
 312                .ack_interrupt  = &rtl821x_ack_interrupt,
 313                .config_intr    = &rtl8211e_config_intr,
 314                .suspend        = genphy_suspend,
 315                .resume         = genphy_resume,
 316                .read_page      = rtl821x_read_page,
 317                .write_page     = rtl821x_write_page,
 318        }, {
 319                PHY_ID_MATCH_EXACT(0x001cc916),
 320                .name           = "RTL8211F Gigabit Ethernet",
 321                .config_init    = &rtl8211f_config_init,
 322                .ack_interrupt  = &rtl8211f_ack_interrupt,
 323                .config_intr    = &rtl8211f_config_intr,
 324                .suspend        = genphy_suspend,
 325                .resume         = genphy_resume,
 326                .read_page      = rtl821x_read_page,
 327                .write_page     = rtl821x_write_page,
 328        }, {
 329                PHY_ID_MATCH_EXACT(0x001cc800),
 330                .name           = "Generic Realtek PHY",
 331                .suspend        = genphy_suspend,
 332                .resume         = genphy_resume,
 333                .read_page      = rtl821x_read_page,
 334                .write_page     = rtl821x_write_page,
 335        }, {
 336                PHY_ID_MATCH_EXACT(0x001cc961),
 337                .name           = "RTL8366RB Gigabit Ethernet",
 338                .config_init    = &rtl8366rb_config_init,
 339                /* These interrupts are handled by the irq controller
 340                 * embedded inside the RTL8366RB, they get unmasked when the
 341                 * irq is requested and ACKed by reading the status register,
 342                 * which is done by the irqchip code.
 343                 */
 344                .ack_interrupt  = genphy_no_ack_interrupt,
 345                .config_intr    = genphy_no_config_intr,
 346                .suspend        = genphy_suspend,
 347                .resume         = genphy_resume,
 348        },
 349};
 350
 351module_phy_driver(realtek_drvs);
 352
 353static const struct mdio_device_id __maybe_unused realtek_tbl[] = {
 354        { PHY_ID_MATCH_VENDOR(0x001cc800) },
 355        { }
 356};
 357
 358MODULE_DEVICE_TABLE(mdio, realtek_tbl);
 359