On 17.04.2019 15:34, kavyasree.kotag...@microchip.com wrote:
> From: Kavya Sree Kotagiri <kavyasree.kotag...@microchip.com>
> 
> The VSC8514 PHY is a 4-ports PHY that is 10/100/1000BASE-T, 100BASE-FX,
> 1000BASE-X, can communicate with the MAC via QSGMII.
> The MAC interface protocol for each port within QSGMII can
> be either 1000BASE-X or SGMII, if the QSGMII MAC that the VSC8514 is
> connecting to supports this functionality.
> VSC8514 also supports SGMII MAC-side autonegotiation on each individual
> port, downshifting, can set the blinking pattern of each of its 4 LEDs,
> SyncE, 1000BASE-T Ring Resiliency as well as HP Auto-MDIX detection.
> 
> This adds support for 10BASE-T, 100BASE-TX, and 1000BASE-T,
> QSGMII link with the MAC, downshifting, HP Auto-MDIX detection
> and blinking pattern for its 4 LEDs.
> 
> The GPIO register bank is a set of registers that are common to all PHYs
> in the package. So any modification in any register of this bank affects
> all PHYs of the package.
> 
> If the PHYs haven't been reset before booting the Linux kernel and were
> configured to use interrupts for e.g. link status updates, it is
> required to clear the interrupts mask register of all PHYs before being
> able to use interrupts with any PHY. The first PHY of the package that
> will be init will take care of clearing all PHYs interrupts mask
> registers. Thus, we need to keep track of the init sequence in the
> package, if it's already been done or if it's to be done.
> 
> Most of the init sequence of a PHY of the package is common to all PHYs
> in the package, thus we use the SMI broadcast feature which enables us
> to propagate a write in one register of one PHY to all PHYs in the same
> package.
> 
> Signed-off-by: Kavya Sree Kotagiri <kavyasree.kotag...@microchip.com>
> Signed-off-by: Quentin Schulz <quentin.sch...@bootlin.com>
> Co-developed-by: Quentin Schulz <quentin.sch...@bootlin.com>
> ---
> 
> Changes in v6:
> - Added proper return value in vsc85xx_csr_ctrl_phy_read().
> - Replaced __mdiobus_write and__mdiobus_read with __phy_write and __phy_read 
> resp.
> - Replaced register addresses in 8514_config_init() with proper constants.
> 
> Changes in v5:
> - Added return statements in functions calling vsc85xx_csr_ctrl_phy_read().
> - Added comments in vsc85xx_csr_ctrl_phy_read() and 
> vsc85xx_csr_ctrl_phy_write().
> 
> Changes in v4:
> - Removed features and aneg_done settings.
> 
> Changes in v3:
> - Used BIT(x) instead of hex values.
> - Replaced magic numbers with constants.
> - Handled delays and timeouts.
> - Added comments where needed.
> 
> Changes in v2:
> - Sorted variable declarations.
> 
>  drivers/net/phy/Kconfig |   2 +-
>  drivers/net/phy/mscc.c  | 471 ++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 472 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
> index 520657945b82..89085e87ecab 100644
> --- a/drivers/net/phy/Kconfig
> +++ b/drivers/net/phy/Kconfig
> @@ -397,7 +397,7 @@ config MICROCHIP_T1_PHY
>  config MICROSEMI_PHY
>       tristate "Microsemi PHYs"
>       ---help---
> -       Currently supports VSC8530, VSC8531, VSC8540 and VSC8541 PHYs
> +       Currently supports VSC8514, VSC8530, VSC8531, VSC8540 and VSC8541 PHYs
>  
>  config NATIONAL_PHY
>       tristate "National Semiconductor PHYs"
> diff --git a/drivers/net/phy/mscc.c b/drivers/net/phy/mscc.c
> index db50efb30df5..e71fef0f788a 100644
> --- a/drivers/net/phy/mscc.c
> +++ b/drivers/net/phy/mscc.c
> @@ -85,12 +85,48 @@ enum rgmii_rx_clock_delay {
>  #define LED_MODE_SEL_MASK(x)           (GENMASK(3, 0) << LED_MODE_SEL_POS(x))
>  #define LED_MODE_SEL(x, mode)                  (((mode) << 
> LED_MODE_SEL_POS(x)) & LED_MODE_SEL_MASK(x))
>  
> +#define MSCC_EXT_PAGE_CSR_CNTL_17           17
> +#define MSCC_EXT_PAGE_CSR_CNTL_18           18
> +
> +#define MSCC_EXT_PAGE_CSR_CNTL_19           19
> +#define MSCC_PHY_CSR_CNTL_19_REG_ADDR(x)    (x)
> +#define MSCC_PHY_CSR_CNTL_19_TARGET(x)      ((x) << 12)
> +#define MSCC_PHY_CSR_CNTL_19_READ           BIT(14)
> +#define MSCC_PHY_CSR_CNTL_19_CMD            BIT(15)
> +
> +#define MSCC_EXT_PAGE_CSR_CNTL_20           20
> +#define MSCC_PHY_CSR_CNTL_20_TARGET(x)      (x)
> +
> +#define PHY_MCB_TARGET                    0x07
> +#define PHY_MCB_S6G_WRITE                 BIT(31)
> +#define PHY_MCB_S6G_READ                  BIT(30)
> +
> +#define PHY_MCB_S6G_CFG                      0x3f
> +#define PHY_S6G_LCPLL_CFG            0x11
> +#define PHY_S6G_PLL5G_CFG0           0x06
> +#define PHY_S6G_PLL_CFG                      0x2b
> +#define PHY_S6G_PLL_STATUS           0x31
> +#define PHY_S6G_COMMON_CFG           0x2c
> +#define PHY_S6G_MISC_CFG             0x3b
> +#define PHY_S6G_GPC_CFG                      0x2e
> +#define PHY_S6G_IB_STATUS0           0x2f
> +
> +#define PHY_S6G_SYS_RST_POS            31
> +#define PHY_S6G_ENA_LANE_POS           18
> +#define PHY_S6G_ENA_LOOP_POS           8
> +#define PHY_S6G_QRATE_POS              6
> +#define PHY_S6G_IF_MODE_POS            4
> +#define PHY_S6G_PLL_ENA_OFFS_POS       21
> +#define PHY_S6G_PLL_FSM_CTRL_DATA_POS          8
> +#define PHY_S6G_PLL_FSM_ENA_POS                7
> +
>  #define MSCC_EXT_PAGE_ACCESS           31
>  #define MSCC_PHY_PAGE_STANDARD                 0x0000 /* Standard registers 
> */
>  #define MSCC_PHY_PAGE_EXTENDED                 0x0001 /* Extended registers 
> */
>  #define MSCC_PHY_PAGE_EXTENDED_2       0x0002 /* Extended reg - page 2 */
>  #define MSCC_PHY_PAGE_EXTENDED_3       0x0003 /* Extended reg - page 3 */
>  #define MSCC_PHY_PAGE_EXTENDED_4       0x0004 /* Extended reg - page 4 */
> +#define MSCC_PHY_PAGE_CSR_CNTL                 MSCC_PHY_PAGE_EXTENDED_4
>  /* Extended reg - GPIO; this is a bank of registers that are shared for all 
> PHYs
>   * in the same package.
>   */
> @@ -216,6 +252,7 @@ enum rgmii_rx_clock_delay {
>  #define MSCC_PHY_TR_MSB                        18
>  
>  /* Microsemi PHY ID's */
> +#define PHY_ID_VSC8514                         0x00070670
>  #define PHY_ID_VSC8530                         0x00070560
>  #define PHY_ID_VSC8531                         0x00070570
>  #define PHY_ID_VSC8540                         0x00070760
> @@ -1742,6 +1779,391 @@ static int vsc8584_did_interrupt(struct phy_device 
> *phydev)
>       return (rc < 0) ? 0 : rc & MII_VSC85XX_INT_MASK_MASK;
>  }
>  
> +static int vsc8514_config_pre_init(struct phy_device *phydev)
> +{
> +     /* These are the settings to override the silicon default
> +      * values to handle hardware performance of PHY. They
> +      * are set at Power-On state and remain until PHY Reset.
> +      */
> +     const struct reg_val pre_init1[] = {
> +             {0x0f90, 0x00688980},
> +             {0x0786, 0x00000003},
> +             {0x07fa, 0x0050100f},
> +             {0x0f82, 0x0012b002},
> +             {0x1686, 0x00000004},
> +             {0x168c, 0x00d2c46f},
> +             {0x17a2, 0x00000620},
> +             {0x16a0, 0x00eeffdd},
> +             {0x16a6, 0x00071448},
> +             {0x16a4, 0x0013132f},
> +             {0x16a8, 0x00000000},
> +             {0x0ffc, 0x00c0a028},
> +             {0x0fe8, 0x0091b06c},
> +             {0x0fea, 0x00041600},
> +             {0x0f80, 0x00fffaff},
> +             {0x0fec, 0x00901809},
> +             {0x0ffe, 0x00b01007},
> +             {0x16b0, 0x00eeff00},
> +             {0x16b2, 0x00007000},
> +             {0x16b4, 0x00000814},
> +     };
> +     unsigned int i;
> +     u16 reg;
> +
> +     phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
> +
> +     /* all writes below are broadcasted to all PHYs in the same package */
> +     reg = phy_base_read(phydev, MSCC_PHY_EXT_CNTL_STATUS);
> +     reg |= SMI_BROADCAST_WR_EN;
> +     phy_base_write(phydev, MSCC_PHY_EXT_CNTL_STATUS, reg);
> +
> +     phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TEST);
> +
> +     reg = phy_base_read(phydev, MSCC_PHY_TEST_PAGE_8);
> +     reg |= BIT(15);
> +     phy_base_write(phydev, MSCC_PHY_TEST_PAGE_8, reg);
> +
> +     phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TR);
> +
> +     for (i = 0; i < ARRAY_SIZE(pre_init1); i++)
> +             vsc8584_csr_write(phydev, pre_init1[i].reg, pre_init1[i].val);
> +
> +     phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TEST);
> +
> +     reg = phy_base_read(phydev, MSCC_PHY_TEST_PAGE_8);
> +     reg &= ~BIT(15);
> +     phy_base_write(phydev, MSCC_PHY_TEST_PAGE_8, reg);
> +
> +     phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
> +
> +     reg = phy_base_read(phydev, MSCC_PHY_EXT_CNTL_STATUS);
> +     reg &= ~SMI_BROADCAST_WR_EN;
> +     phy_base_write(phydev, MSCC_PHY_EXT_CNTL_STATUS, reg);
> +
> +     return 0;
> +}
> +
> +static u32 vsc85xx_csr_ctrl_phy_read(struct phy_device *phydev,
> +                                  u32 target, u32 reg)
> +{
> +     unsigned long deadline;
> +     u32 val, val_l, val_h;
> +
> +     phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_CSR_CNTL);
> +
> +     /* CSR registers are grouped under different Target IDs.
> +      * 6-bit Target_ID is split between MSCC_EXT_PAGE_CSR_CNTL_20 and
> +      * MSCC_EXT_PAGE_CSR_CNTL_19 registers.
> +      * Target_ID[5:2] maps to bits[3:0] of MSCC_EXT_PAGE_CSR_CNTL_20
> +      * and Target_ID[1:0] maps to bits[13:12] of MSCC_EXT_PAGE_CSR_CNTL_19.
> +      */
> +
> +     /* Setup the Target ID */
> +     phy_base_write(phydev, MSCC_EXT_PAGE_CSR_CNTL_20,
> +                    MSCC_PHY_CSR_CNTL_20_TARGET(target >> 2));
> +
> +     /* Trigger CSR Action - Read into the CSR's */
> +     phy_base_write(phydev, MSCC_EXT_PAGE_CSR_CNTL_19,
> +                    MSCC_PHY_CSR_CNTL_19_CMD | MSCC_PHY_CSR_CNTL_19_READ |
> +                    MSCC_PHY_CSR_CNTL_19_REG_ADDR(reg) |
> +                    MSCC_PHY_CSR_CNTL_19_TARGET(target & 0x3));
> +
> +     /* Wait for register access*/
> +     deadline = jiffies + msecs_to_jiffies(PROC_CMD_NCOMPLETED_TIMEOUT_MS);
> +     do {
> +             usleep_range(500, 1000);
> +             val = phy_base_read(phydev, MSCC_EXT_PAGE_CSR_CNTL_19);
> +     } while (time_before(jiffies, deadline) &&
> +             !(val & MSCC_PHY_CSR_CNTL_19_CMD));
> +
> +     if (!(val & MSCC_PHY_CSR_CNTL_19_CMD))
> +             return 0xffffffff;
> +
> +     /* Read the Least Significant Word (LSW) (17) */
> +     val_l = phy_base_read(phydev, MSCC_EXT_PAGE_CSR_CNTL_17);
> +
> +     /* Read the Most Significant Word (MSW) (18) */
> +     val_h = phy_base_read(phydev, MSCC_EXT_PAGE_CSR_CNTL_18);
> +
> +     phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,
> +                    MSCC_PHY_PAGE_STANDARD);
> +
> +     return (val_h << 16) | val_l;
> +}
> +
> +static int vsc85xx_csr_ctrl_phy_write(struct phy_device *phydev,
> +                                   u32 target, u32 reg, u32 val)
> +{
> +     unsigned long deadline;
> +
> +     phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_CSR_CNTL);
> +
> +     /* CSR registers are grouped under different Target IDs.
> +      * 6-bit Target_ID is split between MSCC_EXT_PAGE_CSR_CNTL_20 and
> +      * MSCC_EXT_PAGE_CSR_CNTL_19 registers.
> +      * Target_ID[5:2] maps to bits[3:0] of MSCC_EXT_PAGE_CSR_CNTL_20
> +      * and Target_ID[1:0] maps to bits[13:12] of MSCC_EXT_PAGE_CSR_CNTL_19.
> +      */
> +
> +     /* Setup the Target ID */
> +     phy_base_write(phydev, MSCC_EXT_PAGE_CSR_CNTL_20,
> +                    MSCC_PHY_CSR_CNTL_20_TARGET(target >> 2));
> +
> +     /* Write the Least Significant Word (LSW) (17) */
> +     phy_base_write(phydev, MSCC_EXT_PAGE_CSR_CNTL_17, (u16)val);
> +
> +     /* Write the Most Significant Word (MSW) (18) */
> +     phy_base_write(phydev, MSCC_EXT_PAGE_CSR_CNTL_18, (u16)(val >> 16));
> +
> +     /* Trigger CSR Action - Write into the CSR's */
> +     phy_base_write(phydev, MSCC_EXT_PAGE_CSR_CNTL_19,
> +                    MSCC_PHY_CSR_CNTL_19_CMD |
> +                    MSCC_PHY_CSR_CNTL_19_REG_ADDR(reg) |
> +                    MSCC_PHY_CSR_CNTL_19_TARGET(target & 0x3));
> +
> +     /* Wait for register access */
> +     deadline = jiffies + msecs_to_jiffies(PROC_CMD_NCOMPLETED_TIMEOUT_MS);
> +     do {
> +             usleep_range(500, 1000);
> +             val = phy_base_read(phydev, MSCC_EXT_PAGE_CSR_CNTL_19);
> +     } while (time_before(jiffies, deadline) &&
> +              !(val & MSCC_PHY_CSR_CNTL_19_CMD));
> +
> +     if (!(val & MSCC_PHY_CSR_CNTL_19_CMD))
> +             return -ETIMEDOUT;
> +
> +     phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,
> +                    MSCC_PHY_PAGE_STANDARD);
> +
> +     return 0;
> +}
> +
> +static int __phy_write_mcb_s6g(struct phy_device *phydev, u32 reg, u8 mcb,
> +                            u32 op)
> +{
> +     unsigned long deadline;
> +     u32 val;
> +     int ret;
> +
> +     ret = vsc85xx_csr_ctrl_phy_write(phydev, PHY_MCB_TARGET, reg,
> +                                      op | (1 << mcb));
> +     if (ret)
> +             return -EINVAL;
> +
> +     deadline = jiffies + msecs_to_jiffies(PROC_CMD_NCOMPLETED_TIMEOUT_MS);
> +     do {
> +             usleep_range(500, 1000);
> +             val = vsc85xx_csr_ctrl_phy_read(phydev, PHY_MCB_TARGET, reg);
> +
> +             if (val == 0xffffffff)
> +                     return -EINVAL;
> +
> +     } while (time_before(jiffies, deadline) && (val & op));
> +
> +     if (val & op)
> +             return -ETIMEDOUT;
> +
> +     return 0;
> +}
> +
> +/* Trigger a read to the spcified MCB */
> +static int phy_update_mcb_s6g(struct phy_device *phydev, u32 reg, u8 mcb)
> +{
> +     return __phy_write_mcb_s6g(phydev, reg, mcb, PHY_MCB_S6G_READ);
> +}
> +
> +/* Trigger a write to the spcified MCB */
> +static int phy_commit_mcb_s6g(struct phy_device *phydev, u32 reg, u8 mcb)
> +{
> +     return __phy_write_mcb_s6g(phydev, reg, mcb, PHY_MCB_S6G_WRITE);
> +}
> +
> +static int vsc8514_config_init(struct phy_device *phydev)
> +{
> +     struct vsc8531_private *vsc8531 = phydev->priv;
> +     unsigned long deadline;
> +     u16 val, addr;
> +     int ret, i;
> +     u32 reg;
> +
> +     phydev->mdix_ctrl = ETH_TP_MDI_AUTO;
> +
> +     mutex_lock(&phydev->mdio.bus->mdio_lock);
> +
> +     __phy_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_EXTENDED);
> +     addr = __phy_read(phydev,
> +                       MSCC_PHY_EXT_PHY_CNTL_4);

