imxrt:ENET Use multi PHY
Allow a board to specify a list of PHYs. Then use this list, at run-time, to select and use the PHY populated on the board.
This commit is contained in:
parent
93f37ab1da
commit
73bfeccc3f
@ -250,8 +250,25 @@
|
||||
* ...and further PHY descriptions here.
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_ETH0_PHY_KSZ8081)
|
||||
# define BOARD_PHY_NAME "KSZ8081"
|
||||
#if defined(CONFIG_ETH0_PHY_MULTI)
|
||||
# if !defined(BOARD_ETH0_PHY_LIST)
|
||||
# error "CONFIG_ETH0_PHY_MULTI requires board.h to define BOARD_ETH0_PHY_LIST!"
|
||||
# endif
|
||||
# define BOARD_PHY_NAME g_board_phys[priv->current_phy].name
|
||||
# define BOARD_PHYID1 g_board_phys[priv->current_phy].id1
|
||||
# define BOARD_PHYID2 g_board_phys[priv->current_phy].id2
|
||||
# define BOARD_PHY_STATUS g_board_phys[priv->current_phy].status
|
||||
# define BOARD_PHY_ADDR priv->current_phy_address
|
||||
# define BOARD_PHY_10BASET(s) (imxrt_phy_status(priv, (s), g_board_phys[priv->current_phy].mbps10) != 0)
|
||||
# define BOARD_PHY_100BASET(s) (imxrt_phy_status(priv, (s), g_board_phys[priv->current_phy].mbps100) != 0)
|
||||
# define BOARD_PHY_ISDUPLEX(s) (imxrt_phy_status(priv, (s), g_board_phys[priv->current_phy].duplex) != 0)
|
||||
# define BOARD_PHY_ISCLAUSE45() (g_board_phys[priv->current_phy].clause == 45)
|
||||
# define CLAUSE45
|
||||
# define MMD1 1
|
||||
# define MMD1_PMA_STATUS1 1
|
||||
# define MMD1_PS1_RECEIVE_LINK_STATUS (1 << 2)
|
||||
#elif defined(CONFIG_ETH0_PHY_KSZ8081)
|
||||
# define BOARD_PHY_NAME MII_KSZ8081_NAME
|
||||
# define BOARD_PHYID1 MII_PHYID1_KSZ8081
|
||||
# define BOARD_PHYID2 MII_PHYID2_KSZ8081
|
||||
# define BOARD_PHY_STATUS MII_KSZ8081_PHYCTRL1
|
||||
@ -260,7 +277,7 @@
|
||||
# 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_PHY_NAME MII_LAN8720_NAME
|
||||
# define BOARD_PHYID1 MII_PHYID1_LAN8720
|
||||
# define BOARD_PHYID2 MII_PHYID2_LAN8720
|
||||
# define BOARD_PHY_STATUS MII_LAN8720_SCSR
|
||||
@ -269,7 +286,7 @@
|
||||
# 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_PHY_NAME MII_LAN8742A_NAME
|
||||
# define BOARD_PHYID1 MII_PHYID1_LAN8742A
|
||||
# define BOARD_PHYID2 MII_PHYID2_LAN8742A
|
||||
# define BOARD_PHY_STATUS MII_LAN8740_SCSR
|
||||
@ -278,7 +295,7 @@
|
||||
# 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_PHY_NAME MII_DP83825I_NAME
|
||||
# define BOARD_PHYID1 MII_PHYID1_DP83825I
|
||||
# define BOARD_PHYID2 MII_PHYID2_DP83825I
|
||||
# define BOARD_PHY_STATUS MII_DP83825I_PHYSTS
|
||||
@ -287,7 +304,7 @@
|
||||
# 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_PHY_NAME MII_TJA1103_NAME
|
||||
# define BOARD_PHYID1 MII_PHYID1_TJA1103
|
||||
# define BOARD_PHYID2 MII_PHYID2_TJA1103
|
||||
# define BOARD_PHY_STATUS MII_TJA110X_BSR
|
||||
@ -300,7 +317,7 @@
|
||||
# define MMD1_PMA_STATUS1 1
|
||||
# define MMD1_PS1_RECEIVE_LINK_STATUS (1 << 2)
|
||||
#elif defined(CONFIG_ETH0_PHY_YT8512)
|
||||
# define BOARD_PHY_NAME "YT8512"
|
||||
# define BOARD_PHY_NAME MII_YT8512_NAME
|
||||
# define BOARD_PHYID1 MII_PHYID1_YT8512
|
||||
# define BOARD_PHYID2 MII_PHYID2_YT8512
|
||||
# define BOARD_PHY_STATUS MII_YT8512_PHYSTS
|
||||
@ -375,6 +392,10 @@ struct imxrt_driver_s
|
||||
struct enet_desc_s *txdesc; /* A pointer to the list of TX descriptor */
|
||||
struct enet_desc_s *rxdesc; /* A pointer to the list of RX descriptors */
|
||||
|
||||
#if defined(CONFIG_ETH0_PHY_MULTI)
|
||||
uint8_t current_phy; /* The index of the PHY being used */
|
||||
uint8_t current_phy_address; /* The address of the PHY being used */
|
||||
#endif
|
||||
/* This holds the information visible to the NuttX network */
|
||||
|
||||
struct net_driver_s dev; /* Interface understood by the network */
|
||||
@ -384,6 +405,15 @@ struct imxrt_driver_s
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
/* BOARD_ETH0_PHY_LIST provided by the board.h for CONFIG_ETH0_PHY_MULTI */
|
||||
|
||||
#if defined(CONFIG_ETH0_PHY_MULTI)
|
||||
const struct phy_desc_s g_board_phys[] =
|
||||
{
|
||||
BOARD_ETH0_PHY_LIST
|
||||
};
|
||||
#endif
|
||||
|
||||
static struct imxrt_driver_s g_enet[CONFIG_IMXRT_ENET_NETHIFS];
|
||||
|
||||
/* The DMA descriptors */
|
||||
@ -470,6 +500,13 @@ static int imxrt_ioctl(struct net_driver_s *dev, int cmd,
|
||||
|
||||
/* PHY/MII support */
|
||||
|
||||
#if defined(CONFIG_ETH0_PHY_MULTI)
|
||||
static int imxrt_phy_is(struct imxrt_driver_s *priv, const char *name);
|
||||
static int imxrt_phy_status(struct imxrt_driver_s *priv, int phydata,
|
||||
uint16_t mask);
|
||||
static int imxrt_determine_phy(struct imxrt_driver_s *priv);
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_NETDEV_PHY_IOCTL) && defined(CONFIG_ARCH_PHY_INTERRUPT)
|
||||
static int imxrt_phyintenable(struct imxrt_driver_s *priv);
|
||||
#endif
|
||||
@ -1377,6 +1414,15 @@ static int imxrt_ifup_action(struct net_driver_s *dev, bool resetphy)
|
||||
|
||||
/* Configure the PHY */
|
||||
|
||||
#if defined(CONFIG_ETH0_PHY_MULTI)
|
||||
ret = imxrt_determine_phy(priv);
|
||||
if (ret < 0)
|
||||
{
|
||||
nerr("ERROR: Failed to determine the PHY: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
ret = imxrt_initphy(priv, resetphy);
|
||||
if (ret < 0)
|
||||
{
|
||||
@ -1872,7 +1918,11 @@ static int imxrt_ioctl(struct net_driver_s *dev, int cmd, unsigned long arg)
|
||||
struct mii_ioctl_data_s *req =
|
||||
(struct mii_ioctl_data_s *)((uintptr_t)arg);
|
||||
#if defined(CLAUSE45)
|
||||
if (MII_MSR == req->reg_num)
|
||||
if (
|
||||
# if defined(CONFIG_ETH0_PHY_MULTI)
|
||||
BOARD_PHY_ISCLAUSE45() &&
|
||||
# endif
|
||||
MII_MSR == req->reg_num)
|
||||
{
|
||||
ret = imxrt_readmmd(priv, req->phy_id, MMD1, MMD1_PMA_STATUS1,
|
||||
&req->val_out);
|
||||
@ -1926,46 +1976,60 @@ static int imxrt_ioctl(struct net_driver_s *dev, int cmd, unsigned long arg)
|
||||
#if defined(CONFIG_NETDEV_PHY_IOCTL) && defined(CONFIG_ARCH_PHY_INTERRUPT)
|
||||
static int imxrt_phyintenable(struct imxrt_driver_s *priv)
|
||||
{
|
||||
#if defined(CONFIG_ETH0_PHY_KSZ8051) || defined(CONFIG_ETH0_PHY_KSZ8061) || \
|
||||
defined(CONFIG_ETH0_PHY_KSZ8081) || defined(CONFIG_ETH0_PHY_DP83825I) || \
|
||||
defined(CONFIG_ETH0_YT8512) || defined(CONFIG_ETH0_PHY_MULTI)
|
||||
|
||||
uint16_t phyval;
|
||||
int ret;
|
||||
|
||||
#if defined(CONFIG_ETH0_PHY_KSZ8051) || defined(CONFIG_ETH0_PHY_KSZ8061) || \
|
||||
defined(CONFIG_ETH0_PHY_KSZ8081) || defined(CONFIG_ETH0_PHY_DP83825I)
|
||||
/* Compile time Kzxxxx defaults */
|
||||
|
||||
/* Read the interrupt status register in order to clear any pending
|
||||
* interrupts
|
||||
*/
|
||||
uint16_t mask = MII_KSZ80X1_INT_LDEN | MII_KSZ80X1_INT_LUEN;
|
||||
uint8_t rreg = MII_KSZ8081_INT;
|
||||
uint8_t wreg = rreg;
|
||||
|
||||
ret = imxrt_readmii(priv, priv->phyaddr, MII_KSZ8081_INT, &phyval);
|
||||
if (ret == OK)
|
||||
/* Compile time YT8512 defaults */
|
||||
# if defined(CONFIG_ETH0_YT8512)
|
||||
mask = MII_YT8512_IMR_LD_EN | MII_YT8512_IMR_LU_EN;
|
||||
rreg = MII_YT8512_ISR;
|
||||
wreg = MII_YT8512_IMR;
|
||||
# endif
|
||||
|
||||
/* Run time YT8512 defaults */
|
||||
# if defined(CONFIG_ETH0_PHY_MULTI)
|
||||
if (imxrt_phy_is(priv, MII_YT8512_NAME))
|
||||
{
|
||||
/* Enable link up/down interrupts */
|
||||
|
||||
ret = imxrt_writemii(priv, priv->phyaddr, MII_KSZ8081_INT,
|
||||
(MII_KSZ80X1_INT_LDEN | MII_KSZ80X1_INT_LUEN));
|
||||
mask = MII_YT8512_IMR_LD_EN | MII_YT8512_IMR_LU_EN;
|
||||
rreg = MII_YT8512_ISR;
|
||||
wreg = MII_YT8512_IMR;
|
||||
}
|
||||
|
||||
return ret;
|
||||
#elif defined(CONFIG_ETH0_YT8512)
|
||||
else if (!(imxrt_phy_is(priv, MII_KSZ8051_NAME) ||
|
||||
imxrt_phy_is(priv, MII_KSZ8061_NAME) ||
|
||||
imxrt_phy_is(priv, MII_KSZ8081_NAME) ||
|
||||
imxrt_phy_is(priv, MII_DP83825I_NAME)))
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
# endif
|
||||
|
||||
/* Read the interrupt status register in order to clear any pending
|
||||
* interrupts
|
||||
*/
|
||||
|
||||
ret = imxrt_readmii(priv, priv->phyaddr, MII_YT8512_ISR, &phyval);
|
||||
ret = imxrt_readmii(priv, priv->phyaddr, rreg, &phyval);
|
||||
if (ret == OK)
|
||||
{
|
||||
/* Enable link up/down interrupts */
|
||||
|
||||
ret = imxrt_writemii(priv, priv->phyaddr, MII_YT8512_IMR,
|
||||
(MII_YT8512_IMR_LD_EN | MII_YT8512_IMR_LU_EN));
|
||||
ret = imxrt_writemii(priv, priv->phyaddr, wreg, mask);
|
||||
}
|
||||
|
||||
return ret;
|
||||
#else
|
||||
# error Unrecognized PHY
|
||||
return -ENOSYS;
|
||||
#endif
|
||||
# endif
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -2121,6 +2185,126 @@ static int imxrt_readmii(struct imxrt_driver_s *priv, uint8_t phyaddr,
|
||||
return OK;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_ETH0_PHY_MULTI)
|
||||
/****************************************************************************
|
||||
* Function: imxrt_determine_phy
|
||||
*
|
||||
* Description:
|
||||
* Uses the board.h supplied PHY list to determine which PHY
|
||||
* is populated on this board.
|
||||
*
|
||||
* Input Parameters:
|
||||
* priv - Reference to the private ENET driver state structure
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero on success, a -ENOENT errno value on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int imxrt_determine_phy(struct imxrt_driver_s *priv)
|
||||
{
|
||||
uint16_t phydata = 0xffff;
|
||||
uint8_t phyaddr = 0;
|
||||
uint8_t last_phyaddr = 0;
|
||||
int retries;
|
||||
int ret;
|
||||
|
||||
for (priv->current_phy = 0; priv->current_phy < nitems(g_board_phys);
|
||||
priv->current_phy++)
|
||||
{
|
||||
priv->current_phy_address =
|
||||
(uint8_t) g_board_phys[priv->current_phy].address_lo;
|
||||
last_phyaddr = g_board_phys[priv->current_phy].address_high == 0xffff ?
|
||||
priv->current_phy_address :
|
||||
(uint8_t) g_board_phys[priv->current_phy].address_high;
|
||||
|
||||
for (phyaddr = priv->current_phy_address; phyaddr <= last_phyaddr;
|
||||
phyaddr++)
|
||||
{
|
||||
retries = 0;
|
||||
do
|
||||
{
|
||||
nxsig_usleep(100);
|
||||
phydata = 0xffff;
|
||||
ret = imxrt_readmii(priv, phyaddr, MII_PHYID1, &phydata);
|
||||
}
|
||||
while ((ret < 0 || phydata == 0xffff) && ++retries < 3);
|
||||
|
||||
if (retries <= 3 && ret == 0 &&
|
||||
phydata == g_board_phys[priv->current_phy].id1)
|
||||
{
|
||||
do
|
||||
{
|
||||
nxsig_usleep(100);
|
||||
phydata = 0xffff;
|
||||
ret = imxrt_readmii(priv, phyaddr, MII_PHYID2, &phydata);
|
||||
}
|
||||
while ((ret < 0 || phydata == 0xffff) && ++retries < 3);
|
||||
if (retries <= 3 && ret == 0 &&
|
||||
(phydata & 0xfff0) ==
|
||||
(g_board_phys[priv->current_phy].id2 & 0xfff0))
|
||||
{
|
||||
return OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Function: imxrt_phy_is
|
||||
*
|
||||
* Description:
|
||||
* Compares the name with the current selected PHY's name
|
||||
*
|
||||
* Input Parameters:
|
||||
* priv - Reference to the private ENET driver state structure
|
||||
* name - a pointer to comapre to.
|
||||
*
|
||||
* Returned Value:
|
||||
* 1 on match, a 0 on no match.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int imxrt_phy_is(struct imxrt_driver_s *priv, const char *name)
|
||||
{
|
||||
return strcmp(g_board_phys[priv->current_phy].name, name) == 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Function: imxrt_phy_status
|
||||
*
|
||||
* Description:
|
||||
* Compares the name with the current selected PHY's name.
|
||||
*
|
||||
* Input Parameters:
|
||||
* priv - Reference to the private ENET driver state structure
|
||||
* phydata - last read phy data - may be ignored if there is no
|
||||
* status register defined by the current PHY.
|
||||
* mask - A value to and with phydata if a status register is
|
||||
* defined. Or the value retunred if no status register is
|
||||
* defined.
|
||||
*
|
||||
* Returned Value:
|
||||
* mask or (phydat & mask)
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int imxrt_phy_status(struct imxrt_driver_s *priv, int phydata,
|
||||
uint16_t mask)
|
||||
{
|
||||
int rv = mask;
|
||||
if (g_board_phys[priv->current_phy].status != 0xffff)
|
||||
{
|
||||
rv &= phydata;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
#if defined(CLAUSE45)
|
||||
/****************************************************************************
|
||||
@ -2416,213 +2600,265 @@ static inline int imxrt_initphy(struct imxrt_driver_s *priv, bool renogphy)
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ETH0_PHY_KSZ8081
|
||||
/* Reset PHY */
|
||||
|
||||
imxrt_writemii(priv, phyaddr, MII_MCR, MII_MCR_RESET);
|
||||
|
||||
/* Set RMII mode */
|
||||
|
||||
ret = imxrt_readmii(priv, phyaddr, MII_KSZ8081_PHYCTRL2, &phydata);
|
||||
if (ret < 0)
|
||||
#if defined(CONFIG_ETH0_PHY_KSZ8081) || defined(CONFIG_ETH0_PHY_MULTI)
|
||||
# if defined(CONFIG_ETH0_PHY_MULTI)
|
||||
if (imxrt_phy_is(priv, MII_KSZ8081_NAME))
|
||||
{
|
||||
nerr("ERROR: Failed to read MII_KSZ8081_PHYCTRL2\n");
|
||||
return ret;
|
||||
}
|
||||
# endif
|
||||
/* Reset PHY */
|
||||
|
||||
/* Indicate 50MHz clock */
|
||||
imxrt_writemii(priv, phyaddr, MII_MCR, MII_MCR_RESET);
|
||||
|
||||
imxrt_writemii(priv, phyaddr, MII_KSZ8081_PHYCTRL2,
|
||||
(phydata | (1 << 7)));
|
||||
/* Set RMII mode */
|
||||
|
||||
/* Switch off NAND Tree mode (in case it was set via pinning) */
|
||||
|
||||
ret = imxrt_readmii(priv, phyaddr, MII_KSZ8081_OMSO, &phydata);
|
||||
if (ret < 0)
|
||||
{
|
||||
nerr("ERROR: Failed to read MII_KSZ8081_OMSO: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
imxrt_writemii(priv, phyaddr, MII_KSZ8081_OMSO,
|
||||
(phydata & ~(1 << 5)));
|
||||
|
||||
/* Set Ethernet led to green = activity and yellow = link and */
|
||||
|
||||
ret = imxrt_readmii(priv, phyaddr, MII_KSZ8081_PHYCTRL2, &phydata);
|
||||
if (ret < 0)
|
||||
{
|
||||
nerr("ERROR: Failed to read MII_KSZ8081_PHYCTRL2\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
imxrt_writemii(priv, phyaddr, MII_KSZ8081_PHYCTRL2,
|
||||
(phydata | (1 << 4)));
|
||||
|
||||
imxrt_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 */
|
||||
|
||||
imxrt_writemii(priv, phyaddr, MII_LAN8720_MODES,
|
||||
MII_LAN8720_MODES_RESV | MII_LAN8720_MODES_ALL |
|
||||
MII_LAN8720_MODES_PHYAD(BOARD_PHY_ADDR));
|
||||
|
||||
/* ...and reset PHY */
|
||||
|
||||
imxrt_writemii(priv, phyaddr, MII_MCR, MII_MCR_RESET);
|
||||
|
||||
#elif defined (CONFIG_ETH0_PHY_DP83825I)
|
||||
|
||||
/* Reset PHY */
|
||||
|
||||
imxrt_writemii(priv, phyaddr, MII_MCR, MII_MCR_RESET);
|
||||
|
||||
/* Set RMII mode and Indicate 50MHz clock */
|
||||
|
||||
imxrt_writemii(priv, phyaddr, MII_DP83825I_RCSR,
|
||||
MII_DP83825I_RCSC_ELAST_2 | MII_DP83825I_RCSC_RMIICS);
|
||||
|
||||
imxrt_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_YT8512)
|
||||
|
||||
/* Reset PHY */
|
||||
|
||||
imxrt_writemii(priv, phyaddr, MII_MCR, MII_MCR_RESET);
|
||||
|
||||
/* Config LEDs */
|
||||
|
||||
imxrt_writemii(priv, phyaddr, MII_YT8512_DEBUG_ADDR_OFFSET,
|
||||
MII_YT8512_LED0);
|
||||
|
||||
imxrt_readmii(priv, phyaddr, MII_YT8512_DEBUG_DATA, &phydata);
|
||||
|
||||
imxrt_writemii(priv, phyaddr, MII_YT8512_DEBUG_ADDR_OFFSET,
|
||||
MII_YT8512_LED0);
|
||||
|
||||
imxrt_writemii(priv, phyaddr, MII_YT8512_DEBUG_DATA, 0x331);
|
||||
|
||||
imxrt_writemii(priv, phyaddr, MII_YT8512_DEBUG_ADDR_OFFSET,
|
||||
MII_YT8512_LED1);
|
||||
|
||||
imxrt_readmii(priv, phyaddr, MII_YT8512_DEBUG_DATA, &phydata);
|
||||
|
||||
imxrt_writemii(priv, phyaddr, MII_YT8512_DEBUG_ADDR_OFFSET,
|
||||
MII_YT8512_LED1);
|
||||
|
||||
imxrt_writemii(priv, phyaddr, MII_YT8512_DEBUG_DATA, 0x30);
|
||||
|
||||
/* Set negotiation */
|
||||
|
||||
imxrt_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);
|
||||
imxrt_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 = imxrt_readmii(priv, phyaddr, MII_MSR, &phydata);
|
||||
ret = imxrt_readmii(priv, phyaddr, MII_KSZ8081_PHYCTRL2, &phydata);
|
||||
if (ret < 0)
|
||||
{
|
||||
nerr("ERROR: Failed to read %s MII_MSR: %d\n",
|
||||
BOARD_PHY_NAME, ret);
|
||||
nerr("ERROR: Failed to read MII_KSZ8081_PHYCTRL2\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Indicate 50MHz clock */
|
||||
|
||||
imxrt_writemii(priv, phyaddr, MII_KSZ8081_PHYCTRL2,
|
||||
(phydata | (1 << 7)));
|
||||
|
||||
/* Switch off NAND Tree mode (in case it was set via pinning) */
|
||||
|
||||
ret = imxrt_readmii(priv, phyaddr, MII_KSZ8081_OMSO, &phydata);
|
||||
if (ret < 0)
|
||||
{
|
||||
nerr("ERROR: Failed to read MII_KSZ8081_OMSO: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
imxrt_writemii(priv, phyaddr, MII_KSZ8081_OMSO,
|
||||
(phydata & ~(1 << 5)));
|
||||
|
||||
/* Set Ethernet led to green = activity and yellow = link and */
|
||||
|
||||
ret = imxrt_readmii(priv, phyaddr, MII_KSZ8081_PHYCTRL2, &phydata);
|
||||
if (ret < 0)
|
||||
{
|
||||
nerr("ERROR: Failed to read MII_KSZ8081_PHYCTRL2\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
imxrt_writemii(priv, phyaddr, MII_KSZ8081_PHYCTRL2,
|
||||
(phydata | (1 << 4)));
|
||||
|
||||
imxrt_writemii(priv, phyaddr, MII_ADVERTISE,
|
||||
MII_ADVERTISE_100BASETXFULL |
|
||||
MII_ADVERTISE_100BASETXHALF |
|
||||
MII_ADVERTISE_10BASETXFULL |
|
||||
MII_ADVERTISE_10BASETXHALF |
|
||||
MII_ADVERTISE_CSMA);
|
||||
# if defined(CONFIG_ETH0_PHY_MULTI)
|
||||
}
|
||||
|
||||
# endif
|
||||
#endif
|
||||
#if defined (CONFIG_ETH0_PHY_LAN8720) || \
|
||||
defined (CONFIG_ETH0_PHY_LAN8742A) || \
|
||||
defined (CONFIG_ETH0_PHY_MULTI)
|
||||
|
||||
# if defined(CONFIG_ETH0_PHY_MULTI)
|
||||
if (imxrt_phy_is(priv, MII_LAN8720_NAME) ||
|
||||
imxrt_phy_is(priv, MII_LAN8742A_NAME))
|
||||
{
|
||||
# endif
|
||||
|
||||
/* Make sure that PHY comes up in correct mode when it's reset */
|
||||
|
||||
imxrt_writemii(priv, phyaddr, MII_LAN8720_MODES,
|
||||
MII_LAN8720_MODES_RESV | MII_LAN8720_MODES_ALL |
|
||||
MII_LAN8720_MODES_PHYAD(BOARD_PHY_ADDR));
|
||||
|
||||
/* ...and reset PHY */
|
||||
|
||||
imxrt_writemii(priv, phyaddr, MII_MCR, MII_MCR_RESET);
|
||||
|
||||
# if defined(CONFIG_ETH0_PHY_MULTI)
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
#if defined (CONFIG_ETH0_PHY_DP83825I) || defined (CONFIG_ETH0_PHY_MULTI)
|
||||
|
||||
#if defined(CONFIG_ETH0_PHY_MULTI)
|
||||
if (imxrt_phy_is(priv, MII_DP83825I_NAME))
|
||||
{
|
||||
#endif
|
||||
|
||||
/* Reset PHY */
|
||||
|
||||
imxrt_writemii(priv, phyaddr, MII_MCR, MII_MCR_RESET);
|
||||
|
||||
/* Set RMII mode and Indicate 50MHz clock */
|
||||
|
||||
imxrt_writemii(priv, phyaddr, MII_DP83825I_RCSR,
|
||||
MII_DP83825I_RCSC_ELAST_2 |
|
||||
MII_DP83825I_RCSC_RMIICS);
|
||||
|
||||
imxrt_writemii(priv, phyaddr, MII_ADVERTISE,
|
||||
MII_ADVERTISE_100BASETXFULL |
|
||||
MII_ADVERTISE_100BASETXHALF |
|
||||
MII_ADVERTISE_10BASETXFULL |
|
||||
MII_ADVERTISE_10BASETXHALF |
|
||||
MII_ADVERTISE_CSMA);
|
||||
|
||||
# if defined(CONFIG_ETH0_PHY_MULTI)
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_ETH0_PHY_YT8512) || defined(CONFIG_ETH0_PHY_MULTI)
|
||||
# if defined(CONFIG_ETH0_PHY_MULTI)
|
||||
if (!imxrt_phy_is(priv, MII_YT8512_NAME))
|
||||
{
|
||||
# endif
|
||||
/* Reset PHY */
|
||||
|
||||
imxrt_writemii(priv, phyaddr, MII_MCR, MII_MCR_RESET);
|
||||
|
||||
/* Config LEDs */
|
||||
|
||||
imxrt_writemii(priv, phyaddr, MII_YT8512_DEBUG_ADDR_OFFSET,
|
||||
MII_YT8512_LED0);
|
||||
|
||||
imxrt_readmii(priv, phyaddr, MII_YT8512_DEBUG_DATA, &phydata);
|
||||
|
||||
imxrt_writemii(priv, phyaddr, MII_YT8512_DEBUG_ADDR_OFFSET,
|
||||
MII_YT8512_LED0);
|
||||
|
||||
imxrt_writemii(priv, phyaddr, MII_YT8512_DEBUG_DATA, 0x331);
|
||||
|
||||
imxrt_writemii(priv, phyaddr, MII_YT8512_DEBUG_ADDR_OFFSET,
|
||||
MII_YT8512_LED1);
|
||||
|
||||
imxrt_readmii(priv, phyaddr, MII_YT8512_DEBUG_DATA, &phydata);
|
||||
|
||||
imxrt_writemii(priv, phyaddr, MII_YT8512_DEBUG_ADDR_OFFSET,
|
||||
MII_YT8512_LED1);
|
||||
|
||||
imxrt_writemii(priv, phyaddr, MII_YT8512_DEBUG_DATA, 0x30);
|
||||
|
||||
/* Set negotiation */
|
||||
|
||||
imxrt_writemii(priv, phyaddr, MII_ADVERTISE,
|
||||
MII_ADVERTISE_100BASETXFULL |
|
||||
MII_ADVERTISE_100BASETXHALF |
|
||||
MII_ADVERTISE_10BASETXFULL |
|
||||
MII_ADVERTISE_10BASETXHALF |
|
||||
MII_ADVERTISE_CSMA);
|
||||
|
||||
# if defined(CONFIG_ETH0_PHY_MULTI)
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if !defined(CONFIG_ETH0_PHY_TJA1103)
|
||||
#if defined(CONFIG_ETH0_PHY_MULTI)
|
||||
if (!imxrt_phy_is(priv, MII_TJA1103_NAME))
|
||||
{
|
||||
#endif
|
||||
/* Start auto negotiation */
|
||||
|
||||
ninfo("%s: Start Autonegotiation...\n", BOARD_PHY_NAME);
|
||||
imxrt_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 = imxrt_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)
|
||||
{
|
||||
break;
|
||||
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.
|
||||
*/
|
||||
|
||||
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 */
|
||||
|
||||
imxrt_writemii(priv, phyaddr, MII_MCR, 0);
|
||||
ninfo("%s: Autonegotiation failed [%d] (is cable plugged-in ?)"
|
||||
", default to 10Mbs mode\n",
|
||||
BOARD_PHY_NAME, retries);
|
||||
|
||||
/* Stop auto negotiation */
|
||||
|
||||
imxrt_writemii(priv, phyaddr, MII_MCR, 0);
|
||||
}
|
||||
# if defined(CONFIG_ETH0_PHY_MULTI)
|
||||
}
|
||||
# endif
|
||||
#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
|
||||
# if defined(CONFIG_ETH0_PHY_MULTI)
|
||||
if (!imxrt_phy_is(priv, MII_TJA1103_NAME))
|
||||
{
|
||||
phydata = 0xffff;
|
||||
ret = imxrt_readmii(priv, phyaddr, BOARD_PHY_STATUS, &phydata);
|
||||
}
|
||||
while ((ret < 0 || phydata == 0xffff) && ++retries < 3);
|
||||
# endif
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
/* 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)
|
||||
retries = 0;
|
||||
do
|
||||
{
|
||||
/* Give things one more chance with renegotiation turned on */
|
||||
|
||||
return imxrt_initphy(priv, true);
|
||||
phydata = 0xffff;
|
||||
ret = imxrt_readmii(priv, phyaddr, BOARD_PHY_STATUS, &phydata);
|
||||
}
|
||||
else
|
||||
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)
|
||||
{
|
||||
/* That didn't end well, just give up */
|
||||
if (renogphy == false)
|
||||
{
|
||||
/* Give things one more chance with renegotiation turned on */
|
||||
|
||||
nerr("ERROR: Failed to read %s BOARD_PHY_STATUS[%02x]: %d\n",
|
||||
BOARD_PHY_NAME, BOARD_PHY_STATUS, ret);
|
||||
return ret;
|
||||
return imxrt_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);
|
||||
ninfo("%s: BOARD_PHY_STATUS: %04x\n", BOARD_PHY_NAME, phydata);
|
||||
# if defined(CONFIG_ETH0_PHY_MULTI)
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Set up the transmit and receive control registers based on the
|
||||
|
Loading…
Reference in New Issue
Block a user