diff options
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/phy/Kconfig | 2 | ||||
-rw-r--r-- | drivers/net/phy/broadcom.c | 101 | ||||
-rw-r--r-- | drivers/net/phy/motorcomm.c | 88 | ||||
-rw-r--r-- | drivers/net/zynq_gem.c | 3 |
4 files changed, 191 insertions, 3 deletions
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 0c3c39a550..3d96938eab 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -224,7 +224,7 @@ config PHY_MOTORCOMM tristate "Motorcomm PHYs" help Enables support for Motorcomm network PHYs. - Currently supports the YT8531 Gigabit Ethernet PHYs. + Currently supports the YT8511 and YT8531 Gigabit Ethernet PHYs. config PHY_MSCC bool "Microsemi Corp Ethernet PHYs support" diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c index 36c70da181..82e3bbef7d 100644 --- a/drivers/net/phy/broadcom.c +++ b/drivers/net/phy/broadcom.c @@ -30,10 +30,87 @@ #define MIIM_BCM54XX_EXP_SEL_ER 0x0f00 /* Expansion register select */ #define MIIM_BCM_AUXCNTL_SHDWSEL_MISC 0x0007 -#define MIIM_BCM_AUXCNTL_ACTL_SMDSP_EN 0x0800 +#define MIIM_BCM_AUXCNTL_SHDWSEL_MISC_WIRESPEED_EN 0x0010 +#define MIIM_BCM_AUXCNTL_SHDWSEL_MISC_RGMII_EN 0x0080 +#define MIIM_BCM_AUXCNTL_SHDWSEL_MISC_RGMII_SKEW_EN 0x0100 +#define MIIM_BCM_AUXCNTL_MISC_FORCE_AMDIX 0x0200 +#define MIIM_BCM_AUXCNTL_ACTL_SMDSP_EN 0x0800 +#define MIIM_BCM_AUXCNTL_MISC_WREN 0x8000 #define MIIM_BCM_CHANNEL_WIDTH 0x2000 +#define BCM54810_SHD_CLK_CTL 0x3 +#define BCM54810_SHD_CLK_CTL_GTXCLK_EN BIT(9) + +static int bcm54xx_auxctl_read(struct phy_device *phydev, u16 regnum) +{ + /* The register must be written to both the Shadow Register Select and + * the Shadow Read Register Selector + */ + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_BCM54xx_AUXCNTL, + MIIM_BCM54xx_AUXCNTL_ENCODE(regnum)); + return phy_read(phydev, MDIO_DEVAD_NONE, MIIM_BCM54xx_AUXCNTL); +} + +static int bcm54xx_auxctl_write(struct phy_device *phydev, u16 regnum, u16 val) +{ + return phy_write(phydev, MDIO_DEVAD_NONE, MIIM_BCM54xx_AUXCNTL, regnum | val); +} + +static int bcm_phy_read_shadow(struct phy_device *phydev, u16 shadow) +{ + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_BCM54XX_SHD, + MIIM_BCM54XX_SHD_VAL(shadow)); + return MIIM_BCM54XX_SHD_DATA(phy_read(phydev, MDIO_DEVAD_NONE, + MIIM_BCM54XX_SHD)); +} + +static int bcm_phy_write_shadow(struct phy_device *phydev, u16 shadow, u16 val) +{ + return phy_write(phydev, MDIO_DEVAD_NONE, MIIM_BCM54XX_SHD, + MIIM_BCM54XX_SHD_WR_ENCODE(shadow, val)); +} + +static int bcm54xx_config_clock_delay(struct phy_device *phydev) +{ + int rc, val; + + /* handling PHY's internal RX clock delay */ + val = bcm54xx_auxctl_read(phydev, MIIM_BCM_AUXCNTL_SHDWSEL_MISC); + val |= MIIM_BCM_AUXCNTL_MISC_WREN; + if (phydev->interface == PHY_INTERFACE_MODE_RGMII || + phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) { + /* Disable RGMII RXC-RXD skew */ + val &= ~MIIM_BCM_AUXCNTL_SHDWSEL_MISC_RGMII_SKEW_EN; + } + if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID || + phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) { + /* Enable RGMII RXC-RXD skew */ + val |= MIIM_BCM_AUXCNTL_SHDWSEL_MISC_RGMII_SKEW_EN; + } + rc = bcm54xx_auxctl_write(phydev, MIIM_BCM_AUXCNTL_SHDWSEL_MISC, val); + if (rc < 0) + return rc; + + /* handling PHY's internal TX clock delay */ + val = bcm_phy_read_shadow(phydev, BCM54810_SHD_CLK_CTL); + if (phydev->interface == PHY_INTERFACE_MODE_RGMII || + phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) { + /* Disable internal TX clock delay */ + val &= ~BCM54810_SHD_CLK_CTL_GTXCLK_EN; + } + if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID || + phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) { + /* Enable internal TX clock delay */ + val |= BCM54810_SHD_CLK_CTL_GTXCLK_EN; + } + rc = bcm_phy_write_shadow(phydev, BCM54810_SHD_CLK_CTL, val); + if (rc < 0) + return rc; + + return 0; +} + static void bcm_phy_write_misc(struct phy_device *phydev, u16 reg, u16 chl, u16 value) { @@ -62,6 +139,18 @@ static int bcm5461_config(struct phy_device *phydev) return 0; } +/* Broadcom BCM54210E */ +static int bcm54210e_config(struct phy_device *phydev) +{ + int ret; + + ret = bcm54xx_config_clock_delay(phydev); + if (ret < 0) + return ret; + + return bcm5461_config(phydev); +} + static int bcm54xx_parse_status(struct phy_device *phydev) { unsigned int mii_reg; @@ -311,6 +400,16 @@ static int bcm5482_startup(struct phy_device *phydev) return bcm54xx_parse_status(phydev); } +U_BOOT_PHY_DRIVER(bcm54210e) = { + .name = "Broadcom BCM54210E", + .uid = 0x600d84a0, + .mask = 0xfffffff0, + .features = PHY_GBIT_FEATURES, + .config = &bcm54210e_config, + .startup = &bcm54xx_startup, + .shutdown = &genphy_shutdown, +}; + U_BOOT_PHY_DRIVER(bcm5461s) = { .name = "Broadcom BCM5461S", .uid = 0x2060c0, diff --git a/drivers/net/phy/motorcomm.c b/drivers/net/phy/motorcomm.c index e822fd76f2..8635a960d6 100644 --- a/drivers/net/phy/motorcomm.c +++ b/drivers/net/phy/motorcomm.c @@ -11,6 +11,7 @@ #include <phy.h> #include <linux/bitfield.h> +#define PHY_ID_YT8511 0x0000010a #define PHY_ID_YT8531 0x4f51e91b #define PHY_ID_MASK GENMASK(31, 0) @@ -26,6 +27,31 @@ #define YTPHY_DTS_OUTPUT_CLK_25M 25000000 #define YTPHY_DTS_OUTPUT_CLK_125M 125000000 +#define YT8511_EXT_CLK_GATE 0x0c +#define YT8511_EXT_DELAY_DRIVE 0x0d +#define YT8511_EXT_SLEEP_CTRL 0x27 + +/* 2b00 25m from pll + * 2b01 25m from xtl *default* + * 2b10 62.m from pll + * 2b11 125m from pll + */ +#define YT8511_CLK_125M (BIT(2) | BIT(1)) +#define YT8511_PLLON_SLP BIT(14) + +/* RX Delay enabled = 1.8ns 1000T, 8ns 10/100T */ +#define YT8511_DELAY_RX BIT(0) + +/* TX Gig-E Delay is bits 7:4, default 0x5 + * TX Fast-E Delay is bits 15:12, default 0xf + * Delay = 150ps * N - 250ps + * On = 2000ps, off = 50ps + */ +#define YT8511_DELAY_GE_TX_EN (0xf << 4) +#define YT8511_DELAY_GE_TX_DIS (0x2 << 4) +#define YT8511_DELAY_FE_TX_EN (0xf << 12) +#define YT8511_DELAY_FE_TX_DIS (0x2 << 12) + #define YT8531_SCR_SYNCE_ENABLE BIT(6) /* 1b0 output 25m clock *default* * 1b1 output 125m clock @@ -347,6 +373,58 @@ static void ytphy_dt_parse(struct phy_device *phydev) priv->flag |= TX_CLK_1000_INVERTED; } +static int yt8511_config(struct phy_device *phydev) +{ + u32 ge, fe; + int ret; + + ret = genphy_config_aneg(phydev); + if (ret < 0) + return ret; + + switch (phydev->interface) { + case PHY_INTERFACE_MODE_RGMII: + ge = YT8511_DELAY_GE_TX_DIS; + fe = YT8511_DELAY_FE_TX_DIS; + break; + case PHY_INTERFACE_MODE_RGMII_RXID: + ge = YT8511_DELAY_RX | YT8511_DELAY_GE_TX_DIS; + fe = YT8511_DELAY_FE_TX_DIS; + break; + case PHY_INTERFACE_MODE_RGMII_TXID: + ge = YT8511_DELAY_GE_TX_EN; + fe = YT8511_DELAY_FE_TX_EN; + break; + case PHY_INTERFACE_MODE_RGMII_ID: + ge = YT8511_DELAY_RX | YT8511_DELAY_GE_TX_EN; + fe = YT8511_DELAY_FE_TX_EN; + break; + default: /* do not support other modes */ + return -EOPNOTSUPP; + } + + ret = ytphy_modify_ext(phydev, YT8511_EXT_CLK_GATE, + (YT8511_DELAY_RX | YT8511_DELAY_GE_TX_EN), ge); + if (ret < 0) + return ret; + /* set clock mode to 125m */ + ret = ytphy_modify_ext(phydev, YT8511_EXT_CLK_GATE, + YT8511_CLK_125M, YT8511_CLK_125M); + if (ret < 0) + return ret; + ret = ytphy_modify_ext(phydev, YT8511_EXT_DELAY_DRIVE, + YT8511_DELAY_FE_TX_EN, fe); + if (ret < 0) + return ret; + /* sleep control, disable PLL in sleep for now */ + ret = ytphy_modify_ext(phydev, YT8511_EXT_SLEEP_CTRL, YT8511_PLLON_SLP, + 0); + if (ret < 0) + return ret; + + return 0; +} + static int yt8531_config(struct phy_device *phydev) { struct ytphy_plat_priv *priv = phydev->priv; @@ -425,6 +503,16 @@ static int yt8531_probe(struct phy_device *phydev) return 0; } +U_BOOT_PHY_DRIVER(motorcomm8511) = { + .name = "YT8511 Gigabit Ethernet", + .uid = PHY_ID_YT8511, + .mask = PHY_ID_MASK, + .features = PHY_GBIT_FEATURES, + .config = &yt8511_config, + .startup = &genphy_startup, + .shutdown = &genphy_shutdown, +}; + U_BOOT_PHY_DRIVER(motorcomm8531) = { .name = "YT8531 Gigabit Ethernet", .uid = PHY_ID_YT8531, diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c index f3cdfb0275..3377e669f2 100644 --- a/drivers/net/zynq_gem.c +++ b/drivers/net/zynq_gem.c @@ -890,7 +890,8 @@ static int zynq_gem_probe(struct udevice *dev) if (ret) goto err3; - if (priv->interface == PHY_INTERFACE_MODE_SGMII && phy.dev) { + if (priv->interface == PHY_INTERFACE_MODE_SGMII && + generic_phy_valid(&phy)) { if (IS_ENABLED(CONFIG_DM_ETH_PHY)) { if (device_is_compatible(dev, "cdns,zynqmp-gem") || device_is_compatible(dev, "xlnx,zynqmp-gem")) { |