S32K3XX EMAC MII PHY implementation

This commit is contained in:
Peter van der Perk 2022-12-22 14:08:29 +01:00 committed by Xiang Xiao
parent 3d016db226
commit 7f3cd2d3e8
2 changed files with 543 additions and 14 deletions

View File

@ -190,7 +190,7 @@ config S32K3XX_HAVE_ENET
bool bool
default n default n
select ARCH_HAVE_PHY select ARCH_HAVE_PHY
select ARCH_PHY_INTERRUPT select ARCH_PHY_POLLED
select ARCH_HAVE_NETDEV_STATISTICS select ARCH_HAVE_NETDEV_STATISTICS
# Select MPU when D-cache is enabled for ARM errata 1624041 # Select MPU when D-cache is enabled for ARM errata 1624041

View File

@ -230,6 +230,92 @@
#define BUF ((struct eth_hdr_s *)priv->dev.d_buf) #define BUF ((struct eth_hdr_s *)priv->dev.d_buf)
/* PHY definitions.
*
* The selected PHY must be selected from the drivers/net/Kconfig PHY menu.
* A description of the PHY must be provided here. That description must
* include:
*
* 1. BOARD_PHY_NAME: A PHY name string (for debug output),
* 2. BOARD_PHYID1 and BOARD_PHYID2: The PHYID1 and PHYID2 values (from
* include/nuttx/net/mii.h)
* 3. BOARD_PHY_STATUS: The address of the status register to use when
* querying link status (from include/nuttx/net/mii.h)
* 4. BOARD_PHY_ADDRThe PHY broadcast address of 0 is selected. This
* should be fine as long as there is only a single PHY.
* 5. BOARD_PHY_10BASET: A macro that can convert the status register
* value into a boolean: true=10Base-T, false=Not 10Base-T
* 6. BOARD_PHY_100BASET: A macro that can convert the status register
* value into a boolean: true=100Base-T, false=Not 100Base-T
* 7. BOARD_PHY_ISDUPLEX: A macro that can convert the status register
* value into a boolean: true=duplex mode, false=half-duplex mode
*
* The imxrt1050-evk board uses a KSZ8081 PHY
* The Versiboard2 uses a LAN8720 PHY
* The Teensy-4.1 board uses a DP83825I PHY
*
* ...and further PHY descriptions here.
*/
#if defined(CONFIG_ETH0_PHY_KSZ8081)
# define BOARD_PHY_NAME "KSZ8081"
# define BOARD_PHYID1 MII_PHYID1_KSZ8081
# define BOARD_PHYID2 MII_PHYID2_KSZ8081
# define BOARD_PHY_STATUS MII_KSZ8081_PHYCTRL1
# define BOARD_PHY_ADDR (0)
# define BOARD_PHY_10BASET(s) (((s) & MII_PHYCTRL1_MODE_10HDX) != 0)
# define BOARD_PHY_100BASET(s) (((s) & MII_PHYCTRL1_MODE_100HDX) != 0)
# define BOARD_PHY_ISDUPLEX(s) (((s) & MII_PHYCTRL1_MODE_DUPLEX) != 0)
#elif defined(CONFIG_ETH0_PHY_LAN8720)
# define BOARD_PHY_NAME "LAN8720"
# define BOARD_PHYID1 MII_PHYID1_LAN8720
# define BOARD_PHYID2 MII_PHYID2_LAN8720
# define BOARD_PHY_STATUS MII_LAN8720_SCSR
# define BOARD_PHY_ADDR (1)
# define BOARD_PHY_10BASET(s) (((s)&MII_LAN8720_SPSCR_10MBPS) != 0)
# define BOARD_PHY_100BASET(s) (((s)&MII_LAN8720_SPSCR_100MBPS) != 0)
# define BOARD_PHY_ISDUPLEX(s) (((s)&MII_LAN8720_SPSCR_DUPLEX) != 0)
#elif defined(CONFIG_ETH0_PHY_LAN8742A)
# define BOARD_PHY_NAME "LAN8742A"
# define BOARD_PHYID1 MII_PHYID1_LAN8742A
# define BOARD_PHYID2 MII_PHYID2_LAN8742A
# define BOARD_PHY_STATUS MII_LAN8740_SCSR
# define BOARD_PHY_ADDR (0)
# define BOARD_PHY_10BASET(s) (((s)&MII_LAN8720_SPSCR_10MBPS) != 0)
# define BOARD_PHY_100BASET(s) (((s)&MII_LAN8720_SPSCR_100MBPS) != 0)
# define BOARD_PHY_ISDUPLEX(s) (((s)&MII_LAN8720_SPSCR_DUPLEX) != 0)
#elif defined(CONFIG_ETH0_PHY_DP83825I)
# define BOARD_PHY_NAME "DP83825I"
# define BOARD_PHYID1 MII_PHYID1_DP83825I
# define BOARD_PHYID2 MII_PHYID2_DP83825I
# define BOARD_PHY_STATUS MII_DP83825I_PHYSTS
# define BOARD_PHY_ADDR (0)
# define BOARD_PHY_10BASET(s) (((s) & MII_DP83825I_PHYSTS_SPEED) != 0)
# define BOARD_PHY_100BASET(s) (((s) & MII_DP83825I_PHYSTS_SPEED) == 0)
# define BOARD_PHY_ISDUPLEX(s) (((s) & MII_DP83825I_PHYSTS_DUPLEX) != 0)
#elif defined(CONFIG_ETH0_PHY_TJA1103)
# define BOARD_PHY_NAME "TJA1103"
# define BOARD_PHYID1 MII_PHYID1_TJA1103
# define BOARD_PHYID2 MII_PHYID2_TJA1103
# define BOARD_PHY_STATUS MII_TJA110X_BSR
# define BOARD_PHY_ADDR (18)
# define BOARD_PHY_10BASET(s) 0 /* PHY only supports 100BASE-T1 */
# define BOARD_PHY_100BASET(s) 1 /* PHY only supports 100BASE-T1 */
# define BOARD_PHY_ISDUPLEX(s) 1 /* PHY only supports fullduplex */
# define CLAUSE45 1
# define MMD1 1
# define MMD1_PMA_STATUS1 1
# define MMD1_PS1_RECEIVE_LINK_STATUS (1 << 2)
# define MMD30_VEND1 30
# define VEND1_PHY_IRQ_ACK 0x80A0
# define VEND1_PHY_IRQ_EN 0x80A1
# define VEND1_PHY_IRQ_STATUS 0x80A2
# define PHY_IRQ_LINK_EVENT (1 << 1)
#else
# error "Unrecognized or missing PHY selection"
#endif
/**************************************************************************** /****************************************************************************
* Private Types * Private Types
****************************************************************************/ ****************************************************************************/
@ -363,10 +449,16 @@ static int s32k3xx_phyintenable(struct s32k3xx_driver_s *priv);
#if defined(CONFIG_NETDEV_PHY_IOCTL) #if defined(CONFIG_NETDEV_PHY_IOCTL)
static int s32k3xx_writemii(struct s32k3xx_driver_s *priv, uint8_t phyaddr, static int s32k3xx_writemii(struct s32k3xx_driver_s *priv, uint8_t phyaddr,
uint8_t regaddr, uint16_t data); uint8_t regaddr, uint16_t data);
#endif
static int s32k3xx_readmii(struct s32k3xx_driver_s *priv, uint8_t phyaddr, static int s32k3xx_readmii(struct s32k3xx_driver_s *priv, uint8_t phyaddr,
uint8_t regaddr, uint16_t *data); uint8_t regaddr, uint16_t *data);
#endif
static int s32k3xx_initphy(struct s32k3xx_driver_s *priv, bool renogphy); static int s32k3xx_initphy(struct s32k3xx_driver_s *priv, bool renogphy);
#if defined(CLAUSE45)
static int s32k3xx_readmmd(struct s32k3xx_driver_s *priv, uint8_t phyaddr,
uint8_t mmd, uint16_t regaddr, uint16_t *data);
static int s32k3xx_writemmd(struct s32k3xx_driver_s *priv, uint8_t phyaddr,
uint8_t mmd, uint16_t regaddr, uint16_t data);
#endif
/* Initialization */ /* Initialization */
@ -1903,10 +1995,6 @@ static int s32k3xx_ifup_action(struct net_driver_s *dev, bool resetphy)
| EMAC_MAC_INTERRUPT_ENABLE_RXSTSIE, | EMAC_MAC_INTERRUPT_ENABLE_RXSTSIE,
S32K3XX_EMAC_MAC_INTERRUPT_ENABLE); S32K3XX_EMAC_MAC_INTERRUPT_ENABLE);
putreg32(EMAC_MAC_CONFIGURATION_DM | EMAC_MAC_CONFIGURATION_RE
| EMAC_MAC_CONFIGURATION_TE | EMAC_MAC_CONFIGURATION_FES,
S32K3XX_EMAC_MAC_CONFIGURATION);
regval = EMAC_MAC_PACKET_FILTER_RA; regval = EMAC_MAC_PACKET_FILTER_RA;
#ifdef CONFIG_NET_PROMISCUOUS #ifdef CONFIG_NET_PROMISCUOUS
regval |= EMAC_MAC_PACKET_FILTER_PR; regval |= EMAC_MAC_PACKET_FILTER_PR;
@ -2314,8 +2402,21 @@ static int s32k3xx_ioctl(struct net_driver_s *dev, int cmd,
{ {
struct mii_ioctl_data_s *req = struct mii_ioctl_data_s *req =
(struct mii_ioctl_data_s *)((uintptr_t)arg); (struct mii_ioctl_data_s *)((uintptr_t)arg);
ret = #if defined(CLAUSE45)
s32k3xx_readmii(priv, req->phy_id, req->reg_num, &req->val_out); if (MII_MSR == req->reg_num)
{
ret = s32k3xx_writemmd(priv, priv->phyaddr, MMD30_VEND1,
VEND1_PHY_IRQ_ACK, PHY_IRQ_LINK_EVENT);
ret = s32k3xx_readmmd(priv, req->phy_id, MMD1,
MMD1_PMA_STATUS1, &req->val_out);
}
else
#endif
{
ret = s32k3xx_readmii(priv, req->phy_id,
req->reg_num, &req->val_out);
}
} }
break; break;
@ -2378,6 +2479,14 @@ static int s32k3xx_phyintenable(struct s32k3xx_driver_s *priv)
(MII_KSZ80X1_INT_LDEN | MII_KSZ80X1_INT_LUEN)); (MII_KSZ80X1_INT_LDEN | MII_KSZ80X1_INT_LUEN));
} }
return ret;
#elif defined(CONFIG_ETH0_PHY_TJA1103)
uint16_t phyval;
int ret;
ret = s32k3xx_writemmd(priv, priv->phyaddr, MMD30_VEND1, VEND1_PHY_IRQ_EN,
PHY_IRQ_LINK_EVENT);
return ret; return ret;
#else #else
# error Unrecognized PHY # error Unrecognized PHY
@ -2424,8 +2533,7 @@ static int s32k3xx_writemii(struct s32k3xx_driver_s *priv, uint8_t phyaddr,
S32K3XX_EMAC_MAC_MDIO_DATA); S32K3XX_EMAC_MAC_MDIO_DATA);
regval = getreg32(S32K3XX_EMAC_MAC_MDIO_ADDRESS); regval = getreg32(S32K3XX_EMAC_MAC_MDIO_ADDRESS);
regval |= (EMAC_MAC_MDIO_ADDRESS_GOC_1 | /* Indicate write */ regval |= (EMAC_MAC_MDIO_ADDRESS_GOC_0 |
EMAC_MAC_MDIO_ADDRESS_GOC_0 |
EMAC_MAC_MDIO_ADDRESS_PA(phyaddr) | EMAC_MAC_MDIO_ADDRESS_PA(phyaddr) |
EMAC_MAC_MDIO_ADDRESS_RDA(regaddr) | EMAC_MAC_MDIO_ADDRESS_RDA(regaddr) |
EMAC_MAC_MDIO_ADDRESS_GB); EMAC_MAC_MDIO_ADDRESS_GB);
@ -2451,6 +2559,7 @@ static int s32k3xx_writemii(struct s32k3xx_driver_s *priv, uint8_t phyaddr,
return OK; return OK;
} }
#endif
/**************************************************************************** /****************************************************************************
* Function: s32k3xx_reademii * Function: s32k3xx_reademii
@ -2490,6 +2599,7 @@ static int s32k3xx_readmii(struct s32k3xx_driver_s *priv, uint8_t phyaddr,
regval = getreg32(S32K3XX_EMAC_MAC_MDIO_ADDRESS); regval = getreg32(S32K3XX_EMAC_MAC_MDIO_ADDRESS);
regval |= (EMAC_MAC_MDIO_ADDRESS_GOC_0 | regval |= (EMAC_MAC_MDIO_ADDRESS_GOC_0 |
EMAC_MAC_MDIO_ADDRESS_GOC_1 | /* Indicate read */
EMAC_MAC_MDIO_ADDRESS_PA(phyaddr) | EMAC_MAC_MDIO_ADDRESS_PA(phyaddr) |
EMAC_MAC_MDIO_ADDRESS_RDA(regaddr) | EMAC_MAC_MDIO_ADDRESS_RDA(regaddr) |
EMAC_MAC_MDIO_ADDRESS_GB); EMAC_MAC_MDIO_ADDRESS_GB);
@ -2517,6 +2627,143 @@ static int s32k3xx_readmii(struct s32k3xx_driver_s *priv, uint8_t phyaddr,
return OK; return OK;
} }
#if defined(CLAUSE45)
/****************************************************************************
* Function: s32k3xx_readmmd
*
* Description:
* Read a 16-bit value from a PHY register.
*
* Input Parameters:
* priv - Reference to the private ENET driver state structure
* phyaddr - The PHY address
* mmd - The Selected MMD Space
* regaddr - The PHY register address
* data - A pointer to the location to return the data
*
* Returned Value:
* Zero on success, a negated errno value on failure.
*
****************************************************************************/
static int s32k3xx_readmmd(struct s32k3xx_driver_s *priv, uint8_t phyaddr,
uint8_t mmd, uint16_t regaddr, uint16_t *data)
{
int timeout;
uint32_t regval;
/* Clear the MDIO */
regval = getreg32(S32K3XX_EMAC_MAC_MDIO_ADDRESS);
regval &= ~(EMAC_MAC_MDIO_ADDRESS_PA_MASK |
EMAC_MAC_MDIO_ADDRESS_RDA_MASK |
EMAC_MAC_MDIO_ADDRESS_GOC_0 |
EMAC_MAC_MDIO_ADDRESS_GOC_1 |
EMAC_MAC_MDIO_ADDRESS_C45E);
putreg32(regval, S32K3XX_EMAC_MAC_MDIO_ADDRESS);
putreg32(EMAC_MAC_MDIO_DATA_RA(regaddr), /* CL45 regaddr */
S32K3XX_EMAC_MAC_MDIO_DATA);
regval = getreg32(S32K3XX_EMAC_MAC_MDIO_ADDRESS);
regval |= (EMAC_MAC_MDIO_ADDRESS_GOC_0 |
EMAC_MAC_MDIO_ADDRESS_GOC_1 | /* Indicate read */
EMAC_MAC_MDIO_ADDRESS_PA(phyaddr) |
EMAC_MAC_MDIO_ADDRESS_RDA(mmd) |
EMAC_MAC_MDIO_ADDRESS_C45E |
EMAC_MAC_MDIO_ADDRESS_GB);
putreg32(regval, S32K3XX_EMAC_MAC_MDIO_ADDRESS);
/* Wait for the transfer to complete */
for (timeout = 0; timeout < MII_MAXPOLLS; timeout++)
{
if ((getreg32(S32K3XX_EMAC_MAC_MDIO_ADDRESS)
& EMAC_MAC_MDIO_ADDRESS_GB) == 0)
{
break;
}
}
/* Check for a timeout */
if (timeout == MII_MAXPOLLS)
{
return -ETIMEDOUT;
}
*data = EMAC_MAC_MDIO_DATA_GD(getreg32(S32K3XX_EMAC_MAC_MDIO_DATA));
return OK;
}
/****************************************************************************
* Function: s32k3xx_writemmd
*
* Description:
* Write a 16-bit value to a PHY register.
*
* Input Parameters:
* priv - Reference to the private ENET driver state structure
* phyaddr - The PHY address
* mmd - The Selected MMD Space
* regaddr - The PHY register address
* data - Data
*
* Returned Value:
* Zero on success, a negated errno value on failure.
*
****************************************************************************/
static int s32k3xx_writemmd(struct s32k3xx_driver_s *priv, uint8_t phyaddr,
uint8_t mmd, uint16_t regaddr, uint16_t data)
{
int timeout;
uint32_t regval;
/* Clear the MDIO */
regval = getreg32(S32K3XX_EMAC_MAC_MDIO_ADDRESS);
regval &= ~(EMAC_MAC_MDIO_ADDRESS_PA_MASK |
EMAC_MAC_MDIO_ADDRESS_RDA_MASK |
EMAC_MAC_MDIO_ADDRESS_GOC_0 |
EMAC_MAC_MDIO_ADDRESS_GOC_1 |
EMAC_MAC_MDIO_ADDRESS_C45E);
putreg32(regval, S32K3XX_EMAC_MAC_MDIO_ADDRESS);
putreg32((EMAC_MAC_MDIO_DATA_RA(regaddr) |
EMAC_MAC_MDIO_DATA_GD(data)),
S32K3XX_EMAC_MAC_MDIO_DATA);
regval = getreg32(S32K3XX_EMAC_MAC_MDIO_ADDRESS);
regval |= (EMAC_MAC_MDIO_ADDRESS_GOC_0 |
EMAC_MAC_MDIO_ADDRESS_PA(phyaddr) |
EMAC_MAC_MDIO_ADDRESS_RDA(mmd) |
EMAC_MAC_MDIO_ADDRESS_C45E |
EMAC_MAC_MDIO_ADDRESS_GB);
putreg32(regval, S32K3XX_EMAC_MAC_MDIO_ADDRESS);
/* Wait for the transfer to complete */
for (timeout = 0; timeout < MII_MAXPOLLS; timeout++)
{
if ((getreg32(S32K3XX_EMAC_MAC_MDIO_ADDRESS)
& EMAC_MAC_MDIO_ADDRESS_GB) == 0)
{
break;
}
}
/* Check for a timeout */
if (timeout == MII_MAXPOLLS)
{
return -ETIMEDOUT;
}
return OK;
}
#endif #endif
/**************************************************************************** /****************************************************************************
@ -2540,9 +2787,293 @@ static int s32k3xx_readmii(struct s32k3xx_driver_s *priv, uint8_t phyaddr,
static inline int s32k3xx_initphy(struct s32k3xx_driver_s *priv, static inline int s32k3xx_initphy(struct s32k3xx_driver_s *priv,
bool renogphy) bool renogphy)
{ {
/* Not implemented */ uint16_t phydata;
uint8_t phyaddr = BOARD_PHY_ADDR;
int retries;
int ret;
uint32_t mac_conf = 0;
return 0; if (renogphy)
{
/* Loop (potentially infinitely?) until we successfully communicate
* with the PHY. This is 'standard stuff' that should work for any PHY
* - we are not communicating with it's 'special' registers
* at this point.
*/
ninfo("%s: Try phyaddr: %u\n", BOARD_PHY_NAME, phyaddr);
/* Try to read PHYID1 few times using this address */
retries = 0;
do
{
nxsig_usleep(LINK_WAITUS);
ninfo("%s: Read PHYID1, retries=%d\n",
BOARD_PHY_NAME, retries + 1);
phydata = 0xffff;
ret = s32k3xx_readmii(priv, phyaddr, MII_PHYID1, &phydata);
}
while ((ret < 0 || phydata == 0xffff) && ++retries < 3);
if (retries >= 3)
{
nerr("ERROR: Failed to read %s PHYID1 at address %d\n",
BOARD_PHY_NAME, phyaddr);
return -ENOENT;
}
ninfo("%s: Using PHY address %u\n", BOARD_PHY_NAME, phyaddr);
priv->phyaddr = phyaddr;
/* Verify PHYID1. Compare OUI bits 3-18 */
ninfo("%s: PHYID1: %04x\n", BOARD_PHY_NAME, phydata);
if (phydata != BOARD_PHYID1)
{
nerr("ERROR: PHYID1=%04x incorrect for %s. Expected %04x\n",
phydata, BOARD_PHY_NAME, BOARD_PHYID1);
return -ENXIO;
}
/* Read PHYID2 */
ret = s32k3xx_readmii(priv, phyaddr, MII_PHYID2, &phydata);
if (ret < 0)
{
nerr("ERROR: Failed to read %s PHYID2: %d\n", BOARD_PHY_NAME, ret);
return ret;
}
ninfo("%s: PHYID2: %04x\n", BOARD_PHY_NAME, phydata);
/* Verify PHYID2: Compare OUI bits 19-24 and the 6-bit model number
* (ignoring the 4-bit revision number).
*/
if ((phydata & 0xfff0) != (BOARD_PHYID2 & 0xfff0))
{
nerr("ERROR: PHYID2=%04x incorrect for %s. Expected %04x\n",
(phydata & 0xfff0), BOARD_PHY_NAME, (BOARD_PHYID2 & 0xfff0));
return -ENXIO;
}
#ifdef CONFIG_ETH0_PHY_KSZ8081
/* Reset PHY */
s32k3xx_writemii(priv, phyaddr, MII_MCR, MII_MCR_RESET);
/* Set RMII mode */
ret = s32k3xx_readmii(priv, phyaddr, MII_KSZ8081_PHYCTRL2, &phydata);
if (ret < 0)
{
nerr("ERROR: Failed to read MII_KSZ8081_PHYCTRL2\n");
return ret;
}
/* Indicate 50MHz clock */
s32k3xx_writemii(priv, phyaddr, MII_KSZ8081_PHYCTRL2,
(phydata | (1 << 7)));
/* Switch off NAND Tree mode (in case it was set via pinning) */
ret = s32k3xx_readmii(priv, phyaddr, MII_KSZ8081_OMSO, &phydata);
if (ret < 0)
{
nerr("ERROR: Failed to read MII_KSZ8081_OMSO: %d\n", ret);
return ret;
}
s32k3xx_writemii(priv, phyaddr, MII_KSZ8081_OMSO,
(phydata & ~(1 << 5)));
/* Set Ethernet led to green = activity and yellow = link and */
ret = s32k3xx_readmii(priv, phyaddr, MII_KSZ8081_PHYCTRL2, &phydata);
if (ret < 0)
{
nerr("ERROR: Failed to read MII_KSZ8081_PHYCTRL2\n");
return ret;
}
s32k3xx_writemii(priv, phyaddr, MII_KSZ8081_PHYCTRL2,
(phydata | (1 << 4)));
s32k3xx_writemii(priv, phyaddr, MII_ADVERTISE,
MII_ADVERTISE_100BASETXFULL |
MII_ADVERTISE_100BASETXHALF |
MII_ADVERTISE_10BASETXFULL |
MII_ADVERTISE_10BASETXHALF |
MII_ADVERTISE_CSMA);
#elif defined (CONFIG_ETH0_PHY_LAN8720) || defined (CONFIG_ETH0_PHY_LAN8742A)
/* Make sure that PHY comes up in correct mode when it's reset */
s32k3xx_writemii(priv, phyaddr, MII_LAN8720_MODES,
MII_LAN8720_MODES_RESV | MII_LAN8720_MODES_ALL |
MII_LAN8720_MODES_PHYAD(BOARD_PHY_ADDR));
/* ...and reset PHY */
s32k3xx_writemii(priv, phyaddr, MII_MCR, MII_MCR_RESET);
#elif defined (CONFIG_ETH0_PHY_DP83825I)
/* Reset PHY */
s32k3xx_writemii(priv, phyaddr, MII_MCR, MII_MCR_RESET);
/* Set RMII mode and Indicate 50MHz clock */
s32k3xx_writemii(priv, phyaddr, MII_DP83825I_RCSR,
MII_DP83825I_RCSC_ELAST_2 | MII_DP83825I_RCSC_RMIICS);
s32k3xx_writemii(priv, phyaddr, MII_ADVERTISE,
MII_ADVERTISE_100BASETXFULL |
MII_ADVERTISE_100BASETXHALF |
MII_ADVERTISE_10BASETXFULL |
MII_ADVERTISE_10BASETXHALF |
MII_ADVERTISE_CSMA);
#endif
#if !defined(CONFIG_ETH0_PHY_TJA1103)
/* Start auto negotiation */
ninfo("%s: Start Autonegotiation...\n", BOARD_PHY_NAME);
s32k3xx_writemii(priv, phyaddr, MII_MCR,
(MII_MCR_ANRESTART | MII_MCR_ANENABLE));
/* Wait for auto negotiation to complete */
for (retries = 0; retries < LINK_NLOOPS; retries++)
{
ret = s32k3xx_readmii(priv, phyaddr, MII_MSR, &phydata);
if (ret < 0)
{
nerr("ERROR: Failed to read %s MII_MSR: %d\n",
BOARD_PHY_NAME, ret);
return ret;
}
if (phydata & MII_MSR_ANEGCOMPLETE)
{
break;
}
nxsig_usleep(LINK_WAITUS);
}
if (phydata & MII_MSR_ANEGCOMPLETE)
{
ninfo("%s: Autonegotiation complete\n", BOARD_PHY_NAME);
ninfo("%s: MII_MSR: %04x\n", BOARD_PHY_NAME, phydata);
}
else
{
/* TODO: Autonegotiation has right now failed. Maybe the Eth cable
* is not connected. PHY chip have mechanisms to configure link
* OK. We should leave autconf on, and find a way to re-configure
* MCU whenever the link is ready.
*/
ninfo("%s: Autonegotiation failed [%d] (is cable plugged-in ?), "
"default to 10Mbs mode\n", \
BOARD_PHY_NAME, retries);
/* Stop auto negotiation */
s32k3xx_writemii(priv, phyaddr, MII_MCR, 0);
}
#endif
}
#if !defined(CONFIG_ETH0_PHY_TJA1103)
/* When we get here we have a (negotiated) speed and duplex. This is also
* the point we enter if renegotiation is turned off, so have multiple
* attempts at reading the status register in case the PHY isn't awake
* properly.
*/
retries = 0;
do
{
phydata = 0xffff;
ret = s32k3xx_readmii(priv, phyaddr, BOARD_PHY_STATUS, &phydata);
}
while ((ret < 0 || phydata == 0xffff) && ++retries < 3);
/* If we didn't successfully read anything and we haven't tried a physical
* renegotiation then lets do that
*/
if (retries >= 3)
{
if (renogphy == false)
{
/* Give things one more chance with renegotiation turned on */
return s32k3xx_initphy(priv, true);
}
else
{
/* That didn't end well, just give up */
nerr("ERROR: Failed to read %s BOARD_PHY_STATUS[%02x]: %d\n",
BOARD_PHY_NAME, BOARD_PHY_STATUS, ret);
return ret;
}
}
ninfo("%s: BOARD_PHY_STATUS: %04x\n", BOARD_PHY_NAME, phydata);
#endif
/* Setup half or full duplex */
if (BOARD_PHY_ISDUPLEX(phydata))
{
/* Full duplex */
ninfo("%s: Full duplex\n", BOARD_PHY_NAME);
mac_conf |= EMAC_MAC_CONFIGURATION_DM;
}
else
{
/* Half duplex */
ninfo("%s: Half duplex\n", BOARD_PHY_NAME);
}
if (BOARD_PHY_10BASET(phydata))
{
/* 10 Mbps */
ninfo("%s: 10 Base-T\n", BOARD_PHY_NAME);
}
else if (BOARD_PHY_100BASET(phydata))
{
/* 100 Mbps */
ninfo("%s: 100 Base-T\n", BOARD_PHY_NAME);
mac_conf |= EMAC_MAC_CONFIGURATION_FES;
}
else
{
/* This might happen if Autonegotiation did not complete(?) */
nerr("ERROR: Neither 10- nor 100-BaseT reported: PHY STATUS=%04x\n",
phydata);
return -EIO;
}
putreg32(mac_conf | EMAC_MAC_CONFIGURATION_DM | EMAC_MAC_CONFIGURATION_RE
| EMAC_MAC_CONFIGURATION_TE | EMAC_MAC_CONFIGURATION_PS,
S32K3XX_EMAC_MAC_CONFIGURATION);
return OK;
} }
/**************************************************************************** /****************************************************************************
@ -2976,8 +3507,6 @@ int s32k3xx_netinitialize(int intf)
#ifdef CONFIG_S32K3XX_ENET_PHYINIT #ifdef CONFIG_S32K3XX_ENET_PHYINIT
/* Perform any necessary, one-time, board-specific PHY initialization */ /* Perform any necessary, one-time, board-specific PHY initialization */
/* FIXME unspported */
ret = s32k3xx_phy_boardinitialize(0); ret = s32k3xx_phy_boardinitialize(0);
if (ret < 0) if (ret < 0)
{ {