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

📄 405gp_enet.c

📁 嵌入式ARM的一些源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*-----------------------------------------------------------------------------+
  |
  |       This source code has been made available to you by IBM on an AS-IS
  |       basis.  Anyone receiving this source is licensed under IBM
  |       copyrights to use it in any way he or she deems fit, including
  |       copying it, modifying it, compiling it, and redistributing it either
  |       with or without modifications.  No license under IBM patents or
  |       patent applications is to be implied by the copyright license.
  |
  |       Any user of this software should understand that IBM cannot provide
  |       technical support for this software and will not be responsible for
  |       any consequences resulting from the use of this software.
  |
  |       Any person who transfers this source code or any derivative work
  |       must include the IBM copyright notice, this paragraph, and the
  |       preceding two paragraphs in the transferred software.
  |
  |       COPYRIGHT   I B M   CORPORATION 1995
  |       LICENSED MATERIAL  -  PROGRAM PROPERTY OF I B M
  +-----------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------+
  |
  |  File Name:  enetemac.c
  |
  |  Function:   Device driver for the ethernet EMAC3 macro on the 405GP.
  |
  |  Author:     Mark Wisner
  |
  |  Change Activity-
  |
  |  Date        Description of Change                                       BY
  |  ---------   ---------------------                                       ---
  |  05-May-99   Created                                                     MKW
  |  27-Jun-99   Clean up                                                    JWB
  |  16-Jul-99   Added MAL error recovery and better IP packet handling      MKW
  |  29-Jul-99   Added Full duplex support                                   MKW
  |  06-Aug-99   Changed names for Mal CR reg                                MKW
  |  23-Aug-99   Turned off SYE when running at 10Mbs                        MKW
  |  24-Aug-99   Marked descriptor empty after call_xlc                      MKW
  |  07-Sep-99   Set MAL RX buffer size reg to ENET_MAX_MTU_ALIGNED / 16     MCG
  |              to avoid chaining maximum sized packets. Push starting
  |              RX descriptor address up to the next cache line boundary.
  |  16-Jan-00   Added support for booting with IP of 0x0                    MKW
  |  15-Mar-00   Updated enetInit() to enable broadcast addresses in the 
  |	       EMAC_RXM register.                                          JWB	
  +-----------------------------------------------------------------------------*/

#include <ppcboot.h>
#include <asm/processor.h>
#include <ppc4xx.h>
#include <commproc.h>
#include <405gp_enet.h>
#include <405_mal.h>
#include <miiphy.h>
#include <net.h>
#include <malloc.h>

#ifdef CONFIG_PPC405GP


#define MAXPACKET       1518
#define ENET_MINPACKET  64

static __inline__ unsigned long get_msr(void)
{
  unsigned long msr;

  asm volatile("mfmsr %0" : "=r" (msr) :);
  return msr;
}

static __inline__ void set_msr(unsigned long msr)
{
  asm volatile("mtmsr %0" : : "r" (msr));
}

/*-----------------------------------------------------------------------------+
| Defines for number of buffers and their starting addresses.
| Buffers are in SDRAM space and must be above 0xA000 to avoid conflict
| with the ROM Monitor's data section and must be below 0xF000, where
| the buffers for an PCI ethernet device (if present) would start.
+-----------------------------------------------------------------------------*/
#define NUM_TX_BUFF 1
#define NUM_RX_BUFF 4
#define TX_BUF_START 0x0000A000
#define RX_BUF_START 0x0000A800

/* Ethernet Transmit and Receive Buffers */
#define DBUF_LENGTH  1520
/* #define PKTBUFSRX 2 */

/* static char rxbuf[PKTBUFSRX][ DBUF_LENGTH ]; */
static char *txbuf_ptr;

/*-----------------------------------------------------------------------------+
| Defines for TX and RX descriptors.
| IMPORTANT: The descriptors should be placed in NON-CACHEABLE memory since
|            they are 8 bytes each and must be contiguous. If they were
|            placed in cacheable memory, maintaining software cache coherency
|            may not be possible as a cache flush of a single descriptor could
|            corrupt the other three (in real memory) that are within the same
|            cache line. Here we use the SRAM on the board for the descriptors.
|            The 405GP reference board has 512K of SRAM. The first
|            0x1000 bytes should be reserved for this driver.
+-----------------------------------------------------------------------------*/
#define EMAC_TX_DESCRIPTOR_ADDR 0x00ef0000
#define EMAC_RX_DESCRIPTOR_ADDR (EMAC_TX_DESCRIPTOR_ADDR + \
                                (4 * NUM_TX_BUFF * sizeof(mal_desc_t)))

