@@ -41,6 +41,10 @@ enum {
4141 MV_PCS_1000BASEX = 0x2000 ,
4242
4343 MV_PCS_CSCR1 = 0x8000 ,
44+ MV_PCS_CSCR1_ED_MASK = 0x0300 ,
45+ MV_PCS_CSCR1_ED_OFF = 0x0000 ,
46+ MV_PCS_CSCR1_ED_RX = 0x0200 ,
47+ MV_PCS_CSCR1_ED_NLP = 0x0300 ,
4448 MV_PCS_CSCR1_MDIX_MASK = 0x0060 ,
4549 MV_PCS_CSCR1_MDIX_MDI = 0x0000 ,
4650 MV_PCS_CSCR1_MDIX_MDIX = 0x0020 ,
@@ -243,6 +247,59 @@ static int mv3310_reset(struct phy_device *phydev, u32 unit)
243247 return val & MDIO_CTRL1_RESET ? - ETIMEDOUT : 0 ;
244248}
245249
250+ static int mv3310_get_edpd (struct phy_device * phydev , u16 * edpd )
251+ {
252+ int val ;
253+
254+ val = phy_read_mmd (phydev , MDIO_MMD_PCS , MV_PCS_CSCR1 );
255+ if (val < 0 )
256+ return val ;
257+
258+ switch (val & MV_PCS_CSCR1_ED_MASK ) {
259+ case MV_PCS_CSCR1_ED_NLP :
260+ * edpd = 1000 ;
261+ break ;
262+ case MV_PCS_CSCR1_ED_RX :
263+ * edpd = ETHTOOL_PHY_EDPD_NO_TX ;
264+ break ;
265+ default :
266+ * edpd = ETHTOOL_PHY_EDPD_DISABLE ;
267+ break ;
268+ }
269+ return 0 ;
270+ }
271+
272+ static int mv3310_set_edpd (struct phy_device * phydev , u16 edpd )
273+ {
274+ u16 val ;
275+ int err ;
276+
277+ switch (edpd ) {
278+ case 1000 :
279+ case ETHTOOL_PHY_EDPD_DFLT_TX_MSECS :
280+ val = MV_PCS_CSCR1_ED_NLP ;
281+ break ;
282+
283+ case ETHTOOL_PHY_EDPD_NO_TX :
284+ val = MV_PCS_CSCR1_ED_RX ;
285+ break ;
286+
287+ case ETHTOOL_PHY_EDPD_DISABLE :
288+ val = MV_PCS_CSCR1_ED_OFF ;
289+ break ;
290+
291+ default :
292+ return - EINVAL ;
293+ }
294+
295+ err = phy_modify_mmd_changed (phydev , MDIO_MMD_PCS , MV_PCS_CSCR1 ,
296+ MV_PCS_CSCR1_ED_MASK , val );
297+ if (err > 0 )
298+ err = mv3310_reset (phydev , MV_PCS_BASE_T );
299+
300+ return err ;
301+ }
302+
246303static int mv3310_sfp_insert (void * upstream , const struct sfp_eeprom_id * id )
247304{
248305 struct phy_device * phydev = upstream ;
@@ -345,7 +402,8 @@ static int mv3310_config_init(struct phy_device *phydev)
345402
346403 phydev -> mdix_ctrl = ETH_TP_MDI_AUTO ;
347404
348- return 0 ;
405+ /* Enable EDPD mode - saving 600mW */
406+ return mv3310_set_edpd (phydev , ETHTOOL_PHY_EDPD_DFLT_TX_MSECS );
349407}
350408
351409static int mv3310_get_features (struct phy_device * phydev )
@@ -594,6 +652,28 @@ static int mv3310_read_status(struct phy_device *phydev)
594652 return 0 ;
595653}
596654
655+ static int mv3310_get_tunable (struct phy_device * phydev ,
656+ struct ethtool_tunable * tuna , void * data )
657+ {
658+ switch (tuna -> id ) {
659+ case ETHTOOL_PHY_EDPD :
660+ return mv3310_get_edpd (phydev , data );
661+ default :
662+ return - EOPNOTSUPP ;
663+ }
664+ }
665+
666+ static int mv3310_set_tunable (struct phy_device * phydev ,
667+ struct ethtool_tunable * tuna , const void * data )
668+ {
669+ switch (tuna -> id ) {
670+ case ETHTOOL_PHY_EDPD :
671+ return mv3310_set_edpd (phydev , * (u16 * )data );
672+ default :
673+ return - EOPNOTSUPP ;
674+ }
675+ }
676+
597677static struct phy_driver mv3310_drivers [] = {
598678 {
599679 .phy_id = MARVELL_PHY_ID_88X3310 ,
@@ -608,6 +688,8 @@ static struct phy_driver mv3310_drivers[] = {
608688 .config_aneg = mv3310_config_aneg ,
609689 .aneg_done = mv3310_aneg_done ,
610690 .read_status = mv3310_read_status ,
691+ .get_tunable = mv3310_get_tunable ,
692+ .set_tunable = mv3310_set_tunable ,
611693 },
612694 {
613695 .phy_id = MARVELL_PHY_ID_88E2110 ,
@@ -621,6 +703,8 @@ static struct phy_driver mv3310_drivers[] = {
621703 .config_aneg = mv3310_config_aneg ,
622704 .aneg_done = mv3310_aneg_done ,
623705 .read_status = mv3310_read_status ,
706+ .get_tunable = mv3310_get_tunable ,
707+ .set_tunable = mv3310_set_tunable ,
624708 },
625709};
626710
0 commit comments