SAMA5 GMAC and GMII support is code complete and ready for test

This commit is contained in:
Gregory Nutt 2013-09-27 13:12:04 -06:00
parent f519f94926
commit 9fcbd8879a
5 changed files with 319 additions and 372 deletions

View file

@ -314,121 +314,48 @@ config SAMA5_GMAC_PHYINIT
provide sam_phyinitialize(); The SAMA5 GMAC driver will call this function
one time before it first uses the PHY.
config SAMA5_GMAC_GMII
bool "Use MII interface"
default n
---help---
Support Ethernet MII interface (vs RMII).
config SAMA5_GMAC_RGMII
bool
default y if !SAMA5_GMAC_GMII
default n if SAMA5_GMAC_GMII
config SAMA5_GMAC_AUTONEG
bool "Use autonegotiation"
default y
---help---
Use PHY autonegotiation to determine speed and mode
if !SAMA5_GMAC_AUTONEG
config SAMA5_GMAC_ETHFD
bool "Full duplex"
default n
depends on !SAMA5_GMAC_AUTONEG
---help---
If SAMA5_GMAC_AUTONEG is not defined, then this may be defined to select full duplex
mode. Default: half-duplex
If SAMA5_GMAC_AUTONEG is not defined, then this may be defined to
select full duplex mode. Default: half-duplex
choice
prompt "GMAC Speed"
default SAMA5_GMAC_ETH100MBPS
---help---
If autonegation is not used, then you must select the fixed speed
of the PHY
config SAMA5_GMAC_ETH10MBPS
bool "10 Mbps"
---help---
If SAMA5_GMAC_AUTONEG is not defined, then this may be defined to select 10 MBps
speed. Default: 100 Mbps
config SAMA5_GMAC_ETH100MBPS
bool "100 Mbps"
default n
depends on !SAMA5_GMAC_AUTONEG
---help---
If SAMA5_GMAC_AUTONEG is not defined, then this may be defined to select 100 MBps
speed. Default: 10 Mbps
speed. Default: 100 Mbps
config SAMA5_GMAC_PHYSR
int "PHY Status Register Address (decimal)"
depends on SAMA5_GMAC_AUTONEG
config SAMA5_GMAC_ETH1000MBPS
bool "1000 Mbps"
---help---
This must be provided if SAMA5_GMAC_AUTONEG is defined. The PHY status register
address may diff from PHY to PHY. This configuration sets the address of
the PHY status register.
If SAMA5_GMAC_AUTONEG is not defined, then this may be defined to select 1000 MBps
speed. Default: 100 Mbps
config SAMA5_GMAC_PHYSR_ALTCONFIG
bool "PHY Status Alternate Bit Layout"
default n
depends on SAMA5_GMAC_AUTONEG
---help---
Different PHYs present speed and mode information in different ways. Some
will present separate information for speed and mode (this is the default).
Those PHYs, for example, may provide a 10/100 Mbps indication and a separate
full/half duplex indication. This options selects an alternative representation
where speed and mode information are combined. This might mean, for example,
separate bits for 10HD, 100HD, 10FD and 100FD.
config SAMA5_GMAC_PHYSR_SPEED
hex "PHY Speed Mask"
depends on SAMA5_GMAC_AUTONEG && !SAMA5_GMAC_PHYSR_ALTCONFIG
---help---
This must be provided if SAMA5_GMAC_AUTONEG is defined. This provides bit mask
for isolating the 10 or 100MBps speed indication.
config SAMA5_GMAC_PHYSR_100MBPS
hex "PHY 100Mbps Speed Value"
depends on SAMA5_GMAC_AUTONEG && !SAMA5_GMAC_PHYSR_ALTCONFIG
---help---
This must be provided if SAMA5_GMAC_AUTONEG is defined. This provides the value
of the speed bit(s) indicating 100MBps speed.
config SAMA5_GMAC_PHYSR_MODE
hex "PHY Mode Mask"
depends on SAMA5_GMAC_AUTONEG && !SAMA5_GMAC_PHYSR_ALTCONFIG
---help---
This must be provided if SAMA5_GMAC_AUTONEG is defined. This provide bit mask
for isolating the full or half duplex mode bits.
config SAMA5_GMAC_PHYSR_FULLDUPLEX
hex "PHY Full Duplex Mode Value"
depends on SAMA5_GMAC_AUTONEG && !SAMA5_GMAC_PHYSR_ALTCONFIG
---help---
This must be provided if SAMA5_GMAC_AUTONEG is defined. This provides the
value of the mode bits indicating full duplex mode.
config SAMA5_GMAC_PHYSR_ALTMODE
hex "PHY Mode Mask"
depends on SAMA5_GMAC_AUTONEG && SAMA5_GMAC_PHYSR_ALTCONFIG
---help---
This must be provided if SAMA5_GMAC_AUTONEG is defined. This provide bit mask
for isolating the speed and full/half duplex mode bits.
config SAMA5_GMAC_PHYSR_10HD
hex "10MBase-T Half Duplex Value"
depends on SAMA5_GMAC_AUTONEG && SAMA5_GMAC_PHYSR_ALTCONFIG
---help---
This must be provided if SAMA5_GMAC_AUTONEG is defined. This is the value
under the bit mask that represents the 10Mbps, half duplex setting.
config SAMA5_GMAC_PHYSR_100HD
hex "100Base-T Half Duplex Value"
depends on SAMA5_GMAC_AUTONEG && SAMA5_GMAC_PHYSR_ALTCONFIG
---help---
This must be provided if SAMA5_GMAC_AUTONEG is defined. This is the value
under the bit mask that represents the 100Mbps, half duplex setting.
config SAMA5_GMAC_PHYSR_10FD
hex "10Base-T Full Duplex Value"
depends on SAMA5_GMAC_AUTONEG && SAMA5_GMAC_PHYSR_ALTCONFIG
---help---
This must be provided if SAMA5_GMAC_AUTONEG is defined. This is the value
under the bit mask that represents the 10Mbps, full duplex setting.
config SAMA5_GMAC_PHYSR_100FD
hex "100Base-T Full Duplex Value"
depends on SAMA5_GMAC_AUTONEG && SAMA5_GMAC_PHYSR_ALTCONFIG
---help---
This must be provided if SAMA5_GMAC_AUTONEG is defined. This is the value
under the bit mask that represents the 100Mbps, full duplex setting.
endchoice # GMAC speed
endif # !SAMA5_GMAC_AUTONEG
config SAMA5_GMAC_REGDEBUG
bool "Register-Level Debug"

