From f87f0f95b214162482bc867f32196be9388acef4 Mon Sep 17 00:00:00 2001 From: ardu <1775956414@qq.com> Date: Tue, 27 Jan 2026 15:12:08 +0800 Subject: [PATCH] update --- drivers/net/phy/jlsemi-core.c | 2667 +++++++++++++++++++++++ drivers/net/phy/jlsemi-core.h | 439 ++++ drivers/net/phy/jlsemi-dt-phy.h | 341 +++ drivers/net/phy/jlsemi.c | 577 +++++ include/dt-bindings/phy/jlsemi-dt-phy.h | 341 +++ 5 files changed, 4365 insertions(+) create mode 100644 drivers/net/phy/jlsemi-core.c create mode 100644 drivers/net/phy/jlsemi-core.h create mode 100644 drivers/net/phy/jlsemi-dt-phy.h create mode 100644 drivers/net/phy/jlsemi.c create mode 100644 include/dt-bindings/phy/jlsemi-dt-phy.h diff --git a/drivers/net/phy/jlsemi-core.c b/drivers/net/phy/jlsemi-core.c new file mode 100644 index 000000000..acc07547f --- /dev/null +++ b/drivers/net/phy/jlsemi-core.c @@ -0,0 +1,2667 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2021 JLSemi Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include "jlsemi-core.h" +#include +#include +#include +#include + +#define JL1XXX_PAGE24 24 +#define JL1XXX_LED_BLINK_REG 25 + +#define JL1XXX_PAGE128 128 +#define JL1XXX_LED_GPIO_REG 29 +#define JL1XXX_WOL_CTRL_REG 28 + +#define JL2XXX_PAGE3332 3332 +#define JL2XXX_LED_CTRL_REG 16 +#define JL2XXX_PAGE4096 4096 +#define JL2XXX_LED_BLINK_REG 20 +#define JL2XXX_LED_POLARITY_REG 19 + +#define JL2XXX_PAGE128 128 +#define JL2XXX_FLD_CTRL_REG 28 +#define JL2XXX_FLD_EN BIT(13) +#define JL2XXX_FLD_MASK 0x1800 +#define JL2XXX_FLD_MASK_HEAD 11 +#define JL2XXX_FLD_DELAY_00MS 0 +#define JL2XXX_FLD_DELAY_10MS 1 +#define JL2XXX_FLD_DELAY_20MS 2 +#define JL2XXX_FLD_DELAY_40MS 3 + +#define JL2XXX_SPEED10 0 +#define JL2XXX_SPEED100 1 +#define JL2XXX_SPEED1000 2 + +#define JL2XXX_PHY_MODE_REG 30 +#define JL2XXX_FIBER_1000 BIT(12) +#define JL2XXX_FIBER_100 BIT(11) +#define JL2XXX_PHY_FIBER_MODE_MASK 0x1800 +#define JL2XXX_BMCR_DUPLEX BIT(8) +#define JL2XXX_LPA_FIBER_1000HALF 0x40 +#define JL2XXX_LPA_FIBER_1000FULL 0x20 +#define JL2XXX_BMCR_SPEED_LSB BIT(13) +#define JL2XXX_BMCR_SPEED_MSB BIT(6) +#define JL2XXX_BMCR_AN_RESTART BIT(9) + + + +#define JL2XXX_SUPP_LED_MODE (JL2XXX_LED0_LINK10 | \ + JL2XXX_LED0_LINK100 | \ + JL2XXX_LED0_LINK1000 | \ + JL2XXX_LED0_ACTIVITY | \ + JL2XXX_LED1_LINK10 | \ + JL2XXX_LED1_LINK100 | \ + JL2XXX_LED1_LINK1000 | \ + JL2XXX_LED1_ACTIVITY | \ + JL2XXX_LED2_LINK10 | \ + JL2XXX_LED2_LINK100 | \ + JL2XXX_LED2_LINK1000 | \ + JL2XXX_LED2_ACTIVITY) + +#define JL1XXX_SUPP_GPIO (JL1XXX_GPIO_LED0_EN | \ + JL1XXX_GPIO_LED0_OUT | \ + JL1XXX_GPIO_LED1_EN | \ + JL1XXX_GPIO_LED1_OUT) + +#define JL1XXX_SUPP_LED_MODE (JL1XXX_LED0_EEE | \ + JL1XXX_LED0_100_ACTIVITY | \ + JL1XXX_LED0_10_ACTIVITY | \ + JL1XXX_LED0_100_LINK | \ + JL1XXX_LED0_10_LINK | \ + JL1XXX_LED1_EEE | \ + JL1XXX_LED1_100_ACTIVITY | \ + JL1XXX_LED1_10_ACTIVITY | \ + JL1XXX_LED1_100_LINK | \ + JL1XXX_LED1_10_LINK) + +/************************* Configuration section *************************/ + + +/************************* JLSemi iteration code *************************/ +static int jl1xxx_led_static_op_set(struct phy_device *phydev) +{ + struct jl1xxx_priv *priv = phydev->priv; + int err; + + /* Enable LED operation */ + jlsemi_set_bits(phydev, JL1XXX_PAGE7, + JL1XXX_LED_REG, JL1XXX_LED_EN); + + /* Set led mode */ + if (priv->led.enable & JL1XXX_LED_MODE_EN) { + err = jlsemi_modify_paged_reg(phydev, JL1XXX_PAGE129, + JL1XXX_LED_MODE_REG, + JL1XXX_SUPP_LED_MODE, + priv->led.mode); + if (err < 0) + return err; + } + /* Set led period */ + if (priv->led.enable & JL1XXX_LED_GLOABL_PERIOD_EN) { + err = jlsemi_modify_paged_reg(phydev, JL1XXX_PAGE24, + JL1XXX_LED_BLINK_REG, + LED_PERIOD_MASK, + LEDPERIOD( + priv->led.global_period)); + if (err < 0) + return err; + } + /* Set led on time */ + if (priv->led.enable & JL1XXX_LED_GLOBAL_ON_EN) { + err = jlsemi_modify_paged_reg(phydev, JL1XXX_PAGE24, + JL1XXX_LED_BLINK_REG, + LED_ON_MASK, + LEDON(priv->led.global_on)); + if (err < 0) + return err; + } + /*Set led gpio output */ + if (priv->led.enable & JL1XXX_LED_GPIO_OUT_EN) { + err = jlsemi_modify_paged_reg(phydev, JL1XXX_PAGE128, + JL1XXX_LED_GPIO_REG, + JL1XXX_SUPP_GPIO, + priv->led.gpio_output); + if (err < 0) + return err; + } + + return 0; +} + +static int jl2xxx_led_static_op_set(struct phy_device *phydev) +{ + struct jl2xxx_priv *priv = phydev->priv; + int err; + + /* Set led mode */ + if (priv->led.enable & JL2XXX_LED_MODE_EN) { + err = jlsemi_modify_paged_reg(phydev, JL2XXX_PAGE3332, + JL2XXX_LED_CTRL_REG, + JL2XXX_SUPP_LED_MODE, + priv->led.mode); + if (err < 0) + return err; + } + /* Set led period */ + if (priv->led.enable & JL2XXX_LED_GLOABL_PERIOD_EN) { + err = jlsemi_modify_paged_reg(phydev, JL2XXX_PAGE4096, + JL2XXX_LED_BLINK_REG, + LED_PERIOD_MASK, + LEDPERIOD( + priv->led.global_period)); + if (err < 0) + return err; + } + /* Set led on time */ + if (priv->led.enable & JL2XXX_LED_GLOBAL_ON_EN) { + err = jlsemi_modify_paged_reg(phydev, JL2XXX_PAGE4096, + JL2XXX_LED_BLINK_REG, + LED_ON_MASK, + LEDON(priv->led.global_on)); + if (err < 0) + return err; + } + /* Set led polarity */ + if (priv->led.enable & JL2XXX_LED_POLARITY_EN) { + err = jlsemi_set_bits(phydev, JL2XXX_PAGE4096, + JL2XXX_LED_POLARITY_REG, + priv->led.polarity); + if (err < 0) + return err; + } + + return 0; +} + +struct device *jlsemi_get_mdio(struct phy_device *phydev) +{ +#if JLSEMI_DEV_COMPATIBLE + struct device *dev = &phydev->dev; +#else + struct device *dev = &phydev->mdio.dev; +#endif + return dev; +} + +static struct device_node *get_device_node(struct phy_device *phydev) +{ + struct device *dev = jlsemi_get_mdio(phydev); + + return dev->of_node; +} + +static int jl1xxx_dts_led_cfg_get(struct phy_device *phydev) +{ + struct jl1xxx_priv *priv = phydev->priv; + struct device_node *of_node = get_device_node(phydev); + + of_property_read_u32(of_node, "jl1xxx,led-enable", + &priv->led.enable); + of_property_read_u32(of_node, "jl1xxx,led-mode", + &priv->led.mode); + of_property_read_u32(of_node, "jl1xxx,led-period", + &priv->led.global_period); + of_property_read_u32(of_node, "jl1xxx,led-on", + &priv->led.global_on); + of_property_read_u32(of_node, "jl1xxx,led-gpio", + &priv->led.gpio_output); + + return 0; +} + +static int jl1xxx_dts_wol_cfg_get(struct phy_device *phydev) +{ + struct jl1xxx_priv *priv = phydev->priv; + struct device_node *of_node = get_device_node(phydev); + + of_property_read_u32(of_node, "jl1xxx,wol-enable", + &priv->wol.enable); + + return 0; +} + +static int jl1xxx_dts_intr_cfg_get(struct phy_device *phydev) +{ + struct jl1xxx_priv *priv = phydev->priv; + struct device_node *of_node = get_device_node(phydev); + + of_property_read_u32(of_node, "jl1xxx,interrupt-enable", + &priv->intr.enable); + + return 0; +} + +static int jl1xxx_dts_mdi_cfg_get(struct phy_device *phydev) +{ + struct jl1xxx_priv *priv = phydev->priv; + struct device_node *of_node = get_device_node(phydev); + + of_property_read_u32(of_node, "jl1xxx,mdi-enable", + &priv->mdi.enable); + of_property_read_u32(of_node, "jl1xxx,mdi-rate", + &priv->mdi.rate); + of_property_read_u32(of_node, "jl1xxx,mdi-amplitude", + &priv->mdi.amplitude); + + return 0; +} + +static int jl1xxx_dts_rmii_cfg_get(struct phy_device *phydev) +{ + struct jl1xxx_priv *priv = phydev->priv; + struct device_node *of_node = get_device_node(phydev); + + of_property_read_u32(of_node, "jl1xxx,rmii-enable", + &priv->rmii.enable); + of_property_read_u32(of_node, "jl1xxx,rmii-rx_timing", + &priv->rmii.rx_timing); + of_property_read_u32(of_node, "jl1xxx,rmii-tx_timing", + &priv->rmii.tx_timing); + + return 0; +} + + +static int jl2xxx_dts_led_cfg_get(struct phy_device *phydev) +{ + struct jl2xxx_priv *priv = phydev->priv; + struct device_node *of_node = get_device_node(phydev); + + of_property_read_u32(of_node, "jl2xxx,led-enable", + &priv->led.enable); + of_property_read_u32(of_node, "jl2xxx,led-mode", + &priv->led.mode); + of_property_read_u32(of_node, "jl2xxx,led-period", + &priv->led.global_period); + of_property_read_u32(of_node, "jl2xxx,led-on", + &priv->led.global_on); + of_property_read_u32(of_node, "jl2xxx,led-polarity", + &priv->led.polarity); + + return 0; +} + +static int jl1xxx_c_macro_led_cfg_get(struct phy_device *phydev) +{ + struct jl1xxx_priv *priv = phydev->priv; + + /* Config LED */ + struct jl_led_ctrl led_cfg = { + .enable = JL1XXX_LED_CTRL_EN, + .mode = JL1XXX_CFG_LED_MODE, + .global_period = JL1XXX_GLOBAL_PERIOD_MS, + .global_on = JL1XXX_GLOBAL_ON_MS, + .gpio_output = JL1XXX_CFG_GPIO, + }; + + priv->led = led_cfg; + + return 0; +} + +static int jl1xxx_c_macro_wol_cfg_get(struct phy_device *phydev) +{ + struct jl1xxx_priv *priv = phydev->priv; + + struct jl_wol_ctrl wol_cfg = { + .enable = JL1XXX_WOL_CTRL_EN, + }; + + priv->wol = wol_cfg; + + return 0; +} + +static int jl1xxx_c_macro_intr_cfg_get(struct phy_device *phydev) +{ + struct jl1xxx_priv *priv = phydev->priv; + + struct jl_intr_ctrl intr_cfg = { + .enable = JL1XXX_INTR_CTRL_EN, + }; + + priv->intr = intr_cfg; + + return 0; +} + +static int jl1xxx_c_macro_mdi_cfg_get(struct phy_device *phydev) +{ + struct jl1xxx_priv *priv = phydev->priv; + + struct jl_mdi_ctrl mdi_cfg = { + .enable = JL1XXX_MDI_CTRL_EN, + .rate = JL1XXX_MDI_RATE, + .amplitude = JL1XXX_MDI_AMPLITUDE, + }; + + priv->mdi = mdi_cfg; + + return 0; +} + +static int jl1xxx_c_macro_rmii_cfg_get(struct phy_device *phydev) +{ + struct jl1xxx_priv *priv = phydev->priv; + + struct jl_rmii_ctrl rmii_cfg = { + .enable = JL1XXX_RMII_CTRL_EN, + .tx_timing = JL1XXX_RMII_TX_TIMING, + .rx_timing = JL1XXX_RMII_RX_TIMING, + }; + + priv->rmii = rmii_cfg; + + return 0; +} + +static int jl2xxx_c_macro_led_cfg_get(struct phy_device *phydev) +{ + struct jl2xxx_priv *priv = phydev->priv; + + struct jl_led_ctrl led_cfg = { + .enable = JL2XXX_LED_CTRL_EN, + .mode = JL2XXX_CFG_LED_MODE, + .global_period = JL2XXX_GLOBAL_PERIOD_MS, + .global_on = JL2XXX_GLOBAL_ON_MS, + .polarity = JL2XXX_LED_POLARITY, + }; + + priv->led = led_cfg; + + return 0; +} + +static int jl1xxx_wol_operation_args(struct phy_device *phydev) +{ + struct jl1xxx_priv *priv = phydev->priv; + struct jl_wol_ctrl *wol = &priv->wol; + + if (JLSEMI_KERNEL_DEVICE_TREE_USE) + jl1xxx_dts_wol_cfg_get(phydev); + else + jl1xxx_c_macro_wol_cfg_get(phydev); + + /* Supported by default */ + wol->ethtool = false; + + return 0; +} + +static int jl1xxx_intr_operation_args(struct phy_device *phydev) +{ + struct jl1xxx_priv *priv = phydev->priv; + struct jl_intr_ctrl *intr = &priv->intr; + + if (JLSEMI_KERNEL_DEVICE_TREE_USE) + jl1xxx_dts_intr_cfg_get(phydev); + else + jl1xxx_c_macro_intr_cfg_get(phydev); + + /* Not supported by default */ + intr->ethtool = false; + + return 0; +} + +static int jl1xxx_mdi_operation_args(struct phy_device *phydev) +{ + struct jl1xxx_priv *priv = phydev->priv; + struct jl_mdi_ctrl *mdi = &priv->mdi; + + if (JLSEMI_KERNEL_DEVICE_TREE_USE) + jl1xxx_dts_mdi_cfg_get(phydev); + else + jl1xxx_c_macro_mdi_cfg_get(phydev); + + /* Not supported by default */ + mdi->ethtool = false; + + return 0; +} + +static int jl1xxx_rmii_operation_args(struct phy_device *phydev) +{ + struct jl1xxx_priv *priv = phydev->priv; + struct jl_rmii_ctrl *rmii = &priv->rmii; + + if (JLSEMI_KERNEL_DEVICE_TREE_USE) + jl1xxx_dts_rmii_cfg_get(phydev); + else + jl1xxx_c_macro_rmii_cfg_get(phydev); + + /* Not supported by default */ + rmii->ethtool = false; + + return 0; +} + +static int jl1xxx_led_operation_args(struct phy_device *phydev) +{ + struct jl1xxx_priv *priv = phydev->priv; + struct jl_led_ctrl *led = &priv->led; + + if (JLSEMI_KERNEL_DEVICE_TREE_USE) + jl1xxx_dts_led_cfg_get(phydev); + else + jl1xxx_c_macro_led_cfg_get(phydev); + + /* Not supported by default */ + led->ethtool = false; + + return 0; +} + +static int jl2xxx_led_operation_args(struct phy_device *phydev) +{ + struct jl2xxx_priv *priv = phydev->priv; + struct jl_led_ctrl *led = &priv->led; + + if (JLSEMI_KERNEL_DEVICE_TREE_USE) + jl2xxx_dts_led_cfg_get(phydev); + else + jl2xxx_c_macro_led_cfg_get(phydev); + + /* Not supported by default */ + led->ethtool = false; + + return 0; +} + + +static int jl2xxx_dts_fld_cfg_get(struct phy_device *phydev) +{ + struct jl2xxx_priv *priv = phydev->priv; + struct device_node *of_node = get_device_node(phydev); + + of_property_read_u32(of_node, "jl2xxx,fld-enable", + &priv->fld.enable); + of_property_read_u32(of_node, "jl2xxx,fld-delay", + &priv->fld.delay); + + return 0; +} + +static int jl2xxx_dts_wol_cfg_get(struct phy_device *phydev) +{ + struct jl2xxx_priv *priv = phydev->priv; + struct device_node *of_node = get_device_node(phydev); + + of_property_read_u32(of_node, "jl2xxx,wol-enable", + &priv->wol.enable); + + return 0; +} + +static int jl2xxx_dts_intr_cfg_get(struct phy_device *phydev) +{ + struct jl2xxx_priv *priv = phydev->priv; + struct device_node *of_node = get_device_node(phydev); + + of_property_read_u32(of_node, "jl2xxx,interrupt-enable", + &priv->intr.enable); + + return 0; +} + +static int jl2xxx_dts_downshift_cfg_get(struct phy_device *phydev) +{ + struct jl2xxx_priv *priv = phydev->priv; + struct device_node *of_node = get_device_node(phydev); + + of_property_read_u32(of_node, "jl2xxx,downshift-enable", + &priv->downshift.enable); + of_property_read_u32(of_node, "jl2xxx,downshift-count", + &priv->downshift.count); + + return 0; +} + +static int jl2xxx_dts_rgmii_cfg_get(struct phy_device *phydev) +{ + struct jl2xxx_priv *priv = phydev->priv; + struct device_node *of_node = get_device_node(phydev); + + of_property_read_u32(of_node, "jl2xxx,rgmii-enable", + &priv->rgmii.enable); + of_property_read_u32(of_node, "jl2xxx,rgmii-tx-delay", + &priv->rgmii.tx_delay); + of_property_read_u32(of_node, "jl2xxx,rgmii-rx-delay", + &priv->rgmii.rx_delay); + + return 0; +} + +static int jl2xxx_dts_patch_cfg_get(struct phy_device *phydev) +{ + struct jl2xxx_priv *priv = phydev->priv; + struct device_node *of_node = get_device_node(phydev); + + of_property_read_u32(of_node, "jl2xxx,patch-enable", + &priv->patch.enable); + + return 0; +} + +static int jl2xxx_dts_clk_cfg_get(struct phy_device *phydev) +{ + struct jl2xxx_priv *priv = phydev->priv; + struct device_node *of_node = get_device_node(phydev); + + of_property_read_u32(of_node, "jl2xxx,clk-enable", + &priv->clk.enable); + + return 0; +} + +static int jl2xxx_dts_work_mode_cfg_get(struct phy_device *phydev) +{ + struct jl2xxx_priv *priv = phydev->priv; + struct device_node *of_node = get_device_node(phydev); + + of_property_read_u32(of_node, "jl2xxx,work_mode-enable", + &priv->work_mode.enable); + of_property_read_u32(of_node, "jl2xxx,work_mode-mode", + &priv->work_mode.mode); + + return 0; +} + +static int jl2xxx_dts_lpbk_cfg_get(struct phy_device *phydev) +{ + struct jl2xxx_priv *priv = phydev->priv; + struct device_node *of_node = get_device_node(phydev); + + of_property_read_u32(of_node, "jl2xxx,lpbk-enable", + &priv->lpbk.enable); + of_property_read_u32(of_node, "jl2xxx,lpbk-mode", + &priv->lpbk.mode); + + return 0; +} + +static int jl2xxx_dts_slew_rate_cfg_get(struct phy_device *phydev) +{ + struct jl2xxx_priv *priv = phydev->priv; + struct device_node *of_node = get_device_node(phydev); + + of_property_read_u32(of_node, "jl2xxx,slew_rate-enable", + &priv->slew_rate.enable); + + return 0; +} + +static int jl2xxx_dts_rxc_out_cfg_get(struct phy_device *phydev) +{ + struct jl2xxx_priv *priv = phydev->priv; + struct device_node *of_node = get_device_node(phydev); + + of_property_read_u32(of_node, "jl2xxx,rxc_out-enable", + &priv->rxc_out.enable); + + return 0; +} + +static int jl2xxx_c_macro_fld_cfg_get(struct phy_device *phydev) +{ + struct jl2xxx_priv *priv = phydev->priv; + + struct jl_fld_ctrl fld_cfg = { + .enable = JL2XXX_FLD_CTRL_EN, + .delay = JL2XXX_FLD_DELAY, + }; + + priv->fld = fld_cfg; + + return 0; +} + +static int jl2xxx_c_macro_wol_cfg_get(struct phy_device *phydev) +{ + struct jl2xxx_priv *priv = phydev->priv; + + struct jl_wol_ctrl wol_cfg = { + .enable = JL2XXX_WOL_CTRL_EN, + }; + + priv->wol = wol_cfg; + + return 0; +} + +static int jl2xxx_c_macro_intr_cfg_get(struct phy_device *phydev) +{ + struct jl2xxx_priv *priv = phydev->priv; + + struct jl_intr_ctrl intr_cfg = { + .enable = JL2XXX_INTR_CTRL_EN, + }; + + priv->intr = intr_cfg; + + return 0; +} + +static int jl2xxx_c_macro_downshift_cfg_get(struct phy_device *phydev) +{ + struct jl2xxx_priv *priv = phydev->priv; + + struct jl_downshift_ctrl downshift_cfg = { + .enable = JL2XXX_DSFT_CTRL_EN, + .count = JL2XXX_DSFT_AN_CNT, + }; + + priv->downshift = downshift_cfg; + + return 0; +} + +static int jl2xxx_c_macro_rgmii_cfg_get(struct phy_device *phydev) +{ + struct jl2xxx_priv *priv = phydev->priv; + + struct jl_rgmii_ctrl rgmii_cfg = { + .enable = JL2XXX_RGMII_CTRL_EN, + .rx_delay = JL2XXX_RGMII_RX_DLY_2NS, + .tx_delay = JL2XXX_RGMII_TX_DLY_2NS, + }; + + priv->rgmii = rgmii_cfg; + + return 0; +} + +static int jl2xxx_c_macro_patch_cfg_get(struct phy_device *phydev) +{ + struct jl2xxx_priv *priv = phydev->priv; + + struct jl_patch_ctrl patch_cfg = { + .enable = JL2XXX_PATCH_CTRL_EN, + }; + + priv->patch = patch_cfg; + + return 0; +} + +static int jl2xxx_c_macro_clk_cfg_get(struct phy_device *phydev) +{ + struct jl2xxx_priv *priv = phydev->priv; + + struct jl_clk_ctrl clk_cfg = { + .enable = JL2XXX_CLK_CTRL_EN, + }; + + priv->clk = clk_cfg; + + return 0; +} + +static int jl2xxx_c_macro_work_mode_cfg_get(struct phy_device *phydev) +{ + struct jl2xxx_priv *priv = phydev->priv; + + struct jl_work_mode_ctrl work_mode_cfg = { + .enable = JL2XXX_WORK_MODE_CTRL_EN, + .mode = JL2XXX_WORK_MODE_MODE, + }; + + priv->work_mode = work_mode_cfg; + + return 0; +} + +static int jl2xxx_c_macro_lpbk_cfg_get(struct phy_device *phydev) +{ + struct jl2xxx_priv *priv = phydev->priv; + + struct jl_loopback_ctrl lpbk_cfg = { + .enable = JL2XXX_LPBK_CTRL_EN, + .mode = JL2XXX_LPBK_MODE, + }; + + priv->lpbk = lpbk_cfg; + + return 0; +} + +static int jl2xxx_c_macro_slew_rate_cfg_get(struct phy_device *phydev) +{ + struct jl2xxx_priv *priv = phydev->priv; + + struct jl_slew_rate_ctrl slew_rate_cfg = { + .enable = JL2XXX_SLEW_RATE_CTRL_EN, + }; + + priv->slew_rate = slew_rate_cfg; + + return 0; +} + +static int jl2xxx_c_macro_rxc_out_cfg_get(struct phy_device *phydev) +{ + struct jl2xxx_priv *priv = phydev->priv; + + struct jl_rxc_out_ctrl rxc_out_cfg = { + .enable = JL2XXX_RXC_OUT_CTRL_EN, + }; + + priv->rxc_out = rxc_out_cfg; + + return 0; +} + +static int jl2xxx_fld_operation_args(struct phy_device *phydev) +{ + struct jl2xxx_priv *priv = phydev->priv; + struct jl_fld_ctrl *fld = &priv->fld; + + if (JLSEMI_KERNEL_DEVICE_TREE_USE) + jl2xxx_dts_fld_cfg_get(phydev); + else + jl2xxx_c_macro_fld_cfg_get(phydev); + + /* Supported by default */ + fld->ethtool = false; + + return 0; +} + +static int jl2xxx_wol_operation_args(struct phy_device *phydev) +{ + struct jl2xxx_priv *priv = phydev->priv; + struct jl_wol_ctrl *wol = &priv->wol; + + if (JLSEMI_KERNEL_DEVICE_TREE_USE) + jl2xxx_dts_wol_cfg_get(phydev); + else + jl2xxx_c_macro_wol_cfg_get(phydev); + + /* Supported by default */ + wol->ethtool = false; + + return 0; +} + +static int jl2xxx_intr_operation_args(struct phy_device *phydev) +{ + struct jl2xxx_priv *priv = phydev->priv; + struct jl_intr_ctrl *intr = &priv->intr; + + if (JLSEMI_KERNEL_DEVICE_TREE_USE) + jl2xxx_dts_intr_cfg_get(phydev); + else + jl2xxx_c_macro_intr_cfg_get(phydev); + + /* Not supported by default */ + intr->ethtool = false; + + return 0; +} + +static int jl2xxx_downshift_operation_args(struct phy_device *phydev) +{ + struct jl2xxx_priv *priv = phydev->priv; + struct jl_downshift_ctrl *downshift = &priv->downshift; + + if (JLSEMI_KERNEL_DEVICE_TREE_USE) + jl2xxx_dts_downshift_cfg_get(phydev); + else + jl2xxx_c_macro_downshift_cfg_get(phydev); + + /* Supported by default */ + downshift->ethtool = false; + + return 0; +} + +static int jl2xxx_rgmii_operation_args(struct phy_device *phydev) +{ + struct jl2xxx_priv *priv = phydev->priv; + struct jl_rgmii_ctrl *rgmii = &priv->rgmii; + + if (JLSEMI_KERNEL_DEVICE_TREE_USE) + jl2xxx_dts_rgmii_cfg_get(phydev); + else + jl2xxx_c_macro_rgmii_cfg_get(phydev); + + /* Not supported by default */ + rgmii->ethtool = false; + + return 0; +} + +static int jl2xxx_patch_operation_args(struct phy_device *phydev) +{ + struct jl2xxx_priv *priv = phydev->priv; + struct jl_patch_ctrl *patch = &priv->patch; + + if (JLSEMI_KERNEL_DEVICE_TREE_USE) + jl2xxx_dts_patch_cfg_get(phydev); + else + jl2xxx_c_macro_patch_cfg_get(phydev); + + /* Not supported by default */ + patch->ethtool = false; + + return 0; +} + +static int jl2xxx_clk_operation_args(struct phy_device *phydev) +{ + struct jl2xxx_priv *priv = phydev->priv; + struct jl_clk_ctrl *clk = &priv->clk; + + if (JLSEMI_KERNEL_DEVICE_TREE_USE) + jl2xxx_dts_clk_cfg_get(phydev); + else + jl2xxx_c_macro_clk_cfg_get(phydev); + + /* Not supported by default */ + clk->ethtool = false; + + return 0; +} + +static int jl2xxx_work_mode_operation_args(struct phy_device *phydev) +{ + struct jl2xxx_priv *priv = phydev->priv; + struct jl_work_mode_ctrl *work_mode = &priv->work_mode; + + if (JLSEMI_KERNEL_DEVICE_TREE_USE) + jl2xxx_dts_work_mode_cfg_get(phydev); + else + jl2xxx_c_macro_work_mode_cfg_get(phydev); + + /* Not supported by default */ + work_mode->ethtool = false; + + return 0; +} + +static int jl2xxx_lpbk_operation_args(struct phy_device *phydev) +{ + struct jl2xxx_priv *priv = phydev->priv; + struct jl_loopback_ctrl *lpbk = &priv->lpbk; + + if (JLSEMI_KERNEL_DEVICE_TREE_USE) + jl2xxx_dts_lpbk_cfg_get(phydev); + else + jl2xxx_c_macro_lpbk_cfg_get(phydev); + + /* Not supported by default */ + lpbk->ethtool = false; + + return 0; +} + +static int jl2xxx_slew_rate_operation_args(struct phy_device *phydev) +{ + struct jl2xxx_priv *priv = phydev->priv; + struct jl_slew_rate_ctrl *slew_rate = &priv->slew_rate; + + if (JLSEMI_KERNEL_DEVICE_TREE_USE) + jl2xxx_dts_slew_rate_cfg_get(phydev); + else + jl2xxx_c_macro_slew_rate_cfg_get(phydev); + + /* Not supported by default */ + slew_rate->ethtool = false; + + return 0; +} + +static int jl2xxx_rxc_out_operation_args(struct phy_device *phydev) +{ + struct jl2xxx_priv *priv = phydev->priv; + struct jl_rxc_out_ctrl *rxc_out = &priv->rxc_out; + + if (JLSEMI_KERNEL_DEVICE_TREE_USE) + jl2xxx_dts_rxc_out_cfg_get(phydev); + else + jl2xxx_c_macro_rxc_out_cfg_get(phydev); + + /* Not supported by default */ + rxc_out->ethtool = false; + + return 0; +} + +static int jl2xxx_fld_static_op_set(struct phy_device *phydev) +{ + struct jl2xxx_priv *priv = phydev->priv; + int err; + u8 val; + + val = priv->fld.delay & 0xff; + err = jl2xxx_fld_dynamic_op_set(phydev, &val); + if (err < 0) + return err; + + return 0; +} + +static int jl1xxx_wol_cfg_rmii(struct phy_device *phydev) +{ + int err; + /* WOL Function should be in RMII Mode, the rmii + * clock direction should be output + */ + err = jlsemi_modify_paged_reg(phydev, JL1XXX_PAGE7, + JL1XXX_RMII_CTRL_REG, + JL1XXX_RMII_OUT, + JL1XXX_RMII_MODE); + if (err < 0) + return err; + + return 0; +} + +static int jl1xxx_wol_clear(struct phy_device *phydev) +{ + jlsemi_set_bits(phydev, JL1XXX_PAGE129, + JL1XXX_WOL_CTRL_REG, JL1XXX_WOL_CLEAR); + + jlsemi_clear_bits(phydev, JL1XXX_PAGE129, + JL1XXX_WOL_CTRL_REG, JL1XXX_WOL_CLEAR); + + return 0; +} + +static bool jl1xxx_wol_receive_check(struct phy_device *phydev) +{ + if (jlsemi_fetch_bit(phydev, JL1XXX_PAGE129, + JL1XXX_WOL_CTRL_REG, JL1xxx_WOL_RECEIVE)) + return true; + else + return false; + +} + +static int jl1xxx_wol_enable(struct phy_device *phydev, bool enable) +{ + if (enable) + jlsemi_clear_bits(phydev, JL1XXX_PAGE129, + JL1XXX_WOL_CTRL_REG, JL1XXX_WOL_DIS); + else + jlsemi_set_bits(phydev, JL1XXX_PAGE129, + JL1XXX_WOL_CTRL_REG, JL1XXX_WOL_DIS); + + return 0; +} +static int jl1xxx_wol_store_mac_addr(struct phy_device *phydev) +{ + int err; + + jlsemi_write_page(phydev, JL1XXX_PAGE129); + + /* Store the device address for the magic packet */ + err = phy_write(phydev, JL1XXX_MAC_ADDR2_REG, + ((ADDR8_HIGH_TO_LOW( + phydev->attached_dev->dev_addr[0]) << 8) | + ADDR8_HIGH_TO_LOW( + phydev->attached_dev->dev_addr[1]))); + if (err < 0) + return err; + err = phy_write(phydev, JL1XXX_MAC_ADDR1_REG, + ((ADDR8_HIGH_TO_LOW( + phydev->attached_dev->dev_addr[2]) << 8) | + ADDR8_HIGH_TO_LOW( + phydev->attached_dev->dev_addr[3]))); + if (err < 0) + return err; + err = phy_write(phydev, JL1XXX_MAC_ADDR0_REG, + ((ADDR8_HIGH_TO_LOW( + phydev->attached_dev->dev_addr[4]) << 8) | + ADDR8_HIGH_TO_LOW( + phydev->attached_dev->dev_addr[5]))); + if (err < 0) + return err; + + /* change page to 0 */ + jlsemi_write_page(phydev, JL1XXX_PAGE0); + + return 0; +} + +static int jl2xxx_wol_enable(struct phy_device *phydev, bool enable) +{ + if (enable) { + jlsemi_set_bits(phydev, JL2XXX_WOL_CTRL_PAGE, + JL2XXX_WOL_CTRL_REG, JL2XXX_WOL_GLB_EN); + jlsemi_clear_bits(phydev, JL2XXX_WOL_STAS_PAGE, + JL2XXX_WOL_STAS_REG, JL2XXX_WOL_EN); + } else { + jlsemi_clear_bits(phydev, JL2XXX_WOL_CTRL_PAGE, + JL2XXX_WOL_CTRL_REG, JL2XXX_WOL_GLB_EN); + jlsemi_set_bits(phydev, JL2XXX_WOL_STAS_PAGE, + JL2XXX_WOL_STAS_REG, JL2XXX_WOL_EN); + } + jlsemi_soft_reset(phydev); + + return 0; +} + +static int jl2xxx_wol_active_low_polarity(struct phy_device *phydev, bool low) +{ + if (low) + jlsemi_set_bits(phydev, JL2XXX_WOL_STAS_PAGE, + JL2XXX_WOL_STAS_REG, JL2XXX_WOL_POLARITY); + else + jlsemi_clear_bits(phydev, JL2XXX_WOL_STAS_PAGE, + JL2XXX_WOL_STAS_REG, JL2XXX_WOL_POLARITY); + + return 0; +} + +static int jl2xxx_wol_clear(struct phy_device *phydev) +{ + jlsemi_set_bits(phydev, JL2XXX_WOL_STAS_PAGE, + JL2XXX_WOL_STAS_REG, JL2XXX_WOL_EVENT); + jlsemi_clear_bits(phydev, JL2XXX_WOL_STAS_PAGE, + JL2XXX_WOL_STAS_REG, JL2XXX_WOL_EVENT); + + return 0; +} + +static int jl2xxx_store_mac_addr(struct phy_device *phydev) +{ + int err; + + jlsemi_write_page(phydev, JL2XXX_WOL_STAS_PAGE); + + /* Store the device address for the magic packet */ + err = phy_write(phydev, JL2XXX_MAC_ADDR2_REG, + ((phydev->attached_dev->dev_addr[0] << 8) | + phydev->attached_dev->dev_addr[1])); + if (err < 0) + return err; + err = phy_write(phydev, JL2XXX_MAC_ADDR1_REG, + ((phydev->attached_dev->dev_addr[2] << 8) | + phydev->attached_dev->dev_addr[3])); + if (err < 0) + return err; + err = phy_write(phydev, JL2XXX_MAC_ADDR0_REG, + ((phydev->attached_dev->dev_addr[4] << 8) | + phydev->attached_dev->dev_addr[5])); + if (err < 0) + return err; + + /* change page to 0 */ + jlsemi_write_page(phydev, JL2XXX_PAGE0); + + return 0; +} + +/* Get fast link down for jl2xxx */ +#if (JL2XXX_PHY_TUNABLE) +int jl2xxx_fld_dynamic_op_get(struct phy_device *phydev, u8 *msecs) +{ + int ret; + u16 val; + + ret = jlsemi_read_paged(phydev, JL2XXX_PAGE128, + JL2XXX_FLD_CTRL_REG); + + if (ret < 0) + return ret; + + if (ret & JL2XXX_FLD_EN) { + *msecs = ETHTOOL_PHY_FAST_LINK_DOWN_OFF; + return 0; + } + + val = (ret & JL2XXX_FLD_MASK) >> JL2XXX_FLD_MASK_HEAD; + + switch (val) { + case JL2XXX_FLD_DELAY_00MS: + *msecs = 0; + break; + case JL2XXX_FLD_DELAY_10MS: + *msecs = 10; + break; + case JL2XXX_FLD_DELAY_20MS: + *msecs = 20; + break; + case JL2XXX_FLD_DELAY_40MS: + *msecs = 40; + break; + default: + return -EINVAL; + } + + return 0; +} +#endif +/* Set fast link down for jl2xxx */ +int jl2xxx_fld_dynamic_op_set(struct phy_device *phydev, const u8 *msecs) +{ + u16 val; + int ret; + +#if (JL2XXX_PHY_TUNABLE) + if (*msecs == ETHTOOL_PHY_FAST_LINK_DOWN_OFF) + return jlsemi_clear_bits(phydev, JL2XXX_PAGE128, + JL2XXX_FLD_CTRL_REG, + JL2XXX_FLD_EN); +#endif + if (*msecs <= 5) + val = JL2XXX_FLD_DELAY_00MS; + else if (*msecs <= 15) + val = JL2XXX_FLD_DELAY_10MS; + else if (*msecs <= 30) + val = JL2XXX_FLD_DELAY_20MS; + else + val = JL2XXX_FLD_DELAY_40MS; + + val = val << JL2XXX_FLD_MASK_HEAD; + + ret = jlsemi_modify_paged_reg(phydev, JL2XXX_PAGE128, + JL2XXX_FLD_CTRL_REG, + JL2XXX_FLD_MASK, val); + if (ret < 0) + return ret; + + ret = jlsemi_set_bits(phydev, JL2XXX_PAGE128, + JL2XXX_FLD_CTRL_REG, + JL2XXX_FLD_EN); + if (ret < 0) + return ret; + + return 0; +} + +int jl2xxx_downshift_dynamic_op_get(struct phy_device *phydev, u8 *data) +{ + int val, cnt, enable; + + val = jlsemi_read_paged(phydev, JL2XXX_PAGE0, + JL2XXX_DSFT_CTRL_REG); + + if (val < 0) + return val; + + enable = val & JL2XXX_DSFT_EN; + cnt = (val & JL2XXX_DSFT_AN_MASK) + 1; + +#if (JL2XXX_PHY_TUNABLE) + *data = enable ? cnt : DOWNSHIFT_DEV_DISABLE; +#else + *data = enable ? cnt : 0; +#endif + return 0; +} + +int jl2xxx_downshift_dynamic_op_set(struct phy_device *phydev, u8 cnt) +{ + int val, err; + + if (cnt > JL2XXX_DSFT_CNT_MAX) + return -E2BIG; + + if (!cnt) { + err = jlsemi_clear_bits(phydev, JL2XXX_PAGE0, + JL2XXX_DSFT_CTRL_REG, + JL2XXX_DSFT_EN); + } else { + val = ((cnt - 1) & JL2XXX_DSFT_AN_MASK) | JL2XXX_DSFT_EN | + JL2XXX_DSFT_SMART_EN | JL2XXX_DSFT_AN_ERR_EN | + JL2XXX_DSFT_STL_CNT(18); + err = jlsemi_modify_paged_reg(phydev, JL2XXX_PAGE0, + JL2XXX_DSFT_CTRL_REG, + JL2XXX_DSFT_AN_MASK, val); + } + + if (err < 0) + return err; + + return 0; +} + +int jl2xxx_downshift_static_op_set(struct phy_device *phydev) +{ + struct jl2xxx_priv *priv = phydev->priv; + int err; + + err = jl2xxx_downshift_dynamic_op_set(phydev, + priv->downshift.count); + if (err < 0) + return err; + + return 0; +} + +int jl2xxx_rgmii_static_op_set(struct phy_device *phydev) +{ + struct jl2xxx_priv *priv = phydev->priv; + int err; + + if (priv->rgmii.enable & JL2XXX_RGMII_TX_DLY_EN) { + err = jlsemi_set_bits(phydev, JL2XXX_PAGE3336, + JL2XXX_RGMII_CTRL_REG, + priv->rgmii.tx_delay); + if (err < 0) + return err; + + } else { + err = jlsemi_clear_bits(phydev, JL2XXX_PAGE3336, + JL2XXX_RGMII_CTRL_REG, + priv->rgmii.tx_delay); + if (err < 0) + return err; + } + + if (priv->rgmii.enable & JL2XXX_RGMII_RX_DLY_EN) { + err = jlsemi_set_bits(phydev, JL2XXX_PAGE3336, + JL2XXX_RGMII_CTRL_REG, + priv->rgmii.rx_delay); + if (err < 0) + return err; + } else { + err = jlsemi_clear_bits(phydev, JL2XXX_PAGE3336, + JL2XXX_RGMII_CTRL_REG, + priv->rgmii.rx_delay); + if (err < 0) + return err; + } + + err = jlsemi_soft_reset(phydev); + if (err < 0) + return err; + + return 0; +} + +int jl2xxx_clk_static_op_set(struct phy_device *phydev) +{ + struct jl2xxx_priv *priv = phydev->priv; + int err; + + if (priv->clk.enable & JL2XXX_125M_CLK_OUT_EN) { + err = jlsemi_modify_paged_reg(phydev, JL2XXX_PAGE2627, + JL2XXX_CLK_CTRL_REG, + JL2XXX_CLK_SSC_EN, + JL2XXX_CLK_OUT_PIN | + JL2XXX_CLK_125M_OUT | + JL2XXXX_CLK_SRC); + if (err < 0) + return err; + } else if (priv->clk.enable & JL2XXX_25M_CLK_OUT_EN) { + err = jlsemi_modify_paged_reg(phydev, JL2XXX_PAGE2627, + JL2XXX_CLK_CTRL_REG, + JL2XXX_CLK_SSC_EN | + JL2XXX_CLK_125M_OUT, + JL2XXX_CLK_OUT_PIN | + JL2XXXX_CLK_SRC); + if (err < 0) + return err; + } else if (priv->clk.enable & JL2XXX_CLK_OUT_DIS) { + err = jlsemi_clear_bits(phydev, JL2XXX_PAGE2627, + JL2XXX_CLK_CTRL_REG, + JL2XXX_CLK_OUT_PIN); + if (err < 0) + return err; + } + + err = jlsemi_soft_reset(phydev); + if (err < 0) + return err; + + return 0; +} + +int jl2xxx_slew_rate_static_op_set(struct phy_device *phydev) +{ + int err; + + err = jlsemi_set_bits(phydev, JL2XXX_PAGE258, + JL2XXX_SLEW_RATE_CTRL_REG, + JL2XXX_SLEW_RATE_EN | JL2XXX_SLEW_RATE_REF_CLK | + JL2XXX_SLEW_RATE_SEL_CLK); + if (err < 0) + return err; + + return 0; +} + +int jl2xxx_rxc_out_static_op_set(struct phy_device *phydev) +{ + int err; + + err = jlsemi_set_bits(phydev, JL2XXX_PAGE18, + JL2XXX_RXC_OUT_REG, JL2XXX_RXC_OUT); + if (err < 0) + return err; + + err = jlsemi_soft_reset(phydev); + if (err < 0) + return err; + + return 0; +} + +int jl2xxx_work_mode_static_op_set(struct phy_device *phydev) +{ + struct jl2xxx_priv *priv = phydev->priv; + int err; + + jlsemi_modify_paged_reg(phydev, JL2XXX_PAGE18, + JL2XXX_WORK_MODE_REG, + JL2XXX_WORK_MODE_MASK, + priv->work_mode.mode); + + err = jlsemi_soft_reset(phydev); + if (err < 0) + return err; + + return 0; +} + +static inline int __genphy_setup_forced(struct phy_device *phydev) +{ + int err; + int ctl = 0; + + phydev->pause = phydev->asym_pause = 0; + + if (phydev->speed == SPEED_1000) + ctl |= BMCR_SPEED1000; + else if (phydev->speed == SPEED_100) + ctl |= BMCR_SPEED100; + + if (phydev->duplex == DUPLEX_FULL) + ctl |= BMCR_FULLDPLX; + + err = phy_write(phydev, MII_BMCR, ctl); + + return err; +} + +int jl2xxx_config_aneg_fiber(struct phy_device *phydev) +{ + if (phydev->autoneg != AUTONEG_ENABLE) + return __genphy_setup_forced(phydev); + + /* Dou to fiber auto mode only support 1000M, + * we set 1000M speed to reg0 + * NOTE: Do need restart AN otherwise will link down + */ + jlsemi_modify_paged_reg(phydev, JL2XXX_PAGE0, + JL2XXX_BMCR_REG, + JL2XXX_BMCR_SPEED_LSB, + JL2XXX_BMCR_SPEED_MSB | BMCR_ANENABLE); + return 0; +} + +static int jl2xxx_fiber_autoneg_config(struct phy_device *phydev) +{ + int speed; + int duplex; + + speed = jlsemi_read_paged(phydev, JL2XXX_PAGE0, JL2XXX_PHY_MODE_REG); + if (speed < 0) + return speed; + + duplex = jlsemi_fetch_bit(phydev, JL2XXX_PAGE0, + MII_BMCR, JL2XXX_BMCR_DUPLEX); + if (duplex < 0) + return duplex; + + if (duplex) + phydev->duplex = DUPLEX_FULL; + else + phydev->duplex = DUPLEX_HALF; + + speed &= JL2XXX_PHY_FIBER_MODE_MASK; + switch (speed) { + case JL2XXX_FIBER_1000: + phydev->speed = SPEED_1000; + break; + case JL2XXX_FIBER_100: + phydev->speed = SPEED_100; + break; + default: + break; + } + + return 0; +} + +static int jl2xxx_update_fiber_status(struct phy_device *phydev) +{ + int status; + int link; + + status = jlsemi_read_paged(phydev, JL2XXX_PAGE0, JL2XXX_PHY_MODE_REG); + if (status < 0) + return status; + + link = status & JL2XXX_PHY_FIBER_MODE_MASK; + + if (link) + phydev->link = 1; + else + phydev->link = 0; + + if (phydev->autoneg == AUTONEG_ENABLE) + jl2xxx_fiber_autoneg_config(phydev); + + return 0; +} + +bool jl2xxx_read_fiber_status(struct phy_device *phydev) +{ + bool fiber_ok = false; + u16 phy_mode; + int val; + + val = jlsemi_read_paged(phydev, JL2XXX_PAGE18, JL2XXX_WORK_MODE_REG); + phy_mode = val & JL2XXX_WORK_MODE_MASK; + + if ((phydev->interface != PHY_INTERFACE_MODE_SGMII) && + ((phy_mode == JL2XXX_FIBER_RGMII_MODE) || + (phy_mode == JL2XXX_UTP_FIBER_RGMII_MODE))) { + jl2xxx_update_fiber_status(phydev); + if (phydev->link) + fiber_ok = true; + } + + return fiber_ok; +} + +static int jl2xxx_force_speed(struct phy_device *phydev, u16 speed) +{ + int err; + + if (speed == JL2XXX_SPEED1000) + jlsemi_modify_paged_reg(phydev, JL2XXX_PAGE0, MII_BMCR, + BMCR_SPEED100, BMCR_SPEED1000); + else if (speed == JL2XXX_SPEED100) + jlsemi_modify_paged_reg(phydev, JL2XXX_PAGE0, MII_BMCR, + BMCR_SPEED1000, BMCR_SPEED100); + else if (speed == JL2XXX_SPEED10) + jlsemi_clear_bits(phydev, JL2XXX_PAGE0, MII_BMCR, + BMCR_SPEED1000 | BMCR_SPEED100); + + err = jlsemi_clear_bits(phydev, JL2XXX_PAGE0, MII_BMCR, + BMCR_ANENABLE); + if (err < 0) + return err; + + return 0; +} + +static int jl2xxx_lpbk_force_speed(struct phy_device *phydev) +{ + struct jl2xxx_priv *priv = phydev->priv; + + if (priv->lpbk.mode == JL2XXX_LPBK_PCS_1000M) + jl2xxx_force_speed(phydev, JL2XXX_SPEED1000); + else if (priv->lpbk.mode == JL2XXX_LPBK_PCS_100M) + jl2xxx_force_speed(phydev, JL2XXX_SPEED100); + else if (priv->lpbk.mode == JL2XXX_LPBK_PCS_10M) + jl2xxx_force_speed(phydev, JL2XXX_SPEED10); + + return 0; +} + +int jl2xxx_lpbk_static_op_set(struct phy_device *phydev) +{ + struct jl2xxx_priv *priv = phydev->priv; + int err; + + if ((priv->lpbk.mode == JL2XXX_LPBK_PCS_10M) || + (priv->lpbk.mode == JL2XXX_LPBK_PCS_100M) || + (priv->lpbk.mode == JL2XXX_LPBK_PCS_1000M)) { + err = jlsemi_modify_paged_reg(phydev, JL2XXX_PAGE0, + MII_BMCR, BMCR_LOOPBACK, + BMCR_LOOPBACK); + if (err < 0) + return err; + err = jl2xxx_lpbk_force_speed(phydev); + if (err < 0) + return err; + } else if (priv->lpbk.mode == JL2XXX_LPBK_PMD_1000M) { + err = jlsemi_clear_bits(phydev, JL2XXX_PAGE160, + JL2XXX_REG25, JL2XXX_CPU_RESET); + if (err < 0) + return err; + + jlsemi_write_page(phydev, JL2XXX_PAGE173); + phy_write(phydev, JL2XXX_REG16, JL2XXX_LOAD_GO); + phy_write(phydev, JL2XXX_REG17, JL2XXX_LOAD_DATA0); + jlsemi_write_page(phydev, JL2XXX_PAGE0); + + err = jlsemi_set_bits(phydev, JL2XXX_PAGE160, + JL2XXX_REG25, JL2XXX_CPU_RESET); + if (err < 0) + return err; + + err = jlsemi_modify_paged_reg(phydev, JL2XXX_PAGE0, + JL2XXX_REG20, + JL2XXX_LPBK_MODE_MASK, + JL2XXX_LPBK_PMD_MODE); + if (err < 0) + return err; + + err = jlsemi_set_bits(phydev, JL2XXX_PAGE18, JL2XXX_REG21, + JL2XXX_SPEED1000_NO_AN); + if (err < 0) + return err; + + err = jlsemi_soft_reset(phydev); + if (err < 0) + return err; + + } else if (priv->lpbk.mode == JL2XXX_LPBK_EXT_STUB_1000M) { + err = jlsemi_clear_bits(phydev, JL2XXX_PAGE160, + JL2XXX_REG25, JL2XXX_CPU_RESET); + if (err < 0) + return err; + jlsemi_write_page(phydev, JL2XXX_PAGE173); + phy_write(phydev, JL2XXX_REG16, JL2XXX_LOAD_GO); + phy_write(phydev, JL2XXX_REG17, JL2XXX_LOAD_DATA0); + jlsemi_write_page(phydev, JL2XXX_PAGE0); + + err = jlsemi_set_bits(phydev, JL2XXX_PAGE160, + JL2XXX_REG25, JL2XXX_CPU_RESET); + if (err < 0) + return err; + + err = jlsemi_modify_paged_reg(phydev, JL2XXX_PAGE0, + JL2XXX_REG20, + JL2XXX_LPBK_MODE_MASK, + JL2XXX_LPBK_EXT_MODE); + if (err < 0) + return err; + + err = jlsemi_set_bits(phydev, JL2XXX_PAGE18, JL2XXX_REG21, + JL2XXX_SPEED1000_NO_AN); + if (err < 0) + return err; + + err = jlsemi_soft_reset(phydev); + if (err < 0) + return err; + } + + return 0; +} + +int jl1xxx_mdi_static_op_set(struct phy_device *phydev) +{ + struct jl1xxx_priv *priv = phydev->priv; + int err; + + if (priv->mdi.enable & JL1XXX_MDI_RATE_EN) { + err = jlsemi_set_bits(phydev, JL1XXX_PAGE24, + JL1XXX_REG24, priv->mdi.rate); + if (err < 0) + return err; + } + + if (priv->mdi.enable & JL1XXX_MDI_AMPLITUDE_EN) { + err = jlsemi_modify_paged_reg(phydev, JL1XXX_PAGE24, + JL1XXX_REG24, + JL1XXX_MDI_TX_BM_MASK, + JL1XXX_MDI_TX_BM( + priv->mdi.amplitude)); + if (err < 0) + return err; + } + + return 0; +} + +int jl1xxx_rmii_static_op_set(struct phy_device *phydev) +{ + struct jl1xxx_priv *priv = phydev->priv; + int err; + + if (priv->rmii.enable & JL1XXX_RMII_MODE_EN) { + err = jlsemi_set_bits(phydev, JL1XXX_PAGE7, + JL1XXX_REG16, JL1XXX_RMII_MODE); + if (err < 0) + return err; + } else { + err = jlsemi_clear_bits(phydev, JL1XXX_PAGE7, + JL1XXX_REG16, JL1XXX_RMII_MODE); + if (err < 0) + return err; + return 0; + } + + if (priv->rmii.enable & JL1XXX_RMII_CLK_50M_INPUT_EN) { + err = jlsemi_set_bits(phydev, JL1XXX_PAGE7, + JL1XXX_REG16, + JL1XXX_RMII_CLK_50M_INPUT); + if (err < 0) + return err; + } else { + err = jlsemi_clear_bits(phydev, JL1XXX_PAGE7, + JL1XXX_REG16, + JL1XXX_RMII_CLK_50M_INPUT); + if (err < 0) + return err; + } + + if (priv->rmii.enable & JL1XXX_RMII_CRS_DV_EN) { + err = jlsemi_set_bits(phydev, JL1XXX_PAGE7, + JL1XXX_REG16, + JL1XXX_RMII_CRS_DV); + if (err < 0) + return err; + } else { + err = jlsemi_clear_bits(phydev, JL1XXX_PAGE7, + JL1XXX_REG16, + JL1XXX_RMII_CRS_DV); + if (err < 0) + return err; + } + + if (priv->rmii.enable & JL1XXX_RMII_TX_SKEW_EN) { + err = jlsemi_modify_paged_reg(phydev, JL1XXX_PAGE7, + JL1XXX_REG16, + JL1XXX_RMII_TX_SKEW_MASK, + JL1XXX_RMII_TX_SKEW( + priv->rmii.tx_timing)); + if (err < 0) + return err; + } + + if (priv->rmii.enable & JL1XXX_RMII_RX_SKEW_EN) { + err = jlsemi_modify_paged_reg(phydev, JL1XXX_PAGE7, + JL1XXX_REG16, + JL1XXX_RMII_RX_SKEW_MASK, + JL1XXX_RMII_RX_SKEW( + priv->rmii.rx_timing)); + if (err < 0) + return err; + } + + return 0; +} + +static u16 patch_fw_versions0[] = {0x9101, 0x9107}; +static u16 patch_fw_versions1[] = {0x1101}; +static u16 patch_fw_versions2[] = {0x930a}; + +static u16 patch_version0 = 0xdef2; +static u32 init_data0[] = { + 0x1f00a0, 0x1903f3, 0x1f0012, 0x150100, 0x1f00ad, 0x100000, + 0x11e0c6, 0x1f00a0, 0x1903fb, 0x1903fb, 0x1903fb, 0x1903fb, + 0x1903fb, 0x1903fb, 0x1903fb, 0x1903fb, 0x1f00ad, 0x110000, + 0x120400, 0x130093, 0x140000, 0x150193, 0x160000, 0x170213, + 0x180000, 0x12040c, 0x130293, 0x140000, 0x150313, 0x160000, + 0x170393, 0x180000, 0x120418, 0x130413, 0x140000, 0x150493, + 0x160000, 0x170513, 0x180000, 0x120424, 0x130593, 0x140000, + 0x150613, 0x160000, 0x170693, 0x180000, 0x120430, 0x130713, + 0x140000, 0x150793, 0x160000, 0x171137, 0x180000, 0x12043c, + 0x13006f, 0x140060, 0x15a001, 0x160113, 0x17fd41, 0x18d026, + 0x120448, 0x13d406, 0x14d222, 0x1517b7, 0x160800, 0x17aa23, + 0x189407, 0x120454, 0x130713, 0x1430f0, 0x1567b7, 0x160800, + 0x17a423, 0x1846e7, 0x120460, 0x13a703, 0x14a587, 0x156685, + 0x168f55, 0x17ac23, 0x18a4e7, 0x12046c, 0x1367b9, 0x145737, + 0x150800, 0x168793, 0x17ef27, 0x182023, 0x120478, 0x1374f7, + 0x1407b7, 0x150800, 0x165bfc, 0x17d493, 0x180037, 0x120484, + 0x13f493, 0x141f04, 0x15f793, 0x1607f7, 0x178fc5, 0x18c03e, + 0x120490, 0x134702, 0x140793, 0x150210, 0x160763, 0x1700f7, + 0x180793, 0x12049c, 0x130270, 0x140c63, 0x1530f7, 0x16a001, + 0x1707b7, 0x180002, 0x1204a8, 0x138793, 0x146967, 0x15c83e, + 0x1617b7, 0x170002, 0x188793, 0x1204b4, 0x13e567, 0x14c43e, + 0x1537b7, 0x160002, 0x178793, 0x186867, 0x1204c0, 0x13c23e, + 0x1447b7, 0x150002, 0x168793, 0x17e9a7, 0x1866b7, 0x1204cc, + 0x130800, 0x14ca3e, 0x15a783, 0x166d86, 0x1775c1, 0x188713, + 0x1204d8, 0x130ff5, 0x148ff9, 0x156735, 0x160713, 0x178007, + 0x188fd9, 0x1204e4, 0x13ac23, 0x146cf6, 0x15a783, 0x1665c6, + 0x175737, 0x180800, 0x1204f0, 0x136611, 0x14f793, 0x15f0f7, + 0x16e793, 0x170807, 0x18ae23, 0x1204fc, 0x1364f6, 0x142783, + 0x155c47, 0x169bf5, 0x172223, 0x185cf7, 0x120508, 0x13a703, + 0x14f5c6, 0x158f51, 0x16ae23, 0x17f4e6, 0x180737, 0x120514, + 0x130809, 0x14433c, 0x158fd1, 0x16c33c, 0x170637, 0x180800, + 0x120520, 0x134a74, 0x14679d, 0x158793, 0x160e07, 0x179ae1, + 0x18e693, 0x12052c, 0x130036, 0x14ca74, 0x154678, 0x1676e1, + 0x178693, 0x185006, 0x120538, 0x138ff9, 0x148fd5, 0x1507c2, + 0x168f6d, 0x1783c1, 0x188fd9, 0x120544, 0x13c67c, 0x140713, + 0x151000, 0x160793, 0x170000, 0x189c23, 0x120550, 0x1324e7, + 0x140713, 0x151010, 0x169123, 0x1726e7, 0x18470d, 0x12055c, + 0x13c63a, 0x144702, 0x158d23, 0x162407, 0x17a223, 0x182607, + 0x120568, 0x130793, 0x140270, 0x150413, 0x160000, 0x171463, + 0x1800f7, 0x120574, 0x134789, 0x14c63e, 0x154709, 0x16cc3a, + 0x174702, 0x180793, 0x120580, 0x130270, 0x141463, 0x1500f7, + 0x16478d, 0x17cc3e, 0x180513, 0x12058c, 0x130000, 0x144792, + 0x154581, 0x164485, 0x179782, 0x184018, 0x120598, 0x131775, + 0x14e563, 0x1502e4, 0x162703, 0x170a04, 0x181163, 0x1205a4, + 0x130297, 0x144818, 0x150563, 0x160097, 0x1747a2, 0x18c804, + 0x1205b0, 0x139782, 0x1466b7, 0x150800, 0x16a703, 0x174c46, + 0x189b71, 0x1205bc, 0x136713, 0x140027, 0x15a223, 0x164ce6, + 0x174783, 0x180fd4, 0x1205c8, 0x13c7b9, 0x142683, 0x151004, + 0x164745, 0x179763, 0x1820e6, 0x1205d4, 0x133737, 0x140822, + 0x152683, 0x163007, 0x177645, 0x18167d, 0x1205e0, 0x138ef1, + 0x142023, 0x1530d7, 0x162683, 0x172807, 0x18e693, 0x1205ec, + 0x131006, 0x142023, 0x1528d7, 0x162683, 0x173807, 0x18e693, + 0x1205f8, 0x131006, 0x142023, 0x1538d7, 0x162683, 0x174007, + 0x18e693, 0x120604, 0x131006, 0x142023, 0x1540d7, 0x162683, + 0x174807, 0x18e693, 0x120610, 0x131006, 0x142023, 0x1548d7, + 0x1656b7, 0x170800, 0x18a703, 0x12061c, 0x133486, 0x14830d, + 0x158b05, 0x16cf01, 0x17a703, 0x185c46, 0x120628, 0x137671, + 0x14167d, 0x158f71, 0x166611, 0x17a223, 0x185ce6, 0x120634, + 0x138f51, 0x14a223, 0x155ce6, 0x162703, 0x171084, 0x1846b2, + 0x120640, 0x131c63, 0x1402d7, 0x153737, 0x160822, 0x172683, + 0x182807, 0x12064c, 0x13e693, 0x140016, 0x152023, 0x1628d7, + 0x172683, 0x183807, 0x120658, 0x13e693, 0x140016, 0x152023, + 0x1638d7, 0x172683, 0x184007, 0x120664, 0x13e693, 0x140016, + 0x152023, 0x1640d7, 0x172683, 0x184807, 0x120670, 0x13e693, + 0x140016, 0x152023, 0x1648d7, 0x172703, 0x181004, 0x12067c, + 0x1346b2, 0x149c63, 0x151ae6, 0x160737, 0x170800, 0x184b78, + 0x120688, 0x130693, 0x140ff0, 0x15463d, 0x168b1d, 0x17ce3a, + 0x1852b7, 0x120694, 0x130800, 0x144701, 0x154389, 0x16408d, + 0x174311, 0x180537, 0x1206a0, 0x130820, 0x141593, 0x150077, + 0x1695aa, 0x17418c, 0x184572, 0x1206ac, 0x1305c2, 0x1481c1, + 0x1581a9, 0x167763, 0x1700b5, 0x189533, 0x1206b8, 0x1300e4, + 0x144513, 0x15fff5, 0x168e69, 0x170537, 0x180800, 0x1206c4, + 0x134568, 0x148121, 0x15893d, 0x167463, 0x1702b5, 0x18a583, + 0x1206d0, 0x1306c2, 0x140763, 0x151277, 0x160a63, 0x171217, + 0x1805c2, 0x1206dc, 0x1381c1, 0x14818d, 0x150d63, 0x161097, + 0x178985, 0x180586, 0x1206e8, 0x1395b3, 0x1400b4, 0x15c593, + 0x16fff5, 0x178eed, 0x180705, 0x1206f4, 0x1315e3, 0x14fa67, + 0x1535b7, 0x160822, 0x17a703, 0x183005, 0x120700, 0x13757d, + 0x148a3d, 0x150513, 0x160ff5, 0x178f69, 0x180622, 0x12070c, + 0x138e59, 0x14a023, 0x1530c5, 0x168637, 0x170800, 0x185a38, + 0x120718, 0x1375c1, 0x14f693, 0x150ff6, 0x168593, 0x170ff5, + 0x188f6d, 0x120724, 0x1306a2, 0x148ed9, 0x15da34, 0x164682, + 0x170713, 0x180210, 0x120730, 0x139163, 0x140ee6, 0x154711, + 0x16e391, 0x17471d, 0x182023, 0x12073c, 0x1310e4, 0x142683, + 0x150a04, 0x16471d, 0x179e63, 0x1800e6, 0x120748, 0x136737, + 0x140800, 0x152703, 0x164cc7, 0x170693, 0x184000, 0x120754, + 0x137713, 0x144807, 0x151463, 0x1600d7, 0x172223, 0x180e04, + 0x120760, 0x134018, 0x141163, 0x150497, 0x165703, 0x1700c4, + 0x181793, 0x12076c, 0x130117, 0x14db63, 0x150207, 0x168737, + 0x170800, 0x184778, 0x120778, 0x137713, 0x140807, 0x15e705, + 0x160513, 0x170000, 0x184792, 0x120784, 0x134581, 0x149782, + 0x1547a2, 0x164711, 0x17c818, 0x18c004, 0x120790, 0x130d23, + 0x140094, 0x150ca3, 0x160004, 0x179782, 0x1856b7, 0x12079c, + 0x130800, 0x1442b8, 0x159b71, 0x16c2b8, 0x170513, 0x180000, + 0x1207a8, 0x1347d2, 0x149782, 0x154703, 0x162684, 0x1703e3, + 0x18de07, 0x1207b4, 0x13bbd9, 0x1407b7, 0x150002, 0x168793, + 0x1765c7, 0x18c83e, 0x1207c0, 0x1327b7, 0x140002, 0x158793, + 0x16dae7, 0x17c43e, 0x1847b7, 0x1207cc, 0x130002, 0x148793, + 0x151427, 0x16c23e, 0x1757b7, 0x180002, 0x1207d8, 0x138793, + 0x149867, 0x15b1fd, 0x162683, 0x171504, 0x184709, 0x1207e4, + 0x1399e3, 0x14e2e6, 0x1536b7, 0x160822, 0x17a703, 0x183006, + 0x1207f0, 0x13663d, 0x148f51, 0x15a023, 0x1630e6, 0x17bd39, + 0x18c593, 0x1207fc, 0x130015, 0x14b5dd, 0x158991, 0x1635b3, + 0x1700b0, 0x180589, 0x120808, 0x13bdf9, 0x148991, 0x15b593, + 0x160015, 0x17bfdd, 0x180737, 0x120814, 0x130800, 0x144f28, + 0x15cf89, 0x1647c2, 0x17893d, 0x189782, 0x120820, 0x1347e2, + 0x140713, 0x151000, 0x162223, 0x1710e4, 0x182423, 0x12082c, + 0x1310f4, 0x14474d, 0x15b729, 0x168111, 0x17b7dd, 0x1814e3, + 0x120838, 0x13f097, 0x140737, 0x150800, 0x164770, 0x171713, + 0x180106, 0x120844, 0x135d63, 0x140607, 0x1585b7, 0x160800, + 0x17a683, 0x180d05, 0x120850, 0x1372c5, 0x147313, 0x1500f6, + 0x1612fd, 0x17a703, 0x180d45, 0x12085c, 0x131513, 0x1400c3, + 0x15f6b3, 0x160056, 0x178ec9, 0x18757d, 0x120868, 0x130393, + 0x140ff5, 0x151293, 0x160083, 0x17f6b3, 0x180076, 0x120874, + 0x139b41, 0x148211, 0x15e2b3, 0x160056, 0x171093, 0x180043, + 0x120880, 0x137693, 0x140016, 0x156333, 0x160067, 0x170613, + 0x187ff5, 0x12088c, 0x139713, 0x1400b6, 0x157633, 0x1600c3, + 0x178e59, 0x189513, 0x120898, 0x1300a6, 0x147613, 0x159ff6, + 0x169713, 0x170096, 0x188e49, 0x1208a4, 0x13f293, 0x14f0f2, + 0x158e59, 0x16e2b3, 0x170012, 0x1806a2, 0x1208b0, 0x137613, + 0x14eff6, 0x158e55, 0x16a823, 0x170c55, 0x18aa23, 0x1208bc, + 0x130cc5, 0x1480e3, 0x15e807, 0x1646b7, 0x170822, 0x18a703, + 0x1208c8, 0x13f006, 0x149b61, 0x156713, 0x160027, 0x17a023, + 0x18f0e6, 0x1208d4, 0x13b5ad, 0x140000, 0x150000, 0x160000, + 0x170000, 0x180000, 0x110000, 0x120400, 0x104000, 0x1f0000, +}; + +static u16 patch_version1 = 0x9f73; +static u32 init_data1[] = { + 0x1f00a0, 0x1903f3, 0x1f0012, 0x150100, 0x1f00ad, 0x100000, + 0x11e0c6, 0x1f00a0, 0x1903fb, 0x1903fb, 0x1903fb, 0x1903fb, + 0x1903fb, 0x1903fb, 0x1903fb, 0x1903fb, 0x1f00ad, 0x110000, + 0x120400, 0x130093, 0x140000, 0x150193, 0x160000, 0x170213, + 0x180000, 0x12040c, 0x130293, 0x140000, 0x150313, 0x160000, + 0x170393, 0x180000, 0x120418, 0x130413, 0x140000, 0x150493, + 0x160000, 0x170513, 0x180000, 0x120424, 0x130593, 0x140000, + 0x150613, 0x160000, 0x170693, 0x180000, 0x120430, 0x130713, + 0x140000, 0x150793, 0x160000, 0x171137, 0x180000, 0x12043c, + 0x13006f, 0x140060, 0x15a001, 0x161111, 0x17cc06, 0x18ca22, + 0x120448, 0x13c826, 0x1417b7, 0x150800, 0x16aa23, 0x179407, + 0x180713, 0x120454, 0x1330f0, 0x1467b7, 0x150800, 0x16a423, + 0x1746e7, 0x18a703, 0x120460, 0x13a587, 0x146685, 0x158f55, + 0x16ac23, 0x17a4e7, 0x1867a9, 0x12046c, 0x135737, 0x140800, + 0x158793, 0x16f737, 0x172023, 0x1874f7, 0x120478, 0x1307b7, + 0x140800, 0x155bf8, 0x165793, 0x170037, 0x18f793, 0x120484, + 0x131f07, 0x147713, 0x1507f7, 0x168fd9, 0x170713, 0x180210, + 0x120490, 0x138763, 0x1400e7, 0x150713, 0x160270, 0x178263, + 0x181ce7, 0x12049c, 0x13a001, 0x141437, 0x150002, 0x160793, + 0x17e564, 0x18c43e, 0x1204a8, 0x1337b7, 0x140002, 0x158793, + 0x166867, 0x17c23e, 0x1847b7, 0x1204b4, 0x130002, 0x148793, + 0x15e9a7, 0x16c63e, 0x1767b7, 0x180800, 0x1204c0, 0x13a703, + 0x146d87, 0x1576c1, 0x168693, 0x170ff6, 0x188f75, 0x1204cc, + 0x1366b5, 0x148693, 0x158006, 0x168f55, 0x17ac23, 0x186ce7, + 0x1204d8, 0x13a703, 0x1465c7, 0x1556b7, 0x160800, 0x177713, + 0x18f0f7, 0x1204e4, 0x136713, 0x140807, 0x15ae23, 0x1664e7, + 0x17a703, 0x185c46, 0x1204f0, 0x130413, 0x140000, 0x159b75, + 0x16a223, 0x175ce6, 0x18a703, 0x1204fc, 0x13f5c7, 0x146691, + 0x158f55, 0x16ae23, 0x17f4e7, 0x180737, 0x120508, 0x130809, + 0x14433c, 0x158fd5, 0x16c33c, 0x170793, 0x180000, 0x120514, + 0x130713, 0x141000, 0x159c23, 0x1624e7, 0x170713, 0x181010, + 0x120520, 0x138d23, 0x142407, 0x159123, 0x1626e7, 0x17a223, + 0x182607, 0x12052c, 0x13c026, 0x144782, 0x154581, 0x164485, + 0x170513, 0x180000, 0x120538, 0x134792, 0x149782, 0x154018, + 0x161775, 0x17e563, 0x1802e4, 0x120544, 0x132703, 0x140a04, + 0x151163, 0x160297, 0x174818, 0x180563, 0x120550, 0x130097, + 0x1447a2, 0x15c804, 0x169782, 0x176637, 0x180800, 0x12055c, + 0x132703, 0x144c46, 0x159b71, 0x166713, 0x170027, 0x182223, + 0x120568, 0x134ce6, 0x144703, 0x150fd4, 0x16c739, 0x172603, + 0x181004, 0x120574, 0x134745, 0x141263, 0x1510e6, 0x163737, + 0x170822, 0x182603, 0x120580, 0x133007, 0x1475c5, 0x1515fd, + 0x168e6d, 0x172023, 0x1830c7, 0x12058c, 0x132603, 0x142807, + 0x156613, 0x161006, 0x172023, 0x1828c7, 0x120598, 0x132603, + 0x143807, 0x156613, 0x161006, 0x172023, 0x1838c7, 0x1205a4, + 0x132603, 0x144007, 0x156613, 0x161006, 0x172023, 0x1840c7, + 0x1205b0, 0x132603, 0x144807, 0x156613, 0x161006, 0x172023, + 0x1848c7, 0x1205bc, 0x135637, 0x140800, 0x152703, 0x163486, + 0x17830d, 0x188b05, 0x1205c8, 0x13cf01, 0x142703, 0x155c46, + 0x1675f1, 0x1715fd, 0x188f6d, 0x1205d4, 0x136591, 0x142223, + 0x155ce6, 0x168f4d, 0x172223, 0x185ce6, 0x1205e0, 0x132603, + 0x140a04, 0x15471d, 0x161e63, 0x1700e6, 0x186737, 0x1205ec, + 0x130800, 0x142703, 0x154cc7, 0x160613, 0x174000, 0x187713, + 0x1205f8, 0x134807, 0x141463, 0x1500c7, 0x162223, 0x170e04, + 0x184018, 0x120604, 0x131263, 0x140497, 0x155703, 0x1600c4, + 0x171793, 0x180117, 0x120610, 0x13dc63, 0x140207, 0x158737, + 0x160800, 0x174778, 0x187713, 0x12061c, 0x130807, 0x14e70d, + 0x154782, 0x164581, 0x170513, 0x180000, 0x120628, 0x134792, + 0x149782, 0x1547a2, 0x164711, 0x17c818, 0x18c004, 0x120634, + 0x130d23, 0x140094, 0x150ca3, 0x160004, 0x179782, 0x185637, + 0x120640, 0x130800, 0x144238, 0x159b71, 0x16c238, 0x174782, + 0x180513, 0x12064c, 0x130000, 0x1447b2, 0x159782, 0x164703, + 0x172684, 0x1803e3, 0x120658, 0x13ee07, 0x14bdd1, 0x152437, + 0x160002, 0x170793, 0x18dae4, 0x120664, 0x13c43e, 0x1447b7, + 0x150002, 0x168793, 0x171427, 0x18c23e, 0x120670, 0x1357b7, + 0x140002, 0x158793, 0x169867, 0x17b589, 0x182603, 0x12067c, + 0x131504, 0x144709, 0x151ee3, 0x16f2e6, 0x173637, 0x180822, + 0x120688, 0x132703, 0x143006, 0x1565bd, 0x168f4d, 0x172023, + 0x1830e6, 0x120694, 0x13b725, 0x140000, 0x150000, 0x160000, + 0x170000, 0x180000, 0x110000, 0x120400, 0x104000, 0x1f0000, +}; + +static u16 patch_version2 = 0x2e9c; +static u32 init_data2[] = { + 0x1f00a0, 0x1903f3, 0x1f0012, 0x150100, 0x1f00ad, 0x100000, + 0x11e0c6, 0x1f0102, 0x199000, 0x1f00a0, 0x1903fb, 0x1903fb, + 0x1903fb, 0x1903fb, 0x1903fb, 0x1903fb, 0x1903fb, 0x1903fb, + 0x1f00ad, 0x110000, 0x121000, 0x13937c, 0x140120, 0x15675e, + 0x16fca8, 0x1706b7, 0x180800, 0x12100c, 0x135af8, 0x145793, + 0x150037, 0x16f793, 0x171f07, 0x187713, 0x121018, 0x1307f7, + 0x148fd9, 0x150713, 0x1606a0, 0x179b63, 0x1808e7, 0x121024, + 0x13cd19, 0x141121, 0x15c822, 0x16ca06, 0x17c626, 0x184789, + 0x121030, 0x13842e, 0x140963, 0x152cf5, 0x1640d2, 0x174442, + 0x1844b2, 0x12103c, 0x134501, 0x140161, 0x158082, 0x1617b7, + 0x170800, 0x18aa23, 0x121048, 0x139407, 0x1467b7, 0x150800, + 0x16a703, 0x17a587, 0x186605, 0x121054, 0x138f51, 0x14ac23, + 0x15a4e7, 0x16670d, 0x170713, 0x18e9c7, 0x121060, 0x135637, + 0x140800, 0x152023, 0x1674e6, 0x174ab8, 0x186713, 0x12106c, + 0x130407, 0x14cab8, 0x15a703, 0x164d47, 0x1776fd, 0x188693, + 0x121078, 0x1303f6, 0x148f75, 0x156713, 0x162807, 0x17aa23, + 0x184ce7, 0x121084, 0x13a703, 0x147587, 0x157713, 0x16e1f7, + 0x176713, 0x180607, 0x121090, 0x13ac23, 0x1474e7, 0x15a703, + 0x164f47, 0x177713, 0x18f0f7, 0x12109c, 0x136713, 0x140107, + 0x15aa23, 0x164ee7, 0x17a703, 0x18fc07, 0x1210a8, 0x139b5d, + 0x14a023, 0x15fce7, 0x160713, 0x170300, 0x18a223, 0x1210b4, + 0x13a6e7, 0x144501, 0x158082, 0x166489, 0x179023, 0x180004, + 0x1210c0, 0x134505, 0x142ebd, 0x1557fd, 0x16c49c, 0x17c4dc, + 0x184783, 0x1210cc, 0x130ec4, 0x149363, 0x152407, 0x16b795, + 0x1787b7, 0x180800, 0x1210d8, 0x13a583, 0x140dc7, 0x15a783, + 0x160e07, 0x178b91, 0x188063, 0x1210e4, 0x131807, 0x14d793, + 0x150085, 0x1681b9, 0x178bbd, 0x188985, 0x1210f0, 0x1386b7, + 0x140800, 0x15a703, 0x160d06, 0x17833e, 0x189513, 0x1210fc, + 0x1300c7, 0x1477c5, 0x1517fd, 0x168f7d, 0x178f49, 0x18757d, + 0x121108, 0x130293, 0x140ff5, 0x15a603, 0x160d46, 0x171793, + 0x180083, 0x121114, 0x137733, 0x140057, 0x158f5d, 0x167713, + 0x17f0f7, 0x181793, 0x121120, 0x130043, 0x148f5d, 0x157793, + 0x16ff06, 0x170513, 0x187ff5, 0x12112c, 0x13e7b3, 0x140067, + 0x159613, 0x1600b5, 0x178fe9, 0x188fd1, 0x121138, 0x139513, + 0x1400a5, 0x15f793, 0x169ff7, 0x179613, 0x180095, 0x121144, + 0x138fc9, 0x148fd1, 0x1505a2, 0x16f793, 0x17eff7, 0x188fcd, + 0x121150, 0x13a823, 0x140ce6, 0x15aa23, 0x160cf6, 0x172783, + 0x180f04, 0x12115c, 0x134719, 0x148563, 0x1500e7, 0x16472d, + 0x179263, 0x1810e7, 0x121168, 0x130493, 0x141104, 0x154701, + 0x164781, 0x17d683, 0x180104, 0x121174, 0x13e2b5, 0x1446a1, + 0x154701, 0x16853e, 0x17c436, 0x18c23a, 0x121180, 0x13c03e, + 0x142ca9, 0x1546a2, 0x164712, 0x174782, 0x1816fd, 0x12118c, + 0x13972a, 0x14f6f5, 0x150637, 0x160820, 0x175693, 0x184037, + 0x121198, 0x139713, 0x140077, 0x159732, 0x164310, 0x17d703, + 0x180004, 0x1211a4, 0x139963, 0x1422e6, 0x159593, 0x160017, + 0x176709, 0x18972e, 0x1211b0, 0x135703, 0x140087, 0x157e63, + 0x1600e6, 0x17d703, 0x180184, 0x1211bc, 0x139023, 0x1400d4, + 0x159693, 0x160017, 0x179423, 0x1800e4, 0x1211c8, 0x136709, + 0x149736, 0x151423, 0x1600c7, 0x17d703, 0x180184, 0x1211d4, + 0x133713, 0x140017, 0x150785, 0x164691, 0x170489, 0x1899e3, + 0x1211e0, 0x13f8d7, 0x1447b5, 0x151f63, 0x161807, 0x176785, + 0x1897a2, 0x1211ec, 0x13a703, 0x14a687, 0x154791, 0x160b63, + 0x1718f7, 0x186489, 0x1211f8, 0x13d783, 0x140004, 0x159de3, + 0x16e207, 0x172703, 0x180f04, 0x121204, 0x134789, 0x1418e3, + 0x15e2f7, 0x164505, 0x172c15, 0x185637, 0x121210, 0x130800, + 0x1446b7, 0x150822, 0x164238, 0x17a783, 0x18f806, 0x12121c, + 0x133537, 0x140822, 0x1575c1, 0x16f793, 0x178ff7, 0x18e793, + 0x121228, 0x133007, 0x14a023, 0x15f8f6, 0x162683, 0x173805, + 0x188593, 0x121234, 0x130ff5, 0x14d793, 0x150086, 0x168b85, + 0x17e793, 0x180767, 0x121240, 0x138eed, 0x1407a2, 0x158fd5, + 0x162023, 0x1738f5, 0x187793, 0x12124c, 0x13ffd7, 0x14c23c, + 0x15e793, 0x160027, 0x17c23c, 0x1847c1, 0x121258, 0x139023, + 0x1400f4, 0x154501, 0x1622cd, 0x17bbd9, 0x184585, 0x121264, + 0x134791, 0x14b569, 0x15476d, 0x169fe3, 0x17f6e7, 0x180737, + 0x121270, 0x130002, 0x144481, 0x150713, 0x160a67, 0x178793, + 0x184b84, 0x12127c, 0x130786, 0x1497a2, 0x15d683, 0x160ee7, + 0x178526, 0x180485, 0x121288, 0x13e693, 0x140026, 0x159723, + 0x160ed7, 0x179702, 0x180737, 0x121294, 0x130002, 0x144791, + 0x150713, 0x160a67, 0x179ee3, 0x18fcf4, 0x1212a0, 0x130493, + 0x141000, 0x154501, 0x1614fd, 0x172a15, 0x18fced, 0x1212ac, + 0x134785, 0x148526, 0x15c03e, 0x16222d, 0x17470d, 0x184782, + 0x1212b8, 0x135363, 0x1400a7, 0x154781, 0x160485, 0x174711, + 0x1896e3, 0x1212c4, 0x13fee4, 0x14c38d, 0x156789, 0x164749, + 0x179023, 0x1800e7, 0x1212d0, 0x1347c5, 0x142c23, 0x150ef4, + 0x160793, 0x171000, 0x182a23, 0x1212dc, 0x130ef4, 0x1445d1, + 0x150513, 0x160ec4, 0x172a15, 0x18b709, 0x1212e8, 0x136705, + 0x149722, 0x155783, 0x16a5a7, 0x1746a1, 0x180785, 0x1212f4, + 0x1307c2, 0x1483c1, 0x15f963, 0x1602f6, 0x171d23, 0x18a407, + 0x121300, 0x132823, 0x140e04, 0x154783, 0x160ec4, 0x1789e3, + 0x18da07, 0x12130c, 0x132783, 0x140f04, 0x1585e3, 0x16da07, + 0x172783, 0x180f04, 0x121318, 0x138ee3, 0x14da07, 0x154741, + 0x169de3, 0x17e2e7, 0x1847ed, 0x121324, 0x132823, 0x140ef4, + 0x15bd05, 0x1606b7, 0x170002, 0x181d23, 0x121330, 0x13a4f7, + 0x144481, 0x158693, 0x160a66, 0x178793, 0x184b84, 0x12133c, + 0x130786, 0x1497a2, 0x15d703, 0x160ee7, 0x178526, 0x189b75, + 0x121348, 0x139723, 0x140ee7, 0x159682, 0x160737, 0x170820, + 0x189793, 0x121354, 0x130074, 0x140713, 0x152007, 0x1697ba, + 0x17a023, 0x180007, 0x121360, 0x130737, 0x140002, 0x150485, + 0x164791, 0x170693, 0x180a67, 0x12136c, 0x1396e3, 0x14fcf4, + 0x150737, 0x160828, 0x172783, 0x184807, 0x121378, 0x13e793, + 0x140207, 0x152023, 0x1648f7, 0x1747b9, 0x182823, 0x121384, + 0x130ef4, 0x14b58d, 0x156709, 0x165683, 0x170007, 0x1847c9, + 0x121390, 0x1393e3, 0x14e6f6, 0x1547b7, 0x160800, 0x17a783, + 0x180c87, 0x12139c, 0x130693, 0x141000, 0x1507c2, 0x1683c1, + 0x17f663, 0x1802f6, 0x1213a8, 0x135783, 0x140027, 0x150785, + 0x1607c2, 0x1783c1, 0x181123, 0x1213b4, 0x1300f7, 0x144725, + 0x157fe3, 0x16c6f7, 0x1766b7, 0x180800, 0x1213c0, 0x13a783, + 0x14f5c6, 0x157779, 0x16177d, 0x178ff9, 0x18ae23, 0x1213cc, + 0x13f4f6, 0x14b1a5, 0x151123, 0x160007, 0x17b18d, 0x18c1e3, + 0x1213d8, 0x13dee6, 0x14bbdd, 0x150737, 0x160830, 0x172783, + 0x181807, 0x1213e4, 0x132703, 0x142007, 0x154685, 0x160263, + 0x1702d5, 0x18c763, 0x1213f0, 0x1300a6, 0x148bfd, 0x15c111, + 0x164781, 0x17853e, 0x188082, 0x1213fc, 0x134689, 0x140b63, + 0x1500d5, 0x16478d, 0x1719e3, 0x18fef5, 0x121408, 0x135793, + 0x140047, 0x15a011, 0x168395, 0x178bfd, 0x18b7dd, 0x121414, + 0x1383a9, 0x14bfed, 0x151141, 0x16c422, 0x17c606, 0x1847d1, + 0x121420, 0x13842a, 0x149a63, 0x1500f5, 0x164508, 0x1707b7, + 0x180002, 0x12142c, 0x13c02e, 0x148793, 0x156687, 0x169782, + 0x174582, 0x18c04c, 0x121438, 0x1340b2, 0x144422, 0x150141, + 0x168082, 0x17ed09, 0x184781, 0x121444, 0x134737, 0x140822, + 0x152023, 0x16d0f7, 0x172023, 0x18d8f7, 0x121450, 0x132023, + 0x14e0f7, 0x152023, 0x16e8f7, 0x178082, 0x186785, 0x12145c, + 0x133737, 0x140822, 0x158693, 0x16fff7, 0x172023, 0x1830d7, + 0x121468, 0x132023, 0x145007, 0x152023, 0x165807, 0x172023, + 0x186007, 0x121474, 0x132023, 0x146807, 0x158793, 0x16c007, + 0x17b7e1, 0x180000, 0x1f00a0, 0x1903f3, 0x1903fb, 0x1f0000, +}; + +int jl2xxx_patch_static_op_set(struct phy_device *phydev) +{ + int err; + + err = jl2xxx_pre_init(phydev, init_data0, ARRAY_SIZE(init_data0), + patch_fw_versions0, + ARRAY_SIZE(patch_fw_versions0), patch_version0); + if (err < 0) + return err; + + err = jl2xxx_pre_init(phydev, init_data1, ARRAY_SIZE(init_data1), + patch_fw_versions1, + ARRAY_SIZE(patch_fw_versions1), patch_version1); + if (err < 0) + return err; + + err = jl2xxx_pre_init(phydev, init_data2, ARRAY_SIZE(init_data2), + patch_fw_versions2, + ARRAY_SIZE(patch_fw_versions2), patch_version2); + if (err < 0) + return err; + + return 0; +} + +#if (JLSEMI_PHY_WOL) +int jl1xxx_wol_dynamic_op_get(struct phy_device *phydev) +{ + return jlsemi_fetch_bit(phydev, JL1XXX_PAGE129, + JL1XXX_WOL_CTRL_REG, JL1XXX_WOL_DIS); +} + +int jl2xxx_wol_dynamic_op_get(struct phy_device *phydev) +{ + return jlsemi_fetch_bit(phydev, JL2XXX_WOL_CTRL_PAGE, + JL2XXX_WOL_CTRL_REG, JL2XXX_WOL_EN); +} + +static int jl1xxx_wol_static_op_set(struct phy_device *phydev) +{ + int err; + + err = jl1xxx_wol_dynamic_op_set(phydev); + if (err < 0) + return err; + + return 0; +} +#endif + +int jl1xxx_intr_ack_event(struct phy_device *phydev) +{ + struct jl1xxx_priv *priv = phydev->priv; + int err; + + if (priv->intr.enable & JL1XXX_INTR_STATIC_OP_EN) { + err = phy_read(phydev, JL1XXX_INTR_STATUS_REG); + if (err < 0) + return err; + } + + return 0; +} + +int jl1xxx_intr_static_op_set(struct phy_device *phydev) +{ + struct jl1xxx_priv *priv = phydev->priv; + int err; + int ret = 0; + + if (priv->intr.enable & JL1XXX_INTR_LINK_CHANGE_EN) + ret |= JL1XXX_INTR_LINK; + if (priv->intr.enable & JL1XXX_INTR_AN_ERR_EN) + ret |= JL1XXX_INTR_AN_ERR; + + err = jlsemi_set_bits(phydev, JL1XXX_PAGE7, + JL1XXX_INTR_REG, ret); + if (err < 0) + return err; + + return 0; +} + +#if (JLSEMI_PHY_WOL) +static int jl2xxx_wol_static_op_set(struct phy_device *phydev) +{ + int err; + + err = jl2xxx_wol_dynamic_op_set(phydev); + if (err < 0) + return err; + + return 0; +} + +int jl1xxx_wol_dynamic_op_set(struct phy_device *phydev) +{ + int err; + + err = jl1xxx_wol_cfg_rmii(phydev); + if (err < 0) + return err; + + err = jl1xxx_wol_enable(phydev, true); + if (err < 0) + return err; + + err = jl1xxx_wol_store_mac_addr(phydev); + if (err < 0) + return err; + + if (jl1xxx_wol_receive_check(phydev)) { + err = jl1xxx_wol_clear(phydev); + if (err < 0) + return err; + } + + return 0; +} + +int jl2xxx_wol_dynamic_op_set(struct phy_device *phydev) +{ + int err; + + err = jl2xxx_wol_enable(phydev, true); + if (err < 0) + return err; + + err = jl2xxx_wol_clear(phydev); + if (err < 0) + return err; + + err = jl2xxx_wol_active_low_polarity(phydev, true); + if (err < 0) + return err; + + err = jl2xxx_store_mac_addr(phydev); + if (err < 0) + return err; + + return 0; +} +#endif + +int jl2xxx_intr_ack_event(struct phy_device *phydev) +{ + int err; + + err = jlsemi_read_paged(phydev, JL2XXX_PAGE2627, + JL2XXX_INTR_STATUS_REG); + if (err < 0) + return err; + + return 0; +} + +int jl2xxx_intr_static_op_set(struct phy_device *phydev) +{ + struct jl2xxx_priv *priv = phydev->priv; + int err; + int ret = 0; + + if (priv->intr.enable & JL2XXX_INTR_LINK_CHANGE_EN) + ret |= JL2XXX_INTR_LINK_CHANGE; + if (priv->intr.enable & JL2XXX_INTR_AN_ERR_EN) + ret |= JL2XXX_INTR_AN_ERR; + if (priv->intr.enable & JL2XXX_INTR_AN_COMPLETE_EN) + ret |= JL2XXX_INTR_AN_COMPLETE; + if (priv->intr.enable & JL2XXX_INTR_AN_PAGE_RECE) + ret |= JL2XXX_INTR_AN_PAGE; + + err = jlsemi_set_bits(phydev, JL2XXX_PAGE2626, + JL2XXX_INTR_CTRL_REG, ret); + if (err < 0) + return err; + + err = jlsemi_set_bits(phydev, JL2XXX_PAGE158, + JL2XXX_INTR_PIN_REG, + JL2XXX_INTR_PIN_EN); + if (err < 0) + return err; + + err = jlsemi_set_bits(phydev, JL2XXX_PAGE160, + JL2XXX_PIN_EN_REG, + JL2XXX_PIN_OUTPUT); + if (err < 0) + return err; + + return 0; +} + +int jl1xxx_operation_args_get(struct phy_device *phydev) +{ + jl1xxx_led_operation_args(phydev); + jl1xxx_wol_operation_args(phydev); + jl1xxx_intr_operation_args(phydev); + jl1xxx_mdi_operation_args(phydev); + jl1xxx_rmii_operation_args(phydev); + + return 0; +} + +int jl2xxx_operation_args_get(struct phy_device *phydev) +{ + jl2xxx_led_operation_args(phydev); + jl2xxx_fld_operation_args(phydev); + jl2xxx_wol_operation_args(phydev); + jl2xxx_intr_operation_args(phydev); + jl2xxx_downshift_operation_args(phydev); + jl2xxx_rgmii_operation_args(phydev); + jl2xxx_patch_operation_args(phydev); + jl2xxx_clk_operation_args(phydev); + jl2xxx_work_mode_operation_args(phydev); + jl2xxx_lpbk_operation_args(phydev); + jl2xxx_slew_rate_operation_args(phydev); + jl2xxx_rxc_out_operation_args(phydev); + + return 0; +} + +int jl1xxx_static_op_init(struct phy_device *phydev) +{ + struct jl1xxx_priv *priv = phydev->priv; + int err; + + if (priv->led.enable & JL1XXX_LED_STATIC_OP_EN) { + err = jl1xxx_led_static_op_set(phydev); + if (err < 0) + return err; + } + +#if (JLSEMI_PHY_WOL) + if (priv->wol.enable & JL1XXX_WOL_STATIC_OP_EN) { + err = jl1xxx_wol_static_op_set(phydev); + if (err < 0) + return err; + } +#endif + + if (priv->intr.enable & JL1XXX_INTR_STATIC_OP_EN) { + err = jl1xxx_intr_static_op_set(phydev); + if (err < 0) + return err; + } + + if (priv->mdi.enable & JL1XXX_MDI_STATIC_OP_EN) { + err = jl1xxx_mdi_static_op_set(phydev); + if (err < 0) + return err; + } + + if (priv->rmii.enable & JL1XXX_RMII_STATIC_OP_EN) { + err = jl1xxx_rmii_static_op_set(phydev); + if (err < 0) + return err; + } + + return 0; +} + +int jl2xxx_static_op_init(struct phy_device *phydev) +{ + struct jl2xxx_priv *priv = phydev->priv; + int err; + + if (priv->patch.enable & JL2XXX_PATCH_STATIC_OP_EN) { + err = jl2xxx_patch_static_op_set(phydev); + if (err < 0) + return err; + } + + if (priv->led.enable & JL2XXX_LED_STATIC_OP_EN) { + err = jl2xxx_led_static_op_set(phydev); + if (err < 0) + return err; + } + + if (priv->fld.enable & JL2XXX_FLD_STATIC_OP_EN) { + err = jl2xxx_fld_static_op_set(phydev); + if (err < 0) + return err; + } + +#if (JLSEMI_PHY_WOL) + if (priv->wol.enable & JL2XXX_WOL_STATIC_OP_EN) { + err = jl2xxx_wol_static_op_set(phydev); + if (err < 0) + return err; + } +#endif + + if (priv->intr.enable & JL2XXX_INTR_STATIC_OP_EN) { + err = jl2xxx_intr_static_op_set(phydev); + if (err < 0) + return err; + } + + if (priv->downshift.enable & JL2XXX_DSFT_STATIC_OP_EN) { + err = jl2xxx_downshift_static_op_set(phydev); + if (err < 0) + return err; + } + + if (priv->rgmii.enable & JL2XXX_RGMII_STATIC_OP_EN) { + err = jl2xxx_rgmii_static_op_set(phydev); + if (err < 0) + return err; + } + + if (priv->clk.enable & JL2XXX_CLK_STATIC_OP_EN) { + err = jl2xxx_clk_static_op_set(phydev); + if (err < 0) + return err; + } + + if (priv->work_mode.enable & JL2XXX_WORK_MODE_STATIC_OP_EN) { + err = jl2xxx_work_mode_static_op_set(phydev); + if (err < 0) + return err; + } + + if (priv->lpbk.enable & JL2XXX_LPBK_STATIC_OP_EN) { + err = jl2xxx_lpbk_static_op_set(phydev); + if (err < 0) + return err; + } + + if (priv->slew_rate.enable & JL2XXX_SLEW_RATE_STATIC_OP_EN) { + err = jl2xxx_slew_rate_static_op_set(phydev); + if (err < 0) + return err; + } + + if (priv->rxc_out.enable & JL2XXX_RXC_OUT_STATIC_OP_EN) { + err = jl2xxx_rxc_out_static_op_set(phydev); + if (err < 0) + return err; + } + + return 0; +} + +int jl2xxx_pre_init(struct phy_device *phydev, + u32 *init_data, u16 data_len, + u16 *patch_fw_versions, u16 versions_len, + u16 patch_version) +{ + int i, j; + int regaddr, val; + bool patch_ok = false; + + val = jlsemi_read_paged(phydev, JL2XXX_PAGE0, JL2XXX_PHY_INFO_REG); + for (i = 0; i < versions_len; i++) { + if (val == patch_fw_versions[i]) + patch_ok |= true; + } + + if (!patch_ok) + return 0; + + for (i = 0; i < data_len; i++) { + regaddr = ((init_data[i] >> 16) & 0xff); + val = (init_data[i] & 0xffff); + phy_write(phydev, regaddr, val); + if (regaddr == 0x18) { + phy_write(phydev, 0x10, 0x8006); + for (j = 0; j < 8; j++) { + if (phy_read(phydev, 0x10) == 0) + break; + } + } + } + /* Wait load patch complete */ + msleep(20); + + val = jlsemi_read_paged(phydev, JL2XXX_PAGE174, JL2XXX_PATCH_REG); + + if (val != patch_version) + JLSEMI_PHY_MSG(KERN_ERR + "%s: patch version is not match\n", __func__); + + return 0; +} + +int jlsemi_soft_reset(struct phy_device *phydev) +{ + int err; + + err = jlsemi_set_bits(phydev, JL2XXX_PAGE0, + JL2XXX_BMCR_REG, JL2XXX_SOFT_RESET); + if (err < 0) + return err; + /* Wait soft reset complete*/ + msleep(600); + + return 0; +} + +/********************** Convenience function for phy **********************/ + +/** + * jlsemi_write_page() - write the page register + * @phydev: a pointer to a &struct phy_device + * @page: page values + */ +int jlsemi_write_page(struct phy_device *phydev, int page) +{ + return phy_write(phydev, JLSEMI_PAGE31, page); +} + +/** + * jlsemi_read_page() - write the page register + * @phydev: a pointer to a &struct phy_device + * + * Return: get page values at present + */ +int jlsemi_read_page(struct phy_device *phydev) +{ + return phy_read(phydev, JLSEMI_PAGE31); +} + +/** + * __jlsemi_save_page() - save the page value + *@phydev: a pointer to a &struct phy_device + * + * Return: save page value + */ +static inline int __jlsemi_save_page(struct phy_device *phydev) +{ + return jlsemi_read_page(phydev); +} + +/** + * __jlsemi_select_page() - restore the page register + * @phydev: a pointer to a &struct phy_device + * @page: the page + * + * Return: + * @oldpgae: this is last page value + * @ret: if page is change it will return new page value + */ +static inline int __jlsemi_select_page(struct phy_device *phydev, int page) +{ + int ret, oldpage; + + oldpage = ret = __jlsemi_save_page(phydev); + if (ret < 0) + return ret; + + if (oldpage != page) { + ret = jlsemi_write_page(phydev, page); + if (ret < 0) + return ret; + } + + return oldpage; +} + +/** + * __jlsemi_restore_page() - restore the page register + * @phydev: a pointer to a &struct phy_device + * @oldpage: the old page, return value from __jlsemi_save_page() or + * __jlsemi_select_page() + * @ret: operation's return code + * + * Returns: + * @oldpage if it was a negative value, otherwise + * @ret if it was a negative errno value, otherwise + * phy_write_page()'s negative value if it were in error, otherwise + * @ret + */ +static inline int __jlsemi_restore_page(struct phy_device *phydev, + int oldpage, int ret) +{ + int r; + + if (oldpage >= 0) { + r = jlsemi_write_page(phydev, oldpage); + + /* Propagate the operation return code if the page write + * was successful. + */ + if (ret >= 0 && r < 0) + ret = r; + } else { + /* Propagate the phy page selection error code */ + ret = oldpage; + } + + return ret; +} + +/** + * __jlsemi_modify_reg() - Convenience function for modifying a PHY register + * @phydev: a pointer to a &struct phy_device + * @regnum: register number + * @mask: bit mask of bits to clear + * @set: bit mask of bits to set + * + * Returns negative errno, 0 if there was no change, and 1 in case of change + */ +static inline int __jlsemi_modify_reg(struct phy_device *phydev, + u32 regnum, u16 mask, u16 set) +{ + int newval, ret; + + ret = phy_read(phydev, regnum); + if (ret < 0) + return ret; + + newval = (ret & ~mask) | set; + if (newval == ret) + return 0; + + ret = phy_write(phydev, regnum, newval); + + return ret < 0 ? ret : 1; +} + +/** + * jlsemi_modify_paged_reg() - Function for modifying a paged register + * @phydev: a pointer to a &struct phy_device + * @page: the page for the phy + * @regnum: register number + * @mask: bit mask of bits to clear + * @set: bit mask of bits to set + * + * Returns negative errno, 0 if there was no change, and 1 in case of change + */ +int jlsemi_modify_paged_reg(struct phy_device *phydev, + int page, u32 regnum, + u16 mask, u16 set) +{ + int ret = 0, oldpage; + + oldpage = __jlsemi_select_page(phydev, page); + if (oldpage >= 0) + ret = __jlsemi_modify_reg(phydev, regnum, mask, set); + + return __jlsemi_restore_page(phydev, oldpage, ret); +} + +/** + * jlsemi_set_bits() - Convenience function for setting bits in a PHY register + * @phydev: a pointer to a &struct phy_device + * @page: the page for the phy + * @regnum: register number to write + * @val: bits to set + */ +int jlsemi_set_bits(struct phy_device *phydev, + int page, u32 regnum, u16 val) +{ + return jlsemi_modify_paged_reg(phydev, page, regnum, 0, val); +} + +/** + * jlsemi_clear_bits - Convenience function for clearing bits in a PHY register + * @phydev: the phy_device struct + * @page: the page for the phy + * @regnum: register number to write + * @val: bits to clear + */ +int jlsemi_clear_bits(struct phy_device *phydev, + int page, u32 regnum, u16 val) +{ + return jlsemi_modify_paged_reg(phydev, page, regnum, val, 0); +} + +/** + * jlsemi_fetch_bit() - Convenience function for setting bits in a PHY register + * @phydev: a pointer to a &struct phy_device + * @page: the page for the phy + * @regnum: register number to write + * @val: bit to get + * + * Note: + * you only get one bit at meanwhile + * + */ +int jlsemi_fetch_bit(struct phy_device *phydev, + int page, u32 regnum, u16 val) +{ + int ret = 0, oldpage; + + oldpage = __jlsemi_select_page(phydev, page); + if (oldpage >= 0) { + ret = phy_read(phydev, regnum); + if (ret < 0) + return ret; + ret = ((ret & val) == val) ? 1 : 0; + } + + return __jlsemi_restore_page(phydev, oldpage, ret); +} + +/** + * jlsemi_read_paged() - Convenience function for reading a paged register + * @phydev: a pointer to a &struct phy_device + * @page: the page for the phy + * @regnum: register number + * + * Same rules as for phy_read(). + */ +int jlsemi_read_paged(struct phy_device *phydev, int page, u32 regnum) +{ + int ret = 0, oldpage; + + oldpage = __jlsemi_select_page(phydev, page); + if (oldpage >= 0) + ret = phy_read(phydev, regnum); + + return __jlsemi_restore_page(phydev, oldpage, ret); +} + +#if (KERNEL_VERSION(4, 0, 0) > LINUX_VERSION_CODE) +int jlsemi_drivers_register(struct phy_driver *phydrvs, int size) +{ + int i, j; + int ret; + + for (i = 0; i < size; i++) { + ret = phy_driver_register(&phydrvs[i]); + if (ret) + goto err; + } + + return 0; + +err: + for (j = 0; j < i; j++) + phy_driver_unregister(&phydrvs[j]); + + return ret; +} + +void jlsemi_drivers_unregister(struct phy_driver *phydrvs, int size) +{ + int i; + + for (i = 0; i < size; i++) + phy_driver_unregister(&phydrvs[i]); +} +#else +#endif diff --git a/drivers/net/phy/jlsemi-core.h b/drivers/net/phy/jlsemi-core.h new file mode 100644 index 000000000..0501a452d --- /dev/null +++ b/drivers/net/phy/jlsemi-core.h @@ -0,0 +1,439 @@ +/* SPDX-License-Identifier: GPL-2.0+ + * + * Copyright (C) 2021 JLSemi Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#ifndef _JLSEMI_CORE_H +#define _JLSEMI_CORE_H + +#define JLSEMI_KERNEL_DEVICE_TREE_USE 1 + +#include +#include +#include +#include +#include +#if (JLSEMI_KERNEL_DEVICE_TREE_USE) +#include +#else +#include "jlsemi-dt-phy.h" +#endif + +#define JL1XXX_PHY_ID 0x937c4023 +#define JL2XXX_PHY_ID 0x937c4032 +#define JLSEMI_PHY_ID_MASK 0xfffffff0 + +#define JL1XXX_PAGE0 0 +#define JL1XXX_PAGE7 7 +#define JL1XXX_INTR_REG 19 +#define JL1XXX_INTR_LINK BIT(13) +#define JL1XXX_INTR_AN_ERR BIT(11) +#define JL1XXX_LED_REG 19 +#define JL1XXX_LED_EN BIT(3) +#define JL1XXX_INTR_STATUS_REG 30 + +#define JL1XXX_PAGE7 7 +#define JL1XXX_RMII_CTRL_REG 16 +#define JL1XXX_RMII_OUT BIT(12) +#define JL1XXX_RMII_MODE BIT(3) + +#define JL1XXX_PAGE129 129 +#define JL1XXX_LED_MODE_REG 24 +#define JL1XXX_MAC_ADDR0_REG 25 +#define JL1XXX_MAC_ADDR1_REG 26 +#define JL1XXX_MAC_ADDR2_REG 27 +#define JL1XXX_WOL_CTRL_REG 28 +#define JL1XXX_WOL_DIS BIT(15) +#define JL1XXX_WOL_CLEAR BIT(1) +#define JL1xxx_WOL_RECEIVE BIT(0) +#define ADDR8_HIGH_TO_LOW(n) ((n >> 4) | (n << 4)) + +#define JL1XXX_PAGE24 24 +#define JL1XXX_REG24 24 +#define JL1XXX_MDI_TX_BM_MASK 0x1c00 +#define JL1XXX_MDI_TX_BM(n) (n << 10) +#define JL1XXX_MDI_TX_SRN BIT(0) + +#define JL1XXX_PAGE7 7 +#define JL1XXX_REG16 16 +#define JL1XXX_RMII_MODE BIT(3) +#define JL1XXX_RMII_CLK_50M_INPUT BIT(12) +#define JL1XXX_RMII_TX_SKEW_MASK (0xf << 8) +#define JL1XXX_RMII_TX_SKEW(n) ((n << 8) & JL1XXX_RMII_TX_SKEW_MASK) +#define JL1XXX_RMII_RX_SKEW_MASK (0xf << 4) +#define JL1XXX_RMII_RX_SKEW(n) ((n << 4) & JL1XXX_RMII_RX_SKEW_MASK) +#define JL1XXX_RMII_CRS_DV BIT(2) + +#define JL2XXX_PAGE0 0 +#define JL2XXX_BMCR_REG 0x0000 +#define JL2XXX_SOFT_RESET BIT(15) +#define JL2XXX_SPEED_LSB BIT(13) +#define JL2XXX_AUTONEG_EN BIT(12) +#define JL2XXX_SPEED_MSB BIT(6) +#define JL2XXX_DSFT_CTRL_REG 17 +#define JL2XXX_DSFT_EN BIT(12) +#define JL2XXX_DSFT_SMART_EN BIT(13) +#define JL2XXX_DSFT_TWO_WIRE_EN BIT(14) +#define JL2XXX_DSFT_AN_ERR_EN BIT(15) +#define JL2XXX_DSFT_STL_MASK 0x03e0 +#define JL2XXX_DSFT_STL_CNT(n) (((n << 5) & JL2XXX_DSFT_STL_MASK)) +#define JL2XXX_DSFT_AN_MASK 0x001f +#define JL2XXX_DSFT_CNT_MAX 32 +#define JL2XXX_PHY_INFO_REG 29 +#define JL2XXX_PATCH_MASK 0xffff +#define JL2XXX_SW_MASK 0xffff +#define JL2XXX_AUTO_GAIN_DIS BIT(6) + +#define JLSEMI_PAGE31 0x001f +#define JL2XXX_WOL_CTRL_PAGE 0x0012 +#define JL2XXX_WOL_CTRL_REG 0x0015 +#define JL2XXX_WOL_STAS_PAGE 0x1200 +#define JL2XXX_WOL_STAS_REG 0x0010 +#define JL2XXX_MAC_ADDR2_REG 0x0011 +#define JL2XXX_MAC_ADDR1_REG 0x0012 +#define JL2XXX_MAC_ADDR0_REG 0x0013 +#define JL2XXX_WOL_EVENT BIT(1) +#define JL2XXX_WOL_POLARITY BIT(14) +#define JL2XXX_WOL_EN BIT(15) +#define JL2XXX_WOL_GLB_EN BIT(6) + +#define JL2XXX_PAGE2626 2626 +#define JL2XXX_INTR_CTRL_REG 18 +#define JL2XXX_INTR_LINK_CHANGE BIT(4) +#define JL2XXX_INTR_AN_COMPLETE BIT(3) +#define JL2XXX_INTR_AN_PAGE BIT(2) +#define JL2XXX_INTR_AN_ERR BIT(0) + +#define JL2XXX_PAGE2627 2627 +#define JL2XXX_INTR_STATUS_REG 29 +#define JL2XXX_CLK_CTRL_REG 25 +#define JL2XXX_CLK_OUT_PIN BIT(0) +#define JL2XXX_CLK_SSC_EN BIT(3) +#define JL2XXX_CLK_125M_OUT BIT(11) +#define JL2XXXX_CLK_SRC BIT(12) + +#define JL2XXX_PAGE158 158 +#define JL2XXX_INTR_PIN_REG 16 +#define JL2XXX_INTR_PIN_EN BIT(14) + +#define JL2XXX_PAGE160 160 +#define JL2XXX_PIN_EN_REG 21 +#define JL2XXX_PIN_OUTPUT BIT(11) + +#define JL2XXX_PAGE3336 3336 +#define JL2XXX_RGMII_CTRL_REG 17 + +#define JL2XXX_PAGE18 18 +#define JL2XXX_RXC_OUT_REG 21 +#define JL2XXX_RXC_OUT BIT(14) + +#define JL2XXX_WORK_MODE_REG 21 +#define JL2XXX_WORK_MODE_MASK 0x7 + +#define JL2XXX_PAGE160 160 +#define JL2XXX_REG25 25 +#define JL2XXX_CPU_RESET BIT(3) + +#define JL2XXX_PAGE173 173 +#define JL2XXX_PATCH_REG 0x0010 +#define JL2XXX_REG16 16 +#define JL2XXX_REG17 17 +#define JL2XXX_LOAD_GO 0 +#define JL2XXX_LOAD_DATA0 0x3a01 +#define JL2XXX_REG20 20 +#define JL2XXX_REG21 21 +#define JL2XXX_LPBK_MODE_MASK 0x6 +#define JL2XXX_LPBK_PMD_MODE BIT(2) +#define JL2XXX_LPBK_EXT_MODE BIT(1) + +#define JL2XXX_PAGE174 174 + +#define JL2XXX_REG29 29 + +#define JL2XXX_PAGE191 191 +#define JL2XXX_RGMII_CFG BIT(3) + +#define JL2XXX_PAGE258 258 +#define JL2XXX_SLEW_RATE_CTRL_REG 23 +#define JL2XXX_SLEW_RATE_EN BIT(12) +#define JL2XXX_SLEW_RATE_REF_CLK BIT(13) +#define JL2XXX_SLEW_RATE_SEL_CLK BIT(14) + +#define JL2XXX_REG20 20 +#define JL2XXX_SPEED1000_NO_AN (BIT(11) | BIT(10)) + +#define LED_PERIOD_MASK 0xff00 +#define LEDPERIOD(n) ((n << 8) & LED_PERIOD_MASK) +#define LED_ON_MASK 0x00ff +#define LEDON(n) ((n << 0) & LED_ON_MASK) + +#define ADVERTISE_FIBER_1000HALF 0x40 +#define ADVERTISE_FIBER_1000FULL 0x20 + +/*************************************************************************/ +struct jl_hw_stat { + const char *string; + u8 reg; + u16 page; + u16 mask; + u16 enable; +}; + +static const struct jl_hw_stat jl_phy[] = { + { + .string = "page0,reg0", + .enable = true, + .page = 0, + .reg = 0, + }, { + .string = "page0,reg1", + .enable = false, + .page = 0, + .reg = 1, + }, +}; + +static const struct jl_hw_stat jl2xxx_hw_stats[] = { + { + .string = "phy_patch_version", + .reg = JL2XXX_PATCH_REG, + .page = JL2XXX_PAGE174, + .mask = JL2XXX_PATCH_MASK, + }, { + .string = "phy_software_version", + .reg = JL2XXX_PHY_INFO_REG, + .page = JL2XXX_PAGE0, + .mask = JL2XXX_SW_MASK, + }, +}; + +struct jl_led_ctrl { + u32 enable; /* LED control enable */ + u32 mode; /* LED work mode */ + u32 global_period; /* LED global twinkle period */ + u32 global_on; /* LED global twinkle hold on time */ + u32 gpio_output; /* LED is used as gpio output */ + u32 polarity; /* LED polarity */ + bool ethtool; /* Whether the ethtool is supported */ +}; + +struct jl_fld_ctrl { + u32 enable; /* Fast link down control enable */ + u32 delay; /* Fast link down time */ + bool ethtool; /* Whether the ethtool is supported */ +}; + +struct jl_wol_ctrl { + u32 enable; /* Wake On LAN control enable */ + bool ethtool; /* Whether the ethtool is supported */ +}; + +struct jl_intr_ctrl { + u32 enable; /* Interrupt control enable */ + bool ethtool; /* Whether the ethtool is supported */ +}; + +struct jl_downshift_ctrl { + u32 enable; /* Downshift control enable */ + u32 count; /* Downshift control count */ + bool ethtool; /* Whether the ethtool is supported */ +}; + +struct jl_rgmii_ctrl { + u32 enable; /* Rgmii control enable */ + u32 rx_delay; /* Rgmii control rx delay */ + u32 tx_delay; /* Rgmii control tx delay */ + bool ethtool; /* Whether the ethtool is supported */ +}; + +struct jl_patch_ctrl { + u32 enable; /* Patch control enable */ + bool ethtool; /* Whether the ethtool is supported */ +}; + +struct jl_clk_ctrl { + u32 enable; /* Clock 125M control enable */ + bool ethtool; /* Whether the ethtool is supported */ +}; + +struct jl_work_mode_ctrl { + u32 enable; /* Work mode control enable */ + u32 mode; /* Work mode select mode */ + bool ethtool; /* Whether the ethtool is supported */ +}; + +struct jl_loopback_ctrl { + u32 enable; /* Loopback control enable */ + u32 mode; /* Loopback select mode */ + bool ethtool; /* Whether the ethtool is supported */ +}; + +struct jl_mdi_ctrl { + u32 enable; /* Mdi control enable */ + u32 rate; /* Mdi select Rate */ + u32 amplitude; /* Mdi select amplitude */ + bool ethtool; /* Whether the ethtool is supported */ +}; + +struct jl_rmii_ctrl { + u32 enable; /* Rmii control enable */ + u32 tx_timing; /* Rmii modify tx timing */ + u32 rx_timing; /* Rmii modify rx timing */ + bool ethtool; /* Whether the ethtool is supported */ +}; + +struct jl_slew_rate_ctrl { + u32 enable; /* Slew rate control enable */ + bool ethtool; /* Whether the ethtool is supported */ +}; + +struct jl_rxc_out_ctrl { + u32 enable; /* Rx clock out control enable */ + bool ethtool; /* Whether the ethtool is supported */ +}; + +struct jl1xxx_priv { + struct jl_led_ctrl led; + struct jl_wol_ctrl wol; + struct jl_intr_ctrl intr; + bool static_inited; /* Initialization flag */ + struct jl_mdi_ctrl mdi; + struct jl_rmii_ctrl rmii; +}; + +struct jl2xxx_priv { + struct jl_led_ctrl led; + struct jl_fld_ctrl fld; + struct jl_wol_ctrl wol; + struct jl_intr_ctrl intr; + struct jl_downshift_ctrl downshift; + struct jl_rgmii_ctrl rgmii; + struct jl_patch_ctrl patch; + struct jl_clk_ctrl clk; + const struct jl_hw_stat *hw_stats; + bool static_inited; /* Initialization flag */ + int nstats; /* Record for dynamic operation */ + u64 *stats; /* Pointer for dynamic operation */ + struct jl_work_mode_ctrl work_mode; + struct jl_loopback_ctrl lpbk; + struct jl_slew_rate_ctrl slew_rate; + struct jl_rxc_out_ctrl rxc_out; +}; + +/* macros to simplify debug checking */ +#define JLSEMI_PHY_MSG(msg, args...) printk(msg, ## args) + +/************************* JLSemi iteration code *************************/ +struct device *jlsemi_get_mdio(struct phy_device *phydev); + +int jl2xxx_downshift_dynamic_op_get(struct phy_device *phydev, u8 *data); + +int jl2xxx_downshift_dynamic_op_set(struct phy_device *phydev, u8 cnt); + +int jlsemi_read_paged(struct phy_device *phydev, int page, u32 regnum); + +int jl2xxx_intr_ack_event(struct phy_device *phydev); + +int jl2xxx_intr_static_op_set(struct phy_device *phydev); + +int jl1xxx_intr_ack_event(struct phy_device *phydev); + +int jl1xxx_intr_static_op_set(struct phy_device *phydev); + +int jl2xxx_wol_dynamic_op_get(struct phy_device *phydev); + +int jl2xxx_wol_dynamic_op_set(struct phy_device *phydev); + +int jl1xxx_wol_dynamic_op_get(struct phy_device *phydev); + +int jl1xxx_wol_dynamic_op_set(struct phy_device *phydev); + +int jl2xxx_fld_dynamic_op_get(struct phy_device *phydev, u8 *msecs); + +int jl2xxx_fld_dynamic_op_set(struct phy_device *phydev, const u8 *msecs); + +int jl1xxx_operation_args_get(struct phy_device *phydev); + +int jl1xxx_static_op_init(struct phy_device *phydev); + +int jl2xxx_operation_args_get(struct phy_device *phydev); + +int jl2xxx_static_op_init(struct phy_device *phydev); + +int jlsemi_soft_reset(struct phy_device *phydev); + +int jl2xxx_pre_init(struct phy_device *phydev, + u32 *init_data, u16 data_len, + u16 *patch_fw_versions, u16 versions_len, + u16 patch_version); + +bool jl2xxx_read_fiber_status(struct phy_device *phydev); + +int jl2xxx_config_aneg_fiber(struct phy_device *phydev); + +/********************** Convenience function for phy **********************/ + +/* Notice: You should change page 0 when you When you call it after */ +int jlsemi_write_page(struct phy_device *phydev, int page); + +int jlsemi_read_page(struct phy_device *phydev); + +int jlsemi_modify_paged_reg(struct phy_device *phydev, + int page, u32 regnum, + u16 mask, u16 set); + +int jlsemi_set_bits(struct phy_device *phydev, + int page, u32 regnum, u16 val); + +int jlsemi_clear_bits(struct phy_device *phydev, + int page, u32 regnum, u16 val); + +int jlsemi_fetch_bit(struct phy_device *phydev, + int page, u32 regnum, u16 val); + +int jlsemi_drivers_register(struct phy_driver *phydrvs, int size); + +void jlsemi_drivers_unregister(struct phy_driver *phydrvs, int size); + +/** + * module_jlsemi_driver() - Helper macro for registering PHY drivers + * @__phy_drivers: array of PHY drivers to register + * + * Helper macro for PHY drivers which do not do anything special in module + * init/exit. Each module may only use this macro once, and calling it + * replaces module_init() and module_exit(). + */ +#if (KERNEL_VERSION(4, 0, 0) > LINUX_VERSION_CODE) + +#define jlsemi_module_driver(__phy_drivers, __count) \ +static int __init phy_module_init(void) \ +{ \ + return jlsemi_drivers_register(__phy_drivers, __count); \ +} \ +module_init(phy_module_init); \ +static void __exit phy_module_exit(void) \ +{ \ + jlsemi_drivers_unregister(__phy_drivers, __count); \ +} \ +module_exit(phy_module_exit) + +#define module_jlsemi_driver(__phy_drivers) \ + jlsemi_module_driver(__phy_drivers, ARRAY_SIZE(__phy_drivers)) + +#else + +#define module_jlsemi_driver(__phy_drivers) \ + module_phy_driver(__phy_drivers) +#endif + +#endif /* _JLSEMI_CORE_H */ + diff --git a/drivers/net/phy/jlsemi-dt-phy.h b/drivers/net/phy/jlsemi-dt-phy.h new file mode 100644 index 000000000..0a6e2210e --- /dev/null +++ b/drivers/net/phy/jlsemi-dt-phy.h @@ -0,0 +1,341 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Device Tree constants for JLSemi PHY + * + * Author: Gangqiao Kuang + * + * Copyright (c) 2021 JLSemi Corporation + */ + +#ifndef _DT_BINDINGS_JLSEMI_PHY_H +#define _DT_BINDINGS_JLSEMI_PHY_H + +/**************************** Linux Version Compatible ********************/ +#define JLSEMI_DEV_COMPATIBLE (KERNEL_VERSION(4, 5, 0) > LINUX_VERSION_CODE) +#define JL2XXX_GET_STRING (KERNEL_VERSION(4, 5, 0) <= LINUX_VERSION_CODE) +#define JL2XXX_GET_STAT (KERNEL_VERSION(4, 5, 0) <= LINUX_VERSION_CODE) +#define JL2XXX_PHY_TUNABLE (KERNEL_VERSION(5, 0, 0) <= LINUX_VERSION_CODE) +#define JLSEMI_PHY_WOL (KERNEL_VERSION(3, 10, 0) < LINUX_VERSION_CODE) +/*************************************************************************/ + +/**************************** JLSemi Debug *******************************/ +#define JLSEMI_DEBUG_INFO 0 +/*************************************************************************/ + +/************************* JLSemi Phy Init Reentrant *********************/ +#define JLSEMI_PHY_NOT_REENTRANT false +/*************************************************************************/ + +/**************************** JL1XXX-LED *********************************/ +/* PHY LED Modes Select */ +#define JL1XXX_LED0_STRAP (1 << 0) +#define JL1XXX_LED0_EEE (1 << 1) +#define JL1XXX_LED0_100_ACTIVITY (1 << 2) +#define JL1XXX_LED0_10_ACTIVITY (1 << 3) +#define JL1XXX_LED0_100_LINK (1 << 4) +#define JL1XXX_LED0_10_LINK (1 << 5) +#define JL1XXX_LED1_STRAP (1 << 8) +#define JL1XXX_LED1_EEE (1 << 9) +#define JL1XXX_LED1_100_ACTIVITY (1 << 10) +#define JL1XXX_LED1_10_ACTIVITY (1 << 11) +#define JL1XXX_LED1_100_LINK (1 << 12) +#define JL1XXX_LED1_10_LINK (1 << 13) + +/* PHY LED As Gpio Output Select */ +#define JL1XXX_GPIO_LED0_OUT (1 << 2) +#define JL1XXX_GPIO_LED1_OUT (1 << 3) +#define JL1XXX_GPIO_LED0_EN (1 << 14) +#define JL1XXX_GPIO_LED1_EN (1 << 15) + +/* PHY LED Control Enable Mask Select */ +#define JL1XXX_LED_STATIC_OP_EN (1 << 0) +#define JL1XXX_LED_MODE_EN (1 << 1) +#define JL1XXX_LED_GLOABL_PERIOD_EN (1 << 2) +#define JL1XXX_LED_GLOBAL_ON_EN (1 << 3) +#define JL1XXX_LED_GPIO_OUT_EN (1 << 4) +//-----------------------------------------------------------------------// +/* PHY LED Control Enable Mask Config */ +#define JL1XXX_LED_CTRL_EN (0) + +/* PHY LED Modes Config */ +#define JL1XXX_CFG_LED_MODE (JL1XXX_LED0_100_LINK | \ + JL1XXX_LED0_10_LINK | \ + JL1XXX_LED1_100_ACTIVITY | \ + JL1XXX_LED1_10_ACTIVITY) + +/* PHY LED As Gpio Output Config */ +#define JL1XXX_CFG_GPIO (JL1XXX_GPIO_LED0_EN | \ + JL1XXX_GPIO_LED0_OUT | \ + JL1XXX_GPIO_LED1_EN | \ + JL1XXX_GPIO_LED1_OUT) + +/* PHY LED Global Period Config */ +#define JL1XXX_GLOBAL_PERIOD_MS 0x10 + +/* PHY LED Global Hold On Config */ +#define JL1XXX_GLOBAL_ON_MS 0x8 +/**************************************************************************/ + +/****************************** JL1XXX-WOL ********************************/ +/* PHY WOL Control Enable Mask Select */ +#define JL1XXX_WOL_STATIC_OP_EN (1 << 0) +//-----------------------------------------------------------------------// +/* PHY WOL Control Enable Mask Config */ +#define JL1XXX_WOL_CTRL_EN (0) + +/*************************************************************************/ + +/***************************** JL1XXX-INTR *******************************/ +/* PHY Interrupt Control Enable Mask Select */ +#define JL1XXX_INTR_STATIC_OP_EN (1 << 0) +#define JL1XXX_INTR_LINK_CHANGE_EN (1 << 1) +#define JL1XXX_INTR_AN_ERR_EN (1 << 2) +//-----------------------------------------------------------------------// +/* PHY Interrupt Irq Number Config */ +#define JL1XXX_INTR_IRQ -1 + +/* PHY Interrupt Control Enable Mask Config */ +#define JL1XXX_INTR_CTRL_EN (0) +/*************************************************************************/ + +/**************************** JL1XXX-MDI *********************************/ +/* PHY MDI Control Mode Enable Mask Select */ +#define JL1XXX_MDI_STATIC_OP_EN (1 << 0) +#define JL1XXX_MDI_RATE_EN (1 << 1) +#define JL1XXX_MDI_AMPLITUDE_EN (1 << 2) + +/* PHY MDI Rate Select */ +#define JL1XXX_MDI_RATE_STANDARD 0 +#define JL1XXX_MDI_RATE_ACCELERATE 1 + +/* PHY MDI Amplitude Select */ +#define JL1XXX_MDI_AMPLITUDE0 0 +#define JL1XXX_MDI_AMPLITUDE1 1 +#define JL1XXX_MDI_AMPLITUDE2 2 +#define JL1XXX_MDI_AMPLITUDE3 3 +#define JL1XXX_MDI_AMPLITUDE4 4 +#define JL1XXX_MDI_AMPLITUDE5 5 +#define JL1XXX_MDI_AMPLITUDE6 6 +#define JL1XXX_MDI_AMPLITUDE7 7 +//-----------------------------------------------------------------------// +/* PHY MDI Control Mode Enable Mask Config */ +#define JL1XXX_MDI_CTRL_EN (0) + +/* PHY MDI Rate Config */ +#define JL1XXX_MDI_RATE JL1XXX_MDI_RATE_ACCELERATE + +/* PHY MDI Amplitude Config */ +#define JL1XXX_MDI_AMPLITUDE JL1XXX_MDI_AMPLITUDE4 + +/*************************************************************************/ + +/**************************** JL1XXX-RMII ********************************/ +/* PHY RMII Control Mode Enable Mask Select */ +#define JL1XXX_RMII_STATIC_OP_EN (1 << 0) +#define JL1XXX_RMII_MODE_EN (1 << 1) +#define JL1XXX_RMII_CLK_50M_INPUT_EN (1 << 2) +#define JL1XXX_RMII_TX_SKEW_EN (1 << 3) +#define JL1XXX_RMII_RX_SKEW_EN (1 << 4) +#define JL1XXX_RMII_CRS_DV_EN (1 << 5) +//-----------------------------------------------------------------------// +/* PHY RMII Control Mode Enable Mask Config */ +#define JL1XXX_RMII_CTRL_EN (0) + +/* PHY RMII Timing Config */ +#define JL1XXX_RMII_TX_TIMING 0xf +#define JL1XXX_RMII_RX_TIMING 0xf + +/*************************************************************************/ + +/**************************** JL2XXX-LED *********************************/ +/* PHY LED Modes Select*/ +#define JL2XXX_LED0_LINK10 (1 << 0) +#define JL2XXX_LED0_LINK100 (1 << 1) +#define JL2XXX_LED0_LINK1000 (1 << 3) +#define JL2XXX_LED0_ACTIVITY (1 << 4) +#define JL2XXX_LED1_LINK10 (1 << 5) +#define JL2XXX_LED1_LINK100 (1 << 6) +#define JL2XXX_LED1_LINK1000 (1 << 8) +#define JL2XXX_LED1_ACTIVITY (1 << 9) +#define JL2XXX_LED2_LINK10 (1 << 10) +#define JL2XXX_LED2_LINK100 (1 << 11) +#define JL2XXX_LED2_LINK1000 (1 << 13) +#define JL2XXX_LED2_ACTIVITY (1 << 14) +/* mode_A = 0 and mode_B = 1 default mode_A */ +#define JL2XXX_LED_GLB_MODE_B (1 << 15) + +/* PHY LED Polarity Select */ +#define JL2XXX_LED0_POLARITY (1 << 12) +#define JL2XXX_LED1_POLARITY (1 << 11) +#define JL2XXX_LED2_POLARITY (1 << 10) + +/* PHY LED Control Enable Mask Select */ +#define JL2XXX_LED_STATIC_OP_EN (1 << 0) +#define JL2XXX_LED_MODE_EN (1 << 1) +#define JL2XXX_LED_GLOABL_PERIOD_EN (1 << 2) +#define JL2XXX_LED_GLOBAL_ON_EN (1 << 3) +#define JL2XXX_LED_POLARITY_EN (1 << 4) + +//-----------------------------------------------------------------------// +/* PHY LED Control Enable Mask Config */ +#define JL2XXX_LED_CTRL_EN (0) + +/* PHY LED Modes Config */ +#define JL2XXX_CFG_LED_MODE (JL2XXX_LED0_LINK10 | \ + JL2XXX_LED0_ACTIVITY | \ + JL2XXX_LED1_LINK100 | \ + JL2XXX_LED1_ACTIVITY | \ + JL2XXX_LED2_LINK1000 | \ + JL2XXX_LED2_ACTIVITY) + +/* PHY LED Polarity Config */ +#define JL2XXX_LED_POLARITY (JL2XXX_LED0_POLARITY | \ + JL2XXX_LED1_POLARITY | \ + JL2XXX_LED2_POLARITY) + +/* PHY LED Global Period Config */ +#define JL2XXX_GLOBAL_PERIOD_MS 0x3 + +/* PHY LED Global Hold On Config */ +#define JL2XXX_GLOBAL_ON_MS 0x2 +/*************************************************************************/ + +/**************************** JL2XXX-FLD *********************************/ +/* PHY Fast Link Down Control Enable Mask Select */ +#define JL2XXX_FLD_STATIC_OP_EN (1 << 0) +//-----------------------------------------------------------------------// +/* PHY Fast Link Down Control Enable Mask Config */ +#define JL2XXX_FLD_CTRL_EN (0) + +/* PHY Fast Link Down Delay Config */ +#define JL2XXX_FLD_DELAY 0 +/*************************************************************************/ + +/**************************** JL2XXX-WOL *********************************/ +/* PHY WOL Control Enable Mask Select */ +#define JL2XXX_WOL_STATIC_OP_EN (1 << 0) + +//-----------------------------------------------------------------------// +/* PHY WOL Control Enable Mask Config */ +#define JL2XXX_WOL_CTRL_EN (0) +/*************************************************************************/ + +/**************************** JL2XXX-INTR ********************************/ +/* PHY Interrupt Control Enable Mask Select */ +#define JL2XXX_INTR_STATIC_OP_EN (1 << 0) +#define JL2XXX_INTR_LINK_CHANGE_EN (1 << 1) +#define JL2XXX_INTR_AN_ERR_EN (1 << 2) +#define JL2XXX_INTR_AN_COMPLETE_EN (1 << 3) +#define JL2XXX_INTR_AN_PAGE_RECE (1 << 4) +//-----------------------------------------------------------------------// +/* PHY Interrupt Irq Number Config */ +#define JL2XXX_INTR_IRQ -1 + +/* PHY Interrupt Control Enable Mask Config */ +#define JL2XXX_INTR_CTRL_EN (0) +/*************************************************************************/ + +/**************************** JL2XXX-DSFT ********************************/ +/* PHY Downshift Control Enable Mask */ +#define JL2XXX_DSFT_STATIC_OP_EN (1 << 0) +//-----------------------------------------------------------------------// +/* PHY Downshift Control Enable Config */ +#define JL2XXX_DSFT_CTRL_EN (0) + +/* PHY Downshift Count Config */ +#define JL2XXX_DSFT_AN_CNT 4 +/*************************************************************************/ + +/**************************** JL2XXX-RGMII *******************************/ +/* PHY RGMII Control Mode Enable Mask Select */ +#define JL2XXX_RGMII_STATIC_OP_EN (1 << 0) +#define JL2XXX_RGMII_TX_DLY_EN (1 << 1) +#define JL2XXX_RGMII_RX_DLY_EN (1 << 2) +/* PHY RGMII DELAY BIT */ +#define JL2XXX_RGMII_TX_DLY_2NS (1 << 8) +#define JL2XXX_RGMII_RX_DLY_2NS (1 << 9) +//-----------------------------------------------------------------------// +/* PHY RGMII Control Mode Enable Mask Config */ +#define JL2XXX_RGMII_CTRL_EN (0) + +/*************************************************************************/ + +/**************************** JL2XXX-PATCH *******************************/ +/* PHY Patch Control Mode Enable Mask Select */ +#define JL2XXX_PATCH_STATIC_OP_EN (1 << 0) +//-----------------------------------------------------------------------// +/* PHY Patch Control Mode Enable Mask Config */ +#define JL2XXX_PATCH_CTRL_EN (JL2XXX_PATCH_STATIC_OP_EN) + +/*************************************************************************/ + +/**************************** JL2XXX-CLOCK *******************************/ +/* PHY Clock Control Mode Enable Mask Select */ +#define JL2XXX_CLK_STATIC_OP_EN (1 << 0) +#define JL2XXX_25M_CLK_OUT_EN (1 << 1) +#define JL2XXX_125M_CLK_OUT_EN (1 << 2) +#define JL2XXX_CLK_OUT_DIS (1 << 3) +//-----------------------------------------------------------------------// +/* PHY Clock Control Mode Enable Mask Config */ +#define JL2XXX_CLK_CTRL_EN (0) + +/*************************************************************************/ + +/**************************** JL2XXX-WORK_MODE ***************************/ +/* PHY Work Mode Control Mode Enable Mask Select */ +#define JL2XXX_WORK_MODE_STATIC_OP_EN (1 << 0) + +/* PHY Work Mode Select */ +#define JL2XXX_UTP_RGMII_MODE 0 +#define JL2XXX_FIBER_RGMII_MODE 1 +#define JL2XXX_UTP_FIBER_RGMII_MODE 2 +#define JL2XXX_UTP_SGMII_MODE 3 +#define JL2XXX_PHY_SGMII_RGMII_MODE 4 +#define JL2XXX_MAC_SGMII_RGMII_MODE 5 +#define JL2XXX_UTP_FIBER_FORCE_MODE1 6 +#define JL2XXX_UTP_FIBER_FORCE_MODE2 7 +//-----------------------------------------------------------------------// +/* PHY Work Mode Control Mode Enable Mask Config */ +#define JL2XXX_WORK_MODE_CTRL_EN (0) + +/* PHY Work Mode Config */ +#define JL2XXX_WORK_MODE_MODE JL2XXX_UTP_RGMII_MODE + +/*************************************************************************/ + +/**************************** JL2XXX-LOOPBACK ****************************/ +/* PHY Loopback Control Mode Enable Mask Select */ +#define JL2XXX_LPBK_STATIC_OP_EN (1 << 0) + +/* PHY Loopback Mode Select */ +#define JL2XXX_LPBK_PCS_10M 0 +#define JL2XXX_LPBK_PCS_100M 1 +#define JL2XXX_LPBK_PCS_1000M 2 +#define JL2XXX_LPBK_PMD_1000M 3 +#define JL2XXX_LPBK_EXT_STUB_1000M 4 +//-----------------------------------------------------------------------// +/* PHY Loopback Control Mode Enable Mask Config */ +#define JL2XXX_LPBK_CTRL_EN (0) + +/* PHY Loopback Mode Config */ +#define JL2XXX_LPBK_MODE JL2XXX_LPBK_PCS_1000M +/*************************************************************************/ + +/**************************** JL2XXX-SLEW_RATE ****************************/ +/* PHY Slew Rate Control Mode Enable Mask Select */ +#define JL2XXX_SLEW_RATE_STATIC_OP_EN (1 << 0) +//-----------------------------------------------------------------------// +/* PHY Slew Rate Control Mode Enable Mask Config */ +#define JL2XXX_SLEW_RATE_CTRL_EN (0) + +/*************************************************************************/ + +/**************************** JL2XXX-RXC_OUT *****************************/ +/* PHY Rx Clock Out Control Mode Enable Mask Select */ +#define JL2XXX_RXC_OUT_STATIC_OP_EN (1 << 0) +//-----------------------------------------------------------------------// +/* PHY Rx Clock Out Control Mode Enable Mask Config */ +#define JL2XXX_RXC_OUT_CTRL_EN (0) + +/*************************************************************************/ +#endif diff --git a/drivers/net/phy/jlsemi.c b/drivers/net/phy/jlsemi.c new file mode 100644 index 000000000..73281a6e8 --- /dev/null +++ b/drivers/net/phy/jlsemi.c @@ -0,0 +1,577 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * drivers/net/phy/jlsemi.c + * + * Driver for JLSemi PHYs + * + * Author: Gangqiao Kuang + * + * Copyright (c) 2021 JingLue Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ +#include "jlsemi-core.h" +#include +#include +#include + +#define DRIVER_VERSION "1.2.9" +#define DRIVER_NAME_100M "JL1xxx Fast Ethernet " DRIVER_VERSION +#define DRIVER_NAME_1000M "JL2xxx Gigabit Ethernet " DRIVER_VERSION + +MODULE_DESCRIPTION("JLSemi PHY driver"); +MODULE_AUTHOR("Gangqiao Kuang"); +MODULE_LICENSE("GPL"); + +#if (JLSEMI_DEBUG_INFO) +static int jlsemi_phy_reg_print(struct phy_device *phydev) +{ + int ret; + int i; + + for (i = 0; i < ARRAY_SIZE(jl_phy); i++) { + if (jl_phy[i].enable) { + ret = jlsemi_read_paged(phydev, jl_phy[i].page, + jl_phy[i].reg); + JLSEMI_PHY_MSG("%s: 0x%x\n", jl_phy[i].string, ret); + if (ret < 0) + return ret; + } + } + + return 0; +} +#endif + +static int jl1xxx_probe(struct phy_device *phydev) +{ + struct device *dev = jlsemi_get_mdio(phydev); + struct jl1xxx_priv *jl1xxx = NULL; + int err; + + jl1xxx = devm_kzalloc(dev, sizeof(*jl1xxx), GFP_KERNEL); + if (!jl1xxx) + return -ENOMEM; + + phydev->priv = jl1xxx; + +#if (JLSEMI_KERNEL_DEVICE_TREE_USE) + if (!dev->of_node) + JLSEMI_PHY_MSG("%s: Find device node failed\n", __func__); +#endif + err = jl1xxx_operation_args_get(phydev); + if (err < 0) + return err; + + if (jl1xxx->intr.enable & JL1XXX_INTR_STATIC_OP_EN) + phydev->irq = JL1XXX_INTR_IRQ; + + jl1xxx->static_inited = false; + + return 0; +} + +static int jl1xxx_config_init(struct phy_device *phydev) +{ + struct jl1xxx_priv *priv = phydev->priv; + int ret; + + if (!priv->static_inited) { +#if (JLSEMI_DEBUG_INFO) + JLSEMI_PHY_MSG("jl1xxx_config_init_before:\n"); + ret = jlsemi_phy_reg_print(phydev); + if (ret < 0) + return ret; +#endif + ret = jl1xxx_static_op_init(phydev); + if (ret < 0) + return ret; +#if (JLSEMI_DEBUG_INFO) + JLSEMI_PHY_MSG("jl1xxx_config_init_after:\n"); + ret = jlsemi_phy_reg_print(phydev); + if (ret < 0) + return ret; +#endif + priv->static_inited = JLSEMI_PHY_NOT_REENTRANT; + } + + return 0; +} + +static int jl1xxx_ack_interrupt(struct phy_device *phydev) +{ + int err; + + err = jl1xxx_intr_ack_event(phydev); + if (err < 0) + return err; + + return 0; +} + +static int jl1xxx_config_intr(struct phy_device *phydev) +{ + struct jl1xxx_priv *priv = phydev->priv; + int err; + + if (priv->intr.enable & JL1XXX_INTR_STATIC_OP_EN) { + err = jl1xxx_ack_interrupt(phydev); + if (err < 0) + return err; + + err = jl1xxx_intr_static_op_set(phydev); + if (err < 0) + return err; + } + + return 0; +} + +static int jl1xxx_read_status(struct phy_device *phydev) +{ + struct jl1xxx_priv *priv = phydev->priv; + int err; + + if (priv->intr.enable & JL1XXX_INTR_STATIC_OP_EN) { + err = jl1xxx_ack_interrupt(phydev); + if (err < 0) + return err; + } + + return genphy_read_status(phydev); +} + +static void jl1xxx_remove(struct phy_device *phydev) +{ + struct device *dev = jlsemi_get_mdio(phydev); + struct jl1xxx_priv *priv = phydev->priv; + + if (priv) + devm_kfree(dev, priv); +} + +#if (JLSEMI_PHY_WOL) +static void jl1xxx_get_wol(struct phy_device *phydev, + struct ethtool_wolinfo *wol) +{ + struct jl1xxx_priv *priv = phydev->priv; + int wol_en; + + if (priv->wol.ethtool) { + wol->supported = WAKE_MAGIC; + wol->wolopts = 0; + + wol_en = jl1xxx_wol_dynamic_op_get(phydev); + + if (!wol_en) + wol->wolopts |= WAKE_MAGIC; + } +} + +static int jl1xxx_set_wol(struct phy_device *phydev, + struct ethtool_wolinfo *wol) +{ + struct jl1xxx_priv *priv = phydev->priv; + int err; + + if (priv->wol.ethtool) { + if (wol->wolopts & WAKE_MAGIC) { + err = jl1xxx_wol_dynamic_op_set(phydev); + if (err < 0) + return err; + } + } + + return 0; +} +#endif + +static int jl1xxx_suspend(struct phy_device *phydev) +{ + return genphy_suspend(phydev); +} + +static int jl1xxx_resume(struct phy_device *phydev) +{ + return genphy_resume(phydev); +} + +static int jl2xxx_probe(struct phy_device *phydev) +{ + struct device *dev = jlsemi_get_mdio(phydev); + struct jl2xxx_priv *jl2xxx = NULL; + int err; + + jl2xxx = devm_kzalloc(dev, sizeof(*jl2xxx), GFP_KERNEL); + if (!jl2xxx) + return -ENOMEM; + + phydev->priv = jl2xxx; + +#if (JLSEMI_KERNEL_DEVICE_TREE_USE) + if (!dev->of_node) + JLSEMI_PHY_MSG("%s: Find device node failed\n", __func__); +#endif + err = jl2xxx_operation_args_get(phydev); + if (err < 0) + return err; + + if (jl2xxx->intr.enable & JL2XXX_INTR_STATIC_OP_EN) + phydev->irq = JL2XXX_INTR_IRQ; + + jl2xxx->static_inited = false; + jl2xxx->nstats = ARRAY_SIZE(jl2xxx_hw_stats); + jl2xxx->hw_stats = jl2xxx_hw_stats; + jl2xxx->stats = kcalloc(jl2xxx->nstats, sizeof(u64), GFP_KERNEL); + if (!jl2xxx->stats) + return -ENOMEM; + + return 0; +} + +static int jl2xxx_config_init(struct phy_device *phydev) +{ + struct jl2xxx_priv *priv = phydev->priv; + int ret; + + if (!priv->static_inited) { +#if (JLSEMI_DEBUG_INFO) + JLSEMI_PHY_MSG("jl2xxx_config_init_before:\n"); + ret = jlsemi_phy_reg_print(phydev); + if (ret < 0) + return ret; +#endif + ret = jl2xxx_static_op_init(phydev); + if (ret < 0) + return ret; +#if (JLSEMI_DEBUG_INFO) + JLSEMI_PHY_MSG("jl2xxx_config_init_after:\n"); + ret = jlsemi_phy_reg_print(phydev); + if (ret < 0) + return ret; +#endif + priv->static_inited = JLSEMI_PHY_NOT_REENTRANT; + } + + return 0; +} + +static int jl2xxx_ack_interrupt(struct phy_device *phydev) +{ + int err; + + err = jl2xxx_intr_ack_event(phydev); + if (err < 0) + return err; + + return 0; +} + +static int jl2xxx_config_intr(struct phy_device *phydev) +{ + struct jl2xxx_priv *priv = phydev->priv; + int err; + + if (priv->intr.enable & JL2XXX_INTR_STATIC_OP_EN) { + err = jl2xxx_ack_interrupt(phydev); + if (err < 0) + return err; + + err = jl2xxx_intr_static_op_set(phydev); + if (err < 0) + return err; + } + + return 0; +} + +static int jl2xxx_read_status(struct phy_device *phydev) +{ + struct jl2xxx_priv *priv = phydev->priv; + bool fiber_mode; + int err; + + if (priv->intr.enable & JL2XXX_INTR_STATIC_OP_EN) { + err = jl2xxx_ack_interrupt(phydev); + if (err < 0) + return err; + } + + fiber_mode = jl2xxx_read_fiber_status(phydev); + if (fiber_mode) + return 0; + + return genphy_read_status(phydev); +} + +static int jl1xxx_config_aneg(struct phy_device *phydev) +{ + return genphy_config_aneg(phydev); +} + +static int jl2xxx_config_aneg(struct phy_device *phydev) +{ + u16 phy_mode; + int val; + + val = jlsemi_read_paged(phydev, JL2XXX_PAGE18, + JL2XXX_WORK_MODE_REG); + phy_mode = val & JL2XXX_WORK_MODE_MASK; + + if (phydev->interface == PHY_INTERFACE_MODE_SGMII) + return 0; + + if ((phydev->interface != PHY_INTERFACE_MODE_SGMII) && + ((phy_mode == JL2XXX_FIBER_RGMII_MODE) || + (phy_mode == JL2XXX_UTP_FIBER_RGMII_MODE))) + return jl2xxx_config_aneg_fiber(phydev); + + return genphy_config_aneg(phydev); +} + +static int jl2xxx_suspend(struct phy_device *phydev) +{ + return genphy_suspend(phydev); +} + +static int jl2xxx_resume(struct phy_device *phydev) +{ + return genphy_resume(phydev); +} + +#if (JLSEMI_PHY_WOL) +static void jl2xxx_get_wol(struct phy_device *phydev, + struct ethtool_wolinfo *wol) +{ + struct jl2xxx_priv *priv = phydev->priv; + int wol_en; + + if (priv->wol.ethtool) { + wol->supported = WAKE_MAGIC; + wol->wolopts = 0; + + wol_en = jl2xxx_wol_dynamic_op_get(phydev); + + if (wol_en) + wol->wolopts |= WAKE_MAGIC; + } +} + +static int jl2xxx_set_wol(struct phy_device *phydev, + struct ethtool_wolinfo *wol) +{ + struct jl2xxx_priv *priv = phydev->priv; + int err; + + if (priv->wol.ethtool) { + if (wol->wolopts & WAKE_MAGIC) { + err = jl2xxx_wol_dynamic_op_set(phydev); + if (err < 0) + return err; + } + } + + return 0; +} +#endif + +#if (JL2XXX_PHY_TUNABLE) +static int jl2xxx_get_tunable(struct phy_device *phydev, + struct ethtool_tunable *tuna, void *data) +{ + struct jl2xxx_priv *priv = phydev->priv; + + switch (tuna->id) { + case ETHTOOL_PHY_FAST_LINK_DOWN: + if (priv->fld.ethtool) + return jl2xxx_fld_dynamic_op_get(phydev, data); + else + return 0; + case ETHTOOL_PHY_DOWNSHIFT: + if (priv->downshift.ethtool) + return jl2xxx_downshift_dynamic_op_get(phydev, data); + else + return 0; + default: + return -EOPNOTSUPP; + } + + return 0; +} + +static int jl2xxx_set_tunable(struct phy_device *phydev, + struct ethtool_tunable *tuna, const void *data) +{ + struct jl2xxx_priv *priv = phydev->priv; + + switch (tuna->id) { + case ETHTOOL_PHY_FAST_LINK_DOWN: + if (priv->fld.ethtool) + return jl2xxx_fld_dynamic_op_set(phydev, data); + else + return 0; + case ETHTOOL_PHY_DOWNSHIFT: + if (priv->downshift.ethtool) + return jl2xxx_downshift_dynamic_op_set(phydev, + *(const u8 *)data); + else + return 0; + default: + return -EOPNOTSUPP; + } + + return 0; +} +#endif + +#if (JL2XXX_GET_STAT) +static u64 get_stat(struct phy_device *phydev, int i) +{ + struct jl2xxx_priv *priv = phydev->priv; + int val; + + val = jlsemi_read_paged(phydev, priv->hw_stats[i].page, + priv->hw_stats[i].reg); + if (val < 0) + return U64_MAX; + + val = val & priv->hw_stats[i].mask; + priv->stats[i] += val; + + return priv->stats[i]; +} + +static void jl2xxx_get_stats(struct phy_device *phydev, + struct ethtool_stats *stats, u64 *data) +{ + struct jl2xxx_priv *priv = phydev->priv; + int i; + + if (!priv) + return; + + for (i = 0; i < priv->nstats; i++) + data[i] = get_stat(phydev, i); +} +#endif + +#if (JL2XXX_GET_STRING) +static void jl2xxx_get_strings(struct phy_device *phydev, u8 *data) +{ + struct jl2xxx_priv *priv = phydev->priv; + int i; + + if (!priv) + return; + + for (i = 0; i < priv->nstats; i++) + strlcpy(data + i * ETH_GSTRING_LEN, + priv->hw_stats[i].string, ETH_GSTRING_LEN); +} +#endif + +static void jl2xxx_remove(struct phy_device *phydev) +{ + struct device *dev = jlsemi_get_mdio(phydev); + struct jl2xxx_priv *priv = phydev->priv; + + kfree(priv->stats); + if (priv) + devm_kfree(dev, priv); +} + +static inline int jlsemi_aneg_done(struct phy_device *phydev) +{ + int retval = phy_read(phydev, MII_BMSR); + + return (retval < 0) ? retval : (retval & BMSR_ANEGCOMPLETE); +} + +static int jl2xxx_aneg_done(struct phy_device *phydev) +{ + u16 phy_mode; + int val; + + val = jlsemi_read_paged(phydev, JL2XXX_PAGE18, + JL2XXX_WORK_MODE_REG); + phy_mode = val & JL2XXX_WORK_MODE_MASK; + + if (phydev->interface == PHY_INTERFACE_MODE_SGMII) + return 0; + + // fiber not an complite + if ((phydev->interface != PHY_INTERFACE_MODE_SGMII) && + ((phy_mode == JL2XXX_FIBER_RGMII_MODE) || + (phy_mode == JL2XXX_UTP_FIBER_RGMII_MODE))) + return BMSR_ANEGCOMPLETE; + + return jlsemi_aneg_done(phydev); +} + + +static struct phy_driver jlsemi_drivers[] = { + { + .phy_id = JL1XXX_PHY_ID, + .phy_id_mask = JLSEMI_PHY_ID_MASK, + .name = DRIVER_NAME_100M, + /* PHY_BASIC_FEATURES */ + .features = PHY_BASIC_FEATURES, + .probe = jl1xxx_probe, + .config_intr = jl1xxx_config_intr, + .read_status = jl1xxx_read_status, + .config_init = jl1xxx_config_init, + .config_aneg = jl1xxx_config_aneg, + .aneg_done = jlsemi_aneg_done, + .suspend = jl1xxx_suspend, + .resume = jl1xxx_resume, + .remove = jl1xxx_remove, +#if (JLSEMI_PHY_WOL) + .get_wol = jl1xxx_get_wol, + .set_wol = jl1xxx_set_wol, +#endif + }, + { + .phy_id = JL2XXX_PHY_ID, + .phy_id_mask = JLSEMI_PHY_ID_MASK, + .name = DRIVER_NAME_1000M, + /* PHY_BASIC_FEATURES */ + .features = PHY_GBIT_FEATURES, + .probe = jl2xxx_probe, + .config_intr = jl2xxx_config_intr, + .read_status = jl2xxx_read_status, + .config_init = jl2xxx_config_init, + .config_aneg = jl2xxx_config_aneg, + .aneg_done = jl2xxx_aneg_done, + .suspend = jl2xxx_suspend, + .resume = jl2xxx_resume, + .remove = jl2xxx_remove, +#if (JLSEMI_PHY_WOL) + .get_wol = jl2xxx_get_wol, + .set_wol = jl2xxx_set_wol, +#endif +#if (JL2XXX_PHY_TUNABLE) + .get_tunable = jl2xxx_get_tunable, + .set_tunable = jl2xxx_set_tunable, +#endif +#if (JL2XXX_GET_STAT) + .get_stats = jl2xxx_get_stats, +#endif +#if (JL2XXX_GET_STRING) + .get_strings = jl2xxx_get_strings, +#endif + }, +}; + +module_jlsemi_driver(jlsemi_drivers); + +static struct mdio_device_id __maybe_unused jlsemi_tbl[] = { + {JL1XXX_PHY_ID, JLSEMI_PHY_ID_MASK}, + {JL2XXX_PHY_ID, JLSEMI_PHY_ID_MASK}, + { } +}; + +MODULE_DEVICE_TABLE(mdio, jlsemi_tbl); diff --git a/include/dt-bindings/phy/jlsemi-dt-phy.h b/include/dt-bindings/phy/jlsemi-dt-phy.h new file mode 100644 index 000000000..0a6e2210e --- /dev/null +++ b/include/dt-bindings/phy/jlsemi-dt-phy.h @@ -0,0 +1,341 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Device Tree constants for JLSemi PHY + * + * Author: Gangqiao Kuang + * + * Copyright (c) 2021 JLSemi Corporation + */ + +#ifndef _DT_BINDINGS_JLSEMI_PHY_H +#define _DT_BINDINGS_JLSEMI_PHY_H + +/**************************** Linux Version Compatible ********************/ +#define JLSEMI_DEV_COMPATIBLE (KERNEL_VERSION(4, 5, 0) > LINUX_VERSION_CODE) +#define JL2XXX_GET_STRING (KERNEL_VERSION(4, 5, 0) <= LINUX_VERSION_CODE) +#define JL2XXX_GET_STAT (KERNEL_VERSION(4, 5, 0) <= LINUX_VERSION_CODE) +#define JL2XXX_PHY_TUNABLE (KERNEL_VERSION(5, 0, 0) <= LINUX_VERSION_CODE) +#define JLSEMI_PHY_WOL (KERNEL_VERSION(3, 10, 0) < LINUX_VERSION_CODE) +/*************************************************************************/ + +/**************************** JLSemi Debug *******************************/ +#define JLSEMI_DEBUG_INFO 0 +/*************************************************************************/ + +/************************* JLSemi Phy Init Reentrant *********************/ +#define JLSEMI_PHY_NOT_REENTRANT false +/*************************************************************************/ + +/**************************** JL1XXX-LED *********************************/ +/* PHY LED Modes Select */ +#define JL1XXX_LED0_STRAP (1 << 0) +#define JL1XXX_LED0_EEE (1 << 1) +#define JL1XXX_LED0_100_ACTIVITY (1 << 2) +#define JL1XXX_LED0_10_ACTIVITY (1 << 3) +#define JL1XXX_LED0_100_LINK (1 << 4) +#define JL1XXX_LED0_10_LINK (1 << 5) +#define JL1XXX_LED1_STRAP (1 << 8) +#define JL1XXX_LED1_EEE (1 << 9) +#define JL1XXX_LED1_100_ACTIVITY (1 << 10) +#define JL1XXX_LED1_10_ACTIVITY (1 << 11) +#define JL1XXX_LED1_100_LINK (1 << 12) +#define JL1XXX_LED1_10_LINK (1 << 13) + +/* PHY LED As Gpio Output Select */ +#define JL1XXX_GPIO_LED0_OUT (1 << 2) +#define JL1XXX_GPIO_LED1_OUT (1 << 3) +#define JL1XXX_GPIO_LED0_EN (1 << 14) +#define JL1XXX_GPIO_LED1_EN (1 << 15) + +/* PHY LED Control Enable Mask Select */ +#define JL1XXX_LED_STATIC_OP_EN (1 << 0) +#define JL1XXX_LED_MODE_EN (1 << 1) +#define JL1XXX_LED_GLOABL_PERIOD_EN (1 << 2) +#define JL1XXX_LED_GLOBAL_ON_EN (1 << 3) +#define JL1XXX_LED_GPIO_OUT_EN (1 << 4) +//-----------------------------------------------------------------------// +/* PHY LED Control Enable Mask Config */ +#define JL1XXX_LED_CTRL_EN (0) + +/* PHY LED Modes Config */ +#define JL1XXX_CFG_LED_MODE (JL1XXX_LED0_100_LINK | \ + JL1XXX_LED0_10_LINK | \ + JL1XXX_LED1_100_ACTIVITY | \ + JL1XXX_LED1_10_ACTIVITY) + +/* PHY LED As Gpio Output Config */ +#define JL1XXX_CFG_GPIO (JL1XXX_GPIO_LED0_EN | \ + JL1XXX_GPIO_LED0_OUT | \ + JL1XXX_GPIO_LED1_EN | \ + JL1XXX_GPIO_LED1_OUT) + +/* PHY LED Global Period Config */ +#define JL1XXX_GLOBAL_PERIOD_MS 0x10 + +/* PHY LED Global Hold On Config */ +#define JL1XXX_GLOBAL_ON_MS 0x8 +/**************************************************************************/ + +/****************************** JL1XXX-WOL ********************************/ +/* PHY WOL Control Enable Mask Select */ +#define JL1XXX_WOL_STATIC_OP_EN (1 << 0) +//-----------------------------------------------------------------------// +/* PHY WOL Control Enable Mask Config */ +#define JL1XXX_WOL_CTRL_EN (0) + +/*************************************************************************/ + +/***************************** JL1XXX-INTR *******************************/ +/* PHY Interrupt Control Enable Mask Select */ +#define JL1XXX_INTR_STATIC_OP_EN (1 << 0) +#define JL1XXX_INTR_LINK_CHANGE_EN (1 << 1) +#define JL1XXX_INTR_AN_ERR_EN (1 << 2) +//-----------------------------------------------------------------------// +/* PHY Interrupt Irq Number Config */ +#define JL1XXX_INTR_IRQ -1 + +/* PHY Interrupt Control Enable Mask Config */ +#define JL1XXX_INTR_CTRL_EN (0) +/*************************************************************************/ + +/**************************** JL1XXX-MDI *********************************/ +/* PHY MDI Control Mode Enable Mask Select */ +#define JL1XXX_MDI_STATIC_OP_EN (1 << 0) +#define JL1XXX_MDI_RATE_EN (1 << 1) +#define JL1XXX_MDI_AMPLITUDE_EN (1 << 2) + +/* PHY MDI Rate Select */ +#define JL1XXX_MDI_RATE_STANDARD 0 +#define JL1XXX_MDI_RATE_ACCELERATE 1 + +/* PHY MDI Amplitude Select */ +#define JL1XXX_MDI_AMPLITUDE0 0 +#define JL1XXX_MDI_AMPLITUDE1 1 +#define JL1XXX_MDI_AMPLITUDE2 2 +#define JL1XXX_MDI_AMPLITUDE3 3 +#define JL1XXX_MDI_AMPLITUDE4 4 +#define JL1XXX_MDI_AMPLITUDE5 5 +#define JL1XXX_MDI_AMPLITUDE6 6 +#define JL1XXX_MDI_AMPLITUDE7 7 +//-----------------------------------------------------------------------// +/* PHY MDI Control Mode Enable Mask Config */ +#define JL1XXX_MDI_CTRL_EN (0) + +/* PHY MDI Rate Config */ +#define JL1XXX_MDI_RATE JL1XXX_MDI_RATE_ACCELERATE + +/* PHY MDI Amplitude Config */ +#define JL1XXX_MDI_AMPLITUDE JL1XXX_MDI_AMPLITUDE4 + +/*************************************************************************/ + +/**************************** JL1XXX-RMII ********************************/ +/* PHY RMII Control Mode Enable Mask Select */ +#define JL1XXX_RMII_STATIC_OP_EN (1 << 0) +#define JL1XXX_RMII_MODE_EN (1 << 1) +#define JL1XXX_RMII_CLK_50M_INPUT_EN (1 << 2) +#define JL1XXX_RMII_TX_SKEW_EN (1 << 3) +#define JL1XXX_RMII_RX_SKEW_EN (1 << 4) +#define JL1XXX_RMII_CRS_DV_EN (1 << 5) +//-----------------------------------------------------------------------// +/* PHY RMII Control Mode Enable Mask Config */ +#define JL1XXX_RMII_CTRL_EN (0) + +/* PHY RMII Timing Config */ +#define JL1XXX_RMII_TX_TIMING 0xf +#define JL1XXX_RMII_RX_TIMING 0xf + +/*************************************************************************/ + +/**************************** JL2XXX-LED *********************************/ +/* PHY LED Modes Select*/ +#define JL2XXX_LED0_LINK10 (1 << 0) +#define JL2XXX_LED0_LINK100 (1 << 1) +#define JL2XXX_LED0_LINK1000 (1 << 3) +#define JL2XXX_LED0_ACTIVITY (1 << 4) +#define JL2XXX_LED1_LINK10 (1 << 5) +#define JL2XXX_LED1_LINK100 (1 << 6) +#define JL2XXX_LED1_LINK1000 (1 << 8) +#define JL2XXX_LED1_ACTIVITY (1 << 9) +#define JL2XXX_LED2_LINK10 (1 << 10) +#define JL2XXX_LED2_LINK100 (1 << 11) +#define JL2XXX_LED2_LINK1000 (1 << 13) +#define JL2XXX_LED2_ACTIVITY (1 << 14) +/* mode_A = 0 and mode_B = 1 default mode_A */ +#define JL2XXX_LED_GLB_MODE_B (1 << 15) + +/* PHY LED Polarity Select */ +#define JL2XXX_LED0_POLARITY (1 << 12) +#define JL2XXX_LED1_POLARITY (1 << 11) +#define JL2XXX_LED2_POLARITY (1 << 10) + +/* PHY LED Control Enable Mask Select */ +#define JL2XXX_LED_STATIC_OP_EN (1 << 0) +#define JL2XXX_LED_MODE_EN (1 << 1) +#define JL2XXX_LED_GLOABL_PERIOD_EN (1 << 2) +#define JL2XXX_LED_GLOBAL_ON_EN (1 << 3) +#define JL2XXX_LED_POLARITY_EN (1 << 4) + +//-----------------------------------------------------------------------// +/* PHY LED Control Enable Mask Config */ +#define JL2XXX_LED_CTRL_EN (0) + +/* PHY LED Modes Config */ +#define JL2XXX_CFG_LED_MODE (JL2XXX_LED0_LINK10 | \ + JL2XXX_LED0_ACTIVITY | \ + JL2XXX_LED1_LINK100 | \ + JL2XXX_LED1_ACTIVITY | \ + JL2XXX_LED2_LINK1000 | \ + JL2XXX_LED2_ACTIVITY) + +/* PHY LED Polarity Config */ +#define JL2XXX_LED_POLARITY (JL2XXX_LED0_POLARITY | \ + JL2XXX_LED1_POLARITY | \ + JL2XXX_LED2_POLARITY) + +/* PHY LED Global Period Config */ +#define JL2XXX_GLOBAL_PERIOD_MS 0x3 + +/* PHY LED Global Hold On Config */ +#define JL2XXX_GLOBAL_ON_MS 0x2 +/*************************************************************************/ + +/**************************** JL2XXX-FLD *********************************/ +/* PHY Fast Link Down Control Enable Mask Select */ +#define JL2XXX_FLD_STATIC_OP_EN (1 << 0) +//-----------------------------------------------------------------------// +/* PHY Fast Link Down Control Enable Mask Config */ +#define JL2XXX_FLD_CTRL_EN (0) + +/* PHY Fast Link Down Delay Config */ +#define JL2XXX_FLD_DELAY 0 +/*************************************************************************/ + +/**************************** JL2XXX-WOL *********************************/ +/* PHY WOL Control Enable Mask Select */ +#define JL2XXX_WOL_STATIC_OP_EN (1 << 0) + +//-----------------------------------------------------------------------// +/* PHY WOL Control Enable Mask Config */ +#define JL2XXX_WOL_CTRL_EN (0) +/*************************************************************************/ + +/**************************** JL2XXX-INTR ********************************/ +/* PHY Interrupt Control Enable Mask Select */ +#define JL2XXX_INTR_STATIC_OP_EN (1 << 0) +#define JL2XXX_INTR_LINK_CHANGE_EN (1 << 1) +#define JL2XXX_INTR_AN_ERR_EN (1 << 2) +#define JL2XXX_INTR_AN_COMPLETE_EN (1 << 3) +#define JL2XXX_INTR_AN_PAGE_RECE (1 << 4) +//-----------------------------------------------------------------------// +/* PHY Interrupt Irq Number Config */ +#define JL2XXX_INTR_IRQ -1 + +/* PHY Interrupt Control Enable Mask Config */ +#define JL2XXX_INTR_CTRL_EN (0) +/*************************************************************************/ + +/**************************** JL2XXX-DSFT ********************************/ +/* PHY Downshift Control Enable Mask */ +#define JL2XXX_DSFT_STATIC_OP_EN (1 << 0) +//-----------------------------------------------------------------------// +/* PHY Downshift Control Enable Config */ +#define JL2XXX_DSFT_CTRL_EN (0) + +/* PHY Downshift Count Config */ +#define JL2XXX_DSFT_AN_CNT 4 +/*************************************************************************/ + +/**************************** JL2XXX-RGMII *******************************/ +/* PHY RGMII Control Mode Enable Mask Select */ +#define JL2XXX_RGMII_STATIC_OP_EN (1 << 0) +#define JL2XXX_RGMII_TX_DLY_EN (1 << 1) +#define JL2XXX_RGMII_RX_DLY_EN (1 << 2) +/* PHY RGMII DELAY BIT */ +#define JL2XXX_RGMII_TX_DLY_2NS (1 << 8) +#define JL2XXX_RGMII_RX_DLY_2NS (1 << 9) +//-----------------------------------------------------------------------// +/* PHY RGMII Control Mode Enable Mask Config */ +#define JL2XXX_RGMII_CTRL_EN (0) + +/*************************************************************************/ + +/**************************** JL2XXX-PATCH *******************************/ +/* PHY Patch Control Mode Enable Mask Select */ +#define JL2XXX_PATCH_STATIC_OP_EN (1 << 0) +//-----------------------------------------------------------------------// +/* PHY Patch Control Mode Enable Mask Config */ +#define JL2XXX_PATCH_CTRL_EN (JL2XXX_PATCH_STATIC_OP_EN) + +/*************************************************************************/ + +/**************************** JL2XXX-CLOCK *******************************/ +/* PHY Clock Control Mode Enable Mask Select */ +#define JL2XXX_CLK_STATIC_OP_EN (1 << 0) +#define JL2XXX_25M_CLK_OUT_EN (1 << 1) +#define JL2XXX_125M_CLK_OUT_EN (1 << 2) +#define JL2XXX_CLK_OUT_DIS (1 << 3) +//-----------------------------------------------------------------------// +/* PHY Clock Control Mode Enable Mask Config */ +#define JL2XXX_CLK_CTRL_EN (0) + +/*************************************************************************/ + +/**************************** JL2XXX-WORK_MODE ***************************/ +/* PHY Work Mode Control Mode Enable Mask Select */ +#define JL2XXX_WORK_MODE_STATIC_OP_EN (1 << 0) + +/* PHY Work Mode Select */ +#define JL2XXX_UTP_RGMII_MODE 0 +#define JL2XXX_FIBER_RGMII_MODE 1 +#define JL2XXX_UTP_FIBER_RGMII_MODE 2 +#define JL2XXX_UTP_SGMII_MODE 3 +#define JL2XXX_PHY_SGMII_RGMII_MODE 4 +#define JL2XXX_MAC_SGMII_RGMII_MODE 5 +#define JL2XXX_UTP_FIBER_FORCE_MODE1 6 +#define JL2XXX_UTP_FIBER_FORCE_MODE2 7 +//-----------------------------------------------------------------------// +/* PHY Work Mode Control Mode Enable Mask Config */ +#define JL2XXX_WORK_MODE_CTRL_EN (0) + +/* PHY Work Mode Config */ +#define JL2XXX_WORK_MODE_MODE JL2XXX_UTP_RGMII_MODE + +/*************************************************************************/ + +/**************************** JL2XXX-LOOPBACK ****************************/ +/* PHY Loopback Control Mode Enable Mask Select */ +#define JL2XXX_LPBK_STATIC_OP_EN (1 << 0) + +/* PHY Loopback Mode Select */ +#define JL2XXX_LPBK_PCS_10M 0 +#define JL2XXX_LPBK_PCS_100M 1 +#define JL2XXX_LPBK_PCS_1000M 2 +#define JL2XXX_LPBK_PMD_1000M 3 +#define JL2XXX_LPBK_EXT_STUB_1000M 4 +//-----------------------------------------------------------------------// +/* PHY Loopback Control Mode Enable Mask Config */ +#define JL2XXX_LPBK_CTRL_EN (0) + +/* PHY Loopback Mode Config */ +#define JL2XXX_LPBK_MODE JL2XXX_LPBK_PCS_1000M +/*************************************************************************/ + +/**************************** JL2XXX-SLEW_RATE ****************************/ +/* PHY Slew Rate Control Mode Enable Mask Select */ +#define JL2XXX_SLEW_RATE_STATIC_OP_EN (1 << 0) +//-----------------------------------------------------------------------// +/* PHY Slew Rate Control Mode Enable Mask Config */ +#define JL2XXX_SLEW_RATE_CTRL_EN (0) + +/*************************************************************************/ + +/**************************** JL2XXX-RXC_OUT *****************************/ +/* PHY Rx Clock Out Control Mode Enable Mask Select */ +#define JL2XXX_RXC_OUT_STATIC_OP_EN (1 << 0) +//-----------------------------------------------------------------------// +/* PHY Rx Clock Out Control Mode Enable Mask Config */ +#define JL2XXX_RXC_OUT_CTRL_EN (0) + +/*************************************************************************/ +#endif