This should be on one line, same a few lines later.

> +     addr >>= PHY_CNTL_4_ADDR_POS;
> +
> +     val = __phy_read(phydev,
> +                      MSCC_PHY_ACTIPHY_CNTL);
> +
> +     if (val & PHY_ADDR_REVERSED)
> +             vsc8531->base_addr = phydev->mdio.addr + addr;
> +     else
> +             vsc8531->base_addr = phydev->mdio.addr - addr;
> +
> +     /* Some parts of the init sequence are identical for every PHY in the
> +      * package. Some parts are modifying the GPIO register bank which is a
> +      * set of registers that are affecting all PHYs, a few resetting the
> +      * microprocessor common to all PHYs.
> +      * All PHYs' interrupts mask register has to be zeroed before enabling
> +      * any PHY's interrupt in this register.
> +      * For all these reasons, we need to do the init sequence once and only
> +      * once whatever is the first PHY in the package that is initialized and
> +      * do the correct init sequence for all PHYs that are package-critical
> +      * in this pre-init function.
> +      */
> +     if (!vsc8584_is_pkg_init(phydev, val & PHY_ADDR_REVERSED ? 1 : 0)) {
> +             if ((phydev->phy_id & phydev->drv->phy_id_mask) ==
> +                 (PHY_ID_VSC8514 & phydev->drv->phy_id_mask))

Why do you think this is needed? If this function is used for VSC8514
only, then this is always true.

> +                     ret = vsc8514_config_pre_init(phydev);
> +             else
> +                     ret = -EINVAL;
> +
> +             if (ret)
> +                     goto err;
> +     }
> +
> +     vsc8531->pkg_init = true;
> +
> +     phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,
> +                    MSCC_PHY_PAGE_EXTENDED_GPIO);
> +
> +     val = phy_base_read(phydev, MSCC_PHY_MAC_CFG_FASTLINK);
> +
> +     val &= ~MAC_CFG_MASK;
> +     val |= MAC_CFG_QSGMII;
> +     ret = phy_base_write(phydev, MSCC_PHY_MAC_CFG_FASTLINK, val);
> +
> +     if (ret)
> +             goto err;
> +
> +     ret = vsc8584_cmd(phydev,
> +                       PROC_CMD_MCB_ACCESS_MAC_CONF |
> +                       PROC_CMD_RST_CONF_PORT |
> +                       PROC_CMD_READ_MOD_WRITE_PORT | PROC_CMD_QSGMII_MAC);
> +     if (ret)
> +             goto err;
> +
> +     /* 6g mcb */
> +     phy_update_mcb_s6g(phydev, PHY_MCB_S6G_CFG, 0);
> +     /* lcpll mcb */
> +     phy_update_mcb_s6g(phydev, PHY_S6G_LCPLL_CFG, 0);
> +     /* pll5gcfg0 */
> +     ret = vsc85xx_csr_ctrl_phy_write(phydev, PHY_MCB_TARGET,
> +                                      PHY_S6G_PLL5G_CFG0, 0x7036f145);
> +     if (ret)
> +             goto err;
> +
> +     phy_commit_mcb_s6g(phydev, PHY_S6G_LCPLL_CFG, 0);
> +     /* pllcfg */
> +     ret = vsc85xx_csr_ctrl_phy_write(phydev, PHY_MCB_TARGET,
> +                                      PHY_S6G_PLL_CFG,
> +                                      (3 << PHY_S6G_PLL_ENA_OFFS_POS) |
> +                                      (120 << PHY_S6G_PLL_FSM_CTRL_DATA_POS)
> +                                      | (0 << PHY_S6G_PLL_FSM_ENA_POS));
> +     if (ret)
> +             goto err;
> +
> +     /* commoncfg */
> +     ret = vsc85xx_csr_ctrl_phy_write(phydev, PHY_MCB_TARGET,
> +                                      PHY_S6G_COMMON_CFG,
> +                                      (0 << PHY_S6G_SYS_RST_POS) |
> +                                      (0 << PHY_S6G_ENA_LANE_POS) |
> +                                      (0 << PHY_S6G_ENA_LOOP_POS) |
> +                                      (0 << PHY_S6G_QRATE_POS) |
> +                                      (3 << PHY_S6G_IF_MODE_POS));
> +     if (ret)
> +             goto err;
> +
> +     /* misccfg */
> +     ret = vsc85xx_csr_ctrl_phy_write(phydev, PHY_MCB_TARGET,
> +                                      PHY_S6G_MISC_CFG, 1);
> +     if (ret)
> +             goto err;
> +
> +     /* gpcfg */
> +     ret = vsc85xx_csr_ctrl_phy_write(phydev, PHY_MCB_TARGET,
> +                                      PHY_S6G_GPC_CFG, 768);
> +     if (ret)
> +             goto err;
> +
> +     phy_commit_mcb_s6g(phydev, 0x3e, 0);
> +
> +     deadline = jiffies + msecs_to_jiffies(PROC_CMD_NCOMPLETED_TIMEOUT_MS);
> +     do {
> +             usleep_range(500, 1000);
> +             phy_update_mcb_s6g(phydev, PHY_MCB_S6G_CFG,
> +                                0); /* read 6G MCB into CSRs */
> +             reg = vsc85xx_csr_ctrl_phy_read(phydev, PHY_MCB_TARGET,
> +                                             PHY_S6G_PLL_STATUS);
> +             if (reg == 0xffffffff)
> +                     goto err;
> +
> +     } while (time_before(jiffies, deadline) && (reg & BIT(12)));
> +
> +     if (reg & BIT(12)) {
> +             mutex_unlock(&phydev->mdio.bus->mdio_lock);
> +             return -ETIMEDOUT;
> +     }
> +
> +     /* misccfg */
> +     ret = vsc85xx_csr_ctrl_phy_write(phydev, PHY_MCB_TARGET,
> +                                      PHY_S6G_MISC_CFG, 0);
> +     if (ret)
> +             goto err;
> +
> +     phy_commit_mcb_s6g(phydev, PHY_MCB_S6G_CFG, 0);
> +
> +     deadline = jiffies + msecs_to_jiffies(PROC_CMD_NCOMPLETED_TIMEOUT_MS);
> +     do {
> +             usleep_range(500, 1000);
> +             phy_update_mcb_s6g(phydev, PHY_MCB_S6G_CFG,
> +                                0); /* read 6G MCB into CSRs */
> +             reg = vsc85xx_csr_ctrl_phy_read(phydev, PHY_MCB_TARGET,
> +                                             PHY_S6G_IB_STATUS0);
> +             if (reg == 0xffffffff)
> +                     goto err;

When jumping to err then value of variable ret is returned. But you don't
set ret. In general I would say:
Take a little bit more time when preparing a new version and be more
careful. Several review comments are related to trivial errors.

> +
> +     } while (time_before(jiffies, deadline) && !(reg & BIT(8)));
> +
> +     if (!(reg & BIT(8))) {
> +             mutex_unlock(&phydev->mdio.bus->mdio_lock);
> +             return -ETIMEDOUT;
> +     }
> +
> +     mutex_unlock(&phydev->mdio.bus->mdio_lock);
> +
> +     ret = phy_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
> +     if (ret)
> +             goto err;
> +
> +     val = phy_read(phydev, MSCC_PHY_EXT_PHY_CNTL_1);
> +     val &= ~MEDIA_OP_MODE_MASK;
> +     val |= MEDIA_OP_MODE_COPPER;
> +     ret = phy_write(phydev, MSCC_PHY_EXT_PHY_CNTL_1, val);

