Skip to content
Snippets Groups Projects
lpc17_ethernet.c 56.9 KiB
Newer Older
   * addresses, and perfect station address matches.
   */

  regval = ETH_RXFLCTRL_PERFEN;
#if CONFIG_NET_BROADCAST
  regval |= ETH_RXFLCTRL_BCASTEN;
#endif
#if CONFIG_NET_MULTICAST
  RXFILTERCTRL |= (ETH_RXFLCTRL_MCASTEN | ETH_RXFLCTRL_UCASTEN);
#endif
#if CONFIG_NET_HASH
  RXFILTERCTRL |= (ETH_RXFLCTRL_MCASTHASHEN | ETH_RXFLCTRL_UCASTHASHEN);
#endif
  lpc17_putreg(regval, LPC17_ETH_RXFLCTRL);

  /* Clear any pending interrupts (shouldn't be any) */

  lpc17_putreg(0xffffffff, LPC17_ETH_INTCLR);

  /* Configure interrupts.  The Ethernet interrupt was attached during one-time
   * initialization, so we only need to set the interrupt priority, configure
   * interrupts, and enable them.
  /* Set the interrupt to the highest priority */

#ifdef CONFIG_ARCH_IRQPRIO
#if LM3S_NETHCONTROLLERS > 1
  (void)up_prioritize_irq(priv->irq, CONFIG_ETH_PRIORITY);
#else
  (void)up_prioritize_irq(LPC17_IRQ_ETH, CONFIG_ETH_PRIORITY);
#endif
#endif

  /* Enable Ethernet interrupts.  The way we do this depends on whether or
   * not Wakeup on Lan (WoL) has been configured.
   */

#if CONFIG_NET_WOL
  /* Configure WoL: Clear all receive filter WoLs and enable the perfect
   * match WoL interrupt.  We will wait until the Wake-up to finish
   * bringing things up.
   */

  lpc17_putreg(0xffffffff, LPC17_ETH_RXFLWOLCLR);
  lpc17_putreg(ETH_RXFLCTRL_RXFILEN, LPC17_ETH_RXRLCTRL);
  lpc17_putreg(ETH_INT_WKUP, LPC17_ETH_INTEN);
#else
  /* Otherwise, enable all interrupts except SOFTINT and WoL */

  lpc17_putreg((ETH_INT_RXOVR | ETH_INT_RXERR | ETH_INT_RXFIN | ETH_INT_RXDONE |
                ETH_INT_TXUNR | ETH_INT_TXERR | ETH_INT_TXFIN | ETH_INT_TXDONE),
               LPC17_ETH_INTEN);
  /* Set and activate a timer process */

  (void)wd_start(priv->lp_txpoll, LPC17_WDDELAY, lpc17_polltimer, 1, (uint32_t)priv);

  /* Finally, enable the Ethernet interrupt at the interrupt controller */
patacongo's avatar
patacongo committed
  priv->lp_ifup = true;
#if LM3S_NETHCONTROLLERS > 1
  up_enable_irq(priv->irq);
#else
  up_enable_irq(LPC17_IRQ_ETH);
  return OK;
}

/****************************************************************************
 * Function: lpc17_ifdown
 *
 * Description:
 *   NuttX Callback: Stop the interface.
 *
 * Parameters:
 *   dev  - Reference to the NuttX driver state structure
 *
 * Returned Value:
 *   None
 *
 * Assumptions:
 *
 ****************************************************************************/

static int lpc17_ifdown(struct uip_driver_s *dev)
{
  FAR struct lpc17_driver_s *priv = (FAR struct lpc17_driver_s *)dev->d_private;
  irqstate_t flags;

  /* Disable the Ethernet interrupt */

  flags = irqsave();
  up_disable_irq(LPC17_IRQ_ETH);

  /* Cancel the TX poll timer and TX timeout timers */

  wd_cancel(priv->lp_txpoll);
  wd_cancel(priv->lp_txtimeout);

  /* Reset the device */

patacongo's avatar
patacongo committed
  lpc17_ethreset(priv);
patacongo's avatar
patacongo committed
  priv->lp_ifup = false;
  irqrestore(flags);
  return OK;
}

/****************************************************************************
 * Function: lpc17_txavail
 *
 * Description:
 *   Driver callback invoked when new TX data is available.  This is a 
 *   stimulus perform an out-of-cycle poll and, thereby, reduce the TX
 *   latency.
 *
 * Parameters:
 *   dev  - Reference to the NuttX driver state structure
 *
 * Returned Value:
 *   None
 *
 * Assumptions:
 *   Called in normal user mode
 *
 ****************************************************************************/

