// 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