From 94e7b85e4a801e55240a35ea08ee1060abdfe567 Mon Sep 17 00:00:00 2001 From: fengying0347 Date: Thu, 13 Jan 2022 21:38:33 +0800 Subject: [PATCH] rockchip: add support for Motorcomm YT8531(S) PHY Fixes: #8719, #8763 --- ...Add-driver-for-Motorcomm-YT8531-PHYs.patch | 475 ++++ ...Add-driver-for-Motorcomm-YT85xx-PHYs.patch | 1967 +---------------- ...Add-driver-for-Motorcomm-YT8531-PHYs.patch | 475 ++++ 3 files changed, 1008 insertions(+), 1909 deletions(-) create mode 100644 target/linux/rockchip/patches-5.10/601-net-phy-Add-driver-for-Motorcomm-YT8531-PHYs.patch create mode 100644 target/linux/rockchip/patches-5.4/601-net-phy-Add-driver-for-Motorcomm-YT8531-PHYs.patch diff --git a/target/linux/rockchip/patches-5.10/601-net-phy-Add-driver-for-Motorcomm-YT8531-PHYs.patch b/target/linux/rockchip/patches-5.10/601-net-phy-Add-driver-for-Motorcomm-YT8531-PHYs.patch new file mode 100644 index 000000000..9b9c46dfb --- /dev/null +++ b/target/linux/rockchip/patches-5.10/601-net-phy-Add-driver-for-Motorcomm-YT8531-PHYs.patch @@ -0,0 +1,475 @@ +From abf36eb72942657cef05ebcb2897eaea9064ad06 Mon Sep 17 00:00:00 2001 +From: From: fengying0347 +Date: Thu, 13 Jan 2022 12:59:36 +0800 +Subject: [PATCH] net: phy: Add driver for Motorcomm YT8531(S) PHYs + +--- + .../net/ethernet/stmicro/stmmac/stmmac_main.c | 82 ++++++++ + drivers/net/phy/motorcomm.c | 181 +++++++++++++++++- + drivers/net/phy/phy_device.c | 83 ++++++++ + include/linux/motorcomm_phy.h | 5 + + 4 files changed, 350 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +index 8dc4def..bcd46ca 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c ++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +@@ -121,6 +121,10 @@ static void stmmac_exit_fs(struct net_device *dev); + + #define STMMAC_COAL_TIMER(x) (jiffies + usecs_to_jiffies(x)) + ++#define RTL_8211E_PHY_ID 0x001cc915 ++#define RTL_8211F_PHY_ID 0x001cc916 ++#define YT_8531C_PHY_ID 0x4f51e91b ++ + int stmmac_bus_clks_config(struct stmmac_priv *priv, bool enabled) + { + int ret = 0; +@@ -4950,6 +4954,74 @@ int stmmac_reinit_ringparam(struct net_device *dev, u32 rx_size, u32 tx_size) + return ret; + } + ++static int phy_rtl8211e_led_fixup(struct phy_device *phydev) ++{ ++ int val; ++ ++ printk("%s in\n", __func__); ++ ++ /*switch to extension page44*/ ++ phy_write(phydev, 31, 0x07); ++ phy_write(phydev, 30, 0x2c); ++ ++ /*set led1(yellow) act*/ ++ val = phy_read(phydev, 26); ++ val &= (~(1<<4));// bit4=0 ++ val |= (1<<5);// bit5=1 ++ val &= (~(1<<6));// bit6=0 ++ phy_write(phydev, 26, val); ++ ++ /*set led0(green) link*/ ++ val = phy_read(phydev, 28); ++ val |= (7<<0);// bit0,1,2=1 ++ val &= (~(7<<4));// bit4,5,6=0 ++ val &= (~(7<<8));// bit8,9,10=0 ++ phy_write(phydev, 28, val); ++ ++ /*switch back to page0*/ ++ phy_write(phydev,31,0x00); ++ ++ return 0; ++} ++ ++static int phy_rtl8211f_led_fixup(struct phy_device *phydev) ++{ ++ int val; ++ ++ printk("%s in\n", __func__); ++ ++ /*switch to extension page 0xd04*/ ++ phy_write(phydev, 31, 0xd04); ++ ++ ++ /*set led1(yellow) act*/ ++ /*set led2(green) link*/ ++ val = 0xae00; ++ phy_write(phydev, 16, val); ++ ++ val = 0x0; ++ phy_write(phydev, 17, val); ++ /*switch back to page0*/ ++ phy_write(phydev,31,0x00); ++ ++ return 0; ++} ++ ++static int phy_yt8531_led_fixup(struct phy_device *phydev) ++{ ++ printk("%s in\n", __func__); ++ phy_write(phydev, 0x1e, 0xa00d); ++ phy_write(phydev, 0x1f, 0x670); ++ ++ phy_write(phydev, 0x1e, 0xa00e); ++ phy_write(phydev, 0x1f, 0x2070); ++ ++ phy_write(phydev, 0x1e, 0xa00f); ++ phy_write(phydev, 0x1f, 0x7e); ++ ++ return 0; ++} ++ + /** + * stmmac_dvr_probe + * @device: device pointer +@@ -5173,6 +5245,16 @@ int stmmac_dvr_probe(struct device *device, + netdev_err(ndev, "failed to setup phy (%d)\n", ret); + goto error_phy_setup; + } ++ /* register the PHY board fixup */ ++ ret = phy_register_fixup_for_uid(RTL_8211E_PHY_ID, 0xffffffff, phy_rtl8211e_led_fixup); ++ if (ret) ++ pr_warn("Cannot register PHY board fixup.\n"); ++ ret = phy_register_fixup_for_uid(RTL_8211F_PHY_ID, 0xffffffff, phy_rtl8211f_led_fixup); ++ if (ret) ++ pr_warn("Cannot register PHY board fixup.\n"); ++ ret = phy_register_fixup_for_uid(YT_8531C_PHY_ID, 0xffffffff, phy_yt8531_led_fixup); ++ if (ret) ++ pr_warn("Cannot register PHY board fixup.\n"); + + ret = register_netdev(ndev); + if (ret) { +diff --git a/drivers/net/phy/motorcomm.c b/drivers/net/phy/motorcomm.c +index 17a4f6c..e37dfb9 100644 +--- a/drivers/net/phy/motorcomm.c ++++ b/drivers/net/phy/motorcomm.c +@@ -26,6 +26,13 @@ + #include + #include + ++static int link_mode_8521 = 0; //0: no link; 1: utp; 32: fiber. traced that 1000m fiber uses 32. ++ ++int genphy_config_init(struct phy_device *phydev) ++{ ++ return genphy_read_abilities(phydev); ++} ++ + static int ytphy_read_ext(struct phy_device *phydev, u32 regnum) + { + int ret; +@@ -263,6 +270,38 @@ static int yt8521_config_intr(struct phy_device *phydev) + return phy_write(phydev, REG_INT_MASK, val); + } + ++static int yt8521_adjust_status(struct phy_device *phydev, int val, int is_utp) ++{ ++ int speed_mode, duplex; ++ ++ int speed = SPEED_UNKNOWN; ++ ++ duplex = (val & YT8512_DUPLEX) >> YT8521_DUPLEX_BIT; ++ speed_mode = (val & YT8521_SPEED_MODE) >> YT8521_SPEED_MODE_BIT; ++ switch (speed_mode) { ++ case 0: ++ if (is_utp) ++ speed = SPEED_10; ++ break; ++ case 1: ++ speed = SPEED_100; ++ break; ++ case 2: ++ speed = SPEED_1000; ++ break; ++ case 3: ++ break; ++ default: ++ speed = SPEED_UNKNOWN; ++ break; ++ } ++ ++ phydev->speed = speed; ++ phydev->duplex = duplex; ++ ++ return 0; ++} ++ + static int yt8521_ack_interrupt(struct phy_device *phydev) + { + int val; +@@ -273,6 +312,121 @@ static int yt8521_ack_interrupt(struct phy_device *phydev) + return (val < 0) ? val : 0; + } + ++static int yt8521_read_status(struct phy_device *phydev) ++{ ++ int ret; ++ volatile int val, yt8521_fiber_latch_val, yt8521_fiber_curr_val; ++ volatile int link; ++ int link_utp = 0, link_fiber = 0; ++ ++ /* reading UTP */ ++ ret = ytphy_write_ext(phydev, 0xa000, 0); ++ if (ret < 0) ++ return ret; ++ ++ val = phy_read(phydev, REG_PHY_SPEC_STATUS); ++ if (val < 0) ++ return val; ++ ++ link = val & (BIT(YT8521_LINK_STATUS_BIT)); ++ if (link) { ++ link_utp = 1; ++ link_mode_8521 = 1; ++ yt8521_adjust_status(phydev, val, 1); ++ } ++ else { ++ link_utp = 0; ++ } ++ ++ /* reading Fiber */ ++ ret = ytphy_write_ext(phydev, 0xa000, 2); ++ if (ret < 0) ++ return ret; ++ ++ val = phy_read(phydev, REG_PHY_SPEC_STATUS); ++ if (val < 0) ++ return val; ++ ++ //note: below debug information is used to check multiple PHy ports. ++ //printk (KERN_INFO "yt8521_read_status, fiber status=%04x,macbase=0x%08lx\n", val,(unsigned long)phydev->attached_dev); ++ ++ /* for fiber, from 1000m to 100m, there is not link down from 0x11, and check reg 1 to identify such case ++ * this is important for Linux kernel for that, missing linkdown event will cause problem. ++ */ ++ yt8521_fiber_latch_val = phy_read(phydev, MII_BMSR); ++ yt8521_fiber_curr_val = phy_read(phydev, MII_BMSR); ++ link = val & (BIT(YT8521_LINK_STATUS_BIT)); ++ if ((link) && (yt8521_fiber_latch_val != yt8521_fiber_curr_val)) ++ { ++ link = 0; ++ printk(KERN_INFO "yt8521_read_status, fiber link down detect,latch=%04x,curr=%04x\n", yt8521_fiber_latch_val, yt8521_fiber_curr_val); ++ } ++ ++ if (link) { ++ link_fiber = 1; ++ yt8521_adjust_status(phydev, val, 0); ++ link_mode_8521 = 32; //fiber mode ++ ++ ++ } ++ else { ++ link_fiber = 0; ++ } ++ ++ if (link_utp || link_fiber) { ++ phydev->link = 1; ++ } ++ else { ++ phydev->link = 0; ++ link_mode_8521 = 0; ++ } ++ ++ if (link_utp) { ++ ytphy_write_ext(phydev, 0xa000, 0); ++ } ++ ++ return 0; ++} ++ ++/* ++ * for fiber mode, when speed is 100M, there is no definition for autonegotiation, and ++ * this function handles this case and return 1 per linux kernel's polling. ++ */ ++int yt8521_aneg_done(struct phy_device *phydev) ++{ ++ ++ if ((32 == link_mode_8521) && (SPEED_100 == phydev->speed)) ++ { ++ return 1/*link_mode_8521*/; ++ } ++ ++ return genphy_aneg_done(phydev); ++} ++ ++int yt8521_soft_reset(struct phy_device *phydev) ++{ ++ int ret, val; ++ ++ val = ytphy_read_ext(phydev, 0xa001); ++ ytphy_write_ext(phydev, 0xa001, (val & ~0x8000)); ++ ++ ret = genphy_soft_reset(phydev); ++ if (ret < 0) ++ return ret; ++ ++ return 0; ++} ++ ++int yt8521_suspend(struct phy_device *phydev) ++{ ++ return 0; ++} ++ ++int yt8521_resume(struct phy_device *phydev) ++{ ++ return 0; ++} ++ + static struct phy_driver ytphy_drvs[] = { + { + .phy_id = PHY_ID_YT8010, +@@ -323,7 +477,30 @@ static struct phy_driver ytphy_drvs[] = { + .config_intr = yt8521_config_intr, + .suspend = genphy_suspend, + .resume = genphy_resume, +- }, ++ }, { ++ /* same as 8521 */ ++ .phy_id = PHY_ID_YT8531S, ++ .name = "YT8531S Ethernet", ++ .phy_id_mask = MOTORCOMM_PHY_ID_MASK, ++ .flags = PHY_POLL, ++ .soft_reset = yt8521_soft_reset, ++ .config_aneg = genphy_config_aneg, ++ .aneg_done = yt8521_aneg_done, ++ .config_init = yt8521_config_init, ++ .read_status = yt8521_read_status, ++ .suspend = yt8521_suspend, ++ .resume = yt8521_resume, ++ }, { ++ /* same as 8511 */ ++ .phy_id = PHY_ID_YT8531, ++ .name = "YT8531 Gigabit Ethernet", ++ .phy_id_mask = MOTORCOMM_PHY_ID_MASK, ++ .config_aneg = genphy_config_aneg, ++ .config_init = genphy_config_init, ++ .read_status = genphy_read_status, ++ .suspend = genphy_suspend, ++ .resume = genphy_resume, ++ } + }; + + module_phy_driver(ytphy_drvs); +@@ -339,6 +516,8 @@ static struct mdio_device_id __maybe_unused motorcomm_tbl[] = { + { PHY_ID_YT8512, MOTORCOMM_PHY_ID_MASK }, + { PHY_ID_YT8512B, MOTORCOMM_PHY_ID_MASK }, + { PHY_ID_YT8521, MOTORCOMM_PHY_ID_MASK }, ++ { PHY_ID_YT8531S, MOTORCOMM_PHY_ID_8531_MASK }, ++ { PHY_ID_YT8531, MOTORCOMM_PHY_ID_8531_MASK }, + { } + }; + +diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c +index 950277e..3a35040 100644 +--- a/drivers/net/phy/phy_device.c ++++ b/drivers/net/phy/phy_device.c +@@ -32,6 +32,7 @@ + #include + #include + #include ++#include + + MODULE_DESCRIPTION("PHY library"); + MODULE_AUTHOR("Andy Fleming"); +@@ -409,6 +410,33 @@ int phy_unregister_fixup_for_id(const char *bus_id) + } + EXPORT_SYMBOL(phy_unregister_fixup_for_id); + ++static int phy_mii_rd_ext(struct mii_bus *bus, int phy_id, u32 regnum) ++{ ++ int ret; ++ int val; ++ ++ ret = bus->write(bus, phy_id, REG_DEBUG_ADDR_OFFSET, regnum); ++ if (ret < 0) ++ return ret; ++ ++ val = bus->read(bus, phy_id, REG_DEBUG_DATA); ++ ++ return val; ++} ++ ++static int phy_mii_wr_ext(struct mii_bus *bus, int phy_id, u32 regnum, u16 val) ++{ ++ int ret; ++ ++ ret = bus->write(bus, phy_id, REG_DEBUG_ADDR_OFFSET, regnum); ++ if (ret < 0) ++ return ret; ++ ++ ret = bus->write(bus, phy_id, REG_DEBUG_DATA, val); ++ ++ return ret; ++} ++ + /* Returns 1 if fixup matches phydev in bus_id and phy_uid. + * Fixups can be set to match any in one or more fields. + */ +@@ -816,6 +844,50 @@ static int get_phy_c22_id(struct mii_bus *bus, int addr, u32 *phy_id) + return 0; + } + ++int phy_set_out_125m(struct mii_bus* bus, int phy_id) ++{ ++ int ret; ++ int val; ++ ++ ret = phy_mii_wr_ext(bus, phy_id, 0xa012, 0xd0); ++ mdelay(100); ++ val = phy_mii_rd_ext(bus, phy_id, 0xa012); ++ ++ if (val != 0xd0) ++ { ++ printk(KERN_INFO "phy_set_out_125m error\n"); ++ return -1; ++ } ++ ++ /* disable auto sleep */ ++ val = phy_mii_rd_ext(bus, phy_id, 0x27); ++ if (val < 0) ++ return val; ++ ++ val &= (~BIT(15)); ++ ++ ret = phy_mii_wr_ext(bus, phy_id, 0x27, val); ++ if (ret < 0) ++ return ret; ++ ++ /* enable RXC clock when no wire plug */ ++ val = phy_mii_rd_ext(bus, phy_id, 0xc); ++ if (val < 0) ++ return val; ++ ++ /* ext reg 0xc.b[2:1] ++ 00-----25M from pll; ++ 01---- 25M from xtl;(default) ++ 10-----62.5M from pll; ++ 11----125M from pll(here set to this value) ++ */ ++ val |= (3 << 1); ++ ret = phy_mii_wr_ext(bus, phy_id, 0xc, val); ++ printk(KERN_INFO "phy_set_out_125m, phy clk out, val=%#08x\n", val); ++ ++ return ret; ++} ++ + /** + * get_phy_device - reads the specified PHY device and returns its @phy_device + * struct +@@ -853,6 +925,15 @@ struct phy_device *get_phy_device(struct mii_bus *bus, int addr, bool is_c45) + if (r) + return ERR_PTR(r); + ++ if(phy_id == PHY_ID_YT8531) ++ { ++ r = phy_set_out_125m(bus, addr); ++ if (r<0) ++ { ++ printk (KERN_INFO "failed to set 125m clk out, ret=%d\n",r); ++ } ++ } ++ + return phy_device_create(bus, addr, phy_id, is_c45, &c45_ids); + } + EXPORT_SYMBOL(get_phy_device); +diff --git a/include/linux/motorcomm_phy.h b/include/linux/motorcomm_phy.h +index facce6d..23cccca 100644 +--- a/include/linux/motorcomm_phy.h ++++ b/include/linux/motorcomm_phy.h +@@ -14,6 +14,8 @@ + #define _MOTORCOMM_PHY_H + + #define MOTORCOMM_PHY_ID_MASK 0x00000fff ++#define MOTORCOMM_PHY_ID_8531_MASK 0xffffffff ++#define MOTORCOMM_MPHY_ID_MASK 0x0000ffff + + #define PHY_ID_YT8010 0x00000309 + #define PHY_ID_YT8510 0x00000109 +@@ -21,6 +23,9 @@ + #define PHY_ID_YT8512 0x00000118 + #define PHY_ID_YT8512B 0x00000128 + #define PHY_ID_YT8521 0x0000011a ++#define PHY_ID_YT8531S 0x4f51e91a ++#define PHY_ID_YT8531 0x4f51e91b ++#define PHY_ID_YT8618 0x0000e889 + + #define REG_PHY_SPEC_STATUS 0x11 + #define REG_INT_MASK 0x12 diff --git a/target/linux/rockchip/patches-5.4/600-net-phy-Add-driver-for-Motorcomm-YT85xx-PHYs.patch b/target/linux/rockchip/patches-5.4/600-net-phy-Add-driver-for-Motorcomm-YT85xx-PHYs.patch index c47dcf309..2271308b1 100644 --- a/target/linux/rockchip/patches-5.4/600-net-phy-Add-driver-for-Motorcomm-YT85xx-PHYs.patch +++ b/target/linux/rockchip/patches-5.4/600-net-phy-Add-driver-for-Motorcomm-YT85xx-PHYs.patch @@ -1,121 +1,18 @@ -From acf039521685d9a1d272e8e577c1328c6a5bcca8 Mon Sep 17 00:00:00 2001 -From: baiywt -Date: Thu, 11 Nov 2021 19:53:31 +0800 -Subject: [PATCH 3/3] Add yt8531c support +From 5d6862cc5eac1679d7a4ef388f7c9bbc70e76770 Mon Sep 17 00:00:00 2001 +From: hmz007 +Date: Mon, 5 Jul 2021 17:03:00 +0800 +Subject: [PATCH] net: phy: Add driver for Motorcomm YT85xx PHYs +Signed-off-by: hmz007 --- - .../net/ethernet/stmicro/stmmac/stmmac_main.c | 77 + - drivers/net/phy/Kconfig | 5 + - drivers/net/phy/Makefile | 1 + - drivers/net/phy/motorcomm.c | 1514 +++++++++++++++++ - drivers/net/phy/phy_device.c | 15 + - drivers/net/phy/yt8614-phy.h | 491 ++++++ - include/linux/motorcomm_phy.h | 119 ++ - 7 files changed, 2222 insertions(+) + drivers/net/phy/Kconfig | 5 + + drivers/net/phy/Makefile | 1 + + drivers/net/phy/motorcomm.c | 346 ++++++++++++++++++++++++++++++++++ + include/linux/motorcomm_phy.h | 68 +++++++ + 4 files changed, 420 insertions(+) create mode 100644 drivers/net/phy/motorcomm.c - create mode 100644 drivers/net/phy/yt8614-phy.h create mode 100644 include/linux/motorcomm_phy.h ---- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c -+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c -@@ -112,6 +112,10 @@ - - #define STMMAC_COAL_TIMER(x) (jiffies + usecs_to_jiffies(x)) - -+#define RTL_8211E_PHY_ID 0x001cc915 -+#define RTL_8211F_PHY_ID 0x001cc916 -+#define RTL_YT8531_PHY_ID 0x4f51e91b -+ - /** - * stmmac_verify_args - verify the driver parameters. - * Description: it checks the driver parameters and set a default in case of -@@ -4431,6 +4435,68 @@ - return 0; - } - -+static int phy_rtl8211e_led_fixup(struct phy_device *phydev) -+{ -+ //int val; -+ -+ printk("%s in\n", __func__); -+ -+ /*switch to extension page44*/ -+ phy_write(phydev, 31, 0x07); -+ phy_write(phydev, 30, 0x2c); -+ -+ /*set led1(yellow) act -+ val = phy_read(phydev, 26); -+ val &= (~(1<<4));// bit4=0 -+ val |= (1<<5);// bit5=1 -+ val &= (~(1<<6));// bit6=0*/ -+ phy_write(phydev, 26, 0x20); -+ -+ /*set led0(green) link -+ val = phy_read(phydev, 28); -+ val |= (7<<0);// bit0,1,2=1 -+ val &= (~(7<<4));// bit4,5,6=0 -+ val &= (~(7<<8));// bit8,9,10=0*/ -+ phy_write(phydev, 28, 0x07); -+ -+ /*switch back to page0*/ -+ phy_write(phydev,31,0x00); -+ -+ return 0; -+} -+ -+static int phy_rtl8211f_led_fixup(struct phy_device *phydev) -+{ -+ printk("%s in\n", __func__); -+ -+ /*switch to extension page44*/ -+ phy_write(phydev, 31, 0xd04); -+ -+ /*set led1(yellow) act */ -+ /*set led2(green) link*/ -+ phy_write(phydev, 16, 0xae00); -+ -+ /*switch back to page0*/ -+ phy_write(phydev,31,0x00); -+ -+ return 0; -+} -+ -+static int phy_yt8531_led_fixup(struct phy_device *phydev) -+{ -+ printk("%s in\n", __func__); -+ phy_write(phydev, 0x1e, 0xa00d); -+ phy_write(phydev, 0x1f, 0x670); -+ -+ phy_write(phydev, 0x1e, 0xa00e); -+ phy_write(phydev, 0x1f, 0x2070); -+ -+ phy_write(phydev, 0x1e, 0xa00f); -+ phy_write(phydev, 0x1f, 0x7e); -+ -+ return 0; -+} -+ - /** - * stmmac_dvr_probe - * @device: device pointer -@@ -4656,6 +4722,17 @@ - goto error_phy_setup; - } - -+ ret = phy_register_fixup_for_uid(RTL_8211E_PHY_ID, 0xffffffff, phy_rtl8211e_led_fixup); -+ if (ret) -+ pr_warn("Cannot register PHY board fixup.\n"); -+ ret = phy_register_fixup_for_uid(RTL_8211F_PHY_ID, 0xffffffff, phy_rtl8211f_led_fixup); -+ if (ret) -+ pr_warn("Cannot register PHY board fixup.\n"); -+ ret = phy_register_fixup_for_uid(RTL_YT8531_PHY_ID, 0xffffffff, phy_yt8531_led_fixup); -+ if (ret) -+ pr_warn("Cannot register PHY board fixup.\n"); -+ -+ - ret = register_netdev(ndev); - if (ret) { - dev_err(priv->device, "%s: ERROR %i registering the device\n", --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -519,6 +519,11 @@ config MICROSEMI_PHY @@ -142,7 +39,7 @@ Subject: [PATCH 3/3] Add yt8531c support obj-$(CONFIG_QSEMI_PHY) += qsemi.o --- /dev/null +++ b/drivers/net/phy/motorcomm.c -@@ -0,0 +1,1514 @@ +@@ -0,0 +1,345 @@ +/* + * drivers/net/phy/motorcomm.c + * @@ -170,79 +67,6 @@ Subject: [PATCH 3/3] Add yt8531c support +#include +#include +#include -+#include -+#ifndef LINUX_VERSION_CODE -+#include -+#else -+#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) -+#endif -+/*for wol, 20210604*/ -+#include -+ -+#include "yt8614-phy.h" -+ -+/**** configuration section begin ***********/ -+ -+/* if system depends on ethernet packet to restore from sleep, please define this macro to 1 -+ * otherwise, define it to 0. -+ */ -+#define SYS_WAKEUP_BASED_ON_ETH_PKT 1 -+ -+/* to enable system WOL of phy, please define this macro to 1 -+ * otherwise, define it to 0. -+ */ -+#define YTPHY_ENABLE_WOL 0 -+ -+/* some GMAC need clock input from PHY, for eg., 125M, please enable this macro -+ * by degault, it is set to 0 -+ * NOTE: this macro will need macro SYS_WAKEUP_BASED_ON_ETH_PKT to set to 1 -+ */ -+#define GMAC_CLOCK_INPUT_NEEDED 1 -+ -+ -+#define YT8521_PHY_MODE_FIBER 1 //fiber mode only -+#define YT8521_PHY_MODE_UTP 2 //utp mode only -+#define YT8521_PHY_MODE_POLL 3 //fiber and utp, poll mode -+ -+/* please make choice according to system design -+ * for Fiber only system, please define YT8521_PHY_MODE_CURR 1 -+ * for UTP only system, please define YT8521_PHY_MODE_CURR 2 -+ * for combo system, please define YT8521_PHY_MODE_CURR 3 -+ */ -+#define YT8521_PHY_MODE_CURR 3 -+ -+/**** configuration section end ***********/ -+ -+ -+/* no need to change below */ -+ -+#if (YTPHY_ENABLE_WOL) -+#undef SYS_WAKEUP_BASED_ON_ETH_PKT -+#define SYS_WAKEUP_BASED_ON_ETH_PKT 1 -+#endif -+ -+/* workaround for 8521 fiber 100m mode */ -+static int link_mode_8521 = 0; //0: no link; 1: utp; 32: fiber. traced that 1000m fiber uses 32. -+static int link_mode_8614[4] = {0}; //0: no link; 1: utp; 32: fiber. traced that 1000m fiber uses 32. -+ -+/* for multiple port phy, base phy address */ -+static unsigned int yt_mport_base_phy_addr = 0xff; //0xff: invalid; for 8618 -+static unsigned int yt_mport_base_phy_addr_8614 = 0xff; //0xff: invalid; -+ -+#if ( LINUX_VERSION_CODE > KERNEL_VERSION(5,0,0) ) -+int genphy_config_init(struct phy_device *phydev) -+{ -+ printk(KERN_ERR"csy: genphy_config_init\n"); -+ return genphy_read_abilities(phydev); -+} -+#endif -+ -+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) -+static int ytphy_config_init(struct phy_device *phydev) -+{ -+ return 0; -+} -+#endif + +static int ytphy_read_ext(struct phy_device *phydev, u32 regnum) +{ @@ -351,13 +175,6 @@ Subject: [PATCH 3/3] Add yt8531c support +{ + int ret; + int val; -+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) -+ ret = ytphy_config_init(phydev); -+#else -+ ret = genphy_config_init(phydev); -+#endif -+ if (ret < 0) -+ return ret; + + ret = yt8512_clk_init(phydev); + if (ret < 0) @@ -405,11 +222,7 @@ Subject: [PATCH 3/3] Add yt8531c support + case 2: + case 3: + default: -+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) -+ speed = -1; -+#else + speed = SPEED_UNKNOWN; -+#endif + break; + } + @@ -418,1032 +231,109 @@ Subject: [PATCH 3/3] Add yt8531c support + + return 0; +} -+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) -+#else -+#if 0 -+int yt8521_soft_reset(struct phy_device *phydev) -+{ -+ int ret; -+ -+ ytphy_write_ext(phydev, 0xa000, 0); -+ ret = genphy_soft_reset(phydev); -+ if (ret < 0) -+ return ret; -+ -+ ytphy_write_ext(phydev, 0xa000, 2); -+ ret = genphy_soft_reset(phydev); -+ if (ret < 0) { -+ ytphy_write_ext(phydev, 0xa000, 0); -+ return ret; -+ } -+ -+ return 0; -+} -+#else -+/* qingsong feedback 2 genphy_soft_reset will cause problem. -+ * and this is the reduction version -+ */ -+int yt8521_soft_reset(struct phy_device *phydev) -+{ -+ int ret, val; -+ -+ val = ytphy_read_ext(phydev, 0xa001); -+ ytphy_write_ext(phydev, 0xa001, (val & ~0x8000)); -+ -+ ret = genphy_soft_reset(phydev); -+ if (ret < 0) -+ return ret; -+ -+ return 0; -+} -+#endif -+ -+#endif -+ -+#if GMAC_CLOCK_INPUT_NEEDED -+static int ytphy_mii_rd_ext(struct mii_bus *bus, int phy_id, u32 regnum) -+{ -+ int ret; -+ int val; -+ -+ ret = bus->write(bus, phy_id, REG_DEBUG_ADDR_OFFSET, regnum); -+ if (ret < 0) -+ return ret; -+ -+ val = bus->read(bus, phy_id, REG_DEBUG_DATA); -+ -+ return val; -+} -+ -+static int ytphy_mii_wr_ext(struct mii_bus *bus, int phy_id, u32 regnum, u16 val) -+{ -+ int ret; -+ -+ ret = bus->write(bus, phy_id, REG_DEBUG_ADDR_OFFSET, regnum); -+ if (ret < 0) -+ return ret; -+ -+ ret = bus->write(bus, phy_id, REG_DEBUG_DATA, val); -+ -+ return ret; -+} -+ -+int yt8511_config_dis_txdelay(struct mii_bus *bus, int phy_id) -+{ -+ int ret; -+ int val; -+ -+ /* disable auto sleep */ -+ val = ytphy_mii_rd_ext(bus, phy_id, 0x27); -+ if (val < 0) -+ return val; -+ -+ val &= (~BIT(15)); -+ -+ ret = ytphy_mii_wr_ext(bus, phy_id, 0x27, val); -+ if (ret < 0) -+ return ret; -+ -+ /* enable RXC clock when no wire plug */ -+ val = ytphy_mii_rd_ext(bus, phy_id, 0xc); -+ if (val < 0) -+ return val; -+ -+ /* ext reg 0xc b[7:4] -+ Tx Delay time = 150ps * N - 250ps -+ */ -+ val &= ~(0xf << 4); -+ ret = ytphy_mii_wr_ext(bus, phy_id, 0xc, val); -+ printk("yt8511_config_dis_txdelay..phy txdelay, val=%#08x\n",val); -+ -+ return ret; -+} -+ -+ -+int yt8511_config_out_125m(struct mii_bus *bus, int phy_id) -+{ -+ int ret; -+ int val; -+ -+ ret = ytphy_mii_wr_ext(bus, phy_id, 0xa012, 0xd0); -+ mdelay(100); -+ val = ytphy_mii_rd_ext(bus, phy_id, 0xa012); -+ -+ if(val != 0xd0) -+ { -+ printk("yt8511_config_out_125m error\n"); -+ return -1; -+ } -+ -+ /* disable auto sleep */ -+ val = ytphy_mii_rd_ext(bus, phy_id, 0x27); -+ if (val < 0) -+ return val; -+ -+ val &= (~BIT(15)); -+ -+ ret = ytphy_mii_wr_ext(bus, phy_id, 0x27, val); -+ if (ret < 0) -+ return ret; -+ -+ /* enable RXC clock when no wire plug */ -+ val = ytphy_mii_rd_ext(bus, phy_id, 0xc); -+ if (val < 0) -+ return val; -+ -+ /* ext reg 0xc.b[2:1] -+ 00-----25M from pll; -+ 01---- 25M from xtl;(default) -+ 10-----62.5M from pll; -+ 11----125M from pll(here set to this value) -+ */ -+ val |= (3 << 1); -+ ret = ytphy_mii_wr_ext(bus, phy_id, 0xc, val); -+ printk("yt8511_config_out_125m, phy clk out, val=%#08x\n",val); -+ -+ //ret = ytphy_mii_wr_ext(bus, phy_id, 0xa012, 0x70); -+ -+#if 0 -+ /* for customer, please enable it based on demand. -+ * configure to master -+ */ -+ val = bus->read(bus, phy_id, 0x9/*master/slave config reg*/); -+ val |= (0x3<<11); //to be manual config and force to be master -+ ret = bus->write(bus, phy_id, 0x9, val); //take effect until phy soft reset -+ if (ret < 0) -+ return ret; -+ -+ printk("yt8511_config_out_125m, phy to be master, val=%#08x\n",val); -+#endif -+ -+ return ret; -+} -+ -+EXPORT_SYMBOL(yt8511_config_out_125m); -+ -+static int yt8511_config_init(struct phy_device *phydev) -+{ -+ int ret; -+ -+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) -+ ret = ytphy_config_init(phydev); -+#else -+ ret = genphy_config_init(phydev); -+#endif -+ -+ return ret; -+} -+#endif /*GMAC_CLOCK_INPUT_NEEDED*/ -+ -+#if (YTPHY_ENABLE_WOL) -+static int ytphy_switch_reg_space(struct phy_device *phydev, int space) -+{ -+ int ret; -+ -+ if (space == YTPHY_REG_SPACE_UTP){ -+ ret = ytphy_write_ext(phydev, 0xa000, 0); -+ }else{ -+ ret = ytphy_write_ext(phydev, 0xa000, 2); -+ } -+ -+ return ret; -+} -+ -+static int ytphy_wol_en_cfg(struct phy_device *phydev, ytphy_wol_cfg_t wol_cfg) -+{ -+ int ret=0; -+ int val=0; -+ -+ val = ytphy_read_ext(phydev, YTPHY_WOL_CFG_REG); -+ if (val < 0) -+ return val; -+ -+ if(wol_cfg.enable) { -+ val |= YTPHY_WOL_CFG_EN; -+ -+ if(wol_cfg.type == YTPHY_WOL_TYPE_LEVEL) { -+ val &= ~YTPHY_WOL_CFG_TYPE; -+ val &= ~YTPHY_WOL_CFG_INTR_SEL; -+ } else if(wol_cfg.type == YTPHY_WOL_TYPE_PULSE) { -+ val |= YTPHY_WOL_CFG_TYPE; -+ val |= YTPHY_WOL_CFG_INTR_SEL; -+ -+ if(wol_cfg.width == YTPHY_WOL_WIDTH_84MS) { -+ val &= ~YTPHY_WOL_CFG_WIDTH1; -+ val &= ~YTPHY_WOL_CFG_WIDTH2; -+ } else if(wol_cfg.width == YTPHY_WOL_WIDTH_168MS) { -+ val |= YTPHY_WOL_CFG_WIDTH1; -+ val &= ~YTPHY_WOL_CFG_WIDTH2; -+ } else if(wol_cfg.width == YTPHY_WOL_WIDTH_336MS) { -+ val &= ~YTPHY_WOL_CFG_WIDTH1; -+ val |= YTPHY_WOL_CFG_WIDTH2; -+ } else if(wol_cfg.width == YTPHY_WOL_WIDTH_672MS) { -+ val |= YTPHY_WOL_CFG_WIDTH1; -+ val |= YTPHY_WOL_CFG_WIDTH2; -+ } -+ } -+ } else { -+ val &= ~YTPHY_WOL_CFG_EN; -+ val &= ~YTPHY_WOL_CFG_INTR_SEL; -+ } -+ -+ ret = ytphy_write_ext(phydev, YTPHY_WOL_CFG_REG, val); -+ if (ret < 0) -+ return ret; -+ -+ return 0; -+} -+ -+static void ytphy_get_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol) -+{ -+ int val = 0; -+ -+ wol->supported = WAKE_MAGIC; -+ wol->wolopts = 0; -+ -+ val = ytphy_read_ext(phydev, YTPHY_WOL_CFG_REG); -+ if (val < 0) -+ return; -+ -+ if (val & YTPHY_WOL_CFG_EN) -+ wol->wolopts |= WAKE_MAGIC; -+ -+ return; -+} -+ -+static int ytphy_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol) -+{ -+ int ret, pre_page, val; -+ ytphy_wol_cfg_t wol_cfg; -+ struct net_device *p_attached_dev = phydev->attached_dev; -+ -+ memset(&wol_cfg,0,sizeof(ytphy_wol_cfg_t)); -+ pre_page = ytphy_read_ext(phydev, 0xa000); -+ if (pre_page < 0) -+ return pre_page; -+ -+ /* Switch to phy UTP page */ -+ ret = ytphy_switch_reg_space(phydev, YTPHY_REG_SPACE_UTP); -+ if (ret < 0) -+ return ret; -+ -+ if (wol->wolopts & WAKE_MAGIC) { -+ -+ /* Enable the WOL interrupt */ -+ val = phy_read(phydev, YTPHY_UTP_INTR_REG); -+ val |= YTPHY_WOL_INTR; -+ ret = phy_write(phydev, YTPHY_UTP_INTR_REG, val); -+ if (ret < 0) -+ return ret; -+ -+ /* Set the WOL config */ -+ wol_cfg.enable = 1; //enable -+ wol_cfg.type= YTPHY_WOL_TYPE_PULSE; -+ wol_cfg.width= YTPHY_WOL_WIDTH_672MS; -+ ret = ytphy_wol_en_cfg(phydev, wol_cfg); -+ if (ret < 0) -+ return ret; -+ -+ /* Store the device address for the magic packet */ -+ ret = ytphy_write_ext(phydev, YTPHY_MAGIC_PACKET_MAC_ADDR2, -+ ((p_attached_dev->dev_addr[0] << 8) | -+ p_attached_dev->dev_addr[1])); -+ if (ret < 0) -+ return ret; -+ ret = ytphy_write_ext(phydev, YTPHY_MAGIC_PACKET_MAC_ADDR1, -+ ((p_attached_dev->dev_addr[2] << 8) | -+ p_attached_dev->dev_addr[3])); -+ if (ret < 0) -+ return ret; -+ ret = ytphy_write_ext(phydev, YTPHY_MAGIC_PACKET_MAC_ADDR0, -+ ((p_attached_dev->dev_addr[4] << 8) | -+ p_attached_dev->dev_addr[5])); -+ if (ret < 0) -+ return ret; -+ } else { -+ wol_cfg.enable = 0; //disable -+ wol_cfg.type= YTPHY_WOL_TYPE_MAX; -+ wol_cfg.width= YTPHY_WOL_WIDTH_MAX; -+ ret = ytphy_wol_en_cfg(phydev, wol_cfg); -+ if (ret < 0) -+ return ret; -+ } -+ -+ /* Recover to previous register space page */ -+ ret = ytphy_switch_reg_space(phydev, pre_page); -+ if (ret < 0) -+ return ret; -+ -+ return 0; -+} -+ -+#endif /*(YTPHY_ENABLE_WOL)*/ + +static int yt8521_config_init(struct phy_device *phydev) +{ + int ret; + int val; + -+ phydev->irq = PHY_POLL; -+ -+ ytphy_write_ext(phydev, 0xa000, 0); -+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) -+ ret = ytphy_config_init(phydev); -+#else -+ ret = genphy_config_init(phydev); -+#endif -+ if (ret < 0) -+ return ret; -+ + /* disable auto sleep */ + val = ytphy_read_ext(phydev, YT8521_EXTREG_SLEEP_CONTROL1); + if (val < 0) + return val; + + val &= (~BIT(YT8521_EN_SLEEP_SW_BIT)); -+ + ret = ytphy_write_ext(phydev, YT8521_EXTREG_SLEEP_CONTROL1, val); + if (ret < 0) + return ret; + -+ /* enable RXC clock when no wire plug */ ++ /* switch to access UTP */ + ret = ytphy_write_ext(phydev, 0xa000, 0); + if (ret < 0) + return ret; + ++ /* enable RXC clock when no wire plug */ + val = ytphy_read_ext(phydev, 0xc); + if (val < 0) + return val; ++ + val &= ~(1 << 12); + ret = ytphy_write_ext(phydev, 0xc, val); + if (ret < 0) + return ret; + -+ printk (KERN_INFO "yt8521_config_init, 8521 init call out.\n"); -+ return ret; -+} -+ -+/* -+ * for fiber mode, there is no 10M speed mode and -+ * this function is for this purpose. -+ */ -+static int yt8521_adjust_status(struct phy_device *phydev, int val, int is_utp) -+{ -+ int speed_mode, duplex; -+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) -+ int speed = -1; -+#else -+ int speed = SPEED_UNKNOWN; -+#endif -+ -+ duplex = (val & YT8512_DUPLEX) >> YT8521_DUPLEX_BIT; -+ speed_mode = (val & YT8521_SPEED_MODE) >> YT8521_SPEED_MODE_BIT; -+ switch (speed_mode) { -+ case 0: -+ if (is_utp) -+ speed = SPEED_10; -+ break; -+ case 1: -+ speed = SPEED_100; -+ break; -+ case 2: -+ speed = SPEED_1000; -+ break; -+ case 3: -+ break; -+ default: -+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) -+ speed = -1; -+#else -+ speed = SPEED_UNKNOWN; -+#endif -+ break; -+ } -+ -+ phydev->speed = speed; -+ phydev->duplex = duplex; -+ //printk (KERN_INFO "yt8521_adjust_status call out,regval=0x%04x,mode=%s,speed=%dm...\n", val,is_utp?"utp":"fiber", phydev->speed); -+ -+ return 0; -+} -+ -+/* -+ * for fiber mode, when speed is 100M, there is no definition for autonegotiation, and -+ * this function handles this case and return 1 per linux kernel's polling. -+ */ -+int yt8521_aneg_done (struct phy_device *phydev) -+{ -+ -+ //printk("yt8521_aneg_done callin,speed=%dm,linkmoded=%d\n", phydev->speed,link_mode_8521); -+ -+ if((32 == link_mode_8521) && (SPEED_100 == phydev->speed)) -+ { -+ return 1/*link_mode_8521*/; -+ } -+ -+#if ( LINUX_VERSION_CODE > KERNEL_VERSION(3,11,0) ) -+ return genphy_aneg_done(phydev); -+#else -+ return 1; -+#endif -+} -+ -+static int yt8521_read_status(struct phy_device *phydev) -+{ -+ int ret; -+ volatile int val, yt8521_fiber_latch_val, yt8521_fiber_curr_val; -+ volatile int link; -+ int link_utp = 0, link_fiber = 0; -+ -+#if (YT8521_PHY_MODE_CURR != YT8521_PHY_MODE_FIBER) -+ /* reading UTP */ -+ ret = ytphy_write_ext(phydev, 0xa000, 0); ++ /* output SyncE clock (125mhz) even link is down */ ++ ret = ytphy_write_ext(phydev, 0xa012, 0x38); + if (ret < 0) + return ret; + -+ val = phy_read(phydev, REG_PHY_SPEC_STATUS); ++ /* disable rgmii clk 2ns delay */ ++ val = ytphy_read_ext(phydev, 0xa001); + if (val < 0) + return val; + -+ link = val & (BIT(YT8521_LINK_STATUS_BIT)); -+ if (link) { -+ link_utp = 1; -+ link_mode_8521 = 1; -+ yt8521_adjust_status(phydev, val, 1); -+ } else { -+ link_utp = 0; -+ } -+#endif //(YT8521_PHY_MODE_CURR != YT8521_PHY_MODE_FIBER) -+ -+#if (YT8521_PHY_MODE_CURR != YT8521_PHY_MODE_UTP) -+ /* reading Fiber */ -+ ret = ytphy_write_ext(phydev, 0xa000, 2); ++ val &= ~(1 << 8); ++ ret = ytphy_write_ext(phydev, 0xa001, val); + if (ret < 0) + return ret; + -+ val = phy_read(phydev, REG_PHY_SPEC_STATUS); -+ if (val < 0) -+ return val; -+ -+ //note: below debug information is used to check multiple PHy ports. -+ //printk (KERN_INFO "yt8521_read_status, fiber status=%04x,macbase=0x%08lx\n", val,(unsigned long)phydev->attached_dev); ++ /* setup delay */ ++ val = (1 << 10) | (0xf << 4) | 5; ++ ret = ytphy_write_ext(phydev, 0xa003, val); ++ if (ret < 0) ++ return ret; + -+ /* for fiber, from 1000m to 100m, there is not link down from 0x11, and check reg 1 to identify such case -+ * this is important for Linux kernel for that, missing linkdown event will cause problem. -+ */ -+ yt8521_fiber_latch_val = phy_read(phydev, MII_BMSR); -+ yt8521_fiber_curr_val = phy_read(phydev, MII_BMSR); -+ link = val & (BIT(YT8521_LINK_STATUS_BIT)); -+ if((link) && (yt8521_fiber_latch_val != yt8521_fiber_curr_val)) -+ { -+ link = 0; -+ printk (KERN_INFO "yt8521_read_status, fiber link down detect,latch=%04x,curr=%04x\n", yt8521_fiber_latch_val,yt8521_fiber_curr_val); -+ } -+ -+ if (link) { -+ link_fiber = 1; -+ yt8521_adjust_status(phydev, val, 0); -+ link_mode_8521 = 32; //fiber mode -+ -+ -+ } else { -+ link_fiber = 0; -+ } -+#endif //(YT8521_PHY_MODE_CURR != YT8521_PHY_MODE_UTP) -+ -+ if (link_utp || link_fiber) { -+ phydev->link = 1; -+ } else { -+ phydev->link = 0; -+ link_mode_8521 = 0; -+ } -+ -+#if (YT8521_PHY_MODE_CURR != YT8521_PHY_MODE_FIBER) -+ if (link_utp) { -+ ytphy_write_ext(phydev, 0xa000, 0); -+ } -+#endif -+ -+ //printk (KERN_INFO "yzhang..8521 read status call out,link=%d,linkmode=%d\n", phydev->link, link_mode_8521 ); -+ return 0; -+} -+ -+int yt8521_suspend(struct phy_device *phydev) -+{ -+#if !(SYS_WAKEUP_BASED_ON_ETH_PKT) -+ int value; -+ -+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) -+ mutex_lock(&phydev->lock); -+#else -+ /* no need lock in 4.19 */ -+#endif -+ -+ ytphy_write_ext(phydev, 0xa000, 0); -+ value = phy_read(phydev, MII_BMCR); -+ phy_write(phydev, MII_BMCR, value | BMCR_PDOWN); -+ -+ ytphy_write_ext(phydev, 0xa000, 2); -+ value = phy_read(phydev, MII_BMCR); -+ phy_write(phydev, MII_BMCR, value | BMCR_PDOWN); -+ -+ ytphy_write_ext(phydev, 0xa000, 0); -+ -+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) -+ mutex_unlock(&phydev->lock); -+#else -+ /* no need lock/unlock in 4.19 */ -+#endif -+#endif /*!(SYS_WAKEUP_BASED_ON_ETH_PKT)*/ ++ /* LED0: Unused/Off, LED1: Link, LED2: Activity, 8Hz */ ++ ytphy_write_ext(phydev, 0xa00b, 0xe004); ++ ytphy_write_ext(phydev, 0xa00c, 0); ++ ytphy_write_ext(phydev, 0xa00d, 0x2600); ++ ytphy_write_ext(phydev, 0xa00e, 0x0070); ++ ytphy_write_ext(phydev, 0xa00f, 0x000a); + + return 0; +} + -+int yt8521_resume(struct phy_device *phydev) ++static int yt8521_config_intr(struct phy_device *phydev) +{ -+#if !(SYS_WAKEUP_BASED_ON_ETH_PKT) -+ int value; -+ int ret; -+ -+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) -+ mutex_lock(&phydev->lock); -+#else -+ /* no need lock/unlock in 4.19 */ -+#endif -+ -+ ytphy_write_ext(phydev, 0xa000, 0); -+ value = phy_read(phydev, MII_BMCR); -+ phy_write(phydev, MII_BMCR, value & ~BMCR_PDOWN); -+ -+ /* disable auto sleep */ -+ value = ytphy_read_ext(phydev, YT8521_EXTREG_SLEEP_CONTROL1); -+ if (value < 0) -+ return value; -+ -+ value &= (~BIT(YT8521_EN_SLEEP_SW_BIT)); -+ ret = ytphy_write_ext(phydev, YT8521_EXTREG_SLEEP_CONTROL1, value); -+ if (ret < 0) -+ return ret; -+ -+ /* enable RXC clock when no wire plug */ -+ value = ytphy_read_ext(phydev, 0xc); -+ if (value < 0) -+ return value; -+ value &= ~(1 << 12); -+ ret = ytphy_write_ext(phydev, 0xc, value); -+ if (ret < 0) -+ return ret; -+ -+ ytphy_write_ext(phydev, 0xa000, 2); -+ value = phy_read(phydev, MII_BMCR); -+ phy_write(phydev, MII_BMCR, value & ~BMCR_PDOWN); -+ -+#if (YT8521_PHY_MODE_CURR != YT8521_PHY_MODE_FIBER) -+ ytphy_write_ext(phydev, 0xa000, 0); -+#endif -+ -+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) -+ mutex_unlock(&phydev->lock); -+#else -+ /* no need lock/unlock in 4.19 */ -+#endif -+#endif /*!(SYS_WAKEUP_BASED_ON_ETH_PKT)*/ -+ -+ return 0; -+} -+ -+ -+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) -+#else -+int yt8618_soft_reset(struct phy_device *phydev) -+{ -+ int ret; -+ -+ ytphy_write_ext(phydev, 0xa000, 0); -+ ret = genphy_soft_reset(phydev); -+ if (ret < 0) -+ return ret; -+ -+ return 0; -+} -+ -+int yt8614_soft_reset(struct phy_device *phydev) -+{ -+ int ret; -+ -+ /* utp */ -+ ytphy_write_ext(phydev, 0xa000, 0); -+ ret = genphy_soft_reset(phydev); -+ if (ret < 0) -+ return ret; -+ -+ /* qsgmii */ -+ ytphy_write_ext(phydev, 0xa000, 2); -+ ret = genphy_soft_reset(phydev); -+ if (ret < 0) { -+ ytphy_write_ext(phydev, 0xa000, 0); //back to utp mode -+ return ret; -+ } -+ -+ /* sgmii */ -+ ytphy_write_ext(phydev, 0xa000, 3); -+ ret = genphy_soft_reset(phydev); -+ if (ret < 0) { -+ ytphy_write_ext(phydev, 0xa000, 0); //back to utp mode -+ return ret; -+ } -+ -+ return 0; -+} -+ -+#endif -+ -+static int yt8618_config_init(struct phy_device *phydev) -+{ -+ int ret; + int val; + -+ phydev->irq = PHY_POLL; ++ if (phydev->interrupts == PHY_INTERRUPT_ENABLED) ++ val = BIT(14) | BIT(13) | BIT(11) | BIT(10); ++ else ++ val = 0; + -+ if(0xff == yt_mport_base_phy_addr) -+ /* by default, we think the first phy should be the base phy addr. for mul */ -+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) -+ { -+ yt_mport_base_phy_addr = phydev->addr; -+ }else if (yt_mport_base_phy_addr > phydev->addr) { -+ printk (KERN_INFO "yzhang..8618 init, phy address mismatch, base=%d, cur=%d\n", yt_mport_base_phy_addr, phydev->addr); -+ } -+#else -+ { -+ yt_mport_base_phy_addr = phydev->mdio.addr; -+ }else if (yt_mport_base_phy_addr > phydev->mdio.addr) { -+ printk (KERN_INFO "yzhang..8618 init, phy address mismatch, base=%d, cur=%d\n", yt_mport_base_phy_addr, phydev->mdio.addr); -+ } -+#endif -+ -+ ytphy_write_ext(phydev, 0xa000, 0); -+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) -+ ret = ytphy_config_init(phydev); -+#else -+ ret = genphy_config_init(phydev); -+#endif -+ if (ret < 0) -+ return ret; -+ -+ /* for utp to optimize signal */ -+ ret = ytphy_write_ext(phydev, 0x41, 0x33); -+ if (ret < 0) -+ return ret; -+ ret = ytphy_write_ext(phydev, 0x42, 0x66); -+ if (ret < 0) -+ return ret; -+ ret = ytphy_write_ext(phydev, 0x43, 0xaa); -+ if (ret < 0) -+ return ret; -+ ret = ytphy_write_ext(phydev, 0x44, 0xd0d); -+ if (ret < 0) -+ return ret; -+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) -+ if((phydev->addr > yt_mport_base_phy_addr) && ((2 == phydev->addr - yt_mport_base_phy_addr) || (5 == phydev->addr - yt_mport_base_phy_addr))) -+#else -+ if((phydev->mdio.addr > yt_mport_base_phy_addr) && ((2 == phydev->mdio.addr - yt_mport_base_phy_addr) || (5 == phydev->mdio.addr - yt_mport_base_phy_addr))) -+#endif -+ { -+ ret = ytphy_write_ext(phydev, 0x44, 0x2929); -+ if (ret < 0) -+ return ret; -+ } -+ -+ val = phy_read(phydev, MII_BMCR); -+ phy_write(phydev, MII_BMCR, val | BMCR_RESET); -+ -+ printk (KERN_INFO "yt8618_config_init call out.\n"); -+ return ret; ++ return phy_write(phydev, REG_INT_MASK, val); +} + -+static int yt8614_config_init(struct phy_device *phydev) ++static int yt8521_ack_interrupt(struct phy_device *phydev) +{ -+ int ret = 0; ++ int val; + -+ phydev->irq = PHY_POLL; ++ val = phy_read(phydev, REG_INT_STATUS); ++ phydev_dbg(phydev, "intr status 0x04%x\n", val); + -+ if(0xff == yt_mport_base_phy_addr_8614) -+ /* by default, we think the first phy should be the base phy addr. for mul */ -+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) -+ { -+ yt_mport_base_phy_addr_8614 = (unsigned int)phydev->addr; -+ }else if (yt_mport_base_phy_addr_8614 > (unsigned int)phydev->addr) { -+ printk (KERN_INFO "yzhang..8618 init, phy address mismatch, base=%u, cur=%d\n", yt_mport_base_phy_addr_8614, phydev->addr); -+ } -+#else -+ { -+ yt_mport_base_phy_addr_8614 = (unsigned int)phydev->mdio.addr; -+ }else if (yt_mport_base_phy_addr_8614 > (unsigned int)phydev->mdio.addr) { -+ printk (KERN_INFO "yzhang..8618 init, phy address mismatch, base=%u, cur=%d\n", yt_mport_base_phy_addr_8614, phydev->mdio.addr); -+ } -+#endif -+ return ret; ++ return (val < 0) ? val : 0; +} + -+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) -+#define yt8614_get_port_from_phydev(phydev) ((0xff == yt_mport_base_phy_addr_8614) && (yt_mport_base_phy_addr_8614 <= (phydev)->addr) ? 0 : (unsigned int)((phydev)->addr) - yt_mport_base_phy_addr_8614) -+#else -+#define yt8614_get_port_from_phydev(phydev) ((0xff == yt_mport_base_phy_addr_8614) && (yt_mport_base_phy_addr_8614 <= (phydev)->mdio.addr) ? 0 : (unsigned int)((phydev)->mdio.addr) - yt_mport_base_phy_addr_8614) -+#endif -+ -+int yt8618_aneg_done (struct phy_device *phydev) -+{ -+ -+ return genphy_aneg_done(phydev); -+} -+ -+int yt8614_aneg_done (struct phy_device *phydev) -+{ -+ int port = yt8614_get_port_from_phydev(phydev); -+ -+ /*it should be used for 8614 fiber*/ -+ if((32 == link_mode_8614[port]) && (SPEED_100 == phydev->speed)) -+ { -+ return 1; -+ } -+ -+ return genphy_aneg_done(phydev); -+} -+ -+static int yt8614_read_status(struct phy_device *phydev) -+{ -+ //int i; -+ int ret; -+ volatile int val, yt8614_fiber_latch_val, yt8614_fiber_curr_val; -+ volatile int link; -+ int link_utp = 0, link_fiber = 0; -+ int port = yt8614_get_port_from_phydev(phydev); -+ -+#if (YT8614_PHY_MODE_CURR != YT8521_PHY_MODE_FIBER) -+ /* switch to utp and reading regs */ -+ ret = ytphy_write_ext(phydev, 0xa000, 0); -+ if (ret < 0) -+ return ret; -+ -+ val = phy_read(phydev, REG_PHY_SPEC_STATUS); -+ if (val < 0) -+ return val; -+ -+ link = val & (BIT(YT8521_LINK_STATUS_BIT)); -+ if (link) { -+ link_utp = 1; -+ // here is same as 8521 and re-use the function; -+ yt8521_adjust_status(phydev, val, 1); -+ } else { -+ link_utp = 0; -+ } -+#endif //(YT8614_PHY_MODE_CURR != YT8521_PHY_MODE_FIBER) -+ -+#if (YT8614_PHY_MODE_CURR != YT8521_PHY_MODE_UTP) -+ /* reading Fiber/sgmii */ -+ ret = ytphy_write_ext(phydev, 0xa000, 3); -+ if (ret < 0) -+ return ret; -+ -+ val = phy_read(phydev, REG_PHY_SPEC_STATUS); -+ if (val < 0) -+ return val; -+ -+ //printk (KERN_INFO "yzhang..8614 read fiber status=%04x,macbase=0x%08lx\n", val,(unsigned long)phydev->attached_dev); -+ -+ /* for fiber, from 1000m to 100m, there is not link down from 0x11, and check reg 1 to identify such case */ -+ yt8614_fiber_latch_val = phy_read(phydev, MII_BMSR); -+ yt8614_fiber_curr_val = phy_read(phydev, MII_BMSR); -+ link = val & (BIT(YT8521_LINK_STATUS_BIT)); -+ if((link) && (yt8614_fiber_latch_val != yt8614_fiber_curr_val)) -+ { -+ link = 0; -+ printk (KERN_INFO "yt8614_read_status, fiber link down detect,latch=%04x,curr=%04x\n", yt8614_fiber_latch_val,yt8614_fiber_curr_val); -+ } -+ -+ if (link) { -+ link_fiber = 1; -+ yt8521_adjust_status(phydev, val, 0); -+ link_mode_8614[port] = 32; //fiber mode -+ -+ -+ } else { -+ link_fiber = 0; -+ } -+#endif //(YT8521_PHY_MODE_CURR != YT8521_PHY_MODE_UTP) -+ -+ if (link_utp || link_fiber) { -+ phydev->link = 1; -+ } else { -+ phydev->link = 0; -+ link_mode_8614[port] = 0; -+ } -+ -+#if (YT8614_PHY_MODE_CURR != YT8521_PHY_MODE_FIBER) -+ if (link_utp) { -+ ytphy_write_ext(phydev, 0xa000, 0); -+ } -+#endif -+ //printk (KERN_INFO "yt8614_read_status call out,link=%d,linkmode=%d\n", phydev->link, link_mode_8614[port] ); -+ -+ return 0; -+} -+ -+static int yt8618_read_status(struct phy_device *phydev) -+{ -+ int ret; -+ volatile int val; //maybe for 8614 yt8521_fiber_latch_val, yt8521_fiber_curr_val; -+ volatile int link; -+ int link_utp = 0, link_fiber = 0; -+ -+ /* switch to utp and reading regs */ -+ ret = ytphy_write_ext(phydev, 0xa000, 0); -+ if (ret < 0) -+ return ret; -+ -+ val = phy_read(phydev, REG_PHY_SPEC_STATUS); -+ if (val < 0) -+ return val; -+ -+ link = val & (BIT(YT8521_LINK_STATUS_BIT)); -+ if (link) { -+ link_utp = 1; -+ yt8521_adjust_status(phydev, val, 1); -+ } else { -+ link_utp = 0; -+ } -+ -+ if (link_utp || link_fiber) { -+ phydev->link = 1; -+ } else { -+ phydev->link = 0; -+ } -+ -+ return 0; -+} -+ -+int yt8618_suspend(struct phy_device *phydev) -+{ -+#if !(SYS_WAKEUP_BASED_ON_ETH_PKT) -+ int value; -+ -+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) -+ mutex_lock(&phydev->lock); -+#else -+ /* no need lock in 4.19 */ -+#endif -+ -+ ytphy_write_ext(phydev, 0xa000, 0); -+ value = phy_read(phydev, MII_BMCR); -+ phy_write(phydev, MII_BMCR, value | BMCR_PDOWN); -+ -+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) -+ mutex_unlock(&phydev->lock); -+#else -+ /* no need lock/unlock in 4.19 */ -+#endif -+#endif /*!(SYS_WAKEUP_BASED_ON_ETH_PKT)*/ -+ -+ return 0; -+} -+ -+int yt8618_resume(struct phy_device *phydev) -+{ -+#if !(SYS_WAKEUP_BASED_ON_ETH_PKT) -+ int value; -+ -+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) -+ mutex_lock(&phydev->lock); -+#else -+ /* no need lock/unlock in 4.19 */ -+#endif -+ -+ ytphy_write_ext(phydev, 0xa000, 0); -+ value = phy_read(phydev, MII_BMCR); -+ phy_write(phydev, MII_BMCR, value & ~BMCR_PDOWN); -+ -+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) -+ mutex_unlock(&phydev->lock); -+#else -+ /* no need lock/unlock in 4.19 */ -+#endif -+#endif /*!(SYS_WAKEUP_BASED_ON_ETH_PKT)*/ -+ -+ return 0; -+} -+ -+int yt8614_suspend(struct phy_device *phydev) -+{ -+#if !(SYS_WAKEUP_BASED_ON_ETH_PKT) -+ int value; -+ -+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) -+ mutex_lock(&phydev->lock); -+#else -+ /* no need lock in 4.19 */ -+#endif -+ -+ ytphy_write_ext(phydev, 0xa000, 0); -+ value = phy_read(phydev, MII_BMCR); -+ phy_write(phydev, MII_BMCR, value | BMCR_PDOWN); -+ -+ ytphy_write_ext(phydev, 0xa000, 3); -+ value = phy_read(phydev, MII_BMCR); -+ phy_write(phydev, MII_BMCR, value | BMCR_PDOWN); -+ -+ ytphy_write_ext(phydev, 0xa000, 0); -+ -+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) -+ mutex_unlock(&phydev->lock); -+#else -+ /* no need lock/unlock in 4.19 */ -+#endif -+#endif /*!(SYS_WAKEUP_BASED_ON_ETH_PKT)*/ -+ -+ return 0; -+} -+ -+int yt8614_resume(struct phy_device *phydev) -+{ -+#if !(SYS_WAKEUP_BASED_ON_ETH_PKT) -+ int value; -+ -+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) -+ mutex_lock(&phydev->lock); -+#else -+ /* no need lock/unlock in 4.19 */ -+#endif -+ -+ ytphy_write_ext(phydev, 0xa000, 0); -+ value = phy_read(phydev, MII_BMCR); -+ phy_write(phydev, MII_BMCR, value & ~BMCR_PDOWN); -+ -+ ytphy_write_ext(phydev, 0xa000, 3); -+ value = phy_read(phydev, MII_BMCR); -+ phy_write(phydev, MII_BMCR, value & ~BMCR_PDOWN); -+ -+ ytphy_write_ext(phydev, 0xa000, 0); -+ -+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) -+ mutex_unlock(&phydev->lock); -+#else -+ /* no need lock/unlock in 4.19 */ -+#endif -+#endif /*!(SYS_WAKEUP_BASED_ON_ETH_PKT)*/ -+ -+ return 0; -+} -+ -+ +static struct phy_driver ytphy_drvs[] = { + { -+ .phy_id = PHY_ID_YT8010, -+ .name = "YT8010 Automotive Ethernet", -+ .phy_id_mask = MOTORCOMM_PHY_ID_MASK, -+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(5,4,0) ) -+ .features = PHY_BASIC_FEATURES, -+ .flags = PHY_HAS_INTERRUPT, -+#endif -+ .config_aneg = yt8010_config_aneg, -+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) -+ .config_init = ytphy_config_init, -+#else -+ .config_init = genphy_config_init, -+#endif -+ .read_status = genphy_read_status, ++ .phy_id = PHY_ID_YT8010, ++ .name = "YT8010 Automotive Ethernet", ++ .phy_id_mask = MOTORCOMM_PHY_ID_MASK, ++ .features = PHY_BASIC_FEATURES, ++ .config_aneg = yt8010_config_aneg, ++ .read_status = genphy_read_status, + }, { + .phy_id = PHY_ID_YT8510, + .name = "YT8510 100/10Mb Ethernet", + .phy_id_mask = MOTORCOMM_PHY_ID_MASK, -+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(5,4,0) ) + .features = PHY_BASIC_FEATURES, -+ .flags = PHY_HAS_INTERRUPT, -+#endif -+ .config_aneg = genphy_config_aneg, -+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) -+ .config_init = ytphy_config_init, -+#else -+ .config_init = genphy_config_init, -+#endif + .read_status = genphy_read_status, + }, { + .phy_id = PHY_ID_YT8511, + .name = "YT8511 Gigabit Ethernet", + .phy_id_mask = MOTORCOMM_PHY_ID_MASK, -+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(5,4,0) ) + .features = PHY_GBIT_FEATURES, -+ .flags = PHY_HAS_INTERRUPT, -+#endif -+ .config_aneg = genphy_config_aneg, -+#if GMAC_CLOCK_INPUT_NEEDED -+ .config_init = yt8511_config_init, -+#else -+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) -+ .config_init = ytphy_config_init, -+#else -+ .config_init = genphy_config_init, -+#endif -+#endif + .read_status = genphy_read_status, + .suspend = genphy_suspend, + .resume = genphy_resume, @@ -1451,11 +341,7 @@ Subject: [PATCH 3/3] Add yt8531c support + .phy_id = PHY_ID_YT8512, + .name = "YT8512 Ethernet", + .phy_id_mask = MOTORCOMM_PHY_ID_MASK, -+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(5,4,0) ) + .features = PHY_BASIC_FEATURES, -+ .flags = PHY_HAS_INTERRUPT, -+#endif -+ .config_aneg = genphy_config_aneg, + .config_init = yt8512_config_init, + .read_status = yt8512_read_status, + .suspend = genphy_suspend, @@ -1464,177 +350,25 @@ Subject: [PATCH 3/3] Add yt8531c support + .phy_id = PHY_ID_YT8512B, + .name = "YT8512B Ethernet", + .phy_id_mask = MOTORCOMM_PHY_ID_MASK, -+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(5,4,0) ) + .features = PHY_BASIC_FEATURES, -+ .flags = PHY_HAS_INTERRUPT, -+#endif -+ .config_aneg = genphy_config_aneg, + .config_init = yt8512_config_init, + .read_status = yt8512_read_status, + .suspend = genphy_suspend, + .resume = genphy_resume, + }, { -+ .phy_id = PHY_ID_YT8521, -+ .name = "YT8521 Ethernet", -+ .phy_id_mask = MOTORCOMM_PHY_ID_MASK, -+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(5,4,0) ) -+ .features = PHY_BASIC_FEATURES | PHY_GBIT_FEATURES, -+#endif -+ .flags = PHY_POLL, -+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) -+#else -+ .soft_reset = yt8521_soft_reset, -+#endif -+ .config_aneg = genphy_config_aneg, -+#if ( LINUX_VERSION_CODE > KERNEL_VERSION(3,11,0) ) -+ .aneg_done = yt8521_aneg_done, -+#endif -+ .config_init = yt8521_config_init, -+ .read_status = yt8521_read_status, -+ .suspend = yt8521_suspend, -+ .resume = yt8521_resume, -+#if (YTPHY_ENABLE_WOL) -+ .get_wol = &ytphy_get_wol, -+ .set_wol = &ytphy_set_wol, -+#endif -+ },{ -+ /* same as 8521 */ -+ .phy_id = PHY_ID_YT8531S, -+ .name = "YT8531S Ethernet", -+ .phy_id_mask = MOTORCOMM_PHY_ID_MASK, -+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(5,4,0) ) -+ .features = PHY_BASIC_FEATURES | PHY_GBIT_FEATURES, -+#endif -+ .flags = PHY_POLL, -+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) -+#else -+ .soft_reset = yt8521_soft_reset, -+#endif -+ .config_aneg = genphy_config_aneg, -+#if ( LINUX_VERSION_CODE > KERNEL_VERSION(3,11,0) ) -+ .aneg_done = yt8521_aneg_done, -+#endif -+ .config_init = yt8521_config_init, -+ .read_status = yt8521_read_status, -+ .suspend = yt8521_suspend, -+ .resume = yt8521_resume, -+#if (YTPHY_ENABLE_WOL) -+ .get_wol = &ytphy_get_wol, -+ .set_wol = &ytphy_set_wol, -+#endif -+ }, { -+ /* same as 8511 */ -+ .phy_id = PHY_ID_YT8531, -+ .name = "YT8531 Gigabit Ethernet", ++ .phy_id = PHY_ID_YT8521, ++ .name = "YT8521 Ethernet", + .phy_id_mask = MOTORCOMM_PHY_ID_MASK, -+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(5,4,0) ) -+ .features = PHY_BASIC_FEATURES | PHY_GBIT_FEATURES, -+ .flags = PHY_HAS_INTERRUPT, -+#endif -+ .config_aneg = genphy_config_aneg, -+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) -+ .config_init = ytphy_config_init, -+#else -+ .config_init = genphy_config_init, -+#endif -+ .read_status = genphy_read_status, ++ /* PHY_GBIT_FEATURES */ ++ .config_init = yt8521_config_init, ++ .ack_interrupt = yt8521_ack_interrupt, ++ .config_intr = yt8521_config_intr, + .suspend = genphy_suspend, + .resume = genphy_resume, -+#if (YTPHY_ENABLE_WOL) -+ .get_wol = &ytphy_get_wol, -+ .set_wol = &ytphy_set_wol, -+#endif -+ }, { -+ .phy_id = PHY_ID_YT8618, -+ .name = "YT8618 Ethernet", -+ .phy_id_mask = MOTORCOMM_MPHY_ID_MASK, -+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(5,4,0) ) -+ .features = PHY_BASIC_FEATURES | PHY_GBIT_FEATURES, -+#endif -+ .flags = PHY_POLL, -+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) -+#else -+ .soft_reset = yt8618_soft_reset, -+#endif -+ .config_aneg = genphy_config_aneg, -+#if ( LINUX_VERSION_CODE > KERNEL_VERSION(3,11,0) ) -+ .aneg_done = yt8618_aneg_done, -+#endif -+ .config_init = yt8618_config_init, -+ .read_status = yt8618_read_status, -+ .suspend = yt8618_suspend, -+ .resume = yt8618_resume, -+ }, { -+ .phy_id = PHY_ID_YT8614, -+ .name = "YT8614 Ethernet", -+ .phy_id_mask = MOTORCOMM_MPHY_ID_MASK_8614, -+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(5,4,0) ) -+ .features = PHY_BASIC_FEATURES | PHY_GBIT_FEATURES, -+#endif -+ .flags = PHY_POLL, -+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) -+#else -+ .soft_reset = yt8614_soft_reset, -+#endif -+ .config_aneg = genphy_config_aneg, -+#if ( LINUX_VERSION_CODE > KERNEL_VERSION(3,11,0) ) -+ .aneg_done = yt8614_aneg_done, -+#endif -+ .config_init = yt8614_config_init, -+ .read_status = yt8614_read_status, -+ .suspend = yt8614_suspend, -+ .resume = yt8614_resume, -+ }, ++ }, +}; + -+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) -+static int ytphy_drivers_register(struct phy_driver* phy_drvs, int size) -+{ -+ int i, j; -+ int ret; -+ -+ for (i = 0; i < size; i++) { -+ ret = phy_driver_register(&phy_drvs[i]); -+ if (ret) -+ goto err; -+ } -+ -+ return 0; -+ -+err: -+ for (j = 0; j < i; j++) -+ phy_driver_unregister(&phy_drvs[j]); -+ -+ return ret; -+} -+ -+static void ytphy_drivers_unregister(struct phy_driver* phy_drvs, int size) -+{ -+ int i; -+ -+ for (i = 0; i < size; i++) { -+ phy_driver_unregister(&phy_drvs[i]); -+ } -+} -+ -+static int __init ytphy_init(void) -+{ -+ printk("motorcomm phy register\n"); -+ return ytphy_drivers_register(ytphy_drvs, ARRAY_SIZE(ytphy_drvs)); -+} -+ -+static void __exit ytphy_exit(void) -+{ -+ printk("motorcomm phy unregister\n"); -+ ytphy_drivers_unregister(ytphy_drvs, ARRAY_SIZE(ytphy_drvs)); -+} -+ -+module_init(ytphy_init); -+module_exit(ytphy_exit); -+#else -+/* for linux 4.x */ +module_phy_driver(ytphy_drvs); -+#endif + +MODULE_DESCRIPTION("Motorcomm PHY driver"); +MODULE_AUTHOR("Leilei Zhao"); @@ -1647,544 +381,13 @@ Subject: [PATCH 3/3] Add yt8531c support + { PHY_ID_YT8512, MOTORCOMM_PHY_ID_MASK }, + { PHY_ID_YT8512B, MOTORCOMM_PHY_ID_MASK }, + { PHY_ID_YT8521, MOTORCOMM_PHY_ID_MASK }, -+ { PHY_ID_YT8531S, MOTORCOMM_PHY_ID_8531_MASK }, -+ { PHY_ID_YT8531, MOTORCOMM_PHY_ID_8531_MASK }, -+ { PHY_ID_YT8618, MOTORCOMM_MPHY_ID_MASK }, -+ { PHY_ID_YT8614, MOTORCOMM_MPHY_ID_MASK_8614 }, + { } +}; + +MODULE_DEVICE_TABLE(mdio, motorcomm_tbl); -+ -+ ---- a/drivers/net/phy/phy_device.c -+++ b/drivers/net/phy/phy_device.c -@@ -808,6 +808,8 @@ - return 0; - } - -+int yt8511_config_out_125m(struct mii_bus *bus, int phy_id); -+ - /** - * get_phy_device - reads the specified PHY device and returns its @phy_device - * struct -@@ -835,6 +837,19 @@ - if ((phy_id & 0x1fffffff) == 0x1fffffff) - return ERR_PTR(-ENODEV); - -+ printk (KERN_INFO "yzhang..read phyaddr=%d, phyid=%08x\n",addr, phy_id); -+ -+ if(phy_id == 0x4f51e91b) -+ { -+ printk (KERN_INFO "yzhang..get YT8511, abt to set 125m clk out, phyaddr=%d, phyid=%08x\n",addr, phy_id); -+ r = yt8511_config_out_125m(bus, addr); -+ printk (KERN_INFO "yzhang..8511 set 125m clk out, reg=%#04x\n",bus->read(bus,addr,0x1f)/*double check as delay*/); -+ if (r<0) -+ { -+ printk (KERN_INFO "yzhang..failed to set 125m clk out, ret=%d\n",r); -+ } -+ } -+ - return phy_device_create(bus, addr, phy_id, is_c45, &c45_ids); - } - EXPORT_SYMBOL(get_phy_device); ---- /dev/null -+++ b/drivers/net/phy/yt8614-phy.h -@@ -0,0 +1,491 @@ -+#ifndef _PHY_H_ -+#define _PHY_H_ -+ -+ -+/* configuration for driver */ -+ -+#define YT8614_MAX_LPORT_ID 3 -+ -+#define YT8614_PHY_MODE_FIBER 1 //fiber mode only -+#define YT8614_PHY_MODE_UTP 2 //utp mode only -+#define YT8614_PHY_MODE_POLL 3 //fiber and utp, poll mode -+ -+/* please make choice according to system design -+ * for Fiber only system, please define YT8614_PHY_MODE_CURR 1 -+ * for UTP only system, please define YT8614_PHY_MODE_CURR 2 -+ * for combo system, please define YT8614_PHY_MODE_CURR 3 -+ */ -+#define YT8614_PHY_MODE_CURR 3 -+ -+ -+ -+/* pls dont modify below lines */ -+ -+#define PHY_ID_YT8614 0x4F51E899 //serdes -+#define MOTORCOMM_MPHY_ID_MASK_8614 0xffffffff -+ -+#ifndef BOOL -+#define BOOL unsigned int -+#endif -+ -+#ifndef FALSE -+#define FALSE 0 -+#endif -+ -+#ifndef TRUE -+#define TRUE 1 -+#endif -+ -+#ifndef SPEED_1000M -+#define SPEED_1000M 2 -+#endif -+#ifndef SPEED_100M -+#define SPEED_100M 1 -+#endif -+#ifndef SPEED_10M -+#define SPEED_10M 0 -+#endif -+ -+#ifndef SPEED_UNKNOWN -+#define SPEED_UNKNOWN 0xffff -+#endif -+ -+#ifndef DUPLEX_FULL -+#define DUPLEX_FULL 1 -+#endif -+#ifndef DUPLEX_HALF -+#define DUPLEX_HALF 0 -+#endif -+ -+#ifndef BIT -+#define BIT(n) (0x1<<(n)) -+#endif -+#ifndef s32 -+typedef int s32; -+typedef unsigned int u32; -+typedef unsigned short u16; -+typedef unsigned char u8; -+#endif -+ -+#ifndef REG_PHY_SPEC_STATUS -+#define REG_PHY_SPEC_STATUS 0x11 -+#define REG_DEBUG_ADDR_OFFSET 0x1e -+#define REG_DEBUG_DATA 0x1f -+#endif -+ -+/**********YT8614************************************************/ -+ -+#define YT8614_SMI_SEL_PHY 0x0 -+#define YT8614_SMI_SEL_SDS_QSGMII 0x02 -+#define YT8614_SMI_SEL_SDS_SGMII 0x03 -+ -+/* yt8614 register type */ -+#define YT8614_TYPE_COMMON 0x01 -+#define YT8614_TYPE_UTP_MII 0x02 -+#define YT8614_TYPE_UTP_EXT 0x03 -+#define YT8614_TYPE_LDS_MII 0x04 -+#define YT8614_TYPE_UTP_MMD 0x05 -+#define YT8614_TYPE_SDS_QSGMII_MII 0x06 -+#define YT8614_TYPE_SDS_SGMII_MII 0x07 -+#define YT8614_TYPE_SDS_QSGMII_EXT 0x08 -+#define YT8614_TYPE_SDS_SGMII_EXT 0x09 -+ -+/* YT8614 extended common register */ -+#define YT8614_REG_COM_SMI_MUX 0xA000 -+#define YT8614_REG_COM_SLED_CFG0 0xA001 -+#define YT8614_REG_COM_PHY_ID 0xA002 -+#define YT8614_REG_COM_CHIP_VER 0xA003 -+#define YT8614_REG_COM_SLED_CFG 0xA004 -+#define YT8614_REG_COM_MODE_CHG_RESET 0xA005 -+#define YT8614_REG_COM_SYNCE0_CFG 0xA006 -+#define YT8614_REG_COM_CHIP_MODE 0xA007 -+ -+#define YT8614_REG_COM_HIDE_SPEED 0xA009 -+ -+#define YT8614_REG_COM_SYNCE1_CFG 0xA00E -+ -+#define YT8614_REG_COM_HIDE_FIBER_MODE 0xA019 -+ -+ -+#define YT8614_REG_COM_HIDE_SEL1 0xA054 -+#define YT8614_REG_COM_HIDE_LED_CFG2 0xB8 -+#define YT8614_REG_COM_HIDE_LED_CFG3 0xB9 -+#define YT8614_REG_COM_HIDE_LED_CFG5 0xBB -+ -+#define YT8614_REG_COM_HIDE_LED_CFG4 0xBA //not used currently -+ -+#if 0 -+#define YT8614_REG_COM_HIDE_LED12_CFG 0xA060 //not used currently -+#define YT8614_REG_COM_HIDE_LED13_CFG 0xA061 -+#define YT8614_REG_COM_HIDE_LED14_CFG 0xA062 -+#define YT8614_REG_COM_HIDE_LED15_CFG 0xA063 -+#define YT8614_REG_COM_HIDE_LED16_CFG 0xA064 -+#define YT8614_REG_COM_HIDE_LED17_CFG 0xA065 -+#define YT8614_REG_COM_HIDE_LED18_CFG 0xA066 -+#define YT8614_REG_COM_HIDE_LED19_CFG 0xA067 -+#define YT8614_REG_COM_HIDE_LED20_CFG 0xA068 -+#define YT8614_REG_COM_HIDE_LED21_CFG 0xA069 -+#define YT8614_REG_COM_HIDE_LED22_CFG 0xA06A -+#define YT8614_REG_COM_HIDE_LED23_CFG 0xA06B -+#define YT8614_REG_COM_HIDE_LED24_CFG 0xA06C -+#define YT8614_REG_COM_HIDE_LED25_CFG 0xA06D -+#define YT8614_REG_COM_HIDE_LED26_CFG 0xA06E -+#define YT8614_REG_COM_HIDE_LED27_CFG 0xA06F -+#endif -+ -+#define YT8614_REG_COM_HIDE_LED28_CFG 0xA070 -+#define YT8614_REG_COM_HIDE_LED29_CFG 0xA071 -+#define YT8614_REG_COM_HIDE_LED30_CFG 0xA072 -+#define YT8614_REG_COM_HIDE_LED31_CFG 0xA073 -+#define YT8614_REG_COM_HIDE_LED32_CFG 0xA074 -+#define YT8614_REG_COM_HIDE_LED33_CFG 0xA075 -+#define YT8614_REG_COM_HIDE_LED34_CFG 0xA076 -+#define YT8614_REG_COM_HIDE_LED35_CFG 0xA077 -+ -+#define YT8614_REG_COM_PKG_CFG0 0xA0A0 -+#define YT8614_REG_COM_PKG_CFG1 0xA0A1 -+#define YT8614_REG_COM_PKG_CFG2 0xA0A2 -+#define YT8614_REG_COM_PKG_RX_VALID0 0xA0A3 -+#define YT8614_REG_COM_PKG_RX_VALID1 0xA0A4 -+#define YT8614_REG_COM_PKG_RX_OS0 0xA0A5 -+#define YT8614_REG_COM_PKG_RX_OS1 0xA0A6 -+#define YT8614_REG_COM_PKG_RX_US0 0xA0A7 -+#define YT8614_REG_COM_PKG_RX_US1 0xA0A8 -+#define YT8614_REG_COM_PKG_RX_ERR 0xA0A9 -+#define YT8614_REG_COM_PKG_RX_OS_BAD 0xA0AA -+#define YT8614_REG_COM_PKG_RX_FRAG 0xA0AB -+#define YT8614_REG_COM_PKG_RX_NOSFD 0xA0AC -+#define YT8614_REG_COM_PKG_TX_VALID0 0xA0AD -+#define YT8614_REG_COM_PKG_TX_VALID1 0xA0AE -+#define YT8614_REG_COM_PKG_TX_OS0 0xA0AF -+ -+#define YT8614_REG_COM_PKG_TX_OS1 0xA0B0 -+#define YT8614_REG_COM_PKG_TX_US0 0xA0B1 -+#define YT8614_REG_COM_PKG_TX_US1 0xA0B2 -+#define YT8614_REG_COM_PKG_TX_ERR 0xA0B3 -+#define YT8614_REG_COM_PKG_TX_OS_BAD 0xA0B4 -+#define YT8614_REG_COM_PKG_TX_FRAG 0xA0B5 -+#define YT8614_REG_COM_PKG_TX_NOSFD 0xA0B6 -+#define YT8614_REG_COM_PKG_CFG3 0xA0B7 -+#define YT8614_REG_COM_PKG_AZ_CFG 0xA0B8 -+#define YT8614_REG_COM_PKG_DA_SA_CFG3 0xA0B9 -+ -+#define YT8614_REG_COM_MANU_HW_RESET 0xA0C0 -+ -+/* YT8614 UTP MII register: same as generic phy register definitions */ -+#define REG_MII_BMCR 0x00 /* Basic mode control register */ -+#define REG_MII_BMSR 0x01 /* Basic mode status register */ -+#define REG_MII_PHYSID1 0x02 /* PHYS ID 1 */ -+#define REG_MII_PHYSID2 0x03 /* PHYS ID 2 */ -+#define REG_MII_ADVERTISE 0x04 /* Advertisement control reg */ -+#define REG_MII_LPA 0x05 /* Link partner ability reg */ -+#define REG_MII_EXPANSION 0x06 /* Expansion register */ -+#define REG_MII_NEXT_PAGE 0x07 /* Next page register */ -+#define REG_MII_LPR_NEXT_PAGE 0x08 /* LPR next page register */ -+#define REG_MII_CTRL1000 0x09 /* 1000BASE-T control */ -+#define REG_MII_STAT1000 0x0A /* 1000BASE-T status */ -+ -+#define REG_MII_MMD_CTRL 0x0D /* MMD access control register */ -+#define REG_MII_MMD_DATA 0x0E /* MMD access data register */ -+ -+#define REG_MII_ESTATUS 0x0F /* Extended Status */ -+#define REG_MII_SPEC_CTRL 0x10 /* PHY specific func control */ -+#define REG_MII_SPEC_STATUS 0x11 /* PHY specific status */ -+#define REG_MII_INT_MASK 0x12 /* Interrupt mask register */ -+#define REG_MII_INT_STATUS 0x13 /* Interrupt status register */ -+#define REG_MII_DOWNG_CTRL 0x14 /* Speed auto downgrade control*/ -+#define REG_MII_RERRCOUNTER 0x15 /* Receive error counter */ -+ -+#define REG_MII_EXT_ADDR 0x1E /* Extended reg's address */ -+#define REG_MII_EXT_DATA 0x1F /* Extended reg's date */ -+ -+#ifndef MII_BMSR -+#define MII_BMSR REG_MII_BMSR -+#endif -+ -+#ifndef YT8614_SPEED_MODE_BIT -+#define YT8614_SPEED_MODE 0xc000 -+#define YT8614_DUPLEX 0x2000 -+#define YT8614_SPEED_MODE_BIT 14 -+#define YT8614_DUPLEX_BIT 13 -+#define YT8614_LINK_STATUS_BIT 10 -+ -+#endif -+ -+#define YT8614_REG_COM_HIDE_SPEED_CMB_PRI 0x2000 -+ -+/* YT8614 UTP MMD register */ -+#define YT8614_REG_UTP_MMD_CTRL1 0x00 /* PCS control 1 register */ -+#define YT8614_REG_UTP_MMD_STATUS1 0x01 /* PCS status 1 register */ -+#define YT8614_REG_UTP_MMD_EEE_CTRL 0x14 /* EEE control and capability */ -+#define YT8614_REG_UTP_MMD_EEE_WK_ERR_CNT 0x16 /* EEE wake error counter */ -+#define YT8614_REG_UTP_MMD_EEE_LOCAL_ABI 0x3C /* local device EEE ability */ -+#define YT8614_REG_UTP_MMD_EEE_LP_ABI 0x3D /* link partner EEE ability */ -+#define YT8614_REG_UTP_MMD_EEE_AUTONEG_RES 0x8000 /* autoneg result of EEE */ -+ -+/* YT8614 UTP EXT register */ -+#define YT8614_REG_UTP_EXT_LPBK 0x0A -+#define YT8614_REG_UTP_EXT_SLEEP_CTRL1 0x27 -+#define YT8614_REG_UTP_EXT_DEBUG_MON1 0x5A -+#define YT8614_REG_UTP_EXT_DEBUG_MON2 0x5B -+#define YT8614_REG_UTP_EXT_DEBUG_MON3 0x5C -+#define YT8614_REG_UTP_EXT_DEBUG_MON4 0x5D -+ -+/* YT8614 SDS(1.25G/5G) MII register: same as YT8521S */ -+#define REG_SDS_BMCR 0x00 /* Basic mode control register */ -+#define REG_SDS_BMSR 0x01 /* Basic mode status register */ -+#define REG_SDS_PHYSID1 0x02 /* PHYS ID 1 */ -+#define REG_SDS_PHYSID2 0x03 /* PHYS ID 2 */ -+#define REG_SDS_ADVERTISE 0x04 /* Advertisement control reg */ -+#define REG_SDS_LPA 0x05 /* Link partner ability reg */ -+#define REG_SDS_EXPANSION 0x06 /* Expansion register */ -+#define REG_SDS_NEXT_PAGE 0x07 /* Next page register */ -+#define REG_SDS_LPR_NEXT_PAGE 0x08 /* LPR next page register */ -+ -+#define REG_SDS_ESTATUS 0x0F /* Extended Status */ -+#define REG_SDS_SPEC_STATUS 0x11 /* SDS specific status */ -+ -+#define REG_SDS_100FX_CFG 0x14 /* 100fx cfg */ -+#define REG_SDS_RERRCOUNTER 0x15 /* Receive error counter */ -+#define REG_SDS_LINT_FAIL_CNT 0x16 /* Lint fail counter mon */ -+ -+/* YT8614 SDS(5G) EXT register */ -+#define YT8614_REG_QSGMII_EXT_ANA_DIG_CFG 0x02 /* sds analog digital interface cfg */ -+#define YT8614_REG_QSGMII_EXT_PRBS_CFG1 0x05 /* sds prbs cfg1 */ -+#define YT8614_REG_QSGMII_EXT_PRBS_CFG2_1 0x06 /* sds prbs cfg2 */ -+#define YT8614_REG_QSGMII_EXT_PRBS_CFG2_2 0x07 /* sds prbs cfg2 */ -+#define YT8614_REG_QSGMII_EXT_PRBS_MON1 0x08 /* sds prbs mon1 */ -+#define YT8614_REG_QSGMII_EXT_PRBS_MON2 0x09 /* sds prbs mon2 */ -+#define YT8614_REG_QSGMII_EXT_PRBS_MON3 0x0A /* sds prbs mon3 */ -+#define YT8614_REG_QSGMII_EXT_PRBS_MON4 0x0B /* sds prbs mon4 */ -+#define YT8614_REG_QSGMII_EXT_PRBS_MON5 0x0C /* sds prbs mon5 */ -+#define YT8614_REG_QSGMII_EXT_ANA_CFG2 0xA1 /* Analog cfg2 */ -+ -+/* YT8614 SDS(1.25G) EXT register */ -+#define YT8614_REG_SGMII_EXT_PRBS_CFG1 0x05 /* sds prbs cfg1 */ -+#define YT8614_REG_SGMII_EXT_PRBS_CFG2 0x06 /* sds prbs cfg2 */ -+#define YT8614_REG_SGMII_EXT_PRBS_MON1 0x08 /* sds prbs mon1 */ -+#define YT8614_REG_SGMII_EXT_PRBS_MON2 0x09 /* sds prbs mon2 */ -+#define YT8614_REG_SGMII_EXT_PRBS_MON3 0x0A /* sds prbs mon3 */ -+#define YT8614_REG_SGMII_EXT_PRBS_MON4 0x0B /* sds prbs mon4 */ -+#define YT8614_REG_SGMII_EXT_PRBS_MON5 0x0C /* sds prbs mon5 */ -+#define YT8614_REG_SGMII_EXT_ANA_CFG2 0xA1 /* Analog cfg2 */ -+#define YT8614_REG_SGMII_EXT_HIDE_AUTO_SEN 0xA5 /* Fiber auto sensing */ -+ -+//////////////////////////////////////////////////////////////////// -+#define YT8614_MMD_DEV_ADDR1 0x1 -+#define YT8614_MMD_DEV_ADDR3 0x3 -+#define YT8614_MMD_DEV_ADDR7 0x7 -+#define YT8614_MMD_DEV_ADDR_NONE 0xFF -+ -+/**********YT8521S************************************************/ -+/* Basic mode control register(0x00) */ -+#define BMCR_RESV 0x003f /* Unused... */ -+#define BMCR_SPEED1000 0x0040 /* MSB of Speed (1000) */ -+#define BMCR_CTST 0x0080 /* Collision test */ -+#define BMCR_FULLDPLX 0x0100 /* Full duplex */ -+#define BMCR_ANRESTART 0x0200 /* Auto negotiation restart */ -+#define BMCR_ISOLATE 0x0400 /* Disconnect DP83840 from MII */ -+#define BMCR_PDOWN 0x0800 /* Powerdown the DP83840 */ -+#define BMCR_ANENABLE 0x1000 /* Enable auto negotiation */ -+#define BMCR_SPEED100 0x2000 /* Select 100Mbps */ -+#define BMCR_LOOPBACK 0x4000 /* TXD loopback bits */ -+#define BMCR_RESET 0x8000 /* Reset the DP83840 */ -+ -+/* Basic mode status register(0x01) */ -+#define BMSR_ERCAP 0x0001 /* Ext-reg capability */ -+#define BMSR_JCD 0x0002 /* Jabber detected */ -+#define BMSR_LSTATUS 0x0004 /* Link status */ -+#define BMSR_ANEGCAPABLE 0x0008 /* Able to do auto-negotiation */ -+#define BMSR_RFAULT 0x0010 /* Remote fault detected */ -+#define BMSR_ANEGCOMPLETE 0x0020 /* Auto-negotiation complete */ -+#define BMSR_RESV 0x00c0 /* Unused... */ -+#define BMSR_ESTATEN 0x0100 /* Extended Status in R15 */ -+#define BMSR_100HALF2 0x0200 /* Can do 100BASE-T2 HDX */ -+#define BMSR_100FULL2 0x0400 /* Can do 100BASE-T2 FDX */ -+#define BMSR_10HALF 0x0800 /* Can do 10mbps, half-duplex */ -+#define BMSR_10FULL 0x1000 /* Can do 10mbps, full-duplex */ -+#define BMSR_100HALF 0x2000 /* Can do 100mbps, half-duplex */ -+#define BMSR_100FULL 0x4000 /* Can do 100mbps, full-duplex */ -+#define BMSR_100BASE4 0x8000 /* Can do 100mbps, 4k packets */ -+ -+/* Advertisement control register(0x04) */ -+#define ADVERTISE_SLCT 0x001f /* Selector bits */ -+#define ADVERTISE_CSMA 0x0001 /* Only selector supported */ -+#define ADVERTISE_10HALF 0x0020 /* Try for 10mbps half-duplex */ -+#define ADVERTISE_1000XFULL 0x0020 /* Try for 1000BASE-X full-duplex */ -+#define ADVERTISE_10FULL 0x0040 /* Try for 10mbps full-duplex */ -+#define ADVERTISE_1000XHALF 0x0040 /* Try for 1000BASE-X half-duplex */ -+#define ADVERTISE_100HALF 0x0080 /* Try for 100mbps half-duplex */ -+#define ADVERTISE_1000XPAUSE 0x0080 /* Try for 1000BASE-X pause */ -+#define ADVERTISE_100FULL 0x0100 /* Try for 100mbps full-duplex */ -+#define ADVERTISE_1000XPSE_ASYM 0x0100 /* Try for 1000BASE-X asym pause */ -+#define ADVERTISE_100BASE4 0x0200 /* Try for 100mbps 4k packets */ -+#define ADVERTISE_PAUSE_CAP 0x0400 /* Try for pause */ -+#define ADVERTISE_PAUSE_ASYM 0x0800 /* Try for asymetric pause */ -+#define ADVERTISE_RESV 0x1000 /* Unused... */ -+#define ADVERTISE_RFAULT 0x2000 /* Say we can detect faults */ -+#define ADVERTISE_LPACK 0x4000 /* Ack link partners response */ -+#define ADVERTISE_NPAGE 0x8000 /* Next page bit */ -+ -+#define ADVERTISE_FULL (ADVERTISE_100FULL | ADVERTISE_10FULL | ADVERTISE_CSMA) -+#define ADVERTISE_ALL (ADVERTISE_10HALF | ADVERTISE_10FULL | \ -+ ADVERTISE_100HALF | ADVERTISE_100FULL) -+ -+/* Link partner ability register(0x05) */ -+#define LPA_SLCT 0x001f /* Same as advertise selector */ -+#define LPA_10HALF 0x0020 /* Can do 10mbps half-duplex */ -+#define LPA_1000XFULL 0x0020 /* Can do 1000BASE-X full-duplex */ -+#define LPA_10FULL 0x0040 /* Can do 10mbps full-duplex */ -+#define LPA_1000XHALF 0x0040 /* Can do 1000BASE-X half-duplex */ -+#define LPA_100HALF 0x0080 /* Can do 100mbps half-duplex */ -+#define LPA_1000XPAUSE 0x0080 /* Can do 1000BASE-X pause */ -+#define LPA_100FULL 0x0100 /* Can do 100mbps full-duplex */ -+#define LPA_1000XPAUSE_ASYM 0x0100 /* Can do 1000BASE-X pause asym */ -+#define LPA_100BASE4 0x0200 /* Can do 100mbps 4k packets */ -+#define LPA_PAUSE_CAP 0x0400 /* Can pause */ -+#define LPA_PAUSE_ASYM 0x0800 /* Can pause asymetrically */ -+#define LPA_RESV 0x1000 /* Unused... */ -+#define LPA_RFAULT 0x2000 /* Link partner faulted */ -+#define LPA_LPACK 0x4000 /* Link partner acked us */ -+#define LPA_NPAGE 0x8000 /* Next page bit */ -+ -+/* 1000BASE-T Control register(0x09) */ -+#define ADVERTISE_1000FULL 0x0200 /* Advertise 1000BASE-T full duplex */ -+#define ADVERTISE_1000HALF 0x0100 /* Advertise 1000BASE-T half duplex */ -+#define CTL1000_AS_MASTER 0x0800 -+#define CTL1000_ENABLE_MASTER 0x1000 -+ -+/* 1000BASE-T Status register(0x0A) */ -+#define LPA_1000LOCALRXOK 0x2000 /* Link partner local receiver status */ -+#define LPA_1000REMRXOK 0x1000 /* Link partner remote receiver status */ -+#define LPA_1000FULL 0x0800 /* Link partner 1000BASE-T full duplex */ -+#define LPA_1000HALF 0x0400 /* Link partner 1000BASE-T half duplex */ -+ -+/**********YT8614************************************************/ -+/* Basic mode control register(0x00) */ -+#define FIBER_BMCR_RESV 0x001f /* b[4:0] Unused... */ -+#define FIBER_BMCR_EN_UNIDIR 0x0020 /* b[5] Valid when bit 0.12 is zero and bit 0.8 is one */ -+#define FIBER_BMCR_SPEED1000 0x0040 /* b[6] MSB of Speed (1000) */ -+#define FIBER_BMCR_CTST 0x0080 /* b[7] Collision test */ -+#define FIBER_BMCR_DUPLEX_MODE 0x0100 /* b[8] Duplex mode */ -+#define FIBER_BMCR_ANRESTART 0x0200 /* b[9] Auto negotiation restart */ -+#define FIBER_BMCR_ISOLATE 0x0400 /* b[10] Isolate phy from RGMII/SGMII/FIBER */ -+#define FIBER_BMCR_PDOWN 0x0800 /* b[11] 1: Power down */ -+#define FIBER_BMCR_ANENABLE 0x1000 /* b[12] Enable auto negotiation */ -+#define FIBER_BMCR_SPEED100 0x2000 /* b[13] LSB of Speed (100) */ -+#define FIBER_BMCR_LOOPBACK 0x4000 /* b[14] Internal loopback control */ -+#define FIBER_BMCR_RESET 0x8000 /* b[15] PHY Software Reset(self-clear) */ -+ -+/* Sds specific status register(0x11) */ -+#define FIBER_SSR_ERCAP 0x0001 /* b[0] realtime syncstatus */ -+#define FIBER_SSR_XMIT 0x000E /* b[3:1] realtime transmit statemachine. -+ 001: Xmit Idle; -+ 010: Xmit Config; -+ 100: Xmit Data. */ -+#define FIBER_SSR_SER_MODE_CFG 0x0030 /* b[5:4] realtime serdes working mode. -+ 00: SG_MAC; -+ 01: SG_PHY; -+ 10: FIB_1000; -+ 11: FIB_100. */ -+#define FIBER_SSR_EN_FLOWCTRL_TX 0x0040 /* b[6] realtime en_flowctrl_tx */ -+#define FIBER_SSR_EN_FLOWCTRL_RX 0x0080 /* b[7] realtime en_flowctrl_rx */ -+#define FIBER_SSR_DUPLEX_ERROR 0x0100 /* b[8] realtime deplex error */ -+#define FIBER_SSR_RX_LPI_ACTIVE 0x0200 /* b[9] rx lpi is active */ -+#define FIBER_SSR_LSTATUS 0x0400 /* b[10] Link status real-time */ -+#define FIBER_SSR_PAUSE 0x1800 /* b[12:11] Pause to mac */ -+#define FIBER_SSR_DUPLEX 0x2000 /* b[13] This status bit is valid only when bit10 is 1. -+ 1: full duplex -+ 0: half duplex */ -+#define FIBER_SSR_SPEED_MODE 0xC000 /* b[15:14] These status bits are valid only when bit10 is 1. -+ 10---1000M -+ 01---100M */ -+ -+/* SLED cfg0 (ext 0xA001) */ -+#define FIBER_SLED_CFG0_EN_CTRL 0x00FF /* b[7:0] Control to enable the eight ports' SLED */ -+#define FIBER_SLED_CFG0_BIT_MASK 0x0700 /* b[10:8] 1: enable the pin output */ -+#define FIBER_SLED_CFG0_ACT_LOW 0x0800 /* b[11] control SLED's polarity. 1: active low; 0: active high */ -+#define FIBER_SLED_CFG0_MANU_ST 0x7000 /* b[14:12] SLEDs' manul status, corresponding to each port's 3 SLEDs */ -+#define FIBER_SLED_CFG0_MANU_EN 0x8000 /* b[15] to control serial LEDs status manually */ -+ -+/**********YT8614************************************************/ -+/* Fiber auto sensing(sgmii ext 0xA5) */ -+#define FIBER_AUTO_SEN_ENABLE 0x8000 /* b[15] Enable fiber auto sensing */ -+ -+/* Fiber force speed(common ext 0xA009) */ -+#define FIBER_FORCE_1000M 0x0001 /* b[0] 1:1000BX 0:100FX */ -+ -+#ifndef NULL -+#define NULL 0 -+#endif -+ -+/* errno */ -+enum ytphy_8614_errno_e -+{ -+ SYS_E_NONE, -+ SYS_E_PARAM, -+ SYS_E_MAX -+}; -+ -+/* errno */ -+enum ytphy_8614_combo_speed_e -+{ -+ YT8614_COMBO_FIBER_1000M, -+ YT8614_COMBO_FIBER_100M, -+ YT8614_COMBO_UTP_ONLY, -+ YT8614_COMBO_SPEED_MAX -+}; -+ -+/* definition for porting */ -+/* phy registers access */ -+typedef struct -+{ -+ u16 reg; /* the offset of the phy internal address */ -+ u16 val; /* the value of the register */ -+ u8 regType; /* register type */ -+} phy_data_s; -+ -+/* for porting use. -+ * pls over-write member function read/write for mdio access -+ */ -+typedef struct phy_info_str -+{ -+#if 0 -+ struct phy_device *phydev; -+ int mdio_base; -+#endif -+ unsigned int lport; -+ unsigned int bus_id; -+ unsigned int phy_addr; -+ -+ s32 (*read)(struct phy_info_str *info, phy_data_s *param); -+ s32 (*write)(struct phy_info_str *info, phy_data_s *param); -+}phy_info_s; -+ -+/* get phy access method */ -+s32 yt8614_read_reg(struct phy_info_str *info, phy_data_s *param); -+s32 yt8614_write_reg(struct phy_info_str *info, phy_data_s *param); -+s32 yt8614_phy_soft_reset(u32 lport); -+s32 yt8614_phy_init(u32 lport); -+s32 yt8614_fiber_enable(u32 lport, BOOL enable); -+s32 yt8614_utp_enable(u32 lport, BOOL enable); -+s32 yt8614_fiber_unidirection_set(u32 lport, int speed, BOOL enable); -+s32 yt8614_fiber_autosensing_set(u32 lport, BOOL enable); -+s32 yt8614_fiber_speed_set(u32 lport, int fiber_speed); -+s32 yt8614_qsgmii_autoneg_set(u32 lport, BOOL enable); -+s32 yt8614_sgmii_autoneg_set(u32 lport, BOOL enable); -+s32 yt8614_qsgmii_sgmii_link_status_get(u32 lport, BOOL *enable, BOOL if_qsgmii); -+int yt8614_combo_media_priority_set (u32 lport, int fiber); -+int yt8614_combo_media_priority_get (u32 lport, int *fiber); -+s32 yt8614_utp_autoneg_set(u32 lport, BOOL enable); -+s32 yt8614_utp_autoneg_get(u32 lport, BOOL *enable); -+s32 yt8614_utp_autoneg_ability_set(u32 lport, unsigned int cap_mask); -+s32 yt8614_utp_autoneg_ability_get(u32 lport, unsigned int *cap_mask); -+s32 yt8614_utp_force_duplex_set(u32 lport, BOOL full); -+s32 yt8614_utp_force_duplex_get(u32 lport, BOOL *full); -+s32 yt8614_utp_force_speed_set(u32 lport, unsigned int speed); -+s32 yt8614_utp_force_speed_get(u32 lport, unsigned int *speed); -+int yt8614_autoneg_done_get (u32 lport, int speed, int *aneg); -+int yt8614_media_status_get(u32 lport, int* speed, int* duplex, int* ret_link, int *media); -+ -+#endif --- /dev/null +++ b/include/linux/motorcomm_phy.h -@@ -0,0 +1,119 @@ +@@ -0,0 +1,67 @@ +/* + * include/linux/motorcomm_phy.h + * @@ -2201,8 +404,6 @@ Subject: [PATCH 3/3] Add yt8531c support +#define _MOTORCOMM_PHY_H + +#define MOTORCOMM_PHY_ID_MASK 0x00000fff -+#define MOTORCOMM_PHY_ID_8531_MASK 0xffffffff -+#define MOTORCOMM_MPHY_ID_MASK 0x0000ffff + +#define PHY_ID_YT8010 0x00000309 +#define PHY_ID_YT8510 0x00000109 @@ -2210,12 +411,10 @@ Subject: [PATCH 3/3] Add yt8531c support +#define PHY_ID_YT8512 0x00000118 +#define PHY_ID_YT8512B 0x00000128 +#define PHY_ID_YT8521 0x0000011a -+#define PHY_ID_YT8531S 0x4f51e91a -+#define PHY_ID_YT8531 0x4f51e91b -+//#define PHY_ID_YT8614 0x0000e899 -+#define PHY_ID_YT8618 0x0000e889 + +#define REG_PHY_SPEC_STATUS 0x11 ++#define REG_INT_MASK 0x12 ++#define REG_INT_STATUS 0x13 +#define REG_DEBUG_ADDR_OFFSET 0x1e +#define REG_DEBUG_DATA 0x1f + @@ -2255,54 +454,4 @@ Subject: [PATCH 3/3] Add yt8531c support +#define YT8521_DUPLEX_BIT 13 +#define YT8521_LINK_STATUS_BIT 10 + -+/* based on yt8521 wol config register */ -+#define YTPHY_UTP_INTR_REG 0x12 -+/* WOL Event Interrupt Enable */ -+#define YTPHY_WOL_INTR BIT(6) -+ -+/* Magic Packet MAC address registers */ -+#define YTPHY_MAGIC_PACKET_MAC_ADDR2 0xa007 -+#define YTPHY_MAGIC_PACKET_MAC_ADDR1 0xa008 -+#define YTPHY_MAGIC_PACKET_MAC_ADDR0 0xa009 -+ -+#define YTPHY_WOL_CFG_REG 0xa00a -+#define YTPHY_WOL_CFG_TYPE BIT(0) /* WOL TYPE */ -+#define YTPHY_WOL_CFG_EN BIT(3) /* WOL Enable */ -+#define YTPHY_WOL_CFG_INTR_SEL BIT(6) /* WOL Event Interrupt Enable */ -+#define YTPHY_WOL_CFG_WIDTH1 BIT(1) /* WOL Pulse Width */ -+#define YTPHY_WOL_CFG_WIDTH2 BIT(2) -+ -+#define YTPHY_REG_SPACE_UTP 0 -+#define YTPHY_REG_SPACE_FIBER 2 -+ -+enum ytphy_wol_type_e -+{ -+ YTPHY_WOL_TYPE_LEVEL, -+ YTPHY_WOL_TYPE_PULSE, -+ YTPHY_WOL_TYPE_MAX -+}; -+typedef enum ytphy_wol_type_e ytphy_wol_type_t; -+ -+enum ytphy_wol_width_e -+{ -+ YTPHY_WOL_WIDTH_84MS, -+ YTPHY_WOL_WIDTH_168MS, -+ YTPHY_WOL_WIDTH_336MS, -+ YTPHY_WOL_WIDTH_672MS, -+ YTPHY_WOL_WIDTH_MAX -+}; -+typedef enum ytphy_wol_width_e ytphy_wol_width_t; -+ -+struct ytphy_wol_cfg_s -+{ -+ int enable; -+ int type; -+ int width; -+}; -+typedef struct ytphy_wol_cfg_s ytphy_wol_cfg_t; -+ +#endif /* _MOTORCOMM_PHY_H */ -+ -+ --- -2.25.1 diff --git a/target/linux/rockchip/patches-5.4/601-net-phy-Add-driver-for-Motorcomm-YT8531-PHYs.patch b/target/linux/rockchip/patches-5.4/601-net-phy-Add-driver-for-Motorcomm-YT8531-PHYs.patch new file mode 100644 index 000000000..c870eb73c --- /dev/null +++ b/target/linux/rockchip/patches-5.4/601-net-phy-Add-driver-for-Motorcomm-YT8531-PHYs.patch @@ -0,0 +1,475 @@ +From abf36eb72942657cef05ebcb2897eaea9064ad06 Mon Sep 17 00:00:00 2001 +From: From: fengying0347 +Date: Thu, 13 Jan 2022 12:59:36 +0800 +Subject: [PATCH] net: phy: Add driver for Motorcomm YT8531(S) PHYs + +--- + .../net/ethernet/stmicro/stmmac/stmmac_main.c | 82 ++++++++ + drivers/net/phy/motorcomm.c | 181 +++++++++++++++++- + drivers/net/phy/phy_device.c | 83 ++++++++ + include/linux/motorcomm_phy.h | 5 + + 4 files changed, 350 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +index 8dc4def..bcd46ca 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c ++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +@@ -112,6 +112,10 @@ static void stmmac_exit_fs(struct net_device *dev); + + #define STMMAC_COAL_TIMER(x) (jiffies + usecs_to_jiffies(x)) + ++#define RTL_8211E_PHY_ID 0x001cc915 ++#define RTL_8211F_PHY_ID 0x001cc916 ++#define YT_8531C_PHY_ID 0x4f51e91b ++ + /** + * stmmac_verify_args - verify the driver parameters. + * Description: it checks the driver parameters and set a default in case of +@@ -4431,6 +4435,74 @@ int stmmac_reinit_ringparam(struct net_device *dev, u32 rx_size, u32 tx_size) + return 0; + } + ++static int phy_rtl8211e_led_fixup(struct phy_device *phydev) ++{ ++ int val; ++ ++ printk("%s in\n", __func__); ++ ++ /*switch to extension page44*/ ++ phy_write(phydev, 31, 0x07); ++ phy_write(phydev, 30, 0x2c); ++ ++ /*set led1(yellow) act*/ ++ val = phy_read(phydev, 26); ++ val &= (~(1<<4));// bit4=0 ++ val |= (1<<5);// bit5=1 ++ val &= (~(1<<6));// bit6=0 ++ phy_write(phydev, 26, val); ++ ++ /*set led0(green) link*/ ++ val = phy_read(phydev, 28); ++ val |= (7<<0);// bit0,1,2=1 ++ val &= (~(7<<4));// bit4,5,6=0 ++ val &= (~(7<<8));// bit8,9,10=0 ++ phy_write(phydev, 28, val); ++ ++ /*switch back to page0*/ ++ phy_write(phydev,31,0x00); ++ ++ return 0; ++} ++ ++static int phy_rtl8211f_led_fixup(struct phy_device *phydev) ++{ ++ int val; ++ ++ printk("%s in\n", __func__); ++ ++ /*switch to extension page 0xd04*/ ++ phy_write(phydev, 31, 0xd04); ++ ++ ++ /*set led1(yellow) act*/ ++ /*set led2(green) link*/ ++ val = 0xae00; ++ phy_write(phydev, 16, val); ++ ++ val = 0x0; ++ phy_write(phydev, 17, val); ++ /*switch back to page0*/ ++ phy_write(phydev,31,0x00); ++ ++ return 0; ++} ++ ++static int phy_yt8531_led_fixup(struct phy_device *phydev) ++{ ++ printk("%s in\n", __func__); ++ phy_write(phydev, 0x1e, 0xa00d); ++ phy_write(phydev, 0x1f, 0x670); ++ ++ phy_write(phydev, 0x1e, 0xa00e); ++ phy_write(phydev, 0x1f, 0x2070); ++ ++ phy_write(phydev, 0x1e, 0xa00f); ++ phy_write(phydev, 0x1f, 0x7e); ++ ++ return 0; ++} ++ + /** + * stmmac_dvr_probe + * @device: device pointer +@@ -4655,6 +4727,16 @@ int stmmac_dvr_probe(struct device *device, + netdev_err(ndev, "failed to setup phy (%d)\n", ret); + goto error_phy_setup; + } ++ /* register the PHY board fixup */ ++ ret = phy_register_fixup_for_uid(RTL_8211E_PHY_ID, 0xffffffff, phy_rtl8211e_led_fixup); ++ if (ret) ++ pr_warn("Cannot register PHY board fixup.\n"); ++ ret = phy_register_fixup_for_uid(RTL_8211F_PHY_ID, 0xffffffff, phy_rtl8211f_led_fixup); ++ if (ret) ++ pr_warn("Cannot register PHY board fixup.\n"); ++ ret = phy_register_fixup_for_uid(YT_8531C_PHY_ID, 0xffffffff, phy_yt8531_led_fixup); ++ if (ret) ++ pr_warn("Cannot register PHY board fixup.\n"); + + ret = register_netdev(ndev); + if (ret) { +diff --git a/drivers/net/phy/motorcomm.c b/drivers/net/phy/motorcomm.c +index 17a4f6c..e37dfb9 100644 +--- a/drivers/net/phy/motorcomm.c ++++ b/drivers/net/phy/motorcomm.c +@@ -26,6 +26,13 @@ + #include + #include + ++static int link_mode_8521 = 0; //0: no link; 1: utp; 32: fiber. traced that 1000m fiber uses 32. ++ ++int genphy_config_init(struct phy_device *phydev) ++{ ++ return genphy_read_abilities(phydev); ++} ++ + static int ytphy_read_ext(struct phy_device *phydev, u32 regnum) + { + int ret; +@@ -263,6 +270,38 @@ static int yt8521_config_intr(struct phy_device *phydev) + return phy_write(phydev, REG_INT_MASK, val); + } + ++static int yt8521_adjust_status(struct phy_device *phydev, int val, int is_utp) ++{ ++ int speed_mode, duplex; ++ ++ int speed = SPEED_UNKNOWN; ++ ++ duplex = (val & YT8512_DUPLEX) >> YT8521_DUPLEX_BIT; ++ speed_mode = (val & YT8521_SPEED_MODE) >> YT8521_SPEED_MODE_BIT; ++ switch (speed_mode) { ++ case 0: ++ if (is_utp) ++ speed = SPEED_10; ++ break; ++ case 1: ++ speed = SPEED_100; ++ break; ++ case 2: ++ speed = SPEED_1000; ++ break; ++ case 3: ++ break; ++ default: ++ speed = SPEED_UNKNOWN; ++ break; ++ } ++ ++ phydev->speed = speed; ++ phydev->duplex = duplex; ++ ++ return 0; ++} ++ + static int yt8521_ack_interrupt(struct phy_device *phydev) + { + int val; +@@ -273,6 +312,121 @@ static int yt8521_ack_interrupt(struct phy_device *phydev) + return (val < 0) ? val : 0; + } + ++static int yt8521_read_status(struct phy_device *phydev) ++{ ++ int ret; ++ volatile int val, yt8521_fiber_latch_val, yt8521_fiber_curr_val; ++ volatile int link; ++ int link_utp = 0, link_fiber = 0; ++ ++ /* reading UTP */ ++ ret = ytphy_write_ext(phydev, 0xa000, 0); ++ if (ret < 0) ++ return ret; ++ ++ val = phy_read(phydev, REG_PHY_SPEC_STATUS); ++ if (val < 0) ++ return val; ++ ++ link = val & (BIT(YT8521_LINK_STATUS_BIT)); ++ if (link) { ++ link_utp = 1; ++ link_mode_8521 = 1; ++ yt8521_adjust_status(phydev, val, 1); ++ } ++ else { ++ link_utp = 0; ++ } ++ ++ /* reading Fiber */ ++ ret = ytphy_write_ext(phydev, 0xa000, 2); ++ if (ret < 0) ++ return ret; ++ ++ val = phy_read(phydev, REG_PHY_SPEC_STATUS); ++ if (val < 0) ++ return val; ++ ++ //note: below debug information is used to check multiple PHy ports. ++ //printk (KERN_INFO "yt8521_read_status, fiber status=%04x,macbase=0x%08lx\n", val,(unsigned long)phydev->attached_dev); ++ ++ /* for fiber, from 1000m to 100m, there is not link down from 0x11, and check reg 1 to identify such case ++ * this is important for Linux kernel for that, missing linkdown event will cause problem. ++ */ ++ yt8521_fiber_latch_val = phy_read(phydev, MII_BMSR); ++ yt8521_fiber_curr_val = phy_read(phydev, MII_BMSR); ++ link = val & (BIT(YT8521_LINK_STATUS_BIT)); ++ if ((link) && (yt8521_fiber_latch_val != yt8521_fiber_curr_val)) ++ { ++ link = 0; ++ printk(KERN_INFO "yt8521_read_status, fiber link down detect,latch=%04x,curr=%04x\n", yt8521_fiber_latch_val, yt8521_fiber_curr_val); ++ } ++ ++ if (link) { ++ link_fiber = 1; ++ yt8521_adjust_status(phydev, val, 0); ++ link_mode_8521 = 32; //fiber mode ++ ++ ++ } ++ else { ++ link_fiber = 0; ++ } ++ ++ if (link_utp || link_fiber) { ++ phydev->link = 1; ++ } ++ else { ++ phydev->link = 0; ++ link_mode_8521 = 0; ++ } ++ ++ if (link_utp) { ++ ytphy_write_ext(phydev, 0xa000, 0); ++ } ++ ++ return 0; ++} ++ ++/* ++ * for fiber mode, when speed is 100M, there is no definition for autonegotiation, and ++ * this function handles this case and return 1 per linux kernel's polling. ++ */ ++int yt8521_aneg_done(struct phy_device *phydev) ++{ ++ ++ if ((32 == link_mode_8521) && (SPEED_100 == phydev->speed)) ++ { ++ return 1/*link_mode_8521*/; ++ } ++ ++ return genphy_aneg_done(phydev); ++} ++ ++int yt8521_soft_reset(struct phy_device *phydev) ++{ ++ int ret, val; ++ ++ val = ytphy_read_ext(phydev, 0xa001); ++ ytphy_write_ext(phydev, 0xa001, (val & ~0x8000)); ++ ++ ret = genphy_soft_reset(phydev); ++ if (ret < 0) ++ return ret; ++ ++ return 0; ++} ++ ++int yt8521_suspend(struct phy_device *phydev) ++{ ++ return 0; ++} ++ ++int yt8521_resume(struct phy_device *phydev) ++{ ++ return 0; ++} ++ + static struct phy_driver ytphy_drvs[] = { + { + .phy_id = PHY_ID_YT8010, +@@ -323,7 +477,30 @@ static struct phy_driver ytphy_drvs[] = { + .config_intr = yt8521_config_intr, + .suspend = genphy_suspend, + .resume = genphy_resume, +- }, ++ }, { ++ /* same as 8521 */ ++ .phy_id = PHY_ID_YT8531S, ++ .name = "YT8531S Ethernet", ++ .phy_id_mask = MOTORCOMM_PHY_ID_MASK, ++ .flags = PHY_POLL, ++ .soft_reset = yt8521_soft_reset, ++ .config_aneg = genphy_config_aneg, ++ .aneg_done = yt8521_aneg_done, ++ .config_init = yt8521_config_init, ++ .read_status = yt8521_read_status, ++ .suspend = yt8521_suspend, ++ .resume = yt8521_resume, ++ }, { ++ /* same as 8511 */ ++ .phy_id = PHY_ID_YT8531, ++ .name = "YT8531 Gigabit Ethernet", ++ .phy_id_mask = MOTORCOMM_PHY_ID_MASK, ++ .config_aneg = genphy_config_aneg, ++ .config_init = genphy_config_init, ++ .read_status = genphy_read_status, ++ .suspend = genphy_suspend, ++ .resume = genphy_resume, ++ } + }; + + module_phy_driver(ytphy_drvs); +@@ -339,6 +516,8 @@ static struct mdio_device_id __maybe_unused motorcomm_tbl[] = { + { PHY_ID_YT8512, MOTORCOMM_PHY_ID_MASK }, + { PHY_ID_YT8512B, MOTORCOMM_PHY_ID_MASK }, + { PHY_ID_YT8521, MOTORCOMM_PHY_ID_MASK }, ++ { PHY_ID_YT8531S, MOTORCOMM_PHY_ID_8531_MASK }, ++ { PHY_ID_YT8531, MOTORCOMM_PHY_ID_8531_MASK }, + { } + }; + +diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c +index 950277e..3a35040 100644 +--- a/drivers/net/phy/phy_device.c ++++ b/drivers/net/phy/phy_device.c +@@ -31,6 +31,7 @@ + #include + #include + #include ++#include + + MODULE_DESCRIPTION("PHY library"); + MODULE_AUTHOR("Andy Fleming"); +@@ -440,6 +441,33 @@ int phy_unregister_fixup_for_id(const char *bus_id) + } + EXPORT_SYMBOL(phy_unregister_fixup_for_id); + ++static int phy_mii_rd_ext(struct mii_bus *bus, int phy_id, u32 regnum) ++{ ++ int ret; ++ int val; ++ ++ ret = bus->write(bus, phy_id, REG_DEBUG_ADDR_OFFSET, regnum); ++ if (ret < 0) ++ return ret; ++ ++ val = bus->read(bus, phy_id, REG_DEBUG_DATA); ++ ++ return val; ++} ++ ++static int phy_mii_wr_ext(struct mii_bus *bus, int phy_id, u32 regnum, u16 val) ++{ ++ int ret; ++ ++ ret = bus->write(bus, phy_id, REG_DEBUG_ADDR_OFFSET, regnum); ++ if (ret < 0) ++ return ret; ++ ++ ret = bus->write(bus, phy_id, REG_DEBUG_DATA, val); ++ ++ return ret; ++} ++ + /* Returns 1 if fixup matches phydev in bus_id and phy_uid. + * Fixups can be set to match any in one or more fields. + */ +@@ -808,6 +836,50 @@ static int get_phy_c22_id(struct mii_bus *bus, int addr, u32 *phy_id) + return 0; + } + ++int phy_set_out_125m(struct mii_bus* bus, int phy_id) ++{ ++ int ret; ++ int val; ++ ++ ret = phy_mii_wr_ext(bus, phy_id, 0xa012, 0xd0); ++ mdelay(100); ++ val = phy_mii_rd_ext(bus, phy_id, 0xa012); ++ ++ if (val != 0xd0) ++ { ++ printk(KERN_INFO "phy_set_out_125m error\n"); ++ return -1; ++ } ++ ++ /* disable auto sleep */ ++ val = phy_mii_rd_ext(bus, phy_id, 0x27); ++ if (val < 0) ++ return val; ++ ++ val &= (~BIT(15)); ++ ++ ret = phy_mii_wr_ext(bus, phy_id, 0x27, val); ++ if (ret < 0) ++ return ret; ++ ++ /* enable RXC clock when no wire plug */ ++ val = phy_mii_rd_ext(bus, phy_id, 0xc); ++ if (val < 0) ++ return val; ++ ++ /* ext reg 0xc.b[2:1] ++ 00-----25M from pll; ++ 01---- 25M from xtl;(default) ++ 10-----62.5M from pll; ++ 11----125M from pll(here set to this value) ++ */ ++ val |= (3 << 1); ++ ret = phy_mii_wr_ext(bus, phy_id, 0xc, val); ++ printk(KERN_INFO "phy_set_out_125m, phy clk out, val=%#08x\n", val); ++ ++ return ret; ++} ++ + /** + * get_phy_device - reads the specified PHY device and returns its @phy_device + * struct +@@ -831,6 +903,15 @@ struct phy_device *get_phy_device(struct mii_bus *bus, int addr, bool is_c45) + if (r) + return ERR_PTR(r); + ++ if(phy_id == PHY_ID_YT8531) ++ { ++ r = phy_set_out_125m(bus, addr); ++ if (r<0) ++ { ++ printk (KERN_INFO "failed to set 125m clk out, ret=%d\n",r); ++ } ++ } ++ + /* If the phy_id is mostly Fs, there is no device there */ + if ((phy_id & 0x1fffffff) == 0x1fffffff) + return ERR_PTR(-ENODEV); +diff --git a/include/linux/motorcomm_phy.h b/include/linux/motorcomm_phy.h +index facce6d..23cccca 100644 +--- a/include/linux/motorcomm_phy.h ++++ b/include/linux/motorcomm_phy.h +@@ -14,6 +14,8 @@ + #define _MOTORCOMM_PHY_H + + #define MOTORCOMM_PHY_ID_MASK 0x00000fff ++#define MOTORCOMM_PHY_ID_8531_MASK 0xffffffff ++#define MOTORCOMM_MPHY_ID_MASK 0x0000ffff + + #define PHY_ID_YT8010 0x00000309 + #define PHY_ID_YT8510 0x00000109 +@@ -21,6 +23,9 @@ + #define PHY_ID_YT8512 0x00000118 + #define PHY_ID_YT8512B 0x00000128 + #define PHY_ID_YT8521 0x0000011a ++#define PHY_ID_YT8531S 0x4f51e91a ++#define PHY_ID_YT8531 0x4f51e91b ++#define PHY_ID_YT8618 0x0000e889 + + #define REG_PHY_SPEC_STATUS 0x11 + #define REG_INT_MASK 0x12