static int lpc17_txavail(struct uip_driver_s *dev)
{
  FAR struct lpc17_driver_s *priv = (FAR struct lpc17_driver_s *)dev->d_private;
  irqstate_t flags;

  flags = irqsave();

  /* Ignore the notification if the interface is not yet up */

patacongo's avatar
patacongo committed
  if (priv->lp_ifup)
    {

      /* Check if there is room in the hardware to hold another outgoing packet. */

      /* If so, then poll uIP for new XMIT data */

      (void)uip_poll(&priv->lp_dev, lpc17_uiptxpoll);
    }

  irqrestore(flags);
  return OK;
}

/****************************************************************************
 * Function: lpc17_addmac
 *
 * Description:
 *   NuttX Callback: Add the specified MAC address to the hardware multicast
 *   address filtering
 *
 * Parameters:
 *   dev  - Reference to the NuttX driver state structure
 *   mac  - The MAC address to be added 
 *
 * Returned Value:
 *   None
 *
 * Assumptions:
 *
 ****************************************************************************/

#ifdef CONFIG_NET_IGMP
static int lpc17_addmac(struct uip_driver_s *dev, FAR const uint8_t *mac)
{
  FAR struct lpc17_driver_s *priv = (FAR struct lpc17_driver_s *)dev->d_private;

  /* Add the MAC address to the hardware multicast routing table */

  return OK;
}
#endif

/****************************************************************************
 * Function: lpc17_rmmac
 *
 * Description:
 *   NuttX Callback: Remove the specified MAC address from the hardware multicast
 *   address filtering
 *
 * Parameters:
 *   dev  - Reference to the NuttX driver state structure
 *   mac  - The MAC address to be removed 
 *
 * Returned Value:
 *   None
 *
 * Assumptions:
 *
 ****************************************************************************/

#ifdef CONFIG_NET_IGMP
static int lpc17_rmmac(struct uip_driver_s *dev, FAR const uint8_t *mac)
{
  FAR struct lpc17_driver_s *priv = (FAR struct lpc17_driver_s *)dev->d_private;

  /* Add the MAC address to the hardware multicast routing table */

  return OK;
}
#endif

patacongo's avatar
patacongo committed
/*******************************************************************************
 * Name: lpc17_showpins
 *
 * Description:
 *   Dump GPIO registers
 *
 * Parameters:
 *   None 
 *
 * Returned Value:
 *   None
 *
 * Assumptions:
 *
 *******************************************************************************/

#ifdef CONFIG_LPC17_ENET_REGDEBUG
static void lpc17_showpins(void)
{
  lpc17_dumpgpio(GPIO_PORT0|GPIO_PIN0, "P0[1-15]");
  lpc17_dumpgpio(GPIO_PORT0|GPIO_PIN16, "P0[16-31]");
}
#endif

/*******************************************************************************
 * Name: lpc17_showmii
 *
 * Description:
 *   Dump PHY MII registers
 *
 * Parameters:
 *   phyaddr - The device address where the PHY was discovered
 *
 * Returned Value:
 *   None
 *
 * Assumptions:
 *
 *******************************************************************************/

#if defined(CONFIG_LPC17_ENET_REGDEBUG) && defined(LPC17_HAVE_PHY)
static void lpc17_showmii(uint8_t phyaddr, const char *msg)
{
patacongo's avatar
patacongo committed
  dbg("PHY " LPC17_PHYNAME ": %s\n", msg);
  dbg("  MCR:       %04x\n", lpc17_getreg(MII_MCR));
  dbg("  MSR:       %04x\n", lpc17_getreg(MII_MSR));
  dbg("  ADVERTISE: %04x\n", lpc17_getreg(MII_ADVERTISE));
  dbg("  LPA:       %04x\n", lpc17_getreg(MII_LPA));
  dbg("  EXPANSION: %04x\n", lpc17_getreg(MII_EXPANSION));
patacongo's avatar
patacongo committed
#ifdef CONFIG_PHY_KS8721
patacongo's avatar
patacongo committed
  dbg("  10BTCR:    %04x\n", lpc17_getreg(MII_KS8721_10BTCR));
patacongo's avatar
patacongo committed
#endif
}
#endif

