X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=drivers%2Fnet%2Fphy%2Fti.c;h=6db6edd0d0c844caedb903ebe21d6092e16a4e38;hb=1d63ec3fa40e4899ad1d74d5ed3c926acfda54f2;hp=6ad31a0465863a215287d065a89104e0c221a469;hpb=da409ccc4ae62a0bf7111e2f4419fdbfd1ba3d89;p=oweals%2Fu-boot.git diff --git a/drivers/net/phy/ti.c b/drivers/net/phy/ti.c index 6ad31a0465..6db6edd0d0 100644 --- a/drivers/net/phy/ti.c +++ b/drivers/net/phy/ti.c @@ -1,19 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0 /* * TI PHY drivers * - * SPDX-License-Identifier: GPL-2.0 - * */ #include #include #include #include -#include #include #include -DECLARE_GLOBAL_DATA_PTR; /* TI DP83867 */ #define DP83867_DEVADDR 0x1f @@ -25,7 +22,9 @@ DECLARE_GLOBAL_DATA_PTR; #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 @@ -50,8 +49,12 @@ DECLARE_GLOBAL_DATA_PTR; #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 @@ -90,12 +93,27 @@ DECLARE_GLOBAL_DATA_PTR; #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; }; /** @@ -164,6 +182,26 @@ 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) /** * dp83867_data_init - Convenience function for setting PHY specific data @@ -173,25 +211,60 @@ void phy_write_mmd_indirect(struct phy_device *phydev, int prtad, static int dp83867_of_init(struct phy_device *phydev) { struct dp83867_private *dp83867 = phydev->priv; - struct udevice *dev = phydev->dev; - int node = dev_of_offset(dev); - const void *fdt = gd->fdt_blob; + ofnode node; + u16 val; + + /* Optional configuration */ + + /* + * Keep the default value if ti,clk-output-sel is not set + * or to high + */ - if (fdtdec_get_bool(fdt, node, "ti,max-output-impedance")) + 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 (fdtdec_get_bool(fdt, node, "ti,min-output-impedance")) + 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; - dp83867->rx_id_delay = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev), - "ti,rx-internal-delay", -1); + 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; - dp83867->tx_id_delay = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev), - "ti,tx-internal-delay", -1); + if (ofnode_read_bool(node, "enet-phy-lane-no-swap")) + dp83867->port_mirroring = DP83867_PORT_MIRRORING_DIS; - dp83867->fifo_depth = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev), - "ti,fifo-depth", -1); + + /* 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; } @@ -213,7 +286,7 @@ 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); @@ -233,12 +306,41 @@ static int dp83867_config(struct phy_device *phydev) 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) | (dp83867->fifo_depth << DP83867_PHYCR_FIFO_DEPTH_SHIFT)); if (ret) 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)); @@ -301,6 +403,9 @@ static int dp83867_config(struct phy_device *phydev) } } + if (dp83867->port_mirroring != DP83867_PORT_MIRRORING_KEEP) + dp83867_config_port_mirroring(phydev); + genphy_config_aneg(phydev); return 0;