linux/drivers/net/phy/at803x.c
<<
>>
Prefs
   1/*
   2 * drivers/net/phy/at803x.c
   3 *
   4 * Driver for Atheros 803x PHY
   5 *
   6 * Author: Matus Ujhelyi <ujhelyi.m@gmail.com>
   7 *
   8 * This program is free software; you can redistribute  it and/or modify it
   9 * under  the terms of  the GNU General  Public License as published by the
  10 * Free Software Foundation;  either version 2 of the  License, or (at your
  11 * option) any later version.
  12 */
  13
  14#include <linux/phy.h>
  15#include <linux/module.h>
  16#include <linux/string.h>
  17#include <linux/netdevice.h>
  18#include <linux/etherdevice.h>
  19#include <linux/of_gpio.h>
  20#include <linux/gpio/consumer.h>
  21
  22#define AT803X_INTR_ENABLE                      0x12
  23#define AT803X_INTR_ENABLE_AUTONEG_ERR          BIT(15)
  24#define AT803X_INTR_ENABLE_SPEED_CHANGED        BIT(14)
  25#define AT803X_INTR_ENABLE_DUPLEX_CHANGED       BIT(13)
  26#define AT803X_INTR_ENABLE_PAGE_RECEIVED        BIT(12)
  27#define AT803X_INTR_ENABLE_LINK_FAIL            BIT(11)
  28#define AT803X_INTR_ENABLE_LINK_SUCCESS         BIT(10)
  29#define AT803X_INTR_ENABLE_WIRESPEED_DOWNGRADE  BIT(5)
  30#define AT803X_INTR_ENABLE_POLARITY_CHANGED     BIT(1)
  31#define AT803X_INTR_ENABLE_WOL                  BIT(0)
  32
  33#define AT803X_INTR_STATUS                      0x13
  34
  35#define AT803X_SMART_SPEED                      0x14
  36#define AT803X_LED_CONTROL                      0x18
  37
  38#define AT803X_DEVICE_ADDR                      0x03
  39#define AT803X_LOC_MAC_ADDR_0_15_OFFSET         0x804C
  40#define AT803X_LOC_MAC_ADDR_16_31_OFFSET        0x804B
  41#define AT803X_LOC_MAC_ADDR_32_47_OFFSET        0x804A
  42#define AT803X_MMD_ACCESS_CONTROL               0x0D
  43#define AT803X_MMD_ACCESS_CONTROL_DATA          0x0E
  44#define AT803X_FUNC_DATA                        0x4003
  45#define AT803X_REG_CHIP_CONFIG                  0x1f
  46#define AT803X_BT_BX_REG_SEL                    0x8000
  47
  48#define AT803X_DEBUG_ADDR                       0x1D
  49#define AT803X_DEBUG_DATA                       0x1E
  50
  51#define AT803X_MODE_CFG_MASK                    0x0F
  52#define AT803X_MODE_CFG_SGMII                   0x01
  53
  54#define AT803X_PSSR                     0x11    /*PHY-Specific Status Register*/
  55#define AT803X_PSSR_MR_AN_COMPLETE      0x0200
  56
  57#define AT803X_DEBUG_REG_0                      0x00
  58#define AT803X_DEBUG_RX_CLK_DLY_EN              BIT(15)
  59
  60#define AT803X_DEBUG_REG_5                      0x05
  61#define AT803X_DEBUG_TX_CLK_DLY_EN              BIT(8)
  62
  63#define ATH8030_PHY_ID 0x004dd076
  64#define ATH8031_PHY_ID 0x004dd074
  65#define ATH8035_PHY_ID 0x004dd072
  66#define AT803X_PHY_ID_MASK                      0xffffffef
  67
  68MODULE_DESCRIPTION("Atheros 803x PHY driver");
  69MODULE_AUTHOR("Matus Ujhelyi");
  70MODULE_LICENSE("GPL");
  71
  72struct at803x_priv {
  73        bool phy_reset:1;
  74        struct gpio_desc *gpiod_reset;
  75};
  76
  77struct at803x_context {
  78        u16 bmcr;
  79        u16 advertise;
  80        u16 control1000;
  81        u16 int_enable;
  82        u16 smart_speed;
  83        u16 led_control;
  84};
  85
  86static int at803x_debug_reg_read(struct phy_device *phydev, u16 reg)
  87{
  88        int ret;
  89
  90        ret = phy_write(phydev, AT803X_DEBUG_ADDR, reg);
  91        if (ret < 0)
  92                return ret;
  93
  94        return phy_read(phydev, AT803X_DEBUG_DATA);
  95}
  96
  97static int at803x_debug_reg_mask(struct phy_device *phydev, u16 reg,
  98                                 u16 clear, u16 set)
  99{
 100        u16 val;
 101        int ret;
 102
 103        ret = at803x_debug_reg_read(phydev, reg);
 104        if (ret < 0)
 105                return ret;
 106
 107        val = ret & 0xffff;
 108        val &= ~clear;
 109        val |= set;
 110
 111        return phy_write(phydev, AT803X_DEBUG_DATA, val);
 112}
 113
 114static inline int at803x_enable_rx_delay(struct phy_device *phydev)
 115{
 116        return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_0, 0,
 117                                        AT803X_DEBUG_RX_CLK_DLY_EN);
 118}
 119
 120static inline int at803x_enable_tx_delay(struct phy_device *phydev)
 121{
 122        return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_5, 0,
 123                                        AT803X_DEBUG_TX_CLK_DLY_EN);
 124}
 125
 126/* save relevant PHY registers to private copy */
 127static void at803x_context_save(struct phy_device *phydev,
 128                                struct at803x_context *context)
 129{
 130        context->bmcr = phy_read(phydev, MII_BMCR);
 131        context->advertise = phy_read(phydev, MII_ADVERTISE);
 132        context->control1000 = phy_read(phydev, MII_CTRL1000);
 133        context->int_enable = phy_read(phydev, AT803X_INTR_ENABLE);
 134        context->smart_speed = phy_read(phydev, AT803X_SMART_SPEED);
 135        context->led_control = phy_read(phydev, AT803X_LED_CONTROL);
 136}
 137
 138/* restore relevant PHY registers from private copy */
 139static void at803x_context_restore(struct phy_device *phydev,
 140                                   const struct at803x_context *context)
 141{
 142        phy_write(phydev, MII_BMCR, context->bmcr);
 143        phy_write(phydev, MII_ADVERTISE, context->advertise);
 144        phy_write(phydev, MII_CTRL1000, context->control1000);
 145        phy_write(phydev, AT803X_INTR_ENABLE, context->int_enable);
 146        phy_write(phydev, AT803X_SMART_SPEED, context->smart_speed);
 147        phy_write(phydev, AT803X_LED_CONTROL, context->led_control);
 148}
 149
 150static int at803x_set_wol(struct phy_device *phydev,
 151                          struct ethtool_wolinfo *wol)
 152{
 153        struct net_device *ndev = phydev->attached_dev;
 154        const u8 *mac;
 155        int ret;
 156        u32 value;
 157        unsigned int i, offsets[] = {
 158                AT803X_LOC_MAC_ADDR_32_47_OFFSET,
 159                AT803X_LOC_MAC_ADDR_16_31_OFFSET,
 160                AT803X_LOC_MAC_ADDR_0_15_OFFSET,
 161        };
 162
 163        if (!ndev)
 164                return -ENODEV;
 165
 166        if (wol->wolopts & WAKE_MAGIC) {
 167                mac = (const u8 *) ndev->dev_addr;
 168
 169                if (!is_valid_ether_addr(mac))
 170                        return -EFAULT;
 171
 172                for (i = 0; i < 3; i++) {
 173                        phy_write(phydev, AT803X_MMD_ACCESS_CONTROL,
 174                                  AT803X_DEVICE_ADDR);
 175                        phy_write(phydev, AT803X_MMD_ACCESS_CONTROL_DATA,
 176                                  offsets[i]);
 177                        phy_write(phydev, AT803X_MMD_ACCESS_CONTROL,
 178                                  AT803X_FUNC_DATA);
 179                        phy_write(phydev, AT803X_MMD_ACCESS_CONTROL_DATA,
 180                                  mac[(i * 2) + 1] | (mac[(i * 2)] << 8));
 181                }
 182
 183                value = phy_read(phydev, AT803X_INTR_ENABLE);
 184                value |= AT803X_INTR_ENABLE_WOL;
 185                ret = phy_write(phydev, AT803X_INTR_ENABLE, value);
 186                if (ret)
 187                        return ret;
 188                value = phy_read(phydev, AT803X_INTR_STATUS);
 189        } else {
 190                value = phy_read(phydev, AT803X_INTR_ENABLE);
 191                value &= (~AT803X_INTR_ENABLE_WOL);
 192                ret = phy_write(phydev, AT803X_INTR_ENABLE, value);
 193                if (ret)
 194                        return ret;
 195                value = phy_read(phydev, AT803X_INTR_STATUS);
 196        }
 197
 198        return ret;
 199}
 200
 201static void at803x_get_wol(struct phy_device *phydev,
 202                           struct ethtool_wolinfo *wol)
 203{
 204        u32 value;
 205
 206        wol->supported = WAKE_MAGIC;
 207        wol->wolopts = 0;
 208
 209        value = phy_read(phydev, AT803X_INTR_ENABLE);
 210        if (value & AT803X_INTR_ENABLE_WOL)
 211                wol->wolopts |= WAKE_MAGIC;
 212}
 213
 214static int at803x_suspend(struct phy_device *phydev)
 215{
 216        int value;
 217        int wol_enabled;
 218
 219        mutex_lock(&phydev->lock);
 220
 221        value = phy_read(phydev, AT803X_INTR_ENABLE);
 222        wol_enabled = value & AT803X_INTR_ENABLE_WOL;
 223
 224        value = phy_read(phydev, MII_BMCR);
 225
 226        if (wol_enabled)
 227                value |= BMCR_ISOLATE;
 228        else
 229                value |= BMCR_PDOWN;
 230
 231        phy_write(phydev, MII_BMCR, value);
 232
 233        mutex_unlock(&phydev->lock);
 234
 235        return 0;
 236}
 237
 238static int at803x_resume(struct phy_device *phydev)
 239{
 240        int value;
 241
 242        mutex_lock(&phydev->lock);
 243
 244        value = phy_read(phydev, MII_BMCR);
 245        value &= ~(BMCR_PDOWN | BMCR_ISOLATE);
 246        phy_write(phydev, MII_BMCR, value);
 247
 248        mutex_unlock(&phydev->lock);
 249
 250        return 0;
 251}
 252
 253static int at803x_probe(struct phy_device *phydev)
 254{
 255        struct device *dev = &phydev->mdio.dev;
 256        struct at803x_priv *priv;
 257        struct gpio_desc *gpiod_reset;
 258
 259        priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
 260        if (!priv)
 261                return -ENOMEM;
 262
 263        if (phydev->drv->phy_id != ATH8030_PHY_ID)
 264                goto does_not_require_reset_workaround;
 265
 266        gpiod_reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
 267        if (IS_ERR(gpiod_reset))
 268                return PTR_ERR(gpiod_reset);
 269
 270        priv->gpiod_reset = gpiod_reset;
 271
 272does_not_require_reset_workaround:
 273        phydev->priv = priv;
 274
 275        return 0;
 276}
 277
 278static int at803x_config_init(struct phy_device *phydev)
 279{
 280        int ret;
 281
 282        ret = genphy_config_init(phydev);
 283        if (ret < 0)
 284                return ret;
 285
 286        if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID ||
 287                        phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) {
 288                ret = at803x_enable_rx_delay(phydev);
 289                if (ret < 0)
 290                        return ret;
 291        }
 292
 293        if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID ||
 294                        phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) {
 295                ret = at803x_enable_tx_delay(phydev);
 296                if (ret < 0)
 297                        return ret;
 298        }
 299
 300        return 0;
 301}
 302
 303static int at803x_ack_interrupt(struct phy_device *phydev)
 304{
 305        int err;
 306
 307        err = phy_read(phydev, AT803X_INTR_STATUS);
 308
 309        return (err < 0) ? err : 0;
 310}
 311
 312static int at803x_config_intr(struct phy_device *phydev)
 313{
 314        int err;
 315        int value;
 316
 317        value = phy_read(phydev, AT803X_INTR_ENABLE);
 318
 319        if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
 320                value |= AT803X_INTR_ENABLE_AUTONEG_ERR;
 321                value |= AT803X_INTR_ENABLE_SPEED_CHANGED;
 322                value |= AT803X_INTR_ENABLE_DUPLEX_CHANGED;
 323                value |= AT803X_INTR_ENABLE_LINK_FAIL;
 324                value |= AT803X_INTR_ENABLE_LINK_SUCCESS;
 325
 326                err = phy_write(phydev, AT803X_INTR_ENABLE, value);
 327        }
 328        else
 329                err = phy_write(phydev, AT803X_INTR_ENABLE, 0);
 330
 331        return err;
 332}
 333
 334static void at803x_link_change_notify(struct phy_device *phydev)
 335{
 336        struct at803x_priv *priv = phydev->priv;
 337
 338        /*
 339         * Conduct a hardware reset for AT8030 every time a link loss is
 340         * signalled. This is necessary to circumvent a hardware bug that
 341         * occurs when the cable is unplugged while TX packets are pending
 342         * in the FIFO. In such cases, the FIFO enters an error mode it
 343         * cannot recover from by software.
 344         */
 345        if (phydev->state == PHY_NOLINK) {
 346                if (priv->gpiod_reset && !priv->phy_reset) {
 347                        struct at803x_context context;
 348
 349                        at803x_context_save(phydev, &context);
 350
 351                        gpiod_set_value(priv->gpiod_reset, 1);
 352                        msleep(1);
 353                        gpiod_set_value(priv->gpiod_reset, 0);
 354                        msleep(1);
 355
 356                        at803x_context_restore(phydev, &context);
 357
 358                        phydev_dbg(phydev, "%s(): phy was reset\n",
 359                                   __func__);
 360                        priv->phy_reset = true;
 361                }
 362        } else {
 363                priv->phy_reset = false;
 364        }
 365}
 366
 367static int at803x_aneg_done(struct phy_device *phydev)
 368{
 369        int ccr;
 370
 371        int aneg_done = genphy_aneg_done(phydev);
 372        if (aneg_done != BMSR_ANEGCOMPLETE)
 373                return aneg_done;
 374
 375        /*
 376         * in SGMII mode, if copper side autoneg is successful,
 377         * also check SGMII side autoneg result
 378         */
 379        ccr = phy_read(phydev, AT803X_REG_CHIP_CONFIG);
 380        if ((ccr & AT803X_MODE_CFG_MASK) != AT803X_MODE_CFG_SGMII)
 381                return aneg_done;
 382
 383        /* switch to SGMII/fiber page */
 384        phy_write(phydev, AT803X_REG_CHIP_CONFIG, ccr & ~AT803X_BT_BX_REG_SEL);
 385
 386        /* check if the SGMII link is OK. */
 387        if (!(phy_read(phydev, AT803X_PSSR) & AT803X_PSSR_MR_AN_COMPLETE)) {
 388                pr_warn("803x_aneg_done: SGMII link is not ok\n");
 389                aneg_done = 0;
 390        }
 391        /* switch back to copper page */
 392        phy_write(phydev, AT803X_REG_CHIP_CONFIG, ccr | AT803X_BT_BX_REG_SEL);
 393
 394        return aneg_done;
 395}
 396
 397static struct phy_driver at803x_driver[] = {
 398{
 399        /* ATHEROS 8035 */
 400        .phy_id                 = ATH8035_PHY_ID,
 401        .name                   = "Atheros 8035 ethernet",
 402        .phy_id_mask            = AT803X_PHY_ID_MASK,
 403        .probe                  = at803x_probe,
 404        .config_init            = at803x_config_init,
 405        .set_wol                = at803x_set_wol,
 406        .get_wol                = at803x_get_wol,
 407        .suspend                = at803x_suspend,
 408        .resume                 = at803x_resume,
 409        .features               = PHY_GBIT_FEATURES,
 410        .flags                  = PHY_HAS_INTERRUPT,
 411        .config_aneg            = genphy_config_aneg,
 412        .read_status            = genphy_read_status,
 413        .ack_interrupt          = at803x_ack_interrupt,
 414        .config_intr            = at803x_config_intr,
 415}, {
 416        /* ATHEROS 8030 */
 417        .phy_id                 = ATH8030_PHY_ID,
 418        .name                   = "Atheros 8030 ethernet",
 419        .phy_id_mask            = AT803X_PHY_ID_MASK,
 420        .probe                  = at803x_probe,
 421        .config_init            = at803x_config_init,
 422        .link_change_notify     = at803x_link_change_notify,
 423        .set_wol                = at803x_set_wol,
 424        .get_wol                = at803x_get_wol,
 425        .suspend                = at803x_suspend,
 426        .resume                 = at803x_resume,
 427        .features               = PHY_BASIC_FEATURES,
 428        .flags                  = PHY_HAS_INTERRUPT,
 429        .config_aneg            = genphy_config_aneg,
 430        .read_status            = genphy_read_status,
 431        .ack_interrupt          = at803x_ack_interrupt,
 432        .config_intr            = at803x_config_intr,
 433}, {
 434        /* ATHEROS 8031 */
 435        .phy_id                 = ATH8031_PHY_ID,
 436        .name                   = "Atheros 8031 ethernet",
 437        .phy_id_mask            = AT803X_PHY_ID_MASK,
 438        .probe                  = at803x_probe,
 439        .config_init            = at803x_config_init,
 440        .set_wol                = at803x_set_wol,
 441        .get_wol                = at803x_get_wol,
 442        .suspend                = at803x_suspend,
 443        .resume                 = at803x_resume,
 444        .features               = PHY_GBIT_FEATURES,
 445        .flags                  = PHY_HAS_INTERRUPT,
 446        .config_aneg            = genphy_config_aneg,
 447        .read_status            = genphy_read_status,
 448        .aneg_done              = at803x_aneg_done,
 449        .ack_interrupt          = &at803x_ack_interrupt,
 450        .config_intr            = &at803x_config_intr,
 451} };
 452
 453module_phy_driver(at803x_driver);
 454
 455static struct mdio_device_id __maybe_unused atheros_tbl[] = {
 456        { ATH8030_PHY_ID, AT803X_PHY_ID_MASK },
 457        { ATH8031_PHY_ID, AT803X_PHY_ID_MASK },
 458        { ATH8035_PHY_ID, AT803X_PHY_ID_MASK },
 459        { }
 460};
 461
 462MODULE_DEVICE_TABLE(mdio, atheros_tbl);
 463