From patchwork Thu Jan 5 07:30:22 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Frank Sae X-Patchwork-Id: 13089486 X-Patchwork-Delegate: kuba@kernel.org Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id E9A6DC5479D for ; Thu, 5 Jan 2023 07:30:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230418AbjAEHaL (ORCPT ); Thu, 5 Jan 2023 02:30:11 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37996 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230379AbjAEHaI (ORCPT ); Thu, 5 Jan 2023 02:30:08 -0500 Received: from out29-201.mail.aliyun.com (out29-201.mail.aliyun.com [115.124.29.201]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C8A8453737; Wed, 4 Jan 2023 23:30:06 -0800 (PST) X-Alimail-AntiSpam: AC=CONTINUE;BC=0.08715363|-1;CH=green;DM=|CONTINUE|false|;DS=CONTINUE|ham_system_inform|0.219216-0.0011304-0.779654;FP=0|0|0|0|0|-1|-1|-1;HT=ay29a033018047212;MF=frank.sae@motor-comm.com;NM=1;PH=DS;RN=17;RT=17;SR=0;TI=SMTPD_---.QktmAsD_1672903802; Received: from sun-VirtualBox..(mailfrom:Frank.Sae@motor-comm.com fp:SMTPD_---.QktmAsD_1672903802) by smtp.aliyun-inc.com; Thu, 05 Jan 2023 15:30:03 +0800 From: Frank To: Peter Geis , Andrew Lunn , Heiner Kallweit , Russell King , "David S . Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Rob Herring , Krzysztof Kozlowski Cc: xiaogang.fan@motor-comm.com, fei.zhang@motor-comm.com, hua.sun@motor-comm.com, netdev@vger.kernel.org, linux-kernel@vger.kernel.org, Frank , devicetree@vger.kernel.org Subject: [PATCH net-next v1 1/3] dt-bindings: net: Add Motorcomm yt8xxx ethernet phy Driver bindings Date: Thu, 5 Jan 2023 15:30:22 +0800 Message-Id: <20230105073024.8390-2-Frank.Sae@motor-comm.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230105073024.8390-1-Frank.Sae@motor-comm.com> References: <20230105073024.8390-1-Frank.Sae@motor-comm.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: kuba@kernel.org Add a YAML binding document for the Motorcom yt8xxx Ethernet phy driver. Signed-off-by: Frank --- .../bindings/net/motorcomm,yt8xxx.yaml | 180 ++++++++++++++++++ .../devicetree/bindings/vendor-prefixes.yaml | 2 + MAINTAINERS | 1 + 3 files changed, 183 insertions(+) create mode 100644 Documentation/devicetree/bindings/net/motorcomm,yt8xxx.yaml diff --git a/Documentation/devicetree/bindings/net/motorcomm,yt8xxx.yaml b/Documentation/devicetree/bindings/net/motorcomm,yt8xxx.yaml new file mode 100644 index 000000000000..337a562d864c --- /dev/null +++ b/Documentation/devicetree/bindings/net/motorcomm,yt8xxx.yaml @@ -0,0 +1,180 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/motorcomm,yt8xxx.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MotorComm yt8xxx Ethernet PHY + +maintainers: + - frank + +description: | + Bindings for MotorComm yt8xxx PHYs. + yt8511 will be supported later. + +allOf: + - $ref: ethernet-phy.yaml# + +properties: + motorcomm,clk-out-frequency: + description: clock output in Hertz on clock output pin. + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [0, 25000000, 125000000] + default: 0 + + motorcomm,rx-delay-basic: + description: | + Tristate, setup the basic RGMII RX Clock delay of PHY. + This basic delay is fixed at 2ns (1000Mbps) or 8ns (100Mbps、10Mbps). + This basic delay usually auto set by hardware according to the voltage + of RXD0 pin (low = 0, turn off; high = 1, turn on). + If not exist, this delay is controlled by hardware. + 0: turn off; 1: turn on. + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [0, 1] + + motorcomm,rx-delay-additional-ps: + description: | + Setup the additional RGMII RX Clock delay of PHY defined in pico seconds. + RGMII RX Clock Delay = rx-delay-basic + rx-delay-additional-ps. + enum: + - 0 + - 150 + - 300 + - 450 + - 600 + - 750 + - 900 + - 1050 + - 1200 + - 1350 + - 1500 + - 1650 + - 1800 + - 1950 + - 2100 + - 2250 + + motorcomm,tx-delay-ge-ps: + description: | + Setup PHY's RGMII TX Clock delay defined in pico seconds when the speed + is 1000Mbps. + enum: + - 0 + - 150 + - 300 + - 450 + - 600 + - 750 + - 900 + - 1050 + - 1200 + - 1350 + - 1500 + - 1650 + - 1800 + - 1950 + - 2100 + - 2250 + + motorcomm,tx-delay-fe-ps: + description: | + Setup PHY's RGMII TX Clock delay defined in pico seconds when the speed + is 100Mbps or 10Mbps. + enum: + - 0 + - 150 + - 300 + - 450 + - 600 + - 750 + - 900 + - 1050 + - 1200 + - 1350 + - 1500 + - 1650 + - 1800 + - 1950 + - 2100 + - 2250 + + motorcomm,keep-pll-enabled: + description: | + If set, keep the PLL enabled even if there is no link. Useful if you + want to use the clock output without an ethernet link. + type: boolean + + motorcomm,auto-sleep-disabled: + description: | + If set, PHY will not enter sleep mode and close AFE after unplug cable + for a timer. + type: boolean + + motorcomm,tx-clk-adj-enabled: + description: | + Useful if you want to use tx-clk-xxxx-inverted to adj the delay of tx clk. + type: boolean + + motorcomm,tx-clk-10-inverted: + description: | + Use original or inverted RGMII Transmit PHY Clock to drive the RGMII + Transmit PHY Clock delay train configuration when speed is 10Mbps. + type: boolean + + motorcomm,tx-clk-100-inverted: + description: | + Use original or inverted RGMII Transmit PHY Clock to drive the RGMII + Transmit PHY Clock delay train configuration when speed is 100Mbps. + type: boolean + + motorcomm,tx-clk-1000-inverted: + description: | + Use original or inverted RGMII Transmit PHY Clock to drive the RGMII + Transmit PHY Clock delay train configuration when speed is 1000Mbps. + type: boolean + + motorcomm,sds-tx-amplitude: + description: | + Setup the tx driver amplitude control of SerDes. Higher amplitude is + helpful for long distance. + 0: low; 1: middle; 2: high. + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [0, 1, 2] + +unevaluatedProperties: false + +examples: + - | + ethernet { + #address-cells = <1>; + #size-cells = <0>; + ethernet-phy@5 { + reg = <5>; + + motorcomm,clk-out-frequency = <0>; + #motorcomm,rx-delay-basic = <1>; + motorcomm,rx-delay-additional-ps = <0>; + motorcomm,tx-delay-fe-ps = <2250>; + motorcomm,tx-delay-ge-ps = <150>; + + motorcomm,keep-pll-enabled; + motorcomm,auto-sleep-disabled; + motorcomm,sds-tx-amplitude = <1>; + }; + }; + - | + ethernet { + #address-cells = <1>; + #size-cells = <0>; + phy-mode = "rgmii-id"; + ethernet-phy@5 { + reg = <5>; + + motorcomm,clk-out-frequency = <125000000>; + + motorcomm,keep-pll-enabled; + motorcomm,auto-sleep-disabled; + }; + }; diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml index 70ffb3780621..8d19157e85b7 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml @@ -845,6 +845,8 @@ patternProperties: description: Moortec Semiconductor Ltd. "^mosaixtech,.*": description: Mosaix Technologies, Inc. + "^motorcomm,.*": + description: MotorComm, Inc. "^motorola,.*": description: Motorola, Inc. "^moxa,.*": diff --git a/MAINTAINERS b/MAINTAINERS index 7f0b7181e60a..a1e714980154 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14161,6 +14161,7 @@ M: Peter Geis M: Frank L: netdev@vger.kernel.org S: Maintained +F: Documentation/devicetree/bindings/net/motorcomm,yt8xxx.yaml F: drivers/net/phy/motorcomm.c MOXA SMARTIO/INDUSTIO/INTELLIO SERIAL CARD From patchwork Thu Jan 5 07:30:23 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Frank Sae X-Patchwork-Id: 13089487 X-Patchwork-Delegate: kuba@kernel.org Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2DC5DC54EBC for ; Thu, 5 Jan 2023 07:30:44 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231256AbjAEHaS (ORCPT ); Thu, 5 Jan 2023 02:30:18 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38002 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231244AbjAEHaK (ORCPT ); Thu, 5 Jan 2023 02:30:10 -0500 Received: from out29-174.mail.aliyun.com (out29-174.mail.aliyun.com [115.124.29.174]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DC12053738; Wed, 4 Jan 2023 23:30:07 -0800 (PST) X-Alimail-AntiSpam: AC=CONTINUE;BC=0.07436261|-1;CH=green;DM=|CONTINUE|false|;DS=CONTINUE|ham_system_inform|0.00718991-0.0975541-0.895256;FP=0|0|0|0|0|-1|-1|-1;HT=ay29a033018047199;MF=frank.sae@motor-comm.com;NM=1;PH=DS;RN=17;RT=17;SR=0;TI=SMTPD_---.QktmAuq_1672903803; Received: from sun-VirtualBox..(mailfrom:Frank.Sae@motor-comm.com fp:SMTPD_---.QktmAuq_1672903803) by smtp.aliyun-inc.com; Thu, 05 Jan 2023 15:30:05 +0800 From: Frank To: Peter Geis , Andrew Lunn , Heiner Kallweit , Russell King , "David S . Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Rob Herring , Krzysztof Kozlowski Cc: xiaogang.fan@motor-comm.com, fei.zhang@motor-comm.com, hua.sun@motor-comm.com, netdev@vger.kernel.org, linux-kernel@vger.kernel.org, Frank , devicetree@vger.kernel.org Subject: [PATCH net-next v1 2/3] net: phy: Add dts support for Motorcomm yt8521/yt8531s gigabit ethernet phy Date: Thu, 5 Jan 2023 15:30:23 +0800 Message-Id: <20230105073024.8390-3-Frank.Sae@motor-comm.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230105073024.8390-1-Frank.Sae@motor-comm.com> References: <20230105073024.8390-1-Frank.Sae@motor-comm.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: kuba@kernel.org Add dts support for yt8521 and yt8531s. This patch has been tested on AM335x platform which has one YT8531S interface card and passed all test cases. Signed-off-by: Frank --- drivers/net/phy/motorcomm.c | 517 ++++++++++++++++++++++++++++++------ 1 file changed, 434 insertions(+), 83 deletions(-) diff --git a/drivers/net/phy/motorcomm.c b/drivers/net/phy/motorcomm.c index 685190db72de..7ebcca374a67 100644 --- a/drivers/net/phy/motorcomm.c +++ b/drivers/net/phy/motorcomm.c @@ -10,10 +10,11 @@ #include #include #include +#include #define PHY_ID_YT8511 0x0000010a -#define PHY_ID_YT8521 0x0000011A -#define PHY_ID_YT8531S 0x4F51E91A +#define PHY_ID_YT8521 0x0000011a +#define PHY_ID_YT8531S 0x4f51e91a /* YT8521/YT8531S Register Overview * UTP Register space | FIBER Register space @@ -144,6 +145,16 @@ #define YT8521_ESC1R_SLEEP_SW BIT(15) #define YT8521_ESC1R_PLLON_SLP BIT(14) +/* Phy Serdes analog cfg2 Register */ +#define YTPHY_SERDES_ANALOG_CFG2_REG 0xA1 +#define YTPHY_SAC2R_TX_AMPLITUDE_MASK ((0x7 << 13) | (0x7 << 1)) +#define YT8521_SAC2R_TX_AMPLITUDE_LOW ((0x7 << 13) | (0x0 << 1)) +#define YT8521_SAC2R_TX_AMPLITUDE_MIDDLE ((0x5 << 13) | (0x5 << 1)) +#define YT8521_SAC2R_TX_AMPLITUDE_HIGH ((0x3 << 13) | (0x6 << 1)) +#define YT8531S_SAC2R_TX_AMPLITUDE_LOW ((0x0 << 13) | (0x0 << 1)) +#define YT8531S_SAC2R_TX_AMPLITUDE_MIDDLE ((0x0 << 13) | (0x1 << 1)) +#define YT8531S_SAC2R_TX_AMPLITUDE_HIGH ((0x0 << 13) | (0x2 << 1)) + /* Phy fiber Link timer cfg2 Register */ #define YT8521_LINK_TIMER_CFG2_REG 0xA5 #define YT8521_LTCR_EN_AUTOSEN BIT(15) @@ -161,6 +172,7 @@ #define YT8521_CHIP_CONFIG_REG 0xA001 #define YT8521_CCR_SW_RST BIT(15) +#define YT8521_CCR_RXC_DLY_EN BIT(8) #define YT8521_CCR_MODE_SEL_MASK (BIT(2) | BIT(1) | BIT(0)) #define YT8521_CCR_MODE_UTP_TO_RGMII 0 @@ -178,22 +190,27 @@ #define YT8521_MODE_POLL 0x3 #define YT8521_RGMII_CONFIG1_REG 0xA003 - +#define YT8521_RC1R_TX_CLK_SEL_MASK BIT(14) +#define YT8521_RC1R_TX_CLK_SEL_ORIGINAL (0x0 << 14) +#define YT8521_RC1R_TX_CLK_SEL_INVERTED (0x1 << 14) /* TX Gig-E Delay is bits 3:0, default 0x1 * TX Fast-E Delay is bits 7:4, default 0xf * RX Delay is bits 13:10, default 0x0 * Delay = 150ps * N * On = 2250ps, off = 0ps */ -#define YT8521_RC1R_RX_DELAY_MASK (0xF << 10) -#define YT8521_RC1R_RX_DELAY_EN (0xF << 10) -#define YT8521_RC1R_RX_DELAY_DIS (0x0 << 10) -#define YT8521_RC1R_FE_TX_DELAY_MASK (0xF << 4) -#define YT8521_RC1R_FE_TX_DELAY_EN (0xF << 4) -#define YT8521_RC1R_FE_TX_DELAY_DIS (0x0 << 4) -#define YT8521_RC1R_GE_TX_DELAY_MASK (0xF << 0) -#define YT8521_RC1R_GE_TX_DELAY_EN (0xF << 0) -#define YT8521_RC1R_GE_TX_DELAY_DIS (0x0 << 0) +#define YT8521_RC1R_GE_TX_DELAY_BIT (0) +#define YT8521_RC1R_FE_TX_DELAY_BIT (4) +#define YT8521_RC1R_RX_DELAY_BIT (10) +#define YT8521_RC1R_RX_DELAY_MASK (0xF << YT8521_RC1R_RX_DELAY_BIT) +#define YT8521_RC1R_RX_DELAY_EN (0xF << YT8521_RC1R_RX_DELAY_BIT) +#define YT8521_RC1R_RX_DELAY_DIS (0x0 << YT8521_RC1R_RX_DELAY_BIT) +#define YT8521_RC1R_FE_TX_DELAY_MASK (0xF << YT8521_RC1R_FE_TX_DELAY_BIT) +#define YT8521_RC1R_FE_TX_DELAY_EN (0xF << YT8521_RC1R_FE_TX_DELAY_BIT) +#define YT8521_RC1R_FE_TX_DELAY_DIS (0x0 << YT8521_RC1R_FE_TX_DELAY_BIT) +#define YT8521_RC1R_GE_TX_DELAY_MASK (0xF << YT8521_RC1R_GE_TX_DELAY_BIT) +#define YT8521_RC1R_GE_TX_DELAY_EN (0xF << YT8521_RC1R_GE_TX_DELAY_BIT) +#define YT8521_RC1R_GE_TX_DELAY_DIS (0x0 << YT8521_RC1R_GE_TX_DELAY_BIT) #define YTPHY_MISC_CONFIG_REG 0xA006 #define YTPHY_MCR_FIBER_SPEED_MASK BIT(0) @@ -222,11 +239,33 @@ */ #define YTPHY_WCR_TYPE_PULSE BIT(0) -#define YT8531S_SYNCE_CFG_REG 0xA012 -#define YT8531S_SCR_SYNCE_ENABLE BIT(6) +#define YTPHY_SYNCE_CFG_REG 0xA012 +#define YT8521_SCR_CLK_SRC_MASK (BIT(2) | BIT(1)) +#define YT8521_SCR_CLK_SRC_PLL_125M (0x0 << 1) +#define YT8521_SCR_CLK_SRC_REF_25M (0x3 << 1) +#define YT8521_SCR_SYNCE_ENABLE BIT(5) +#define YT8521_SCR_CLK_FRE_SEL_MASK BIT(3) +#define YT8521_SCR_CLK_FRE_SEL_125M (0x1 << 3) +#define YT8521_SCR_CLK_FRE_SEL_25M (0x0 << 3) +#define YT8531_SCR_CLK_SRC_MASK (BIT(3) | BIT(2) | BIT(1)) +#define YT8531_SCR_CLK_SRC_PLL_125M (0x0 << 1) +#define YT8531_SCR_CLK_SRC_REF_25M (0x4 << 1) +#define YT8531_SCR_SYNCE_ENABLE BIT(6) +#define YT8531_SCR_CLK_FRE_SEL_MASK BIT(4) +#define YT8531_SCR_CLK_FRE_SEL_125M (0x1 << 4) +#define YT8531_SCR_CLK_FRE_SEL_25M (0x0 << 4) /* Extended Register end */ +#define YTPHY_DTS_MAX_TX_AMPLITUDE 0x2 +#define YTPHY_DTS_MAX_DELAY_VAL 2250 +#define YTPHY_DTS_STEP_DELAY_VAL 150 +#define YTPHY_DTS_INVAL_VAL 0xFF + +#define YTPHY_DTS_OUTPUT_CLK_DIS 0 +#define YTPHY_DTS_OUTPUT_CLK_25M 25000000 +#define YTPHY_DTS_OUTPUT_CLK_125M 125000000 + struct yt8521_priv { /* combo_advertising is used for case of YT8521 in combo mode, * this means that yt8521 may work in utp or fiber mode which depends @@ -243,6 +282,30 @@ struct yt8521_priv { * YT8521_RSSR_TO_BE_ARBITRATED */ u8 reg_page; + + /* The following parameters are from dts */ + /* rx delay = rx_delay_basic + rx_delay_additional + * basic delay is ~2ns, 0 = off, 1 = on + * rx_delay_additional,delay time = 150ps * val + */ + u8 rx_delay_basic; + u8 rx_delay_additional; + + /* tx_delay_ge is tx_delay for 1000Mbps + * tx_delay_fe is tx_delay for 100Mbps or 10Mbps + * delay time = 150ps * val + */ + u8 tx_delay_ge; + u8 tx_delay_fe; + u8 sds_tx_amplitude; + bool keep_pll_enabled; + bool auto_sleep_disabled; + bool clock_ouput; /* output clock ctl: 0=off, 1=on */ + bool clock_freq_125M; /* output clock freq selcect: 0=25M, 1=125M */ + bool tx_clk_adj_enabled;/* tx clk adj ctl: 0=off, 1=on */ + bool tx_clk_10_inverted; + bool tx_clk_100_inverted; + bool tx_clk_1000_inverted; }; /** @@ -593,6 +656,325 @@ static int yt8521_write_page(struct phy_device *phydev, int page) return ytphy_modify_ext(phydev, YT8521_REG_SPACE_SELECT_REG, mask, set); }; +static int ytphy_parse_dt(struct phy_device *phydev) +{ + struct device_node *node = phydev->mdio.dev.of_node; + struct yt8521_priv *priv = phydev->priv; + u32 freq, val; + int ret; + + priv->rx_delay_additional = YTPHY_DTS_INVAL_VAL; + priv->sds_tx_amplitude = YTPHY_DTS_INVAL_VAL; + priv->rx_delay_basic = YTPHY_DTS_INVAL_VAL; + priv->tx_delay_ge = YTPHY_DTS_INVAL_VAL; + priv->tx_delay_fe = YTPHY_DTS_INVAL_VAL; + + if (!IS_ENABLED(CONFIG_OF_MDIO)) { + priv->auto_sleep_disabled = true; + priv->keep_pll_enabled = true; + return 0; + } + + ret = of_property_read_u32(node, "motorcomm,clk-out-frequency", &freq); + if (ret < 0) + freq = YTPHY_DTS_OUTPUT_CLK_DIS;/* default value as dts*/ + + switch (freq) { + case YTPHY_DTS_OUTPUT_CLK_DIS: + priv->clock_ouput = false; + break; + case YTPHY_DTS_OUTPUT_CLK_25M: + priv->clock_freq_125M = false; + priv->clock_ouput = true; + break; + case YTPHY_DTS_OUTPUT_CLK_125M: + priv->clock_freq_125M = true; + priv->clock_ouput = true; + break; + default: + phydev_err(phydev, "invalid motorcomm,clk-out-frequency\n"); + return -EINVAL; + } + + if (!of_property_read_u32(node, "motorcomm,rx-delay-basic", &val)) { + if (val > 1) { + phydev_err(phydev, + "invalid motorcomm,rx-delay-basic\n"); + return -EINVAL; + } + priv->rx_delay_basic = val; + } + + if (!of_property_read_u32(node, "motorcomm,rx-delay-additional-ps", &val)) { + if (val > YTPHY_DTS_MAX_DELAY_VAL) { + phydev_err(phydev, "invalid motorcomm,rx-delay-additional-ps\n"); + return -EINVAL; + } + if (val) + val /= YTPHY_DTS_STEP_DELAY_VAL; + priv->rx_delay_additional = val; + } + + if (!of_property_read_u32(node, "motorcomm,tx-delay-fe-ps", &val)) { + if (val > YTPHY_DTS_MAX_DELAY_VAL) { + phydev_err(phydev, + "invalid motorcomm,tx-delay-fe-ps\n"); + return -EINVAL; + } + if (val) + val /= YTPHY_DTS_STEP_DELAY_VAL; + priv->tx_delay_fe = val; + } + + if (!of_property_read_u32(node, "motorcomm,tx-delay-ge-ps", &val)) { + if (val > YTPHY_DTS_MAX_DELAY_VAL) { + phydev_err(phydev, + "invalid motorcomm,tx-delay-ge-ps\n"); + return -EINVAL; + } + if (val) + val /= YTPHY_DTS_STEP_DELAY_VAL; + priv->tx_delay_ge = val; + } + + if (of_property_read_bool(node, "motorcomm,keep-pll-enabled")) + priv->keep_pll_enabled = true; + + if (of_property_read_bool(node, "motorcomm,auto-sleep-disabled")) + priv->auto_sleep_disabled = true; + + if (of_property_read_bool(node, "motorcomm,tx-clk-adj-enabled")) + priv->tx_clk_adj_enabled = true; + if (priv->tx_clk_adj_enabled) { + if (of_property_read_bool(node, "motorcomm,tx-clk-10-inverted")) + priv->tx_clk_10_inverted = true; + if (of_property_read_bool(node, "motorcomm,tx-clk-100-inverted")) + priv->tx_clk_100_inverted = true; + if (of_property_read_bool(node, "motorcomm,tx-clk-1000-inverted")) + priv->tx_clk_1000_inverted = true; + } + + if (!of_property_read_u32(node, "motorcomm,sds-tx-amplitude", &val)) { + if (val > YTPHY_DTS_MAX_TX_AMPLITUDE) { + phydev_err(phydev, + "invalid motorcomm,sds-tx-amplitude\n"); + return -EINVAL; + } + priv->sds_tx_amplitude = val; + } + + return 0; +} + +static int ytphy_clk_out_config(struct phy_device *phydev) +{ + struct yt8521_priv *priv = phydev->priv; + u16 set = 0; + u16 mask; + + switch (phydev->drv->phy_id) { + case PHY_ID_YT8511: + /* YT8511 will be supported later */ + return -EOPNOTSUPP; + case PHY_ID_YT8521: + mask = YT8521_SCR_SYNCE_ENABLE; + if (priv->clock_ouput) { + mask |= YT8521_SCR_CLK_SRC_MASK; + mask |= YT8521_SCR_CLK_FRE_SEL_MASK; + set |= YT8521_SCR_SYNCE_ENABLE; + if (priv->clock_freq_125M) { + set |= YT8521_SCR_CLK_FRE_SEL_125M; + set |= YT8521_SCR_CLK_SRC_PLL_125M; + } else { + set |= YT8521_SCR_CLK_FRE_SEL_25M; + set |= YT8521_SCR_CLK_SRC_REF_25M; + } + } + break; + case PHY_ID_YT8531: + case PHY_ID_YT8531S: + mask = YT8531_SCR_SYNCE_ENABLE; + if (priv->clock_ouput) { + mask |= YT8531_SCR_CLK_SRC_MASK; + mask |= YT8531_SCR_CLK_FRE_SEL_MASK; + set |= YT8531_SCR_SYNCE_ENABLE; + if (priv->clock_freq_125M) { + set |= YT8531_SCR_CLK_FRE_SEL_125M; + set |= YT8531_SCR_CLK_SRC_PLL_125M; + } else { + set |= YT8531_SCR_CLK_FRE_SEL_25M; + set |= YT8531_SCR_CLK_SRC_REF_25M; + } + } + break; + default: + phydev_err(phydev, "invalid phy id\n"); + return -EINVAL; + } + + return ytphy_modify_ext(phydev, YTPHY_SYNCE_CFG_REG, mask, set); +} + +static int ytphy_serdes_tx_amplitude_config(struct phy_device *phydev) +{ + u16 yt8531s_tx_amplitude[] = { YT8531S_SAC2R_TX_AMPLITUDE_LOW, + YT8531S_SAC2R_TX_AMPLITUDE_MIDDLE, + YT8531S_SAC2R_TX_AMPLITUDE_HIGH }; + u16 yt8521_tx_amplitude[] = { YT8521_SAC2R_TX_AMPLITUDE_LOW, + YT8521_SAC2R_TX_AMPLITUDE_MIDDLE, + YT8521_SAC2R_TX_AMPLITUDE_HIGH }; + struct yt8521_priv *priv = phydev->priv; + u16 tx_amplitude; + + if (priv->sds_tx_amplitude == YTPHY_DTS_INVAL_VAL) + /* don't config Serdes tx amplitude.*/ + return 0; + + switch (phydev->drv->phy_id) { + case PHY_ID_YT8511: + case PHY_ID_YT8531: + /* YT8511 and YT8531 not support this function.*/ + return -EOPNOTSUPP; + case PHY_ID_YT8521: + tx_amplitude = yt8521_tx_amplitude[priv->sds_tx_amplitude]; + break; + case PHY_ID_YT8531S: + tx_amplitude = yt8531s_tx_amplitude[priv->sds_tx_amplitude]; + break; + default: + phydev_err(phydev, "invalid phy id\n"); + return -EINVAL; + } + + return ytphy_modify_ext(phydev, YTPHY_SERDES_ANALOG_CFG2_REG, + YTPHY_SAC2R_TX_AMPLITUDE_MASK, tx_amplitude); +} + +static int ytphy_rgmii_clk_delay_config(struct phy_device *phydev) +{ + struct yt8521_priv *priv = phydev->priv; + u16 mask = 0; + u16 val = 0; + int ret; + + /* rx delay basic controlled by dts.*/ + if (priv->rx_delay_basic != YTPHY_DTS_INVAL_VAL) { + if (priv->rx_delay_basic) + val = YT8521_CCR_RXC_DLY_EN; + ret = ytphy_modify_ext(phydev, YT8521_CHIP_CONFIG_REG, + YT8521_CCR_RXC_DLY_EN, val); + if (ret < 0) + return ret; + } + + val = 0; + /* If rx_delay_additional and tx_delay_* are all not be seted in dts, + * then used the fixed *_DELAY_DIS or *_DELAY_EN. Otherwise, use the + * value set by rx_delay_additional, tx_delay_ge and tx_delay_fe. + */ + if ((priv->rx_delay_additional & priv->tx_delay_ge & priv->tx_delay_fe) + == YTPHY_DTS_INVAL_VAL) { + switch (phydev->interface) { + case PHY_INTERFACE_MODE_RGMII: + val |= YT8521_RC1R_GE_TX_DELAY_DIS; + val |= YT8521_RC1R_FE_TX_DELAY_DIS; + val |= YT8521_RC1R_RX_DELAY_DIS; + break; + case PHY_INTERFACE_MODE_RGMII_RXID: + val |= YT8521_RC1R_GE_TX_DELAY_DIS; + val |= YT8521_RC1R_FE_TX_DELAY_DIS; + val |= YT8521_RC1R_RX_DELAY_EN; + break; + case PHY_INTERFACE_MODE_RGMII_TXID: + val |= YT8521_RC1R_GE_TX_DELAY_EN; + val |= YT8521_RC1R_FE_TX_DELAY_EN; + val |= YT8521_RC1R_RX_DELAY_DIS; + break; + case PHY_INTERFACE_MODE_RGMII_ID: + val |= YT8521_RC1R_GE_TX_DELAY_EN; + val |= YT8521_RC1R_FE_TX_DELAY_EN; + val |= YT8521_RC1R_RX_DELAY_EN; + break; + default: /* do not support other modes */ + return -EOPNOTSUPP; + } + mask = YT8521_RC1R_RX_DELAY_MASK | YT8521_RC1R_FE_TX_DELAY_MASK + | YT8521_RC1R_GE_TX_DELAY_MASK; + } else { + switch (phydev->interface) { + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII_TXID: + case PHY_INTERFACE_MODE_RGMII_ID: + if (priv->rx_delay_additional != YTPHY_DTS_INVAL_VAL) { + mask |= YT8521_RC1R_RX_DELAY_MASK; + val |= (priv->rx_delay_additional) << YT8521_RC1R_RX_DELAY_BIT; + } + if (priv->tx_delay_fe != YTPHY_DTS_INVAL_VAL) { + mask |= YT8521_RC1R_FE_TX_DELAY_MASK; + val |= (priv->tx_delay_fe) << YT8521_RC1R_FE_TX_DELAY_BIT; + } + if (priv->tx_delay_ge != YTPHY_DTS_INVAL_VAL) { + mask |= YT8521_RC1R_GE_TX_DELAY_MASK; + val |= (priv->tx_delay_ge) << YT8521_RC1R_GE_TX_DELAY_BIT; + } + break; + default: /* do not support other modes */ + return -EOPNOTSUPP; + } + } + + return ytphy_modify_ext(phydev, YT8521_RGMII_CONFIG1_REG, mask, val); +} + +static int ytphy_clk_delay_config(struct phy_device *phydev) +{ + switch (phydev->drv->phy_id) { + case PHY_ID_YT8511: + /* YT8511 will be supported later */ + return -EOPNOTSUPP; + case PHY_ID_YT8521: + case PHY_ID_YT8531S: + /* YT8521 and YT8531S support SGMII mode, but don't need + * delay. + */ + if (phydev->interface == PHY_INTERFACE_MODE_SGMII) + return 0; + + return ytphy_rgmii_clk_delay_config(phydev); + case PHY_ID_YT8531: + /* YT8531 don't support SGMII mode. */ + return ytphy_rgmii_clk_delay_config(phydev); + default: + phydev_err(phydev, "invalid phy id\n"); + return -EINVAL; + } + + return 0; +} + +static int ytphy_probe_helper(struct phy_device *phydev) +{ + struct device *dev = &phydev->mdio.dev; + struct yt8521_priv *priv; + int ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + phydev->priv = priv; + + ret = ytphy_parse_dt(phydev); + if (ret < 0) + return ret; + + phy_lock_mdio_bus(phydev); + ret = ytphy_clk_out_config(phydev); + phy_unlock_mdio_bus(phydev); + return ret; +} + /** * yt8521_probe() - read chip config then set suitable polling_mode * @phydev: a pointer to a &struct phy_device @@ -601,16 +983,15 @@ static int yt8521_write_page(struct phy_device *phydev, int page) */ static int yt8521_probe(struct phy_device *phydev) { - struct device *dev = &phydev->mdio.dev; struct yt8521_priv *priv; int chip_config; int ret; - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; + ret = ytphy_probe_helper(phydev); + if (ret < 0) + return ret; - phydev->priv = priv; + priv = phydev->priv; chip_config = ytphy_read_ext_with_lock(phydev, YT8521_CHIP_CONFIG_REG); if (chip_config < 0) @@ -651,26 +1032,6 @@ static int yt8521_probe(struct phy_device *phydev) return 0; } -/** - * yt8531s_probe() - read chip config then set suitable polling_mode - * @phydev: a pointer to a &struct phy_device - * - * returns 0 or negative errno code - */ -static int yt8531s_probe(struct phy_device *phydev) -{ - int ret; - - /* Disable SyncE clock output by default */ - ret = ytphy_modify_ext_with_lock(phydev, YT8531S_SYNCE_CFG_REG, - YT8531S_SCR_SYNCE_ENABLE, 0); - if (ret < 0) - return ret; - - /* same as yt8521_probe */ - return yt8521_probe(phydev); -} - /** * ytphy_utp_read_lpa() - read LPA then setup lp_advertising for utp * @phydev: a pointer to a &struct phy_device @@ -1125,6 +1486,34 @@ static int yt8521_resume(struct phy_device *phydev) return yt8521_modify_utp_fiber_bmcr(phydev, BMCR_PDOWN, 0); } +static int ytphy_config_init_helper(struct phy_device *phydev) +{ + struct yt8521_priv *priv = phydev->priv; + int ret; + + ret = ytphy_clk_delay_config(phydev); + if (ret < 0) + return ret; + + /* disable auto sleep */ + if (priv->auto_sleep_disabled) { + ret = ytphy_modify_ext(phydev, YT8521_EXTREG_SLEEP_CONTROL1_REG, + YT8521_ESC1R_SLEEP_SW, 0); + if (ret < 0) + return ret; + } + + /* enable RXC clock when no wire plug */ + if (priv->keep_pll_enabled) { + ret = ytphy_modify_ext(phydev, YT8521_CLOCK_GATING_REG, + YT8521_CGR_RX_CLK_EN, 0); + if (ret < 0) + return ret; + } + + return 0; +} + /** * yt8521_config_init() - called to initialize the PHY * @phydev: a pointer to a &struct phy_device @@ -1135,59 +1524,21 @@ static int yt8521_config_init(struct phy_device *phydev) { int old_page; int ret = 0; - u16 val; old_page = phy_select_page(phydev, YT8521_RSSR_UTP_SPACE); if (old_page < 0) goto err_restore_page; - switch (phydev->interface) { - case PHY_INTERFACE_MODE_RGMII: - val = YT8521_RC1R_GE_TX_DELAY_DIS | YT8521_RC1R_FE_TX_DELAY_DIS; - val |= YT8521_RC1R_RX_DELAY_DIS; - break; - case PHY_INTERFACE_MODE_RGMII_RXID: - val = YT8521_RC1R_GE_TX_DELAY_DIS | YT8521_RC1R_FE_TX_DELAY_DIS; - val |= YT8521_RC1R_RX_DELAY_EN; - break; - case PHY_INTERFACE_MODE_RGMII_TXID: - val = YT8521_RC1R_GE_TX_DELAY_EN | YT8521_RC1R_FE_TX_DELAY_EN; - val |= YT8521_RC1R_RX_DELAY_DIS; - break; - case PHY_INTERFACE_MODE_RGMII_ID: - val = YT8521_RC1R_GE_TX_DELAY_EN | YT8521_RC1R_FE_TX_DELAY_EN; - val |= YT8521_RC1R_RX_DELAY_EN; - break; - case PHY_INTERFACE_MODE_SGMII: - break; - default: /* do not support other modes */ - ret = -EOPNOTSUPP; - goto err_restore_page; - } - - /* set rgmii delay mode */ - if (phydev->interface != PHY_INTERFACE_MODE_SGMII) { - ret = ytphy_modify_ext(phydev, YT8521_RGMII_CONFIG1_REG, - (YT8521_RC1R_RX_DELAY_MASK | - YT8521_RC1R_FE_TX_DELAY_MASK | - YT8521_RC1R_GE_TX_DELAY_MASK), - val); - if (ret < 0) - goto err_restore_page; - } - - /* disable auto sleep */ - ret = ytphy_modify_ext(phydev, YT8521_EXTREG_SLEEP_CONTROL1_REG, - YT8521_ESC1R_SLEEP_SW, 0); + ret = ytphy_config_init_helper(phydev); if (ret < 0) goto err_restore_page; - /* enable RXC clock when no wire plug */ - ret = ytphy_modify_ext(phydev, YT8521_CLOCK_GATING_REG, - YT8521_CGR_RX_CLK_EN, 0); + ret = yt8521_write_page(phydev, YT8521_RSSR_FIBER_SPACE); if (ret < 0) goto err_restore_page; + ret = ytphy_serdes_tx_amplitude_config(phydev); + err_restore_page: return phy_restore_page(phydev, old_page, ret); } @@ -1778,7 +2129,7 @@ static struct phy_driver motorcomm_phy_drvs[] = { PHY_ID_MATCH_EXACT(PHY_ID_YT8531S), .name = "YT8531S Gigabit Ethernet", .get_features = yt8521_get_features, - .probe = yt8531s_probe, + .probe = yt8521_probe, .read_page = yt8521_read_page, .write_page = yt8521_write_page, .get_wol = ytphy_get_wol, @@ -1804,7 +2155,7 @@ static const struct mdio_device_id __maybe_unused motorcomm_tbl[] = { { PHY_ID_MATCH_EXACT(PHY_ID_YT8511) }, { PHY_ID_MATCH_EXACT(PHY_ID_YT8521) }, { PHY_ID_MATCH_EXACT(PHY_ID_YT8531S) }, - { /* sentinal */ } + { /* sentinel */ } }; MODULE_DEVICE_TABLE(mdio, motorcomm_tbl); From patchwork Thu Jan 5 07:30:24 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Frank Sae X-Patchwork-Id: 13089489 X-Patchwork-Delegate: kuba@kernel.org Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 607A9C3DA7A for ; Thu, 5 Jan 2023 07:31:15 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230266AbjAEHao (ORCPT ); Thu, 5 Jan 2023 02:30:44 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38008 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230407AbjAEHaM (ORCPT ); Thu, 5 Jan 2023 02:30:12 -0500 Received: from out29-126.mail.aliyun.com (out29-126.mail.aliyun.com [115.124.29.126]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 455D14BD59; Wed, 4 Jan 2023 23:30:10 -0800 (PST) X-Alimail-AntiSpam: AC=CONTINUE;BC=0.07440397|-1;CH=green;DM=|CONTINUE|false|;DS=CONTINUE|ham_system_inform|0.00960953-0.221312-0.769078;FP=0|0|0|0|0|-1|-1|-1;HT=ay29a033018047198;MF=frank.sae@motor-comm.com;NM=1;PH=DS;RN=17;RT=17;SR=0;TI=SMTPD_---.QktmAx9_1672903805; Received: from sun-VirtualBox..(mailfrom:Frank.Sae@motor-comm.com fp:SMTPD_---.QktmAx9_1672903805) by smtp.aliyun-inc.com; Thu, 05 Jan 2023 15:30:06 +0800 From: Frank To: Peter Geis , Andrew Lunn , Heiner Kallweit , Russell King , "David S . Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Rob Herring , Krzysztof Kozlowski Cc: xiaogang.fan@motor-comm.com, fei.zhang@motor-comm.com, hua.sun@motor-comm.com, netdev@vger.kernel.org, linux-kernel@vger.kernel.org, Frank , devicetree@vger.kernel.org Subject: [PATCH net-next v1 3/3] net: phy: Add driver for Motorcomm yt8531 gigabit ethernet phy Date: Thu, 5 Jan 2023 15:30:24 +0800 Message-Id: <20230105073024.8390-4-Frank.Sae@motor-comm.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230105073024.8390-1-Frank.Sae@motor-comm.com> References: <20230105073024.8390-1-Frank.Sae@motor-comm.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: kuba@kernel.org Add driver for Motorcomm yt8531 gigabit ethernet phy. This patch has been tested on AM335x platform which has one YT8531 interface card and passed all test cases. Signed-off-by: Frank --- drivers/net/phy/Kconfig | 2 +- drivers/net/phy/motorcomm.c | 127 +++++++++++++++++++++++++++++++++++- 2 files changed, 126 insertions(+), 3 deletions(-) diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 1327290decab..e25c061e619a 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -257,7 +257,7 @@ config MOTORCOMM_PHY tristate "Motorcomm PHYs" help Enables support for Motorcomm network PHYs. - Currently supports the YT8511, YT8521, YT8531S Gigabit Ethernet PHYs. + Currently supports the YT8511, YT8521, YT8531, YT8531S Gigabit Ethernet PHYs. config NATIONAL_PHY tristate "National Semiconductor PHYs" diff --git a/drivers/net/phy/motorcomm.c b/drivers/net/phy/motorcomm.c index 7ebcca374a67..23d7e48587cf 100644 --- a/drivers/net/phy/motorcomm.c +++ b/drivers/net/phy/motorcomm.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * Motorcomm 8511/8521/8531S PHY driver. + * Motorcomm 8511/8521/8531/8531S PHY driver. * * Author: Peter Geis * Author: Frank @@ -14,6 +14,7 @@ #define PHY_ID_YT8511 0x0000010a #define PHY_ID_YT8521 0x0000011a +#define PHY_ID_YT8531 0x4f51e91b #define PHY_ID_YT8531S 0x4f51e91a /* YT8521/YT8531S Register Overview @@ -542,6 +543,69 @@ static int ytphy_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol) return phy_restore_page(phydev, old_page, ret); } +static int yt8531_set_wol(struct phy_device *phydev, + struct ethtool_wolinfo *wol) +{ + struct net_device *p_attached_dev; + const u16 mac_addr_reg[] = { + YTPHY_WOL_MACADDR2_REG, + YTPHY_WOL_MACADDR1_REG, + YTPHY_WOL_MACADDR0_REG, + }; + const u8 *mac_addr; + u16 mask; + u16 val; + int ret; + u8 i; + + if (wol->wolopts & WAKE_MAGIC) { + p_attached_dev = phydev->attached_dev; + if (!p_attached_dev) + return -ENODEV; + + mac_addr = (const u8 *)p_attached_dev->dev_addr; + if (!is_valid_ether_addr(mac_addr)) + return -EINVAL; + + /* Store the device address for the magic packet */ + for (i = 0; i < 3; i++) { + ret = ytphy_write_ext_with_lock(phydev, mac_addr_reg[i], + ((mac_addr[i * 2] << 8)) | + (mac_addr[i * 2 + 1])); + if (ret < 0) + return ret; + } + + /* Enable WOL feature */ + mask = YTPHY_WCR_PULSE_WIDTH_MASK | YTPHY_WCR_INTR_SEL; + val = YTPHY_WCR_ENABLE | YTPHY_WCR_INTR_SEL; + val |= YTPHY_WCR_TYPE_PULSE | YTPHY_WCR_PULSE_WIDTH_672MS; + ret = ytphy_modify_ext_with_lock(phydev, YTPHY_WOL_CONFIG_REG, + mask, val); + if (ret < 0) + return ret; + + /* Enable WOL interrupt */ + ret = phy_modify(phydev, YTPHY_INTERRUPT_ENABLE_REG, 0, + YTPHY_IER_WOL); + if (ret < 0) + return ret; + } else { + /* Disable WOL feature */ + mask = YTPHY_WCR_ENABLE | YTPHY_WCR_INTR_SEL; + ret = ytphy_modify_ext_with_lock(phydev, YTPHY_WOL_CONFIG_REG, + mask, 0); + + /* Disable WOL interrupt */ + ret = phy_modify(phydev, YTPHY_INTERRUPT_ENABLE_REG, + YTPHY_IER_WOL, 0); + if (ret < 0) + return ret; + } + + return 0; +} + static int yt8511_read_page(struct phy_device *phydev) { return __phy_read(phydev, YT8511_PAGE_SELECT); @@ -1032,6 +1096,11 @@ static int yt8521_probe(struct phy_device *phydev) return 0; } +static int yt8531_probe(struct phy_device *phydev) +{ + return ytphy_probe_helper(phydev); +} + /** * ytphy_utp_read_lpa() - read LPA then setup lp_advertising for utp * @phydev: a pointer to a &struct phy_device @@ -1543,6 +1612,48 @@ static int yt8521_config_init(struct phy_device *phydev) return phy_restore_page(phydev, old_page, ret); } +static int yt8531_config_init(struct phy_device *phydev) +{ + int ret; + + phy_lock_mdio_bus(phydev); + ret = ytphy_config_init_helper(phydev); + phy_unlock_mdio_bus(phydev); + + return ret; +} + +static void yt8531_link_change_notify(struct phy_device *phydev) +{ + struct yt8521_priv *priv = phydev->priv; + u16 val = 0; + + if (!(priv->tx_clk_adj_enabled)) + return; + + if (phydev->speed < 0) + return; + + switch (phydev->speed) { + case SPEED_1000: + if (priv->tx_clk_1000_inverted) + val = YT8521_RC1R_TX_CLK_SEL_INVERTED; + break; + case SPEED_100: + if (priv->tx_clk_100_inverted) + val = YT8521_RC1R_TX_CLK_SEL_INVERTED; + break; + case SPEED_10: + if (priv->tx_clk_10_inverted) + val = YT8521_RC1R_TX_CLK_SEL_INVERTED; + break; + default: + return; + } + ytphy_modify_ext_with_lock(phydev, YT8521_RGMII_CONFIG1_REG, + YT8521_RC1R_TX_CLK_SEL_MASK, val); +} + /** * yt8521_prepare_fiber_features() - A small helper function that setup * fiber's features. @@ -2125,6 +2236,17 @@ static struct phy_driver motorcomm_phy_drvs[] = { .suspend = yt8521_suspend, .resume = yt8521_resume, }, + { + PHY_ID_MATCH_EXACT(PHY_ID_YT8531), + .name = "YT8531 Gigabit Ethernet", + .probe = yt8531_probe, + .config_init = yt8531_config_init, + .suspend = genphy_suspend, + .resume = genphy_resume, + .get_wol = ytphy_get_wol, + .set_wol = yt8531_set_wol, + .link_change_notify = yt8531_link_change_notify, + }, { PHY_ID_MATCH_EXACT(PHY_ID_YT8531S), .name = "YT8531S Gigabit Ethernet", @@ -2146,7 +2268,7 @@ static struct phy_driver motorcomm_phy_drvs[] = { module_phy_driver(motorcomm_phy_drvs); -MODULE_DESCRIPTION("Motorcomm 8511/8521/8531S PHY driver"); +MODULE_DESCRIPTION("Motorcomm 8511/8521/8531/8531S PHY driver"); MODULE_AUTHOR("Peter Geis"); MODULE_AUTHOR("Frank"); MODULE_LICENSE("GPL"); @@ -2154,6 +2276,7 @@ MODULE_LICENSE("GPL"); static const struct mdio_device_id __maybe_unused motorcomm_tbl[] = { { PHY_ID_MATCH_EXACT(PHY_ID_YT8511) }, { PHY_ID_MATCH_EXACT(PHY_ID_YT8521) }, + { PHY_ID_MATCH_EXACT(PHY_ID_YT8531) }, { PHY_ID_MATCH_EXACT(PHY_ID_YT8531S) }, { /* sentinel */ } };