| // SPDX-License-Identifier: MIT | |
| /* | |
| * Microsemi PHY drivers | |
| * | |
| * | |
| * 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; | |
| } |