2323 * link takes priority and the other port is completely locked out.
2424 */
2525#include <linux/ctype.h>
26+ #include <linux/delay.h>
2627#include <linux/hwmon.h>
2728#include <linux/marvell_phy.h>
2829#include <linux/phy.h>
@@ -39,6 +40,12 @@ enum {
3940 MV_PCS_BASE_R = 0x1000 ,
4041 MV_PCS_1000BASEX = 0x2000 ,
4142
43+ MV_PCS_CSCR1 = 0x8000 ,
44+ MV_PCS_CSCR1_MDIX_MASK = 0x0060 ,
45+ MV_PCS_CSCR1_MDIX_MDI = 0x0000 ,
46+ MV_PCS_CSCR1_MDIX_MDIX = 0x0020 ,
47+ MV_PCS_CSCR1_MDIX_AUTO = 0x0060 ,
48+
4249 MV_PCS_CSSR1 = 0x8008 ,
4350 MV_PCS_CSSR1_SPD1_MASK = 0xc000 ,
4451 MV_PCS_CSSR1_SPD1_SPD2 = 0xc000 ,
@@ -216,6 +223,26 @@ static int mv3310_hwmon_probe(struct phy_device *phydev)
216223}
217224#endif
218225
226+ static int mv3310_reset (struct phy_device * phydev , u32 unit )
227+ {
228+ int retries , val , err ;
229+
230+ err = phy_modify_mmd (phydev , MDIO_MMD_PCS , unit + MDIO_CTRL1 ,
231+ MDIO_CTRL1_RESET , MDIO_CTRL1_RESET );
232+ if (err < 0 )
233+ return err ;
234+
235+ retries = 20 ;
236+ do {
237+ msleep (5 );
238+ val = phy_read_mmd (phydev , MDIO_MMD_PCS , unit + MDIO_CTRL1 );
239+ if (val < 0 )
240+ return val ;
241+ } while (val & MDIO_CTRL1_RESET && -- retries );
242+
243+ return val & MDIO_CTRL1_RESET ? - ETIMEDOUT : 0 ;
244+ }
245+
219246static int mv3310_sfp_insert (void * upstream , const struct sfp_eeprom_id * id )
220247{
221248 struct phy_device * phydev = upstream ;
@@ -316,6 +343,8 @@ static int mv3310_config_init(struct phy_device *phydev)
316343 phydev -> interface != PHY_INTERFACE_MODE_10GBASER )
317344 return - ENODEV ;
318345
346+ phydev -> mdix_ctrl = ETH_TP_MDI_AUTO ;
347+
319348 return 0 ;
320349}
321350
@@ -345,14 +374,42 @@ static int mv3310_get_features(struct phy_device *phydev)
345374 return 0 ;
346375}
347376
377+ static int mv3310_config_mdix (struct phy_device * phydev )
378+ {
379+ u16 val ;
380+ int err ;
381+
382+ switch (phydev -> mdix_ctrl ) {
383+ case ETH_TP_MDI_AUTO :
384+ val = MV_PCS_CSCR1_MDIX_AUTO ;
385+ break ;
386+ case ETH_TP_MDI_X :
387+ val = MV_PCS_CSCR1_MDIX_MDIX ;
388+ break ;
389+ case ETH_TP_MDI :
390+ val = MV_PCS_CSCR1_MDIX_MDI ;
391+ break ;
392+ default :
393+ return - EINVAL ;
394+ }
395+
396+ err = phy_modify_mmd_changed (phydev , MDIO_MMD_PCS , MV_PCS_CSCR1 ,
397+ MV_PCS_CSCR1_MDIX_MASK , val );
398+ if (err > 0 )
399+ err = mv3310_reset (phydev , MV_PCS_BASE_T );
400+
401+ return err ;
402+ }
403+
348404static int mv3310_config_aneg (struct phy_device * phydev )
349405{
350406 bool changed = false;
351407 u16 reg ;
352408 int ret ;
353409
354- /* We don't support manual MDI control */
355- phydev -> mdix_ctrl = ETH_TP_MDI_AUTO ;
410+ ret = mv3310_config_mdix (phydev );
411+ if (ret < 0 )
412+ return ret ;
356413
357414 if (phydev -> autoneg == AUTONEG_DISABLE )
358415 return genphy_c45_pma_setup_forced (phydev );
0 commit comments