diff mbox series

[2/2] net: phy: Add some configuration from device-tree

Message ID 20240130085935.33722-3-bastien.curutchet@bootlin.com
State New
Headers show
Series Add device tree binding support to TI's DP83640 | expand

Commit Message

Bastien Curutchet Jan. 30, 2024, 8:59 a.m. UTC
Some features can now be enabled or disabled from device tree.
If attributes are present in device-tree, features are enabled
or disabled via MDIO registers. Else, hardware configuration is
left as is.
These features are : Energy Detect Mode, PHY Control Frames,
LED configuration and Fiber Mode.

Signed-off-by: Bastien Curutchet <bastien.curutchet@bootlin.com>
---
 drivers/net/phy/dp83640.c     | 131 +++++++++++++++++++++++++++++++++-
 drivers/net/phy/dp83640_reg.h |  21 +++++-
 2 files changed, 150 insertions(+), 2 deletions(-)
diff mbox series

Patch

diff --git a/drivers/net/phy/dp83640.c b/drivers/net/phy/dp83640.c
index 5c42c47dc564..f5770002b849 100644
--- a/drivers/net/phy/dp83640.c
+++ b/drivers/net/phy/dp83640.c
@@ -7,6 +7,7 @@ 
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
+#include <dt-bindings/net/ti-dp83640.h>
 #include <linux/crc32.h>
 #include <linux/ethtool.h>
 #include <linux/kernel.h>
@@ -16,6 +17,7 @@ 
 #include <linux/net_tstamp.h>
 #include <linux/netdevice.h>
 #include <linux/if_vlan.h>
+#include <linux/of.h>
 #include <linux/phy.h>
 #include <linux/ptp_classify.h>
 #include <linux/ptp_clock_kernel.h>
@@ -1418,15 +1420,142 @@  static int dp83640_ts_info(struct mii_timestamper *mii_ts,
 	return 0;
 }
 
