net: phy: MSCC Add Support for VSC8530-VSC8531-VSC8540-VSC8541
authorJohn Haechten <john.haechten@microsemi.com>
Fri, 9 Dec 2016 22:15:17 +0000 (22:15 +0000)
committerJoe Hershberger <joe.hershberger@ni.com>
Wed, 8 Feb 2017 22:32:58 +0000 (16:32 -0600)
Signed-off-by: John Haechten <john.haechten@microsemi.com>
Acked-by: Joe Hershberger <joe.hershberger@ni.com>
configs/am335x_evm_defconfig
drivers/net/phy/Kconfig
drivers/net/phy/Makefile
drivers/net/phy/mscc.c [new file with mode: 0644]
drivers/net/phy/phy.c
include/phy.h

index ab7b9aa..73df55d 100644 (file)
@@ -58,3 +58,4 @@ CONFIG_G_DNL_VENDOR_NUM=0x0451
 CONFIG_G_DNL_PRODUCT_NUM=0xd022
 CONFIG_RSA=y
 CONFIG_SPL_OF_LIBFDT=y
+CONFIG_PHY_MSCC=y
index 52529f2..1d514e9 100644 (file)
@@ -45,6 +45,9 @@ config PHY_MARVELL
 config PHY_MICREL
        bool "Micrel Ethernet PHYs support"
 
+config PHY_MSCC
+       bool "Microsemi Corp Ethernet PHYs support"
+
 config PHY_NATSEMI
        bool "National Semiconductor Ethernet PHYs support"
 
index 1e299b9..d372971 100644 (file)
@@ -27,3 +27,4 @@ obj-$(CONFIG_PHY_TERANETICS) += teranetics.o
 obj-$(CONFIG_PHY_TI) += ti.o
 obj-$(CONFIG_PHY_XILINX) += xilinx_phy.o
 obj-$(CONFIG_PHY_VITESSE) += vitesse.o