/****************************************************************************
 * Function: lpc17_phywrite
 *
 * Description:
 *   Write a value to an MII PHY register
 *
 * Parameters:
 *   phyaddr - The device address where the PHY was discovered
 *   regaddr - The address of the PHY register to be written
 *   phydata - The data to write to the PHY register 
 *
 * Returned Value:
 *   None
 *
 * Assumptions:
 *
 ****************************************************************************/

patacongo's avatar
patacongo committed
#ifdef LPC17_HAVE_PHY
static void lpc17_phywrite(uint8_t phyaddr, uint8_t regaddr, uint16_t phydata)
{
  uint32_t regval;

  /* Set PHY address and PHY register address */

  regval = ((uint32_t)phyaddr << ETH_MADR_PHYADDR_SHIFT) |
           ((uint32_t)regaddr << ETH_MADR_REGADDR_SHIFT);
  lpc17_putreg(regval, LPC17_ETH_MADR);

  /* Set up to write */

  lpc17_putreg(ETH_MCMD_WRITE, LPC17_ETH_MCMD);

  /* Write the register data to the PHY */

  lpc17_putreg((uint32_t)phydata, LPC17_ETH_MWTD);

  /* Wait for the PHY command to complete */

  while ((lpc17_getreg(LPC17_ETH_MIND) & ETH_MIND_BUSY) != 0);
}
patacongo's avatar
patacongo committed
#endif

/****************************************************************************
patacongo's avatar
patacongo committed
 * Function: lpc17_phyread
 *
 * Description:
 *   Read a value from an MII PHY register
 *
 * Parameters:
 *   phyaddr - The device address where the PHY was discovered
 *   regaddr - The address of the PHY register to be written
 *
 * Returned Value:
 *   Data read from the PHY register
 *
 * Assumptions:
 *
 ****************************************************************************/

patacongo's avatar
patacongo committed
#ifdef LPC17_HAVE_PHY
static uint16_t lpc17_phyread(uint8_t phyaddr, uint8_t regaddr)
{
  uint32_t regval;

  lpc17_putreg(0, LPC17_ETH_MCMD);

  /* Set PHY address and PHY register address */

  regval = ((uint32_t)phyaddr << ETH_MADR_PHYADDR_SHIFT) |
           ((uint32_t)regaddr << ETH_MADR_REGADDR_SHIFT);
  lpc17_putreg(regval, LPC17_ETH_MADR);

  /* Set up to read */

  lpc17_putreg(ETH_MCMD_READ, LPC17_ETH_MCMD);

  /* Wait for the PHY command to complete */

  while ((lpc17_getreg(LPC17_ETH_MIND) & (ETH_MIND_BUSY|ETH_MIND_NVALID)) != 0);
  lpc17_putreg(0, LPC17_ETH_MCMD);

  /* Return the PHY register data */

patacongo's avatar
patacongo committed
  return (uint16_t)(lpc17_getreg(LPC17_ETH_MRDD) & ETH_MRDD_MASK);
}
#endif

/****************************************************************************
 * Function: lpc17_phyreset
 *
 * Description:
 *   Reset the PHY
 *
 * Parameters:
 *   phyaddr - The device address where the PHY was discovered
 *
 * Returned Value:
 *   None
 *
 * Assumptions:
 *
 ****************************************************************************/

#ifdef LPC17_HAVE_PHY
static inline int lpc17_phyreset(uint8_t phyaddr)
{
  int32_t timeout;
  uint16_t phyreg;

  /* Reset the PHY.  Needs a minimal 50uS delay after reset. */

  lpc17_phywrite(phyaddr, MII_MCR, MII_MCR_RESET);

  /* Wait for a minimum of 50uS no matter what */

  up_udelay(50);

  /* The MCR reset bit is self-clearing.  Wait for it to be clear
   * indicating that the reset is complete.
   */

  for (timeout = MII_BIG_TIMEOUT; timeout > 0; timeout--)
    {
      phyreg = lpc17_phyread(phyaddr, MII_MCR);
      if ((phyreg & MII_MCR_RESET) == 0)
        {
          return OK;
        }
    }

patacongo's avatar
patacongo committed
  ndbg("Reset failed. MCR: %04x\n", phyreg);
patacongo's avatar
patacongo committed
  return -ETIMEDOUT;
}
#endif

