1
1
// SPDX-License-Identifier: GPL-2.0+
2
2
/*
3
- * Motorcomm 8511/8521/8531S PHY driver.
3
+ * Motorcomm 8511/8521/8531/ 8531S PHY driver.
4
4
*
5
5
* Author: Peter Geis <[email protected] >
6
6
* Author: Frank <[email protected] >
14
14
15
15
#define PHY_ID_YT8511 0x0000010a
16
16
#define PHY_ID_YT8521 0x0000011a
17
+ #define PHY_ID_YT8531 0x4f51e91b
17
18
#define PHY_ID_YT8531S 0x4f51e91a
18
19
19
20
/* YT8521/YT8531S Register Overview
@@ -517,6 +518,61 @@ static int ytphy_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol)
517
518
return phy_restore_page (phydev , old_page , ret );
518
519
}
519
520
521
+ static int yt8531_set_wol (struct phy_device * phydev ,
522
+ struct ethtool_wolinfo * wol )
523
+ {
524
+ const u16 mac_addr_reg [] = {
525
+ YTPHY_WOL_MACADDR2_REG ,
526
+ YTPHY_WOL_MACADDR1_REG ,
527
+ YTPHY_WOL_MACADDR0_REG ,
528
+ };
529
+ const u8 * mac_addr ;
530
+ u16 mask , val ;
531
+ int ret ;
532
+ u8 i ;
533
+
534
+ if (wol -> wolopts & WAKE_MAGIC ) {
535
+ mac_addr = phydev -> attached_dev -> dev_addr ;
536
+
537
+ /* Store the device address for the magic packet */
538
+ for (i = 0 ; i < 3 ; i ++ ) {
539
+ ret = ytphy_write_ext_with_lock (phydev , mac_addr_reg [i ],
540
+ ((mac_addr [i * 2 ] << 8 )) |
541
+ (mac_addr [i * 2 + 1 ]));
542
+ if (ret < 0 )
543
+ return ret ;
544
+ }
545
+
546
+ /* Enable WOL feature */
547
+ mask = YTPHY_WCR_PULSE_WIDTH_MASK | YTPHY_WCR_INTR_SEL ;
548
+ val = YTPHY_WCR_ENABLE | YTPHY_WCR_INTR_SEL ;
549
+ val |= YTPHY_WCR_TYPE_PULSE | YTPHY_WCR_PULSE_WIDTH_672MS ;
550
+ ret = ytphy_modify_ext_with_lock (phydev , YTPHY_WOL_CONFIG_REG ,
551
+ mask , val );
552
+ if (ret < 0 )
553
+ return ret ;
554
+
555
+ /* Enable WOL interrupt */
556
+ ret = phy_modify (phydev , YTPHY_INTERRUPT_ENABLE_REG , 0 ,
557
+ YTPHY_IER_WOL );
558
+ if (ret < 0 )
559
+ return ret ;
560
+ } else {
561
+ /* Disable WOL feature */
562
+ mask = YTPHY_WCR_ENABLE | YTPHY_WCR_INTR_SEL ;
563
+ ret = ytphy_modify_ext_with_lock (phydev , YTPHY_WOL_CONFIG_REG ,
564
+ mask , 0 );
565
+
566
+ /* Disable WOL interrupt */
567
+ ret = phy_modify (phydev , YTPHY_INTERRUPT_ENABLE_REG ,
568
+ YTPHY_IER_WOL , 0 );
569
+ if (ret < 0 )
570
+ return ret ;
571
+ }
572
+
573
+ return 0 ;
574
+ }
575
+
520
576
static int yt8511_read_page (struct phy_device * phydev )
521
577
{
522
578
return __phy_read (phydev , YT8511_PAGE_SELECT );
@@ -767,6 +823,17 @@ static int ytphy_rgmii_clk_delay_config(struct phy_device *phydev)
767
823
return ytphy_modify_ext (phydev , YT8521_RGMII_CONFIG1_REG , mask , val );
768
824
}
769
825
826
+ static int ytphy_rgmii_clk_delay_config_with_lock (struct phy_device * phydev )
827
+ {
828
+ int ret ;
829
+
830
+ phy_lock_mdio_bus (phydev );
831
+ ret = ytphy_rgmii_clk_delay_config (phydev );
832
+ phy_unlock_mdio_bus (phydev );
833
+
834
+ return ret ;
835
+ }
836
+
770
837
/**
771
838
* yt8521_probe() - read chip config then set suitable polling_mode
772
839
* @phydev: a pointer to a &struct phy_device
@@ -891,6 +958,43 @@ static int yt8521_probe(struct phy_device *phydev)
891
958
val );
892
959
}
893
960
961
+ static int yt8531_probe (struct phy_device * phydev )
962
+ {
963
+ struct device_node * node = phydev -> mdio .dev .of_node ;
964
+ u16 mask , val ;
965
+ u32 freq ;
966
+
967
+ if (of_property_read_u32 (node , "motorcomm,clk-out-frequency-hz" , & freq ))
968
+ freq = YTPHY_DTS_OUTPUT_CLK_DIS ;
969
+
970
+ switch (freq ) {
971
+ case YTPHY_DTS_OUTPUT_CLK_DIS :
972
+ mask = YT8531_SCR_SYNCE_ENABLE ;
973
+ val = 0 ;
974
+ break ;
975
+ case YTPHY_DTS_OUTPUT_CLK_25M :
976
+ mask = YT8531_SCR_SYNCE_ENABLE | YT8531_SCR_CLK_SRC_MASK |
977
+ YT8531_SCR_CLK_FRE_SEL_125M ;
978
+ val = YT8531_SCR_SYNCE_ENABLE |
979
+ FIELD_PREP (YT8531_SCR_CLK_SRC_MASK ,
980
+ YT8531_SCR_CLK_SRC_REF_25M );
981
+ break ;
982
+ case YTPHY_DTS_OUTPUT_CLK_125M :
983
+ mask = YT8531_SCR_SYNCE_ENABLE | YT8531_SCR_CLK_SRC_MASK |
984
+ YT8531_SCR_CLK_FRE_SEL_125M ;
985
+ val = YT8531_SCR_SYNCE_ENABLE | YT8531_SCR_CLK_FRE_SEL_125M |
986
+ FIELD_PREP (YT8531_SCR_CLK_SRC_MASK ,
987
+ YT8531_SCR_CLK_SRC_PLL_125M );
988
+ break ;
989
+ default :
990
+ phydev_warn (phydev , "Freq err:%u\n" , freq );
991
+ return - EINVAL ;
992
+ }
993
+
994
+ return ytphy_modify_ext_with_lock (phydev , YTPHY_SYNCE_CFG_REG , mask ,
995
+ val );
996
+ }
997
+
894
998
/**
895
999
* ytphy_utp_read_lpa() - read LPA then setup lp_advertising for utp
896
1000
* @phydev: a pointer to a &struct phy_device
@@ -1387,6 +1491,94 @@ static int yt8521_config_init(struct phy_device *phydev)
1387
1491
return phy_restore_page (phydev , old_page , ret );
1388
1492
}
1389
1493
1494
+ static int yt8531_config_init (struct phy_device * phydev )
1495
+ {
1496
+ struct device_node * node = phydev -> mdio .dev .of_node ;
1497
+ int ret ;
1498
+
1499
+ ret = ytphy_rgmii_clk_delay_config_with_lock (phydev );
1500
+ if (ret < 0 )
1501
+ return ret ;
1502
+
1503
+ if (of_property_read_bool (node , "motorcomm,auto-sleep-disabled" )) {
1504
+ /* disable auto sleep */
1505
+ ret = ytphy_modify_ext_with_lock (phydev ,
1506
+ YT8521_EXTREG_SLEEP_CONTROL1_REG ,
1507
+ YT8521_ESC1R_SLEEP_SW , 0 );
1508
+ if (ret < 0 )
1509
+ return ret ;
1510
+ }
1511
+
1512
+ if (of_property_read_bool (node , "motorcomm,keep-pll-enabled" )) {
1513
+ /* enable RXC clock when no wire plug */
1514
+ ret = ytphy_modify_ext_with_lock (phydev ,
1515
+ YT8521_CLOCK_GATING_REG ,
1516
+ YT8521_CGR_RX_CLK_EN , 0 );
1517
+ if (ret < 0 )
1518
+ return ret ;
1519
+ }
1520
+
1521
+ return 0 ;
1522
+ }
1523
+
1524
+ /**
1525
+ * yt8531_link_change_notify() - Adjust the tx clock direction according to
1526
+ * the current speed and dts config.
1527
+ * @phydev: a pointer to a &struct phy_device
1528
+ *
1529
+ * NOTE: This function is only used to adapt to VF2 with JH7110 SoC. Please
1530
+ * keep "motorcomm,tx-clk-adj-enabled" not exist in dts when the soc is not
1531
+ * JH7110.
1532
+ */
1533
+ static void yt8531_link_change_notify (struct phy_device * phydev )
1534
+ {
1535
+ struct device_node * node = phydev -> mdio .dev .of_node ;
1536
+ bool tx_clk_adj_enabled = false;
1537
+ bool tx_clk_1000_inverted ;
1538
+ bool tx_clk_100_inverted ;
1539
+ bool tx_clk_10_inverted ;
1540
+ u16 val = 0 ;
1541
+ int ret ;
1542
+
1543
+ if (of_property_read_bool (node , "motorcomm,tx-clk-adj-enabled" ))
1544
+ tx_clk_adj_enabled = true;
1545
+
1546
+ if (!tx_clk_adj_enabled )
1547
+ return ;
1548
+
1549
+ if (of_property_read_bool (node , "motorcomm,tx-clk-10-inverted" ))
1550
+ tx_clk_10_inverted = true;
1551
+ if (of_property_read_bool (node , "motorcomm,tx-clk-100-inverted" ))
1552
+ tx_clk_100_inverted = true;
1553
+ if (of_property_read_bool (node , "motorcomm,tx-clk-1000-inverted" ))
1554
+ tx_clk_1000_inverted = true;
1555
+
1556
+ if (phydev -> speed < 0 )
1557
+ return ;
1558
+
1559
+ switch (phydev -> speed ) {
1560
+ case SPEED_1000 :
1561
+ if (tx_clk_1000_inverted )
1562
+ val = YT8521_RC1R_TX_CLK_SEL_INVERTED ;
1563
+ break ;
1564
+ case SPEED_100 :
1565
+ if (tx_clk_100_inverted )
1566
+ val = YT8521_RC1R_TX_CLK_SEL_INVERTED ;
1567
+ break ;
1568
+ case SPEED_10 :
1569
+ if (tx_clk_10_inverted )
1570
+ val = YT8521_RC1R_TX_CLK_SEL_INVERTED ;
1571
+ break ;
1572
+ default :
1573
+ return ;
1574
+ }
1575
+
1576
+ ret = ytphy_modify_ext_with_lock (phydev , YT8521_RGMII_CONFIG1_REG ,
1577
+ YT8521_RC1R_TX_CLK_SEL_INVERTED , val );
1578
+ if (ret < 0 )
1579
+ phydev_warn (phydev , "Modify TX_CLK_SEL err:%d\n" , ret );
1580
+ }
1581
+
1390
1582
/**
1391
1583
* yt8521_prepare_fiber_features() - A small helper function that setup
1392
1584
* fiber's features.
@@ -1969,6 +2161,17 @@ static struct phy_driver motorcomm_phy_drvs[] = {
1969
2161
.suspend = yt8521_suspend ,
1970
2162
.resume = yt8521_resume ,
1971
2163
},
2164
+ {
2165
+ PHY_ID_MATCH_EXACT (PHY_ID_YT8531 ),
2166
+ .name = "YT8531 Gigabit Ethernet" ,
2167
+ .probe = yt8531_probe ,
2168
+ .config_init = yt8531_config_init ,
2169
+ .suspend = genphy_suspend ,
2170
+ .resume = genphy_resume ,
2171
+ .get_wol = ytphy_get_wol ,
2172
+ .set_wol = yt8531_set_wol ,
2173
+ .link_change_notify = yt8531_link_change_notify ,
2174
+ },
1972
2175
{
1973
2176
PHY_ID_MATCH_EXACT (PHY_ID_YT8531S ),
1974
2177
.name = "YT8531S Gigabit Ethernet" ,
@@ -1990,14 +2193,15 @@ static struct phy_driver motorcomm_phy_drvs[] = {
1990
2193
1991
2194
module_phy_driver (motorcomm_phy_drvs );
1992
2195
1993
- MODULE_DESCRIPTION ("Motorcomm 8511/8521/8531S PHY driver" );
2196
+ MODULE_DESCRIPTION ("Motorcomm 8511/8521/8531/ 8531S PHY driver" );
1994
2197
MODULE_AUTHOR ("Peter Geis" );
1995
2198
MODULE_AUTHOR ("Frank" );
1996
2199
MODULE_LICENSE ("GPL" );
1997
2200
1998
2201
static const struct mdio_device_id __maybe_unused motorcomm_tbl [] = {
1999
2202
{ PHY_ID_MATCH_EXACT (PHY_ID_YT8511 ) },
2000
2203
{ PHY_ID_MATCH_EXACT (PHY_ID_YT8521 ) },
2204
+ { PHY_ID_MATCH_EXACT (PHY_ID_YT8531 ) },
2001
2205
{ PHY_ID_MATCH_EXACT (PHY_ID_YT8531S ) },
2002
2206
{ /* sentinel */ }
2003
2207
};
0 commit comments