+obj-$(CONFIG_PHY_MSCC) += mscc.o
diff --git a/drivers/net/phy/mscc.c b/drivers/net/phy/mscc.c
new file mode 100644 (file)
index 0000000..439f5e3
--- /dev/null
@@ -0,0 +1,508 @@
+/*
+ * Microsemi PHY drivers
+ *
+ * SPDX-License-Identifier: The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Microsemi Corporation
+ *
+ * Author: John Haechten
+ *
+ */
+
+#include <miiphy.h>
+#include <bitfield.h>
+
+/* Microsemi PHY ID's */
+#define PHY_ID_VSC8530                  0x00070560
+#define PHY_ID_VSC8531                  0x00070570
+#define PHY_ID_VSC8540                  0x00070760
+#define PHY_ID_VSC8541                  0x00070770
+
+/* Microsemi VSC85xx PHY Register Pages */
+#define MSCC_EXT_PAGE_ACCESS            31     /* Page Access Register */
+#define MSCC_PHY_PAGE_STD              0x0000 /* Standard registers */
+#define MSCC_PHY_PAGE_EXT1             0x0001 /* Extended registers - page 1 */
+#define MSCC_PHY_PAGE_EXT2             0x0002 /* Extended registers - page 2 */
+#define MSCC_PHY_PAGE_EXT3             0x0003 /* Extended registers - page 3 */
+#define MSCC_PHY_PAGE_EXT4             0x0004 /* Extended registers - page 4 */
+#define MSCC_PHY_PAGE_GPIO             0x0010 /* GPIO registers */
+#define MSCC_PHY_PAGE_TEST             0x2A30 /* TEST Page registers */
+#define MSCC_PHY_PAGE_TR               0x52B5 /* Token Ring Page registers */
+
+/* Std Page Register 28 - PHY AUX Control/Status */
+#define MIIM_AUX_CNTRL_STAT_REG                28
+#define MIIM_AUX_CNTRL_STAT_ACTIPHY_TO (0x0004)
+#define MIIM_AUX_CNTRL_STAT_F_DUPLEX   (0x0020)
+#define MIIM_AUX_CNTRL_STAT_SPEED_MASK (0x0018)
+#define MIIM_AUX_CNTRL_STAT_SPEED_POS  (3)
+#define MIIM_AUX_CNTRL_STAT_SPEED_10M  (0x0)
+#define MIIM_AUX_CNTRL_STAT_SPEED_100M (0x1)
+#define MIIM_AUX_CNTRL_STAT_SPEED_1000M        (0x2)
+
+/* Std Page Register 23 - Extended PHY CTRL_1 */
+#define MSCC_PHY_EXT_PHY_CNTL_1_REG    23
+#define MAC_IF_SELECTION_MASK          (0x1800)
+#define MAC_IF_SELECTION_GMII          (0)
+#define MAC_IF_SELECTION_RMII          (1)
+#define MAC_IF_SELECTION_RGMII         (2)
+#define MAC_IF_SELECTION_POS           (11)
+#define MAC_IF_SELECTION_WIDTH         (2)
+
+/* Extended Page 2 Register 20E2 */
+#define MSCC_PHY_RGMII_CNTL_REG                20
+#define VSC_FAST_LINK_FAIL2_ENA_MASK   (0x8000)
+#define RX_CLK_OUT_MASK                        (0x0800)
+#define RX_CLK_OUT_POS                 (11)
+#define RX_CLK_OUT_WIDTH               (1)
+#define RX_CLK_OUT_NORMAL              (0)
+#define RX_CLK_OUT_DISABLE             (1)
+#define RGMII_RX_CLK_DELAY_POS         (4)
+#define RGMII_RX_CLK_DELAY_WIDTH       (3)
+#define RGMII_RX_CLK_DELAY_MASK                (0x0070)
+#define RGMII_TX_CLK_DELAY_POS         (0)
+#define RGMII_TX_CLK_DELAY_WIDTH       (3)
+#define RGMII_TX_CLK_DELAY_MASK                (0x0007)
+
+/* Extended Page 2 Register 27E2 */
+#define MSCC_PHY_WOL_MAC_CONTROL       27
+#define EDGE_RATE_CNTL_POS             (5)
+#define EDGE_RATE_CNTL_WIDTH           (3)
+#define EDGE_RATE_CNTL_MASK            (0x00E0)
+#define RMII_CLK_OUT_ENABLE_POS                (4)
+#define RMII_CLK_OUT_ENABLE_WIDTH      (1)
+#define RMII_CLK_OUT_ENABLE_MASK       (0x10)
+
+/* Token Ring Page 0x52B5 Registers */
+#define MSCC_PHY_REG_TR_ADDR_16                16
+#define MSCC_PHY_REG_TR_DATA_17                17
+#define MSCC_PHY_REG_TR_DATA_18                18
+
+/* Token Ring - Read Value in */
+#define MSCC_PHY_TR_16_READ            (0xA000)
+/* Token Ring - Write Value out */
+#define MSCC_PHY_TR_16_WRITE           (0x8000)
+
+/* Token Ring Registers */
+#define MSCC_PHY_TR_LINKDETCTRL_POS    (3)
+#define MSCC_PHY_TR_LINKDETCTRL_WIDTH  (2)
+#define MSCC_PHY_TR_LINKDETCTRL_VAL    (3)
+#define MSCC_PHY_TR_LINKDETCTRL_MASK   (0x0018)
+#define MSCC_PHY_TR_LINKDETCTRL_ADDR   (0x07F8)
+
+#define MSCC_PHY_TR_VGATHRESH100_POS   (0)
+#define MSCC_PHY_TR_VGATHRESH100_WIDTH (7)
+#define MSCC_PHY_TR_VGATHRESH100_VAL   (0x0018)
+#define MSCC_PHY_TR_VGATHRESH100_MASK  (0x007f)
+#define MSCC_PHY_TR_VGATHRESH100_ADDR  (0x0FA4)
+
+#define MSCC_PHY_TR_VGAGAIN10_U_POS    (0)
+#define MSCC_PHY_TR_VGAGAIN10_U_WIDTH  (1)
+#define MSCC_PHY_TR_VGAGAIN10_U_MASK   (0x0001)
+#define MSCC_PHY_TR_VGAGAIN10_U_VAL    (0)
+
+#define MSCC_PHY_TR_VGAGAIN10_L_POS    (12)
+#define MSCC_PHY_TR_VGAGAIN10_L_WIDTH  (4)
+#define MSCC_PHY_TR_VGAGAIN10_L_MASK   (0xf000)
+#define MSCC_PHY_TR_VGAGAIN10_L_VAL    (0x0001)
+#define MSCC_PHY_TR_VGAGAIN10_ADDR     (0x0F92)
+
+/* General Timeout Values */
+#define MSCC_PHY_RESET_TIMEOUT         (100)
+#define MSCC_PHY_MICRO_TIMEOUT         (500)
+
+/* RGMII/GMII Clock Delay (Skew) Options */ enum vsc_phy_rgmii_skew {
+       VSC_PHY_RGMII_DELAY_200_PS,
+       VSC_PHY_RGMII_DELAY_800_PS,
+       VSC_PHY_RGMII_DELAY_1100_PS,
+       VSC_PHY_RGMII_DELAY_1700_PS,
+       VSC_PHY_RGMII_DELAY_2000_PS,
+       VSC_PHY_RGMII_DELAY_2300_PS,
+       VSC_PHY_RGMII_DELAY_2600_PS,
+       VSC_PHY_RGMII_DELAY_3400_PS,
+};
+
+/* MAC i/f Clock Edge Rage Control (Slew), See Reg27E2  */ enum
+vsc_phy_clk_slew {
+       VSC_PHY_CLK_SLEW_RATE_0,
+       VSC_PHY_CLK_SLEW_RATE_1,
+       VSC_PHY_CLK_SLEW_RATE_2,
+       VSC_PHY_CLK_SLEW_RATE_3,
+       VSC_PHY_CLK_SLEW_RATE_4,
+       VSC_PHY_CLK_SLEW_RATE_5,
+       VSC_PHY_CLK_SLEW_RATE_6,
+       VSC_PHY_CLK_SLEW_RATE_7,
+};
+
+
+static int mscc_vsc8531_vsc8541_init_scripts(struct phy_device *phydev)
+{
+       u16     reg_val;
+
+       /* Set to Access Token Ring Registers */
+       phy_write(phydev, MDIO_DEVAD_NONE,
+                 MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TR);
+
+       /* Update LinkDetectCtrl default to optimized values */
+       /* Determined during Silicon Validation Testing */
+       phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_ADDR_16,
+                 (MSCC_PHY_TR_LINKDETCTRL_ADDR | MSCC_PHY_TR_16_READ));
+       reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_DATA_17);
+       reg_val = bitfield_replace(reg_val, MSCC_PHY_TR_LINKDETCTRL_POS,
+                                  MSCC_PHY_TR_LINKDETCTRL_WIDTH,
+                                  MSCC_PHY_TR_LINKDETCTRL_VAL);
+
+       phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_DATA_17, reg_val);
+       phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_ADDR_16,
+                 (MSCC_PHY_TR_LINKDETCTRL_ADDR | MSCC_PHY_TR_16_WRITE));
+
+       /* Update VgaThresh100 defaults to optimized values */
+       /* Determined during Silicon Validation Testing */
+       phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_ADDR_16,
+                 (MSCC_PHY_TR_VGATHRESH100_ADDR | MSCC_PHY_TR_16_READ));
+
+       reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_DATA_18);
+       reg_val = bitfield_replace(reg_val, MSCC_PHY_TR_VGATHRESH100_POS,
+                                  MSCC_PHY_TR_VGATHRESH100_WIDTH,
+                                  MSCC_PHY_TR_VGATHRESH100_VAL);
+
+       phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_DATA_18, reg_val);
+       phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_ADDR_16,
+                 (MSCC_PHY_TR_VGATHRESH100_ADDR | MSCC_PHY_TR_16_WRITE));
+
+       /* Update VgaGain10 defaults to optimized values */
+       /* Determined during Silicon Validation Testing */
+       phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_ADDR_16,
+                 (MSCC_PHY_TR_VGAGAIN10_ADDR | MSCC_PHY_TR_16_READ));
+
+       reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_DATA_18);
+       reg_val = bitfield_replace(reg_val, MSCC_PHY_TR_VGAGAIN10_U_POS,
+                                  MSCC_PHY_TR_VGAGAIN10_U_WIDTH,
+                                  MSCC_PHY_TR_VGAGAIN10_U_VAL);
+
+       phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_DATA_18, reg_val);
+       reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_DATA_17);
+       reg_val = bitfield_replace(reg_val, MSCC_PHY_TR_VGAGAIN10_L_POS,
+                                  MSCC_PHY_TR_VGAGAIN10_L_WIDTH,
+                                  MSCC_PHY_TR_VGAGAIN10_L_VAL);
+
+       phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_DATA_17, reg_val);
+       phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_ADDR_16,
+                 (MSCC_PHY_TR_VGAGAIN10_ADDR | MSCC_PHY_TR_16_WRITE));
+
+       /* Set back to Access Standard Page Registers */
+       phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
+                 MSCC_PHY_PAGE_STD);
+
+       return 0;
+}
+
+static int mscc_parse_status(struct phy_device *phydev)
+{
+       u16 speed;
+       u16 mii_reg;
+
+       mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_AUX_CNTRL_STAT_REG);
+
+       if (mii_reg & MIIM_AUX_CNTRL_STAT_F_DUPLEX)
+               phydev->duplex = DUPLEX_FULL;
+       else
+               phydev->duplex = DUPLEX_HALF;
+
+       speed = mii_reg & MIIM_AUX_CNTRL_STAT_SPEED_MASK;
+       speed = speed >> MIIM_AUX_CNTRL_STAT_SPEED_POS;
+
+       switch (speed) {
+       case MIIM_AUX_CNTRL_STAT_SPEED_1000M:
+               phydev->speed = SPEED_1000;
+               break;
+       case MIIM_AUX_CNTRL_STAT_SPEED_100M:
+               phydev->speed = SPEED_100;
+               break;
+       case MIIM_AUX_CNTRL_STAT_SPEED_10M:
+               phydev->speed = SPEED_10;
+               break;
+       default:
+               phydev->speed = SPEED_10;
+               break;
+       }
+
+       return 0;
+}
+
+static int mscc_startup(struct phy_device *phydev)
+{
+       int retval;
+
+       retval = genphy_update_link(phydev);
+
+       if (retval)
+               return retval;
+
+       return mscc_parse_status(phydev);
+}
+
+static int mscc_phy_soft_reset(struct phy_device *phydev)
+{
+       int     retval = 0;
+       u16     timeout = MSCC_PHY_RESET_TIMEOUT;
+       u16     reg_val = 0;
+
+       phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
+                 MSCC_PHY_PAGE_STD);
+
+       reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
+       phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, (reg_val | BMCR_RESET));
+
+       reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
+
+       while ((reg_val & BMCR_RESET) && (timeout > 0)) {
+               reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
+               timeout--;
+               udelay(1000);   /* 1 ms */
+       }
+
+       if (timeout == 0) {
+               printf("MSCC PHY Soft_Reset Error: mac i/f = 0x%x\n",
+                      phydev->interface);
+               retval = -ETIME;
+       }
+
+       return retval;
+}
+
+static int vsc8531_vsc8541_mac_config(struct phy_device *phydev)
+{
+       u16     reg_val = 0;
+       u16     mac_if = 0;
+       u16     rx_clk_out = 0;
+
+       /* For VSC8530/31 the only MAC modes are RMII/RGMII. */
+       /* For VSC8540/41 the only MAC modes are (G)MII and RMII/RGMII. */
+       /* Setup MAC Configuration */
+       switch (phydev->interface) {
+       case PHY_INTERFACE_MODE_MII:
+       case PHY_INTERFACE_MODE_GMII:
+               /* Set Reg23.12:11=0 */
+               mac_if = MAC_IF_SELECTION_GMII;
+               /* Set Reg20E2.11=1 */
+               rx_clk_out = RX_CLK_OUT_DISABLE;
+               break;
+
+       case PHY_INTERFACE_MODE_RMII:
+               /* Set Reg23.12:11=1 */
+               mac_if = MAC_IF_SELECTION_RMII;
+               /* Set Reg20E2.11=0 */
+               rx_clk_out = RX_CLK_OUT_NORMAL;
+               break;
+
+       case PHY_INTERFACE_MODE_RGMII:
+               /* Set Reg23.12:11=2 */
+               mac_if = MAC_IF_SELECTION_RGMII;
+               /* Set Reg20E2.11=0 */
+               rx_clk_out = RX_CLK_OUT_NORMAL;
+               break;
+
+       default:
+               printf("MSCC PHY - INVALID MAC i/f Config: mac i/f = 0x%x\n",
+                      phydev->interface);
+               return -EINVAL;
+       }
+
+       phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
+                 MSCC_PHY_PAGE_STD);
+
+       reg_val = phy_read(phydev, MDIO_DEVAD_NONE,
+                          MSCC_PHY_EXT_PHY_CNTL_1_REG);
+       /* Set MAC i/f bits Reg23.12:11 */
+       reg_val = bitfield_replace(reg_val, MAC_IF_SELECTION_POS,
+                                  MAC_IF_SELECTION_WIDTH, mac_if);
+       /* Update Reg23.12:11 */
+       phy_write(phydev, MDIO_DEVAD_NONE,
+                 MSCC_PHY_EXT_PHY_CNTL_1_REG, reg_val);
+       /* Setup ExtPg_2 Register Access */
+       phy_write(phydev, MDIO_DEVAD_NONE,
+                 MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_EXT2);
+       /* Read Reg20E2 */
+       reg_val = phy_read(phydev, MDIO_DEVAD_NONE,
+                          MSCC_PHY_RGMII_CNTL_REG);
+       reg_val = bitfield_replace(reg_val, RX_CLK_OUT_POS,
+                                  RX_CLK_OUT_WIDTH, rx_clk_out);
+       /* Update Reg20E2.11 */
+       phy_write(phydev, MDIO_DEVAD_NONE,
+                 MSCC_PHY_RGMII_CNTL_REG, reg_val);
+       /* Before leaving - Change back to Std Page Register Access */
+       phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
+                 MSCC_PHY_PAGE_STD);
+
+       return 0;
+}
+
+static int vsc8531_config(struct phy_device *phydev)
+{
+       int  retval = -EINVAL;
+       u16  reg_val;
+       u16  rmii_clk_out;
+       enum vsc_phy_rgmii_skew  rx_clk_skew = VSC_PHY_RGMII_DELAY_1700_PS;
+       enum vsc_phy_rgmii_skew  tx_clk_skew = VSC_PHY_RGMII_DELAY_800_PS;
+       enum vsc_phy_clk_slew    edge_rate = VSC_PHY_CLK_SLEW_RATE_4;
+
+       /* For VSC8530/31 and VSC8540/41 the init scripts are the same */
+       mscc_vsc8531_vsc8541_init_scripts(phydev);
+
+       /* For VSC8530/31 the only MAC modes are RMII/RGMII. */
+       switch (phydev->interface) {
+       case PHY_INTERFACE_MODE_RMII:
+       case PHY_INTERFACE_MODE_RGMII:
+               retval = vsc8531_vsc8541_mac_config(phydev);
+               if (retval != 0)
+                       return retval;
+
+               retval = mscc_phy_soft_reset(phydev);
+               if (retval != 0)
+                       return retval;
+               break;
+       default:
+               printf("PHY 8530/31 MAC i/f Config Error: mac i/f = 0x%x\n",
+                      phydev->interface);
+               return -EINVAL;
+       }
+       /* Default RMII Clk Output to 0=OFF/1=ON  */
+       rmii_clk_out = 0;
+
+       phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
+                 MSCC_PHY_PAGE_EXT2);
+       reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MSCC_PHY_RGMII_CNTL_REG);
+
+       /* Reg20E2 - Update RGMII RX_Clk Skews. */
+       reg_val = bitfield_replace(reg_val, RGMII_RX_CLK_DELAY_POS,
+                                  RGMII_RX_CLK_DELAY_WIDTH, rx_clk_skew);
+       /* Reg20E2 - Update RGMII TX_Clk Skews. */
+       reg_val = bitfield_replace(reg_val, RGMII_TX_CLK_DELAY_POS,
+                                  RGMII_TX_CLK_DELAY_WIDTH, tx_clk_skew);
+
+       phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_RGMII_CNTL_REG, reg_val);
+
+       reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MSCC_PHY_WOL_MAC_CONTROL);
+       /* Reg27E2 - Update Clk Slew Rate. */
+       reg_val = bitfield_replace(reg_val, EDGE_RATE_CNTL_POS,
+                                  EDGE_RATE_CNTL_WIDTH, edge_rate);
+       /* Reg27E2 - Update RMII Clk Out. */
+       reg_val = bitfield_replace(reg_val, RMII_CLK_OUT_ENABLE_POS,
+                                  RMII_CLK_OUT_ENABLE_WIDTH, rmii_clk_out);
+       /* Update Reg27E2 */
+       phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_WOL_MAC_CONTROL, reg_val);
+       phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
+                 MSCC_PHY_PAGE_STD);
+
+       return genphy_config_aneg(phydev);
+}
+
+static int vsc8541_config(struct phy_device *phydev)
+{
+       int  retval = -EINVAL;
+       u16  reg_val;
+       u16  rmii_clk_out;
+       enum vsc_phy_rgmii_skew  rx_clk_skew = VSC_PHY_RGMII_DELAY_1700_PS;
+       enum vsc_phy_rgmii_skew  tx_clk_skew = VSC_PHY_RGMII_DELAY_800_PS;
+       enum vsc_phy_clk_slew    edge_rate = VSC_PHY_CLK_SLEW_RATE_4;
+
+       /* For VSC8530/31 and VSC8540/41 the init scripts are the same */
+       mscc_vsc8531_vsc8541_init_scripts(phydev);
+
+       /* For VSC8540/41 the only MAC modes are (G)MII and RMII/RGMII. */
+       switch (phydev->interface) {
+       case PHY_INTERFACE_MODE_MII:
+       case PHY_INTERFACE_MODE_GMII:
+       case PHY_INTERFACE_MODE_RMII:
+       case PHY_INTERFACE_MODE_RGMII:
+               retval = vsc8531_vsc8541_mac_config(phydev);
+               if (retval != 0)
+                       return retval;
+
+               retval = mscc_phy_soft_reset(phydev);
+               if (retval != 0)
+                       return retval;
+               break;
+       default:
+               printf("PHY 8541 MAC i/f config Error: mac i/f = 0x%x\n",
+                      phydev->interface);
+               return -EINVAL;
+       }
+       /* Default RMII Clk Output to 0=OFF/1=ON  */
+       rmii_clk_out = 0;
+
+       phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
+                 MSCC_PHY_PAGE_EXT2);
+       reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MSCC_PHY_RGMII_CNTL_REG);
+       /* Reg20E2 - Update RGMII RX_Clk Skews. */
+       reg_val = bitfield_replace(reg_val, RGMII_RX_CLK_DELAY_POS,
+                                  RGMII_RX_CLK_DELAY_WIDTH, rx_clk_skew);
+       /* Reg20E2 - Update RGMII TX_Clk Skews. */
+       reg_val = bitfield_replace(reg_val, RGMII_TX_CLK_DELAY_POS,
+                                  RGMII_TX_CLK_DELAY_WIDTH, tx_clk_skew);
+       phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_RGMII_CNTL_REG, reg_val);
+
+       reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MSCC_PHY_WOL_MAC_CONTROL);
+       /* Reg27E2 - Update Clk Slew Rate. */
+       reg_val = bitfield_replace(reg_val, EDGE_RATE_CNTL_POS,
+                                  EDGE_RATE_CNTL_WIDTH, edge_rate);
+       /* Reg27E2 - Update RMII Clk Out. */
+       reg_val = bitfield_replace(reg_val, RMII_CLK_OUT_ENABLE_POS,
+                                  RMII_CLK_OUT_ENABLE_WIDTH, rmii_clk_out);
+       /* Update Reg27E2 */
+       phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_WOL_MAC_CONTROL, reg_val);
+       phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
+                 MSCC_PHY_PAGE_STD);
+
+       return genphy_config_aneg(phydev);
+}
+
+static struct phy_driver VSC8530_driver = {
+       .name = "Microsemi VSC8530",
+       .uid = PHY_ID_VSC8530,
+       .mask = 0x000ffff0,
+       .features = PHY_BASIC_FEATURES,
+       .config = &vsc8531_config,
+       .startup = &mscc_startup,
+       .shutdown = &genphy_shutdown,
+};
+
+static struct phy_driver VSC8531_driver = {
+       .name = "Microsemi VSC8531",
+       .uid = PHY_ID_VSC8531,
+       .mask = 0x000ffff0,
+       .features = PHY_GBIT_FEATURES,
+       .config = &vsc8531_config,
+       .startup = &mscc_startup,
+       .shutdown = &genphy_shutdown,
+};
+
+static struct phy_driver VSC8540_driver = {
+       .name = "Microsemi VSC8540",
+       .uid = PHY_ID_VSC8540,
+       .mask = 0x000ffff0,
+       .features = PHY_BASIC_FEATURES,
+       .config = &vsc8541_config,
+       .startup = &mscc_startup,
+       .shutdown = &genphy_shutdown,
+};
+
+static struct phy_driver VSC8541_driver = {
+       .name = "Microsemi VSC8541",
+       .uid = PHY_ID_VSC8541,
+       .mask = 0x000ffff0,
+       .features = PHY_GBIT_FEATURES,
+       .config = &vsc8541_config,
+       .startup = &mscc_startup,
+       .shutdown = &genphy_shutdown,
+};
+
+int phy_mscc_init(void)
+{
+       phy_register(&VSC8530_driver);
+       phy_register(&VSC8531_driver);
+       phy_register(&VSC8540_driver);
+       phy_register(&VSC8541_driver);
+
+       return 0;
+}
index 80bdfb6..8db6574 100644 (file)
@@ -512,6 +512,9 @@ int phy_init(void)
 #ifdef CONFIG_PHY_XILINX
        phy_xilinx_init();
 #endif
+#ifdef CONFIG_PHY_MSCC
+       phy_mscc_init();
+#endif
 
        return 0;
 }
index 268d9a1..5477496 100644 (file)
@@ -266,6 +266,7 @@ int phy_teranetics_init(void);
 int phy_ti_init(void);
 int phy_vitesse_init(void);
 int phy_xilinx_init(void);
+int phy_mscc_init(void);
 
 int board_phy_config(struct phy_device *phydev);
 int get_phy_id(struct mii_dev *bus, int addr, int devad, u32 *phy_id);