/****************************************************************************
 * Function: lpc17_phyautoneg
 *
 * Description:
 *   Enable auto-negotiation.
 *
 * Parameters:
 *   phyaddr - The device address where the PHY was discovered
 *
 * Returned Value:
 *   None
 *
 * Assumptions:
 *   The adverisement regiser has already been configured.
 *
 ****************************************************************************/

#if defined(LPC17_HAVE_PHY) && defined(CONFIG_PHY_AUTONEG)
static inline int lpc17_phyautoneg(uint8_t phyaddr)
{
  int32_t timeout;
  uint16_t phyreg;

  /* Start auto-negotiation */

  lpc17_phywrite(phyaddr, MII_MCR, MII_MCR_ANENABLE | MII_MCR_ANRESTART);

  /* Wait for autonegotiation to complete */

  for (timeout = MII_BIG_TIMEOUT; timeout > 0; timeout--)
    {
      /* Check if auto-negotiation has completed */

      phyreg = lpc17_phyread(phyaddr, MII_MSR);
      if ((phyreg & (MII_MSR_LINKSTATUS | MII_MSR_ANEGCOMPLETE)) == 
          (MII_MSR_LINKSTATUS | MII_MSR_ANEGCOMPLETE))
        {
          /* Yes.. return success */

          return OK;
        }
    }

patacongo's avatar
patacongo committed
  ndbg("Auto-negotiation failed. MSR: %04x\n", phyreg);
patacongo's avatar
patacongo committed
  return -ETIMEDOUT;
}
#endif

/****************************************************************************
patacongo's avatar
patacongo committed
 * Function: lpc17_phymode
patacongo's avatar
patacongo committed
 *
 * Description:
patacongo's avatar
patacongo committed
 *   Set the PHY to operate at a selected speed/duplex mode.
patacongo's avatar
patacongo committed
 *
 * Parameters:
 *   phyaddr - The device address where the PHY was discovered
patacongo's avatar
patacongo committed
 *   mode - speed/duplex mode
patacongo's avatar
patacongo committed
 *
 * Returned Value:
 *   None
 *
 * Assumptions:
 *
 ****************************************************************************/

#ifdef LPC17_HAVE_PHY
patacongo's avatar
patacongo committed
static int lpc17_phymode(uint8_t phyaddr, uint8_t mode)
patacongo's avatar
patacongo committed
{
  int32_t timeout;
  uint16_t phyreg;

  /* Disable auto-negotiation and set fixed Speed and Duplex settings */

  phyreg = 0;
patacongo's avatar
patacongo committed
  if ((mode & LPC17_SPEED_MASK) ==  LPC17_SPEED_100)
patacongo's avatar
patacongo committed
    {
      phyreg = MII_MCR_SPEED100;
    }

patacongo's avatar
patacongo committed
  if ((mode & LPC17_DUPLEX_MASK) == LPC17_DUPLEX_FULL)
patacongo's avatar
patacongo committed
    {
      phyreg |= MII_MCR_FULLDPLX;
    }

  lpc17_phywrite(phyaddr, MII_MCR, phyreg);

  /* Then wait for the link to be established */

  for (timeout = MII_BIG_TIMEOUT; timeout > 0; timeout--)
    {
      phyreg = lpc17_phyread(phyaddr, MII_MSR);
      if (phyreg & MII_MSR_LINKSTATUS)
        {
          /* Yes.. return success */

          return OK;
        }
    }

patacongo's avatar
patacongo committed
  ndbg("Link failed. MSR: %04x\n", phyreg);
patacongo's avatar
patacongo committed
  return -ETIMEDOUT;
}
#endif

/****************************************************************************
 * Function: lpc17_phyinit
 *
 * Description:
 *   Initialize the PHY
 *
 * Parameters:
 *   priv - Pointer to EMAC device driver structure 
 *
 * Returned Value:
 *   None directly.  As a side-effect, it will initialize priv->lp_phyaddr
 *   and priv->lp_phymode.
patacongo's avatar
patacongo committed
 *
 * Assumptions:
 *
 ****************************************************************************/

