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@xxxxxxxxxxx> --- drivers/net/phy/dp83640.c | 131 +++++++++++++++++++++++++++++++++- drivers/net/phy/dp83640_reg.h | 21 +++++- 2 files changed, 150 insertions(+), 2 deletions(-) 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 */ -- 2.43.0