Other Parts Discussed in Thread: ETHERNET-SW, DP83TG720EVM-MC,
Hi Team,
This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
Hi Team,
Hi Mark,
Has customer looked at Ethernet-SW page? There is a link to DP83TG720's driver there.
Sincerely,
Gerome
Hi Gerome,
Mark forwarded us this link before. It is a driver file set for this PHY in Linux kernel. We are looking for support to boot up this PHY in uboot. Such as a uboot specific driver file, instructions for necessary configuration changes, etc.
Thanks,
Ziran
Gerome,
Back to the dp83tg720 drivers for Linux kernel, we have patched the driver files in the repository link you sent above, into our Yocto Linux build. We can have the driver built-in or loaded as an LKM. When loaded as LKM, we got these reasonable messages:
root@s32r45evb:~# modinfo dp83tg720
Hi Ziran,
Please see attached.
// SPDX-License-Identifier: GPL-2.0-only /* Driver for the Texas Instruments DP83TG720 PHY * Copyright (C) 2020 Texas Instruments Incorporated - http://www.ti.com/ */ #include <linux/ethtool.h> #include <linux/etherdevice.h> #include <linux/kernel.h> #include <linux/mii.h> #include <linux/module.h> #include <linux/phy.h> #include <linux/netdevice.h> #define DP83TG720ES1_PHY_ID 0x2000a280 #define DP83TG720ES2_PHY_ID 0x2000a281 #define DP83TG720CS_1_0_PHY_ID 0x2000a283 #define DP83TG720CS_1_1_PHY_ID 0x2000a284 #define DP83TG721CS_1_0_PHY_ID 0x2000a290 #define DP83720_DEVADDR 0x1f #define DP83720_DEVADDR_MMD1 0x1 #define MII_DP83720_INT_STAT1 0x12 #define MII_DP83720_INT_STAT2 0x13 #define MII_DP83720_INT_STAT3 0x18 #define MII_DP83720_RESET_CTRL 0x1f #define DP83720_HW_RESET BIT(15) #define DP83720_SW_RESET BIT(14) #define DP83720_STRAP 0x45d #define DP83720_SGMII_CTRL 0x608 #define SGMII_CONFIG_VAL 0x027B /* INT_STAT1 bits */ #define DP83720_ANEG_COMPLETE_INT_EN BIT(2) #define DP83720_ESD_EVENT_INT_EN BIT(3) #define DP83720_LINK_STAT_INT_EN BIT(5) #define DP83720_ENERGY_DET_INT_EN BIT(6) #define DP83720_LINK_QUAL_INT_EN BIT(7) /* INT_STAT2 bits */ #define DP83720_SLEEP_MODE_INT_EN BIT(2) #define DP83720_OVERTEMP_INT_EN BIT(3) #define DP83720_OVERVOLTAGE_INT_EN BIT(6) #define DP83720_UNDERVOLTAGE_INT_EN BIT(7) /* INT_STAT3 bits */ #define DP83720_LPS_INT_EN BIT(0) #define DP83720_WAKE_REQ_EN BIT(1) #define DP83720_NO_FRAME_INT_EN BIT(2) #define DP83720_POR_DONE_INT_EN BIT(3) /* SGMII CTRL bits */ #define DP83720_SGMII_AUTO_NEG_EN BIT(0) #define DP83720_SGMII_EN BIT(9) /* Strap bits */ #define DP83720_MASTER_MODE BIT(5) #define DP83720_RGMII_IS_EN BIT(12) #define DP83720_SGMII_IS_EN BIT(13) #define DP83720_RX_SHIFT_EN BIT(14) #define DP83720_TX_SHIFT_EN BIT(15) /* RGMII ID CTRL */ #define DP83720_RGMII_ID_CTRL 0x602 #define DP83720_RX_CLK_SHIFT BIT(1) #define DP83720_TX_CLK_SHIFT BIT(0) enum dp83720_chip_type { DP83720_ES1, DP83720_ES2, DP83720_CS1, DP83720_CS1_1, DP83721_CS1, }; struct dp83720_init_reg { int reg; int val; }; static const struct dp83720_init_reg dp83720_es1_init[] = { {0x182, 0x3000}, {0x56a, 0xfc5}, {0x510, 0x2d51}, {0x408, 0x400}, {0x409, 0x2b}, {0x509, 0x4c04}, {0x8a1, 0xbff}, {0x802, 0x422}, {0x853, 0x632}, {0x824, 0x15e0}, {0x86a, 0x106}, {0x852, 0x3261}, {0x851, 0x5141}, {0x852, 0x327a}, {0x851, 0x6652}, {0x405, 0x1a0}, {0x423, 0x2}, {0x422, 0x0}, {0x420, 0x5510}, {0x421, 0x4077}, {0x412, 0x10}, {0x40f, 0x10}, {0x85d, 0x6405}, {0x894, 0x5557}, {0x892, 0x1b0}, {0x877, 0x55}, {0x80b, 0x16}, {0x864, 0x1fd0}, {0x865, 0xa}, }; static const struct dp83720_init_reg dp83720_es2_master_init[] = { {0x408, 0x580}, {0x409, 0x2a}, {0x8a1, 0xbff}, {0x802, 0x422}, {0x840, 0x4120}, {0x841, 0x6151}, {0x8a3, 0x24e9}, {0x800, 0x2090}, {0x864, 0x1fd0}, {0x865, 0x2}, {0x405, 0x6800}, {0x420, 0x3310}, {0x412, 0x10}, {0x40f, 0xe4ce}, {0x844, 0x3f10}, {0x8a0, 0x1e7}, {0x843, 0x327a}, {0x842, 0x6652}, {0x50b, 0x7e7c}, {0x56a, 0x7f41}, {0x56b, 0xffb4}, {0x813, 0x3fa0}, {0x88d, 0x3fa0}, {0x899, 0x3fa0}, }; static const struct dp83720_init_reg dp83720_es2_slave_init[] = { {0x408, 0x580}, {0x409, 0x2a}, {0x8a1, 0xbff}, {0x802, 0x422}, {0x853, 0x632}, {0x824, 0x15e0}, {0x86a, 0x106}, {0x852, 0x327a}, {0x851, 0x6652}, {0x405, 0x6800}, {0x420, 0x3310}, {0x412, 0x10}, {0x40f, 0x10}, {0x85d, 0x6405}, {0x894, 0x5057}, {0x892, 0x1b0}, {0x877, 0x55}, {0x80b, 0x16}, {0x864, 0x1fd0}, {0x865, 0x2}, {0x50b, 0x7e7c}, {0x56a, 0x7f41}, {0x56c, 0xffb4}, {0x813, 0x3fa0}, {0x88d, 0x3fa0}, {0x899, 0x3fa0}, }; static const struct dp83720_init_reg dp83720_cs1_master_init[] = { {0x408, 0x580}, {0x409, 0x2a}, {0x8a1, 0xbff}, {0x802, 0x422}, {0x864, 0x1fd0}, {0x865, 0x2}, {0x8a3, 0x24e9}, {0x800, 0x2090}, {0x840, 0x4120}, {0x841, 0x6151}, {0x8a0, 0x01e7}, {0x879, 0xe4ce}, {0x89f, 0x1}, {0x844, 0x3f10}, {0x843, 0x327a}, {0x842, 0x6652}, {0x8a8, 0xe080}, {0x8a9, 0x3f0}, {0x88d, 0x3fa0}, {0x889, 0x3fa0}, {0x50b, 0x7e7c}, {0x56a, 0x5f41}, {0x56b, 0xffb4}, {0x56c, 0xffb4}, {0x573, 0x1}, }; static const struct dp83720_init_reg dp83720_cs1_slave_init[] = { {0x408, 0x580}, {0x409, 0x2a}, {0x8a1, 0xbff}, {0x802, 0x422}, {0x864, 0x1fd0}, {0x865, 0x2}, {0x853, 0x632}, {0x824, 0x15e0}, {0x86a, 0x106}, {0x894, 0x5057}, {0x85d, 0x6405}, {0x892, 0x1b0}, {0x852, 0x327a}, {0x851, 0x6652}, {0x877, 0x55}, {0x80b, 0x16}, {0x8a8, 0xe080}, {0x8a9, 0x3f0}, {0x88d, 0x3fa0}, {0x899, 0x3fa0}, {0x1f, 0x4000}, {0x56a, 0x5f41}, {0x56b, 0xffb4}, {0x56c, 0xffb4}, {0x573, 0x1}, }; static const struct dp83720_init_reg dp83720_cs1_1_master_init[] = { {0x405, 0x5800}, {0x8ad, 0x3c51}, {0x894, 0x5df7}, {0x8a0, 0x9e7}, {0x8c0, 0x4000}, {0x814, 0x4800}, {0x80d, 0x2ebf}, {0x8c1, 0xb00}, {0x87d, 0x001}, {0x82e, 0x000}, {0x837, 0x0f4}, {0x8be, 0x200}, {0x8c5, 0x4000}, {0x8c7, 0x2000}, {0x8b3, 0x05a}, {0x8b4, 0x05a}, {0x8b0, 0x202}, {0x8b5, 0x0ea}, {0x8ba, 0x2828}, {0x8bb, 0x6828}, {0x8bc, 0x028}, {0x8bf, 0x000}, {0x8b1, 0x014}, {0x8b2, 0x008}, {0x8ec, 0x000}, {0x8c8, 0x003}, {0x8be, 0x201}, {0x18c, 0x001}, }; static const struct dp83720_init_reg dp83720_cs1_1_slave_init[] = { {0x894, 0x5df7}, {0x56a, 0x5f40}, {0x405, 0x5800}, {0x8ad, 0x3c51}, {0x894, 0x5df7}, {0x8a0, 0x9e7}, {0x8c0, 0x4000}, {0x814, 0x4800}, {0x80d, 0x2ebf}, {0x8c1, 0xb00}, {0x87d, 0x001}, {0x82e, 0x000}, {0x837, 0x0f4}, {0x8be, 0x200}, {0x8c5, 0x4000}, {0x8c7, 0x2000}, {0x8b3, 0x05a}, {0x8b4, 0x05a}, {0x8b0, 0x202}, {0x8b5, 0x0ea}, {0x8ba, 0x2828}, {0x8bb, 0x6828}, {0x8bc, 0x028}, {0x8bf, 0x000}, {0x8b1, 0x014}, {0x8b2, 0x008}, {0x8ec, 0x000}, {0x8c8, 0x003}, {0x8be, 0x201}, {0x56a, 0x5f40}, {0x18c, 0x001}, }; static const struct dp83720_init_reg dp83721_cs1_master_init[] = { {0x001F,0x8000}, {0x0573,0x0801}, {0x0834,0xC001}, {0x0405,0x6C00}, {0x08AD,0x3C51}, {0x0894,0x5DF7}, {0x08A0,0x09E7}, {0x08C0,0x4000}, {0x0814,0x4800}, {0x080D,0x2EBF}, {0x08C1,0x0B00}, {0x087D,0x0001}, {0x082E,0x0000}, {0x0837,0x00F8}, {0x08BE,0x0200}, {0x08C5,0x4000}, {0x08C7,0x2000}, {0x08B3,0x005A}, {0x08B4,0x005A}, {0x08B0,0x0202}, {0x08B5,0x00EA}, {0x08BA,0x2828}, {0x08BB,0x6828}, {0x08BC,0x0028}, {0x08BF,0x0000}, {0x08B1,0x0014}, {0x08B2,0x0008}, {0x08EC,0x0000}, {0x08FC,0x0091}, {0x08BE,0x0201}, {0x0335,0x0010}, {0x0336,0x0009}, {0x0337,0x0208}, {0x0338,0x0208}, {0x0339,0x02CB}, {0x033A,0x0208}, {0x033B,0x0109}, {0x0418,0x0380}, {0x0420,0xFF10}, {0x0421,0x4033}, {0x0422,0x0800}, {0x0423,0x0002}, {0x0484,0x0003}, {0x055D,0x0008}, {0x042B,0x0018}, {0x087C,0x0080}, {0x08C1,0x0900}, {0x08fc,0x4091}, {0x0881,0x5146}, {0x08be,0x02a1}, {0x0867,0x9999}, {0x0869,0x9666}, {0x086a,0x0009}, {0x0822,0x11e1}, {0x08f9,0x1f11}, {0x08a3,0x24e8}, {0x018C,0x0001}, {0x001F,0x4000}, {0x0573,0x0001}, {0x056A,0x5F41}, }; static const struct dp83720_init_reg dp83721_cs1_slave_init[] = { {0x405, 0x6C00}, {0x8ad, 0x3c51}, {0x894, 0x5df7}, {0x8a0, 0x9e7}, {0x8c0, 0x4000}, {0x814, 0x4800}, {0x80d, 0x2ebf}, {0x8c1, 0xb00}, {0x87d, 0x001}, {0x82e, 0x000}, {0x837, 0x0f4}, {0x8be, 0x200}, {0x8c5, 0x4000}, {0x8c7, 0x2000}, {0x8b3, 0x05a}, {0x8b4, 0x05a}, {0x8b0, 0x202}, {0x8b5, 0x0ea}, {0x8ba, 0x2828}, {0x8bb, 0x6828}, {0x8bc, 0x028}, {0x8bf, 0x000}, {0x8b1, 0x014}, {0x8b2, 0x008}, {0x8ec, 0x000}, {0x8c8, 0x003}, {0x8be, 0x201}, {0x56a, 0x5f40}, {0x18c, 0x001}, }; struct dp83720_private { int chip; bool is_master; bool is_rgmii; bool is_sgmii; bool rx_shift; bool tx_shift; }; #if 0 static irqreturn_t dp83720_handle_interrupt(struct phy_device *phydev) { int irq_status; irq_status = phy_read(phydev, MII_DP83720_INT_STAT1); if (irq_status < 0) { phy_error(phydev); return IRQ_NONE; } if (irq_status & ((irq_status & GENMASK(7, 0)) << 8)) goto trigger_machine; irq_status = phy_read(phydev, MII_DP83720_INT_STAT2); if (irq_status < 0) { phy_error(phydev); return IRQ_NONE; } if (irq_status & ((irq_status & GENMASK(7, 0)) << 8)) goto trigger_machine; irq_status = phy_read(phydev, MII_DP83720_INT_STAT3); if (irq_status < 0) { phy_error(phydev); return IRQ_NONE; } if (irq_status & ((irq_status & GENMASK(7, 0)) << 8)) goto trigger_machine; return IRQ_NONE; trigger_machine: phy_trigger_machine(phydev); return IRQ_HANDLED; } #endif static int dp83720_config_intr(struct phy_device *phydev) { int misr_status, ret; if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { misr_status = phy_read(phydev, MII_DP83720_INT_STAT1); if (misr_status < 0) return misr_status; misr_status |= (DP83720_ANEG_COMPLETE_INT_EN | DP83720_ESD_EVENT_INT_EN | DP83720_LINK_STAT_INT_EN | DP83720_ENERGY_DET_INT_EN | DP83720_LINK_QUAL_INT_EN); ret = phy_write(phydev, MII_DP83720_INT_STAT1, misr_status); if (ret < 0) return ret; misr_status = phy_read(phydev, MII_DP83720_INT_STAT2); if (misr_status < 0) return misr_status; misr_status |= (DP83720_SLEEP_MODE_INT_EN | DP83720_OVERTEMP_INT_EN | DP83720_OVERVOLTAGE_INT_EN | DP83720_UNDERVOLTAGE_INT_EN); ret = phy_write(phydev, MII_DP83720_INT_STAT2, misr_status); if (ret < 0) return ret; misr_status = phy_read(phydev, MII_DP83720_INT_STAT3); if (misr_status < 0) return misr_status; misr_status |= (DP83720_LPS_INT_EN | DP83720_WAKE_REQ_EN | DP83720_NO_FRAME_INT_EN | DP83720_POR_DONE_INT_EN); ret = phy_write(phydev, MII_DP83720_INT_STAT3, misr_status); } else { ret = phy_write(phydev, MII_DP83720_INT_STAT1, 0); if (ret < 0) return ret; ret = phy_write(phydev, MII_DP83720_INT_STAT2, 0); if (ret < 0) return ret; ret = phy_write(phydev, MII_DP83720_INT_STAT3, 0); if (ret < 0) return ret; ret = phy_read(phydev, MII_DP83720_INT_STAT1); if (ret < 0) return ret; ret = phy_read(phydev, MII_DP83720_INT_STAT2); if (ret < 0) return ret; ret = phy_read(phydev, MII_DP83720_INT_STAT3); if (ret < 0) return ret; ret = 0; } return ret; } static int dp83720_config_aneg(struct phy_device *phydev) { int value, ret; if (phydev->interface == PHY_INTERFACE_MODE_SGMII) { value = phy_read(phydev, DP83720_SGMII_CTRL); ret = phy_write_mmd(phydev, DP83720_DEVADDR, DP83720_SGMII_CTRL, SGMII_CONFIG_VAL); if (ret < 0) return ret; } return genphy_config_aneg(phydev); } static int dp83720_read_straps(struct phy_device *phydev) { struct dp83720_private *dp83720 = phydev->priv; int strap; strap = phy_read_mmd(phydev, DP83720_DEVADDR, DP83720_STRAP); if (strap < 0) return strap; if (strap & DP83720_MASTER_MODE) dp83720->is_master = true; if (strap & DP83720_RGMII_IS_EN) dp83720->is_rgmii = true; if (strap & DP83720_SGMII_IS_EN) dp83720->is_sgmii = true; if (strap & DP83720_RX_SHIFT_EN) dp83720->rx_shift = true; if (strap & DP83720_TX_SHIFT_EN) dp83720->tx_shift = true; return 0; }; static int dp83720_reset(struct phy_device *phydev, bool hw_reset) { int ret; if (hw_reset) ret = phy_write_mmd(phydev, DP83720_DEVADDR, MII_DP83720_RESET_CTRL, DP83720_HW_RESET); else ret = phy_write_mmd(phydev, DP83720_DEVADDR, MII_DP83720_RESET_CTRL, DP83720_SW_RESET); if (ret) return ret; mdelay(100); return 0; } static int dp83720_phy_reset(struct phy_device *phydev) { int ret; ret = dp83720_reset(phydev, false); if (ret) return ret; ret = dp83720_read_straps(phydev); if (ret) return ret; return 0; } static int dp83720_write_seq(struct phy_device *phydev, const struct dp83720_init_reg *init_data, int size) { int ret; int i; for (i = 0; i < size; i++) { ret = phy_write_mmd(phydev, DP83720_DEVADDR, init_data[i].reg, init_data[i].val); if (ret) return ret; } return 0; } static int dp83720_chip_init(struct phy_device *phydev) { struct dp83720_private *dp83720 = phydev->priv; int ret; ret = dp83720_reset(phydev, true); if (ret) return ret; phydev->autoneg = AUTONEG_DISABLE; phydev->speed = SPEED_1000; phydev->duplex = DUPLEX_FULL; linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, phydev->supported); if (dp83720->chip == DP83720_CS1 && dp83720->is_master) { ret = phy_write_mmd(phydev, DP83720_DEVADDR, MII_BMSR, 0x940); if (ret) return ret; ret = phy_write_mmd(phydev, DP83720_DEVADDR, MII_BMSR, 0x140); if (ret) return ret; } if (dp83720->is_master) ret = phy_write_mmd(phydev, DP83720_DEVADDR_MMD1, 0x0834, 0xc001); else ret = phy_write_mmd(phydev, DP83720_DEVADDR_MMD1, 0x0834, 0x8001); if (ret) return ret; switch (dp83720->chip) { case DP83720_ES1: ret = dp83720_write_seq(phydev, dp83720_es1_init, ARRAY_SIZE(dp83720_es1_init)); break; case DP83720_ES2: if (dp83720->is_master) ret = dp83720_write_seq(phydev, dp83720_es2_master_init, ARRAY_SIZE(dp83720_es2_master_init)); else ret = dp83720_write_seq(phydev, dp83720_es2_slave_init, ARRAY_SIZE(dp83720_es2_slave_init)); break; case DP83720_CS1: ret = phy_write_mmd(phydev, DP83720_DEVADDR, 0x573, 0x101); if (ret) return ret; if (dp83720->is_master) ret = dp83720_write_seq(phydev, dp83720_cs1_master_init, ARRAY_SIZE(dp83720_cs1_master_init)); else ret = dp83720_write_seq(phydev, dp83720_cs1_slave_init, ARRAY_SIZE(dp83720_cs1_slave_init)); break; case DP83720_CS1_1: ret = phy_write_mmd(phydev, DP83720_DEVADDR, 0x573, 0x101); if (ret) return ret; if (dp83720->is_master) ret = dp83720_write_seq(phydev, dp83720_cs1_1_master_init, ARRAY_SIZE(dp83720_cs1_1_master_init)); else ret = dp83720_write_seq(phydev, dp83720_cs1_1_slave_init, ARRAY_SIZE(dp83720_cs1_1_slave_init)); ret = dp83720_reset(phydev, false); ret = phy_write_mmd(phydev, DP83720_DEVADDR, 0x573, 0x001); if (ret) return ret; return phy_write_mmd(phydev, DP83720_DEVADDR, 0x56a, 0x5f41); case DP83721_CS1: ret = phy_write_mmd(phydev, DP83720_DEVADDR, 0x573, 0x101); if (ret) return ret; if (dp83720->is_master) ret = dp83720_write_seq(phydev, dp83721_cs1_master_init, ARRAY_SIZE(dp83721_cs1_master_init)); else ret = dp83720_write_seq(phydev, dp83721_cs1_slave_init, ARRAY_SIZE(dp83721_cs1_slave_init)); ret = dp83720_reset(phydev, false); ret = phy_write_mmd(phydev, DP83720_DEVADDR, 0x573, 0x001); if (ret) return ret; return phy_write_mmd(phydev, DP83720_DEVADDR, 0x56a, 0x5f41); default: return -EINVAL; }; if (ret) return ret; /* Enable the PHY */ ret = phy_write_mmd(phydev, DP83720_DEVADDR, 0x18c, 0x1); if (ret) return ret; mdelay(10); /* Do a software reset to restart the PHY with the updated values */ return dp83720_reset(phydev, false); } static int dp83720_config_init(struct phy_device *phydev) { struct device *dev = &phydev->mdio.dev; s32 rx_int_delay; s32 tx_int_delay; int rgmii_delay; int value, ret; ret = dp83720_chip_init(phydev); if (ret) return ret; if (phy_interface_is_rgmii(phydev)) { rx_int_delay = phy_get_internal_delay(phydev, dev, NULL, 0, true); if (rx_int_delay <= 0) rgmii_delay = 0; else rgmii_delay = DP83720_RX_CLK_SHIFT; tx_int_delay = phy_get_internal_delay(phydev, dev, NULL, 0, false); if (tx_int_delay <= 0) rgmii_delay &= ~DP83720_TX_CLK_SHIFT; else rgmii_delay |= DP83720_TX_CLK_SHIFT; if (rgmii_delay) { ret = phy_set_bits_mmd(phydev, DP83720_DEVADDR_MMD1, DP83720_RGMII_ID_CTRL, rgmii_delay); if (ret) return ret; } } value = phy_read_mmd(phydev, DP83720_DEVADDR, DP83720_SGMII_CTRL); if (value < 0) return value; if (phydev->interface == PHY_INTERFACE_MODE_SGMII) value |= DP83720_SGMII_EN; else value &= ~DP83720_SGMII_EN; ret = phy_write_mmd(phydev, DP83720_DEVADDR, DP83720_SGMII_CTRL, value); if (ret < 0) return ret; return 0; } static int dp83720_probe(struct phy_device *phydev) { struct dp83720_private *dp83720; int ret; dp83720 = devm_kzalloc(&phydev->mdio.dev, sizeof(*dp83720), GFP_KERNEL); if (!dp83720) return -ENOMEM; phydev->priv = dp83720; ret = dp83720_read_straps(phydev); if (ret) return ret; switch (phydev->phy_id) { case DP83TG720ES1_PHY_ID: dp83720->chip = DP83720_ES1; break; case DP83TG720ES2_PHY_ID: dp83720->chip = DP83720_ES2; break; case DP83TG720CS_1_0_PHY_ID: dp83720->chip = DP83720_CS1; break; case DP83TG720CS_1_1_PHY_ID: dp83720->chip = DP83720_CS1_1; break; case DP83TG721CS_1_0_PHY_ID: dp83720->chip = DP83721_CS1; break; default: return -EINVAL; }; return dp83720_config_init(phydev); } #define DP83720_PHY_DRIVER(_id, _name) \ { \ PHY_ID_MATCH_EXACT(_id), \ .name = (_name), \ .probe = dp83720_probe, \ /* PHY_GBIT_FEATURES */ \ .soft_reset = dp83720_phy_reset, \ .config_init = dp83720_config_init, \ .config_aneg = dp83720_config_aneg, \ /*if 0 \ .handle_interrupt = dp83720_handle_interrupt, \ #endif */ \ .config_intr = dp83720_config_intr, \ .suspend = genphy_suspend, \ .resume = genphy_resume, \ } static struct phy_driver dp83720_driver[] = { DP83720_PHY_DRIVER(DP83TG720ES1_PHY_ID, "TI DP83TG720ES1"), DP83720_PHY_DRIVER(DP83TG720ES2_PHY_ID, "TI DP83TG720ES2"), DP83720_PHY_DRIVER(DP83TG720CS_1_0_PHY_ID, "TI DP83TG720CS1.0"), DP83720_PHY_DRIVER(DP83TG720CS_1_1_PHY_ID, "TI DP83TG720CS1.1"), DP83720_PHY_DRIVER(DP83TG721CS_1_0_PHY_ID, "TI DP83TG721CS1.0"), }; module_phy_driver(dp83720_driver); static struct mdio_device_id __maybe_unused dp83720_tbl[] = { { PHY_ID_MATCH_EXACT(DP83TG720ES1_PHY_ID) }, { PHY_ID_MATCH_EXACT(DP83TG720ES2_PHY_ID) }, { PHY_ID_MATCH_EXACT(DP83TG720CS_1_0_PHY_ID) }, { PHY_ID_MATCH_EXACT(DP83TG720CS_1_1_PHY_ID) }, { PHY_ID_MATCH_EXACT(DP83TG721CS_1_0_PHY_ID) }, { }, }; MODULE_DEVICE_TABLE(mdio, dp83720_tbl); MODULE_DESCRIPTION("Texas Instruments DP83TG720 PHY driver"); MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com"); MODULE_LICENSE("GPL");
Sincerely,
Gerome
Hey Gerome,
Thanks for the quick update! So this is a new driver file that we should swap in to replace the old one?
Ziran
Hi Ziran,
This is correct. We will look to publish this as soon as we can.
Sincerely,
Gerome
Gerome,
The new driver file did the trick! Now driver is loaded and link is up as shown in Linux kernel message.
Now I am facing a new problem. We link this T1 PHY up with a TI DP83TG720EVM-MC media converter, then to a laptop with a 1000Based-T (RJ45) NIC. I set both IP addresses in the same LAN, which is 192.168.56.11 on the T1 PHY, then 192.168.56.6 on the laptop NIC.
I can't ping between them. When I ping from T1 to the laptop, I can see the D2 LED on the EVM-MC blinking, so T1 is sending packets out. However, the laptop cannot receive them or ping back for some reason.
Any suggestions?
Ziran
Hello,
It is great news that the new driver file worked. Could you please try reading PHY registers 0x1, 0x602, 0x430? Please be aware that the last two registers are extended registers and thus should be accessed in a particular manner as described in datasheet section 7.4.11. Also is LED0 (either D4 or D3) on?
Can you also provide a block diagram of the setup for my understanding?
Sincerely,
Gerome
Can see the instructions in Sec. 7.4.11. What utility tool in Linux should I use to read these 3 PHY registers?
You meant LED0 on the EVM media converter, correct? It is D4, and it is on (tg720 PHY set as Slave).
The connection is as the following:
Our DSP board with TG720 PHY and running Linux --- thru a T1 cable --- DP83TG720EVM Media Converter --- thru a CAT5/6 cable --- A laptop with a common RJ45 ethernet NIC
Please let me know if this is sufficient or you need more detailed diagram.
Ziran
Hi Ziran,
This could lead to an issue on the custom board. I would recommend trying to test ping between 2x EVMs and PCs to rule out the EVM.
Sincerely,
Gerome
okay -- that's a good idea. About checking register values on the booted TG720 PHY, do you have recommendations of Linux commands or utility tools, or just a script, to read these registers? I think it is important that we can do that so to verify the hardware states.
Thanks,
Ziran
Gerome,
Thanks. Got phytool working, can read the following register values of T1 PHY in Linux:
Register Value
0x1 0x0141
0x2 0x2000
0x3 0xa284
0x602 0x2000
0x430 0x0004
Please see if there is anything wrong.
Ziran
I forgot you mentioned that 0x602 and 0x430 need extended register space access. I read Section 7.4.11, however couldn't quite follow it. Could you send me an example procedure, for example, for reading from 0x602?
Ziran
Ziran,
Could you try and made 0x602 = 0x0 and retry ping?
Also, so you are pinging from DSP to laptop, not other way around? Wanting to understand the flow to see where the signal could be lost.
Sincerely,
Gerome
Hey Gerome,
I set 0x602 = 0x0. It didn't bring a noticeable change. Still cannot ping from DSP board (with this TG720 PHY) to host PC. During this pinging, I can see the D2 LED of the media converter (in between DSP and host PC) blinking, because T1 PHY is sending packets. I can also see the orange LED of the RJ45 on the media converter board blinking roughly in sync with the D2 LED. However, the ping is not thru, with the following error message:
From 192.168.56.11 icmp_seq=73 Destination Host Unreachable
From 192.168.56.11 icmp_seq=74 Destination Host Unreachable
...
I also tried pinging from host PC to the DSP board. Can also see D2 and RJ45 LED indicators on the media converter in sync. However, ping is not thru.
Pinging 192.168.56.11 from 192.168.56.6 with 32 bytes of data:
Reply from 192.168.56.6: Destination host unreachable.
Reply from 192.168.56.6: Destination host unreachable.
......
Ziran
Hi Ziran,
At this point, it may be necessary to do throughput testing to have better idea of where the signal is getting corrupted.
For DP83TG720, the necessary loopbacks are Reverse Loopback to redirect traffic from MDI back out to MDI, while Analog/Digital/MII loopback will be sufficient for MII traffic rerouting. Using these configurations will isolate where the issue lies.
Sincerely,
Gerome
I just tried connecting two EVM media converters (MC) back to back. The connection is the following:
Host PC1 RJ45 --- RJ45/EVM MC1/T1 --- T1 cable --- T1/EVM MC2/RJ45 --- Host PC2 RJ45
I cannot ping PC1 to PC2, or PC2 to PC1. This time, there is no TG720 activity indications on either MC. Their D2s and D4s are not lit.
Any conclusion from this observation? Does this MC work right out of box, or need some configuration first?
Ziran
Ziran,
Please check the master/slave configuration on the EVM. I would imagine they are both either master/master or slave/slave and thus do not have link.
Sincerely,
Gerome
So the EVM's TG720 should be one Master and the other one Slave, correct? I can just use the J2 jumper on the board to set them?
Cerome,
Did the M/S change and now Host PC1 and PC2 can ping each other just fine. So the EVM MC appears to be working.
Back to the single MC connection, from all the indicator lights (T1 on the MC, RJ45s on the MC and on the host PC) it seems there is a link. If I disconnect/connect this link, the Linux kernel message also responds and says Link is down or up. It is just I can't ping thru.
Could you elaborate on the throughput testing? I don't know how it is configured or run just from your description.
Ziran
Ziran,
This register should either be 0x8001 or 0xC001. The fact that it is reading 0x0 is a concern. Regarding throughput, I would want to focus in on your custom board. If PHY is getting link, issue may be on MAC side. Are you running RGMII or SGMII? Are you ensuring that traces are length matched to 5 mils if SGMII, or if RGMII, signals have been probed to obey setup and hold time?
For throughput testing, the idea is that the SoC would be able to generate and check incoming packets. If the packets are different, then it can detect that discrepancy. PHY would loopback to isolate signal chain via various loopbacks to assist with this.
Sincerely,
Gerome
Hi Gerome,
How can we further debug this register error, and whatever it indicates? Can check other register values and send to you.
We are running RGMII. 'RGMII-id" mode, and initial physical pins based configuration on this PHY is MAC[2:0] = 101 = RGMII TX SHIFT. We haven't probed the signal to obey setup and hold time. Is there a more detailed description of this signal probe procedure that we can follow?
Ziran
Ziran,
Please be aware that master/slave configuration is governed as register 0x1834. So the MMID for this is 0x1 while the register within that space is 0x834. This is opposed to MMID 0x1F like most of our PHY registers.
For RGMII probing, just try to probe at input pins of MAC and PHY to see what is the signal looking like at the input and understand the skews between data and clock.
Sincerely,
Gerome
Gerome,
Correct~ that one register is on MMD1, not 1f. Now I read its value to be 0xC001. So it is set as Master, which agrees with the tg720 on the media converter set as Slave. I think this PHY on our DSP board needs to be set as Slave. What should I do?
Ziran
Ziran,
Reg 0x45D is a strap register that is read only. This will only yield the values which PHY has read to understand what it has strapped into.
You will need to find the analogous registers to the strap fields that are writable to change to the appropriate value. As you are talking master/slave, you will need to change 0x1834 to be the appropriate value and the software restart the PHY via Reg 0x1F = 0x4000. Otherwise, you may change the strapping resistor associated with master/slave as per our datasheet.
Sincerely,
Gerome
Gerome,
When pinging from the T1 PHY (192.168.56.11) to the PC (192.168.56.6), the WireShark running on the PC immediately showed the incoming traffic, as seen in the attached screenshot. We can see correct info of both IP addresses and both MAC addresses. And the PC responded right after the ping query. What would this observation suggest?
Also, since this is a point to point connection, do we need a crossover cable in the chain? I am not sure with a TI media converter in the middle, how is the Tx/Rx pairing handled.
Thanks,
Ziran
Ziran,
This looks like ping works right? So this portion of thread would be resolved?
A crossover cable is not needed as PHY is able to do cross-over detection and correction with Auto MDI-X on the standard PHY side of the EVM.
Sincerely,
Gerome
Gerome,
But we still don't have a successful ping. On the PHY side (DSP board running Linux and pinging), the ping says "Destination Host Unreachable" with 100% packet loss. I think the reply packets from host PC back to the PHY didn't go through.
Ziran
Hi Ziran,
Just to refocus the conversation, can you please provide a block diagram detailing the working and non-working scenarios?
Also just to be clear, the T1 PHY at 192.168.56.11 is DP83TG720?
Sincerely,
Gerome
Hi Gerome,
Please find a block diagram attached. Lunewave_block_diagram.pptx
Yes, the TI PHY is a DP83TG720S-Q1 (with PHY ID register value 0x2000a284), and its IP is set to 192.168.56.11.
Please also take a look at our Ethernet schematic, to see if our routing has any problems. 11 ENET_PCIE_ADC_Clock.pdf
Thank you,
Ziran
Ziran,
Focusing on the DSP board PHY, I would advise throwing that PHY into MII loopback and doing a throughput test. This would validate the RGMII connection.
Sincerely,
Gerome
You can see from the schematic, that our strap pins set the PHY address to 0xc, and MAC [2:0] to '101' = RGMII Tx Shift mode, and LED0 and LED1 so Slave and Autonomous modes. However, after booting up in Linux, the strap register 0x45d = 0x916C ('0111 0001 0110 1100'). So this register is getting the PHY address and MAC[2:0] values from hardware correctly. However, you can see the MSB 0111 means the Tx_SHIFT is disabled, and RX_SHIFT, RGMII and SGMII are all enabled, disagreeing with our MAC[2:0] setting. Also the M/S bit (Bit 5) is 1, disagreeing with our LED0 setting.
Do these discrepancies indicate issues?
Ziran
Gerome,
Could you send me some detailed procedure? Honestly the only thing I know about loopback at this moment is 127.0.0.1 is a loopback ip address.
Ziran
Ziran,
It appears the LED circuits look a little funky. If you see Figure 8-17 of SNLS603C, these show the proper way to strap PHY LED pin. You have a configuration where you have D1 and Rcl, but no Rp. It is uncertain if PHY sees a voltage on the node that is high enough to override mode 1 into mode 2.
Regarding shift mode, I believe these correlate. 0x9 = '1001'.
To throw PHY into MII loopback, please use register 0x0[14], as well as restart the PHY with register 0x1F = 0x4000 as best practice whenever making a register change. Figure 8-9 is a close indicator of the signal path I am recommending to try.
Sincerely,
Gerome
Gerome,
Right, 1001 are the correct bits then. M/S bit is still wrong which resonates with your concern on the LED circuits. I will follow up on the MII loopback.
Thanks!
Ziran
Okay -- same here then. Ngoc, can you ping from your board to the PC successfully? Our current issue is our PHY cannot receive any packets. Its Rx packets count is always zero -- so we cannot ping either way.
Gerome, our Linux seems to be setting the gmac0_rx_rgmii clock to 25MHz. This TG720 PHY will run its Rx clock at 125MHz. So this is a mismatch. Do you know how to configure Linux gmac0_rx_rgmii clock rate to 125MHz?
Ziran
Hi Ziran,
Unfortunately, I am not a software expert and cannot help debug this. But from a hardware standpoint, as DP83TG720 is a 1G only device, it seems to be some type of mismatch in the way Linux is seeing the PHY, as there is no physical way for RX_CLK to be 25MHz.
Sincerely,
Gerome
Hi Gerome,
We did some more tests, including loopback tests. Here are the results:
Ziran
Hi Ziran,
It sounds like from these results that the PHY's MAC interface is working properly. Would we consider this thread closed? If there are further questions unrelated, you can open up a new thread so other engineers can also leverage the learnings here.
Sincerely,
Gerome
Hi Gerome and Ngoc,
We finally found a fix for the PHY ping/receiving failure. The rgmii mode Tx and Rx clock shifts are set by writing to the 0x602 register (DP83720_RGMII_ID_CTRL). We noticed that in the dp83tg720.c driver file TI provided, the write function is using a wrong base register to access that extended register space:
if (tx_int_delay <= 0)
rgmii_delay &= ~DP83720_TX_CLK_SHIFT;
else
rgmii_delay |= DP83720_TX_CLK_SHIFT;
if (rgmii_delay) {
ret = phy_set_bits_mmd(phydev, DP83720_DEVADDR_MMD1,
DP83720_RGMII_ID_CTRL,
rgmii_delay);
if (ret)
return ret;
}
DP83720_DEVADDR_MMD1 should be instead DP83720_DEVADDR.
With this change and enabling the rgmii clock shift in the Linux kernel device tree, our PHY is now fully back to life.
Ziran