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.

DP83867IR: Problems with automatic Speed Optimization (downshift) not happening

Part Number: DP83867IR

I am using the TI83867IRRGZ chip for ethernet on our card (connected to an NXP IMX6DL CPU) and having some trouble with automatic downshift from 1gbps to 100mbps when there are only 4 wires (2 pairs, A and B) in the cable.

 

Have had no problem with 8 wires and running 1gbps, but when I have limited the number of wires the chip doesn’t seem to automatically select lower speed.

 

From what I can see (SPEED SELECTION  (bit14-15) in register PHYSTS 0x0011, see below) the MAC/PHY layer detects the missing wires and sets 100mbps speed, however the link layer still advertises 1000mbps and since the link partner also advertise 1000mbps it seems this speed is selected, and no data is transmitted.

 

 

I have this problem for both U-boot and Linux (old release using kernel 4.9). However I patched the dp83867 driver for Linux included in 4.9 with a new read_status function (which I found in the latest Linux driver: github.com/.../dp83867.c) which reads register PHYSTS and manully overrides the set speed:

 

int status = phy_read(phydev, MII_DP83867_PHYSTS);

if (status & DP83867_PHYSTS_1000)

                phydev->speed = SPEED_1000;

else if (status & DP83867_PHYSTS_100)

                phydev->speed = SPEED_100;

else

                phydev->speed = SPEED_10;

 

This worked very well when connecting the card to my PC using a Linksys USB3GIG network adapter, however does not work when connecting with the same cable to a Cisco SG250-08 switch.

There may be additional changes in the newer driver that works around this, and I'm looking into patching more of that, but have to handle my older kernel missing som callback/function hooks used in the newer kernel.

 

 

For both Linux and U-boot forcing 100mbps speed or disabling 1gbps negotiation gives a working 100mbps connection regardless of device on the other end:

 

U-boot (as described in https://community.nxp.com/t5/i-MX-Processors/u-Boot-changing-ethernet-speed-with-i-MX6/td-p/1247947):

mii write 0 0x9 0x0

mii write 0 0x0 0x3300

 

Linux:

ethtool -s eth0 speed 100 duplex full autoneg on

 

 

I feel that if I could set the correct register values for the chip this should function automatically, but I cant seem to find the right configuration.

 

For example I've been trying to enable Speed optimization for 1000baseT mode by setting both SPEED_OPT_ENHANCED_EN (bit8) and SPEED_OPT_EN (bit9) of CFG2 (0x0014) register. But I have never seen SPEED_OPT_STATUS (bit7) of PHYSTS be 1 which I would expect if Speed Optimization is enabled(?), but it always 0.

I've done this either by adding the following to board_phy_config function in my u-boot build:

#define DP83867_CFG2                0x14

#define DP83867_SPEED_OPTIMIZED_EN                           (BIT(6) | BIT(8) | BIT(9))

val = phy_read(phydev, MDIO_DEVAD_NONE, DP83867_CFG2);

val |= DP83867_SPEED_OPTIMIZED_EN;

phy_write(phydev, MDIO_DEVAD_NONE, DP83867_CFG2, val);

 

Or manually using mii tool in the u-boot command line:

mii write 0 0x14 0x2BC7

mii write 0 0x0 0x1340 # retrigger auto-negotiation

 

 

What am I missing or have done wrong?

 

 

 

Register values after initalization (with 4 wires), read using "mii read 0 X" tool in U-boot (with DP83867_SPEED_OPTIMIZED_EN disabled) - connected to Linksys PC adapter:

 

0x00: 1140

0x01: 796D

0x02: 2000

0x03: A231

0x04: 01E1

0x05: CDE1

0x06: 006F

0x07: 2001

0x08: 7001

0x09: 0300

0x0a: 0800

0x0b: 0000

0x0c: 0000

0x0d: 401F

0x0e: 00A8

0x0f: 3000

0x10: 4040

0x11: 7C02

0x12: 0000

0x13: 9CC0

0x14: 29C7

0x15: 0000

0x16: 0000

0x17: 0040

0x18: 6150

0x19: 4444

0x1a: 0002

0x1b: 0000

0x1c: 0000

0x1d: 0000

0x1e: 0002

0x1f: 0000

 

Register values after initalization (with 4 wires), read using "mii read 0 X" tool in U-boot (with DP83867_SPEED_OPTIMIZED_EN enabled) - connected to Linksys PC adapter:

 

0x00: 1140

0x01: 796D

0x02: 2000

0x03: A231

0x04: 01E1

0x05: CDE1

0x06: 006D

0x07: 2001

0x08: 7001

0x09: 0300

0x0a: 0800

0x0b: 0000

0x0c: 0000

0x0d: 401F

0x0e: 00A8

0x0f: 3000

0x10: 4040

0x11: 7F02

0x12: 0000

0x13: 9CC6

0x14: 2BC7

0x15: 0000

0x16: 0000

0x17: 0040

0x18: 6150

0x19: 4444

0x1a: 0002

0x1b: 0000

0x1c: 0000

0x1d: 0000

0x1e: 0002

0x1f: 0000

 

 

U-Boot 2019.07-00018-g20cfbc5354-dirty (Apr 21 2022 - 15:25:58 +0200)

With ethernet section of board file:

 

#define ENET_PAD_CTRL  (PAD_CTL_PUS_100K_UP |                                    \

                PAD_CTL_SPEED_MED | PAD_CTL_DSE_40ohm | PAD_CTL_HYS)

 

