PHY Initialization Issue on external reset (mcf5223x)

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

PHY Initialization Issue on external reset (mcf5223x)

3,627 Views
ChrisChelmecki
Contributor I
I'm having an issue with the mcf5223x phy not initializing properly after a short reset.  If I hold down the reset button on my mcf5223demo for 3-4 seconds, everything starts up properly.  When I press and release the reset button quickly, every other time I will get no link/activity.  If I try to hold reset for ~1 sec I will get a link/activity, which will then go away and the collision light will go on constantly. It always works in the debugger or after switched off.

I am using the Interniche/Gregori phy initialization code.  Also I tried to reset the phy in software before I initialize it, but this did not seem to affect the problem.

Has anyone seen this issue before/ have any ideas?

Thanks,

Chris

Labels (1)
0 Kudos
6 Replies

853 Views
ericgregori
Contributor I
I tested this with a hub, and did not see an issue.
 
Are you connected directly to a laptop?
 
If so,  it could be that the auto-negotiation state machine in the laptop did not miss a link pulse and never reset it's autonegotioan state machine. As far as it knows, you never unplugged. 
 
Before the reset were you at 10Mbps or 100Mbps?
 
I would like to look into this further.
0 Kudos

853 Views
ChrisChelmecki
Contributor I
We did test it with both a 10Mbit and a 10/100 hub(I believe it was using 100 half duplex).  We also used both the MCF5223Demo board and a custom board that has a mcf52235 on it.  So far the only solution that we have is to introduce a delay after the initialization and enable of the ePhy before we start polling it for a status.  The manual specifies a delay of ~360us, however for us to reliably get the phy starting after a watchdog reset, we had to set the delay up around 2sec.  It seems that before we introduced the delay, the polling loop would time out long before we had the link status. 

Let me know if you have any ideas or would like to have me test anything.

Thanks,

Chris Chelmecki

0 Kudos

853 Views
ChrisChelmecki
Contributor I
Oh, also, it was set up with auto negotiation disabled per the errata for the processor.  I used the ePhy initialization that I believe you posted and head it set up so that it would try to force 100 half duplex, then 10 half duplex.

Chris
0 Kudos

853 Views
Petter_fupp
Contributor I
This seems to be related to my autonegotiation problem. On power-up, I'm able to connect automatically with both 100 and 10 Mbps (100 is tried first). If connected on 100 Mbps, and the PHY link is disconnected (e.g cable removed) and connected to a 10 Mbps router or hub everything is fine. To make this work, a software state machine checks the link state (PHY_R1_LS) and performs "re-initialisation" when required.

But my problem: when connected with 10 Mbps, I'm unable to kick the PHY hardware hard enough to make a 100 Mbps connection (after moving the ethernet cable). Attempts to fully re-initialise PHY and FEC have failed.

It seems like the PHY is unable to connect with 100 Mbps after beeing set up for 10 Mbps. The currently only solution for me is to perform hardware reset of the MCF5223x.
0 Kudos

853 Views
ChrisChelmecki
Contributor I
We're doing the same sort of thing, and it seems to work... sort of.

First of all, on boot we have the big two second delay as noted above..

Assuming that hardware autonegotiation is failing, we will have a software task that runs occasionally check the link and reinitialize the phy if the link is down.. Since we don't know why the link went down, we periodically switch between the two forced speeds until we get a link.  So if I plug the device into a 10Mbps hub on boot, then unplug it after its been initialized, when I plug it back in, it will be unknown whether it's checking for a 10 or 100Mbps link.  So if then plugged into a 10/100 hub, it might still connect at 10Mbps.

Here's our periodic function:

  if(autonegotiation_status <= 0)
   {
      fec_mii_read_b(FEC_PHY0, PHY_REG_PSR, &mii_psr_reg);

      if((mii_psr_reg & 0x0500) == 0x0400)
      {
         autonegotiation_status = 1;
         return;
      }

      if(link_speed == 0)
      {
         if(phy_check_count++ > 800)
         {
            fec_mii_read_b(FEC_PHY0, 1, &mii_cr_reg);

            /* Check link status */
            if((mii_cr_reg & 0x0004) == 0)
            {
               fec_mii_read_b(FEC_PHY0, 0, &mii_cr_reg);
               mii_cr_reg &= ~0x1100; /* Manual half-duplex */
               mii_cr_reg ^= 0x2000; /* Change data rate */
               fec_mii_write_b(FEC_PHY0, 0, mii_cr_reg);
               fec_mii_write_b(FEC_PHY0, 0, (mii_cr_reg|0x0200)); // Force re-negotiate
            }
            phy_check_count = 0;
         }
      }
      else
      {
         phy_check_count = 0;
      }
   }

link_speed is filled in in the ePhy interrupt.

Chris

0 Kudos

