⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 smsc9118.c

📁 SMSC LAN device linux Uboot code
💻 C
📖 第 1 页 / 共 2 页
字号:
	  // Set automatic flow control.
	  *AFC_CFG = 0x008c46af;

	  // Flash LEDs.
	  *GPIO_CFG = 0x70700000;

	  // Disable interrupts until the rest of initialization is complete.
	  *INT_EN = 0x0;				// Clear interrupt enables
	  *INT_STS = 0xffffffff;		// Clear pending interrupts
	  *IRQ_CFG = 0x00000001;		// IRQ disable

	  // Enable flow control and pause frame time
	  SetMacReg(MAC_FLOW, 0xffff0002);

	  // Set MAC address, if octet 0 is non-null assume it's all good.
	  {
			unsigned mac_addrh;
			unsigned mac_addrl;

			memcpy(macAddr, bis->bi_enetaddr, ENET_ADDR_LENGTH);
			mac_addrh = macAddr[5] << 8 | macAddr[4];
			mac_addrl = macAddr[3] << 24 | macAddr[2] << 16 |
				  macAddr[1] << 8 | macAddr[0];
			if (mac_addrh != 0 || mac_addrl != 0) {
				  SetMacReg(MAC_ADDRH, mac_addrh);
				  SetMacReg(MAC_ADDRL, mac_addrl);
			}
	  }

	  // Dump old status and data
	  *TX_CFG = (TX_CFG_TXS_DUMP | TX_CFG_TXD_DUMP);
	  *RX_CFG = (RX_CFG_FORCE_DISCARD);

	  // Initialize Tx parameters
	  *HW_CFG = ((*HW_CFG & HW_CFG_TX_FIF_SZ_MSK) | HW_CFG_SF);
	  *FIFO_INT = FIFO_INT_TDAL_MSK;	  // Max out value
	  *INT_EN |= INT_EN_TDFA_INT_EN;
	  {
			// Disable MAC heartbeat SQE and enable MAC transmitter
			ulong macCR = GetMacReg(MAC_CR);
			macCR |= (MAC_CR_TXEN | MAC_CR_HBDIS);
			macCR &= ~MAC_CR_PRMS;	// Turn off promiscuous mode
			macCR |= MAC_CR_BCAST;	// Don't accept broadcast frames
			SetMacReg(MAC_CR, macCR);
	  }

	  // Initialize Rx parameters
	  *RX_CFG = 0x00000000;			// 4byte end-alignment
	  {
			// Enable receiver.
			ulong macCR = GetMacReg(MAC_CR);
			SetMacReg(MAC_CR, (macCR | MAC_CR_RXEN));
	  }
	  *FIFO_INT = ((*FIFO_INT & 0xffff0000) | 0x00000101);
	  *INT_EN |= (INT_EN_RSFL_INT_EN | INT_EN_RXE_INT_EN);
	  *INT_EN |= INT_EN_RXDFH_INT_EN;

	  // Initialize PHY parameters
	  if (((GetPhyReg(PHY_ID1) == PHY_ID1_LAN9118) && 
		   (GetPhyReg(PHY_ID2) == PHY_ID2_LAN9118)) ||
	      ((GetPhyReg(PHY_ID1) == PHY_ID1_LAN9218) && 
		   (GetPhyReg(PHY_ID2) == PHY_ID2_LAN9218)))
	  {
		  // Reset the PHY
		  SetPhyReg(PHY_BCR, PHY_BCR_RST);
		  timeout = PHY_TIMEOUT;
		  lan9118_udelay(50*1000);	// > 50ms
		  while(timeout-- && (GetPhyReg(PHY_BCR) & PHY_BCR_RST))
		  {
				lan9118_udelay(10);
		  }
		  if (timeout == 0)
		  {
				LAN9118_WARN("PHY reset incomplete\n");
				RetVal = FALSE;
				goto done;
		  }

		  // Setup and start auto negotiation
		  {
				ushort anar;
				ushort bcr;
				char * spddplx;

				anar = GetPhyReg(PHY_ANAR);
				anar &= ~PHY_ANAR_PAUSE_OP_MSK;
				anar |= PHY_ANAR_PAUSE_OP_BOTH;
				anar |= (PHY_ANAR_10_FDPLX | PHY_ANAR_10_ABLE |
					  PHY_ANAR_100_TX_FDPLX | PHY_ANAR_100_TX_ABLE);
				SetPhyReg(PHY_ANAR, anar);

				DELAY(2);
				bcr = GetPhyReg(PHY_BCR);
				bcr |= (PHY_BCR_SS | PHY_BCR_FDPLX);
				SetPhyReg(PHY_BCR, bcr);
				DELAY(2);

				printf("start Auto negotiation... (take ~2sec)\n");
				bcr = GetPhyReg(PHY_BCR);
				bcr |= (PHY_BCR_ANE | PHY_BCR_RSTAN);
				SetPhyReg(PHY_BCR, bcr);
				DELAY(2);

				timeout = PHY_AN_TIMEOUT;
				while((timeout--) && ((GetPhyReg(PHY_BSR) & PHY_BSR_ANC) == 0)) {
					  lan9118_udelay(500000);
				}
				if ((GetPhyReg(PHY_BSR) & PHY_BSR_ANC) == 0) {
					  LAN9118_WARN("Auto negotiation failed\n");
					  RetVal = FALSE;
					  goto done;
				}

				if ((GetPhyReg(PHY_BSR) & PHY_BSR_LINK_STATUS) == 0) {
					  LAN9118_WARN("Link down\n");
					  RetVal = FALSE;
					  goto done;
				}

				switch ((GetPhyReg(PHY_PHYSCSR) & PHY_PHYSCSR_SPEED_MSK)>>2) {
					  case 0x01:
							spddplx = "10BaseT, half duplex";
							break;
					  case 0x02:
							spddplx = "100BaseTX, half duplex";
							break;
					  case 0x05:
							spddplx = "10BaseT, full duplex";
							break;
					  case 0x06:
							spddplx = "100BaseTX, full duplex";
							break;
					  default:
							spddplx = "Unknown";
							break;
				}
				printf("Auto negotiation complete, %s\n", spddplx);
		  }

		  // If PHYs auto negotiated for full duplex, enable full duplex in MAC.
		  if ((GetPhyReg(PHY_ANAR) & GetPhyReg(PHY_ANLPAR)) & 0x0140) {
				SetMacReg(MAC_CR, (GetMacReg(MAC_CR) | 0x00100000));
		  }
		  // correct PHY_ID is detected
		  goto done;
	  }
	  else
	  {
			printf("Unknown PHY ID : 0x%x, 0x%x\n", GetPhyReg(PHY_ID1), GetPhyReg(PHY_ID2));
	  }

	  goto done;