+#ifdef CONFIG_OF_MDIO
+static int dp83640_of_init(struct phy_device *phydev)
+{
+	struct device *dev = &phydev->mdio.dev;
+	struct device_node *of_node = dev->of_node;
+	int reg_val;
+	u32 of_val;
+	int ret;
+
+	if (!of_node)
+		return 0;
+
+	/* All configured features reside in PAGE 0 */
+	phy_write(phydev, PAGESEL, 0);
+
+	/* Energy detect mode */
+	reg_val = phy_read(phydev, EDCR);
+	if (of_property_present(of_node, "ti,energy-detect-en"))
+		reg_val |= ED_EN;
+	else
+		reg_val &= ~ED_EN;
+	phy_write(phydev, EDCR, reg_val);
+
+	/* CLK_OUTPUT Pin */
+	if (of_property_present(of_node, "ti,clk-output")) {
+		ret = of_property_read_u32(of_node, "ti,clk-output", &of_val);
+		if (ret)
+			return ret;
+
+		reg_val = phy_read(phydev, PHYCR2);
+		switch (of_val) {
+		case 0:
+			reg_val |= CLK_OUT_DIS;
+			break;
+		case 1:
+			reg_val &= ~CLK_OUT_DIS;
+			break;
+		default:
+			phydev_err(phydev, "Invalid value for ti,clk-output property (%d)"
+					, of_val);
+			return -EINVAL;
+		}
+		phy_write(phydev, PHYCR2, reg_val);
+	}
+
+	/* LED configuration */
+	if (of_property_present(of_node, "ti,led-config"))  {
+		ret = of_property_read_u32(of_node, "ti,led-config", &of_val);
+		if (ret)
+			return ret;
+
+		reg_val = phy_read(phydev, PHYCR) & ~(LED_CNFG_1 | LED_CNFG_0);
+		switch (of_val) {
+		case DP83640_PHYCR_LED_CNFG_MODE_1:
+			reg_val |= LED_CNFG_0;
+			break;
+		case DP83640_PHYCR_LED_CNFG_MODE_2:
+			/* Keeping LED_CNFG_1 and LED_CNFG_0 unset */
+			break;
+		case DP83640_PHYCR_LED_CNFG_MODE_3:
+			reg_val |= LED_CNFG_1;
+			break;
+		default:
+			phydev_err(phydev, "Invalid value for ti,led-config property (%d)"
+					, of_val);
+			return -EINVAL;
+		}
+		phy_write(phydev, PHYCR, reg_val);
+	}
+	if (of_property_present(of_node, "ti,phy-control-frames")) {
+		of_property_read_u32(of_node, "ti,phy-control-frames", &of_val);
+		if (ret)
+			return ret;
+
+		reg_val = phy_read(phydev, PCFCR);
+		switch (of_val) {
+		case 0:
+			reg_val &= ~PCF_EN;
+			break;
+		case 1:
+			reg_val |= PCF_EN;
+			break;
+		default:
+			phydev_err(phydev, "Invalid value for ti,phy-control-frames property (%d)"
+					, of_val);
+			return -EINVAL;
+		}
+		phy_write(phydev, PCFCR, reg_val);
+	}
+	if (of_property_present(of_node, "ti,fiber-mode")) {
+		ret = of_property_read_u32(of_node, "ti,fiber-mode", &of_val);
+		if (ret)
+			return ret;
+
+		reg_val = phy_read(phydev, PCSR);
+		switch (of_val) {
+		case 0:
+			reg_val &= ~FX_EN;
+			break;
+		case 1:
+			reg_val |= FX_EN;
+			break;
+		default:
+			phydev_err(phydev, "Invalid value for ti,fiber-mode property (%d)"
+					, of_val);
+			return -EINVAL;
+		}
+		phy_write(phydev, PCSR, reg_val);
+		/* Write SOFT_RESET bit to ensure configuration */
+		reg_val = phy_read(phydev, PHYCR2) | SOFT_RESET;
+		phy_write(phydev, PHYCR2, reg_val);
+	}
+
+	return 0;
+}
+#else
+static int dp83640_of_init(struct phy_device *phydev)
+{
+	return 0;
+}
+#endif /* CONFIG_OF_MDIO */
+
 static int dp83640_probe(struct phy_device *phydev)
 {
 	struct dp83640_clock *clock;
 	struct dp83640_private *dp83640;
-	int err = -ENOMEM, i;
+	int err, i;
 
 	if (phydev->mdio.addr == BROADCAST_ADDR)
 		return 0;
 
+	err = dp83640_of_init(phydev);
+	if (err < 0)
+		return err;
+
+	err = -ENOMEM;
 	clock = dp83640_clock_get_bus(phydev->mdio.bus);
 	if (!clock)
 		goto no_clock;
diff --git a/drivers/net/phy/dp83640_reg.h b/drivers/net/phy/dp83640_reg.h
index daae7fa58fb8..8877ba560406 100644
--- a/drivers/net/phy/dp83640_reg.h
+++ b/drivers/net/phy/dp83640_reg.h
@@ -6,7 +6,11 @@ 
 #define HAVE_DP83640_REGISTERS
 
 /* #define PAGE0                  0x0000 */
+#define PCSR                      0x0016 /* PCS Configuration and Status Register */
+#define PHYCR                     0x0019 /* PHY Control Register */
 #define PHYCR2                    0x001c /* PHY Control Register 2 */
+#define EDCR                      0x001D /* Energy Detect Control Register */
+#define PCFCR                     0x001F /* PHY Control Frames Control Register */
 
 #define PAGE4                     0x0004
 #define PTP_CTL                   0x0014 /* PTP Control Register */
@@ -50,8 +54,23 @@ 
 #define PTP_GPIOMON               0x001e /* PTP GPIO Monitor Register */
 #define PTP_RXHASH                0x001f /* PTP Receive Hash Register */
 
+/* Bit definitions for the PCSR register */
+#define FX_EN		          BIT(6)  /* Enable FX Fiber Mode */
+
+/* Bit definitions for the PHYCR register */
+#define LED_CNFG_0	          BIT(5)  /* LED configuration, bit 0 */
+#define LED_CNFG_1	          BIT(6)  /* LED configuration, bit 1 */
+
 /* Bit definitions for the PHYCR2 register */
-#define BC_WRITE                  (1<<11) /* Broadcast Write Enable */
+#define CLK_OUT_DIS	          BIT(1)  /* Disable CLK_OUT pin */
+#define SOFT_RESET		  BIT(9)  /* Soft Reset */
+#define BC_WRITE                  BIT(11) /* Broadcast Write Enable */
+
+/* Bit definitions for the EDCR register */
+#define ED_EN		          BIT(15) /* Enable Energy Detect Mode */
+
+/* Bit definitions for the PCFCR register */
+#define PCF_EN	                  BIT(0)  /* Enable PHY Control Frames */
 
 /* Bit definitions for the PTP_CTL register */
 #define TRIG_SEL_SHIFT            (10)    /* PTP Trigger Select */