📄 405gp_enet.c
字号:
/*-----------------------------------------------------------------------------+
|
| 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 + -