cleanup:
	  if (txbp != NULL) {
			free(txbp);
	  }

done:
	  return (RetVal);
}

static void
lan9118_close(void)
{
	  // Release the TX buffer.
	  if (txbp != NULL) {
			free(txbp);
	  }
}

static int
lan9118_read()
{
	  int curBufNdx;
	  int loopCount = 0;
	  ulong rxStatus;
	  ulong count;
	  ulong len;
	  int ffwdOk = TRUE;
	  int timeout;
	  int handled = 0;

	  while((*RX_FIFO_INF & 0x00ff0000) != 0) {
			if (loopCount >= NUM_RX_BUFF) {
//printf("read: loopCount exceeded\n");
				  break;	  // Packet buffers full
			}

			curBufNdx = rxNdx;
			loopCount++;
			if (++rxNdx >= NUM_RX_BUFF) {
				  rxNdx = 0;  // Wrap buffer slot #
			}

			rxStatus = *RX_STATUS_FIFO_PORT;
			len = count = rxStatus >> 16;

			if (count >= 4*sizeof(ulong)) {
				  ffwdOk = TRUE;	// Use h/w to toss packet
			} else {
				  ffwdOk = FALSE;	// Have to empty manually on error
			}

			if (count != 0) {
				  if (count > ENET_MAX_MTU) {
						count = 0;
				  } else {
						if ((rxStatus & TX_STATUS_FIFO_ES) != 0) {
							  count = 0;
						}
				  }
			}

			if (count == 0) {
				  if (ffwdOk == TRUE) {
						// Drain it the fast way
						*RX_DP_CTL = RX_DP_FFWD;
						timeout = FFWD_TIMEOUT;
						while (timeout-- && (*RX_DP_CTL & RX_DP_FFWD)) {
							  lan9118_udelay(1);
						}
						if ((*RX_DP_CTL & RX_DP_FFWD) != 0) {
							  LAN9118_WARN("lan9118_read: fast "
									"forward op failed\n");
							  break;
						}
				  } else {
						// Drain it manually
						while (len--) {
							volatile ulong tmp = *RX_FIFO_PORT;
						}
				  }
			} else if (rxAvlQue[rxNdxIn].index != -1) {
				  LAN9118_WARN("lan9118_read: read buffers full!\n");
				  break;
			} else {
				  register ulong *rxbpl;
				  int ndx;

				  TotalRxPackets++;
				  TotalBytes += count;
				  rxAvlQue[rxNdxIn].index = curBufNdx;
				  rxAvlQue[rxNdxIn].len = count;
				  if (++rxNdxIn >= NUM_RX_BUFF) {
						rxNdxIn = 0;
				  }

				  // Copy this packet to a NetRxPacket buffer
				  handled = 1;
//printf("read: %d empty reads prior to this one\n", EmptyReads);
				  EmptyReads = 0;
				  rxbpl = (ulong *)rxbp[curBufNdx];
				  for (ndx = (count+3)/sizeof(ulong); ndx > 0; ndx--) {
						*rxbpl++ = *RX_FIFO_PORT;
				  }
#if 0
{
	printf("Received: packet contents follows.\n");
	int i;
	for (i = 1; i <= count; i++) {
		  printf("0x%02x ", rxbp[curBufNdx][i-1]);
		  if (!(i%16))
			  printf("\n");
	}
	printf("\n");
}
#endif
				  DELAY(3);
			}
	  }

	  if (handled) {
			for (;;) {
				  curBufNdx = rxAvlQue[rxNdxOut].index;
				  if (curBufNdx == -1) {
						len = -1;	// Nothing else received
//printf("read: nothing else received: rxNdxOut: %d curBufNdx: %d\n", rxNdxOut, curBufNdx);
						break;
				  }
				  len = rxAvlQue[rxNdxOut].len;
//printf("read: sending a packet up: rxNdxOut: %d curBufNdx: %d\n", rxNdxOut, curBufNdx);
				  NetReceive(NetRxPackets[curBufNdx], len - 4);
				  rxAvlQue[rxNdxOut].index = -1;	  // Free buffer
				  if (++rxNdxOut >= NUM_RX_BUFF) {
						rxNdxOut = 0;	  // Handle wrap
				  }
			}
	  } else {
			EmptyReads++;
			return (-1);	  // Nothing was received
	  }

	  return (len);
}