I think I mentioned it earlier, phy_modify() can be used here.

> +     if (ret)
> +             goto err;
> +
> +     ret = genphy_soft_reset(phydev);
> +
> +     if (ret)
> +             return ret;
> +
> +     for (i = 0; i < vsc8531->nleds; i++) {
> +             ret = vsc85xx_led_cntl_set(phydev, i, vsc8531->leds_mode[i]);
> +             if (ret)
> +                     return ret;
> +     }
> +
> +     return ret;
> +
> +err:
> +     mutex_unlock(&phydev->mdio.bus->mdio_lock);
> +     return ret;
> +}
> +
>  static int vsc85xx_ack_interrupt(struct phy_device *phydev)
>  {
>       int rc = 0;
> @@ -1791,6 +2213,31 @@ static int vsc85xx_read_status(struct phy_device 
> *phydev)
>       return genphy_read_status(phydev);
>  }
>  
> +static int vsc8514_probe(struct phy_device *phydev)
> +{
> +     struct vsc8531_private *vsc8531;
> +     u32 default_mode[4] = {VSC8531_LINK_1000_ACTIVITY,
> +        VSC8531_LINK_100_ACTIVITY, VSC8531_LINK_ACTIVITY,
> +        VSC8531_DUPLEX_COLLISION};
> +
> +     vsc8531 = devm_kzalloc(&phydev->mdio.dev, sizeof(*vsc8531), GFP_KERNEL);
> +     if (!vsc8531)
> +             return -ENOMEM;
> +
> +     phydev->priv = vsc8531;
> +
> +     vsc8531->nleds = 4;
> +     vsc8531->supp_led_modes = VSC85XX_SUPP_LED_MODES;
> +     vsc8531->hw_stats = vsc85xx_hw_stats;
> +     vsc8531->nstats = ARRAY_SIZE(vsc85xx_hw_stats);
> +     vsc8531->stats = devm_kmalloc_array(&phydev->mdio.dev, vsc8531->nstats,
> +                                         sizeof(u64), GFP_KERNEL);
> +     if (!vsc8531->stats)
> +             return -ENOMEM;
> +
> +     return vsc85xx_dt_led_modes_get(phydev, default_mode);
> +}
> +
>  static int vsc8574_probe(struct phy_device *phydev)
>  {
>       struct vsc8531_private *vsc8531;
> @@ -1878,6 +2325,29 @@ static int vsc85xx_probe(struct phy_device *phydev)
>  
>  /* Microsemi VSC85xx PHYs */
>  static struct phy_driver vsc85xx_driver[] = {
> +{
> +     .phy_id         = PHY_ID_VSC8514,
> +     .name           = "Microsemi GE VSC8514 SyncE",
> +     .phy_id_mask    = 0xfffffff0,
> +     .soft_reset     = &genphy_soft_reset,
> +     .config_init    = &vsc8514_config_init,
> +     .config_aneg    = &vsc85xx_config_aneg,
> +     .read_status    = &vsc85xx_read_status,
> +     .ack_interrupt  = &vsc85xx_ack_interrupt,
> +     .config_intr    = &vsc85xx_config_intr,
> +     .suspend        = &genphy_suspend,
> +     .resume         = &genphy_resume,
> +     .probe          = &vsc8514_probe,
> +     .set_wol        = &vsc85xx_wol_set,
> +     .get_wol        = &vsc85xx_wol_get,
> +     .get_tunable    = &vsc85xx_get_tunable,
> +     .set_tunable    = &vsc85xx_set_tunable,
> +     .read_page      = &vsc85xx_phy_read_page,
> +     .write_page     = &vsc85xx_phy_write_page,
> +     .get_sset_count = &vsc85xx_get_sset_count,
> +     .get_strings    = &vsc85xx_get_strings,
> +     .get_stats      = &vsc85xx_get_stats,
> +},
>  {
>       .phy_id         = PHY_ID_VSC8530,
>       .name           = "Microsemi FE VSC8530",
> @@ -2034,6 +2504,7 @@ static struct phy_driver vsc85xx_driver[] = {
>  module_phy_driver(vsc85xx_driver);
>  
>  static struct mdio_device_id __maybe_unused vsc85xx_tbl[] = {
> +     { PHY_ID_VSC8514, 0xfffffff0, },
>       { PHY_ID_VSC8530, 0xfffffff0, },
>       { PHY_ID_VSC8531, 0xfffffff0, },
>       { PHY_ID_VSC8540, 0xfffffff0, },
> 

Reply via email to