View file

@ -237,6 +237,7 @@
#define EMAC_INT_WOL (1 << 14) /* Bit 14: Wake On LAN */
#define EMAC_INT_ALL (0x00007cff)
#define EMAC_INT_UNUSED (0xffff8300)
/* Phy Maintenance Register */

View file

@ -583,6 +583,7 @@
#define GMAC_INT_WOL (1 << 28) /* Bit 28: Wake On LAN (not in IMR) */
#define GMAC_INT_ALL (0x17fcfcff)
#define GMAC_INT_UNUSED (0xe8030300)
/* PHY Maintenance Register */

View file

@ -1307,7 +1307,7 @@ static int sam_emac_interrupt(int irq, void *context)
tsr = sam_getreg(priv, SAM_EMAC_TSR);
imr = sam_getreg(priv, SAM_EMAC_IMR);
pending = isr & ~(imr | 0xffc300);
pending = isr & ~(imr | EMAC_INT_UNUSED);
nllvdbg("isr: %08x pending: %08x\n", isr, pending);
/* Check for the completion of a transmission. This should be done before
@ -2159,10 +2159,12 @@ static int sam_autonegotiate(struct sam_emac_s *priv)
nllvdbg("PHYID2: %04x PHY address: %02x\n", phyid2, priv->phyaddr);
if (phyid1 == MII_OUI_MSB &&
((phyid2 & MII_PHYID2_OUI) >> 10) == MII_OUI_LSB)
((phyid2 & MII_PHYID2_OUI_MASK) >> MII_PHYID2_OUI_SHIFT) == MII_OUI_LSB)
{
nllvdbg(" Vendor Model Number: %04x\n", ((phyid2 >> 4) & 0x3f));
nllvdbg(" Model Revision Number: %04x\n", (phyid2 & 7));
nllvdbg(" Vendor Model Number: %04x\n",
(phyid2 & MII_PHYID2_MODEL_MASK) >> MII_PHYID2_MODEL_SHIFT);
nllvdbg(" Model Revision Number: %04x\n",
(phyid2 & MII_PHYID2_REV_MASK) >> MII_PHYID2_REV_SHIFT);
}
else
{
@ -2570,6 +2572,12 @@ static void sam_txreset(struct sam_emac_s *priv)
txdesc[CONFIG_SAMA5_EMAC_NTXBUFFERS - 1].status =
EMACTXD_STA_USED | EMACTXD_STA_WRAP;
/* Flush the entire TX descriptor table to RAM */
cp15_clean_dcache((uintptr_t)txdesc,
(uintptr_t)txdesc +
CONFIG_SAMA5_EMAC_NTXBUFFERS * sizeof(struct emac_txdesc_s));
/* Set the Transmit Buffer Queue Pointer Register */
physaddr = sam_physramaddr((uintptr_t)txdesc);

View file