#ifdef LPC17_HAVE_PHY
static inline int lpc17_phyinit(struct lpc17_driver_s *priv)
{
  unsigned int phyaddr;
  uint16_t phyreg;
  uint32_t regval;
  int ret;

  /* MII configuration: host clocked divided per board.h, no suppress
   * preambl,e no scan increment.
   */

  lpc17_putreg(ETH_MCFG_CLKSEL_DIV, LPC17_ETH_MCFG);
  lpc17_putreg(0, LPC17_ETH_MCMD);

  /* Enter RMII mode and select 100 MBPS support */

  lpc17_putreg(ETH_CMD_RMII, LPC17_ETH_CMD);
  lpc17_putreg(ETH_SUPP_SPEED, LPC17_ETH_SUPP);

  /* Find PHY Address.  Because controller has a pull-up and the
   * PHY have pull-down resistors on RXD lines some times the PHY
   * latches different at different addresses.
   */

  for (phyaddr = 1; phyaddr < 32; phyaddr++)
    {
       /* Check if we can see the selected device ID at this
        * PHY address.
        */

       phyreg = (unsigned int)lpc17_phyread(phyaddr, MII_PHYID1);
       if (phyreg == LPC17_PHYID1)
        {
          phyreg = lpc17_phyread(phyaddr, MII_PHYID2);
          if (phyreg  == LPC17_PHYID2)
            {
              break;
            }
        }
    }
patacongo's avatar
patacongo committed
  nvdbg("phyaddr: %d\n", phyaddr);
patacongo's avatar
patacongo committed

  /* Check if the PHY device address was found */

  if (phyaddr > 31)
    {
      /* Failed to find PHY at any location */

      return -ENODEV;
    }

  /* Save the discovered PHY device address */

  priv->lp_phyaddr = phyaddr;

  /* Reset the PHY */

  ret = lpc17_phyreset(phyaddr);
  if (ret < 0)
    {
      return ret;
    }
  lpc17_showmii(phyaddr, "After reset");

  /* Check for preamble suppression support */

  phyreg = lpc17_phyread(phyaddr, MII_MSR);
  if ((phyreg & MII_MSR_MFRAMESUPPRESS) != 0)
    {
      /* The PHY supports preamble suppression */

      regval  = lpc17_getreg(LPC17_ETH_MCFG);
      regval |= ETH_MCFG_SUPPRE;
      lpc17_putreg(regval, LPC17_ETH_MCFG);
    }

  /* Are we configured to do auto-negotiation? */

#ifdef CONFIG_PHY_AUTONEG
  /* Setup the Auto-negotiation advertisement: 100 or 10, and HD or FD */

  lpc17_phywrite(phyaddr, MII_ADVERTISE, 
                 (MII_ADVERTISE_100BASETXFULL | MII_ADVERTISE_100BASETXHALF |
                  MII_ADVERTISE_10BASETXFULL  | MII_ADVERTISE_10BASETXHALF  |
                  MII_ADVERTISE_CSMA));
patacongo's avatar
patacongo committed

  /* Then perform the auto-negotiation */

patacongo's avatar
patacongo committed
  ret = lpc17_phyautoneg(phyaddr);
  if (ret < 0)
    {
      return ret;
    }
#else
  /* Set up the fixed PHY configuration */

patacongo's avatar
patacongo committed
  ret = lpc17_phymode(phyaddr, LPC17_MODE_DEFLT);
patacongo's avatar
patacongo committed
  if (ret < 0)
    {
      return ret;
    }
#endif

  /* The link is established */

  lpc17_showmii(phyaddr, "After link established");

  /* Check configuration */

#ifdef CONFIG_PHY_KS8721
  phyreg = lpc17_phyread(phyaddr, MII_KS8721_10BTCR);

  switch (phyreg & KS8721_10BTCR_MODE_MASK)
    {
      case KS8721_10BTCR_MODE_10BTHD:  /* 10BASE-T half duplex */
patacongo's avatar
patacongo committed
        priv->lp_mode = LPC17_10BASET_HD;
patacongo's avatar
patacongo committed
        lpc17_putreg(0, LPC17_ETH_SUPP);
        break;
      case KS8721_10BTCR_MODE_100BTHD: /* 100BASE-T half duplex */
patacongo's avatar
patacongo committed
        priv->lp_mode = LPC17_100BASET_HD;
patacongo's avatar
patacongo committed
        break;
      case KS8721_10BTCR_MODE_10BTFD: /* 10BASE-T full duplex */
patacongo's avatar
patacongo committed
        priv->lp_mode = LPC17_10BASET_FD;
patacongo's avatar
patacongo committed
        lpc17_putreg(0, LPC17_ETH_SUPP);
        break;
      case KS8721_10BTCR_MODE_100BTFD: /* 100BASE-T full duplex */
patacongo's avatar
patacongo committed
        priv->lp_mode = LPC17_100BASET_FD;
patacongo's avatar
patacongo committed
        break;
      default:
patacongo's avatar
patacongo committed
        dbg("Unrecognized mode: %04x\n", phyreg);
patacongo's avatar
patacongo committed
        return -ENODEV;
    }
patacongo's avatar
patacongo committed
#else
#  warning "PHY Unknown: speed and duplex are bogus"
patacongo's avatar
patacongo committed
#endif

patacongo's avatar
patacongo committed
  ndbg("%dBase-T %s duplex\n",
       priv->lp_mode & LPC17_SPEED_MASK ==  LPC17_SPEED_100 ? 100 : 10,
       priv->lp_mode & LPC17_DUPLEX_MASK == LPC17_DUPLEX_FULL ?"full" : "half");
patacongo's avatar
patacongo committed
  /* Disable auto-configuration.  Set the fixed speed/duplex mode.
   * (probably more than little redundant).
   */
patacongo's avatar
patacongo committed
  ret = lpc17_phymode(phyaddr, LPC17_MODE_DEFLT);
  lpc17_showmii(phyaddr, "After final configuration");
  return ret;
}
#else
static inline int lpc17_phyinit(struct lpc17_driver_s *priv)
{
  priv->lp_mode = LPC17_MODE_DEFLT;
  return OK;
}
patacongo's avatar
patacongo committed
#endif
/****************************************************************************
 * Function: lpc17_txdescinit
 *
 * Description:
 *   Initialize the EMAC Tx descriptor table
 *
 * Parameters:
 *   priv - Pointer to EMAC device driver structure 
 *
 * Returned Value:
 *   None directory.
 *   As a side-effect, it will initialize priv->lp_phyaddr and
 *   priv->lp_phymode.
 *
 * Assumptions:
 *
 ****************************************************************************/