/* define the number of channels implemented */
#define EMAC_RXCHL      1
#define EMAC_TXCHL      1

/*-----------------------------------------------------------------------------+
| Defines for MAL/EMAC interrupt conditions as reported in the UIC (Universal
| Interrupt Controller).
+-----------------------------------------------------------------------------*/
#define MAL_UIC_ERR ( UIC_MAL_SERR | UIC_MAL_TXDE  | UIC_MAL_RXDE)
#define MAL_UIC_DEF  (UIC_MAL_RXEOB | MAL_UIC_ERR)
#define EMAC_UIC_DEF UIC_ENET

/*-----------------------------------------------------------------------------+
| Global variables. TX and RX descriptors and buffers.
+-----------------------------------------------------------------------------*/
static volatile mal_desc_t *tx;
static volatile mal_desc_t *rx;

/* IER globals */
static unsigned long emac_ier;
static unsigned long mal_ier;


/* Statistic Areas */
#define MAX_ERR_LOG 10
struct emac_stats
{
  int data_len_err;
  int rx_frames;
  int rx;
  int rx_prot_err;
};

static struct stats
{                               /* Statistic Block */
  struct emac_stats emac;
  int int_err;
  short tx_err_log[MAX_ERR_LOG];
  short rx_err_log[MAX_ERR_LOG];
} stats;

static int first_init   = 0;

static int tx_err_index = 0;           /* Transmit Error Index for tx_err_log */
static int rx_err_index = 0;           /* Receive Error Index for rx_err_log */

static int rx_slot = 0;                /* MAL Receive Slot */
static int rx_i_index = 0;             /* Receive Interrupt Queue Index */
static int rx_u_index = 0;             /* Receive User Queue Index */
static int rx_ready[NUM_RX_BUFF];      /* Receive Ready Queue */

static int tx_slot = 0;                /* MAL Transmit Slot */
static int tx_i_index = 0;             /* Transmit Interrupt Queue Index */
static int tx_u_index = 0;             /* Transmit User Queue Index */
static int tx_run[NUM_TX_BUFF];        /* Transmit Running Queue */

static volatile int rx_ptr = -1;

static char             emac_hwd_addr[ENET_ADDR_LENGTH];

static void enet_rcv (unsigned long malisr);

/*-----------------------------------------------------------------------------+
| Prototypes and externals.
+-----------------------------------------------------------------------------*/
void mal_err (unsigned long isr, unsigned long uic, unsigned long mal_def,
              unsigned long mal_errr);
void emac_err (unsigned long isr);


void eth_halt(void)
{
  /* EMAC RESET */
  out32 (EMAC_M0, EMAC_M0_SRST);
}


