X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=drivers%2Fnet%2Fphy%2Fti.c;h=6db6edd0d0c844caedb903ebe21d6092e16a4e38;hb=1d63ec3fa40e4899ad1d74d5ed3c926acfda54f2;hp=937426bc85652ef123a076e681e6ace4e6c3cb91;hpb=814013253fd4cf932d0fb32f7043f09a2a748d9a;p=oweals%2Fu-boot.git diff --git a/drivers/net/phy/ti.c b/drivers/net/phy/ti.c index 937426bc85..6db6edd0d0 100644 --- a/drivers/net/phy/ti.c +++ b/drivers/net/phy/ti.c @@ -1,11 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0 /* * TI PHY drivers * - * SPDX-License-Identifier: GPL-2.0 - * */ #include #include +#include +#include + +#include +#include + /* TI DP83867 */ #define DP83867_DEVADDR 0x1f @@ -17,8 +22,11 @@ #define DP83867_CTRL 0x1f /* Extended Registers */ +#define DP83867_CFG4 0x0031 #define DP83867_RGMIICTL 0x0032 +#define DP83867_STRAP_STS1 0x006E #define DP83867_RGMIIDCTL 0x0086 +#define DP83867_IO_MUX_CFG 0x0170 #define DP83867_SW_RESET BIT(15) #define DP83867_SW_RESTART BIT(14) @@ -41,8 +49,12 @@ #define DP83867_RGMII_TX_CLK_DELAY_EN BIT(1) #define DP83867_RGMII_RX_CLK_DELAY_EN BIT(0) +/* STRAP_STS1 bits */ +#define DP83867_STRAP_STS1_RESERVED BIT(11) + /* PHY CTRL bits */ #define DP83867_PHYCR_FIFO_DEPTH_SHIFT 14 +#define DP83867_PHYCR_RESERVED_MASK BIT(11) #define DP83867_MDI_CROSSOVER 5 #define DP83867_MDI_CROSSOVER_AUTO 2 #define DP83867_MDI_CROSSOVER_MDIX 2 @@ -71,6 +83,39 @@ #define MII_MMD_CTRL_INCR_RDWT 0x8000 /* post increment on reads & writes */ #define MII_MMD_CTRL_INCR_ON_WT 0xC000 /* post increment on writes only */ +/* User setting - can be taken from DTS */ +#define DEFAULT_RX_ID_DELAY DP83867_RGMIIDCTL_2_25_NS +#define DEFAULT_TX_ID_DELAY DP83867_RGMIIDCTL_2_75_NS +#define DEFAULT_FIFO_DEPTH DP83867_PHYCR_FIFO_DEPTH_4_B_NIB + +/* IO_MUX_CFG bits */ +#define DP83867_IO_MUX_CFG_IO_IMPEDANCE_CTRL 0x1f + +#define DP83867_IO_MUX_CFG_IO_IMPEDANCE_MAX 0x0 +#define DP83867_IO_MUX_CFG_IO_IMPEDANCE_MIN 0x1f +#define DP83867_IO_MUX_CFG_CLK_O_SEL_SHIFT 8 +#define DP83867_IO_MUX_CFG_CLK_O_SEL_MASK \ + GENMASK(0x1f, DP83867_IO_MUX_CFG_CLK_O_SEL_SHIFT) + +/* CFG4 bits */ +#define DP83867_CFG4_PORT_MIRROR_EN BIT(0) + +enum { + DP83867_PORT_MIRRORING_KEEP, + DP83867_PORT_MIRRORING_EN, + DP83867_PORT_MIRRORING_DIS, +}; + +struct dp83867_private { + int rx_id_delay; + int tx_id_delay; + int fifo_depth; + int io_impedance; + bool rxctrl_strap_quirk; + int port_mirroring; + int clk_output_sel; +}; + /** * phy_read_mmd_indirect - reads data from the MMD registers * @phydev: The PHY device bus @@ -137,39 +182,166 @@ void phy_write_mmd_indirect(struct phy_device *phydev, int prtad, phy_write(phydev, addr, MII_MMD_DATA, data); } +static int dp83867_config_port_mirroring(struct phy_device *phydev) +{ + struct dp83867_private *dp83867 = + (struct dp83867_private *)phydev->priv; + u16 val; + + val = phy_read_mmd_indirect(phydev, DP83867_CFG4, DP83867_DEVADDR, + phydev->addr); + + if (dp83867->port_mirroring == DP83867_PORT_MIRRORING_EN) + val |= DP83867_CFG4_PORT_MIRROR_EN; + else + val &= ~DP83867_CFG4_PORT_MIRROR_EN; + + phy_write_mmd_indirect(phydev, DP83867_CFG4, DP83867_DEVADDR, + phydev->addr, val); + + return 0; +} + +#if defined(CONFIG_DM_ETH) /** - * phy_interface_is_rgmii - Convenience function for testing if a PHY interface - * is RGMII (all variants) + * dp83867_data_init - Convenience function for setting PHY specific data + * * @phydev: the phy_device struct */ -static inline bool phy_interface_is_rgmii(struct phy_device *phydev) +static int dp83867_of_init(struct phy_device *phydev) { - return phydev->interface >= PHY_INTERFACE_MODE_RGMII && - phydev->interface <= PHY_INTERFACE_MODE_RGMII_TXID; + struct dp83867_private *dp83867 = phydev->priv; + ofnode node; + u16 val; + + /* Optional configuration */ + + /* + * Keep the default value if ti,clk-output-sel is not set + * or to high + */ + + dp83867->clk_output_sel = + ofnode_read_u32_default(node, "ti,clk-output-sel", + DP83867_CLK_O_SEL_REF_CLK); + + node = phy_get_ofnode(phydev); + if (!ofnode_valid(node)) + return -EINVAL; + + if (ofnode_read_bool(node, "ti,max-output-impedance")) + dp83867->io_impedance = DP83867_IO_MUX_CFG_IO_IMPEDANCE_MAX; + else if (ofnode_read_bool(node, "ti,min-output-impedance")) + dp83867->io_impedance = DP83867_IO_MUX_CFG_IO_IMPEDANCE_MIN; + else + dp83867->io_impedance = -EINVAL; + + if (ofnode_read_bool(node, "ti,dp83867-rxctrl-strap-quirk")) + dp83867->rxctrl_strap_quirk = true; + dp83867->rx_id_delay = ofnode_read_u32_default(node, + "ti,rx-internal-delay", + -1); + + dp83867->tx_id_delay = ofnode_read_u32_default(node, + "ti,tx-internal-delay", + -1); + + dp83867->fifo_depth = ofnode_read_u32_default(node, "ti,fifo-depth", + -1); + if (ofnode_read_bool(node, "enet-phy-lane-swap")) + dp83867->port_mirroring = DP83867_PORT_MIRRORING_EN; + + if (ofnode_read_bool(node, "enet-phy-lane-no-swap")) + dp83867->port_mirroring = DP83867_PORT_MIRRORING_DIS; + + + /* Clock output selection if muxing property is set */ + if (dp83867->clk_output_sel != DP83867_CLK_O_SEL_REF_CLK) { + val = phy_read_mmd_indirect(phydev, DP83867_IO_MUX_CFG, + DP83867_DEVADDR, phydev->addr); + val &= ~DP83867_IO_MUX_CFG_CLK_O_SEL_MASK; + val |= (dp83867->clk_output_sel << + DP83867_IO_MUX_CFG_CLK_O_SEL_SHIFT); + phy_write_mmd_indirect(phydev, DP83867_IO_MUX_CFG, + DP83867_DEVADDR, phydev->addr, val); + } + + return 0; } +#else +static int dp83867_of_init(struct phy_device *phydev) +{ + struct dp83867_private *dp83867 = phydev->priv; -/* User setting - can be taken from DTS */ -#define RX_ID_DELAY 8 -#define TX_ID_DELAY 0xa -#define FIFO_DEPTH 1 + dp83867->rx_id_delay = DEFAULT_RX_ID_DELAY; + dp83867->tx_id_delay = DEFAULT_TX_ID_DELAY; + dp83867->fifo_depth = DEFAULT_FIFO_DEPTH; + dp83867->io_impedance = -EINVAL; + + return 0; +} +#endif static int dp83867_config(struct phy_device *phydev) { + struct dp83867_private *dp83867; unsigned int val, delay, cfg2; - int ret; + int ret, bs; + + if (!phydev->priv) { + dp83867 = kzalloc(sizeof(*dp83867), GFP_KERNEL); + if (!dp83867) + return -ENOMEM; + + phydev->priv = dp83867; + ret = dp83867_of_init(phydev); + if (ret) + goto err_out; + } else { + dp83867 = (struct dp83867_private *)phydev->priv; + } /* Restart the PHY. */ val = phy_read(phydev, MDIO_DEVAD_NONE, DP83867_CTRL); phy_write(phydev, MDIO_DEVAD_NONE, DP83867_CTRL, val | DP83867_SW_RESTART); + /* Mode 1 or 2 workaround */ + if (dp83867->rxctrl_strap_quirk) { + val = phy_read_mmd_indirect(phydev, DP83867_CFG4, + DP83867_DEVADDR, phydev->addr); + val &= ~BIT(7); + phy_write_mmd_indirect(phydev, DP83867_CFG4, + DP83867_DEVADDR, phydev->addr, val); + } + if (phy_interface_is_rgmii(phydev)) { ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_DP83867_PHYCTRL, (DP83867_MDI_CROSSOVER_AUTO << DP83867_MDI_CROSSOVER) | - (FIFO_DEPTH << DP83867_PHYCR_FIFO_DEPTH_SHIFT)); + (dp83867->fifo_depth << DP83867_PHYCR_FIFO_DEPTH_SHIFT)); if (ret) - return ret; - } else { + goto err_out; + + /* The code below checks if "port mirroring" N/A MODE4 has been + * enabled during power on bootstrap. + * + * Such N/A mode enabled by mistake can put PHY IC in some + * internal testing mode and disable RGMII transmission. + * + * In this particular case one needs to check STRAP_STS1 + * register's bit 11 (marked as RESERVED). + */ + + bs = phy_read_mmd_indirect(phydev, DP83867_STRAP_STS1, + DP83867_DEVADDR, phydev->addr); + val = phy_read(phydev, MDIO_DEVAD_NONE, MII_DP83867_PHYCTRL); + if (bs & DP83867_STRAP_STS1_RESERVED) { + val &= ~DP83867_PHYCR_RESERVED_MASK; + phy_write(phydev, MDIO_DEVAD_NONE, MII_DP83867_PHYCTRL, + val); + } + + } else if (phy_interface_is_sgmii(phydev)) { phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, (BMCR_ANENABLE | BMCR_FULLDPLX | BMCR_SPEED1000)); @@ -189,13 +361,12 @@ static int dp83867_config(struct phy_device *phydev) DP83867_PHYCTRL_SGMIIEN | (DP83867_MDI_CROSSOVER_MDIX << DP83867_MDI_CROSSOVER) | - (FIFO_DEPTH << DP83867_PHYCTRL_RXFIFO_SHIFT) | - (FIFO_DEPTH << DP83867_PHYCTRL_TXFIFO_SHIFT)); + (dp83867->fifo_depth << DP83867_PHYCTRL_RXFIFO_SHIFT) | + (dp83867->fifo_depth << DP83867_PHYCTRL_TXFIFO_SHIFT)); phy_write(phydev, MDIO_DEVAD_NONE, MII_DP83867_BISCR, 0x0); } - if ((phydev->interface >= PHY_INTERFACE_MODE_RGMII_ID) && - (phydev->interface <= PHY_INTERFACE_MODE_RGMII_RXID)) { + if (phy_interface_is_rgmii(phydev)) { val = phy_read_mmd_indirect(phydev, DP83867_RGMIICTL, DP83867_DEVADDR, phydev->addr); @@ -212,15 +383,35 @@ static int dp83867_config(struct phy_device *phydev) phy_write_mmd_indirect(phydev, DP83867_RGMIICTL, DP83867_DEVADDR, phydev->addr, val); - delay = (RX_ID_DELAY | - (TX_ID_DELAY << DP83867_RGMII_TX_CLK_DELAY_SHIFT)); + delay = (dp83867->rx_id_delay | + (dp83867->tx_id_delay << DP83867_RGMII_TX_CLK_DELAY_SHIFT)); phy_write_mmd_indirect(phydev, DP83867_RGMIIDCTL, DP83867_DEVADDR, phydev->addr, delay); + + if (dp83867->io_impedance >= 0) { + val = phy_read_mmd_indirect(phydev, + DP83867_IO_MUX_CFG, + DP83867_DEVADDR, + phydev->addr); + val &= ~DP83867_IO_MUX_CFG_IO_IMPEDANCE_CTRL; + val |= dp83867->io_impedance & + DP83867_IO_MUX_CFG_IO_IMPEDANCE_CTRL; + phy_write_mmd_indirect(phydev, DP83867_IO_MUX_CFG, + DP83867_DEVADDR, phydev->addr, + val); + } } + if (dp83867->port_mirroring != DP83867_PORT_MIRRORING_KEEP) + dp83867_config_port_mirroring(phydev); + genphy_config_aneg(phydev); return 0; + +err_out: + kfree(dp83867); + return ret; } static struct phy_driver DP83867_driver = {