static inline void lpc17_txdescinit(struct lpc17_driver_s *priv)
{
  uint32_t *txdesc;
  uint32_t *txstat;
  uint32_t pktaddr;
  int i;

  /* Configure Tx descriptor and status tables */

  lpc17_putreg(LPC17_TXDESC_BASE, LPC17_ETH_TXDESC);
  lpc17_putreg(LPC17_TXSTAT_BASE, LPC17_ETH_TXSTAT);
  lpc17_putreg(CONFIG_ETH_NTXDESC-1, LPC17_ETH_TXDESCRNO);

  /* Initialize Tx descriptors and link to packet buffers */

  txdesc  = (uint32_t*)LPC17_TXDESC_BASE;
  pktaddr = LPC17_TXBUFFER_BASE;

  for (i = 0; i < CONFIG_ETH_NTXDESC; i++)
    {
      *txdesc++ = pktaddr;
      *txdesc++ = (TXDESC_CONTROL_INT | (LPC17_MAXPACKET_SIZE - 1));
      pktaddr  += LPC17_MAXPACKET_SIZE;
    }

  /* Initialize Tx status */

  txstat  = (uint32_t*)LPC17_TXSTAT_BASE;
  for (i = 0; i < CONFIG_ETH_NTXDESC; i++)
    {
      *txstat++ = 0;
    }

  /* Point to first Tx descriptor */

  lpc17_putreg(0, LPC17_ETH_TXPRODIDX);
}

/****************************************************************************
 * Function: lpc17_rxdescinit
 *
 * Description:
 *   Initialize the EMAC Rx descriptor table
 *
 * Parameters:
 *   priv - Pointer to EMAC device driver structure 
 *
 * Returned Value:
 *   None directory.
 *   As a side-effect, it will initialize priv->lp_phyaddr and
 *   priv->lp_phymode.
 *
 * Assumptions:
 *
 ****************************************************************************/

static inline void lpc17_rxdescinit(struct lpc17_driver_s *priv)
{
  uint32_t *rxdesc;
  uint32_t *rxstat;
  uint32_t pktaddr;
  int i;

  /* Configure Rx descriptor and status tables */

  lpc17_putreg(LPC17_RXDESC_BASE, LPC17_ETH_RXDESC);
  lpc17_putreg(LPC17_RXSTAT_BASE, LPC17_ETH_RXSTAT);
  lpc17_putreg(CONFIG_ETH_NRXDESC-1, LPC17_ETH_RXDESCNO);

  /* Initialize Rx descriptors and link to packet buffers */

  rxdesc  = (uint32_t*)LPC17_RXDESC_BASE;
  pktaddr = LPC17_RXBUFFER_BASE;

  for (i = 0; i < CONFIG_ETH_NRXDESC; i++)
    {
      *rxdesc++ = pktaddr;
      *rxdesc++ = (RXDESC_CONTROL_INT | (LPC17_MAXPACKET_SIZE - 1));
      pktaddr  += LPC17_MAXPACKET_SIZE;
    }

  /* Initialize Rx status */

  rxstat  = (uint32_t*)LPC17_TXSTAT_BASE;
  for (i = 0; i < CONFIG_ETH_NRXDESC; i++)
    {
      *rxstat++ = 0;
      *rxstat++ = 0;
    }

  /* Point to first Tx descriptor */

  lpc17_putreg(0, LPC17_ETH_RXPRODIDX);
}