853 Views
Petter_fupp
Contributor I
Here is my state machine and initialisation code, to provide more details on my problem:
Code:
void mcf5223x_eth_init_ephy(char use_100_mbps, char negotiate){ uint16 reg0; while(!fec_mii_read(FEC_PHY0, PHY_REG_CR, &reg0)) ; if (use_100_mbps)  reg0 |= PHY_R0_DR; // 100 Mbps else  reg0 &= ~PHY_R0_DR; // 10 Mbps reg0 &= ~PHY_R0_DPLX;  // Half duplex reg0 &= ~PHY_R0_ANE;  // Manual mode  while(!fec_mii_write(FEC_PHY0, PHY_REG_CR, reg0)) ; if (negotiate) {  while(!fec_mii_write(FEC_PHY0, PHY_REG_CR, (reg0|PHY_R0_RAN))) ; }}void mcf5223x_eth_init(char use_100_mbps){ uint16 mymwdata; // Temp variable for MII read/write data fec_mii_init(SYSTEM_CLOCK_MHZ); // Enable EPHY module with PHY clocks MCF_PHY_EPHYCTL0 &= ~(MCF_PHY_EPHYCTL0_EPHYEN);  // Disable ePHY module MCF_PHY_EPHYCTL1 = MCF_PHY_EPHYCTL1_PHYADDR(FEC_PHY0); // Adress is 0 MCF_PHY_EPHYCTL0 &= ~(MCF_PHY_EPHYCTL0_DIS100 | MCF_PHY_EPHYCTL0_DIS10);  MCF_PHY_EPHYCTL0 |= MCF_PHY_EPHYCTL0_ANDIS;  // Disable HW auto-negotiate MCF_PHY_EPHYCTL0 |= MCF_PHY_EPHYCTL0_EPHYEN;  // Enable ePHY module mcf5223x_eth_init_ephy(use_100_mbps, FALSE); // Enable PHY interrupts in Reg 16 (PHY Interrupt Control Register) mymwdata = PHY_R16_ACKIE | PHY_R16_PRIE | PHY_R16_LCIE | PHY_R16_ANIE; mymwdata = mymwdata | PHY_R16_PDFIE | PHY_R16_RFIE | PHY_R16_JABIE; while (!(fec_mii_write(FEC_PHY0, PHY_REG_IR, mymwdata))) ; // Set ePHY interrupt vector and control register mcf5xxx_set_handler(0x40+36, (ADDRESS)ephy_handler); MCF_INTC0_ICR36 = MCF_INTC_ICR_IL(2) | MCF_INTC_ICR_IP(7); MCF_INTC0_IMRH &=  ~(MCF_INTC_IMRH_MASK36);}#define TRIES_100M 2typedef enum { DOWN_10 = 0, DOWN_100, UP_10, UP_100} eth_link_state;eth_link_state link_state = DOWN_100;char tries_100 = TRIES_100M, stable_state = FALSE, negotiate_10 = TRUE;int gotlink = FALSE;void mcf5223x_ephy_fsm(void){ uint16 reg1; eth_link_state state; char link_up; // Read link status while (!fec_mii_read(FEC_PHY0, PHY_REG_SR, &reg1)) ; link_up = FALSE; if (reg1 & PHY_R1_LS)  link_up = TRUE;  state = link_state; switch (link_state) {   case DOWN_10:   if (link_up) {    negotiate_10 = TRUE;    if (tries_100) {     printf("ephy: 10M OK, try 100M\n");#warning This does not work properly     mcf5223x_eth_init(TRUE);  // Re-init EPHY     mcf5223x_eth_init_ephy(TRUE, TRUE); // 100M     stable_state = FALSE;     state = DOWN_100;    } else {     printf("ephy: 10M OK, link UP\n");     gotlink = TRUE;     stable_state = TRUE;     state = UP_10;    }   } else if (!stable_state) {    if (negotiate_10) {     printf("ephy: 10M negotiate\n");     mcf5223x_eth_init_ephy(FALSE, TRUE); // 10M, negotiate     negotiate_10 = FALSE;    } else {     printf("ephy: 10M stable, link DOWN\n");     stable_state = TRUE;     tries_100 = TRIES_100M;    }   }   break;   case UP_10:   if (!link_up) {    printf("ephy: 10M lost, link DOWN\n");    gotlink = FALSE;    stable_state = FALSE;    state = DOWN_10;   }   break;   case DOWN_100:   if (link_up) {    printf("ephy: 100M OK, link UP\n");    gotlink = TRUE;    stable_state = TRUE;    state = UP_100;   } else {    tries_100--;        if (tries_100) {     mcf5223x_eth_init_ephy(TRUE, TRUE); // 100M, negotiate          } else {     printf("ephy: 100M failed, try 10M\n");     mcf5223x_eth_init(TRUE);  // Re-init EPHY     mcf5223x_eth_init_ephy(FALSE, TRUE); // 10M, negotiate     state = DOWN_10;    }   }   break;   case UP_100:   if (!link_up) {    printf("ephy: 100M lost, try 10M, link DOWN\n");    mcf5223x_eth_init(TRUE);   // Re-init EPHY    gotlink = FALSE;    stable_state = FALSE;    state = DOWN_10;   }   break;   default:   asm("halt");   break; } link_state = state;}

 
In power-up, I call mcf5223x_eth_init(TRUE), and after setting up other TCP stuff, the mcf5223x_ephy_fsm() function is called approximately every 1.5 seconds (from the "superloop-task", not a timer interrupt).

The variable stable_state can be used elsewhere to check if negotiation has "settled" (if e.g sending stuff on TCP in end of power-up sequence).

The variable gotlink can be used elsewhere to check if the unit has a physical connection to another ethernet unit.

In the example above, printf writes to the UART without using interrupts.

Chris: your re-init code seems functionally very similar to mine. Thanks for posting, so I could compare.
0 Kudos