📄 am79970.c
字号:
/************************************************************* * File: lib/am79970.c * Purpose: A tftp driver for the Am79C970A Ethernet controller * Author: Phil Bunce (pjb@carmel.com) * Revision History: * 980615 Created from sonic.c * 981114 Functional for big endian. * 981125 Functional for little endian. * 981127 Moved the GETRXREC swapPkt to ether.c * 981216 Omit all of initDA if already done. This fixes the prob * of IDON timeout on second Ether download. * 990317 Updated value in initDA(). */#include <string.h>#include <utypes.h>#include <mips.h>#if 0 /* debug */#define STATIC /* */#else#define STATIC static#endif/*#define VERBOSE /* turn on verbose mode *//* * This file contains the low-level driver for the Am79C970A * Ethernet controller. It is called by functions in lib/ether.c. * When used this way, it is used to provide PMON with a method to * support download using tftp via Ethernet. *//* * Everything on this chip is accessed via 4 registers. RDP, RAP, RESET, * and BDP. RDP and RAP are used to access the CSR regs, RAP and BDP are * used to access the BCR regs. CSR1&2 point to the INIT block. The * rdr and tdr pointers in the INIT block point to the rx and tx descriptor * rings. Note that the byte-count fields hold the 2's complement of the * byte count. Visit www.amd.com for a full technical manual on the Am79C970A. */#define ETHER_BASE 0xbfe00000#ifdef CHECKS_ON#include <assert.h>#else#define assert(x)#endif#define inw(a) (*((Ulong *)(a)))#define outw(a,v) (*((Ulong *)(a))=(v))#define outh(a,v) (*((Ushort *)(a))=(v))#define swap32(n) ( \ ((((Ulong)(n))>>24)&0x000000ff) | \ ((((Ulong)(n))>>8)&0x0000ff00) | \ ((((Ulong)(n))<<8)&0x00ff0000) | \ ((((Ulong)(n))<<24)&0xff000000) \ )#ifdef ETHERNET /* skip the entire file if ethernet is not enabled */#define ALIGNED(n,a) (((Ulong)(a))&(n-1))?0:1typedef volatile struct RDrec { /* 16-byte align */ Ulong cw1; /* RCC RPC MCNT */ Ulong cw2; /* OWN ...... BCNT */ char *buf; int resv; } RDrec;#define MCNTMASK 0xfff /* RD cw1 */typedef volatile struct TDrec { /* 16-byte align */ Ulong cw1; /* BUFF .... TRC */ Ulong cw2; /* OWN ...... BCNT */ char *buf; int resv; } TDrec;/* pointed to by CSR2:CSR1 */typedef volatile struct INITrec { /* 4-byte align */ Ulong cw; /* TLE RLE MODE */ Ulong padr0; /* mac addr - ls byte is 1st byte of adr */ Ulong padr1; /* mac addr - last 2 bytes */ Ulong ladr0; /* multicast only - mbz */ Ulong ladr1; /* multicast only - mbz */ RDrec *rdr; TDrec *tdr; Ulong resv; } INITrec;#define TDRSIZE 3 /* 2^N of TDR size. ie. 2=4 3=8 4=16 5=32 */#define RDRSIZE 3 /* 2^N of RDR size. ie. 2=4 3=8 4=16 5=32 */#define RBUFSIZE 1500#define TBUFSIZE 64#define ATDRSIZE (1<<TDRSIZE) /* actual tdr size */#define ARDRSIZE (1<<RDRSIZE) /* actual rdr size *//* TD cw1 */#define BUFF (1<<31)#define UFLO (1<<30)#define EXDEF (1<<29)#define LCOL (1<<28)#define LCAR (1<<27)#define RTRY (1<<26)#define TDRMASK (0x3fff<12)/* TD cw2 */#define OWN (1<<31)#define ERR (1<<30)#define ADD (1<<29)#define MORE (1<<28)#define ONE (1<<27)#define DEF (1<<26)#define STP (1<<25)#define ENP (1<<24)#define BCNTMASK 0xfff /* RD & TD cw2: rx max buffer, tx bytes in buffer */#define ONES (0xf<<12) /* must be ones. required. RD & TD cw2 *//* INIT cw */#define TLE_SHFT 28#define RLE_SHFT 20TDrec *next_TD,*base_TD;int next_TDcnt;RDrec *next_RD,*base_RD;int next_RDcnt;/*************** Ethernet stuff ******************************/#include <ether.h>/****************** Globals **********************************/extern int vflag;static INITrec *init_ptr;/****************** Forward Declarations *********************/#define M_RDP (ETHER_BASE+0x10)#define M_RAP (ETHER_BASE+0x14)#define M_RESET (ETHER_BASE+0x18)#define M_BDP (ETHER_BASE+0x1c)/* PCI Configuration Space Definitions */#define PCI_VENDORID (0x00)#define PCI_DEVICEID (0x02)#define PCI_COMMAND (0x04)#define PCI_STATUS (0x06)#define PCI_REVID (0x08)#define PCI_PIR (0x09) /* Not used on AMD controller */#define PCI_SUBCLASS (0x0a)#define PCI_BASECLASS (0x0b)#define PCI_CACHELINE (0x0c)#define PCI_LATENCY (0x0d)#define PCI_HEADERTYPE (0x0e)#define PCI_BIST (0x0f) /* Not used on AMD controller */#define PCI_BASEADDRESS0 (0x10)#define PCI_BASEADDRESS1 (0x14)#define PCI_BASEADDRESS2 (0x18) /* Not used on AMD controller */#define PCI_BASEADDRESS3 (0x1c) /* Not used on AMD controller */#define PCI_BASEADDRESS4 (0x20) /* Not used on AMD controller */#define PCI_BASEADDRESS5 (0x24) /* Not used on AMD controller */#define PCI_CARDBUSCIS (0x28) /* Not used on AMD controller */#define PCI_SUBVENDORID (0x2c) /* Not used on AMD controller */#define PCI_SUBSYSID (0x2e) /* Not used on AMD controller */#define PCI_EXPANSIONROM (0x30)#define PCI_INTLINE (0x3c)#define PCI_INTPIN (0x3d)#define PCI_MINGNT (0x3e)#define PCI_MAXLAT (0x3f)#define TYPE0 0x00#define TYPE1 0x01#define AMDDEVAD 0xbfe90000 /* Ethernet controller has */ /* IDSEL connected to AD16 */#define AMD_VENDOR_ID 0x20001022#define CSR0_ERR (1<<15)#define CSR0_BABL (1<<14)#define CSR0_CERR (1<<13)#define CSR0_MISS (1<<12)#define CSR0_MERR (1<<11)#define CSR0_RINT (1<<10)#define CSR0_TINT (1<<9)#define CSR0_IDON (1<<8)#define CSR0_INTR (1<<7)#define CSR0_IENA (1<<6)#define CSR0_RXON (1<<5)#define CSR0_TXON (1<<4)#define CSR0_TDMD (1<<3)#define CSR0_STOP (1<<2)#define CSR0_STRT (1<<1)#define CSR0_INIT (1<<0)#define CSR_STATUS 0 /* 16-bit */#define CSR_INIT 1 /* 32-bit */#define CSR_RDRBASE 24 /* 32-bit */#define CSR_RDRNEXT 26 /* 32-bit */#define CSR_RDRCUR 28 /* 32-bit */#define CSR_TDRBASE 30 /* 32-bit */#define CSR_TDRCUR 34 /* 32-bit */#define CSR_RDRCNT 72 /* 16-bit */#define CSR_TDRCNT 74 /* 16-bit */#define CSR_RDRLEN 76 /* 16-bit */#define CSR_TDRLEN 78 /* 16-bit */#define CSR3_BSWP (1<<2) /* byte swap */#define BCR20_SSIZE32 (1<<8)#define SWSTYLE_3 3/* csr15 is programmed via word0 of the init block */#define CSR15_PROM (1<<15) /* enable promiscuous mode */#define CSR15_DRCVBC (1<<14) /* disable rx broadcast */#define CSR15_DRCVPA (1<<13) /* disable rx phy adr */#define CSR15_DLNKTST (1<<12) /* disable link status */#define CSR15_DAPC (1<<11) /* disable auto pol corr */#define CSR15_MENDECL (1<<10) /* mendec loopback mode */#define CSR15_LRT (1<<9) /* low rx threshold (T-MAU) */#define CSR15_TSEL (1<<9) /* low rx threshold (AUI) */#define CSR15_PORTSELMSK (3<<7) /* port select bits */#define CSR15_INTL (1<<6) /* internal loopback */#define CSR15_DRTY (1<<5) /* disable retry */#define CSR15_FCOLL (1<<4) /* force collision */#define CSR15_DXMTFCS (1<<3) /* disable tx crc */#define CSR15_LOOP (1<<2) /* loopback mode */#define CSR15_DTX (1<<1) /* disable tx */#define CSR15_DRX (1<<0) /* disable rx *//************************************************************** void *xalloc(int size)* On bdmr4102, can't use std malloc as that allocs from sdram. * PCI Ethernet controller can't access sdram. Use 128KB of sram * at 0xae000000 instead.*/void *xalloc(int size){static void *bufptr;void *v;if (bufptr == 0) bufptr = (void *)0xae000000;v = bufptr;size = (size+16)&~15;((char *)bufptr) += size;if (bufptr >= (void *)0xae020000) return(0);return(v);}/**************************************************************/STATIC Ushort getCSR(int n){Ushort v;outw(M_RAP,n);v = inw(M_RDP);return(v);}/**************************************************************/STATIC Ulong getCSRw(int n){Ulong v;v = (getCSR(n+1)<<16)|getCSR(n);return(v);}/**************************************************************/STATIC void putCSR(int n,Ulong v){outw(M_RAP,n);outw(M_RDP,v);}/**************************************************************/STATIC void putCSRw(int n,Ulong v){putCSR(n+1,v>>16);putCSR(n,v&0xffff);}/**************************************************************/STATIC Ushort getBCR(int n){outw(M_RAP,n);return(inw(M_BDP));}/**************************************************************/STATIC void putBCR(int n,Ushort v){outw(M_RAP,n);outw(M_BDP,v);}#ifdef VERBOSE/**************************************************************/STATIC void printRD(RDrec *r){if (((Ulong)r)&0xf) printf("error: RDrec not aligned.\n");printf("RDrec %08x: ",r);printf("cw1=%08x ",r->cw1);printf("cw2=%08x ",r->cw2);printf("buf=%08x ",r->buf);printf("resv=%x ",r->resv);printf("\n");}/**************************************************************/STATIC void printTD(TDrec *r){if (((Ulong)r)&0xf) printf("error: TDrec not aligned.\n");printf("TDrec %08x: ",r);printf("cw1=%08x ",r->cw1);printf("cw2=%08x ",r->cw2);printf("buf=%08x ",r->buf);printf("resv=%x ",r->resv);printf("\n");}/**************************************************************/STATIC printINIT(INITrec *r){if (((Ulong)r)&0x3) printf("error: INITrec not aligned.\n");printf("INITrec %08x:\n\t",r);printf("cw=%08x ",r->cw);printf("mac=%04x%08x ",r->padr1,r->padr0);printf("ladr=%x.%x ",r->ladr1,r->ladr0);printf("rdr=%08x ",r->rdr);printf("tdr=%08x ",r->tdr);printf("\n");}/**************************************************************/STATIC void printCSRs(){int i;for (i=0;i<32;i++) { if ((i%8)==0) printf("\n%2d - ",i); printf("%04x ",getCSR(i)); }printf("\n");}#endif/**************************************************************/STATIC int initDA(Uchar *macadr){INITrec *ir;RDrec *rr;TDrec *tr;int i;Ulong v;if (init_ptr) return(1); /* 981216 only do this the first time *//* # Setup Ethernet PCI Configuration Space # # Since this is an embedded application with no expansion slots this # code forgoes the process of scanning all PCI devices. We do a # detect of the the AMD ethernet controller as Device 20 which has # IDSEL pin hardwired to AD16 on the eval board. The routine then # maps the ethernet registers to 0x1fbb0000 and IO space starting at 0x0, # configures timing, disables the expansion ROM, and configures interrupts. # The routine finishs by configuring the Fbus unit # # Set up Bus Unit for Configuration Transaction *//* Map all 1fexxxxx memory space to PCI */outw(M_FBUSCMP,0x000f1fe0);/* map cfg space starting at 0x1e000000 - 0x1effffff */outw(M_FBUSAC,0x40071fe8);/* Configure FBUS unit. Burst length set to 1 and Ext Ack. Mmaster */outw(M_FBUSCFG,0x08); /* 990317 was 0x0c */ /* Perform a PCI Device Detect */v = inw(AMDDEVAD+PCI_VENDORID);if (v != AMD_VENDOR_ID) { printf("failed device detect %08x\n",v); return(0); }/* Disconnect Controller from all but configuration cycles */outw(AMDDEVAD+PCI_COMMAND,0);/* # Even though there is no IO space in MIPS we will initialize # the register to begin at zero. The bus controller on the 4102 # supports IO space so if somebody wants to use it, it starts at 0x0 */outw(AMDDEVAD+PCI_BASEADDRESS0,0);outw(AMDDEVAD+PCI_BASEADDRESS0+4,0);/* # Assign AMD Ethernet Controller to 0x1fe00000 # There are 32 bytes of address locations required */ outw(AMDDEVAD+PCI_BASEADDRESS1,ETHER_BASE-0xa0000000);outw(AMDDEVAD+PCI_BASEADDRESS1+4,0);/* # Disable Expansion ROM */outw(AMDDEVAD+PCI_EXPANSIONROM,0);/* # Configure Latency Timer */v = inw(AMDDEVAD+PCI_CACHELINE);v &= 0xffff00ff;outw(AMDDEVAD+PCI_CACHELINE,v);/* # Configure Command Register */outw(AMDDEVAD+PCI_COMMAND,0x07);/* Enable Bus Mastering, Memory Access, IO Access. Disable Parity, * SERR, VGA, etc. */outw(M_RDP,0); /* switch to DWORD mode *//* 981216 I used to wrap an if !init_ptr around just this section */ir = (INITrec *)xalloc(sizeof(INITrec));if (!ir || !ALIGNED(4,ir)) return(0);rr = (RDrec *)xalloc(sizeof(RDrec)*ARDRSIZE);if (!rr || !ALIGNED(16,rr)) return(0);ir->rdr = (log2phy(rr));base_RD = next_RD = rr;for (i=0;i<ARDRSIZE;i++,rr++) { rr->buf = (log2phy(xalloc(RBUFSIZE))); if (!rr->buf) return(0); rr->cw1 = rr->resv = 0; rr->cw2 = (OWN|ONES|((0-RBUFSIZE)&0xfff)); }tr = (TDrec *)xalloc(sizeof(TDrec)*ATDRSIZE);if (!tr || !ALIGNED(16,rr)) return(0);ir->tdr = (log2phy(tr));base_TD = next_TD = tr;for (i=0;i<ATDRSIZE;i++,tr++) { tr->buf = (log2phy(xalloc(TBUFSIZE))); if (!tr->buf) return(0); tr->cw1 = tr->resv = 0; tr->cw2 = (ONES|((0-TBUFSIZE)&0xfff)); }init_ptr = ir;putBCR(20,BCR20_SSIZE32|SWSTYLE_3);putBCR(6,1); /* led2 = collisions */#ifdef MIPSEBputCSR(3,CSR3_BSWP); /* byte swap */#endifir->cw = (TDRSIZE<<TLE_SHFT)|(RDRSIZE<<RLE_SHFT);#ifdef PROMISCUOUSir->cw |= CSR15_PROM;#endifir->padr0 = ((macadr[3]<<24)|(macadr[2]<<16)|(macadr[1]<<8)|macadr[0]);ir->padr1 = ((macadr[5]<<8)|macadr[4]);ir->ladr0 = ir->ladr1 = ir->resv = 0;putCSRw(CSR_INIT,(Ulong)log2phy(ir));putCSR(0,CSR0_STRT|CSR0_INIT);for (i=0;i<1000000;i++) if (getCSR(0)&CSR0_IDON) break;if (i >= 1000000) { printf("timeout waiting for IDON.\n"); putCSR(0,CSR0_STOP);#ifdef VERBOSE printCSRs(); printINIT(ir);#endif return(0); }return(1);}/************************************************************** volatile void *am79970_driver(int op,void *vp1,void *vp2)* Main entry point for the driver.*/volatile void *am79970_driver(int op,void *vp1,void *vp2){char *macAddr = vp1;RDrec *rr = vp1;int *pLen = vp2;TDrec *tr;int n;switch (op) { case ETHER_INIT : /* int ether_driver(ETHER_INIT,Uchar *macAddr,void) */ if (!initDA(macAddr)) return(0); return((void *)1); case ETHER_GETTBA : /* char *ether_driver(ETHER_GETTBA,void, int *len) */ tr = next_TD; if (tr->cw2&OWN) return(0); n = *pLen; tr->cw2 = ONES|STP|ENP|((0-n)&0xfff); return(phy2k1(tr->buf)); case ETHER_TBARDY : /* int ether_driver(ETHER_TBRDY,void,void) */ tr = next_TD; tr->cw2 |= OWN; putCSR(CSR_STATUS,getCSR(CSR_STATUS)|CSR0_TDMD); /* inform the chip */ next_TD++; next_TDcnt++; if (next_TDcnt >= ATDRSIZE) { next_TD = base_TD; next_TDcnt = 0; } return((void *)1); case ETHER_GETRXREC : /* RXREC *ether_driver(ETHER_GETRXREC,void,void) */ rr = next_RD; if (rr->cw2&OWN) return(0); return(rr); case ETHER_GETRBA : /* char *ether_driver(ETHER_GETRBA,RXrec *rr,int *len) */ *pLen = rr->cw1&MCNTMASK; return(phy2k1(rr->buf)); case ETHER_RXDONE : /* int ether_driver(ETHER_RXDONE,RXrec *rr,void) */ rr->cw2 |= OWN; next_RD++; next_RDcnt++; if (next_RDcnt >= ARDRSIZE) { next_RD = base_RD; next_RDcnt = 0; } return((void *)1); case ETHER_RXRDY : /* int ether_driver(ETHER_RXRDY,void,void) */ rr = next_RD; if (rr->cw2&OWN) return(0); return((void *)1); default : return(0); }return(0);}#elseam79970_foobar() {}#endif /* ETHERNET */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -