Ejemplo n.º 1
0
int eth_rx (void)
{
	int nLen = 0;
	unsigned int unStatus;

	unStatus =
		*get_eth_reg_addr (NS9750_ETH_EINTR) & NS9750_ETH_EINTR_RX_MA;

	if (!unStatus)
		/* no packet available, return immediately */
		return 0;

	DEBUG_FN (DEBUG_RX);

	/* unLen always < max(nLen) and discard checksum */
	nLen = (int) aRxBufferDesc[0].unLen - 4;

	/* acknowledge status register */
	*get_eth_reg_addr (NS9750_ETH_EINTR) = unStatus;

	aRxBufferDesc[0].unLen = 1522;
	aRxBufferDesc[0].s.bits.uFull = 0;

	/* Buffer A descriptor available again */
	*get_eth_reg_addr (NS9750_ETH_RXFREE) |= 0x1;

	/* NetReceive may call eth_send. Due to a possible bug of the NS9750 we
	 * have to acknowledge the received frame before sending a new one */
	if (unStatus & NS9750_ETH_EINTR_RXDONEA)
		NetReceive (NetRxPackets[0], nLen);

	return nLen;
}
static void
na_mii_reset(struct net_device *dev)
{
	struct netarmeth_dev *na_dev;

	NA_PRINTK("na_mii_reset\n");

	if (dev == NULL) {
		NA_PRINTK("na_mii_reset - NULL parameter\n");
		return;
	}
	na_dev = dev->priv;

	na_dev->phy_type = na_mii_identify_phy();
	if ((na_dev->phy_type != NA_ENABLE_PHY) &&
	    (na_dev->phy_type != NA_HOME_PHY)) {
		printk(KERN_WARNING "%s:  Found other than Enable, Lucent or Home PHY.\n", dev->name);
	}

	/* select appropriate Control register */
	if (na_dev->phy_type == NA_HOME_PHY)
		outl_t(0x100, get_eth_reg_addr(NETARM_ETH_MII_ADDR));
	else
		outl_t(0x400, get_eth_reg_addr(NETARM_ETH_MII_ADDR));

	outl_t(0x8000, get_eth_reg_addr(NETARM_ETH_MII_WRITE));
	na_mii_poll_busy();

	outl_t(0, get_eth_reg_addr(NETARM_ETH_MII_WRITE));
	na_mii_poll_busy();
}
Ejemplo n.º 3
0
void eth_halt (void)
{
	DEBUG_FN (DEBUG_INIT);

	*get_eth_reg_addr (NS9750_ETH_MAC1) &= ~NS9750_ETH_MAC1_RXEN;
	*get_eth_reg_addr (NS9750_ETH_EGCR1) &= ~(NS9750_ETH_EGCR1_ERX |
						  NS9750_ETH_EGCR1_ERXDMA |
						  NS9750_ETH_EGCR1_ETX |
						  NS9750_ETH_EGCR1_ETXDMA);
}
int eth_init(bd_t * pbis)
{
	unsigned char aucMACAddr[6];
	char *pcTmp = getenv("ethaddr");
	char *pcEnd;
	int i;

	DEBUG_FN(DEBUG_INIT);

	/* no need to check for hardware */

	if (!ns7520_eth_reset())
		return -1;

	if (NULL == pcTmp)
		return -1;

	for (i = 0; i < 6; i++) {
		aucMACAddr[i] =
		    pcTmp ? simple_strtoul(pcTmp, &pcEnd, 16) : 0;
		pcTmp = (*pcTmp) ? pcEnd + 1 : pcEnd;
	}

	/* configure ethernet address */

	*get_eth_reg_addr(NS7520_ETH_SA1) =
	    aucMACAddr[5] << 8 | aucMACAddr[4];
	*get_eth_reg_addr(NS7520_ETH_SA2) =
	    aucMACAddr[3] << 8 | aucMACAddr[2];
	*get_eth_reg_addr(NS7520_ETH_SA3) =
	    aucMACAddr[1] << 8 | aucMACAddr[0];

	/* enable hardware */

	*get_eth_reg_addr(NS7520_ETH_MAC1) = NS7520_ETH_MAC1_RXEN;
	*get_eth_reg_addr(NS7520_ETH_SUPP) = NS7520_ETH_SUPP_JABBER;
	*get_eth_reg_addr(NS7520_ETH_MAC1) = NS7520_ETH_MAC1_RXEN;

	/* the linux kernel may give packets < 60 bytes, for example arp */
	*get_eth_reg_addr(NS7520_ETH_MAC2) = NS7520_ETH_MAC2_CRCEN |
	    NS7520_ETH_MAC2_PADEN | NS7520_ETH_MAC2_HUGE;

	/* Broadcast/multicast allowed; if you don't set this even unicast chokes */
	/* Based on NS7520 errata documentation */
	*get_eth_reg_addr(NS7520_ETH_SAFR) =
	    NS7520_ETH_SAFR_BROAD | NS7520_ETH_SAFR_PRM;

	/* enable receive and transmit FIFO, use 10/100 Mbps MII */
	*get_eth_reg_addr(NS7520_ETH_EGCR) |=
	    NS7520_ETH_EGCR_ETXWM_75 |
	    NS7520_ETH_EGCR_ERX |
	    NS7520_ETH_EGCR_ERXREG |
	    NS7520_ETH_EGCR_ERXBR | NS7520_ETH_EGCR_ETX;

	return 0;
}
Ejemplo n.º 5
0
static void ns9750_mii_write (unsigned short uiRegister,
			      unsigned short uiData)
{
	DEBUG_FN (DEBUG_MII_LOW);

	/* write MII register to be written */
	*get_eth_reg_addr (NS9750_ETH_MADR) =
		NS9750_ETH_PHY_ADDRESS << 8 | uiRegister;

	*get_eth_reg_addr (NS9750_ETH_MWTD) = uiData;

	if (!ns9750_mii_poll_busy ()) {
		printf (KERN_WARNING NS9750_DRIVER_NAME
			": MII still busy in write\n");
	}
}
static void
na_get_mac_addr(struct net_device *dev)
{
  unsigned short *p;

  NA_PRINTK("na_get_mac_addr\n");

  p = (unsigned short *) dev->dev_addr;
  p[0] = (unsigned short) inl_t(get_eth_reg_addr(NETARM_ETH_SAL_STATION_ADDR_1));
  p[1] = (unsigned short) inl_t(get_eth_reg_addr(NETARM_ETH_SAL_STATION_ADDR_2));
  p[2] = (unsigned short) inl_t(get_eth_reg_addr(NETARM_ETH_SAL_STATION_ADDR_3));

  NA_PRINTK2("  %X %X %X %X %X %X\n",
    dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
    dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
}
Ejemplo n.º 7
0
static unsigned short ns9750_mii_read (unsigned short uiRegister)
{
	DEBUG_FN (DEBUG_MII_LOW);

	/* write MII register to be read */
	*get_eth_reg_addr (NS9750_ETH_MADR) =
		NS9750_ETH_PHY_ADDRESS << 8 | uiRegister;

	*get_eth_reg_addr (NS9750_ETH_MCMD) = NS9750_ETH_MCMD_READ;

	if (!ns9750_mii_poll_busy ())
		printk (KERN_WARNING NS9750_DRIVER_NAME
			": MII still busy in read\n");
	/* continue to read */

	*get_eth_reg_addr (NS9750_ETH_MCMD) = 0;

	return (unsigned short) (*get_eth_reg_addr (NS9750_ETH_MRDD));
}
static void
na_rx_fifo_reset(unsigned long ldev)
{
  struct net_device *dev = (struct net_device *)ldev;
  struct netarmeth_dev *na_dev = dev->priv;

  /* If we're still receiving packets, keep going. */
  if (na_dev->stats.rx_packets != na_dev->rx_fifo_packets) {
    na_dev->rx_fifo_packets = na_dev->stats.rx_packets;
    NA_PRINTK2("na_rx_fifo_reset 1\n");
  }
  else if (inl_t(get_eth_reg_addr(NETARM_ETH_GEN_CTRL)) & NETARM_ETH_GCR_ERXDMA
	   && !(inl_t(get_dma_reg_addr(NETARM_DMA1A_STATUS)) & 0xdf000000)
	   && ((inl_t(get_eth_reg_addr(NETARM_ETH_GEN_STAT)) & 0x0a000000)
	       == 0x02000000)) { 
      na_reset_rx_fifo(na_dev);	    
  }
  na_enable_timer(dev);
}
Ejemplo n.º 9
0
static unsigned int ns9750_mii_poll_busy (void)
{
	unsigned int unTimeout = 10000;

	DEBUG_FN (DEBUG_MII_LOW);

	while (((*get_eth_reg_addr (NS9750_ETH_MIND) & NS9750_ETH_MIND_BUSY)
		== NS9750_ETH_MIND_BUSY) && unTimeout)
		unTimeout--;

	return unTimeout;
}
Ejemplo n.º 10
0
static unsigned long
na_mii_check_speed(struct netarmeth_dev *na_dev)
{
	// Check link status.  If 0, default to 100 Mbps.
	NA_PRINTK("na_mii_check_speed\n");

	if (na_dev->phy_type == NA_HOME_PHY) {
		/* The AMD Home PHY only supports 10 Mbps anyway */
		NA_PRINTK("  returning NA_10MBPS (HomePHY)\n");
		na_dev->media_100BaseT = NA_10MBPS;
	} else {
		/* Read Status register */
		outl_t(0x401, get_eth_reg_addr(NETARM_ETH_MII_ADDR));
		outl_t((inl_t(get_eth_reg_addr(NETARM_ETH_MII_CMD)) | NETARM_ETH_MIIC_RSTAT),
		       get_eth_reg_addr(NETARM_ETH_MII_CMD));
		na_mii_poll_busy();

		if ((inl_t(get_eth_reg_addr(NETARM_ETH_MII_READ)) & 0x0004) == 0) {
			NA_PRINTK("  returning NA_100MBPS (link is down)\n");
			na_dev->media_100BaseT = NA_100MBPS;
		} else {
			/* Now it's OK to check the normal speed status */
			outl_t(0x417, get_eth_reg_addr(NETARM_ETH_MII_ADDR));
			outl_t((inl_t(get_eth_reg_addr(NETARM_ETH_MII_CMD)) | NETARM_ETH_MIIC_RSTAT),
			       get_eth_reg_addr(NETARM_ETH_MII_CMD));
			na_mii_poll_busy();

			if ((inl_t(get_eth_reg_addr(NETARM_ETH_MII_READ)) & 0x0200) != 0) {
				NA_PRINTK("  returning NA_100MBPS (b)\n");
				na_dev->media_100BaseT = NA_100MBPS;
			} else {
				NA_PRINTK("  returning NA_10MBPS\n");
				na_dev->media_100BaseT = NA_10MBPS;
			}
		}
	}
	return(na_dev->media_100BaseT);
}
Ejemplo n.º 11
0
static unsigned long
na_mii_poll_busy(void)
{
	unsigned long start_time, current_time;

	// Poll until the busy bit is clear or one second has elapsed.
	// (this is PHY-type-independent)

	start_time = current_time = jiffies;
	while ((current_time < start_time + NA_MII_POLL_BUSY_DELAY) &&
	       (inl_t(get_eth_reg_addr(NETARM_ETH_MII_IND)) &
	        NETARM_ETH_MIII_BUSY)) {
		current_time = jiffies;
	}
	if (current_time < start_time + NA_MII_POLL_BUSY_DELAY) {
		return (1);
	} else {
		NA_PRINTK("na_mii_poll_busy - one second elapsed.\n");
		return (0);
	}
}
Ejemplo n.º 12
0
int eth_send (volatile void *pPacket, int nLen)
{
	ulong ulTimeout;

	DEBUG_FN (DEBUG_TX);

	/* clear old status values */
	*get_eth_reg_addr (NS9750_ETH_EINTR) &=
		*get_eth_reg_addr (NS9750_ETH_EINTR) & NS9750_ETH_EINTR_TX_MA;

	/* prepare Tx Descriptors */

	pTxBufferDesc->punSrc = (unsigned int *) pPacket;	/* pPacket is 32bit
								 * aligned */
	pTxBufferDesc->unLen = nLen;
	/* only 32bit accesses allowed. wrap, full, interrupt and enabled to 1 */
	pTxBufferDesc->s.unReg = 0xf0000000;
	/* pTxBufferDesc is the first possible buffer descriptor */
	*get_eth_reg_addr (NS9750_ETH_TXPTR) = 0x0;

	/* enable processor for next frame */

	*get_eth_reg_addr (NS9750_ETH_EGCR2) &= ~NS9750_ETH_EGCR2_TCLER;
	*get_eth_reg_addr (NS9750_ETH_EGCR2) |= NS9750_ETH_EGCR2_TCLER;

	ulTimeout = get_timer (0);

	DEBUG_ARGS0 (DEBUG_TX | DEBUG_MINOR,
		     "Waiting for transmission to finish\n");
	while (!
	       (*get_eth_reg_addr (NS9750_ETH_EINTR) &
		(NS9750_ETH_EINTR_TXDONE | NS9750_ETH_EINTR_TXERR))) {
		/* do nothing, wait for completion */
		if (get_timer (0) - ulTimeout > TX_TIMEOUT) {
			DEBUG_ARGS0 (DEBUG_TX, "Transmit Timed out\n");
			return -1;
		}
	}
	DEBUG_ARGS0 (DEBUG_TX | DEBUG_MINOR, "transmitted...\n");

	return 0;
}
Ejemplo n.º 13
0
static void ns9750_link_update_egcr (void)
{
	unsigned int unEGCR;
	unsigned int unMAC2;
	unsigned int unIPGT;

	DEBUG_FN (DEBUG_LINK);

	unEGCR = *get_eth_reg_addr (NS9750_ETH_EGCR1);
	unMAC2 = *get_eth_reg_addr (NS9750_ETH_MAC2);
	unIPGT = *get_eth_reg_addr (NS9750_ETH_IPGT) & ~NS9750_ETH_IPGT_MA;

	unMAC2 &= ~NS9750_ETH_MAC2_FULLD;
	if ((uiLastLinkStatus & PHY_LXT971_STAT2_DUPLEX_MODE)
	    == PHY_LXT971_STAT2_DUPLEX_MODE) {
		unMAC2 |= NS9750_ETH_MAC2_FULLD;
		unIPGT |= 0x15; /* see [1] p. 339 */
	} else
		unIPGT |= 0x12; /* see [1] p. 339 */

	*get_eth_reg_addr (NS9750_ETH_MAC2) = unMAC2;
	*get_eth_reg_addr (NS9750_ETH_EGCR1) = unEGCR;
	*get_eth_reg_addr (NS9750_ETH_IPGT) = unIPGT;
}
Ejemplo n.º 14
0
/* the PHY stuff */

static char ns9750_mii_identify_phy( void );
static unsigned short ns9750_mii_read( unsigned short uiRegister );
static void ns9750_mii_write( unsigned short uiRegister, unsigned short uiData );
static unsigned int ns9750_mii_get_clock_divisor( unsigned int unMaxMDIOClk );
static unsigned int ns9750_mii_poll_busy( void );

static unsigned int nPhyMaxMdioClock = PHY_MDIO_MAX_CLK;
static unsigned char ucLinkMode =      FS_EEPROM_AUTONEG_ENABLE;
static unsigned int uiLastLinkStatus;
static PhyType phyDetected = PHY_NONE;

/* we use only one tx buffer descriptor */
static tx_buffer_desc_t* pTxBufferDesc =
	(tx_buffer_desc_t*) get_eth_reg_addr( NS9750_ETH_TXBD );

/* we use only one rx buffer descriptor of the 4 */
static rx_buffer_desc_t aRxBufferDesc[ 4 ];

/***********************************************************************
 * @Function: eth_init
 * @Return: -1 on failure otherwise 0
 * @Descr: Initializes the ethernet engine and uses either FS Forth's default
 *	   MAC addr or the one in environment
 ***********************************************************************/

int eth_init (bd_t * pbis)
{
	/* This default MAC Addr is reserved by FS Forth-Systeme for the case of
	   EEPROM failures */
Ejemplo n.º 15
0
static unsigned long
na_mii_negotiate(struct netarmeth_dev *na_dev)
{
	unsigned long start_time, current_time;
	unsigned long read_data;

	NA_PRINTK("na_mii_negotiate\n");

	/* Select Autonegotiation Advertisement register */
	if (na_dev->phy_type == NA_HOME_PHY)
		outl_t(0x101, get_eth_reg_addr(NETARM_ETH_MII_ADDR));
	else
		outl_t(0x404, get_eth_reg_addr(NETARM_ETH_MII_ADDR));

	/* Enable auto-negotiation */
	outl_t(0x01E1, get_eth_reg_addr(NETARM_ETH_MII_WRITE));
	na_mii_poll_busy();

	/* Select Control register */
	if (na_dev->phy_type == NA_HOME_PHY)
		outl_t(0x100, get_eth_reg_addr(NETARM_ETH_MII_ADDR));
	else
		outl_t(0x400, get_eth_reg_addr(NETARM_ETH_MII_ADDR));

	/* Restart auto-negotiation */
	outl_t(0x1200, get_eth_reg_addr(NETARM_ETH_MII_WRITE));
	na_mii_poll_busy();

	// Wait for auto-negotiation to complete or for predefined delay to elapse.

	start_time = current_time = jiffies;
	do {
		/* Select Status register */
		if (na_dev->phy_type == NA_HOME_PHY)
			outl_t(0x101, get_eth_reg_addr(NETARM_ETH_MII_ADDR));
		else
			outl_t(0x401, get_eth_reg_addr(NETARM_ETH_MII_ADDR));

		outl_t((inl_t(get_eth_reg_addr(NETARM_ETH_MII_CMD))
		        | NETARM_ETH_MIIC_RSTAT),
		       get_eth_reg_addr(NETARM_ETH_MII_CMD));
		na_mii_poll_busy();

		read_data = inl_t(get_eth_reg_addr(NETARM_ETH_MII_READ));
		if ((read_data & 0x0024) == 0x0024) {
			return (0);
		}
		current_time = jiffies;
	} while (current_time < start_time + NA_MII_NEGOTIATE_DELAY);

	NA_PRINTK("  MII negotiation delay elapsed\n");
	return (1);
}
Ejemplo n.º 16
0
static na_phy_type
na_mii_identify_phy(void)
{
	int id_reg_a, id_reg_b;

	NA_PRINTK("na_mii_identify_phy\n");

	/* check for Enable PHY */
	outl_t(0x402, get_eth_reg_addr(NETARM_ETH_MII_ADDR));
	outl_t((inl_t(get_eth_reg_addr(NETARM_ETH_MII_CMD)) | NETARM_ETH_MIIC_RSTAT),
	       get_eth_reg_addr(NETARM_ETH_MII_CMD));
	na_mii_poll_busy();
	id_reg_a = inl_t(get_eth_reg_addr(NETARM_ETH_MII_READ));

	if (id_reg_a == 0x0043) {
		/* This must be an Enable or a Lucent LU3X31 PHY chip */
		NA_PRINTK("  Enable PHY\n");
		return (NA_ENABLE_PHY);
	}

	/* check for AMD 79C901 HomePHY */
	outl_t(0x102, get_eth_reg_addr(NETARM_ETH_MII_ADDR));
	outl_t((inl_t(get_eth_reg_addr(NETARM_ETH_MII_CMD)) | NETARM_ETH_MIIC_RSTAT),
	       get_eth_reg_addr(NETARM_ETH_MII_CMD));
	na_mii_poll_busy();
	id_reg_a = inl_t(get_eth_reg_addr(NETARM_ETH_MII_READ));

	outl_t(0x103, get_eth_reg_addr(NETARM_ETH_MII_ADDR));
	outl_t((inl_t(get_eth_reg_addr(NETARM_ETH_MII_CMD)) | NETARM_ETH_MIIC_RSTAT),
	       get_eth_reg_addr(NETARM_ETH_MII_CMD));
	na_mii_poll_busy();
	id_reg_b = inl_t(get_eth_reg_addr(NETARM_ETH_MII_READ));

	if ((id_reg_a == 0x0000) && (id_reg_b == 0x6b71)) {
		/* This must be an AMD Home PHY chip */
		NA_PRINTK("  Home PHY\n");
		return (NA_HOME_PHY);
	}

	/* else, i.e. default */
	NA_PRINTK("  Level 1 PHY\n");
	return (NA_LEVEL1_PHY);
}
Ejemplo n.º 17
0
static void
na_reset_rx_fifo(struct netarmeth_dev *na_dev)
{
  unsigned long reg;
  int           i;

  NA_PRINTK("na_reset_rx_fifo\n");

  // Disable receive DMA.

  outl_t((inl_t(get_eth_reg_addr(NETARM_ETH_GEN_CTRL))
	  & ~NETARM_ETH_GCR_ERXDMA),
	 get_eth_reg_addr(NETARM_ETH_GEN_CTRL));

  // Disable receive FIFO.

  outl_t((inl_t(get_eth_reg_addr(NETARM_ETH_GEN_CTRL)) & ~NETARM_ETH_GCR_ERX),
	 get_eth_reg_addr(NETARM_ETH_GEN_CTRL));

  // Disable DMA

  outl_t((inl_t(get_dma_reg_addr(NETARM_DMA1A_CONTROL)) & 0x7ffffc00),
	 get_dma_reg_addr(NETARM_DMA1A_CONTROL));

  // Delay 20 microsconds.

  udelay(20);

  // If NRIP or CAIP is set, reset them.
  
  reg = inl_t(get_dma_reg_addr(NETARM_DMA1A_CONTROL));
  if (reg & 0x20000000) {
    reg &= 0x20f00000;
    outl_t(reg, get_dma_reg_addr(NETARM_DMA1A_CONTROL));
  }

  // Reset DMA descriptors

  for (i = 0; i < NA_MAX_RX_BUF; i++) {
    na_dev->rx_dma_desc[i].src_buf_ptr  = (unsigned long) virt_to_bus(na_dev->rx_skb[i]->data);
    na_dev->rx_dma_desc[i].src_buf_ptr &= ~(NETARM_DMA_BD0_LAST
					    | NETARM_DMA_BD0_IDONE);
    na_dev->rx_dma_desc[i].buf_len      = NA_MAX_ETH_FRAME;
    na_dev->rx_dma_desc[i].stat         = 0;
    // Clear the F bit.
    na_dev->rx_dma_desc[i].buf_len     &= ~NETARM_DMA_BD1_FULL;
  }
  na_dev->rx_dma_desc[NA_MAX_RX_BUF-1].src_buf_ptr |= NETARM_DMA_BD0_WRAP;
  na_dev->rx_sw_index = 0;

  // Reenable DMA

  outl_t((inl_t(get_dma_reg_addr(NETARM_DMA1A_CONTROL)) | 0x80000000),
	 get_dma_reg_addr(NETARM_DMA1A_CONTROL));

  // Reenable receive FIFO.

  outl_t((inl_t(get_eth_reg_addr(NETARM_ETH_GEN_CTRL)) | NETARM_ETH_GCR_ERX),
	 get_eth_reg_addr(NETARM_ETH_GEN_CTRL));

  // Reenable receive DMA.

  outl_t((inl_t(get_eth_reg_addr(NETARM_ETH_GEN_CTRL))
	  | NETARM_ETH_GCR_ERXDMA),
	 get_eth_reg_addr(NETARM_ETH_GEN_CTRL));
}
Ejemplo n.º 18
0
static int ns9750_eth_reset (void)
{
	DEBUG_FN (DEBUG_MINOR);

	/* Reset MAC */
	*get_eth_reg_addr (NS9750_ETH_EGCR1) |= NS9750_ETH_EGCR1_MAC_HRST;
	udelay (5);		/* according to [1], p.322 */
	*get_eth_reg_addr (NS9750_ETH_EGCR1) &= ~NS9750_ETH_EGCR1_MAC_HRST;

	/* reset and initialize PHY */

	*get_eth_reg_addr (NS9750_ETH_MAC1) &= ~NS9750_ETH_MAC1_SRST;

	/* we don't support hot plugging of PHY, therefore we don't reset
	   phyDetected and nPhyMaxMdioClock here. The risk is if the setting is
	   incorrect the first open
	   may detect the PHY correctly but succeding will fail
	   For reseting the PHY and identifying we have to use the standard
	   MDIO CLOCK value 2.5 MHz only after hardware reset
	   After having identified the PHY we will do faster */

	*get_eth_reg_addr (NS9750_ETH_MCFG) =
		ns9750_mii_get_clock_divisor (nPhyMaxMdioClock);

	/* reset PHY */
	ns9750_mii_write (PHY_COMMON_CTRL, PHY_COMMON_CTRL_RESET);
	ns9750_mii_write (PHY_COMMON_CTRL, 0);

	/* @TODO check time */
	udelay (3000);		/* [2] p.70 says at least 300us reset recovery time. But
				   go sure, it didn't worked stable at higher timer
				   frequencies under LxNETES-2.x */

	/* MII clock has been setup to default, ns9750_mii_identify_phy should
	   work for all */

	if (!ns9750_mii_identify_phy ()) {
		printk (KERN_ERR NS9750_DRIVER_NAME
			": Unsupported PHY, aborting\n");
		return 0;
	}

	/* now take the highest MDIO clock possible after detection */
	*get_eth_reg_addr (NS9750_ETH_MCFG) =
		ns9750_mii_get_clock_divisor (nPhyMaxMdioClock);


	/* PHY has been detected, so there can be no abort reason and we can
	   finish initializing ethernet */

	uiLastLinkStatus = 0xff;	/* undefined */

	if ((ucLinkMode & FS_EEPROM_AUTONEG_ENABLE_MASK) ==
	    FS_EEPROM_AUTONEG_DISABLE)
		/* use parameters defined */
		ns9750_link_force ();
	else
		ns9750_link_auto_negotiate ();

	if (phyDetected == PHY_LXT971A)
		/* set LED2 to link mode */
		ns9750_mii_write (PHY_LXT971_LED_CFG,
				  PHY_LXT971_LED_CFG_LINK_ACT <<
				  PHY_LXT971_LED_CFG_SHIFT_LED2);

	return 1;
}
int eth_rx(void)
{
	int i;
	unsigned short rxlen;
	unsigned short totrxlen = 0;
	unsigned int *addr;
	unsigned int rxstatus, lastrxlen;
	char *pa;

	/* If RXBR is 1, data block was received */
	while (((*get_eth_reg_addr(NS7520_ETH_EGSR)) &
		NS7520_ETH_EGSR_RXBR) == NS7520_ETH_EGSR_RXBR) {

		/* get status register and the length of received block */
		rxstatus = *get_eth_reg_addr(NS7520_ETH_ERSR);
		rxlen = (rxstatus & NS7520_ETH_ERSR_RXSIZE) >> 16;

		/* clear RXBR to make fifo available */
		*get_eth_reg_addr(NS7520_ETH_EGSR) = NS7520_ETH_EGSR_RXBR;

		if (rxstatus & NS7520_ETH_ERSR_ROVER) {
			printf("Receive overrun, resetting FIFO.\n");
			*get_eth_reg_addr(NS7520_ETH_EGCR) &=
			    ~NS7520_ETH_EGCR_ERX;
			udelay(20);
			*get_eth_reg_addr(NS7520_ETH_EGCR) |=
			    NS7520_ETH_EGCR_ERX;
		}
		if (rxlen == 0) {
			printf("Nothing.\n");
			return 0;
		}

		addr = (unsigned int *) NetRxPackets[0];
		pa = (char *) NetRxPackets[0];

		/* read the fifo */
		for (i = 0; i < rxlen / 4; i++) {
			*addr = *get_eth_reg_addr(NS7520_ETH_FIFO);
			addr++;
		}

		if ((*get_eth_reg_addr(NS7520_ETH_EGSR)) &
		    NS7520_ETH_EGSR_RXREGR) {
			/* RXFDB indicates wether the last word is 1,2,3 or 4 bytes long */
			lastrxlen =
			    ((*get_eth_reg_addr(NS7520_ETH_EGSR)) &
			     NS7520_ETH_EGSR_RXFDB_MA) >> 28;
			*addr = *get_eth_reg_addr(NS7520_ETH_FIFO);
			switch (lastrxlen) {
			case 1:
				*addr &= 0xff000000;
				break;
			case 2:
				*addr &= 0xffff0000;
				break;
			case 3:
				*addr &= 0xffffff00;
				break;
			}
		}

		/* Pass the packet up to the protocol layers. */
		NetReceive(NetRxPackets[0], rxlen - 4);
		totrxlen += rxlen - 4;
	}
int eth_send(volatile void *pPacket, int nLen)
{
	int i, length32, retval = 1;
	char *pa;
	unsigned int *pa32, lastp = 0, rest;
	unsigned int status;

	pa = (char *) pPacket;
	pa32 = (unsigned int *) pPacket;
	length32 = nLen / 4;
	rest = nLen % 4;

	/* make sure there's no garbage in the last word */
	switch (rest) {
	case 0:
		lastp = pa32[length32 - 1];
		length32--;
		break;
	case 1:
		lastp = pa32[length32] & 0x000000ff;
		break;
	case 2:
		lastp = pa32[length32] & 0x0000ffff;
		break;
	case 3:
		lastp = pa32[length32] & 0x00ffffff;
		break;
	}

	while (((*get_eth_reg_addr(NS7520_ETH_EGSR)) &
		NS7520_ETH_EGSR_TXREGE)
	       == 0) {
	}

	/* write to the fifo */
	for (i = 0; i < length32; i++)
		*get_eth_reg_addr(NS7520_ETH_FIFO) = pa32[i];

	/* the last word is written to an extra register, this
	   starts the transmission */
	*get_eth_reg_addr(NS7520_ETH_FIFOL) = lastp;

	/* Wait for it to be done */
	while ((*get_eth_reg_addr(NS7520_ETH_EGSR) & NS7520_ETH_EGSR_TXBC)
	       == 0) {
	}
	status = (*get_eth_reg_addr(NS7520_ETH_ETSR));
	*get_eth_reg_addr(NS7520_ETH_EGSR) = NS7520_ETH_EGSR_TXBC;	/* Clear it now */

	if (status & NS7520_ETH_ETSR_TXOK) {
		retval = 0;	/* We're OK! */
	} else if (status & NS7520_ETH_ETSR_TXDEF) {
		printf("Deferred, we'll see.\n");
		retval = 0;
	} else if (status & NS7520_ETH_ETSR_TXAL) {
		printf("Late collision error, %d collisions.\n",
		       (*get_eth_reg_addr(NS7520_ETH_ETSR)) &
		       NS7520_ETH_ETSR_TXCOLC);
	} else if (status & NS7520_ETH_ETSR_TXAEC) {
		printf("Excessive collisions: %d\n",
		       (*get_eth_reg_addr(NS7520_ETH_ETSR)) &
		       NS7520_ETH_ETSR_TXCOLC);
	} else if (status & NS7520_ETH_ETSR_TXAED) {
		printf("Excessive deferral on xmit.\n");
	} else if (status & NS7520_ETH_ETSR_TXAUR) {
		printf("Packet underrun.\n");
	} else if (status & NS7520_ETH_ETSR_TXAJ) {
		printf("Jumbo packet error.\n");
	} else {
		printf("Error: Should never get here.\n");
	}

	return (retval);
}
Ejemplo n.º 21
0
int eth_init (bd_t * pbis)
{
	/* This default MAC Addr is reserved by FS Forth-Systeme for the case of
	   EEPROM failures */
	unsigned char aucMACAddr[6] = { 0x00, 0x04, 0xf3, 0x00, 0x06, 0x35 };
	char *pcTmp = getenv ("ethaddr");
	char *pcEnd;
	int i;

	DEBUG_FN (DEBUG_INIT);

	/* no need to check for hardware */

	if (!ns9750_eth_reset ())
		return -1;

	if (pcTmp != NULL)
		for (i = 0; i < 6; i++) {
			aucMACAddr[i] =
				pcTmp ? simple_strtoul (pcTmp, &pcEnd,
							16) : 0;
			pcTmp = (*pcTmp) ? pcEnd + 1 : pcEnd;
		}

	/* configure ethernet address */

	*get_eth_reg_addr (NS9750_ETH_SA1) =
		aucMACAddr[5] << 8 | aucMACAddr[4];
	*get_eth_reg_addr (NS9750_ETH_SA2) =
		aucMACAddr[3] << 8 | aucMACAddr[2];
	*get_eth_reg_addr (NS9750_ETH_SA3) =
		aucMACAddr[1] << 8 | aucMACAddr[0];

	/* enable hardware */

	*get_eth_reg_addr (NS9750_ETH_MAC1) = NS9750_ETH_MAC1_RXEN;

	/* the linux kernel may give packets < 60 bytes, for example arp */
	*get_eth_reg_addr (NS9750_ETH_MAC2) = NS9750_ETH_MAC2_CRCEN |
		NS9750_ETH_MAC2_PADEN | NS9750_ETH_MAC2_HUGE;

	/* enable receive and transmit FIFO, use 10/100 Mbps MII */
	*get_eth_reg_addr (NS9750_ETH_EGCR1) =
		NS9750_ETH_EGCR1_ETXWM |
		NS9750_ETH_EGCR1_ERX |
		NS9750_ETH_EGCR1_ERXDMA |
		NS9750_ETH_EGCR1_ETX |
		NS9750_ETH_EGCR1_ETXDMA | NS9750_ETH_EGCR1_ITXA;

	/* prepare DMA descriptors */
	for (i = 0; i < 4; i++) {
		aRxBufferDesc[i].punSrc = 0;
		aRxBufferDesc[i].unLen = 0;
		aRxBufferDesc[i].s.bits.uWrap = 1;
		aRxBufferDesc[i].s.bits.uInt = 1;
		aRxBufferDesc[i].s.bits.uEnable = 0;
		aRxBufferDesc[i].s.bits.uFull = 0;
	}

	/* NetRxPackets[ 0 ] is initialized before eth_init is called and never
	   changes. NetRxPackets is 32bit aligned */
	aRxBufferDesc[0].punSrc = (unsigned int *) NetRxPackets[0];
	aRxBufferDesc[0].s.bits.uEnable = 1;
	aRxBufferDesc[0].unLen = 1522;	/* as stated in [1] p.307 */

	*get_eth_reg_addr (NS9750_ETH_RXAPTR) =
		(unsigned int) &aRxBufferDesc[0];

	/* [1] Tab. 221 states less than 5us */
	*get_eth_reg_addr (NS9750_ETH_EGCR1) |= NS9750_ETH_EGCR1_ERXINIT;
	while (!
	       (*get_eth_reg_addr (NS9750_ETH_EGSR) & NS9750_ETH_EGSR_RXINIT))
		/* wait for finish */
		udelay (1);

	/* @TODO do we need to clear RXINIT? */
	*get_eth_reg_addr (NS9750_ETH_EGCR1) &= ~NS9750_ETH_EGCR1_ERXINIT;

	*get_eth_reg_addr (NS9750_ETH_RXFREE) = 0x1;

	return 0;
}