diff --git a/target/linux/rockchip/armv8/config-5.10 b/target/linux/rockchip/armv8/config-5.10 index 96dc5759c8..41e65622d6 100644 --- a/target/linux/rockchip/armv8/config-5.10 +++ b/target/linux/rockchip/armv8/config-5.10 @@ -375,6 +375,7 @@ CONFIG_MMC_SDHCI_OF_DWCMSHC=y # CONFIG_MMC_SDHCI_PCI is not set CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MODULES_USE_ELF_RELA=y +CONFIG_MOTORCOMM_PHY=y CONFIG_MQ_IOSCHED_DEADLINE=y # CONFIG_MTD_CFI is not set CONFIG_MTD_CMDLINE_PARTS=y diff --git a/target/linux/rockchip/armv8/config-5.4 b/target/linux/rockchip/armv8/config-5.4 index 2a12ef5dea..232e642de4 100644 --- a/target/linux/rockchip/armv8/config-5.4 +++ b/target/linux/rockchip/armv8/config-5.4 @@ -356,6 +356,7 @@ CONFIG_MMC_SDHCI_OF_DWCMSHC=y # CONFIG_MMC_SDHCI_PCI is not set CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MODULES_USE_ELF_RELA=y +CONFIG_MOTORCOMM_PHY=y CONFIG_MQ_IOSCHED_DEADLINE=y # CONFIG_MTD_CFI is not set CONFIG_MTD_CMDLINE_PARTS=y diff --git a/target/linux/rockchip/patches-5.10/600-net-phy-Add-driver-for-Motorcomm-YT85xx-PHYs.patch b/target/linux/rockchip/patches-5.10/600-net-phy-Add-driver-for-Motorcomm-YT85xx-PHYs.patch new file mode 100644 index 0000000000..e478541c0c --- /dev/null +++ b/target/linux/rockchip/patches-5.10/600-net-phy-Add-driver-for-Motorcomm-YT85xx-PHYs.patch @@ -0,0 +1,457 @@ +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 +--- + 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 include/linux/motorcomm_phy.h + +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -297,6 +297,11 @@ config MICROSEMI_PHY + help + Currently supports VSC8514, VSC8530, VSC8531, VSC8540 and VSC8541 PHYs + ++config MOTORCOMM_PHY ++ tristate "Motorcomm PHYs" ++ help ++ Supports the YT8010, YT8510, YT8511, YT8512 PHYs. ++ + config NATIONAL_PHY + tristate "National Semiconductor PHYs" + help +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -82,6 +82,7 @@ obj-$(CONFIG_MICREL_PHY) += micrel.o + obj-$(CONFIG_MICROCHIP_PHY) += microchip.o + obj-$(CONFIG_MICROCHIP_T1_PHY) += microchip_t1.o + obj-$(CONFIG_MICROSEMI_PHY) += mscc/ ++obj-$(CONFIG_MOTORCOMM_PHY) += motorcomm.o + obj-$(CONFIG_NATIONAL_PHY) += national.o + obj-$(CONFIG_NXP_TJA11XX_PHY) += nxp-tja11xx.o + obj-$(CONFIG_QSEMI_PHY) += qsemi.o +--- /dev/null ++++ b/drivers/net/phy/motorcomm.c +@@ -0,0 +1,345 @@ ++/* ++ * drivers/net/phy/motorcomm.c ++ * ++ * Driver for Motorcomm PHYs ++ * ++ * Author: Leilei Zhao ++ * ++ * Copyright (c) 2019 Motorcomm, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ * ++ * Support : Motorcomm Phys: ++ * Giga phys: yt8511, yt8521 ++ * 100/10 Phys : yt8512, yt8512b, yt8510 ++ * Automotive 100Mb Phys : yt8010 ++ * Automotive 100/10 hyper range Phys: yt8510 ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static int ytphy_read_ext(struct phy_device *phydev, u32 regnum) ++{ ++ int ret; ++ int val; ++ ++ ret = phy_write(phydev, REG_DEBUG_ADDR_OFFSET, regnum); ++ if (ret < 0) ++ return ret; ++ ++ val = phy_read(phydev, REG_DEBUG_DATA); ++ ++ return val; ++} ++ ++static int ytphy_write_ext(struct phy_device *phydev, u32 regnum, u16 val) ++{ ++ int ret; ++ ++ ret = phy_write(phydev, REG_DEBUG_ADDR_OFFSET, regnum); ++ if (ret < 0) ++ return ret; ++ ++ ret = phy_write(phydev, REG_DEBUG_DATA, val); ++ ++ return ret; ++} ++ ++static int yt8010_config_aneg(struct phy_device *phydev) ++{ ++ phydev->speed = SPEED_100; ++ return 0; ++} ++ ++static int yt8512_clk_init(struct phy_device *phydev) ++{ ++ int ret; ++ int val; ++ ++ val = ytphy_read_ext(phydev, YT8512_EXTREG_AFE_PLL); ++ if (val < 0) ++ return val; ++ ++ val |= YT8512_CONFIG_PLL_REFCLK_SEL_EN; ++ ++ ret = ytphy_write_ext(phydev, YT8512_EXTREG_AFE_PLL, val); ++ if (ret < 0) ++ return ret; ++ ++ val = ytphy_read_ext(phydev, YT8512_EXTREG_EXTEND_COMBO); ++ if (val < 0) ++ return val; ++ ++ val |= YT8512_CONTROL1_RMII_EN; ++ ++ ret = ytphy_write_ext(phydev, YT8512_EXTREG_EXTEND_COMBO, val); ++ if (ret < 0) ++ return ret; ++ ++ val = phy_read(phydev, MII_BMCR); ++ if (val < 0) ++ return val; ++ ++ val |= YT_SOFTWARE_RESET; ++ ret = phy_write(phydev, MII_BMCR, val); ++ ++ return ret; ++} ++ ++static int yt8512_led_init(struct phy_device *phydev) ++{ ++ int ret; ++ int val; ++ int mask; ++ ++ val = ytphy_read_ext(phydev, YT8512_EXTREG_LED0); ++ if (val < 0) ++ return val; ++ ++ val |= YT8512_LED0_ACT_BLK_IND; ++ ++ mask = YT8512_LED0_DIS_LED_AN_TRY | YT8512_LED0_BT_BLK_EN | ++ YT8512_LED0_HT_BLK_EN | YT8512_LED0_COL_BLK_EN | ++ YT8512_LED0_BT_ON_EN; ++ val &= ~mask; ++ ++ ret = ytphy_write_ext(phydev, YT8512_EXTREG_LED0, val); ++ if (ret < 0) ++ return ret; ++ ++ val = ytphy_read_ext(phydev, YT8512_EXTREG_LED1); ++ if (val < 0) ++ return val; ++ ++ val |= YT8512_LED1_BT_ON_EN; ++ ++ mask = YT8512_LED1_TXACT_BLK_EN | YT8512_LED1_RXACT_BLK_EN; ++ val &= ~mask; ++ ++ ret = ytphy_write_ext(phydev, YT8512_LED1_BT_ON_EN, val); ++ ++ return ret; ++} ++ ++static int yt8512_config_init(struct phy_device *phydev) ++{ ++ int ret; ++ int val; ++ ++ ret = yt8512_clk_init(phydev); ++ if (ret < 0) ++ return ret; ++ ++ ret = yt8512_led_init(phydev); ++ ++ /* disable auto sleep */ ++ val = ytphy_read_ext(phydev, YT8512_EXTREG_SLEEP_CONTROL1); ++ if (val < 0) ++ return val; ++ ++ val &= (~BIT(YT8512_EN_SLEEP_SW_BIT)); ++ ++ ret = ytphy_write_ext(phydev, YT8512_EXTREG_SLEEP_CONTROL1, val); ++ if (ret < 0) ++ return ret; ++ ++ return ret; ++} ++ ++static int yt8512_read_status(struct phy_device *phydev) ++{ ++ int ret; ++ int val; ++ int speed, speed_mode, duplex; ++ ++ ret = genphy_update_link(phydev); ++ if (ret) ++ return ret; ++ ++ val = phy_read(phydev, REG_PHY_SPEC_STATUS); ++ if (val < 0) ++ return val; ++ ++ duplex = (val & YT8512_DUPLEX) >> YT8512_DUPLEX_BIT; ++ speed_mode = (val & YT8512_SPEED_MODE) >> YT8512_SPEED_MODE_BIT; ++ switch (speed_mode) { ++ case 0: ++ speed = SPEED_10; ++ break; ++ case 1: ++ speed = SPEED_100; ++ break; ++ case 2: ++ case 3: ++ default: ++ speed = SPEED_UNKNOWN; ++ break; ++ } ++ ++ phydev->speed = speed; ++ phydev->duplex = duplex; ++ ++ return 0; ++} ++ ++static int yt8521_config_init(struct phy_device *phydev) ++{ ++ int ret; ++ int val; ++ ++ /* 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; ++ ++ /* 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; ++ ++ /* output SyncE clock (125mhz) even link is down */ ++ ret = ytphy_write_ext(phydev, 0xa012, 0x38); ++ if (ret < 0) ++ return ret; ++ ++ /* disable rgmii clk 2ns delay */ ++ val = ytphy_read_ext(phydev, 0xa001); ++ if (val < 0) ++ return val; ++ ++ val &= ~(1 << 8); ++ ret = ytphy_write_ext(phydev, 0xa001, val); ++ if (ret < 0) ++ return ret; ++ ++ /* setup delay */ ++ val = (1 << 10) | (0xf << 4) | 5; ++ ret = ytphy_write_ext(phydev, 0xa003, val); ++ if (ret < 0) ++ return ret; ++ ++ /* 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; ++} ++ ++static int yt8521_config_intr(struct phy_device *phydev) ++{ ++ int val; ++ ++ if (phydev->interrupts == PHY_INTERRUPT_ENABLED) ++ val = BIT(14) | BIT(13) | BIT(11) | BIT(10); ++ else ++ val = 0; ++ ++ return phy_write(phydev, REG_INT_MASK, val); ++} ++ ++static int yt8521_ack_interrupt(struct phy_device *phydev) ++{ ++ int val; ++ ++ val = phy_read(phydev, REG_INT_STATUS); ++ phydev_dbg(phydev, "intr status 0x04%x\n", val); ++ ++ return (val < 0) ? val : 0; ++} ++ ++static struct phy_driver ytphy_drvs[] = { ++ { ++ .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, ++ .features = PHY_BASIC_FEATURES, ++ .read_status = genphy_read_status, ++ }, { ++ .phy_id = PHY_ID_YT8511, ++ .name = "YT8511 Gigabit Ethernet", ++ .phy_id_mask = MOTORCOMM_PHY_ID_MASK, ++ .features = PHY_GBIT_FEATURES, ++ .read_status = genphy_read_status, ++ .suspend = genphy_suspend, ++ .resume = genphy_resume, ++ }, { ++ .phy_id = PHY_ID_YT8512, ++ .name = "YT8512 Ethernet", ++ .phy_id_mask = MOTORCOMM_PHY_ID_MASK, ++ .features = PHY_BASIC_FEATURES, ++ .config_init = yt8512_config_init, ++ .read_status = yt8512_read_status, ++ .suspend = genphy_suspend, ++ .resume = genphy_resume, ++ }, { ++ .phy_id = PHY_ID_YT8512B, ++ .name = "YT8512B Ethernet", ++ .phy_id_mask = MOTORCOMM_PHY_ID_MASK, ++ .features = PHY_BASIC_FEATURES, ++ .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, ++ /* PHY_GBIT_FEATURES */ ++ .config_init = yt8521_config_init, ++ .ack_interrupt = yt8521_ack_interrupt, ++ .config_intr = yt8521_config_intr, ++ .suspend = genphy_suspend, ++ .resume = genphy_resume, ++ }, ++}; ++ ++module_phy_driver(ytphy_drvs); ++ ++MODULE_DESCRIPTION("Motorcomm PHY driver"); ++MODULE_AUTHOR("Leilei Zhao"); ++MODULE_LICENSE("GPL"); ++ ++static struct mdio_device_id __maybe_unused motorcomm_tbl[] = { ++ { PHY_ID_YT8010, MOTORCOMM_PHY_ID_MASK }, ++ { PHY_ID_YT8510, MOTORCOMM_PHY_ID_MASK }, ++ { PHY_ID_YT8511, MOTORCOMM_PHY_ID_MASK }, ++ { PHY_ID_YT8512, MOTORCOMM_PHY_ID_MASK }, ++ { PHY_ID_YT8512B, MOTORCOMM_PHY_ID_MASK }, ++ { PHY_ID_YT8521, MOTORCOMM_PHY_ID_MASK }, ++ { } ++}; ++ ++MODULE_DEVICE_TABLE(mdio, motorcomm_tbl); +--- /dev/null ++++ b/include/linux/motorcomm_phy.h +@@ -0,0 +1,67 @@ ++/* ++ * include/linux/motorcomm_phy.h ++ * ++ * Motorcomm PHY IDs ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ * ++ */ ++ ++#ifndef _MOTORCOMM_PHY_H ++#define _MOTORCOMM_PHY_H ++ ++#define MOTORCOMM_PHY_ID_MASK 0x00000fff ++ ++#define PHY_ID_YT8010 0x00000309 ++#define PHY_ID_YT8510 0x00000109 ++#define PHY_ID_YT8511 0x0000010a ++#define PHY_ID_YT8512 0x00000118 ++#define PHY_ID_YT8512B 0x00000128 ++#define PHY_ID_YT8521 0x0000011a ++ ++#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 ++ ++#define YT8512_EXTREG_AFE_PLL 0x50 ++#define YT8512_EXTREG_EXTEND_COMBO 0x4000 ++#define YT8512_EXTREG_LED0 0x40c0 ++#define YT8512_EXTREG_LED1 0x40c3 ++ ++#define YT8512_EXTREG_SLEEP_CONTROL1 0x2027 ++ ++#define YT_SOFTWARE_RESET 0x8000 ++ ++#define YT8512_CONFIG_PLL_REFCLK_SEL_EN 0x0040 ++#define YT8512_CONTROL1_RMII_EN 0x0001 ++#define YT8512_LED0_ACT_BLK_IND 0x1000 ++#define YT8512_LED0_DIS_LED_AN_TRY 0x0001 ++#define YT8512_LED0_BT_BLK_EN 0x0002 ++#define YT8512_LED0_HT_BLK_EN 0x0004 ++#define YT8512_LED0_COL_BLK_EN 0x0008 ++#define YT8512_LED0_BT_ON_EN 0x0010 ++#define YT8512_LED1_BT_ON_EN 0x0010 ++#define YT8512_LED1_TXACT_BLK_EN 0x0100 ++#define YT8512_LED1_RXACT_BLK_EN 0x0200 ++#define YT8512_SPEED_MODE 0xc000 ++#define YT8512_DUPLEX 0x2000 ++ ++#define YT8512_SPEED_MODE_BIT 14 ++#define YT8512_DUPLEX_BIT 13 ++#define YT8512_EN_SLEEP_SW_BIT 15 ++ ++#define YT8521_EXTREG_SLEEP_CONTROL1 0x27 ++#define YT8521_EN_SLEEP_SW_BIT 15 ++ ++#define YT8521_SPEED_MODE 0xc000 ++#define YT8521_DUPLEX 0x2000 ++#define YT8521_SPEED_MODE_BIT 14 ++#define YT8521_DUPLEX_BIT 13 ++#define YT8521_LINK_STATUS_BIT 10 ++ ++#endif /* _MOTORCOMM_PHY_H */ 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 new file mode 100644 index 0000000000..2271308b1a --- /dev/null +++ b/target/linux/rockchip/patches-5.4/600-net-phy-Add-driver-for-Motorcomm-YT85xx-PHYs.patch @@ -0,0 +1,457 @@ +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 +--- + 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 include/linux/motorcomm_phy.h + +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -519,6 +519,11 @@ config MICROSEMI_PHY + ---help--- + Currently supports VSC8514, VSC8530, VSC8531, VSC8540 and VSC8541 PHYs + ++config MOTORCOMM_PHY ++ tristate "Motorcomm PHYs" ++ ---help--- ++ Supports the YT8010, YT8510, YT8511, YT8512 PHYs. ++ + config NATIONAL_PHY + tristate "National Semiconductor PHYs" + ---help--- +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -98,6 +98,7 @@ obj-$(CONFIG_MICREL_PHY) += micrel.o + obj-$(CONFIG_MICROCHIP_PHY) += microchip.o + obj-$(CONFIG_MICROCHIP_T1_PHY) += microchip_t1.o + obj-$(CONFIG_MICROSEMI_PHY) += mscc.o ++obj-$(CONFIG_MOTORCOMM_PHY) += motorcomm.o + obj-$(CONFIG_NATIONAL_PHY) += national.o + obj-$(CONFIG_NXP_TJA11XX_PHY) += nxp-tja11xx.o + obj-$(CONFIG_QSEMI_PHY) += qsemi.o +--- /dev/null ++++ b/drivers/net/phy/motorcomm.c +@@ -0,0 +1,345 @@ ++/* ++ * drivers/net/phy/motorcomm.c ++ * ++ * Driver for Motorcomm PHYs ++ * ++ * Author: Leilei Zhao ++ * ++ * Copyright (c) 2019 Motorcomm, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ * ++ * Support : Motorcomm Phys: ++ * Giga phys: yt8511, yt8521 ++ * 100/10 Phys : yt8512, yt8512b, yt8510 ++ * Automotive 100Mb Phys : yt8010 ++ * Automotive 100/10 hyper range Phys: yt8510 ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static int ytphy_read_ext(struct phy_device *phydev, u32 regnum) ++{ ++ int ret; ++ int val; ++ ++ ret = phy_write(phydev, REG_DEBUG_ADDR_OFFSET, regnum); ++ if (ret < 0) ++ return ret; ++ ++ val = phy_read(phydev, REG_DEBUG_DATA); ++ ++ return val; ++} ++ ++static int ytphy_write_ext(struct phy_device *phydev, u32 regnum, u16 val) ++{ ++ int ret; ++ ++ ret = phy_write(phydev, REG_DEBUG_ADDR_OFFSET, regnum); ++ if (ret < 0) ++ return ret; ++ ++ ret = phy_write(phydev, REG_DEBUG_DATA, val); ++ ++ return ret; ++} ++ ++static int yt8010_config_aneg(struct phy_device *phydev) ++{ ++ phydev->speed = SPEED_100; ++ return 0; ++} ++ ++static int yt8512_clk_init(struct phy_device *phydev) ++{ ++ int ret; ++ int val; ++ ++ val = ytphy_read_ext(phydev, YT8512_EXTREG_AFE_PLL); ++ if (val < 0) ++ return val; ++ ++ val |= YT8512_CONFIG_PLL_REFCLK_SEL_EN; ++ ++ ret = ytphy_write_ext(phydev, YT8512_EXTREG_AFE_PLL, val); ++ if (ret < 0) ++ return ret; ++ ++ val = ytphy_read_ext(phydev, YT8512_EXTREG_EXTEND_COMBO); ++ if (val < 0) ++ return val; ++ ++ val |= YT8512_CONTROL1_RMII_EN; ++ ++ ret = ytphy_write_ext(phydev, YT8512_EXTREG_EXTEND_COMBO, val); ++ if (ret < 0) ++ return ret; ++ ++ val = phy_read(phydev, MII_BMCR); ++ if (val < 0) ++ return val; ++ ++ val |= YT_SOFTWARE_RESET; ++ ret = phy_write(phydev, MII_BMCR, val); ++ ++ return ret; ++} ++ ++static int yt8512_led_init(struct phy_device *phydev) ++{ ++ int ret; ++ int val; ++ int mask; ++ ++ val = ytphy_read_ext(phydev, YT8512_EXTREG_LED0); ++ if (val < 0) ++ return val; ++ ++ val |= YT8512_LED0_ACT_BLK_IND; ++ ++ mask = YT8512_LED0_DIS_LED_AN_TRY | YT8512_LED0_BT_BLK_EN | ++ YT8512_LED0_HT_BLK_EN | YT8512_LED0_COL_BLK_EN | ++ YT8512_LED0_BT_ON_EN; ++ val &= ~mask; ++ ++ ret = ytphy_write_ext(phydev, YT8512_EXTREG_LED0, val); ++ if (ret < 0) ++ return ret; ++ ++ val = ytphy_read_ext(phydev, YT8512_EXTREG_LED1); ++ if (val < 0) ++ return val; ++ ++ val |= YT8512_LED1_BT_ON_EN; ++ ++ mask = YT8512_LED1_TXACT_BLK_EN | YT8512_LED1_RXACT_BLK_EN; ++ val &= ~mask; ++ ++ ret = ytphy_write_ext(phydev, YT8512_LED1_BT_ON_EN, val); ++ ++ return ret; ++} ++ ++static int yt8512_config_init(struct phy_device *phydev) ++{ ++ int ret; ++ int val; ++ ++ ret = yt8512_clk_init(phydev); ++ if (ret < 0) ++ return ret; ++ ++ ret = yt8512_led_init(phydev); ++ ++ /* disable auto sleep */ ++ val = ytphy_read_ext(phydev, YT8512_EXTREG_SLEEP_CONTROL1); ++ if (val < 0) ++ return val; ++ ++ val &= (~BIT(YT8512_EN_SLEEP_SW_BIT)); ++ ++ ret = ytphy_write_ext(phydev, YT8512_EXTREG_SLEEP_CONTROL1, val); ++ if (ret < 0) ++ return ret; ++ ++ return ret; ++} ++ ++static int yt8512_read_status(struct phy_device *phydev) ++{ ++ int ret; ++ int val; ++ int speed, speed_mode, duplex; ++ ++ ret = genphy_update_link(phydev); ++ if (ret) ++ return ret; ++ ++ val = phy_read(phydev, REG_PHY_SPEC_STATUS); ++ if (val < 0) ++ return val; ++ ++ duplex = (val & YT8512_DUPLEX) >> YT8512_DUPLEX_BIT; ++ speed_mode = (val & YT8512_SPEED_MODE) >> YT8512_SPEED_MODE_BIT; ++ switch (speed_mode) { ++ case 0: ++ speed = SPEED_10; ++ break; ++ case 1: ++ speed = SPEED_100; ++ break; ++ case 2: ++ case 3: ++ default: ++ speed = SPEED_UNKNOWN; ++ break; ++ } ++ ++ phydev->speed = speed; ++ phydev->duplex = duplex; ++ ++ return 0; ++} ++ ++static int yt8521_config_init(struct phy_device *phydev) ++{ ++ int ret; ++ int val; ++ ++ /* 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; ++ ++ /* 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; ++ ++ /* output SyncE clock (125mhz) even link is down */ ++ ret = ytphy_write_ext(phydev, 0xa012, 0x38); ++ if (ret < 0) ++ return ret; ++ ++ /* disable rgmii clk 2ns delay */ ++ val = ytphy_read_ext(phydev, 0xa001); ++ if (val < 0) ++ return val; ++ ++ val &= ~(1 << 8); ++ ret = ytphy_write_ext(phydev, 0xa001, val); ++ if (ret < 0) ++ return ret; ++ ++ /* setup delay */ ++ val = (1 << 10) | (0xf << 4) | 5; ++ ret = ytphy_write_ext(phydev, 0xa003, val); ++ if (ret < 0) ++ return ret; ++ ++ /* 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; ++} ++ ++static int yt8521_config_intr(struct phy_device *phydev) ++{ ++ int val; ++ ++ if (phydev->interrupts == PHY_INTERRUPT_ENABLED) ++ val = BIT(14) | BIT(13) | BIT(11) | BIT(10); ++ else ++ val = 0; ++ ++ return phy_write(phydev, REG_INT_MASK, val); ++} ++ ++static int yt8521_ack_interrupt(struct phy_device *phydev) ++{ ++ int val; ++ ++ val = phy_read(phydev, REG_INT_STATUS); ++ phydev_dbg(phydev, "intr status 0x04%x\n", val); ++ ++ return (val < 0) ? val : 0; ++} ++ ++static struct phy_driver ytphy_drvs[] = { ++ { ++ .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, ++ .features = PHY_BASIC_FEATURES, ++ .read_status = genphy_read_status, ++ }, { ++ .phy_id = PHY_ID_YT8511, ++ .name = "YT8511 Gigabit Ethernet", ++ .phy_id_mask = MOTORCOMM_PHY_ID_MASK, ++ .features = PHY_GBIT_FEATURES, ++ .read_status = genphy_read_status, ++ .suspend = genphy_suspend, ++ .resume = genphy_resume, ++ }, { ++ .phy_id = PHY_ID_YT8512, ++ .name = "YT8512 Ethernet", ++ .phy_id_mask = MOTORCOMM_PHY_ID_MASK, ++ .features = PHY_BASIC_FEATURES, ++ .config_init = yt8512_config_init, ++ .read_status = yt8512_read_status, ++ .suspend = genphy_suspend, ++ .resume = genphy_resume, ++ }, { ++ .phy_id = PHY_ID_YT8512B, ++ .name = "YT8512B Ethernet", ++ .phy_id_mask = MOTORCOMM_PHY_ID_MASK, ++ .features = PHY_BASIC_FEATURES, ++ .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, ++ /* PHY_GBIT_FEATURES */ ++ .config_init = yt8521_config_init, ++ .ack_interrupt = yt8521_ack_interrupt, ++ .config_intr = yt8521_config_intr, ++ .suspend = genphy_suspend, ++ .resume = genphy_resume, ++ }, ++}; ++ ++module_phy_driver(ytphy_drvs); ++ ++MODULE_DESCRIPTION("Motorcomm PHY driver"); ++MODULE_AUTHOR("Leilei Zhao"); ++MODULE_LICENSE("GPL"); ++ ++static struct mdio_device_id __maybe_unused motorcomm_tbl[] = { ++ { PHY_ID_YT8010, MOTORCOMM_PHY_ID_MASK }, ++ { PHY_ID_YT8510, MOTORCOMM_PHY_ID_MASK }, ++ { PHY_ID_YT8511, MOTORCOMM_PHY_ID_MASK }, ++ { PHY_ID_YT8512, MOTORCOMM_PHY_ID_MASK }, ++ { PHY_ID_YT8512B, MOTORCOMM_PHY_ID_MASK }, ++ { PHY_ID_YT8521, MOTORCOMM_PHY_ID_MASK }, ++ { } ++}; ++ ++MODULE_DEVICE_TABLE(mdio, motorcomm_tbl); +--- /dev/null ++++ b/include/linux/motorcomm_phy.h +@@ -0,0 +1,67 @@ ++/* ++ * include/linux/motorcomm_phy.h ++ * ++ * Motorcomm PHY IDs ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ * ++ */ ++ ++#ifndef _MOTORCOMM_PHY_H ++#define _MOTORCOMM_PHY_H ++ ++#define MOTORCOMM_PHY_ID_MASK 0x00000fff ++ ++#define PHY_ID_YT8010 0x00000309 ++#define PHY_ID_YT8510 0x00000109 ++#define PHY_ID_YT8511 0x0000010a ++#define PHY_ID_YT8512 0x00000118 ++#define PHY_ID_YT8512B 0x00000128 ++#define PHY_ID_YT8521 0x0000011a ++ ++#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 ++ ++#define YT8512_EXTREG_AFE_PLL 0x50 ++#define YT8512_EXTREG_EXTEND_COMBO 0x4000 ++#define YT8512_EXTREG_LED0 0x40c0 ++#define YT8512_EXTREG_LED1 0x40c3 ++ ++#define YT8512_EXTREG_SLEEP_CONTROL1 0x2027 ++ ++#define YT_SOFTWARE_RESET 0x8000 ++ ++#define YT8512_CONFIG_PLL_REFCLK_SEL_EN 0x0040 ++#define YT8512_CONTROL1_RMII_EN 0x0001 ++#define YT8512_LED0_ACT_BLK_IND 0x1000 ++#define YT8512_LED0_DIS_LED_AN_TRY 0x0001 ++#define YT8512_LED0_BT_BLK_EN 0x0002 ++#define YT8512_LED0_HT_BLK_EN 0x0004 ++#define YT8512_LED0_COL_BLK_EN 0x0008 ++#define YT8512_LED0_BT_ON_EN 0x0010 ++#define YT8512_LED1_BT_ON_EN 0x0010 ++#define YT8512_LED1_TXACT_BLK_EN 0x0100 ++#define YT8512_LED1_RXACT_BLK_EN 0x0200 ++#define YT8512_SPEED_MODE 0xc000 ++#define YT8512_DUPLEX 0x2000 ++ ++#define YT8512_SPEED_MODE_BIT 14 ++#define YT8512_DUPLEX_BIT 13 ++#define YT8512_EN_SLEEP_SW_BIT 15 ++ ++#define YT8521_EXTREG_SLEEP_CONTROL1 0x27 ++#define YT8521_EN_SLEEP_SW_BIT 15 ++ ++#define YT8521_SPEED_MODE 0xc000 ++#define YT8521_DUPLEX 0x2000 ++#define YT8521_SPEED_MODE_BIT 14 ++#define YT8521_DUPLEX_BIT 13 ++#define YT8521_LINK_STATUS_BIT 10 ++ ++#endif /* _MOTORCOMM_PHY_H */