static iomux_v3_cfg_t const enet_pads1[] = {

                MX6_PAD_ENET_MDIO__ENET_MDIO                 | MUX_PAD_CTRL(ENET_PAD_CTRL),

                MX6_PAD_ENET_MDC__ENET_MDC                     | MUX_PAD_CTRL(ENET_PAD_CTRL),

                MX6_PAD_RGMII_TXC__RGMII_TXC      | MUX_PAD_CTRL(ENET_PAD_CTRL),

                MX6_PAD_RGMII_TD0__RGMII_TD0     | MUX_PAD_CTRL(ENET_PAD_CTRL),

                MX6_PAD_RGMII_TD1__RGMII_TD1     | MUX_PAD_CTRL(ENET_PAD_CTRL),

                MX6_PAD_RGMII_TD2__RGMII_TD2     | MUX_PAD_CTRL(ENET_PAD_CTRL),

                MX6_PAD_RGMII_TD3__RGMII_TD3     | MUX_PAD_CTRL(ENET_PAD_CTRL),

                MX6_PAD_RGMII_TX_CTL__RGMII_TX_CTL        | MUX_PAD_CTRL(ENET_PAD_CTRL),

                MX6_PAD_ENET_REF_CLK__ENET_TX_CLK         | MUX_PAD_CTRL(ENET_PAD_CTRL),

    MX6_PAD_RGMII_RXC__RGMII_RXC | MUX_PAD_CTRL(ENET_PAD_CTRL),

                MX6_PAD_RGMII_RD0__RGMII_RD0 | MUX_PAD_CTRL(ENET_PAD_CTRL),

                MX6_PAD_RGMII_RD1__RGMII_RD1 | MUX_PAD_CTRL(ENET_PAD_CTRL),

                MX6_PAD_RGMII_RD2__RGMII_RD2 | MUX_PAD_CTRL(ENET_PAD_CTRL),

                MX6_PAD_RGMII_RD3__RGMII_RD3 | MUX_PAD_CTRL(ENET_PAD_CTRL),

    MX6_PAD_RGMII_RX_CTL__RGMII_RX_CTL | MUX_PAD_CTRL(ENET_PAD_CTRL),

                /*  PHY nRST */

                MX6_PAD_SD3_RST__GPIO7_IO08                        | MUX_PAD_CTRL(OUTPUT_40OHM),

};

 

/* Configure eth0 PHY board-specific behavior, called by fec_probe */

int board_phy_config(struct phy_device *phydev)

{

                unsigned short val;

 

                /* TI DP83867 */

                const int devad = 0x001f;

                if (phydev->phy_id == 0x2000a231) {

                               /* Configure register 0x170 for ref CLKOUT */

                               phy_write(phydev, MDIO_DEVAD_NONE, MII_MMD_CTRL, devad);

                               phy_write(phydev, MDIO_DEVAD_NONE, MII_MMD_DATA, 0x0170);

                               phy_write(phydev, MDIO_DEVAD_NONE, MII_MMD_CTRL, devad | MII_MMD_CTRL_NOINCR);

                               val = phy_read(phydev, MDIO_DEVAD_NONE, MII_MMD_DATA);

                               val &= ~0x1f00;

                               val |= 0x0b00; /* chD tx clock*/

//                           val |= 0x0c00; /* Reference clock*/

                               phy_write(phydev, MDIO_DEVAD_NONE, MII_MMD_DATA, val);

                }

 

                if (phydev->drv->config) {

                               phydev->drv->config(phydev);

                }

 

                return 0;

}

 

int board_eth_init(bd_t *bis)

