diff options
author | John Haechten <john.haechten@microsemi.com> | 2016-12-09 22:15:17 (GMT) |
---|---|---|
committer | Joe Hershberger <joe.hershberger@ni.com> | 2017-02-08 22:32:58 (GMT) |
commit | a5fd13ad1913d9c66c47666dbedac7703a48e502 (patch) | |
tree | ec4385251f5aa5d8c25928654223f60aac82e4c2 /drivers/net/phy/mscc.c | |
parent | af2cbfd6b982f7a52414ea50b2ece0290d4b748f (diff) | |
download | u-boot-fsl-qoriq-a5fd13ad1913d9c66c47666dbedac7703a48e502.tar.xz |
net: phy: MSCC Add Support for VSC8530-VSC8531-VSC8540-VSC8541
Signed-off-by: John Haechten <john.haechten@microsemi.com>
Acked-by: Joe Hershberger <joe.hershberger@ni.com>
Diffstat (limited to 'drivers/net/phy/mscc.c')
-rw-r--r-- | drivers/net/phy/mscc.c | 508 |
1 files changed, 508 insertions, 0 deletions
diff --git a/drivers/net/phy/mscc.c b/drivers/net/phy/mscc.c new file mode 100644 index 0000000..439f5e3 --- /dev/null +++ b/drivers/net/phy/mscc.c @@ -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; +} |