/*-----------------------------------------------------------------------------+
+----------------------------------------------------------------------------*/
int eth_init (bd_t *bis)
{
  int i;
  unsigned long reg;
  unsigned long msr;
  unsigned long speed;
  unsigned long duplex;
  unsigned mode_reg;

  malloc(10);

  msr = get_msr();
  set_msr(msr & ~(MSR_EE));

  /* MAL RESET */
  mtdcr(malmcr, MAL_CR_MMSR);

  tx_err_index = 0;           /* Transmit Error Index for tx_err_log */
  rx_err_index = 0;           /* Receive Error Index for rx_err_log */

  rx_slot = 0;                /* MAL Receive Slot */
  rx_i_index = 0;             /* Receive Interrupt Queue Index */
  rx_u_index = 0;             /* Receive User Queue Index */

  tx_slot = 0;                /* MAL Transmit Slot */
  tx_i_index = 0;             /* Transmit Interrupt Queue Index */
  tx_u_index = 0;             /* Transmit User Queue Index */

  /* EMAC RESET */
  out32 (EMAC_M0, EMAC_M0_SRST);
  for (i = 0; i < 1000; i++);
  out32 (EMAC_M0, in32 (EMAC_M0) & ~EMAC_M0_SRST);

  speed = miiphy_speed();
  printf("ENET Speed is %d Mbs... \n\r", (int)speed);
  duplex = miiphy_duplex();
  if( duplex == HALF)
    printf("HALF duplex connection\n\r");
  else
    printf("FULL duplex connection\n\r");

  /* set the Mal configuration reg */
  mtdcr(malmcr, MAL_CR_PLBB | MAL_CR_OPBBL | MAL_CR_LEA | MAL_CR_PLBLT_DEFAULT);

  /* set up the TX and RX descriptors */
  tx = (mal_desc_t *) EMAC_TX_DESCRIPTOR_ADDR;
  rx = (mal_desc_t *) EMAC_RX_DESCRIPTOR_ADDR;

  for (i = 0; i < NUM_TX_BUFF; i++)
    {
      tx[i].ctrl = 0;
      tx[i].data_len = 0;
      if (first_init == 0)
        txbuf_ptr = (char *)malloc(DBUF_LENGTH);
      tx[i].data_ptr = txbuf_ptr;
      if ((NUM_TX_BUFF - 1) == i)
        tx[i].ctrl |= MAL_TX_CTRL_WRAP;
      tx_run[i] = -1;
#if 0
      printf("TX_BUFF %d @ 0x%08lx\n", i, (ulong)tx[i].data_ptr);
#endif
    }

  for (i = 0; i < NUM_RX_BUFF; i++)
    {
      rx[i].ctrl = 0;
      rx[i].data_len = 0;
      //      rx[i].data_ptr = (char *) &rx_buff[i];
      rx[i].data_ptr = (char *)NetRxPackets[i];
      if ((NUM_RX_BUFF - 1) == i)
        rx[i].ctrl |= MAL_RX_CTRL_WRAP;
      rx[i].ctrl |=   MAL_RX_CTRL_EMPTY | MAL_RX_CTRL_INTR;
      rx_ready[i] = -1;
#if 0
      printf("RX_BUFF %d @ 0x%08lx\n", i, (ulong)rx[i].data_ptr);
#endif
    }

  memcpy(emac_hwd_addr, bis->bi_enetaddr, ENET_ADDR_LENGTH);

  reg = 0x00000000;

  reg |= emac_hwd_addr[0];           /* set high address */
  reg = reg << 8;
  reg |= emac_hwd_addr[1];

  out32 (EMAC_IAH, reg);

  reg = 0x00000000;
  reg |= emac_hwd_addr[2];           /* set low address  */
  reg = reg << 8;
  reg |= emac_hwd_addr[3];
  reg = reg << 8;
  reg |= emac_hwd_addr[4];
  reg = reg << 8;
  reg |= emac_hwd_addr[5];

  out32 (EMAC_IAL, reg);

  /* setup MAL tx & rx channel pointers */
  mtdcr(maltxctp0r, EMAC_TX_DESCRIPTOR_ADDR);
  mtdcr(malrxctp0r, EMAC_RX_DESCRIPTOR_ADDR);

  /* Reset transmit and receive channels */
  mtdcr(malrxcarr, 0x80000000);     /* 2 channels */
  mtdcr(maltxcarr, 0x80000000);     /* 2 channels */
  
  /* Enable MAL transmit and receive channels */
  mtdcr(maltxcasr, 0x80000000);     /* 1 channel */
  mtdcr(malrxcasr, 0x80000000);     /* 1 channel */

  /* set RX buffer size */
  mtdcr(malrcbs0, ENET_MAX_MTU_ALIGNED / 16);

  /* set transmit enable & receive enable */
  out32 (EMAC_M0, EMAC_M0_TXE | EMAC_M0_RXE);

  /* set receive fifo to 4k and tx fifo to 2k */
  mode_reg = EMAC_M1_RFS_4K | EMAC_M1_TX_FIFO_2K;

  /* set speed */
  if (speed == _100BASET)
    mode_reg = mode_reg | EMAC_M1_MF_100MBPS;
  else
    mode_reg = mode_reg & ~0x00C00000;  /* 10 MBPS */
  if( duplex == FULL)
    mode_reg = mode_reg | 0x80000000;

  out32 (EMAC_M1, mode_reg);

  /* Enable broadcast and indvidual address */
  out32 (EMAC_RXM, EMAC_RMR_BAE | EMAC_RMR_IAE /*|
                                                 EMAC_RMR_ARRP| EMAC_RMR_SFCS |
                                                 EMAC_RMR_SP */);

  /* we probably need to set the tx mode1 reg? maybe at tx time */

  /* set transmit request threshold register */
  out32 (EMAC_TRTR, 0x18000000);  /* 256 byte threshold */

  /* set recieve  low/high water mark register */
  out32 (EMAC_RX_HI_LO_WMARK, 0x0f002000);

  /* Frame gap set */
  out32 (EMAC_I_FRAME_GAP_REG, 0x00000008);

#if 0 /* test-only */

⌨️ 快捷键说明

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