@ -103,84 +103,15 @@
# error "CONFIG_SAMA5_GMAC_PHYADDR must be defined in the NuttX configuration"
#endif
#if !defined(CONFIG_SAMA5_GMAC_GMII) && !defined(CONFIG_SAMA5_GMAC_RGMII)
# warning "Neither CONFIG_SAMA5_GMAC_GMII nor CONFIG_SAMA5_GMAC_RGMII defined"
#endif
#if defined(CONFIG_SAMA5_GMAC_GMII) && defined(CONFIG_SAMA5_GMAC_RGMII)
# error "Both CONFIG_SAMA5_GMAC_GMII and CONFIG_SAMA5_GMAC_RGMII defined"
#endif
#ifdef CONFIG_SAMA5_GMAC_AUTONEG
# ifndef CONFIG_SAMA5_GMAC_PHYSR
# error "CONFIG_SAMA5_GMAC_PHYSR must be defined in the NuttX configuration"
# endif
# ifdef CONFIG_SAMA5_GMAC_PHYSR_ALTCONFIG
# ifndef CONFIG_SAMA5_GMAC_PHYSR_ALTMODE
# error "CONFIG_SAMA5_GMAC_PHYSR_ALTMODE must be defined in the NuttX configuration"
# endif
# ifndef CONFIG_SAMA5_GMAC_PHYSR_10HD
# error "CONFIG_SAMA5_GMAC_PHYSR_10HD must be defined in the NuttX configuration"
# endif
# ifndef CONFIG_SAMA5_GMAC_PHYSR_100HD
# error "CONFIG_SAMA5_GMAC_PHYSR_100HD must be defined in the NuttX configuration"
# endif
# ifndef CONFIG_SAMA5_GMAC_PHYSR_10FD
# error "CONFIG_SAMA5_GMAC_PHYSR_10FD must be defined in the NuttX configuration"
# endif
# ifndef CONFIG_SAMA5_GMAC_PHYSR_100FD
# error "CONFIG_SAMA5_GMAC_PHYSR_100FD must be defined in the NuttX configuration"
# endif
# else
# ifndef CONFIG_SAMA5_GMAC_PHYSR_SPEED
# error "CONFIG_SAMA5_GMAC_PHYSR_SPEED must be defined in the NuttX configuration"
# endif
# ifndef CONFIG_SAMA5_GMAC_PHYSR_100MBPS
# error "CONFIG_SAMA5_GMAC_PHYSR_100MBPS must be defined in the NuttX configuration"
# endif
# ifndef CONFIG_SAMA5_GMAC_PHYSR_MODE
# error "CONFIG_SAMA5_GMAC_PHYSR_MODE must be defined in the NuttX configuration"
# endif
# ifndef CONFIG_SAMA5_GMAC_PHYSR_FULLDUPLEX
# error "CONFIG_SAMA5_GMAC_PHYSR_FULLDUPLEX must be defined in the NuttX configuration"
# endif
# endif
#endif
/* PHY definitions */
#ifdef SAMA5_GMAC_PHY_KSZ90x1
# define GMII_OUI_MSB 0x0022
# define GMII_OUI_LSB 0x05
# define GMII_OUI_LSB GMII_PHYID2_OUI(5)
#else
# error Unknown PHY
#endif
#ifdef CONFIG_SAMA5_GMAC_PHYSR_ALTCONFIG
# define PHYSR_MODE(sr) ((sr) & CONFIG_SAMA5_GMAC_PHYSR_ALTMODE)
# define PHYSR_ISMODE(sr,m) (PHYSR_MODE(sr) == (m))
# define PHYSR_IS10HDX(sr) PHYSR_ISMODE(sr,CONFIG_SAMA5_GMAC_PHYSR_10HD)
# define PHYSR_IS100HDX(sr) PHYSR_ISMODE(sr,CONFIG_SAMA5_GMAC_PHYSR_100HD)
# define PHYSR_IS10FDX(sr) PHYSR_ISMODE(sr,CONFIG_SAMA5_GMAC_PHYSR_10FD)
# define PHYSR_IS100FDX(sr) PHYSR_ISMODE(sr,CONFIG_SAMA5_GMAC_PHYSR_100FD)
#else
# define PHYSR_MODESPEED (CONFIG_PHYSR_MODE | CONFIG_PHYSR_SPEED)
# define PHYSR_10HDX (0)
# define PHYSR_100HDX (CONFIG_PHYSR_100MBPS)
# define PHYSR_10FDX (CONFIG_PHYSR_FULLDUPLEX)
# define PHYSR_100FDX (CONFIG_PHYSR_FULLDUPLEX | CONFIG_PHYSR_100MBPS)
# define PHYSR_IS10HDX(sr) (((sr) & PHYSR_MODESPEED) == PHYSR_10HDX)
# define PHYSR_IS100HDX(sr) (((sr) & PHYSR_MODESPEED) == PHYSR_100HDX)
# define PHYSR_IS10FDX(sr) (((sr) & PHYSR_MODESPEED) == PHYSR_10FDX)
# define PHYSR_IS100FDX(sr) (((sr) & PHYSR_MODESPEED) == PHYSR_100FDX)
#endif
/* GMAC buffer sizes, number of buffers, and number of descriptors.
*
* REVISIT: The CONFIG_NET_MULTIBUFFER might be useful. It might be possible
@ -384,8 +315,11 @@ static int sam_phyread(struct sam_gmac_s *priv, uint8_t phyaddr,
uint8_t regaddr, uint16_t *phyval);
static int sam_phywrite(struct sam_gmac_s *priv, uint8_t phyaddr,
uint8_t regaddr, uint16_t phyval);
#ifdef CONFIG_SAMA5_GMAC_AUTONEG
static int sam_autonegotiate(struct sam_gmac_s *priv);
static bool sam_linkup(struct sam_gmac_s *priv);
#else
static void sam_linkspeed(struct sam_gmac_s *priv);
#endif
static void sam_mdcclock(struct sam_gmac_s *priv);
static int sam_phyinit(struct sam_gmac_s *priv);
@ -677,7 +611,7 @@ static void sam_buffer_free(struct sam_gmac_s *priv)
* Function: sam_transmit
*
* Description:
* Start hardware transmission. Called either from the txdone interrupt
* Start hardware transmission. Called either from the TX done interrupt
* handling or from watchdog based polling.
*
* Parameters:
@ -907,7 +841,7 @@ static void sam_dopoll(struct sam_gmac_s *priv)
static int sam_recvframe(struct sam_gmac_s *priv)
{
struct gmac_rxdesc_s *rxdesc;
volatile struct gmac_rxdesc_s *rxdesc;
struct uip_driver_s *dev;
const uint8_t *src;
uint8_t *dest;
@ -1308,7 +1242,7 @@ static int sam_gmac_interrupt(int irq, void *context)
tsr = sam_getreg(priv, SAM_GMAC_TSR);
imr = sam_getreg(priv, SAM_GMAC_IMR);
pending = isr & ~(imr | 0xffc300);
pending = isr & ~(imr | GMAC_INT_UNUSED);
nllvdbg("isr: %08x pending: %08x\n", isr, pending);
/* Check for the completion of a transmission. This should be done before
@ -1373,6 +1307,22 @@ static int sam_gmac_interrupt(int irq, void *context)
clrbits |= GMAC_TSR_UND;
}
/* Check for HRESP not OK */
if ((tsr & GMAC_TSR_HRESP) != 0)
{
nlldbg("ERROR: HRESP not OK: %08x\n", tsr);
clrbits |= GMAC_TSR_HRESP;
}
/* Check for Late Collitions (LCO) */
if ((tsr & GMAC_TSR_LCO) != 0)
{
nlldbg("ERROR: Late collision: %08x\n", tsr);
clrbits |= GMAC_TSR_LCO;
}
/* Clear status */
sam_putreg(priv, SAM_GMAC_TSR, clrbits);
@ -1427,6 +1377,14 @@ static int sam_gmac_interrupt(int irq, void *context)
clrbits |= GMAC_RSR_BNA;
}
/* Check for HRESP not OK (HNO)*/
if ((rsr & GMAC_RSR_HNO) != 0)
{
nlldbg("ERROR: HRESP not OK: %08x\n", rsr);
clrbits |= GMAC_RSR_HNO;
}
/* Clear status */
sam_putreg(priv, SAM_GMAC_RSR, clrbits);
@ -1574,6 +1532,7 @@ static int sam_ifup(struct uip_driver_s *dev)
/* Initialize for PHY access */
sam_phyreset(priv);
ret = sam_phyinit(priv);
if (ret < 0)
{
@ -1581,6 +1540,7 @@ static int sam_ifup(struct uip_driver_s *dev)
return ret;
}
#ifdef CONFIG_SAMA5_GMAC_AUTONEG
/* Auto Negotiate, working in RMII mode */
ret = sam_autonegotiate(priv);
@ -1589,9 +1549,11 @@ static int sam_ifup(struct uip_driver_s *dev)
nlldbg("ERROR: sam_autonegotiate failed: %d\n", ret);
return ret;
}
#else
/* Just force the configured link speed */
while (sam_linkup(priv) == 0);
nllvdbg("Link detected \n");
sam_linkspeed(priv);
#endif
/* Enable normal MAC operation */
@ -1791,22 +1753,21 @@ static void sam_phydump(struct sam_gmac_s *priv)
sam_enablemdio(priv);
#ifdef CONFIG_SAMA5_GMAC_RGMII
nllvdbg("RMII Registers (Address %02x)\n", priv->phyaddr);
#else /* defined(CONFIG_SAMA5_GMAC_GMII) */
nllvdbg("MII Registers (Address %02x)\n", priv->phyaddr);
#endif
nllvdbg("GMII Registers (Address %02x)\n", priv->phyaddr);
sam_phyread(priv, priv->phyaddr, GMII_MCR, &phyval);
nllvdbg(" MCR: %04x\n", phyval);
nllvdbg(" MCR: %04x\n", phyval);
sam_phyread(priv, priv->phyaddr, GMII_MSR, &phyval);
nllvdbg(" MSR: %04x\n", phyval);
nllvdbg(" MSR: %04x\n", phyval);
sam_phyread(priv, priv->phyaddr, GMII_ADVERTISE, &phyval);
nllvdbg(" ADVERTISE: %04x\n", phyval);
nllvdbg(" ADVERTISE: %04x\n", phyval);
sam_phyread(priv, priv->phyaddr, GMII_LPA, &phyval);
nllvdbg(" LPR: %04x\n", phyval);
sam_phyread(priv, priv->phyaddr, CONFIG_SAMA5_GMAC_PHYSR, &phyval);
nllvdbg(" PHYSR: %04x\n", phyval);
nllvdbg(" LPR: %04x\n", phyval);
sam_phyread(priv, priv->phyaddr, GMII_1000BTCR, &phyval);
nllvdbg(" 1000BTCR: %04x\n", phyval);
sam_phyread(priv, priv->phyaddr, GMII_1000BTSR, &phyval);
nllvdbg(" 1000BTSR: %04x\n", phyval);
sam_phyread(priv, priv->phyaddr, GMII_ESTATUS, &phyval);
nllvdbg(" ESTATUS: %04x\n", phyval);
/* Disable management port */
@ -1831,7 +1792,7 @@ static void sam_phydump(struct sam_gmac_s *priv)
static void sam_enablemdio(struct sam_gmac_s *priv)
{
uint32_t regval;
uint32_t ncr;
uint32_t enables;
/* Enable management port */
@ -2042,8 +2003,6 @@ static int sam_phyfind(struct sam_gmac_s *priv, uint8_t *phyaddr)
{
nllvdbg(" PHYID1: %04x PHY addr: %d\n", phyval, candidate);
*phyaddr = candidate;
sam_phyread(priv, candidate, CONFIG_SAMA5_GMAC_PHYSR, &phyval);
nllvdbg(" PHYSR: %04x PHY addr: %d\n", phyval, candidate);
}
/* Disable management port */
@ -2173,15 +2132,19 @@ static int sam_phywrite(struct sam_gmac_s *priv, uint8_t phyaddr,
*
****************************************************************************/
#ifdef CONFIG_SAMA5_GMAC_AUTONEG
static int sam_autonegotiate(struct sam_gmac_s *priv)
{
uint32_t regval;
uint32_t ncr;
uint32_t linkmode;
uint16_t phyval;
uint16_t phyid1;
uint16_t phyid2;
uint16_t mcr;
uint16_t msr;
uint16_t advertise;
uint16_t lpa;
uint16_t btcr;
uint16_t btsr;
int timeout;
int ret;
@ -2189,58 +2152,57 @@ static int sam_autonegotiate(struct sam_gmac_s *priv)
sam_enablemdio(priv);
/* Verify tht we can read the PHYID register */
/* Read the MS bits of the OUI from Pthe PHYID1 register */
ret = sam_phyread(priv, priv->phyaddr, GMII_PHYID1, &phyid1);
if (ret < 0)
{
nlldbg("ERROR: Failed to read PHYID1\n");
nlldbg("ERROR: Failed to read PHYID1 register\n");
goto errout;
}
nllvdbg("PHYID1: %04x PHY address: %02x\n", phyid1, priv->phyaddr);
/* Read the LS bits of the OUI from Pthe PHYID2 register */
ret = sam_phyread(priv, priv->phyaddr, GMII_PHYID2, &phyid2);
if (ret < 0)
{
nlldbg("ERROR: Failed to read PHYID2\n");
nlldbg("ERROR: Failed to read PHYID2 register\n");
goto errout;
}
nllvdbg("PHYID2: %04x PHY address: %02x\n", phyid2, priv->phyaddr);
if (phyid1 == GMII_OUI_MSB &&
((phyid2 & GMII_PHYID2_OUI) >> 10) == GMII_OUI_LSB)
(phyid2 & GMII_PHYID2_OUI_MASK) == GMII_OUI_LSB)
{
nllvdbg(" Vendor Model Number: %04x\n", ((phyid2 >> 4) & 0x3f));
nllvdbg(" Model Revision Number: %04x\n", (phyid2 & 7));
nllvdbg(" Vendor Model Number: %04x\n",
(phyid2 & GMII_PHYID2_MODEL_MASK) >> GMII_PHYID2_MODEL_SHIFT);
nllvdbg(" Model Revision Number: %04x\n",
(phyid2 & GMII_PHYID2_REV_MASK) >> GMII_PHYID2_REV_SHIFT);
}
else
{
nlldbg("ERROR: PHY not recognized\n");
nlldbg("ERROR: PHY not recognized: PHYID1=%04x PHYID2=%04x\n",
phyid1, phyid2);
}
/* Setup control register */
#ifdef SAMA5_GMAC_PHY_KSZ90x1
/* Set up the KSZ9020/31 PHY */
ret = sam_phyread(priv, priv->phyaddr, GMII_MCR, &mcr);
if (ret < 0)
{
nlldbg("ERROR: Failed to read MCR\n");
goto errout;
}
phyval = GMII_KSZ90x1_RCCPSR | GMII_ERCR_WRITE;
sam_phywrite(priv, priv->phyaddr, GMII_ERCR, phyval);
sam_phywrite(priv, priv->phyaddr, GMII_ERDWR, 0xf2f4);
mcr &= ~GMII_MCR_ANENABLE; /* Remove autonegotiation enable */
mcr &= ~(GMII_MCR_LOOPBACK | GMII_MCR_PDOWN);
mcr |= GMII_MCR_ISOLATE; /* Electrically isolate PHY */
phyval = GMII_KSZ90x1_RRDPSR | GMII_ERCR_WRITE;
sam_phywrite(priv, priv->phyaddr, GMII_ERCR, phyval);
sam_phywrite(priv, priv->phyaddr, GMII_ERDWR, 0x2222);
ret = sam_phywrite(priv, priv->phyaddr, GMII_MCR, mcr);
if (ret < 0)
{
nlldbg("ERROR: Failed to write MCR\n");
goto errout;
}
ret = sam_phywrite(priv, priv->phyaddr, GMII_KSZ90x1_ICS, 0xff00);
#endif
/* Set the Auto_negotiation Advertisement Register MII advertising for
/* Set the Auto_negotiation Advertisement Register, MII advertising for
* Next page 100BaseTxFD and HD, 10BaseTFD and HD, IEEE 802.3
*/
@ -2251,56 +2213,65 @@ static int sam_autonegotiate(struct sam_gmac_s *priv)
ret = sam_phywrite(priv, priv->phyaddr, GMII_ADVERTISE, advertise);
if (ret < 0)
{
nlldbg("ERROR: Failed to write ANAR\n");
nlldbg("ERROR: Failed to write ADVERTISE register\n");
goto errout;
}
/* Read and modify control register */
/* Modify the 1000Base-T control register to advertise 1000Base-T full
* and half duplex support.
*/
ret = sam_phyread(priv, priv->phyaddr, GMII_MCR, &mcr);
ret = sam_phyread(priv, priv->phyaddr, GMII_1000BTCR, &btcr);
if (ret < 0)
{
nlldbg("ERROR: Failed to read MCR\n");
nlldbg("ERROR: Failed to read 1000BTCR register: %d\n", ret);
goto errout;
}
mcr |= (GMII_MCR_SPEED100 | GMII_MCR_ANENABLE | GMII_MCR_FULLDPLX);
ret = sam_phywrite(priv, priv->phyaddr, GMII_MCR, mcr);
btcr |= GMII_1000BTCR_1000BASETFULL | GMII_1000BTCR_1000BASETHALF;
ret = sam_phywrite(priv, priv->phyaddr, GMII_1000BTCR, btcr);
if (ret < 0)
{
nlldbg("ERROR: Failed to write MCR\n");
nlldbg("ERROR: Failed to write 1000BTCR register: %d\n", ret);
goto errout;
}
/* Restart Auto_negotiation */
mcr |= GMII_MCR_ANRESTART;
mcr &= ~GMII_MCR_ISOLATE;
ret = sam_phywrite(priv, priv->phyaddr, GMII_MCR, mcr);
ret = sam_phyread(priv, priv->phyaddr, GMII_MCR, &phyval);
if (ret < 0)
{
nlldbg("ERROR: Failed to write MCR\n");
nlldbg("ERROR: Failed to read MCR register: %d\n", ret);
goto errout;
}
nllvdbg(" MCR: %04x\n", mcr);
phyval |= GMII_MCR_ANRESTART;
/* Check AutoNegotiate complete */
ret = sam_phywrite(priv, priv->phyaddr, GMII_MCR, phyval);
if (ret < 0)
{
nlldbg("ERROR: Failed to write MCR register: %d\n", ret);
goto errout;
}
nllvdbg(" MCR: 0x%X\n", phyval);
/* Wait for autonegotion to complete */
timeout = 0;
for (;;)
{
ret = sam_phyread(priv, priv->phyaddr, GMII_MSR, &msr);
ret = sam_phyread(priv, priv->phyaddr, GMII_MSR, &phyval);
if (ret < 0)
{
nlldbg("ERROR: Failed to read MSR\n");
nlldbg("ERROR: Failed to read MSR register: %d\n", ret);
goto errout;
}
/* Completed successfully? */
/* Check for completion of autonegotiation */
if ((msr & GMII_MSR_ANEGCOMPLETE) != 0)
if ((phyval & GMII_MSR_ANEGCOMPLETE) != 0)
{
/* Yes.. break out of the loop */
@ -2319,55 +2290,110 @@ static int sam_autonegotiate(struct sam_gmac_s *priv)
}
}
/* Get the AutoNeg Link partner base page */
/* Setup the GMAC local link speed */
ret = sam_phyread(priv, priv->phyaddr, GMII_LPA, &lpa);
if (ret < 0)
linkmode = 0; /* 10Base-T Half-Duplex */
timeout = 0;
for (;;)
{
nlldbg("ERROR: Failed to read ANLPAR\n");
goto errout;
ret = sam_phyread(priv, priv->phyaddr, GMII_1000BTSR, &btsr);
if (ret == 0)
{
nlldbg("ERROR: Failed to read 1000BTSR register: %d\n", ret);
goto errout;
}
/* Setup the GMAC link speed */
if ((btsr & GMII_1000BTSR_LP1000BASETFULL) != 0 &&
(btcr & GMII_1000BTCR_1000BASETHALF) != 0)
{
/* Set RGMII for 1000BaseTX and Full Duplex */
linkmode = (GMAC_NCFGR_FD | GMAC_NCFGR_GBE);
break;
}
else if ((btsr & GMII_1000BTSR_LP1000BASETHALF) != 0 &&
(btcr & GMII_1000BTCR_1000BASETFULL) != 0)
{
/* Set RGMII for 1000BaseT and Half Duplex */
linkmode = GMAC_NCFGR_GBE;
break;
}
/* Get the Autonegotiation Link partner base page */
ret = sam_phyread(priv, priv->phyaddr, GMII_LPA, &lpa);
if (ret == 0)
{
nlldbg("ERROR: Failed to read LPA register: %d\n", ret);
goto errout;
}
/* Setup the GMAC link speed */
if ((advertise & GMII_ADVERTISE_100BASETXFULL) != 0 &&
(lpa & GMII_LPA_100BASETXFULL) != 0)
{
/* Set RGMII for 100BaseTX and Full Duplex */
linkmode = (GMAC_NCFGR_SPD | GMAC_NCFGR_FD);
break;
}
else if ((advertise & GMII_ADVERTISE_10BASETXFULL) != 0 &&
(lpa & GMII_LPA_10BASETXFULL) != 0)
{
/* Set RGMII for 10BaseT and Full Duplex */
linkmode = GMAC_NCFGR_FD;
break;
}
else if ((advertise & GMII_ADVERTISE_100BASETXHALF) != 0 &&
(lpa & GMII_LPA_100BASETXHALF) != 0)
{
/* Set RGMII for 100BaseTX and half Duplex */
linkmode = GMAC_NCFGR_SPD;
break;
}
else if ((advertise & GMII_ADVERTISE_10BASETXHALF) != 0 &&
(lpa & GMII_LPA_10BASETXHALF) != 0)
{
/* Set RGMII for 10BaseT and half Duplex */
break;
}
/* Check for a timeout */
if (++timeout >= PHY_RETRY_MAX)
{
nlldbg("ERROR: TimeOut\n");
sam_phydump(priv);
ret = -ETIMEDOUT;
goto errout;
}
}
/* Setup the GMAC link speed */
/* Disable RX and TX momentarily */
ncr = sam_getreg(priv, SAM_GMAC_NCR);
sam_putreg(priv, SAM_GMAC_NCR, ncr & ~(GMAC_NCR_RXEN | GMAC_NCR_TXEN));
/* Modify the NCFGR register based on the negotiated speed and duplex */
regval = sam_getreg(priv, SAM_GMAC_NCFGR);
regval &= (GMAC_NCFGR_SPD | GMAC_NCFGR_FD);
if (((advertise & lpa) & GMII_ADVERTISE_100BASETXFULL) != 0)
{
/* Set MII for 100BaseTX and Full Duplex */
regval |= (GMAC_NCFGR_SPD | GMAC_NCFGR_FD);
}
else if (((advertise & lpa) & GMII_ADVERTISE_10BASETXFULL) != 0)
{
/* Set MII for 10BaseT and Full Duplex */
regval |= GMAC_NCFGR_FD;
}
else if (((advertise & lpa) & GMII_ADVERTISE_100BASETXHALF) != 0)
{
/* Set MII for 100BaseTX and half Duplex */
regval |= GMAC_NCFGR_SPD;
}
#if 0
else if (((advertise & lpa) & GMII_ADVERTISE_10BASETXHALF) != 0)
{
/* set MII for 10BaseT and half Duplex */
}
#endif
regval &= ~(GMAC_NCFGR_SPD | GMAC_NCFGR_FD | GMAC_NCFGR_GBE);
regval |= linkmode;
sam_putreg(priv, SAM_GMAC_NCFGR, regval);
sam_putreg(priv, SAM_GMAC_NCR, ncr);
/* Select RMII/MII */
/* Enable RGMII enable */
regval = sam_getreg(priv, SAM_GMAC_UR);
#ifdef CONFIG_SAMA5_GMAC_RGMII
regval = sam_getreg(priv, SAM_GMAC_UR);
regval |= GMAC_UR_RGMII;
#else /* defined(CONFIG_SAMA5_GMAC_GMII) */
regval &= ~GMAC_UR_RGMII;
#endif
sam_putreg(priv, SAM_GMAC_UR, regval);
errout:
@ -2376,100 +2402,53 @@ errout:
sam_disablemdio(priv);
return ret;
}
#endif
/****************************************************************************
* Function: sam_linkup
* Function: sam_linkspeed
*
* Description:
* Check if the link is up
* If autonegotiation is not configured, then just force the configuration
* mode
*
* Parameters:
* priv - A reference to the private driver state structure
*
* Returned Value:
* true: The link is up
* None
*
****************************************************************************/
static bool sam_linkup(struct sam_gmac_s *priv)
#ifndef CONFIG_SAMA5_GMAC_AUTONEG
statoc void sam_linkspeed(struct sam_gmac_s *priv)
{
uint32_t regval;
uint16_t msr;
uint16_t physr;
bool linkup = false;
int ret;
uint32_t ncr;
/* Enable management port */
/* Disable RX and TX momentarily */
sam_enablemdio(priv);
ncr = sam_getreg(priv, SAM_GMAC_NCR);
sam_putreg(priv, SAM_GMAC_NCR, ncr & ~(GMAC_NCR_RXEN | GMAC_NCR_TXEN));
/* Read the PHY MSR register */
ret = sam_phyread(priv, priv->phyaddr, GMII_MSR, &msr);
if (ret < 0)
{
nlldbg("ERROR: Failed to read MSR: %d\n", ret);
goto errout;
}
if ((msr & GMII_MSR_LINKSTATUS) == 0)
{
nlldbg("ERROR: MSR LinkStatus: %04x\n", msr);
goto errout;
}
/* Re-configure Link speed */
ret = sam_phyread(priv, priv->phyaddr, CONFIG_SAMA5_GMAC_PHYSR, &physr);
if (ret < 0)
{
nlldbg("ERROR: Failed to read PHYSR: %d\n", ret);
goto errout;
}
/* Modify the NCFGR register based on the configured speed and duplex */
regval = sam_getreg(priv, SAM_GMAC_NCFGR);
regval &= ~(GMAC_NCFGR_SPD | GMAC_NCFGR_FD);
regval &= ~(GMAC_NCFGR_SPD | GMAC_NCFGR_FD | GMAC_NCFGR_GBE);
if ((msr & GMII_MSR_100BASETXFULL) != 0 && PHYSR_IS100FDX(physr))
{
/* Set GMAC for 100BaseTX and Full Duplex */
regval |= (GMAC_NCFGR_SPD | GMAC_NCFGR_FD);
}
else if ((msr & GMII_MSR_10BASETXFULL) != 0 && PHYSR_IS10FDX(physr))
{
/* Set MII for 10BaseT and Full Duplex */
regval |= GMAC_NCFGR_FD;
}
else if ((msr & GMII_MSR_100BASETXHALF) != 0 && PHYSR_IS100HDX(physr))
{
/* Set MII for 100BaseTX and Half Duplex */
regval |= GMAC_NCFGR_SPD;
}
#if 0
else if ((msr & GMII_MSR_10BASETXHALF) != 0 && PHYSR_IS10HDX(physr))
{
/* Set MII for 10BaseT and Half Duplex */
}
#ifdef SAMA5_GMAC_ETHFD
regval |= GMAC_NCFGR_FD;
#endif
sam_putreg(priv, SAM_GMAC_NCFGR, regval);
#if defined(SAMA5_GMAC_ETH100MBPS)
regval |= GMAC_NCFGR_SPD;
#elif defined(SAMA5_GMAC_ETH1000MBPS) */
regval |= GMAC_NCFGR_GBE;
#endif
/* Start the GMAC transfers */
nllvdbg("Link is up\n");
linkup = true;
errout:
/* Disable management port */
sam_disablemdio(priv);
return linkup;
sam_puttreg(priv, SAM_GMAC_NCFGR, regval);
sam_putreg(priv, SAM_GMAC_NCR, ncr);
}
#endif
/****************************************************************************
* Function: sam_mdcclock
@ -2631,7 +2610,7 @@ static void sam_txreset(struct sam_gmac_s *priv)
/* Disable TX */
regval = sam_getreg(priv, SAM_GMAC_NCR);
regval = sam_getreg(priv, SAM_GMAC_NCR);
regval &= ~GMAC_NCR_TXEN;
sam_putreg(priv, SAM_GMAC_NCR, regval);
@ -2641,20 +2620,27 @@ static void sam_txreset(struct sam_gmac_s *priv)
priv->txtail = 0;
for (ndx = 0; ndx < CONFIG_SAMA5_GMAC_NTXBUFFERS; ndx++)
{
bufaddr = (uint32_t)(&(txbuffer[ndx * GMAC_TX_UNITSIZE]));
{
bufaddr = (uintptr_t)(&(txbuffer[ndx * GMAC_TX_UNITSIZE]));
/* Set the buffer address and mark the descriptor as in used by firmware */
/* Set the buffer address and mark the descriptor as in used by
* firmware.
*/
physaddr = sam_physramaddr(bufaddr);
txdesc[ndx].addr = physaddr;
txdesc[ndx].status = GMACTXD_STA_USED;
}
physaddr = sam_physramaddr(bufaddr);
txdesc[ndx].addr = physaddr;
txdesc[ndx].status = (uint32_t)GMACTXD_STA_USED;
}
/* Mark the final descriptor in the list */
txdesc[CONFIG_SAMA5_GMAC_NTXBUFFERS - 1].status =
GMACTXD_STA_USED | GMACTXD_STA_WRAP;
txdesc[CONFIG_SAMA5_GMAC_NTXBUFFERS - 1].status = GMACTXD_STA_USED | GMACTXD_STA_WRAP;
/* Flush the entire TX descriptor table to RAM */
cp15_clean_dcache((uintptr_t)txdesc,
(uintptr_t)txdesc +
CONFIG_SAMA5_GMAC_NTXBUFFERS * sizeof(struct gmac_txdesc_s));
/* Set the Transmit Buffer Queue Base Register */
@ -2682,7 +2668,7 @@ static void sam_rxreset(struct sam_gmac_s *priv)
{
struct gmac_rxdesc_s *rxdesc = priv->rxdesc;
uint8_t *rxbuffer = priv->rxbuffer;
uint32_t bufaddr;
uintptr_t bufaddr;
uint32_t physaddr;
uint32_t regval;
int ndx;
@ -2842,36 +2828,57 @@ static int sam_gmac_configure(struct sam_gmac_s *priv)
/* Clear all status bits in the receive status register. */
regval = (GMAC_RSR_RXOVR | GMAC_RSR_REC | GMAC_RSR_BNA);
regval = (GMAC_RSR_RXOVR | GMAC_RSR_REC | GMAC_RSR_BNA | GMAC_RSR_HNO);
sam_putreg(priv, SAM_GMAC_RSR, regval);
/* Clear all status bits in the transmit status register */
regval = (GMAC_TSR_UBR | GMAC_TSR_COL | GMAC_TSR_RLE | GMAC_TSR_TFC |
GMAC_TSR_TXCOMP | GMAC_TSR_UND);
regval = GMAC_TSR_UBR | GMAC_TSR_COL | GMAC_TSR_RLE | GMAC_TSR_TXGO |
GMAC_TSR_TFC | GMAC_TSR_TXCOMP | GMAC_TSR_UND | GMAC_TSR_HRESP |
GMAC_TSR_LCO;
sam_putreg(priv, SAM_GMAC_TSR, regval);
/* Clear any pending interrupts */
(void)sam_getreg(priv, SAM_GMAC_ISR);
/* Enable/disable the copy of data into the buffers, ignore broadcasts.
* Don't copy FCS.
/* Initial configuration:
*
* SPD = 0 : Assuming 1000Base-T full duplex
* FD = 1 : Assuming 1000Base-T full duplex
* DNVLAN = 0 : Don't discard non-VLAN frames
* JFRAME = 0 : Disable jumbo frames
* CAF : Depends on CONFIG_NET_PROMISCUOUS
* NBC : Depends on CONFIG_SAMA5_GMAC_NBC
* MTIHEN = 0 : Multicast hash disabled
* UNIHEN = 0 : Unicast hash disabled
* MAXFS = 0 : Disable receive 1536 byte frames
* GBE = 1 : Assuming 1000Base-T full duplex
* RTY = 0 : Disable retry test
* PEN = 1 : Pause frames disabled
* RXBUFO = 0 : No receive buffer offset
* LFERD = 0 : No length field error discard
* RFCS = 1 : Remove FCS
* CLK = 4 : Assuming MCK <= 160MHz
* DBW = 1 : 64-bit data bus with
* DCPF = 0 : Copy of pause frames not disabled
* RXCOEN = 0 : RX checksum offload disabled
* EFRHD = 0 : Disable frames received in half duple
* IRXFCS = 0 : Disable ignore RX FCX
* IPGSEN = 0 : IP stretch disabled
* RXBP = 0 : Receive bad pre-ambled disabled
* IRXER = 0 : Disable ignore IPG GXER
*/
regval = sam_getreg(priv, SAM_GMAC_NCFGR);
regval |= (GMAC_NCFGR_RFCS | GMAC_NCFGR_PEN);
regval = GMAC_NCFGR_FD | GMAC_NCFGR_GBE | GMAC_NCFGR_PEN |
GMAC_NCFGR_RFCS | GMAC_NCFGR_CLK_DIV64 | GMAC_NCFGR_DBW_64;
#ifdef CONFIG_NET_PROMISCUOUS
regval |= GMAC_NCFGR_CAF;
#else
regval &= ~GMAC_NCFGR_CAF;
regval |= GMAC_NCFGR_CAF;
#endif
#ifdef CONFIG_SAMA5_GMAC_NBC
regval |= GMAC_NCFGR_NBC;
#else
regval &= ~GMAC_NCFGR_NBC;
regval |= GMAC_NCFGR_NBC;
#endif
sam_putreg(priv, SAM_GMAC_NCFGR, regval);
@ -2889,9 +2896,12 @@ static int sam_gmac_configure(struct sam_gmac_s *priv)
/* Setup the interrupts for TX events, RX events, and error events */
regval = (GMAC_INT_RCOMP | GMAC_INT_RXUBR | GMAC_INT_TUR | GMAC_INT_RLEX |
GMAC_INT_TFC | GMAC_INT_TCOMP | GMAC_INT_ROVR | GMAC_INT_HRESP |
GMAC_INT_PFNZ | GMAC_INT_PTZ);
regval = GMAC_INT_MFS | GMAC_INT_RCOMP | GMAC_INT_RXUBR | GMAC_INT_TXUBR |
GMAC_INT_TUR | GMAC_INT_RLEX | GMAC_INT_TFC | GMAC_INT_TCOMP |
GMAC_INT_ROVR | GMAC_INT_HRESP | GMAC_INT_PFNZ | GMAC_INT_PTZ |
GMAC_INT_PFTR | GMAC_INT_EXINT | GMAC_INT_DRQFR | GMAC_INT_SFR |
GMAC_INT_DRQFT | GMAC_INT_SFT | GMAC_INT_PDRQFR | GMAC_INT_PDRSFR |
GMAC_INT_PDRQFT | GMAC_INT_PDRSFT;
sam_putreg(priv, SAM_GMAC_IER, regval);
return OK;
}