patacongo's avatar
patacongo committed
/****************************************************************************
 * Function: lpc17_macmode
 *
 * Description:
 *   Set the MAC to operate at a selected speed/duplex mode.
 *
 * Parameters:
 *   mode - speed/duplex mode
 *
 * Returned Value:
 *   None
 *
 * Assumptions:
 *
 ****************************************************************************/

#ifdef LPC17_HAVE_PHY
static void lpc17_macmode(uint8_t mode)
{
  uint32_t regval;

  /* Set up for full or half duplex operation */

  if ((mode & LPC17_DUPLEX_MASK) == LPC17_DUPLEX_FULL)
    {
      /* Set the back-to-back inter-packet gap */
 
      lpc17_putreg(21, LPC17_ETH_IPGT);

      /* Set MAC to operate in full duplex mode with CRC and Pad enabled */

      regval = lpc17_getreg(LPC17_ETH_MAC2);
      regval |= (ETH_MAC2_FD | ETH_MAC2_CRCEN | ETH_MAC2_PADCRCEN);
      lpc17_putreg(regval, LPC17_ETH_MAC2);

      /* Select full duplex operation for ethernet controller */

      regval = lpc17_getreg(LPC17_ETH_CMD);
      regval |= (ETH_CMD_FD | ETH_CMD_RMII | ETH_CMD_PRFRAME);
      lpc17_putreg(regval, LPC17_ETH_CMD);
    }
  else
    {
      /* Set the back-to-back inter-packet gap */
 
      lpc17_putreg(18, LPC17_ETH_IPGT);

      /* Set MAC to operate in half duplex mode with CRC and Pad enabled */

      regval = lpc17_getreg(LPC17_ETH_MAC2);
      regval &= ~ETH_MAC2_FD;
      regval |= (ETH_MAC2_CRCEN | ETH_MAC2_PADCRCEN);
      lpc17_putreg(regval, LPC17_ETH_MAC2);

      /* Select half duplex operation for ethernet controller */

      regval = lpc17_getreg(LPC17_ETH_CMD);
      regval &= ~ETH_CMD_FD;
      regval |= (ETH_CMD_RMII | ETH_CMD_PRFRAME);
      lpc17_putreg(regval, LPC17_ETH_CMD);
    }

  /* This is currently done in lpc17_phyinit().  That doesn't
   * seem like the right place. It should be done here.
   */

#if 0
  regval = lpc17_getreg(LPC17_ETH_SUPP);
  if ((mode & LPC17_SPEED_MASK) == LPC17_SPEED_100)
    {
      regval |= ETH_SUPP_SPEED;
    }
  else
    {
      regval &= ~ETH_SUPP_SPEED;
    }
  lpc17_putreg(regval, LPC17_ETH_SUPP);
#endif
patacongo's avatar
patacongo committed
}
#endif

/****************************************************************************
 * Function: lpc17_ethreset
 *
 * Description:
 *   Configure and reset the Ethernet module, leaving it in a disabled state.
 *
 * Parameters:
 *   priv   - Reference to the driver state structure
 *
 * Returned Value:
 *   OK on success; a negated errno on failure
 *
 * Assumptions:
 *
 ****************************************************************************/

static void lpc17_ethreset(struct lpc17_driver_s *priv)
{
  irqstate_t flags;

patacongo's avatar
patacongo committed
  /* Reset the MAC */
patacongo's avatar
patacongo committed

patacongo's avatar
patacongo committed
  flags = irqsave();
patacongo's avatar
patacongo committed

patacongo's avatar
patacongo committed
  /* Put the MAC into the reset state */
patacongo's avatar
patacongo committed

patacongo's avatar
patacongo committed
  lpc17_putreg((ETH_MAC1_TXRST    | ETH_MAC1_MCSTXRST |ETH_MAC1_RXRST |
                ETH_MAC1_MCSRXRST | ETH_MAC1_SIMRST   | ETH_MAC1_SOFTRST),
               LPC17_ETH_MAC1);
patacongo's avatar
patacongo committed

patacongo's avatar
patacongo committed
  /* Disable RX/RX, clear modes, reset all control registers */
patacongo's avatar
patacongo committed

patacongo's avatar
patacongo committed
  lpc17_putreg((ETH_CMD_REGRST | ETH_CMD_TXRST | ETH_CMD_RXRST),
               LPC17_ETH_CMD);
patacongo's avatar
patacongo committed

patacongo's avatar
patacongo committed
  /* Take the MAC out of the reset state */

  up_udelay(50);
  lpc17_putreg(0, LPC17_ETH_MAC1);

  /* The RMII bit must be set on initialization (I'm not sure
   * this needs to be done here but... oh well.
   */

  lpc17_putreg(ETH_CMD_RMII, LPC17_ETH_CMD);

  /* Set other misc configuration-related registers to default values */

  lpc17_putreg(0, LPC17_ETH_MAC2);
  lpc17_putreg(0, LPC17_ETH_SUPP);
  lpc17_putreg(0, LPC17_ETH_TEST);

  lpc17_putreg(18, LPC17_ETH_IPGR);
  lpc17_putreg(((15 << ETH_CLRT_RMAX_SHIFT) | (55 << ETH_CLRT_COLWIN_SHIFT)),
               LPC17_ETH_CLRT);
  lpc17_putreg(0x0600, LPC17_ETH_MAXF);
patacongo's avatar
patacongo committed

  /* Disable all Ethernet controller interrupts */

patacongo's avatar
patacongo committed
  lpc17_putreg(0, LPC17_ETH_INTEN);

patacongo's avatar
patacongo committed
  /* Clear any pending interrupts (shouldn't be any) */

patacongo's avatar
patacongo committed
  lpc17_putreg(0xffffffff, LPC17_ETH_INTCLR);
patacongo's avatar
patacongo committed
  irqrestore(flags);
/****************************************************************************
 * Public Functions
 ****************************************************************************/

/****************************************************************************
 * Function: lpc17_ethinitialize
 *
 * Description:
 *   Initialize one Ethernet controller and driver structure.
 *   intf - Selects the interface to be initialized.
 *
 * Returned Value:
 *   OK on success; Negated errno on failure.
 *
 * Assumptions:
 *
 ****************************************************************************/

#if LPC17_NETHCONTROLLERS > 1
int lpc17_ethinitialize(int intf)
#else
static inline int lpc17_ethinitialize(int intf)
#endif
patacongo's avatar
patacongo committed
  struct lpc17_driver_s *priv;
patacongo's avatar
patacongo committed
  int ret;
patacongo's avatar
patacongo committed
  DEBUGASSERT(inf < LPC17_NETHCONTROLLERS);
  priv = &g_ethdrvr[intf];

  /* Turn on the ethernet MAC clock */

  regval  = lpc17_getreg(LPC17_SYSCON_PCONP);
  regval |= SYSCON_PCONP_PCENET;
  lpc17_putreg(regval, LPC17_SYSCON_PCONP);

  /* Configure all GPIO pins needed by ENET */

  for (i = 0; i < GPIO_NENET_PINS; i++)
    {
      (void)lpc17_configgpio(g_enetpins[i]);
    }
  lpc17_showpins();

  /* Initialize the driver structure */

patacongo's avatar
patacongo committed
  memset(priv, 0, sizeof(struct lpc17_driver_s));
patacongo's avatar
patacongo committed
  priv->lp_dev.d_ifup    = lpc17_ifup;    /* I/F down callback */
  priv->lp_dev.d_ifdown  = lpc17_ifdown;  /* I/F up (new IP address) callback */
  priv->lp_dev.d_txavail = lpc17_txavail; /* New TX data callback */
#ifdef CONFIG_NET_IGMP
patacongo's avatar
patacongo committed
  priv->lp_dev.d_addmac  = lpc17_addmac;  /* Add multicast MAC address */
  priv->lp_dev.d_rmmac   = lpc17_rmmac;   /* Remove multicast MAC address */
#endif
  priv->lp_dev.d_private = (void*)priv;   /* Used to recover private state from dev */

#if LM3S_NETHCONTROLLERS > 1