net: phy: mscc: handle the clkout control on some phy

A patch from »add clkout support to mscc phys« in state Mailinglist for linux-kernel

From: Heiko Stuebner <heiko.stuebner@...> Date: Mon, 8 Jun 2020 17:31:09 +0200

Commit-Message

At least VSC8530/8531/8540/8541 contain a clock output that can emit a predefined rate of 25, 50 or 125MHz. This may then feed back into the network interface as source clock. So follow the example the at803x already set and introduce a vsc8531,clk-out-frequency property to set that output. Signed-off-by: Heiko Stuebner <heiko.stuebner@...>

Patch-Comment

drivers/net/phy/mscc/mscc.h | 9 ++++ drivers/net/phy/mscc/mscc_main.c | 87 +++++++++++++++++++++++++++++--- 2 files changed, 89 insertions(+), 7 deletions(-)

Statistics

  • 89 lines added
  • 7 lines removed

Changes

------------------------- drivers/net/phy/mscc/mscc.h --------------------------
index fbcee5fce7b2..a3afc35c3eab 100644
@@ -218,6 +218,13 @@ enum rgmii_clock_delay {
#define INT_MEM_DATA_M 0x00ff
#define INT_MEM_DATA(x) (INT_MEM_DATA_M & (x))
+#define MSCC_CLKOUT_CNTL 13
+#define CLKOUT_ENABLE BIT(15)
+#define CLKOUT_FREQ_MASK GENMASK(14, 13)
+#define CLKOUT_FREQ_25M (0x0 << 13)
+#define CLKOUT_FREQ_50M (0x1 << 13)
+#define CLKOUT_FREQ_125M (0x2 << 13)
+
#define MSCC_PHY_PROC_CMD 18
#define PROC_CMD_NCOMPLETED 0x8000
#define PROC_CMD_FAILED 0x4000
@@ -360,6 +367,8 @@ struct vsc8531_private {
*/
unsigned int base_addr;
+ u32 clkout_rate;
+
#if IS_ENABLED(CONFIG_MACSEC)
/* MACsec fields:
* - One SecY per device (enforced at the s/w implementation level)
----------------------- drivers/net/phy/mscc/mscc_main.c -----------------------
index 5d2777522fb4..2f06cfa2f539 100644
@@ -432,6 +432,18 @@ static int vsc85xx_dt_led_mode_get(struct phy_device *phydev,
return led_mode;
}
+static void vsc8531_dt_clkout_rate_get(struct phy_device *phydev)
+{
+ struct vsc8531_private *priv = phydev->priv;
+ struct device *dev = &phydev->mdio.dev;
+ struct device_node *of_node = dev->of_node;
+
+ if (!of_node)
+ return;
+
+ of_property_read_u32(of_node, "enet-phy-clock-out-frequency",
+ &priv->clkout_rate);
+}
#else
static int vsc85xx_edge_rate_magic_get(struct phy_device *phydev)
{
@@ -444,6 +456,10 @@ static int vsc85xx_dt_led_mode_get(struct phy_device *phydev,
{
return default_mode;
}
+
+static void vsc8531_dt_clkout_rate_get(struct phy_device *phydev)
+{
+}
#endif /* CONFIG_OF_MDIO */
static int vsc85xx_dt_led_modes_get(struct phy_device *phydev,
@@ -1508,6 +1524,37 @@ static int vsc85xx_config_init(struct phy_device *phydev)
return 0;
}
+static int vsc8531_config_init(struct phy_device *phydev)
+{
+ struct vsc8531_private *vsc8531 = phydev->priv;
+ u16 val;
+ int rc;
+
+ rc = vsc85xx_config_init(phydev);
+ if (rc)
+ return rc;
+
+ switch (vsc8531->clkout_rate) {
+ case 0:
+ val = 0;
+ break;
+ case 25000000:
+ val = CLKOUT_FREQ_25M | CLKOUT_ENABLE;
+ break;
+ case 50000000:
+ val = CLKOUT_FREQ_50M | CLKOUT_ENABLE;
+ break;
+ case 125000000:
+ val = CLKOUT_FREQ_125M | CLKOUT_ENABLE;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return phy_write_paged(phydev, MSCC_PHY_PAGE_EXTENDED_GPIO,
+ MSCC_CLKOUT_CNTL, val);
+}
+
static int vsc8584_did_interrupt(struct phy_device *phydev)
{
int rc = 0;
@@ -1981,6 +2028,32 @@ static int vsc8514_probe(struct phy_device *phydev)
vsc8531->base_addr, 0);
}
+static int vsc8531_probe(struct phy_device *phydev)
+{
+ struct vsc8531_private *vsc8531;
+ int rate_magic, rc;
+ u32 default_mode[2] = {VSC8531_LINK_1000_ACTIVITY,
+ VSC8531_LINK_100_ACTIVITY};
+
+ rate_magic = vsc85xx_edge_rate_magic_get(phydev);
+ if (rate_magic < 0)
+ return rate_magic;
+
+ rc = vsc85xx_probe_helper(phydev, default_mode,
+ ARRAY_SIZE(default_mode),
+ VSC85XX_SUPP_LED_MODES,
+ vsc85xx_hw_stats,
+ ARRAY_SIZE(vsc85xx_hw_stats));
+ if (rc < 0)
+ return rc;
+
+ vsc8531 = phydev->priv;
+ vsc8531->rate_magic = rate_magic;
+ vsc8531_dt_clkout_rate_get(phydev);
+
+ return 0;
+}
+
static int vsc8574_probe(struct phy_device *phydev)
{
struct vsc8531_private *vsc8531;
@@ -2136,14 +2209,14 @@ static struct phy_driver vsc85xx_driver[] = {
.phy_id_mask = 0xfffffff0,
/* PHY_BASIC_FEATURES */
.soft_reset = &genphy_soft_reset,
- .config_init = &vsc85xx_config_init,
+ .config_init = &vsc8531_config_init,
.config_aneg = &vsc85xx_config_aneg,
.read_status = &vsc85xx_read_status,
.ack_interrupt = &vsc85xx_ack_interrupt,
.config_intr = &vsc85xx_config_intr,
.suspend = &genphy_suspend,
.resume = &genphy_resume,
- .probe = &vsc85xx_probe,
+ .probe = &vsc8531_probe,
.set_wol = &vsc85xx_wol_set,
.get_wol = &vsc85xx_wol_get,
.get_tunable = &vsc85xx_get_tunable,
@@ -2160,14 +2233,14 @@ static struct phy_driver vsc85xx_driver[] = {
.phy_id_mask = 0xfffffff0,
/* PHY_GBIT_FEATURES */
.soft_reset = &genphy_soft_reset,
- .config_init = &vsc85xx_config_init,
+ .config_init = &vsc8531_config_init,
.config_aneg = &vsc85xx_config_aneg,
.read_status = &vsc85xx_read_status,
.ack_interrupt = &vsc85xx_ack_interrupt,
.config_intr = &vsc85xx_config_intr,
.suspend = &genphy_suspend,
.resume = &genphy_resume,
- .probe = &vsc85xx_probe,
+ .probe = &vsc8531_probe,
.set_wol = &vsc85xx_wol_set,
.get_wol = &vsc85xx_wol_get,
.get_tunable = &vsc85xx_get_tunable,
@@ -2184,14 +2257,14 @@ static struct phy_driver vsc85xx_driver[] = {
.phy_id_mask = 0xfffffff0,
/* PHY_BASIC_FEATURES */
.soft_reset = &genphy_soft_reset,
- .config_init = &vsc85xx_config_init,
+ .config_init = &vsc8531_config_init,
.config_aneg = &vsc85xx_config_aneg,
.read_status = &vsc85xx_read_status,
.ack_interrupt = &vsc85xx_ack_interrupt,
.config_intr = &vsc85xx_config_intr,
.suspend = &genphy_suspend,
.resume = &genphy_resume,
- .probe = &vsc85xx_probe,
+ .probe = &vsc8531_probe,
.set_wol = &vsc85xx_wol_set,
.get_wol = &vsc85xx_wol_get,
.get_tunable = &vsc85xx_get_tunable,
@@ -2208,7 +2281,7 @@ static struct phy_driver vsc85xx_driver[] = {
.phy_id_mask = 0xfffffff0,
/* PHY_GBIT_FEATURES */
.soft_reset = &genphy_soft_reset,
- .config_init = &vsc85xx_config_init,
+ .config_init = &vsc8531_config_init,
.config_aneg = &vsc85xx_config_aneg,
.read_status = &vsc85xx_read_status,
.ack_interrupt = &vsc85xx_ack_interrupt,
 
 

Recent Patches

About Us

Sed lacus. Donec lectus. Nullam pretium nibh ut turpis. Nam bibendum. In nulla tortor, elementum vel, tempor at, varius non, purus. Mauris vitae nisl nec metus placerat consectetuer.

Read More...