static int sendToNet(uchar * txbp, int len)
{
	  ulong tx_cmd_a, tx_cmd_b;
	  int i;
	  ulong * txbpl = (ulong *)txbp;

	  lastTxTag++;

#if   DEBUG
	  {
			printf("sendToNet: packet contents follows.\n");
			int i;
			int j = 0;
			for (i = 0; i < len; i++) {
				  if (++j == 20) {
						j = 0;
						printf("\n");
				  }
				  printf("%0.1x ", txbp[i]);
			}
			printf("\n");

//			printf("sendToNet: peek TX status: 0x%0.8x\n",
//				  *TX_STATUS_FIFO_PEEK);
	  }
#endif		// DEBUG

	  tx_cmd_a = (((ulong)txbp & 0x3) << 16) | 0x00003000 | len;
	  tx_cmd_b = (lastTxTag << 16) | len;

#if   DEBUG
	  printf("sendToNet: tx_cmd_a: 0x%0.8x tx_cmd_b: 0x%0.8x\n",
			tx_cmd_a, tx_cmd_b);
#endif		// DEBUG

	  *TX_FIFO_PORT = tx_cmd_a;
	  *TX_FIFO_PORT = tx_cmd_b;

	  for (i = (len+3)/sizeof(ulong); i > 0; i--) {
			*TX_FIFO_PORT = *txbpl++; 
	  }

	  *TX_CFG = TX_CFG_TX_ON;		// Enable transmitter

	  return (TRUE);
}

static int lan9118_write(volatile void *ptr, int len)
{
	  ulong startTime;
	  ulong timeout;
	  char statusStr[64];

	  if (len > ENET_MAX_MTU) {
			len = ENET_MAX_MTU;
	  }

	  // Copy the packet.
	  memcpy((void *)txbp, (void *)ptr, len);

	  // Drain the TX status fifo just in case there are old (good) statuses.
	  for (timeout=0; timeout<TX_TIMEOUT_COUNT; timeout++)
	  {
		  if ((*TX_FIFO_INF & TX_FIFO_TXSUSED_MSK) == 0) {
				break;
		  }
		  printf("lan9118_write: discarded old TX status\n");
	  }
	  if (timeout == TX_TIMEOUT_COUNT)	// timed out?  Yes--
	  {
		DumpCsrRegs();
		DumpMacRegs();
		DumpPhyRegs();
	  }

	  if (sendToNet(txbp, len) == FALSE) {
			return (-1);
	  }

//printf("write: sent packet out: len: %d\n", len);

	  startTime = get_timer(0);
	  while (1) {
			if ((*TX_FIFO_INF & TX_FIFO_TXSUSED_MSK) == 0) {
				  // No status yet
				  if ((get_timer(0) - startTime) > TX_TIMEOUT) {
						return (-1);
				  }
			} else {
				  ulong txStatus = *TX_STATUS_FIFO_PORT;

				  if ((txStatus & TX_STATUS_FIFO_ES) == TX_STATUS_FIFO_ES) {
						sprintf(statusStr, "lan9118_write: error "
							  "status: 0x%0.8x\n", txStatus);
						LAN9118_WARN(statusStr);
						return (-1);
				  } else {
						*TX_CFG |= TX_CFG_STOP_TX; // Stop transmitter
						return (len);				// successful send
				  }
			}
	  }
}

int	eth_init(bd_t *bd)
{
	return lan9118_open(bd);
}

void eth_halt(void)
{
	lan9118_close();
}

int	eth_rx(void)
{
	int	r;

	r = lan9118_read();

	return r;
}

int	eth_send(volatile void *packet, int length)
{
	return lan9118_write(packet, length);
}

#endif		// #ifdef CONFIG_DRIVER_SMSC9118

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -