Skip to content
Snippets Groups Projects
lpc17_ethernet.c 72.4 KiB
Newer Older
patacongo's avatar
patacongo committed
        */

       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, priv->lp_mode);
patacongo's avatar
patacongo committed
  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_NET_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_NET_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_NET_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_NET_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_NET_NRXDESC; i++)
    {
      *rxdesc++ = pktaddr;
      *rxdesc++ = (RXDESC_CONTROL_INT | (LPC17_MAXPACKET_SIZE - 1));
      pktaddr  += LPC17_MAXPACKET_SIZE;
    }

  /* Initialize Rx status */

  rxstat  = (uint32_t*)LPC17_RXSTAT_BASE;
  for (i = 0; i < CONFIG_NET_NRXDESC; i++)
    {
      *rxstat++ = 0;
      *rxstat++ = 0;
    }

  /* Point to first Rx descriptor */
  lpc17_putreg(0, LPC17_ETH_RXCONSIDX);
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

  lpc17_putreg((ETH_MAC1_TXRST    | ETH_MAC1_MCSTXRST | ETH_MAC1_RXRST |
patacongo's avatar
patacongo committed
                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).
patacongo's avatar
patacongo committed
   */

  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);
patacongo's avatar
patacongo committed

  /* Set the Maximum Frame size register. "This field resets to the value
   * 0x0600, which represents a maximum receive frame of 1536 octets. An
   * untagged maximum size Ethernet frame is 1518 octets. A tagged frame adds
   * four octets for a total of 1522 octets. If a shorter maximum length
   * restriction is desired, program this 16-bit field."
   */

patacongo's avatar
patacongo committed
  lpc17_putreg(LPC17_MAXPACKET_SIZE, 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:
 *
 ****************************************************************************/

patacongo's avatar
patacongo committed
#if CONFIG_LPC17_NINTERFACES > 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(intf < CONFIG_LPC17_NINTERFACES);
patacongo's avatar
patacongo committed
  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 */

patacongo's avatar
patacongo committed
#if CONFIG_LPC17_NINTERFACES > 1
patacongo's avatar
patacongo committed
# error "A mechanism to associate base address an IRQ with an interface is needed"
  priv->lp_base          = ??;            /* Ethernet controller base address */
  priv->lp_irq           = ??;            /* Ethernet controller IRQ number */
#endif

  /* Create a watchdog for timing polling for and timing of transmisstions */

patacongo's avatar
patacongo committed
  priv->lp_txpoll        = wd_create();   /* Create periodic poll timer */
  priv->lp_txtimeout     = wd_create();   /* Create TX timeout timer */
patacongo's avatar
patacongo committed

patacongo's avatar
patacongo committed
  /* Reset the Ethernet controller and leave in the ifdown statue.  The
   * Ethernet controller will be properly re-initialized each time
   * lpc17_ifup() is called.
patacongo's avatar
patacongo committed
   */

  lpc17_ifdown(&priv->lp_dev);

  /* Attach the IRQ to the driver */

patacongo's avatar
patacongo committed
#if CONFIG_LPC17_NINTERFACES > 1
patacongo's avatar
patacongo committed
  ret = irq_attach(priv->irq, lpc17_interrupt);
#else
  ret = irq_attach(LPC17_IRQ_ETH, lpc17_interrupt);
#endif
  if (ret != 0)
    {
      /* We could not attach the ISR to the the interrupt */
patacongo's avatar
patacongo committed
      return -EAGAIN;
    }

  /* Register the device with the OS so that socket IOCTLs can be performed */

  (void)netdev_register(&priv->lp_dev);
/****************************************************************************
 * Name: up_netinitialize
 *
 * Description:
 *   Initialize the first network interface.  If there are more than one
 *   interface in the chip, then board-specific logic will have to provide
 *   this function to determine which, if any, Ethernet controllers should
 *   be initialized.
 *
 ****************************************************************************/

patacongo's avatar
patacongo committed
#if CONFIG_LPC17_NINTERFACES == 1
void up_netinitialize(void)
{
  (void)lpc17_ethinitialize(0);
}
#endif
#endif /* LPC17_NETHCONTROLLERS > 0 */
#endif /* CONFIG_NET && CONFIG_LPC17_ETHERNET */