From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from phobos.denx.de (phobos.denx.de [85.214.62.61]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 2093BC433F5 for ; Wed, 22 Dec 2021 07:58:15 +0000 (UTC) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 43EFA82F91; Wed, 22 Dec 2021 08:58:13 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="Ojow1FLl"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id E2D4682FB4; Wed, 22 Dec 2021 08:58:11 +0100 (CET) Received: from mail-ed1-x529.google.com (mail-ed1-x529.google.com [IPv6:2a00:1450:4864:20::529]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id 9478B80F81 for ; Wed, 22 Dec 2021 08:58:07 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=christian.gmeiner@gmail.com Received: by mail-ed1-x529.google.com with SMTP id y22so5328672edq.2 for ; Tue, 21 Dec 2021 23:58:07 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=R2GoEDAFiM4PbgTbA4VVFZZhqPZAoGNhALfBCQoRNEk=; b=Ojow1FLldLSGTtovKaJxnpoD3CQQVhEO37YnME5hM8ime295UYRphaogrs1qqVYXzu feMhr1I/dl8d7OAsWhI0lbx0MCiuNt6CduTMp55LN0aiePps8rxXa0WRSWcyRfVp57Ob /C5+OSTVYpuouGeC5UES6LOtumvwB0oKx+neH7sp32Lw2cZ3FZpCDVhiyH/KSgKUHx7C 5/4e1f4NuZQ7bCi38RYtMFdp+hvcAWwuQrNZ21SvRcr7DHCtJfU/NMMBDp+zNTkz1mqV 99bblFYMSr6CB0UfkJ+tAhUdVB+MN2YMFWFo89NTmy9QgTspWLtYNg1966+T/lwi111L CqYQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=R2GoEDAFiM4PbgTbA4VVFZZhqPZAoGNhALfBCQoRNEk=; b=IgQVmg8A65/cGXjUO4M/jfnLpohwstkhXurFCr9o9oXQAI3tjZkl1g7zauWMC01qeP EGBL/s3YWfYFLeBilnBR5+JUqg/0LpYr9p/8AZoTA1d7kr2EZUQd1T3FlXR01HP82S4j smFIJUWLweKn/uyY9VmfNgFs/7y5f1HTFYS+dAh2Kwy/yNMQvVL1qL0TKb8I+v3NuXoh rZ8kvPs2cpfu9R91SgWS+TN/C92GxVGP/H+27D6F2W/WYvPlOV7VNCNzLCupL4169e2J dvWWOYKH2RDpxoQo6UqmdY9TodEyzNbl1LIHb7R68MMX2Qr8fHqHXC0xaHQ3Umh5prxz BPag== X-Gm-Message-State: AOAM533v+wYsmgVCtKWNYeTy5meAJGrfgyCVqN9Z6KVvnWIj3ZmgLvMG yEYiDgjFRJ2tYYJb27d+X6S+LOnGg11Qhg== X-Google-Smtp-Source: ABdhPJy4Gm1wWrMUsfDs9N7ZrS62R+8INafghmwibEoNZBA4bc8X8+2DidBJU5qD+IIKAI/7Hl4T/w== X-Received: by 2002:a17:907:2cc4:: with SMTP id hg4mr1509475ejc.150.1640159886713; Tue, 21 Dec 2021 23:58:06 -0800 (PST) Received: from localhost.localdomain.at (62-178-82-229.cable.dynamic.surfer.at. [62.178.82.229]) by smtp.gmail.com with ESMTPSA id qt5sm411048ejb.214.2021.12.21.23.58.05 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 21 Dec 2021 23:58:06 -0800 (PST) From: Christian Gmeiner To: u-boot@lists.denx.de Cc: Dominic Rath , Christian Gmeiner , Joe Hershberger , Ramon Fried , Priyanka Jain , Michal Simek , Kuldeep Singh , Abbie Chang , Bin Meng , "Radu Pirea (NXP OSS)" Subject: [PATCH] net: phy: add TI DP83869HM ethernet driver Date: Wed, 22 Dec 2021 08:57:46 +0100 Message-Id: <20211222075803.211141-1-christian.gmeiner@gmail.com> X-Mailer: git-send-email 2.33.1 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.38 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.2 at phobos.denx.de X-Virus-Status: Clean From: Dominic Rath This driver is based on an older downstream TI kernel, with changes and cleanups to work with mainline device-tree bindings. Signed-off-by: Dominic Rath Signed-off-by: Christian Gmeiner --- drivers/net/phy/Kconfig | 6 + drivers/net/phy/Makefile | 1 + drivers/net/phy/dp83869.c | 507 +++++++++++++++++++++++++++ drivers/net/phy/ti_phy_init.c | 4 + drivers/net/phy/ti_phy_init.h | 1 + include/dt-bindings/net/ti-dp83869.h | 60 ++++ 6 files changed, 579 insertions(+) create mode 100644 drivers/net/phy/dp83869.c create mode 100644 include/dt-bindings/net/ti-dp83869.h diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 68ee7d7a2d..c6e58058d9 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -290,6 +290,12 @@ config PHY_TI_DP83867 ---help--- Adds support for the TI DP83867 1Gbit PHY. +config PHY_TI_DP83869 + select PHY_TI + bool "Texas Instruments Ethernet DP83869 PHY support" + ---help--- + Adds support for the TI DP83869 1Gbit PHY. + config PHY_TI_GENERIC select PHY_TI bool "Texas Instruments Generic Ethernet PHYs support" diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 218b8c7669..77f7f60621 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -29,6 +29,7 @@ obj-$(CONFIG_PHY_SMSC) += smsc.o obj-$(CONFIG_PHY_TERANETICS) += teranetics.o obj-$(CONFIG_PHY_TI) += ti_phy_init.o obj-$(CONFIG_PHY_TI_DP83867) += dp83867.o +obj-$(CONFIG_PHY_TI_DP83869) += dp83869.o obj-$(CONFIG_PHY_XILINX) += xilinx_phy.o obj-$(CONFIG_PHY_XILINX_GMII2RGMII) += xilinx_gmii2rgmii.o obj-$(CONFIG_PHY_VITESSE) += vitesse.o diff --git a/drivers/net/phy/dp83869.c b/drivers/net/phy/dp83869.c new file mode 100644 index 0000000000..c9461185cf --- /dev/null +++ b/drivers/net/phy/dp83869.c @@ -0,0 +1,507 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * TI PHY drivers + * + */ + +#include +#include +#include +#include + +#include +#include + +/* TI DP83869 */ +#define DP83869_DEVADDR 0x1f + +#define MII_DP83869_PHYCTRL 0x10 +#define MII_DP83869_MICR 0x12 +#define MII_DP83869_CFG2 0x14 +#define MII_DP83869_BISCR 0x16 +#define DP83869_CTRL 0x1f +#define DP83869_CFG4 0x1e + +/* Extended Registers */ +#define DP83869_GEN_CFG3 0x0031 +#define DP83869_RGMIICTL 0x0032 +#define DP83869_STRAP_STS1 0x006E +#define DP83869_RGMIIDCTL 0x0086 +#define DP83869_IO_MUX_CFG 0x0170 +#define DP83869_OP_MODE 0x01df +#define DP83869_FX_CTRL 0x0c00 + +#define DP83869_SW_RESET BIT(15) +#define DP83869_SW_RESTART BIT(14) + +/* MICR Interrupt bits */ +#define MII_DP83869_MICR_AN_ERR_INT_EN BIT(15) +#define MII_DP83869_MICR_SPEED_CHNG_INT_EN BIT(14) +#define MII_DP83869_MICR_DUP_MODE_CHNG_INT_EN BIT(13) +#define MII_DP83869_MICR_PAGE_RXD_INT_EN BIT(12) +#define MII_DP83869_MICR_AUTONEG_COMP_INT_EN BIT(11) +#define MII_DP83869_MICR_LINK_STS_CHNG_INT_EN BIT(10) +#define MII_DP83869_MICR_FALSE_CARRIER_INT_EN BIT(8) +#define MII_DP83869_MICR_SLEEP_MODE_CHNG_INT_EN BIT(4) +#define MII_DP83869_MICR_WOL_INT_EN BIT(3) +#define MII_DP83869_MICR_XGMII_ERR_INT_EN BIT(2) +#define MII_DP83869_MICR_POL_CHNG_INT_EN BIT(1) +#define MII_DP83869_MICR_JABBER_INT_EN BIT(0) + +#define MII_DP83869_BMCR_DEFAULT (BMCR_ANENABLE | \ + BMCR_FULLDPLX | \ + BMCR_SPEED1000) + +/* This is the same bit mask as the BMCR so re-use the BMCR default */ +#define DP83869_FX_CTRL_DEFAULT MII_DP83869_BMCR_DEFAULT + +/* CFG1 bits */ +#define DP83869_CFG1_DEFAULT (ADVERTISE_1000HALF | \ + ADVERTISE_1000FULL | \ + CTL1000_AS_MASTER) + +/* RGMIICTL bits */ +#define DP83869_RGMII_TX_CLK_DELAY_EN BIT(1) +#define DP83869_RGMII_RX_CLK_DELAY_EN BIT(0) + +/* STRAP_STS1 bits */ +#define DP83869_STRAP_OP_MODE_MASK GENMASK(2, 0) +#define DP83869_STRAP_STS1_RESERVED BIT(11) +#define DP83869_STRAP_MIRROR_ENABLED BIT(12) + +/* PHY CTRL bits */ +#define DP83869_PHYCR_RX_FIFO_DEPTH_SHIFT 12 +#define DP83869_PHYCR_RX_FIFO_DEPTH_MASK GENMASK(13, 12) +#define DP83869_PHYCR_TX_FIFO_DEPTH_SHIFT 14 +#define DP83869_PHYCR_TX_FIFO_DEPTH_MASK GENMASK(15, 14) +#define DP83869_PHYCR_RESERVED_MASK BIT(11) +#define DP83869_PHYCR_MDI_CROSSOVER_SHIFT 5 +#define DP83869_PHYCR_MDI_CROSSOVER_MDIX 2 +#define DP83869_PHY_CTRL_DEFAULT 0x48 + +/* RGMIIDCTL bits */ +#define DP83869_RGMII_TX_CLK_DELAY_SHIFT 4 +#define DP83869_CLK_DELAY_DEF 7 + +/* CFG2 bits */ +#define MII_DP83869_CFG2_SPEEDOPT_10EN 0x0040 +#define MII_DP83869_CFG2_SGMII_AUTONEGEN 0x0080 +#define MII_DP83869_CFG2_SPEEDOPT_ENH 0x0100 +#define MII_DP83869_CFG2_SPEEDOPT_CNT 0x0800 +#define MII_DP83869_CFG2_SPEEDOPT_INTLOW 0x2000 +#define MII_DP83869_CFG2_MASK 0x003F + +/* User setting - can be taken from DTS */ +#define DEFAULT_FIFO_DEPTH DP83869_PHYCR_FIFO_DEPTH_4_B_NIB + +/* IO_MUX_CFG bits */ +#define DP83869_IO_MUX_CFG_IO_IMPEDANCE_CTRL 0x1f + +#define DP83869_IO_MUX_CFG_IO_IMPEDANCE_MAX 0x0 +#define DP83869_IO_MUX_CFG_IO_IMPEDANCE_MIN 0x1f +#define DP83869_IO_MUX_CFG_CLK_O_DISABLE BIT(6) +#define DP83869_IO_MUX_CFG_CLK_O_SEL_SHIFT 8 +#define DP83869_IO_MUX_CFG_CLK_O_SEL_MASK \ + GENMASK(0x1f, DP83869_IO_MUX_CFG_CLK_O_SEL_SHIFT) + +/* CFG3 bits */ +#define DP83869_CFG3_PORT_MIRROR_EN BIT(0) + +/* OP MODE bits */ +#define DP83869_OP_MODE_MII BIT(5) +#define DP83869_SGMII_RGMII_BRIDGE BIT(6) + +enum { + DP83869_PORT_MIRRORING_KEEP, + DP83869_PORT_MIRRORING_EN, + DP83869_PORT_MIRRORING_DIS, +}; + +struct dp83869_private { + int tx_fifo_depth; + int rx_fifo_depth; + s32 rx_int_delay; + s32 tx_int_delay; + int io_impedance; + int port_mirroring; + bool set_clk_output; + int clk_output_sel; + int mode; +}; + +static int dp83869_readext(struct phy_device *phydev, int addr, int devad, int reg) +{ + return phy_read_mmd(phydev, devad, reg); +} + +static int dp83869_writeext(struct phy_device *phydev, int addr, int devad, int reg, u16 val) +{ + return phy_write_mmd(phydev, devad, reg, val); +} + +static int dp83869_config_port_mirroring(struct phy_device *phydev) +{ + struct dp83869_private *dp83869 = + (struct dp83869_private *)phydev->priv; + u16 val; + + val = phy_read_mmd(phydev, DP83869_DEVADDR, DP83869_CFG4); + + if (dp83869->port_mirroring == DP83869_PORT_MIRRORING_EN) + val |= DP83869_CFG3_PORT_MIRROR_EN; + else + val &= ~DP83869_CFG3_PORT_MIRROR_EN; + + phy_write_mmd(phydev, DP83869_DEVADDR, DP83869_CFG4, val); + + return 0; +} + +#ifdef CONFIG_DM_ETH +static const int dp83869_internal_delay[] = {250, 500, 750, 1000, 1250, 1500, + 1750, 2000, 2250, 2500, 2750, 3000, + 3250, 3500, 3750, 4000}; + +static int dp83869_set_strapped_mode(struct phy_device *phydev) +{ + struct dp83869_private *dp83869 = phydev->priv; + int val; + + val = phy_read_mmd(phydev, DP83869_DEVADDR, DP83869_STRAP_STS1); + if (val < 0) + return val; + + dp83869->mode = val & DP83869_STRAP_OP_MODE_MASK; + + return 0; +} + +/** + * dp83869_data_init - Convenience function for setting PHY specific data + * + * @phydev: the phy_device struct + */ +static int dp83869_of_init(struct phy_device *phydev) +{ + struct dp83869_private * const dp83869 = phydev->priv; + const int delay_entries = ARRAY_SIZE(dp83869_internal_delay); + int ret; + ofnode node; + + node = phy_get_ofnode(phydev); + if (!ofnode_valid(node)) + return -EINVAL; + + dp83869->io_impedance = -EINVAL; + + /* Optional configuration, set to default if required */ + dp83869->clk_output_sel = ofnode_read_u32_default(node, "ti,clk-output-sel", + DP83869_CLK_O_SEL_CHN_A_RCLK); + + if (dp83869->clk_output_sel > DP83869_CLK_O_SEL_REF_CLK && + dp83869->clk_output_sel != DP83869_CLK_O_SEL_OFF) + dp83869->clk_output_sel = DP83869_CLK_O_SEL_REF_CLK; + + /* If operation mode is not set use setting from straps */ + ret = ofnode_read_s32(node, "ti,op-mode", &dp83869->mode); + if (ret == 0) { + if (dp83869->mode < DP83869_RGMII_COPPER_ETHERNET || + dp83869->mode > DP83869_SGMII_COPPER_ETHERNET) + return -EINVAL; + } else { + ret = dp83869_set_strapped_mode(phydev); + if (ret) + return ret; + } + + if (ofnode_read_bool(node, "ti,max-output-impedance")) + dp83869->io_impedance = DP83869_IO_MUX_CFG_IO_IMPEDANCE_MAX; + else if (ofnode_read_bool(node, "ti,min-output-impedance")) + dp83869->io_impedance = DP83869_IO_MUX_CFG_IO_IMPEDANCE_MIN; + + if (ofnode_read_bool(node, "enet-phy-lane-swap")) { + dp83869->port_mirroring = DP83869_PORT_MIRRORING_EN; + } else { + ret = phy_read_mmd(phydev, DP83869_DEVADDR, DP83869_STRAP_STS1); + + if (ret < 0) + return ret; + + if (ret & DP83869_STRAP_MIRROR_ENABLED) + dp83869->port_mirroring = DP83869_PORT_MIRRORING_EN; + else + dp83869->port_mirroring = DP83869_PORT_MIRRORING_DIS; + } + + dp83869->rx_fifo_depth = ofnode_read_s32_default(node, "rx-fifo-depth", + DP83869_PHYCR_FIFO_DEPTH_4_B_NIB); + + dp83869->tx_fifo_depth = ofnode_read_s32_default(node, "tx-fifo-depth", + DP83869_PHYCR_FIFO_DEPTH_4_B_NIB); + + /* RX delay *must* be specified if internal delay of RX is used. */ + if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID || + phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) { + dp83869->rx_int_delay = ofnode_read_u32_default(node, "rx-internal-delay-ps", + DP83869_CLK_DELAY_DEF); + if (dp83869->rx_int_delay > delay_entries) { + dp83869->rx_int_delay = DP83869_CLK_DELAY_DEF; + pr_debug("rx-internal-delay-ps not set/invalid, default to %ups\n", + dp83869_internal_delay[dp83869->rx_int_delay]); + } + + dp83869->rx_int_delay = dp83869_internal_delay[dp83869->rx_int_delay]; + } + + /* TX delay *must* be specified if internal delay of RX is used. */ + if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID || + phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) { + dp83869->tx_int_delay = ofnode_read_u32_default(node, "tx-internal-delay-ps", + DP83869_CLK_DELAY_DEF); + if (dp83869->tx_int_delay > delay_entries) { + dp83869->tx_int_delay = DP83869_CLK_DELAY_DEF; + pr_debug("tx-internal-delay-ps not set/invalid, default to %ups\n", + dp83869_internal_delay[dp83869->tx_int_delay]); + } + + dp83869->tx_int_delay = dp83869_internal_delay[dp83869->tx_int_delay]; + } + + return 0; +} +#else +static int dp83869_of_init(struct phy_device *phydev) +{ + struct dp83869_private *dp83869 = phydev->priv; + + dp83869->rx_int_delay = DP83869_RGMIIDCTL_2_25_NS; + dp83869->tx_int_delay = DP83869_RGMIIDCTL_2_75_NS; + dp83869->fifo_depth = DEFAULT_FIFO_DEPTH; + dp83869->io_impedance = -EINVAL; + + return 0; +} +#endif /* CONFIG_OF_MDIO */ + +static int dp83869_configure_rgmii(struct phy_device *phydev, + struct dp83869_private *dp83869) +{ + int ret = 0, val; + + if (phy_interface_is_rgmii(phydev)) { + val = phy_read(phydev, MDIO_DEVAD_NONE, MII_DP83869_PHYCTRL); + if (val < 0) + return val; + + val &= ~(DP83869_PHYCR_TX_FIFO_DEPTH_MASK | DP83869_PHYCR_RX_FIFO_DEPTH_MASK); + val |= (dp83869->tx_fifo_depth << DP83869_PHYCR_TX_FIFO_DEPTH_SHIFT); + val |= (dp83869->rx_fifo_depth << DP83869_PHYCR_RX_FIFO_DEPTH_SHIFT); + + ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_DP83869_PHYCTRL, val); + if (ret) + return ret; + } + + if (dp83869->io_impedance >= 0) { + val = phy_read_mmd(phydev, DP83869_DEVADDR, DP83869_IO_MUX_CFG); + + val &= ~DP83869_IO_MUX_CFG_IO_IMPEDANCE_CTRL; + val |= dp83869->io_impedance & DP83869_IO_MUX_CFG_IO_IMPEDANCE_CTRL; + + ret = phy_write_mmd(phydev, DP83869_DEVADDR, DP83869_IO_MUX_CFG, val); + + if (ret) + return ret; + } + + return ret; +} + +static int dp83869_configure_mode(struct phy_device *phydev, + struct dp83869_private *dp83869) +{ + int phy_ctrl_val; + int ret, val; + + if (dp83869->mode < DP83869_RGMII_COPPER_ETHERNET || + dp83869->mode > DP83869_SGMII_COPPER_ETHERNET) + return -EINVAL; + + /* Below init sequence for each operational mode is defined in + * section 9.4.8 of the datasheet. + */ + ret = phy_write_mmd(phydev, DP83869_DEVADDR, DP83869_OP_MODE, + dp83869->mode); + if (ret) + return ret; + + ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, MII_DP83869_BMCR_DEFAULT); + if (ret) + return ret; + + phy_ctrl_val = (dp83869->rx_fifo_depth << DP83869_PHYCR_RX_FIFO_DEPTH_SHIFT | + dp83869->tx_fifo_depth << DP83869_PHYCR_TX_FIFO_DEPTH_SHIFT | + DP83869_PHY_CTRL_DEFAULT); + + switch (dp83869->mode) { + case DP83869_RGMII_COPPER_ETHERNET: + ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_DP83869_PHYCTRL, + phy_ctrl_val); + if (ret) + return ret; + + ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_CTRL1000, DP83869_CFG1_DEFAULT); + if (ret) + return ret; + + ret = dp83869_configure_rgmii(phydev, dp83869); + if (ret) + return ret; + break; + case DP83869_RGMII_SGMII_BRIDGE: + val = phy_read_mmd(phydev, DP83869_DEVADDR, DP83869_OP_MODE); + + val |= DP83869_SGMII_RGMII_BRIDGE; + + ret = phy_write_mmd(phydev, DP83869_DEVADDR, DP83869_OP_MODE, val); + + if (ret) + return ret; + + ret = phy_write_mmd(phydev, DP83869_DEVADDR, + DP83869_FX_CTRL, DP83869_FX_CTRL_DEFAULT); + if (ret) + return ret; + + break; + case DP83869_1000M_MEDIA_CONVERT: + ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_DP83869_PHYCTRL, + phy_ctrl_val); + if (ret) + return ret; + + ret = phy_write_mmd(phydev, DP83869_DEVADDR, + DP83869_FX_CTRL, DP83869_FX_CTRL_DEFAULT); + if (ret) + return ret; + break; + case DP83869_100M_MEDIA_CONVERT: + ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_DP83869_PHYCTRL, + phy_ctrl_val); + if (ret) + return ret; + break; + case DP83869_SGMII_COPPER_ETHERNET: + ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_DP83869_PHYCTRL, + phy_ctrl_val); + if (ret) + return ret; + + ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_CTRL1000, DP83869_CFG1_DEFAULT); + if (ret) + return ret; + + ret = phy_write_mmd(phydev, DP83869_DEVADDR, + DP83869_FX_CTRL, DP83869_FX_CTRL_DEFAULT); + if (ret) + return ret; + + break; + default: + return -EINVAL; + } + + return ret; +} + +static int dp83869_config(struct phy_device *phydev) +{ + struct dp83869_private *dp83869; + unsigned int val; + int ret; + + dp83869 = (struct dp83869_private *)phydev->priv; + + ret = dp83869_of_init(phydev); + if (ret) + return ret; + + ret = dp83869_configure_mode(phydev, dp83869); + if (ret) + return ret; + + if (dp83869->port_mirroring != DP83869_PORT_MIRRORING_KEEP) + dp83869_config_port_mirroring(phydev); + + /* Clock output selection if muxing property is set */ + if (dp83869->clk_output_sel != DP83869_CLK_O_SEL_REF_CLK) { + val = phy_read_mmd(phydev, DP83869_DEVADDR, DP83869_IO_MUX_CFG); + + val &= ~DP83869_IO_MUX_CFG_CLK_O_SEL_MASK; + val |= dp83869->clk_output_sel << DP83869_IO_MUX_CFG_CLK_O_SEL_SHIFT; + + ret = phy_write_mmd(phydev, DP83869_DEVADDR, DP83869_IO_MUX_CFG, val); + + if (ret) + return ret; + } + + if (phy_interface_is_rgmii(phydev)) { + ret = phy_write_mmd(phydev, DP83869_DEVADDR, DP83869_RGMIIDCTL, + dp83869->rx_int_delay | + dp83869->tx_int_delay << DP83869_RGMII_TX_CLK_DELAY_SHIFT); + if (ret) + return ret; + + val = phy_read_mmd(phydev, DP83869_DEVADDR, DP83869_RGMIICTL); + val |= (DP83869_RGMII_TX_CLK_DELAY_EN | + DP83869_RGMII_RX_CLK_DELAY_EN); + + if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) + val &= ~(DP83869_RGMII_TX_CLK_DELAY_EN | + DP83869_RGMII_RX_CLK_DELAY_EN); + + if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) + val &= ~DP83869_RGMII_TX_CLK_DELAY_EN; + + if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) + val &= ~DP83869_RGMII_RX_CLK_DELAY_EN; + + ret = phy_write_mmd(phydev, DP83869_DEVADDR, DP83869_RGMIICTL, + val); + } + + genphy_config_aneg(phydev); + return 0; +} + +static int dp83869_probe(struct phy_device *phydev) +{ + struct dp83869_private *dp83869; + + dp83869 = kzalloc(sizeof(*dp83869), GFP_KERNEL); + if (!dp83869) + return -ENOMEM; + + phydev->priv = dp83869; + return 0; +} + +static struct phy_driver DP83869_driver = { + .name = "TI DP83869", + .uid = 0x2000a0f1, + .mask = 0xfffffff0, + .features = PHY_GBIT_FEATURES, + .probe = dp83869_probe, + .config = &dp83869_config, + .startup = &genphy_startup, + .shutdown = &genphy_shutdown, + .readext = dp83869_readext, + .writeext = dp83869_writeext +}; + +int phy_dp83869_init(void) +{ + phy_register(&DP83869_driver); + return 0; +} diff --git a/drivers/net/phy/ti_phy_init.c b/drivers/net/phy/ti_phy_init.c index 50eff77692..075b19a39f 100644 --- a/drivers/net/phy/ti_phy_init.c +++ b/drivers/net/phy/ti_phy_init.c @@ -88,6 +88,10 @@ int phy_ti_init(void) phy_dp83867_init(); #endif +#ifdef CONFIG_PHY_TI_DP83869 + phy_dp83869_init(); +#endif + #ifdef CONFIG_PHY_TI_GENERIC phy_register(&dp83822_driver); phy_register(&dp83825s_driver); diff --git a/drivers/net/phy/ti_phy_init.h b/drivers/net/phy/ti_phy_init.h index 6c7f6c640a..bcb3d320d3 100644 --- a/drivers/net/phy/ti_phy_init.h +++ b/drivers/net/phy/ti_phy_init.h @@ -11,5 +11,6 @@ #define _TI_GEN_PHY_H int phy_dp83867_init(void); +int phy_dp83869_init(void); #endif /* _TI_GEN_PHY_H */ diff --git a/include/dt-bindings/net/ti-dp83869.h b/include/dt-bindings/net/ti-dp83869.h new file mode 100644 index 0000000000..b3a5ac4a17 --- /dev/null +++ b/include/dt-bindings/net/ti-dp83869.h @@ -0,0 +1,60 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * TI DP83869 PHY drivers + * + */ + +#ifndef _DT_BINDINGS_TI_DP83869_H +#define _DT_BINDINGS_TI_DP83869_H + +/* PHY CTRL bits */ +#define DP83869_PHYCR_FIFO_DEPTH_3_B_NIB 0x00 +#define DP83869_PHYCR_FIFO_DEPTH_4_B_NIB 0x01 +#define DP83869_PHYCR_FIFO_DEPTH_6_B_NIB 0x02 +#define DP83869_PHYCR_FIFO_DEPTH_8_B_NIB 0x03 + +/* RGMIIDCTL internal delay for rx and tx */ +#define DP83869_RGMIIDCTL_250_PS 0x0 +#define DP83869_RGMIIDCTL_500_PS 0x1 +#define DP83869_RGMIIDCTL_750_PS 0x2 +#define DP83869_RGMIIDCTL_1_NS 0x3 +#define DP83869_RGMIIDCTL_1_25_NS 0x4 +#define DP83869_RGMIIDCTL_1_50_NS 0x5 +#define DP83869_RGMIIDCTL_1_75_NS 0x6 +#define DP83869_RGMIIDCTL_2_00_NS 0x7 +#define DP83869_RGMIIDCTL_2_25_NS 0x8 +#define DP83869_RGMIIDCTL_2_50_NS 0x9 +#define DP83869_RGMIIDCTL_2_75_NS 0xa +#define DP83869_RGMIIDCTL_3_00_NS 0xb +#define DP83869_RGMIIDCTL_3_25_NS 0xc +#define DP83869_RGMIIDCTL_3_50_NS 0xd +#define DP83869_RGMIIDCTL_3_75_NS 0xe +#define DP83869_RGMIIDCTL_4_00_NS 0xf + +/* IO_MUX_CFG - Clock output selection */ +#define DP83869_CLK_O_SEL_CHN_A_RCLK 0x0 +#define DP83869_CLK_O_SEL_CHN_B_RCLK 0x1 +#define DP83869_CLK_O_SEL_CHN_C_RCLK 0x2 +#define DP83869_CLK_O_SEL_CHN_D_RCLK 0x3 +#define DP83869_CLK_O_SEL_CHN_A_RCLK_DIV5 0x4 +#define DP83869_CLK_O_SEL_CHN_B_RCLK_DIV5 0x5 +#define DP83869_CLK_O_SEL_CHN_C_RCLK_DIV5 0x6 +#define DP83869_CLK_O_SEL_CHN_D_RCLK_DIV5 0x7 +#define DP83869_CLK_O_SEL_CHN_A_TCLK 0x8 +#define DP83869_CLK_O_SEL_CHN_B_TCLK 0x9 +#define DP83869_CLK_O_SEL_CHN_C_TCLK 0xA +#define DP83869_CLK_O_SEL_CHN_D_TCLK 0xB +#define DP83869_CLK_O_SEL_REF_CLK 0xC +/* Special flag to indicate clock should be off */ +#define DP83869_CLK_O_SEL_OFF 0xFFFFFFFF + +/* OPMODE - Operation mode */ +#define DP83869_RGMII_COPPER_ETHERNET 0x00 +#define DP83869_RGMII_1000_BASE 0x01 +#define DP83869_RGMII_100_BASE 0x02 +#define DP83869_RGMII_SGMII_BRIDGE 0x03 +#define DP83869_1000M_MEDIA_CONVERT 0x04 +#define DP83869_100M_MEDIA_CONVERT 0x05 +#define DP83869_SGMII_COPPER_ETHERNET 0x06 + +#endif -- 2.33.1