linux/drivers/net/phy/bcm54140.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/* Broadcom BCM54140 Quad SGMII/QSGMII Copper/Fiber Gigabit PHY
   3 *
   4 * Copyright (c) 2020 Michael Walle <michael@walle.cc>
   5 */
   6
   7#include <linux/bitfield.h>
   8#include <linux/brcmphy.h>
   9#include <linux/hwmon.h>
  10#include <linux/module.h>
  11#include <linux/phy.h>
  12
  13#include "bcm-phy-lib.h"
  14
  15/* RDB per-port registers
  16 */
  17#define BCM54140_RDB_ISR                0x00a   /* interrupt status */
  18#define BCM54140_RDB_IMR                0x00b   /* interrupt mask */
  19#define  BCM54140_RDB_INT_LINK          BIT(1)  /* link status changed */
  20#define  BCM54140_RDB_INT_SPEED         BIT(2)  /* link speed change */
  21#define  BCM54140_RDB_INT_DUPLEX        BIT(3)  /* duplex mode changed */
  22#define BCM54140_RDB_SPARE1             0x012   /* spare control 1 */
  23#define  BCM54140_RDB_SPARE1_LSLM       BIT(2)  /* link speed LED mode */
  24#define BCM54140_RDB_SPARE2             0x014   /* spare control 2 */
  25#define  BCM54140_RDB_SPARE2_WS_RTRY_DIS BIT(8) /* wirespeed retry disable */
  26#define  BCM54140_RDB_SPARE2_WS_RTRY_LIMIT GENMASK(4, 2) /* retry limit */
  27#define BCM54140_RDB_SPARE3             0x015   /* spare control 3 */
  28#define  BCM54140_RDB_SPARE3_BIT0       BIT(0)
  29#define BCM54140_RDB_LED_CTRL           0x019   /* LED control */
  30#define  BCM54140_RDB_LED_CTRL_ACTLINK0 BIT(4)
  31#define  BCM54140_RDB_LED_CTRL_ACTLINK1 BIT(8)
  32#define BCM54140_RDB_C_APWR             0x01a   /* auto power down control */
  33#define  BCM54140_RDB_C_APWR_SINGLE_PULSE       BIT(8)  /* single pulse */
  34#define  BCM54140_RDB_C_APWR_APD_MODE_DIS       0 /* ADP disable */
  35#define  BCM54140_RDB_C_APWR_APD_MODE_EN        1 /* ADP enable */
  36#define  BCM54140_RDB_C_APWR_APD_MODE_DIS2      2 /* ADP disable */
  37#define  BCM54140_RDB_C_APWR_APD_MODE_EN_ANEG   3 /* ADP enable w/ aneg */
  38#define  BCM54140_RDB_C_APWR_APD_MODE_MASK      GENMASK(6, 5)
  39#define  BCM54140_RDB_C_APWR_SLP_TIM_MASK BIT(4)/* sleep timer */
  40#define  BCM54140_RDB_C_APWR_SLP_TIM_2_7 0      /* 2.7s */
  41#define  BCM54140_RDB_C_APWR_SLP_TIM_5_4 1      /* 5.4s */
  42#define BCM54140_RDB_C_PWR              0x02a   /* copper power control */
  43#define  BCM54140_RDB_C_PWR_ISOLATE     BIT(5)  /* super isolate mode */
  44#define BCM54140_RDB_C_MISC_CTRL        0x02f   /* misc copper control */
  45#define  BCM54140_RDB_C_MISC_CTRL_WS_EN BIT(4)  /* wirespeed enable */
  46
  47/* RDB global registers
  48 */
  49#define BCM54140_RDB_TOP_IMR            0x82d   /* interrupt mask */
  50#define  BCM54140_RDB_TOP_IMR_PORT0     BIT(4)
  51#define  BCM54140_RDB_TOP_IMR_PORT1     BIT(5)
  52#define  BCM54140_RDB_TOP_IMR_PORT2     BIT(6)
  53#define  BCM54140_RDB_TOP_IMR_PORT3     BIT(7)
  54#define BCM54140_RDB_MON_CTRL           0x831   /* monitor control */
  55#define  BCM54140_RDB_MON_CTRL_V_MODE   BIT(3)  /* voltage mode */
  56#define  BCM54140_RDB_MON_CTRL_SEL_MASK GENMASK(2, 1)
  57#define  BCM54140_RDB_MON_CTRL_SEL_TEMP 0       /* meassure temperature */
  58#define  BCM54140_RDB_MON_CTRL_SEL_1V0  1       /* meassure AVDDL 1.0V */
  59#define  BCM54140_RDB_MON_CTRL_SEL_3V3  2       /* meassure AVDDH 3.3V */
  60#define  BCM54140_RDB_MON_CTRL_SEL_RR   3       /* meassure all round-robin */
  61#define  BCM54140_RDB_MON_CTRL_PWR_DOWN BIT(0)  /* power-down monitor */
  62#define BCM54140_RDB_MON_TEMP_VAL       0x832   /* temperature value */
  63#define BCM54140_RDB_MON_TEMP_MAX       0x833   /* temperature high thresh */
  64#define BCM54140_RDB_MON_TEMP_MIN       0x834   /* temperature low thresh */
  65#define  BCM54140_RDB_MON_TEMP_DATA_MASK GENMASK(9, 0)
  66#define BCM54140_RDB_MON_1V0_VAL        0x835   /* AVDDL 1.0V value */
  67#define BCM54140_RDB_MON_1V0_MAX        0x836   /* AVDDL 1.0V high thresh */
  68#define BCM54140_RDB_MON_1V0_MIN        0x837   /* AVDDL 1.0V low thresh */
  69#define  BCM54140_RDB_MON_1V0_DATA_MASK GENMASK(10, 0)
  70#define BCM54140_RDB_MON_3V3_VAL        0x838   /* AVDDH 3.3V value */
  71#define BCM54140_RDB_MON_3V3_MAX        0x839   /* AVDDH 3.3V high thresh */
  72#define BCM54140_RDB_MON_3V3_MIN        0x83a   /* AVDDH 3.3V low thresh */
  73#define  BCM54140_RDB_MON_3V3_DATA_MASK GENMASK(11, 0)
  74#define BCM54140_RDB_MON_ISR            0x83b   /* interrupt status */
  75#define  BCM54140_RDB_MON_ISR_3V3       BIT(2)  /* AVDDH 3.3V alarm */
  76#define  BCM54140_RDB_MON_ISR_1V0       BIT(1)  /* AVDDL 1.0V alarm */
  77#define  BCM54140_RDB_MON_ISR_TEMP      BIT(0)  /* temperature alarm */
  78
  79/* According to the datasheet the formula is:
  80 *   T = 413.35 - (0.49055 * bits[9:0])
  81 */
  82#define BCM54140_HWMON_TO_TEMP(v) (413350L - (v) * 491)
  83#define BCM54140_HWMON_FROM_TEMP(v) DIV_ROUND_CLOSEST_ULL(413350L - (v), 491)
  84
  85/* According to the datasheet the formula is:
  86 *   U = bits[11:0] / 1024 * 220 / 0.2
  87 *
  88 * Normalized:
  89 *   U = bits[11:0] / 4096 * 2514
  90 */
  91#define BCM54140_HWMON_TO_IN_1V0(v) ((v) * 2514 >> 11)
  92#define BCM54140_HWMON_FROM_IN_1V0(v) DIV_ROUND_CLOSEST_ULL(((v) << 11), 2514)
  93
  94/* According to the datasheet the formula is:
  95 *   U = bits[10:0] / 1024 * 880 / 0.7
  96 *
  97 * Normalized:
  98 *   U = bits[10:0] / 2048 * 4400
  99 */
 100#define BCM54140_HWMON_TO_IN_3V3(v) ((v) * 4400 >> 12)
 101#define BCM54140_HWMON_FROM_IN_3V3(v) DIV_ROUND_CLOSEST_ULL(((v) << 12), 4400)
 102
 103#define BCM54140_HWMON_TO_IN(ch, v) ((ch) ? BCM54140_HWMON_TO_IN_3V3(v) \
 104                                          : BCM54140_HWMON_TO_IN_1V0(v))
 105#define BCM54140_HWMON_FROM_IN(ch, v) ((ch) ? BCM54140_HWMON_FROM_IN_3V3(v) \
 106                                            : BCM54140_HWMON_FROM_IN_1V0(v))
 107#define BCM54140_HWMON_IN_MASK(ch) ((ch) ? BCM54140_RDB_MON_3V3_DATA_MASK \
 108                                         : BCM54140_RDB_MON_1V0_DATA_MASK)
 109#define BCM54140_HWMON_IN_VAL_REG(ch) ((ch) ? BCM54140_RDB_MON_3V3_VAL \
 110                                            : BCM54140_RDB_MON_1V0_VAL)
 111#define BCM54140_HWMON_IN_MIN_REG(ch) ((ch) ? BCM54140_RDB_MON_3V3_MIN \
 112                                            : BCM54140_RDB_MON_1V0_MIN)
 113#define BCM54140_HWMON_IN_MAX_REG(ch) ((ch) ? BCM54140_RDB_MON_3V3_MAX \
 114                                            : BCM54140_RDB_MON_1V0_MAX)
 115#define BCM54140_HWMON_IN_ALARM_BIT(ch) ((ch) ? BCM54140_RDB_MON_ISR_3V3 \
 116                                              : BCM54140_RDB_MON_ISR_1V0)
 117
 118/* This PHY has two different PHY IDs depening on its MODE_SEL pin. This
 119 * pin choses between 4x SGMII and QSGMII mode:
 120 *   AE02_5009 4x SGMII
 121 *   AE02_5019 QSGMII
 122 */
 123#define BCM54140_PHY_ID_MASK    0xffffffe8
 124
 125#define BCM54140_PHY_ID_REV(phy_id)     ((phy_id) & 0x7)
 126#define BCM54140_REV_B0                 1
 127
 128#define BCM54140_DEFAULT_DOWNSHIFT 5
 129#define BCM54140_MAX_DOWNSHIFT 9
 130
 131struct bcm54140_priv {
 132        int port;
 133        int base_addr;
 134#if IS_ENABLED(CONFIG_HWMON)
 135        /* protect the alarm bits */
 136        struct mutex alarm_lock;
 137        u16 alarm;
 138#endif
 139};
 140
 141#if IS_ENABLED(CONFIG_HWMON)
 142static umode_t bcm54140_hwmon_is_visible(const void *data,
 143                                         enum hwmon_sensor_types type,
 144                                         u32 attr, int channel)
 145{
 146        switch (type) {
 147        case hwmon_in:
 148                switch (attr) {
 149                case hwmon_in_min:
 150                case hwmon_in_max:
 151                        return 0644;
 152                case hwmon_in_label:
 153                case hwmon_in_input:
 154                case hwmon_in_alarm:
 155                        return 0444;
 156                default:
 157                        return 0;
 158                }
 159        case hwmon_temp:
 160                switch (attr) {
 161                case hwmon_temp_min:
 162                case hwmon_temp_max:
 163                        return 0644;
 164                case hwmon_temp_input:
 165                case hwmon_temp_alarm:
 166                        return 0444;
 167                default:
 168                        return 0;
 169                }
 170        default:
 171                return 0;
 172        }
 173}
 174
 175static int bcm54140_hwmon_read_alarm(struct device *dev, unsigned int bit,
 176                                     long *val)
 177{
 178        struct phy_device *phydev = dev_get_drvdata(dev);
 179        struct bcm54140_priv *priv = phydev->priv;
 180        int tmp, ret = 0;
 181
 182        mutex_lock(&priv->alarm_lock);
 183
 184        /* latch any alarm bits */
 185        tmp = bcm_phy_read_rdb(phydev, BCM54140_RDB_MON_ISR);
 186        if (tmp < 0) {
 187                ret = tmp;
 188                goto out;
 189        }
 190        priv->alarm |= tmp;
 191
 192        *val = !!(priv->alarm & bit);
 193        priv->alarm &= ~bit;
 194
 195out:
 196        mutex_unlock(&priv->alarm_lock);
 197        return ret;
 198}
 199
 200static int bcm54140_hwmon_read_temp(struct device *dev, u32 attr, long *val)
 201{
 202        struct phy_device *phydev = dev_get_drvdata(dev);
 203        u16 reg;
 204        int tmp;
 205
 206        switch (attr) {
 207        case hwmon_temp_input:
 208                reg = BCM54140_RDB_MON_TEMP_VAL;
 209                break;
 210        case hwmon_temp_min:
 211                reg = BCM54140_RDB_MON_TEMP_MIN;
 212                break;
 213        case hwmon_temp_max:
 214                reg = BCM54140_RDB_MON_TEMP_MAX;
 215                break;
 216        case hwmon_temp_alarm:
 217                return bcm54140_hwmon_read_alarm(dev,
 218                                                 BCM54140_RDB_MON_ISR_TEMP,
 219                                                 val);
 220        default:
 221                return -EOPNOTSUPP;
 222        }
 223
 224        tmp = bcm_phy_read_rdb(phydev, reg);
 225        if (tmp < 0)
 226                return tmp;
 227
 228        *val = BCM54140_HWMON_TO_TEMP(tmp & BCM54140_RDB_MON_TEMP_DATA_MASK);
 229
 230        return 0;
 231}
 232
 233static int bcm54140_hwmon_read_in(struct device *dev, u32 attr,
 234                                  int channel, long *val)
 235{
 236        struct phy_device *phydev = dev_get_drvdata(dev);
 237        u16 bit, reg;
 238        int tmp;
 239
 240        switch (attr) {
 241        case hwmon_in_input:
 242                reg = BCM54140_HWMON_IN_VAL_REG(channel);
 243                break;
 244        case hwmon_in_min:
 245                reg = BCM54140_HWMON_IN_MIN_REG(channel);
 246                break;
 247        case hwmon_in_max:
 248                reg = BCM54140_HWMON_IN_MAX_REG(channel);
 249                break;
 250        case hwmon_in_alarm:
 251                bit = BCM54140_HWMON_IN_ALARM_BIT(channel);
 252                return bcm54140_hwmon_read_alarm(dev, bit, val);
 253        default:
 254                return -EOPNOTSUPP;
 255        }
 256
 257        tmp = bcm_phy_read_rdb(phydev, reg);
 258        if (tmp < 0)
 259                return tmp;
 260
 261        tmp &= BCM54140_HWMON_IN_MASK(channel);
 262        *val = BCM54140_HWMON_TO_IN(channel, tmp);
 263
 264        return 0;
 265}
 266
 267static int bcm54140_hwmon_read(struct device *dev,
 268                               enum hwmon_sensor_types type, u32 attr,
 269                               int channel, long *val)
 270{
 271        switch (type) {
 272        case hwmon_temp:
 273                return bcm54140_hwmon_read_temp(dev, attr, val);
 274        case hwmon_in:
 275                return bcm54140_hwmon_read_in(dev, attr, channel, val);
 276        default:
 277                return -EOPNOTSUPP;
 278        }
 279}
 280
 281static const char *const bcm54140_hwmon_in_labels[] = {
 282        "AVDDL",
 283        "AVDDH",
 284};
 285
 286static int bcm54140_hwmon_read_string(struct device *dev,
 287                                      enum hwmon_sensor_types type, u32 attr,
 288                                      int channel, const char **str)
 289{
 290        switch (type) {
 291        case hwmon_in:
 292                switch (attr) {
 293                case hwmon_in_label:
 294                        *str = bcm54140_hwmon_in_labels[channel];
 295                        return 0;
 296                default:
 297                        return -EOPNOTSUPP;
 298                }
 299        default:
 300                return -EOPNOTSUPP;
 301        }
 302}
 303
 304static int bcm54140_hwmon_write_temp(struct device *dev, u32 attr,
 305                                     int channel, long val)
 306{
 307        struct phy_device *phydev = dev_get_drvdata(dev);
 308        u16 mask = BCM54140_RDB_MON_TEMP_DATA_MASK;
 309        u16 reg;
 310
 311        val = clamp_val(val, BCM54140_HWMON_TO_TEMP(mask),
 312                        BCM54140_HWMON_TO_TEMP(0));
 313
 314        switch (attr) {
 315        case hwmon_temp_min:
 316                reg = BCM54140_RDB_MON_TEMP_MIN;
 317                break;
 318        case hwmon_temp_max:
 319                reg = BCM54140_RDB_MON_TEMP_MAX;
 320                break;
 321        default:
 322                return -EOPNOTSUPP;
 323        }
 324
 325        return bcm_phy_modify_rdb(phydev, reg, mask,
 326                                  BCM54140_HWMON_FROM_TEMP(val));
 327}
 328
 329static int bcm54140_hwmon_write_in(struct device *dev, u32 attr,
 330                                   int channel, long val)
 331{
 332        struct phy_device *phydev = dev_get_drvdata(dev);
 333        u16 mask = BCM54140_HWMON_IN_MASK(channel);
 334        u16 reg;
 335
 336        val = clamp_val(val, 0, BCM54140_HWMON_TO_IN(channel, mask));
 337
 338        switch (attr) {
 339        case hwmon_in_min:
 340                reg = BCM54140_HWMON_IN_MIN_REG(channel);
 341                break;
 342        case hwmon_in_max:
 343                reg = BCM54140_HWMON_IN_MAX_REG(channel);
 344                break;
 345        default:
 346                return -EOPNOTSUPP;
 347        }
 348
 349        return bcm_phy_modify_rdb(phydev, reg, mask,
 350                                  BCM54140_HWMON_FROM_IN(channel, val));
 351}
 352
 353static int bcm54140_hwmon_write(struct device *dev,
 354                                enum hwmon_sensor_types type, u32 attr,
 355                                int channel, long val)
 356{
 357        switch (type) {
 358        case hwmon_temp:
 359                return bcm54140_hwmon_write_temp(dev, attr, channel, val);
 360        case hwmon_in:
 361                return bcm54140_hwmon_write_in(dev, attr, channel, val);
 362        default:
 363                return -EOPNOTSUPP;
 364        }
 365}
 366
 367static const struct hwmon_channel_info *bcm54140_hwmon_info[] = {
 368        HWMON_CHANNEL_INFO(temp,
 369                           HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX |
 370                           HWMON_T_ALARM),
 371        HWMON_CHANNEL_INFO(in,
 372                           HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
 373                           HWMON_I_ALARM | HWMON_I_LABEL,
 374                           HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
 375                           HWMON_I_ALARM | HWMON_I_LABEL),
 376        NULL
 377};
 378
 379static const struct hwmon_ops bcm54140_hwmon_ops = {
 380        .is_visible = bcm54140_hwmon_is_visible,
 381        .read = bcm54140_hwmon_read,
 382        .read_string = bcm54140_hwmon_read_string,
 383        .write = bcm54140_hwmon_write,
 384};
 385
 386static const struct hwmon_chip_info bcm54140_chip_info = {
 387        .ops = &bcm54140_hwmon_ops,
 388        .info = bcm54140_hwmon_info,
 389};
 390
 391static int bcm54140_enable_monitoring(struct phy_device *phydev)
 392{
 393        u16 mask, set;
 394
 395        /* 3.3V voltage mode */
 396        set = BCM54140_RDB_MON_CTRL_V_MODE;
 397
 398        /* select round-robin */
 399        mask = BCM54140_RDB_MON_CTRL_SEL_MASK;
 400        set |= FIELD_PREP(BCM54140_RDB_MON_CTRL_SEL_MASK,
 401                          BCM54140_RDB_MON_CTRL_SEL_RR);
 402
 403        /* remove power-down bit */
 404        mask |= BCM54140_RDB_MON_CTRL_PWR_DOWN;
 405
 406        return bcm_phy_modify_rdb(phydev, BCM54140_RDB_MON_CTRL, mask, set);
 407}
 408
 409static int bcm54140_probe_once(struct phy_device *phydev)
 410{
 411        struct device *hwmon;
 412        int ret;
 413
 414        /* enable hardware monitoring */
 415        ret = bcm54140_enable_monitoring(phydev);
 416        if (ret)
 417                return ret;
 418
 419        hwmon = devm_hwmon_device_register_with_info(&phydev->mdio.dev,
 420                                                     "BCM54140", phydev,
 421                                                     &bcm54140_chip_info,
 422                                                     NULL);
 423        return PTR_ERR_OR_ZERO(hwmon);
 424}
 425#endif
 426
 427static int bcm54140_base_read_rdb(struct phy_device *phydev, u16 rdb)
 428{
 429        int ret;
 430
 431        phy_lock_mdio_bus(phydev);
 432        ret = __phy_package_write(phydev, MII_BCM54XX_RDB_ADDR, rdb);
 433        if (ret < 0)
 434                goto out;
 435
 436        ret = __phy_package_read(phydev, MII_BCM54XX_RDB_DATA);
 437
 438out:
 439        phy_unlock_mdio_bus(phydev);
 440        return ret;
 441}
 442
 443static int bcm54140_base_write_rdb(struct phy_device *phydev,
 444                                   u16 rdb, u16 val)
 445{
 446        int ret;
 447
 448        phy_lock_mdio_bus(phydev);
 449        ret = __phy_package_write(phydev, MII_BCM54XX_RDB_ADDR, rdb);
 450        if (ret < 0)
 451                goto out;
 452
 453        ret = __phy_package_write(phydev, MII_BCM54XX_RDB_DATA, val);
 454
 455out:
 456        phy_unlock_mdio_bus(phydev);
 457        return ret;
 458}
 459
 460/* Under some circumstances a core PLL may not lock, this will then prevent
 461 * a successful link establishment. Restart the PLL after the voltages are
 462 * stable to workaround this issue.
 463 */
 464static int bcm54140_b0_workaround(struct phy_device *phydev)
 465{
 466        int spare3;
 467        int ret;
 468
 469        spare3 = bcm_phy_read_rdb(phydev, BCM54140_RDB_SPARE3);
 470        if (spare3 < 0)
 471                return spare3;
 472
 473        spare3 &= ~BCM54140_RDB_SPARE3_BIT0;
 474
 475        ret = bcm_phy_write_rdb(phydev, BCM54140_RDB_SPARE3, spare3);
 476        if (ret)
 477                return ret;
 478
 479        ret = phy_modify(phydev, MII_BMCR, 0, BMCR_PDOWN);
 480        if (ret)
 481                return ret;
 482
 483        ret = phy_modify(phydev, MII_BMCR, BMCR_PDOWN, 0);
 484        if (ret)
 485                return ret;
 486
 487        spare3 |= BCM54140_RDB_SPARE3_BIT0;
 488
 489        return bcm_phy_write_rdb(phydev, BCM54140_RDB_SPARE3, spare3);
 490}
 491
 492/* The BCM54140 is a quad PHY where only the first port has access to the
 493 * global register. Thus we need to find out its PHY address.
 494 *
 495 */
 496static int bcm54140_get_base_addr_and_port(struct phy_device *phydev)
 497{
 498        struct bcm54140_priv *priv = phydev->priv;
 499        struct mii_bus *bus = phydev->mdio.bus;
 500        int addr, min_addr, max_addr;
 501        int step = 1;
 502        u32 phy_id;
 503        int tmp;
 504
 505        min_addr = phydev->mdio.addr;
 506        max_addr = phydev->mdio.addr;
 507        addr = phydev->mdio.addr;
 508
 509        /* We scan forward and backwards and look for PHYs which have the
 510         * same phy_id like we do. Step 1 will scan forward, step 2
 511         * backwards. Once we are finished, we have a min_addr and
 512         * max_addr which resembles the range of PHY addresses of the same
 513         * type of PHY. There is one caveat; there may be many PHYs of
 514         * the same type, but we know that each PHY takes exactly 4
 515         * consecutive addresses. Therefore we can deduce our offset
 516         * to the base address of this quad PHY.
 517         */
 518
 519        while (1) {
 520                if (step == 3) {
 521                        break;
 522                } else if (step == 1) {
 523                        max_addr = addr;
 524                        addr++;
 525                } else {
 526                        min_addr = addr;
 527                        addr--;
 528                }
 529
 530                if (addr < 0 || addr >= PHY_MAX_ADDR) {
 531                        addr = phydev->mdio.addr;
 532                        step++;
 533                        continue;
 534                }
 535
 536                /* read the PHY id */
 537                tmp = mdiobus_read(bus, addr, MII_PHYSID1);
 538                if (tmp < 0)
 539                        return tmp;
 540                phy_id = tmp << 16;
 541                tmp = mdiobus_read(bus, addr, MII_PHYSID2);
 542                if (tmp < 0)
 543                        return tmp;
 544                phy_id |= tmp;
 545
 546                /* see if it is still the same PHY */
 547                if ((phy_id & phydev->drv->phy_id_mask) !=
 548                    (phydev->drv->phy_id & phydev->drv->phy_id_mask)) {
 549                        addr = phydev->mdio.addr;
 550                        step++;
 551                }
 552        }
 553
 554        /* The range we get should be a multiple of four. Please note that both
 555         * the min_addr and max_addr are inclusive. So we have to add one if we
 556         * subtract them.
 557         */
 558        if ((max_addr - min_addr + 1) % 4) {
 559                dev_err(&phydev->mdio.dev,
 560                        "Detected Quad PHY IDs %d..%d doesn't make sense.\n",
 561                        min_addr, max_addr);
 562                return -EINVAL;
 563        }
 564
 565        priv->port = (phydev->mdio.addr - min_addr) % 4;
 566        priv->base_addr = phydev->mdio.addr - priv->port;
 567
 568        return 0;
 569}
 570
 571static int bcm54140_probe(struct phy_device *phydev)
 572{
 573        struct bcm54140_priv *priv;
 574        int ret;
 575
 576        priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL);
 577        if (!priv)
 578                return -ENOMEM;
 579
 580        phydev->priv = priv;
 581
 582        ret = bcm54140_get_base_addr_and_port(phydev);
 583        if (ret)
 584                return ret;
 585
 586        devm_phy_package_join(&phydev->mdio.dev, phydev, priv->base_addr, 0);
 587
 588#if IS_ENABLED(CONFIG_HWMON)
 589        mutex_init(&priv->alarm_lock);
 590
 591        if (phy_package_init_once(phydev)) {
 592                ret = bcm54140_probe_once(phydev);
 593                if (ret)
 594                        return ret;
 595        }
 596#endif
 597
 598        phydev_dbg(phydev, "probed (port %d, base PHY address %d)\n",
 599                   priv->port, priv->base_addr);
 600
 601        return 0;
 602}
 603
 604static int bcm54140_config_init(struct phy_device *phydev)
 605{
 606        u16 reg = 0xffff;
 607        int ret;
 608
 609        /* Apply hardware errata */
 610        if (BCM54140_PHY_ID_REV(phydev->phy_id) == BCM54140_REV_B0) {
 611                ret = bcm54140_b0_workaround(phydev);
 612                if (ret)
 613                        return ret;
 614        }
 615
 616        /* Unmask events we are interested in. */
 617        reg &= ~(BCM54140_RDB_INT_DUPLEX |
 618                 BCM54140_RDB_INT_SPEED |
 619                 BCM54140_RDB_INT_LINK);
 620        ret = bcm_phy_write_rdb(phydev, BCM54140_RDB_IMR, reg);
 621        if (ret)
 622                return ret;
 623
 624        /* LED1=LINKSPD[1], LED2=LINKSPD[2], LED3=LINK/ACTIVITY */
 625        ret = bcm_phy_modify_rdb(phydev, BCM54140_RDB_SPARE1,
 626                                 0, BCM54140_RDB_SPARE1_LSLM);
 627        if (ret)
 628                return ret;
 629
 630        ret = bcm_phy_modify_rdb(phydev, BCM54140_RDB_LED_CTRL,
 631                                 0, BCM54140_RDB_LED_CTRL_ACTLINK0);
 632        if (ret)
 633                return ret;
 634
 635        /* disable super isolate mode */
 636        return bcm_phy_modify_rdb(phydev, BCM54140_RDB_C_PWR,
 637                                  BCM54140_RDB_C_PWR_ISOLATE, 0);
 638}
 639
 640static irqreturn_t bcm54140_handle_interrupt(struct phy_device *phydev)
 641{
 642        int irq_status, irq_mask;
 643
 644        irq_status = bcm_phy_read_rdb(phydev, BCM54140_RDB_ISR);
 645        if (irq_status < 0) {
 646                phy_error(phydev);
 647                return IRQ_NONE;
 648        }
 649
 650        irq_mask = bcm_phy_read_rdb(phydev, BCM54140_RDB_IMR);
 651        if (irq_mask < 0) {
 652                phy_error(phydev);
 653                return IRQ_NONE;
 654        }
 655        irq_mask = ~irq_mask;
 656
 657        if (!(irq_status & irq_mask))
 658                return IRQ_NONE;
 659
 660        phy_trigger_machine(phydev);
 661
 662        return IRQ_HANDLED;
 663}
 664
 665static int bcm54140_ack_intr(struct phy_device *phydev)
 666{
 667        int reg;
 668
 669        /* clear pending interrupts */
 670        reg = bcm_phy_read_rdb(phydev, BCM54140_RDB_ISR);
 671        if (reg < 0)
 672                return reg;
 673
 674        return 0;
 675}
 676
 677static int bcm54140_config_intr(struct phy_device *phydev)
 678{
 679        struct bcm54140_priv *priv = phydev->priv;
 680        static const u16 port_to_imr_bit[] = {
 681                BCM54140_RDB_TOP_IMR_PORT0, BCM54140_RDB_TOP_IMR_PORT1,
 682                BCM54140_RDB_TOP_IMR_PORT2, BCM54140_RDB_TOP_IMR_PORT3,
 683        };
 684        int reg, err;
 685
 686        if (priv->port >= ARRAY_SIZE(port_to_imr_bit))
 687                return -EINVAL;
 688
 689        reg = bcm54140_base_read_rdb(phydev, BCM54140_RDB_TOP_IMR);
 690        if (reg < 0)
 691                return reg;
 692
 693        if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
 694                err = bcm54140_ack_intr(phydev);
 695                if (err)
 696                        return err;
 697
 698                reg &= ~port_to_imr_bit[priv->port];
 699                err = bcm54140_base_write_rdb(phydev, BCM54140_RDB_TOP_IMR, reg);
 700        } else {
 701                reg |= port_to_imr_bit[priv->port];
 702                err = bcm54140_base_write_rdb(phydev, BCM54140_RDB_TOP_IMR, reg);
 703                if (err)
 704                        return err;
 705
 706                err = bcm54140_ack_intr(phydev);
 707        }
 708
 709        return err;
 710}
 711
 712static int bcm54140_get_downshift(struct phy_device *phydev, u8 *data)
 713{
 714        int val;
 715
 716        val = bcm_phy_read_rdb(phydev, BCM54140_RDB_C_MISC_CTRL);
 717        if (val < 0)
 718                return val;
 719
 720        if (!(val & BCM54140_RDB_C_MISC_CTRL_WS_EN)) {
 721                *data = DOWNSHIFT_DEV_DISABLE;
 722                return 0;
 723        }
 724
 725        val = bcm_phy_read_rdb(phydev, BCM54140_RDB_SPARE2);
 726        if (val < 0)
 727                return val;
 728
 729        if (val & BCM54140_RDB_SPARE2_WS_RTRY_DIS)
 730                *data = 1;
 731        else
 732                *data = FIELD_GET(BCM54140_RDB_SPARE2_WS_RTRY_LIMIT, val) + 2;
 733
 734        return 0;
 735}
 736
 737static int bcm54140_set_downshift(struct phy_device *phydev, u8 cnt)
 738{
 739        u16 mask, set;
 740        int ret;
 741
 742        if (cnt > BCM54140_MAX_DOWNSHIFT && cnt != DOWNSHIFT_DEV_DEFAULT_COUNT)
 743                return -EINVAL;
 744
 745        if (!cnt)
 746                return bcm_phy_modify_rdb(phydev, BCM54140_RDB_C_MISC_CTRL,
 747                                          BCM54140_RDB_C_MISC_CTRL_WS_EN, 0);
 748
 749        if (cnt == DOWNSHIFT_DEV_DEFAULT_COUNT)
 750                cnt = BCM54140_DEFAULT_DOWNSHIFT;
 751
 752        if (cnt == 1) {
 753                mask = 0;
 754                set = BCM54140_RDB_SPARE2_WS_RTRY_DIS;
 755        } else {
 756                mask = BCM54140_RDB_SPARE2_WS_RTRY_DIS;
 757                mask |= BCM54140_RDB_SPARE2_WS_RTRY_LIMIT;
 758                set = FIELD_PREP(BCM54140_RDB_SPARE2_WS_RTRY_LIMIT, cnt - 2);
 759        }
 760        ret = bcm_phy_modify_rdb(phydev, BCM54140_RDB_SPARE2,
 761                                 mask, set);
 762        if (ret)
 763                return ret;
 764
 765        return bcm_phy_modify_rdb(phydev, BCM54140_RDB_C_MISC_CTRL,
 766                                  0, BCM54140_RDB_C_MISC_CTRL_WS_EN);
 767}
 768
 769static int bcm54140_get_edpd(struct phy_device *phydev, u16 *tx_interval)
 770{
 771        int val;
 772
 773        val = bcm_phy_read_rdb(phydev, BCM54140_RDB_C_APWR);
 774        if (val < 0)
 775                return val;
 776
 777        switch (FIELD_GET(BCM54140_RDB_C_APWR_APD_MODE_MASK, val)) {
 778        case BCM54140_RDB_C_APWR_APD_MODE_DIS:
 779        case BCM54140_RDB_C_APWR_APD_MODE_DIS2:
 780                *tx_interval = ETHTOOL_PHY_EDPD_DISABLE;
 781                break;
 782        case BCM54140_RDB_C_APWR_APD_MODE_EN:
 783        case BCM54140_RDB_C_APWR_APD_MODE_EN_ANEG:
 784                switch (FIELD_GET(BCM54140_RDB_C_APWR_SLP_TIM_MASK, val)) {
 785                case BCM54140_RDB_C_APWR_SLP_TIM_2_7:
 786                        *tx_interval = 2700;
 787                        break;
 788                case BCM54140_RDB_C_APWR_SLP_TIM_5_4:
 789                        *tx_interval = 5400;
 790                        break;
 791                }
 792        }
 793
 794        return 0;
 795}
 796
 797static int bcm54140_set_edpd(struct phy_device *phydev, u16 tx_interval)
 798{
 799        u16 mask, set;
 800
 801        mask = BCM54140_RDB_C_APWR_APD_MODE_MASK;
 802        if (tx_interval == ETHTOOL_PHY_EDPD_DISABLE)
 803                set = FIELD_PREP(BCM54140_RDB_C_APWR_APD_MODE_MASK,
 804                                 BCM54140_RDB_C_APWR_APD_MODE_DIS);
 805        else
 806                set = FIELD_PREP(BCM54140_RDB_C_APWR_APD_MODE_MASK,
 807                                 BCM54140_RDB_C_APWR_APD_MODE_EN_ANEG);
 808
 809        /* enable single pulse mode */
 810        set |= BCM54140_RDB_C_APWR_SINGLE_PULSE;
 811
 812        /* set sleep timer */
 813        mask |= BCM54140_RDB_C_APWR_SLP_TIM_MASK;
 814        switch (tx_interval) {
 815        case ETHTOOL_PHY_EDPD_DFLT_TX_MSECS:
 816        case ETHTOOL_PHY_EDPD_DISABLE:
 817        case 2700:
 818                set |= BCM54140_RDB_C_APWR_SLP_TIM_2_7;
 819                break;
 820        case 5400:
 821                set |= BCM54140_RDB_C_APWR_SLP_TIM_5_4;
 822                break;
 823        default:
 824                return -EINVAL;
 825        }
 826
 827        return bcm_phy_modify_rdb(phydev, BCM54140_RDB_C_APWR, mask, set);
 828}
 829
 830static int bcm54140_get_tunable(struct phy_device *phydev,
 831                                struct ethtool_tunable *tuna, void *data)
 832{
 833        switch (tuna->id) {
 834        case ETHTOOL_PHY_DOWNSHIFT:
 835                return bcm54140_get_downshift(phydev, data);
 836        case ETHTOOL_PHY_EDPD:
 837                return bcm54140_get_edpd(phydev, data);
 838        default:
 839                return -EOPNOTSUPP;
 840        }
 841}
 842
 843static int bcm54140_set_tunable(struct phy_device *phydev,
 844                                struct ethtool_tunable *tuna, const void *data)
 845{
 846        switch (tuna->id) {
 847        case ETHTOOL_PHY_DOWNSHIFT:
 848                return bcm54140_set_downshift(phydev, *(const u8 *)data);
 849        case ETHTOOL_PHY_EDPD:
 850                return bcm54140_set_edpd(phydev, *(const u16 *)data);
 851        default:
 852                return -EOPNOTSUPP;
 853        }
 854}
 855
 856static struct phy_driver bcm54140_drivers[] = {
 857        {
 858                .phy_id         = PHY_ID_BCM54140,
 859                .phy_id_mask    = BCM54140_PHY_ID_MASK,
 860                .name           = "Broadcom BCM54140",
 861                .flags          = PHY_POLL_CABLE_TEST,
 862                .features       = PHY_GBIT_FEATURES,
 863                .config_init    = bcm54140_config_init,
 864                .handle_interrupt = bcm54140_handle_interrupt,
 865                .config_intr    = bcm54140_config_intr,
 866                .probe          = bcm54140_probe,
 867                .suspend        = genphy_suspend,
 868                .resume         = genphy_resume,
 869                .soft_reset     = genphy_soft_reset,
 870                .get_tunable    = bcm54140_get_tunable,
 871                .set_tunable    = bcm54140_set_tunable,
 872                .cable_test_start = bcm_phy_cable_test_start_rdb,
 873                .cable_test_get_status = bcm_phy_cable_test_get_status_rdb,
 874        },
 875};
 876module_phy_driver(bcm54140_drivers);
 877
 878static struct mdio_device_id __maybe_unused bcm54140_tbl[] = {
 879        { PHY_ID_BCM54140, BCM54140_PHY_ID_MASK },
 880        { }
 881};
 882
 883MODULE_AUTHOR("Michael Walle");
 884MODULE_DESCRIPTION("Broadcom BCM54140 PHY driver");
 885MODULE_DEVICE_TABLE(mdio, bcm54140_tbl);
 886MODULE_LICENSE("GPL");
 887