2019-01-21 19:05:50 +01:00
// SPDX-License-Identifier: GPL-2.0+
2017-06-05 12:23:16 +01:00
/*
* Marvell 10 G 88 x3310 PHY driver
*
* Based upon the ID registers , this PHY appears to be a mixture of IPs
* from two different companies .
*
* There appears to be several different data paths through the PHY which
* are automatically managed by the PHY . The following has been determined
2017-12-29 12:46:22 +00:00
* via observation and experimentation for a setup using single - lane Serdes :
2017-06-05 12:23:16 +01:00
*
* SGMII PHYXS - - BASE - T PCS - - 10 G PMA - - AN - - Copper ( for < = 1 G )
* 10 GBASE - KR PHYXS - - BASE - T PCS - - 10 G PMA - - AN - - Copper ( for 10 G )
* 10 GBASE - KR PHYXS - - BASE - R PCS - - Fiber
*
2017-12-29 12:46:22 +00:00
* With XAUI , observation shows :
*
* XAUI PHYXS - - < appropriate PCS as above >
*
* and no switching of the host interface mode occurs .
*
2017-06-05 12:23:16 +01:00
* If both the fiber and copper ports are connected , the first to gain
* link takes priority and the other port is completely locked out .
*/
2018-04-03 10:31:45 +01:00
# include <linux/ctype.h>
2020-03-03 18:08:34 +00:00
# include <linux/delay.h>
2018-04-03 10:31:45 +01:00
# include <linux/hwmon.h>
2017-11-28 14:26:30 +01:00
# include <linux/marvell_phy.h>
2018-04-03 10:31:45 +01:00
# include <linux/phy.h>
2019-11-15 19:56:56 +00:00
# include <linux/sfp.h>
2017-06-05 12:23:16 +01:00
2019-02-23 00:37:42 +01:00
# define MV_PHY_ALASKA_NBT_QUIRK_MASK 0xfffffffe
# define MV_PHY_ALASKA_NBT_QUIRK_REV (MARVELL_PHY_ID_88X3310 | 0xa)
2017-06-05 12:23:16 +01:00
enum {
2020-04-14 20:49:03 +01:00
MV_PMA_FW_VER0 = 0xc011 ,
MV_PMA_FW_VER1 = 0xc012 ,
2021-04-07 22:22:44 +02:00
MV_PMA_21X0_PORT_CTRL = 0xc04a ,
MV_PMA_21X0_PORT_CTRL_SWRST = BIT ( 15 ) ,
MV_PMA_21X0_PORT_CTRL_MACTYPE_MASK = 0x7 ,
MV_PMA_21X0_PORT_CTRL_MACTYPE_USXGMII = 0x0 ,
MV_PMA_2180_PORT_CTRL_MACTYPE_DXGMII = 0x1 ,
MV_PMA_2180_PORT_CTRL_MACTYPE_QXGMII = 0x2 ,
MV_PMA_21X0_PORT_CTRL_MACTYPE_5GBASER = 0x4 ,
MV_PMA_21X0_PORT_CTRL_MACTYPE_5GBASER_NO_SGMII_AN = 0x5 ,
MV_PMA_21X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH = 0x6 ,
2019-05-28 10:34:42 +01:00
MV_PMA_BOOT = 0xc050 ,
MV_PMA_BOOT_FATAL = BIT ( 0 ) ,
2017-06-05 12:23:16 +01:00
MV_PCS_BASE_T = 0x0000 ,
MV_PCS_BASE_R = 0x1000 ,
MV_PCS_1000BASEX = 0x2000 ,
2020-03-03 18:08:34 +00:00
MV_PCS_CSCR1 = 0x8000 ,
2020-03-03 18:08:40 +00:00
MV_PCS_CSCR1_ED_MASK = 0x0300 ,
MV_PCS_CSCR1_ED_OFF = 0x0000 ,
MV_PCS_CSCR1_ED_RX = 0x0200 ,
MV_PCS_CSCR1_ED_NLP = 0x0300 ,
2020-03-03 18:08:34 +00:00
MV_PCS_CSCR1_MDIX_MASK = 0x0060 ,
MV_PCS_CSCR1_MDIX_MDI = 0x0000 ,
MV_PCS_CSCR1_MDIX_MDIX = 0x0020 ,
MV_PCS_CSCR1_MDIX_AUTO = 0x0060 ,
2020-02-27 09:46:36 +00:00
MV_PCS_CSSR1 = 0x8008 ,
MV_PCS_CSSR1_SPD1_MASK = 0xc000 ,
MV_PCS_CSSR1_SPD1_SPD2 = 0xc000 ,
MV_PCS_CSSR1_SPD1_1000 = 0x8000 ,
MV_PCS_CSSR1_SPD1_100 = 0x4000 ,
MV_PCS_CSSR1_SPD1_10 = 0x0000 ,
MV_PCS_CSSR1_DUPLEX_FULL = BIT ( 13 ) ,
MV_PCS_CSSR1_RESOLVED = BIT ( 11 ) ,
MV_PCS_CSSR1_MDIX = BIT ( 6 ) ,
MV_PCS_CSSR1_SPD2_MASK = 0x000c ,
MV_PCS_CSSR1_SPD2_5000 = 0x0008 ,
MV_PCS_CSSR1_SPD2_2500 = 0x0004 ,
MV_PCS_CSSR1_SPD2_10000 = 0x0000 ,
2017-12-29 12:46:27 +00:00
2020-04-26 09:22:06 +03:00
/* Temperature read register (88E2110 only) */
MV_PCS_TEMP = 0x8042 ,
2021-07-11 18:38:15 +02:00
/* Number of ports on the device */
MV_PCS_PORT_INFO = 0xd00d ,
MV_PCS_PORT_INFO_NPORTS_MASK = 0x0380 ,
MV_PCS_PORT_INFO_NPORTS_SHIFT = 7 ,
2017-06-05 12:23:16 +01:00
/* These registers appear at 0x800X and 0xa00X - the 0xa00X control
* registers appear to set themselves to the 0x800 X when AN is
* restarted , but status registers appear readable from either .
*/
MV_AN_CTRL1000 = 0x8000 , /* 1000base-T control register */
MV_AN_STAT1000 = 0x8001 , /* 1000base-T status register */
2018-04-03 10:31:45 +01:00
/* Vendor2 MMD registers */
2019-04-02 15:10:28 +02:00
MV_V2_PORT_CTRL = 0xf001 ,
2021-04-07 22:22:43 +02:00
MV_V2_PORT_CTRL_PWRDOWN = BIT ( 11 ) ,
MV_V2_33X0_PORT_CTRL_SWRST = BIT ( 15 ) ,
MV_V2_33X0_PORT_CTRL_MACTYPE_MASK = 0x7 ,
MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI = 0x0 ,
MV_V2_3310_PORT_CTRL_MACTYPE_XAUI_RATE_MATCH = 0x1 ,
MV_V2_3340_PORT_CTRL_MACTYPE_RXAUI_NO_SGMII_AN = 0x1 ,
MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI_RATE_MATCH = 0x2 ,
MV_V2_3310_PORT_CTRL_MACTYPE_XAUI = 0x3 ,
MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER = 0x4 ,
MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_NO_SGMII_AN = 0x5 ,
MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH = 0x6 ,
MV_V2_33X0_PORT_CTRL_MACTYPE_USXGMII = 0x7 ,
2020-04-26 09:22:06 +03:00
/* Temperature control/read registers (88X3310 only) */
2018-04-03 10:31:45 +01:00
MV_V2_TEMP_CTRL = 0xf08a ,
MV_V2_TEMP_CTRL_MASK = 0xc000 ,
MV_V2_TEMP_CTRL_SAMPLE = 0x0000 ,
MV_V2_TEMP_CTRL_DISABLE = 0xc000 ,
MV_V2_TEMP = 0xf08c ,
MV_V2_TEMP_UNKNOWN = 0x9600 , /* unknown function */
} ;
2021-04-07 22:22:45 +02:00
struct mv3310_chip {
2021-04-07 22:22:46 +02:00
void ( * init_supported_interfaces ) ( unsigned long * mask ) ;
2021-04-07 22:22:45 +02:00
int ( * get_mactype ) ( struct phy_device * phydev ) ;
int ( * init_interface ) ( struct phy_device * phydev , int mactype ) ;
2021-04-07 22:22:47 +02:00
# ifdef CONFIG_HWMON
int ( * hwmon_read_temp_reg ) ( struct phy_device * phydev ) ;
# endif
2021-04-07 22:22:45 +02:00
} ;
2018-04-03 10:31:45 +01:00
struct mv3310_priv {
2021-04-07 22:22:46 +02:00
DECLARE_BITMAP ( supported_interfaces , PHY_INTERFACE_MODE_MAX ) ;
2020-04-14 20:49:03 +01:00
u32 firmware_ver ;
2020-06-28 10:04:51 +03:00
bool rate_match ;
2021-04-07 22:22:45 +02:00
phy_interface_t const_interface ;
2020-04-14 20:49:03 +01:00
2018-04-03 10:31:45 +01:00
struct device * hwmon_dev ;
char * hwmon_name ;
2017-06-05 12:23:16 +01:00
} ;
2021-04-07 22:22:45 +02:00
static const struct mv3310_chip * to_mv3310_chip ( struct phy_device * phydev )
{
return phydev - > drv - > driver_data ;
}
2018-04-03 10:31:45 +01:00
# ifdef CONFIG_HWMON
static umode_t mv3310_hwmon_is_visible ( const void * data ,
enum hwmon_sensor_types type ,
u32 attr , int channel )
{
if ( type = = hwmon_chip & & attr = = hwmon_chip_update_interval )
return 0444 ;
if ( type = = hwmon_temp & & attr = = hwmon_temp_input )
return 0444 ;
return 0 ;
}
2020-04-26 09:22:06 +03:00
static int mv3310_hwmon_read_temp_reg ( struct phy_device * phydev )
{
return phy_read_mmd ( phydev , MDIO_MMD_VEND2 , MV_V2_TEMP ) ;
}
static int mv2110_hwmon_read_temp_reg ( struct phy_device * phydev )
{
return phy_read_mmd ( phydev , MDIO_MMD_PCS , MV_PCS_TEMP ) ;
}
2018-04-03 10:31:45 +01:00
static int mv3310_hwmon_read ( struct device * dev , enum hwmon_sensor_types type ,
u32 attr , int channel , long * value )
{
struct phy_device * phydev = dev_get_drvdata ( dev ) ;
2021-04-07 22:22:47 +02:00
const struct mv3310_chip * chip = to_mv3310_chip ( phydev ) ;
2018-04-03 10:31:45 +01:00
int temp ;
if ( type = = hwmon_chip & & attr = = hwmon_chip_update_interval ) {
* value = MSEC_PER_SEC ;
return 0 ;
}
if ( type = = hwmon_temp & & attr = = hwmon_temp_input ) {
2021-04-07 22:22:47 +02:00
temp = chip - > hwmon_read_temp_reg ( phydev ) ;
2018-04-03 10:31:45 +01:00
if ( temp < 0 )
return temp ;
* value = ( ( temp & 0xff ) - 75 ) * 1000 ;
return 0 ;
}
return - EOPNOTSUPP ;
}
static const struct hwmon_ops mv3310_hwmon_ops = {
. is_visible = mv3310_hwmon_is_visible ,
. read = mv3310_hwmon_read ,
} ;
static u32 mv3310_hwmon_chip_config [ ] = {
HWMON_C_REGISTER_TZ | HWMON_C_UPDATE_INTERVAL ,
0 ,
} ;
static const struct hwmon_channel_info mv3310_hwmon_chip = {
. type = hwmon_chip ,
. config = mv3310_hwmon_chip_config ,
} ;
static u32 mv3310_hwmon_temp_config [ ] = {
HWMON_T_INPUT ,
0 ,
} ;
static const struct hwmon_channel_info mv3310_hwmon_temp = {
. type = hwmon_temp ,
. config = mv3310_hwmon_temp_config ,
} ;
static const struct hwmon_channel_info * mv3310_hwmon_info [ ] = {
& mv3310_hwmon_chip ,
& mv3310_hwmon_temp ,
NULL ,
} ;
static const struct hwmon_chip_info mv3310_hwmon_chip_info = {
. ops = & mv3310_hwmon_ops ,
. info = mv3310_hwmon_info ,
} ;
static int mv3310_hwmon_config ( struct phy_device * phydev , bool enable )
{
u16 val ;
int ret ;
2020-04-26 09:22:06 +03:00
if ( phydev - > drv - > phy_id ! = MARVELL_PHY_ID_88X3310 )
return 0 ;
2018-04-03 10:31:45 +01:00
ret = phy_write_mmd ( phydev , MDIO_MMD_VEND2 , MV_V2_TEMP ,
MV_V2_TEMP_UNKNOWN ) ;
if ( ret < 0 )
return ret ;
val = enable ? MV_V2_TEMP_CTRL_SAMPLE : MV_V2_TEMP_CTRL_DISABLE ;
2019-02-10 19:58:49 +01:00
return phy_modify_mmd ( phydev , MDIO_MMD_VEND2 , MV_V2_TEMP_CTRL ,
MV_V2_TEMP_CTRL_MASK , val ) ;
2018-04-03 10:31:45 +01:00
}
static int mv3310_hwmon_probe ( struct phy_device * phydev )
{
struct device * dev = & phydev - > mdio . dev ;
struct mv3310_priv * priv = dev_get_drvdata ( & phydev - > mdio . dev ) ;
int i , j , ret ;
priv - > hwmon_name = devm_kstrdup ( dev , dev_name ( dev ) , GFP_KERNEL ) ;
if ( ! priv - > hwmon_name )
return - ENODEV ;
for ( i = j = 0 ; priv - > hwmon_name [ i ] ; i + + ) {
if ( isalnum ( priv - > hwmon_name [ i ] ) ) {
if ( i ! = j )
priv - > hwmon_name [ j ] = priv - > hwmon_name [ i ] ;
j + + ;
}
}
priv - > hwmon_name [ j ] = ' \0 ' ;
ret = mv3310_hwmon_config ( phydev , true ) ;
if ( ret )
return ret ;
priv - > hwmon_dev = devm_hwmon_device_register_with_info ( dev ,
priv - > hwmon_name , phydev ,
& mv3310_hwmon_chip_info , NULL ) ;
return PTR_ERR_OR_ZERO ( priv - > hwmon_dev ) ;
}
# else
static inline int mv3310_hwmon_config ( struct phy_device * phydev , bool enable )
{
return 0 ;
}
static int mv3310_hwmon_probe ( struct phy_device * phydev )
{
return 0 ;
}
# endif
2020-03-03 18:08:45 +00:00
static int mv3310_power_down ( struct phy_device * phydev )
{
return phy_set_bits_mmd ( phydev , MDIO_MMD_VEND2 , MV_V2_PORT_CTRL ,
MV_V2_PORT_CTRL_PWRDOWN ) ;
}
static int mv3310_power_up ( struct phy_device * phydev )
{
2020-04-14 20:49:08 +01:00
struct mv3310_priv * priv = dev_get_drvdata ( & phydev - > mdio . dev ) ;
int ret ;
ret = phy_clear_bits_mmd ( phydev , MDIO_MMD_VEND2 , MV_V2_PORT_CTRL ,
MV_V2_PORT_CTRL_PWRDOWN ) ;
2020-04-21 12:04:46 +03:00
if ( phydev - > drv - > phy_id ! = MARVELL_PHY_ID_88X3310 | |
priv - > firmware_ver < 0x00030000 )
2020-04-14 20:49:08 +01:00
return ret ;
return phy_set_bits_mmd ( phydev , MDIO_MMD_VEND2 , MV_V2_PORT_CTRL ,
2021-04-07 22:22:42 +02:00
MV_V2_33X0_PORT_CTRL_SWRST ) ;
2020-03-03 18:08:45 +00:00
}
2020-03-03 18:08:34 +00:00
static int mv3310_reset ( struct phy_device * phydev , u32 unit )
{
2020-03-23 23:05:56 +08:00
int val , err ;
2020-03-03 18:08:34 +00:00
err = phy_modify_mmd ( phydev , MDIO_MMD_PCS , unit + MDIO_CTRL1 ,
MDIO_CTRL1_RESET , MDIO_CTRL1_RESET ) ;
if ( err < 0 )
return err ;
2020-03-23 23:05:56 +08:00
return phy_read_mmd_poll_timeout ( phydev , MDIO_MMD_PCS ,
unit + MDIO_CTRL1 , val ,
! ( val & MDIO_CTRL1_RESET ) ,
5000 , 100000 , true ) ;
2020-03-03 18:08:34 +00:00
}
2020-03-03 18:08:40 +00:00
static int mv3310_get_edpd ( struct phy_device * phydev , u16 * edpd )
{
int val ;
val = phy_read_mmd ( phydev , MDIO_MMD_PCS , MV_PCS_CSCR1 ) ;
if ( val < 0 )
return val ;
switch ( val & MV_PCS_CSCR1_ED_MASK ) {
case MV_PCS_CSCR1_ED_NLP :
* edpd = 1000 ;
break ;
case MV_PCS_CSCR1_ED_RX :
* edpd = ETHTOOL_PHY_EDPD_NO_TX ;
break ;
default :
* edpd = ETHTOOL_PHY_EDPD_DISABLE ;
break ;
}
return 0 ;
}
static int mv3310_set_edpd ( struct phy_device * phydev , u16 edpd )
{
u16 val ;
int err ;
switch ( edpd ) {
case 1000 :
case ETHTOOL_PHY_EDPD_DFLT_TX_MSECS :
val = MV_PCS_CSCR1_ED_NLP ;
break ;
case ETHTOOL_PHY_EDPD_NO_TX :
val = MV_PCS_CSCR1_ED_RX ;
break ;
case ETHTOOL_PHY_EDPD_DISABLE :
val = MV_PCS_CSCR1_ED_OFF ;
break ;
default :
return - EINVAL ;
}
err = phy_modify_mmd_changed ( phydev , MDIO_MMD_PCS , MV_PCS_CSCR1 ,
MV_PCS_CSCR1_ED_MASK , val ) ;
if ( err > 0 )
err = mv3310_reset ( phydev , MV_PCS_BASE_T ) ;
return err ;
}
2019-11-15 19:56:56 +00:00
static int mv3310_sfp_insert ( void * upstream , const struct sfp_eeprom_id * id )
{
struct phy_device * phydev = upstream ;
__ETHTOOL_DECLARE_LINK_MODE_MASK ( support ) = { 0 , } ;
phy_interface_t iface ;
sfp_parse_support ( phydev - > sfp_bus , id , support ) ;
2019-12-11 10:55:59 +00:00
iface = sfp_select_interface ( phydev - > sfp_bus , support ) ;
2019-11-15 19:56:56 +00:00
2020-01-03 20:43:23 +00:00
if ( iface ! = PHY_INTERFACE_MODE_10GBASER ) {
2019-11-15 19:56:56 +00:00
dev_err ( & phydev - > mdio . dev , " incompatible SFP module inserted \n " ) ;
return - EINVAL ;
}
return 0 ;
}
static const struct sfp_upstream_ops mv3310_sfp_ops = {
. attach = phy_sfp_attach ,
. detach = phy_sfp_detach ,
. module_insert = mv3310_sfp_insert ,
} ;
2017-06-05 12:23:16 +01:00
static int mv3310_probe ( struct phy_device * phydev )
{
2021-04-07 22:22:46 +02:00
const struct mv3310_chip * chip = to_mv3310_chip ( phydev ) ;
2018-04-03 10:31:45 +01:00
struct mv3310_priv * priv ;
2017-06-05 12:23:16 +01:00
u32 mmd_mask = MDIO_DEVS_PMAPMD | MDIO_DEVS_AN ;
2018-04-03 10:31:45 +01:00
int ret ;
2017-06-05 12:23:16 +01:00
if ( ! phydev - > is_c45 | |
( phydev - > c45_ids . devices_in_package & mmd_mask ) ! = mmd_mask )
return - ENODEV ;
2019-05-28 10:34:42 +01:00
ret = phy_read_mmd ( phydev , MDIO_MMD_PMAPMD , MV_PMA_BOOT ) ;
if ( ret < 0 )
return ret ;
if ( ret & MV_PMA_BOOT_FATAL ) {
dev_warn ( & phydev - > mdio . dev ,
" PHY failed to boot firmware, status=%04x \n " , ret ) ;
return - ENODEV ;
}
2018-04-03 10:31:45 +01:00
priv = devm_kzalloc ( & phydev - > mdio . dev , sizeof ( * priv ) , GFP_KERNEL ) ;
if ( ! priv )
return - ENOMEM ;
dev_set_drvdata ( & phydev - > mdio . dev , priv ) ;
2020-04-14 20:49:03 +01:00
ret = phy_read_mmd ( phydev , MDIO_MMD_PMAPMD , MV_PMA_FW_VER0 ) ;
if ( ret < 0 )
return ret ;
priv - > firmware_ver = ret < < 16 ;
ret = phy_read_mmd ( phydev , MDIO_MMD_PMAPMD , MV_PMA_FW_VER1 ) ;
if ( ret < 0 )
return ret ;
priv - > firmware_ver | = ret ;
phydev_info ( phydev , " Firmware version %u.%u.%u.%u \n " ,
priv - > firmware_ver > > 24 , ( priv - > firmware_ver > > 16 ) & 255 ,
( priv - > firmware_ver > > 8 ) & 255 , priv - > firmware_ver & 255 ) ;
2020-03-03 18:08:45 +00:00
/* Powering down the port when not in use saves about 600mW */
ret = mv3310_power_down ( phydev ) ;
if ( ret )
return ret ;
2018-04-03 10:31:45 +01:00
ret = mv3310_hwmon_probe ( phydev ) ;
if ( ret )
return ret ;
2021-04-07 22:22:46 +02:00
chip - > init_supported_interfaces ( priv - > supported_interfaces ) ;
2019-11-15 19:56:56 +00:00
return phy_sfp_probe ( phydev , & mv3310_sfp_ops ) ;
2018-04-03 10:31:45 +01:00
}
2020-08-10 17:01:58 +02:00
static void mv3310_remove ( struct phy_device * phydev )
{
mv3310_hwmon_config ( phydev , false ) ;
}
2018-04-03 10:31:45 +01:00
static int mv3310_suspend ( struct phy_device * phydev )
{
2020-03-03 18:08:45 +00:00
return mv3310_power_down ( phydev ) ;
2017-06-05 12:23:16 +01:00
}
2018-04-03 10:31:45 +01:00
static int mv3310_resume ( struct phy_device * phydev )
{
2019-04-02 15:10:28 +02:00
int ret ;
2020-03-03 18:08:45 +00:00
ret = mv3310_power_up ( phydev ) ;
2019-04-02 15:10:28 +02:00
if ( ret )
return ret ;
2018-04-03 10:31:45 +01:00
return mv3310_hwmon_config ( phydev , true ) ;
}
2019-02-23 00:37:42 +01:00
/* Some PHYs in the Alaska family such as the 88X3310 and the 88E2010
* don ' t set bit 14 in PMA Extended Abilities ( 1.11 ) , although they do
* support 2.5 GBASET and 5 GBASET . For these models , we can still read their
* 2.5 G / 5 G extended abilities register ( 1.21 ) . We detect these models based on
* the PMA device identifier , with a mask matching models known to have this
* issue
*/
static bool mv3310_has_pma_ngbaset_quirk ( struct phy_device * phydev )
{
if ( ! ( phydev - > c45_ids . devices_in_package & MDIO_DEVS_PMAPMD ) )
return false ;
/* Only some revisions of the 88X3310 family PMA seem to be impacted */
return ( phydev - > c45_ids . device_ids [ MDIO_MMD_PMAPMD ] &
MV_PHY_ALASKA_NBT_QUIRK_MASK ) = = MV_PHY_ALASKA_NBT_QUIRK_REV ;
}
2021-04-07 22:22:45 +02:00
static int mv2110_get_mactype ( struct phy_device * phydev )
{
int mactype ;
mactype = phy_read_mmd ( phydev , MDIO_MMD_PMAPMD , MV_PMA_21X0_PORT_CTRL ) ;
if ( mactype < 0 )
return mactype ;
return mactype & MV_PMA_21X0_PORT_CTRL_MACTYPE_MASK ;
}
static int mv3310_get_mactype ( struct phy_device * phydev )
{
int mactype ;
mactype = phy_read_mmd ( phydev , MDIO_MMD_VEND2 , MV_V2_PORT_CTRL ) ;
if ( mactype < 0 )
return mactype ;
return mactype & MV_V2_33X0_PORT_CTRL_MACTYPE_MASK ;
}
static int mv2110_init_interface ( struct phy_device * phydev , int mactype )
2017-06-05 12:23:16 +01:00
{
2020-06-28 10:04:51 +03:00
struct mv3310_priv * priv = dev_get_drvdata ( & phydev - > mdio . dev ) ;
2021-04-07 22:22:45 +02:00
priv - > rate_match = false ;
2021-04-07 22:22:48 +02:00
if ( mactype = = MV_PMA_21X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH )
2021-04-07 22:22:45 +02:00
priv - > rate_match = true ;
2021-04-07 22:22:48 +02:00
if ( mactype = = MV_PMA_21X0_PORT_CTRL_MACTYPE_USXGMII )
priv - > const_interface = PHY_INTERFACE_MODE_USXGMII ;
else if ( mactype = = MV_PMA_21X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH )
2021-04-07 22:22:45 +02:00
priv - > const_interface = PHY_INTERFACE_MODE_10GBASER ;
2021-04-07 22:22:48 +02:00
else if ( mactype = = MV_PMA_21X0_PORT_CTRL_MACTYPE_5GBASER | |
mactype = = MV_PMA_21X0_PORT_CTRL_MACTYPE_5GBASER_NO_SGMII_AN )
priv - > const_interface = PHY_INTERFACE_MODE_NA ;
else
return - EINVAL ;
2021-04-07 22:22:45 +02:00
return 0 ;
}
static int mv3310_init_interface ( struct phy_device * phydev , int mactype )
{
struct mv3310_priv * priv = dev_get_drvdata ( & phydev - > mdio . dev ) ;
priv - > rate_match = false ;
if ( mactype = = MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH | |
mactype = = MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI_RATE_MATCH | |
mactype = = MV_V2_3310_PORT_CTRL_MACTYPE_XAUI_RATE_MATCH )
priv - > rate_match = true ;
2021-04-07 22:22:48 +02:00
if ( mactype = = MV_V2_33X0_PORT_CTRL_MACTYPE_USXGMII )
priv - > const_interface = PHY_INTERFACE_MODE_USXGMII ;
else if ( mactype = = MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH | |
mactype = = MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_NO_SGMII_AN | |
mactype = = MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER )
2021-04-07 22:22:45 +02:00
priv - > const_interface = PHY_INTERFACE_MODE_10GBASER ;
2021-04-07 22:22:48 +02:00
else if ( mactype = = MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI_RATE_MATCH | |
mactype = = MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI )
2021-04-07 22:22:45 +02:00
priv - > const_interface = PHY_INTERFACE_MODE_RXAUI ;
2021-04-07 22:22:48 +02:00
else if ( mactype = = MV_V2_3310_PORT_CTRL_MACTYPE_XAUI_RATE_MATCH | |
mactype = = MV_V2_3310_PORT_CTRL_MACTYPE_XAUI )
2021-04-07 22:22:45 +02:00
priv - > const_interface = PHY_INTERFACE_MODE_XAUI ;
2021-04-07 22:22:48 +02:00
else
return - EINVAL ;
2021-04-07 22:22:45 +02:00
return 0 ;
}
2021-04-07 22:22:49 +02:00
static int mv3340_init_interface ( struct phy_device * phydev , int mactype )
{
struct mv3310_priv * priv = dev_get_drvdata ( & phydev - > mdio . dev ) ;
int err = 0 ;
priv - > rate_match = false ;
if ( mactype = = MV_V2_3340_PORT_CTRL_MACTYPE_RXAUI_NO_SGMII_AN )
priv - > const_interface = PHY_INTERFACE_MODE_RXAUI ;
else
err = mv3310_init_interface ( phydev , mactype ) ;
return err ;
}
2021-04-07 22:22:45 +02:00
static int mv3310_config_init ( struct phy_device * phydev )
{
2021-04-07 22:22:46 +02:00
struct mv3310_priv * priv = dev_get_drvdata ( & phydev - > mdio . dev ) ;
2021-04-07 22:22:45 +02:00
const struct mv3310_chip * chip = to_mv3310_chip ( phydev ) ;
int err , mactype ;
2020-03-03 18:08:45 +00:00
2017-06-05 12:23:16 +01:00
/* Check that the PHY interface type is compatible */
2021-04-07 22:22:46 +02:00
if ( ! test_bit ( phydev - > interface , priv - > supported_interfaces ) )
2017-06-05 12:23:16 +01:00
return - ENODEV ;
2020-03-03 18:08:34 +00:00
phydev - > mdix_ctrl = ETH_TP_MDI_AUTO ;
2020-03-03 18:08:45 +00:00
/* Power up so reset works */
err = mv3310_power_up ( phydev ) ;
if ( err )
return err ;
2021-04-07 22:22:45 +02:00
mactype = chip - > get_mactype ( phydev ) ;
if ( mactype < 0 )
return mactype ;
err = chip - > init_interface ( phydev , mactype ) ;
2021-04-07 22:22:48 +02:00
if ( err ) {
phydev_err ( phydev , " MACTYPE configuration invalid \n " ) ;
2021-04-07 22:22:45 +02:00
return err ;
2021-04-07 22:22:48 +02:00
}
2020-06-28 10:04:51 +03:00
2020-03-03 18:08:40 +00:00
/* Enable EDPD mode - saving 600mW */
return mv3310_set_edpd ( phydev , ETHTOOL_PHY_EDPD_DFLT_TX_MSECS ) ;
2019-02-23 00:37:38 +01:00
}
static int mv3310_get_features ( struct phy_device * phydev )
{
int ret , val ;
2019-02-11 15:25:28 +01:00
ret = genphy_c45_pma_read_abilities ( phydev ) ;
if ( ret )
return ret ;
2017-06-05 12:23:16 +01:00
2019-02-23 00:37:42 +01:00
if ( mv3310_has_pma_ngbaset_quirk ( phydev ) ) {
val = phy_read_mmd ( phydev , MDIO_MMD_PMAPMD ,
MDIO_PMA_NG_EXTABLE ) ;
if ( val < 0 )
return val ;
linkmode_mod_bit ( ETHTOOL_LINK_MODE_2500baseT_Full_BIT ,
phydev - > supported ,
val & MDIO_PMA_NG_EXTABLE_2_5GBT ) ;
linkmode_mod_bit ( ETHTOOL_LINK_MODE_5000baseT_Full_BIT ,
phydev - > supported ,
val & MDIO_PMA_NG_EXTABLE_5GBT ) ;
}
2017-06-05 12:23:16 +01:00
return 0 ;
}
2020-03-03 18:08:34 +00:00
static int mv3310_config_mdix ( struct phy_device * phydev )
{
u16 val ;
int err ;
switch ( phydev - > mdix_ctrl ) {
case ETH_TP_MDI_AUTO :
val = MV_PCS_CSCR1_MDIX_AUTO ;
break ;
case ETH_TP_MDI_X :
val = MV_PCS_CSCR1_MDIX_MDIX ;
break ;
case ETH_TP_MDI :
val = MV_PCS_CSCR1_MDIX_MDI ;
break ;
default :
return - EINVAL ;
}
err = phy_modify_mmd_changed ( phydev , MDIO_MMD_PCS , MV_PCS_CSCR1 ,
MV_PCS_CSCR1_MDIX_MASK , val ) ;
if ( err > 0 )
err = mv3310_reset ( phydev , MV_PCS_BASE_T ) ;
return err ;
}
2017-06-05 12:23:16 +01:00
static int mv3310_config_aneg ( struct phy_device * phydev )
{
bool changed = false ;
2018-11-10 23:43:33 +01:00
u16 reg ;
2017-06-05 12:23:16 +01:00
int ret ;
2020-03-03 18:08:34 +00:00
ret = mv3310_config_mdix ( phydev ) ;
if ( ret < 0 )
return ret ;
2017-12-29 12:46:27 +00:00
2019-02-16 20:44:59 +01:00
if ( phydev - > autoneg = = AUTONEG_DISABLE )
return genphy_c45_pma_setup_forced ( phydev ) ;
2017-06-05 12:23:16 +01:00
2019-02-17 10:30:45 +01:00
ret = genphy_c45_an_config_aneg ( phydev ) ;
2017-06-05 12:23:16 +01:00
if ( ret < 0 )
return ret ;
if ( ret > 0 )
changed = true ;
2019-02-17 10:30:45 +01:00
/* Clause 45 has no standardized support for 1000BaseT, therefore
* use vendor registers for this mode .
*/
2018-11-10 23:43:33 +01:00
reg = linkmode_adv_to_mii_ctrl1000_t ( phydev - > advertising ) ;
2019-02-10 19:58:49 +01:00
ret = phy_modify_mmd_changed ( phydev , MDIO_MMD_AN , MV_AN_CTRL1000 ,
2019-02-06 07:38:43 +01:00
ADVERTISE_1000FULL | ADVERTISE_1000HALF , reg ) ;
2017-06-05 12:23:16 +01:00
if ( ret < 0 )
return ret ;
if ( ret > 0 )
changed = true ;
2019-02-18 21:27:46 +01:00
return genphy_c45_check_and_restart_aneg ( phydev , changed ) ;
2017-06-05 12:23:16 +01:00
}
static int mv3310_aneg_done ( struct phy_device * phydev )
{
int val ;
val = phy_read_mmd ( phydev , MDIO_MMD_PCS , MV_PCS_BASE_R + MDIO_STAT1 ) ;
if ( val < 0 )
return val ;
if ( val & MDIO_STAT1_LSTATUS )
return 1 ;
return genphy_c45_aneg_done ( phydev ) ;
}
2017-12-29 12:46:32 +00:00
static void mv3310_update_interface ( struct phy_device * phydev )
{
2020-06-28 10:04:51 +03:00
struct mv3310_priv * priv = dev_get_drvdata ( & phydev - > mdio . dev ) ;
2021-04-07 22:22:48 +02:00
if ( ! phydev - > link )
return ;
2021-04-07 22:22:45 +02:00
/* In all of the "* with Rate Matching" modes the PHY interface is fixed
* at 10 Gb . The PHY adapts the rate to actual wire speed with help of
2020-06-28 10:04:51 +03:00
* internal 16 KB buffer .
2021-04-07 22:22:48 +02:00
*
* In USXGMII mode the PHY interface mode is also fixed .
2020-06-28 10:04:51 +03:00
*/
2021-04-07 22:22:48 +02:00
if ( priv - > rate_match | |
priv - > const_interface = = PHY_INTERFACE_MODE_USXGMII ) {
2021-04-07 22:22:45 +02:00
phydev - > interface = priv - > const_interface ;
2020-06-28 10:04:51 +03:00
return ;
}
2021-04-07 22:22:48 +02:00
/* The PHY automatically switches its serdes interface (and active PHYXS
* instance ) between Cisco SGMII , 2500 BaseX , 5 GBase - R and 10 GBase - R /
* xaui / rxaui modes according to the speed .
* Florian suggests setting phydev - > interface to communicate this to the
* MAC . Only do this if we are already in one of the above modes .
*/
switch ( phydev - > speed ) {
case SPEED_10000 :
phydev - > interface = priv - > const_interface ;
break ;
case SPEED_5000 :
phydev - > interface = PHY_INTERFACE_MODE_5GBASER ;
break ;
case SPEED_2500 :
phydev - > interface = PHY_INTERFACE_MODE_2500BASEX ;
break ;
case SPEED_1000 :
case SPEED_100 :
case SPEED_10 :
phydev - > interface = PHY_INTERFACE_MODE_SGMII ;
break ;
default :
break ;
2017-12-29 12:46:32 +00:00
}
}
2017-06-05 12:23:16 +01:00
/* 10GBASE-ER,LR,LRM,SR do not support autonegotiation. */
2020-02-27 09:46:36 +00:00
static int mv3310_read_status_10gbaser ( struct phy_device * phydev )
2017-06-05 12:23:16 +01:00
{
phydev - > link = 1 ;
phydev - > speed = SPEED_10000 ;
phydev - > duplex = DUPLEX_FULL ;
2021-02-09 17:38:52 +01:00
phydev - > port = PORT_FIBRE ;
2017-06-05 12:23:16 +01:00
return 0 ;
}
2020-02-27 09:46:36 +00:00
static int mv3310_read_status_copper ( struct phy_device * phydev )
2017-06-05 12:23:16 +01:00
{
2020-02-27 09:46:36 +00:00
int cssr1 , speed , val ;
2017-06-05 12:23:16 +01:00
2019-02-07 21:41:46 +01:00
val = genphy_c45_read_link ( phydev ) ;
2017-06-05 12:23:16 +01:00
if ( val < 0 )
return val ;
val = phy_read_mmd ( phydev , MDIO_MMD_AN , MDIO_STAT1 ) ;
if ( val < 0 )
return val ;
2020-02-27 09:46:36 +00:00
cssr1 = phy_read_mmd ( phydev , MDIO_MMD_PCS , MV_PCS_CSSR1 ) ;
if ( cssr1 < 0 )
return val ;
/* If the link settings are not resolved, mark the link down */
if ( ! ( cssr1 & MV_PCS_CSSR1_RESOLVED ) ) {
phydev - > link = 0 ;
return 0 ;
}
/* Read the copper link settings */
speed = cssr1 & MV_PCS_CSSR1_SPD1_MASK ;
if ( speed = = MV_PCS_CSSR1_SPD1_SPD2 )
speed | = cssr1 & MV_PCS_CSSR1_SPD2_MASK ;
switch ( speed ) {
case MV_PCS_CSSR1_SPD1_SPD2 | MV_PCS_CSSR1_SPD2_10000 :
phydev - > speed = SPEED_10000 ;
break ;
case MV_PCS_CSSR1_SPD1_SPD2 | MV_PCS_CSSR1_SPD2_5000 :
phydev - > speed = SPEED_5000 ;
break ;
case MV_PCS_CSSR1_SPD1_SPD2 | MV_PCS_CSSR1_SPD2_2500 :
phydev - > speed = SPEED_2500 ;
break ;
case MV_PCS_CSSR1_SPD1_1000 :
phydev - > speed = SPEED_1000 ;
break ;
case MV_PCS_CSSR1_SPD1_100 :
phydev - > speed = SPEED_100 ;
break ;
case MV_PCS_CSSR1_SPD1_10 :
phydev - > speed = SPEED_10 ;
break ;
}
phydev - > duplex = cssr1 & MV_PCS_CSSR1_DUPLEX_FULL ?
DUPLEX_FULL : DUPLEX_HALF ;
2021-02-09 17:38:52 +01:00
phydev - > port = PORT_TP ;
2020-02-27 09:46:36 +00:00
phydev - > mdix = cssr1 & MV_PCS_CSSR1_MDIX ?
ETH_TP_MDI_X : ETH_TP_MDI ;
2017-06-05 12:23:16 +01:00
if ( val & MDIO_AN_STAT1_COMPLETE ) {
val = genphy_c45_read_lpa ( phydev ) ;
if ( val < 0 )
return val ;
2018-03-01 10:23:03 +00:00
/* Read the link partner's 1G advertisement */
2017-06-05 12:23:16 +01:00
val = phy_read_mmd ( phydev , MDIO_MMD_AN , MV_AN_STAT1000 ) ;
if ( val < 0 )
return val ;
2018-12-05 21:49:41 +01:00
mii_stat1000_mod_linkmode_lpa_t ( phydev - > lp_advertising , val ) ;
2017-06-05 12:23:16 +01:00
2020-02-27 09:46:36 +00:00
/* Update the pause status */
phy_resolve_aneg_pause ( phydev ) ;
2017-06-05 12:23:16 +01:00
}
2020-02-27 09:46:36 +00:00
return 0 ;
}
2017-06-05 12:23:16 +01:00
2020-02-27 09:46:36 +00:00
static int mv3310_read_status ( struct phy_device * phydev )
{
int err , val ;
2017-12-29 12:46:27 +00:00
2020-02-27 09:46:36 +00:00
phydev - > speed = SPEED_UNKNOWN ;
phydev - > duplex = DUPLEX_UNKNOWN ;
linkmode_zero ( phydev - > lp_advertising ) ;
phydev - > link = 0 ;
phydev - > pause = 0 ;
phydev - > asym_pause = 0 ;
phydev - > mdix = ETH_TP_MDI_INVALID ;
2017-12-29 12:46:27 +00:00
2020-02-27 09:46:36 +00:00
val = phy_read_mmd ( phydev , MDIO_MMD_PCS , MV_PCS_BASE_R + MDIO_STAT1 ) ;
if ( val < 0 )
return val ;
if ( val & MDIO_STAT1_LSTATUS )
err = mv3310_read_status_10gbaser ( phydev ) ;
else
err = mv3310_read_status_copper ( phydev ) ;
if ( err < 0 )
return err ;
if ( phydev - > link )
mv3310_update_interface ( phydev ) ;
2017-06-05 12:23:16 +01:00
return 0 ;
}
2020-03-03 18:08:40 +00:00
static int mv3310_get_tunable ( struct phy_device * phydev ,
struct ethtool_tunable * tuna , void * data )
{
switch ( tuna - > id ) {
case ETHTOOL_PHY_EDPD :
return mv3310_get_edpd ( phydev , data ) ;
default :
return - EOPNOTSUPP ;
}
}
static int mv3310_set_tunable ( struct phy_device * phydev ,
struct ethtool_tunable * tuna , const void * data )
{
switch ( tuna - > id ) {
case ETHTOOL_PHY_EDPD :
return mv3310_set_edpd ( phydev , * ( u16 * ) data ) ;
default :
return - EOPNOTSUPP ;
}
}
2021-04-07 22:22:46 +02:00
static void mv3310_init_supported_interfaces ( unsigned long * mask )
{
__set_bit ( PHY_INTERFACE_MODE_SGMII , mask ) ;
__set_bit ( PHY_INTERFACE_MODE_2500BASEX , mask ) ;
__set_bit ( PHY_INTERFACE_MODE_5GBASER , mask ) ;
__set_bit ( PHY_INTERFACE_MODE_XAUI , mask ) ;
__set_bit ( PHY_INTERFACE_MODE_RXAUI , mask ) ;
__set_bit ( PHY_INTERFACE_MODE_10GBASER , mask ) ;
__set_bit ( PHY_INTERFACE_MODE_USXGMII , mask ) ;
}
2021-04-07 22:22:49 +02:00
static void mv3340_init_supported_interfaces ( unsigned long * mask )
{
__set_bit ( PHY_INTERFACE_MODE_SGMII , mask ) ;
__set_bit ( PHY_INTERFACE_MODE_2500BASEX , mask ) ;
__set_bit ( PHY_INTERFACE_MODE_5GBASER , mask ) ;
__set_bit ( PHY_INTERFACE_MODE_RXAUI , mask ) ;
__set_bit ( PHY_INTERFACE_MODE_10GBASER , mask ) ;
__set_bit ( PHY_INTERFACE_MODE_USXGMII , mask ) ;
}
2021-04-07 22:22:46 +02:00
static void mv2110_init_supported_interfaces ( unsigned long * mask )
{
__set_bit ( PHY_INTERFACE_MODE_SGMII , mask ) ;
__set_bit ( PHY_INTERFACE_MODE_2500BASEX , mask ) ;
__set_bit ( PHY_INTERFACE_MODE_5GBASER , mask ) ;
__set_bit ( PHY_INTERFACE_MODE_10GBASER , mask ) ;
__set_bit ( PHY_INTERFACE_MODE_USXGMII , mask ) ;
}
2021-04-07 22:22:52 +02:00
static void mv2111_init_supported_interfaces ( unsigned long * mask )
{
__set_bit ( PHY_INTERFACE_MODE_SGMII , mask ) ;
__set_bit ( PHY_INTERFACE_MODE_2500BASEX , mask ) ;
__set_bit ( PHY_INTERFACE_MODE_10GBASER , mask ) ;
__set_bit ( PHY_INTERFACE_MODE_USXGMII , mask ) ;
}
2021-04-07 22:22:45 +02:00
static const struct mv3310_chip mv3310_type = {
2021-04-07 22:22:46 +02:00
. init_supported_interfaces = mv3310_init_supported_interfaces ,
2021-04-07 22:22:45 +02:00
. get_mactype = mv3310_get_mactype ,
. init_interface = mv3310_init_interface ,
2021-04-07 22:22:47 +02:00
# ifdef CONFIG_HWMON
. hwmon_read_temp_reg = mv3310_hwmon_read_temp_reg ,
# endif
2021-04-07 22:22:45 +02:00
} ;
2021-04-07 22:22:49 +02:00
static const struct mv3310_chip mv3340_type = {
. init_supported_interfaces = mv3340_init_supported_interfaces ,
. get_mactype = mv3310_get_mactype ,
. init_interface = mv3340_init_interface ,
# ifdef CONFIG_HWMON
. hwmon_read_temp_reg = mv3310_hwmon_read_temp_reg ,
# endif
} ;
2021-04-07 22:22:45 +02:00
static const struct mv3310_chip mv2110_type = {
2021-04-07 22:22:46 +02:00
. init_supported_interfaces = mv2110_init_supported_interfaces ,
2021-04-07 22:22:45 +02:00
. get_mactype = mv2110_get_mactype ,
. init_interface = mv2110_init_interface ,
2021-04-07 22:22:47 +02:00
# ifdef CONFIG_HWMON
. hwmon_read_temp_reg = mv2110_hwmon_read_temp_reg ,
# endif
2021-04-07 22:22:45 +02:00
} ;
2021-04-07 22:22:52 +02:00
static const struct mv3310_chip mv2111_type = {
. init_supported_interfaces = mv2111_init_supported_interfaces ,
. get_mactype = mv2110_get_mactype ,
. init_interface = mv2110_init_interface ,
# ifdef CONFIG_HWMON
. hwmon_read_temp_reg = mv2110_hwmon_read_temp_reg ,
# endif
} ;
2021-07-11 18:38:15 +02:00
static int mv3310_get_number_of_ports ( struct phy_device * phydev )
{
int ret ;
ret = phy_read_mmd ( phydev , MDIO_MMD_PCS , MV_PCS_PORT_INFO ) ;
if ( ret < 0 )
return ret ;
ret & = MV_PCS_PORT_INFO_NPORTS_MASK ;
ret > > = MV_PCS_PORT_INFO_NPORTS_SHIFT ;
return ret + 1 ;
}
static int mv3310_match_phy_device ( struct phy_device * phydev )
{
return mv3310_get_number_of_ports ( phydev ) = = 1 ;
}
static int mv3340_match_phy_device ( struct phy_device * phydev )
{
return mv3310_get_number_of_ports ( phydev ) = = 4 ;
}
2021-04-07 22:22:52 +02:00
static int mv211x_match_phy_device ( struct phy_device * phydev , bool has_5g )
{
int val ;
if ( ( phydev - > c45_ids . device_ids [ MDIO_MMD_PMAPMD ] &
MARVELL_PHY_ID_MASK ) ! = MARVELL_PHY_ID_88E2110 )
return 0 ;
val = phy_read_mmd ( phydev , MDIO_MMD_PCS , MDIO_SPEED ) ;
if ( val < 0 )
return val ;
return ! ! ( val & MDIO_PCS_SPEED_5G ) = = has_5g ;
}
static int mv2110_match_phy_device ( struct phy_device * phydev )
{
return mv211x_match_phy_device ( phydev , true ) ;
}
static int mv2111_match_phy_device ( struct phy_device * phydev )
{
return mv211x_match_phy_device ( phydev , false ) ;
}
2017-06-05 12:23:16 +01:00
static struct phy_driver mv3310_drivers [ ] = {
{
2019-02-23 00:37:41 +01:00
. phy_id = MARVELL_PHY_ID_88X3310 ,
2021-07-11 18:38:15 +02:00
. phy_id_mask = MARVELL_PHY_ID_MASK ,
. match_phy_device = mv3310_match_phy_device ,
2017-06-05 12:23:16 +01:00
. name = " mv88x3310 " ,
2021-04-07 22:22:45 +02:00
. driver_data = & mv3310_type ,
2019-02-23 00:37:38 +01:00
. get_features = mv3310_get_features ,
2017-06-05 12:23:16 +01:00
. config_init = mv3310_config_init ,
2018-04-03 10:31:45 +01:00
. probe = mv3310_probe ,
. suspend = mv3310_suspend ,
. resume = mv3310_resume ,
2017-06-05 12:23:16 +01:00
. config_aneg = mv3310_config_aneg ,
. aneg_done = mv3310_aneg_done ,
. read_status = mv3310_read_status ,
2020-03-03 18:08:40 +00:00
. get_tunable = mv3310_get_tunable ,
. set_tunable = mv3310_set_tunable ,
2020-08-10 17:01:58 +02:00
. remove = mv3310_remove ,
2021-03-24 00:46:41 +08:00
. set_loopback = genphy_c45_loopback ,
2017-06-05 12:23:16 +01:00
} ,
2021-04-07 22:22:49 +02:00
{
2021-07-11 18:38:15 +02:00
. phy_id = MARVELL_PHY_ID_88X3310 ,
. phy_id_mask = MARVELL_PHY_ID_MASK ,
. match_phy_device = mv3340_match_phy_device ,
2021-04-07 22:22:49 +02:00
. name = " mv88x3340 " ,
. driver_data = & mv3340_type ,
. get_features = mv3310_get_features ,
. config_init = mv3310_config_init ,
. probe = mv3310_probe ,
. suspend = mv3310_suspend ,
. resume = mv3310_resume ,
. config_aneg = mv3310_config_aneg ,
. aneg_done = mv3310_aneg_done ,
. read_status = mv3310_read_status ,
. get_tunable = mv3310_get_tunable ,
. set_tunable = mv3310_set_tunable ,
. remove = mv3310_remove ,
. set_loopback = genphy_c45_loopback ,
} ,
2019-02-23 00:37:44 +01:00
{
. phy_id = MARVELL_PHY_ID_88E2110 ,
. phy_id_mask = MARVELL_PHY_ID_MASK ,
2021-04-07 22:22:52 +02:00
. match_phy_device = mv2110_match_phy_device ,
2021-04-07 22:22:50 +02:00
. name = " mv88e2110 " ,
2021-04-07 22:22:45 +02:00
. driver_data = & mv2110_type ,
2019-02-23 00:37:44 +01:00
. probe = mv3310_probe ,
2019-04-02 15:10:29 +02:00
. suspend = mv3310_suspend ,
. resume = mv3310_resume ,
2019-02-23 00:37:44 +01:00
. config_init = mv3310_config_init ,
. config_aneg = mv3310_config_aneg ,
. aneg_done = mv3310_aneg_done ,
. read_status = mv3310_read_status ,
2020-03-03 18:08:40 +00:00
. get_tunable = mv3310_get_tunable ,
. set_tunable = mv3310_set_tunable ,
2020-08-10 17:01:58 +02:00
. remove = mv3310_remove ,
2021-03-24 00:46:41 +08:00
. set_loopback = genphy_c45_loopback ,
2019-02-23 00:37:44 +01:00
} ,
2021-04-07 22:22:52 +02:00
{
. phy_id = MARVELL_PHY_ID_88E2110 ,
. phy_id_mask = MARVELL_PHY_ID_MASK ,
. match_phy_device = mv2111_match_phy_device ,
. name = " mv88e2111 " ,
. driver_data = & mv2111_type ,
. probe = mv3310_probe ,
. suspend = mv3310_suspend ,
. resume = mv3310_resume ,
. config_init = mv3310_config_init ,
. config_aneg = mv3310_config_aneg ,
. aneg_done = mv3310_aneg_done ,
. read_status = mv3310_read_status ,
. get_tunable = mv3310_get_tunable ,
. set_tunable = mv3310_set_tunable ,
. remove = mv3310_remove ,
. set_loopback = genphy_c45_loopback ,
} ,
2017-06-05 12:23:16 +01:00
} ;
module_phy_driver ( mv3310_drivers ) ;
static struct mdio_device_id __maybe_unused mv3310_tbl [ ] = {
2021-07-11 18:38:15 +02:00
{ MARVELL_PHY_ID_88X3310 , MARVELL_PHY_ID_MASK } ,
2019-02-23 00:37:44 +01:00
{ MARVELL_PHY_ID_88E2110 , MARVELL_PHY_ID_MASK } ,
2017-06-05 12:23:16 +01:00
{ } ,
} ;
MODULE_DEVICE_TABLE ( mdio , mv3310_tbl ) ;
2021-04-07 22:22:53 +02:00
MODULE_DESCRIPTION ( " Marvell Alaska X/M multi-gigabit Ethernet PHY driver " ) ;
2017-06-05 12:23:16 +01:00
MODULE_LICENSE ( " GPL " ) ;