{

                uint32_t base = IMX_FEC_BASE;

                struct mii_dev *bus = NULL;

                struct phy_device *phydev = NULL;

                int ret;

 

    imx_iomux_v3_setup_multiple_pads(enet_pads1, ARRAY_SIZE(enet_pads1));

                gpio_direction_output(IMX_GPIO_NR(7, 8), 1);

 

                mdelay(10);

 

#ifdef CONFIG_FEC_MXC

                bus = fec_get_miibus(base, -1);

                if (!bus)

                               return -EINVAL;

                /* scan phy 0 */

                phydev = phy_find_by_mask(bus, 0x01, PHY_INTERFACE_MODE_RGMII);

                if (!phydev) {

                               ret = -EINVAL;

                               goto free_bus;

                }

                printf("using phy at %d\n", phydev->addr);

                ret  = fec_probe(bus, -1, base, bus, phydev);

                if (ret)

                               goto free_phydev;

#endif

 

 

#ifdef CONFIG_CI_UDC

                /* For otg ethernet*/

                usb_eth_initialize(bis);

#endif

                return 0;

 

free_phydev:

                free(phydev);

free_bus:

                free(bus);

                return ret;

}

 

 Here is the schema for the PHY:

  • Hi Asmund, 

    We have began to look into your query. 

    On an initial look, it does not seem to me like you did anything wrong, and what you have should work. 

    I am not familiar with Linux setup for PHY so I cannot comment on the code, however as far as register writes, you seem to be writing the correct thing.

    Please help me understand, but the bottom line of your issue is the fact the PHY doesn't advertise 100M speed when there is only 4 wires, and nothing is transmitted as a result?

    If the PHY is set in 1G mode, and you remove wires during operation, I am not sure how the PHY would react, what do you have it strapped for?

    Best,

    Alon 

  • Hi Alon,

    Great! Thanks. Slight smile

    I'm thinking if I can get it to work in U-boot which is closer to the bare metal, then I would be able to make it work in Linux.


    As far as I can tell it DOES advertise 10M/100M/1000M (according to the datasheet the RGZ only supports strapping either 10/100/1000 or 100/100 (ANEG_SEL)), LED_1 is strapped to mode1 and register STRAP_STS1 value is 0x0. Also register ANAR has value 0x01E1 indicating that 100BASE-TX and 10BASE-T is advertised.
    So it is more a problem of 1G mode being advertised and selected even though there are only 4 wires.

    I have not attempted to switch between 4 and 8 wire cables during operation yet, only while powered down.

    A similar report is mentioned here https://support.xilinx.com/s/question/0D52E00006hph0iSAA/ti-dp83867-autonegotiation-problem , could this have anything to do with Next Page Support?
    I also see that the according to register ANLPAR bits 10 (PAUSE) and 11 (ASM_DIR), the switch does not advertise support for those while the PC adapter does, if that may have an effect?

  • Hi Asmund,

    I confirmed with the team, the PHY will not be able to detect how many wires are connected, and so if both the PHY and the link partner are advertising 1G, that will be selected.

    What is your application? Cause typically you would strap/ register write the PHY to whatever criteria you want to run it as. 

    Best,

    Alon

  • Hi Alon,

    So what you are saying is that the register PHYSTS bits 14-15 does not report what the PHY/MAC layer speed supported, but rather final speed negotiated including LINK layer?

    I checked the advertised speed by link partner and it seems that my PC (with linksys adapter) DOES somehow detect that the the cable is not able to support 1Gbps and thus does not advertise 1Gbps speed, while the switch advertises 1Gbps regardless of the cable:

    -- Gbps negotiation enabled (default) --
    0x14 (CFG2): 29C7
    0x9 (CFG1): 0300

    4 wire to SWITCH:
    0x11 (PHYSTS): B302 = 1Gbps speed selected!!!
    0xA (STS1): 0x800 = 1Gbps advertised by link partner

    8 wire to SWITCH:
    0x11 (PHYSTS): BC02 = 1Gbps speed selected
    0xA (STS1): 0x3800 = 1Gbps advertised by link partner

    4 wire to PC:
    0x11 (PHYSTS): 7F02 = 100Mbps speed selected
    0xA (STS1): 0x0000 = 1Gbps NOT advertised by link partner

    8 wire to PC:
    0x11 (PHYSTS): AC02 = 1Gbps speed selected
    0xA (STS1): 0x3800 = 1Gbps advertised by link partner


    -- Gbps negotiation disabled and speed optimization enabled --
    0x14 (CFG2): 2BC7
    0x9 (CFG1): 0x0000

    4 wire to SWITCH:
    0x11 (PHYSTS): 7F02 = 100Mbps speed selected
    0xA (STS1): 0x800 = 1Gbps advertised by link partner

    8 wire to SWITCH:
    0x11 (PHYSTS): 7C02 = 100Mbps speed selected
    0xA (STS1): 0x800 = 1Gbps advertised by link partner

    4 wire to PC:
    0x11 (PHYSTS): 7C02 = 100Mbps speed selected
    0xA (STS1): 0x000 = 1Gbps NOT advertised by link partner

    8 wire to PC:
    0x11 (PHYSTS): 7C02 = 100Mbps speed selected
    0xA (STS1): 0x800 = 1Gbps advertised by link partner

    My results looks to match what you are saying that the PHY is not able to detect missing wires and that it is the link partner that makes things work in my setup. And I can't rely on the link partner helping me in the wild, I have no guarantees on what kind of (custom) cabling will be used.

    I wonder why my switch doesn't do the same thing as my PC/Linksys adapter (or maybe Windows somehow?) and not advertise 1gbps on 4 wire cable.

    I'll look into adding functionality to the driver to attempt to send packet to link partner and then downshift manually if there is no response at 1gbps speed.

    Thanks for your help. Slight smile