URL
https://opencores.org/ocsvn/openrisc/openrisc/trunk
Subversion Repositories openrisc
Compare Revisions
- This comparison shows the changes necessary to convert path
/openrisc/trunk/orpsocv2/boards/xilinx/ml501/sw
- from Rev 67 to Rev 69
- ↔ Reverse comparison
Rev 67 → Rev 69
/eth/eth.c
0,0 → 1,935
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Interrupt-driven Ethernet test code //// |
//// //// |
//// Description //// |
//// ORPSoC test software //// |
//// //// |
//// To Do: //// |
//// - It's a simple test for now, but could be adapted for //// |
//// standalone use. //// |
//// //// |
//// Author(s): //// |
//// - jb, jb@orsoc.se, with parts taken from Linux kernel //// |
//// open_eth driver. //// |
//// //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Copyright (C) 2009 Authors and OPENCORES.ORG //// |
//// //// |
//// This source file may be used and distributed without //// |
//// restriction provided that this copyright statement is not //// |
//// removed from the file and that any derivative work contains //// |
//// the original copyright notice and the associated disclaimer. //// |
//// //// |
//// This source file is free software; you can redistribute it //// |
//// and/or modify it under the terms of the GNU Lesser General //// |
//// Public License as published by the Free Software Foundation; //// |
//// either version 2.1 of the License, or (at your option) any //// |
//// later version. //// |
//// //// |
//// This source is distributed in the hope that it will be //// |
//// useful, but WITHOUT ANY WARRANTY; without even the implied //// |
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //// |
//// PURPOSE. See the GNU Lesser General Public License for more //// |
//// details. //// |
//// //// |
//// You should have received a copy of the GNU Lesser General //// |
//// Public License along with this source; if not, download it //// |
//// from http://www.opencores.org/lgpl.shtml //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
|
#include "support.h" |
#include "board.h" |
#include "spr_defs.h" |
#include "int.h" |
#include "uart.h" |
#include "open_eth.h" |
#include "mii.h" |
|
/* Dummy exception functions */ |
void buserr_except(){} |
void dpf_except(){} |
void ipf_except(){} |
void lpint_except(){} |
void align_except(){} |
void illegal_except(){} |
void hpint_except(){} |
void dtlbmiss_except(){} |
void itlbmiss_except(){} |
void range_except(){} |
void syscall_except(){} |
void fpu_except(){} |
void trap_except(){} |
void res2_except(){} |
|
volatile unsigned tx_done; |
|
/* Functions in this file */ |
void ethmac_setup(void); |
void oeth_printregs(void); |
void ethphy_init(void); |
void oeth_dump_bds(); |
/* Interrupt functions */ |
void oeth_interrupt(void); |
static void oeth_rx(void); |
static void oeth_tx(void); |
|
/* Defining RTLSIM turns off use of real printf'ing to save time in simulation */ |
//#define RTLSIM |
|
#ifdef RTLSIM |
#define printk |
#else |
#define printk printf |
#endif |
|
/* Let the ethernet packets use a space beginning here for buffering */ |
#define ETH_BUFF_BASE 0x01000000 |
|
|
#define RXBUFF_PREALLOC 1 |
#define TXBUFF_PREALLOC 1 |
//#undef RXBUFF_PREALLOC |
//#undef TXBUFF_PREALLOC |
|
/* The transmitter timeout |
*/ |
#define TX_TIMEOUT (2*HZ) |
|
/* Buffer number (must be 2^n) |
*/ |
#define OETH_RXBD_NUM 8 |
#define OETH_TXBD_NUM 8 |
#define OETH_RXBD_NUM_MASK (OETH_RXBD_NUM-1) |
#define OETH_TXBD_NUM_MASK (OETH_TXBD_NUM-1) |
|
/* Buffer size |
*/ |
#define OETH_RX_BUFF_SIZE 2048 |
#define OETH_TX_BUFF_SIZE 2048 |
|
/* OR32 Page size def */ |
#define PAGE_SHIFT 13 |
#define PAGE_SIZE (1UL << PAGE_SHIFT) |
|
/* How many buffers per page |
*/ |
#define OETH_RX_BUFF_PPGAE (PAGE_SIZE/OETH_RX_BUFF_SIZE) |
#define OETH_TX_BUFF_PPGAE (PAGE_SIZE/OETH_TX_BUFF_SIZE) |
|
/* How many pages is needed for buffers |
*/ |
#define OETH_RX_BUFF_PAGE_NUM (OETH_RXBD_NUM/OETH_RX_BUFF_PPGAE) |
#define OETH_TX_BUFF_PAGE_NUM (OETH_TXBD_NUM/OETH_TX_BUFF_PPGAE) |
|
/* Buffer size (if not XXBUF_PREALLOC |
*/ |
#define MAX_FRAME_SIZE 1518 |
|
/* The buffer descriptors track the ring buffers. |
*/ |
struct oeth_private { |
//struct sk_buff* rx_skbuff[OETH_RXBD_NUM]; |
//struct sk_buff* tx_skbuff[OETH_TXBD_NUM]; |
|
unsigned short tx_next; /* Next buffer to be sent */ |
unsigned short tx_last; /* Next buffer to be checked if packet sent */ |
unsigned short tx_full; /* Buffer ring fuul indicator */ |
unsigned short rx_cur; /* Next buffer to be checked if packet received */ |
|
oeth_regs *regs; /* Address of controller registers. */ |
oeth_bd *rx_bd_base; /* Address of Rx BDs. */ |
oeth_bd *tx_bd_base; /* Address of Tx BDs. */ |
|
// struct net_device_stats stats; |
}; |
/* |
void * memcpy(char* dest, char* src, int size) |
{ |
int i; |
for (i=0;i<size;i++) dest[i] = src[i]; |
return (void*) dest; |
} |
*/ |
void oeth_printregs(void) |
{ |
volatile oeth_regs *regs; |
regs = (oeth_regs *)(OETH_REG_BASE); |
|
printk("Oeth regs: Mode Register : 0x%lx\n",(unsigned long) regs->moder); /* Mode Register */ |
printk("Oeth regs: Interrupt Source Register 0x%lx\n", (unsigned long) regs->int_src); /* Interrupt Source Register */ |
printk("Oeth regs: Interrupt Mask Register 0x%lx\n",(unsigned long) regs->int_mask); /* Interrupt Mask Register */ |
printk("Oeth regs: Back to Bak Inter Packet Gap Register 0x%lx\n",(unsigned long) regs->ipgt); /* Back to Bak Inter Packet Gap Register */ |
printk("Oeth regs: Non Back to Back Inter Packet Gap Register 1 0x%lx\n",(unsigned long) regs->ipgr1); /* Non Back to Back Inter Packet Gap Register 1 */ |
printk("Oeth regs: Non Back to Back Inter Packet Gap Register 2 0x%lx\n",(unsigned long) regs->ipgr2); /* Non Back to Back Inter Packet Gap Register 2 */ |
printk("Oeth regs: Packet Length Register (min. and max.) 0x%lx\n",(unsigned long) regs->packet_len); /* Packet Length Register (min. and max.) */ |
printk("Oeth regs: Collision and Retry Configuration Register 0x%lx\n",(unsigned long) regs->collconf); /* Collision and Retry Configuration Register */ |
printk("Oeth regs: Transmit Buffer Descriptor Number Register 0x%lx\n",(unsigned long) regs->tx_bd_num); /* Transmit Buffer Descriptor Number Register */ |
printk("Oeth regs: Control Module Mode Register 0x%lx\n",(unsigned long) regs->ctrlmoder); /* Control Module Mode Register */ |
printk("Oeth regs: MII Mode Register 0x%lx\n",(unsigned long) regs->miimoder); /* MII Mode Register */ |
printk("Oeth regs: MII Command Register 0x%lx\n",(unsigned long) regs->miicommand); /* MII Command Register */ |
printk("Oeth regs: MII Address Register 0x%lx\n",(unsigned long) regs->miiaddress); /* MII Address Register */ |
printk("Oeth regs: MII Transmit Data Register 0x%lx\n",(unsigned long) regs->miitx_data); /* MII Transmit Data Register */ |
printk("Oeth regs: MII Receive Data Register 0x%lx\n",(unsigned long) regs->miirx_data); /* MII Receive Data Register */ |
printk("Oeth regs: MII Status Register 0x%lx\n",(unsigned long) regs->miistatus); /* MII Status Register */ |
printk("Oeth regs: MAC Individual Address Register 0 0x%lx\n",(unsigned long) regs->mac_addr0); /* MAC Individual Address Register 0 */ |
printk("Oeth regs: MAC Individual Address Register 1 0x%lx\n",(unsigned long) regs->mac_addr1); /* MAC Individual Address Register 1 */ |
printk("Oeth regs: Hash Register 0 0x%lx\n",(unsigned long) regs->hash_addr0); /* Hash Register 0 */ |
printk("Oeth regs: Hash Register 1 0x%lx\n",(unsigned long) regs->hash_addr1); /* Hash Register 1 */ |
|
} |
|
static int last_char; |
|
void spin_cursor(void) |
{ |
#ifdef RTLSIM |
return; |
#endif |
volatile unsigned int i; // So the loop doesn't get optimised away |
printk(" \r"); |
if (last_char == 0) |
printk("/"); |
else if (last_char == 1) |
printk("-"); |
else if (last_char == 2) |
printk("\\"); |
else if (last_char == 3) |
printk("|"); |
else if (last_char == 4) |
printk("/"); |
else if (last_char == 5) |
printk("-"); |
else if (last_char == 6) |
printk("\\"); |
else if (last_char == 7) |
{ |
printk("|"); |
last_char=-1; |
} |
|
last_char++; |
|
for(i=0;i<20000;i++); |
|
} |
|
#define PHYNUM 0 |
|
/* Scan the MIIM bus for PHYs */ |
void scan_ethphys(void) |
{ |
unsigned int phynum,regnum, i; |
|
volatile oeth_regs *regs; |
regs = (oeth_regs *)(OETH_REG_BASE); |
|
regs->miitx_data = 0; |
|
for(phynum=0;phynum<32;phynum++) |
{ |
for (regnum=0;regnum<8;regnum++) |
{ |
printk("scan_ethphys: phy %d r%d ",phynum, regnum); |
|
/* Now actually perform the read on the MIIM bus*/ |
regs->miiaddress = (regnum << 8) | phynum; /* Basic Control Register */ |
regs->miicommand = OETH_MIICOMMAND_RSTAT; |
|
while(!(regs->miistatus & OETH_MIISTATUS_BUSY)); /* Wait for command to be registered*/ |
|
regs->miicommand = 0; |
|
while(regs->miistatus & OETH_MIISTATUS_BUSY); |
|
printk("%x\n",regs->miirx_data); |
} |
} |
} |
|
|
void ethmac_scanstatus(void) |
{ |
volatile oeth_regs *regs; |
regs = (oeth_regs *)(OETH_REG_BASE); |
|
|
//printk("Oeth: regs->miistatus %x regs->miirx_data %x\n",regs->miistatus, regs->miirx_data); |
regs->miiaddress = 0; |
regs->miitx_data = 0; |
regs->miicommand = OETH_MIICOMMAND_SCANSTAT; |
//printk("Oeth: regs->miiaddress %x regs->miicommand %x\n",regs->miiaddress, regs->miicommand); |
//regs->miicommand = 0; |
volatile int i; for(i=0;i<1000;i++); |
while(regs->miistatus & OETH_MIISTATUS_BUSY) ; |
//spin_cursor(); |
//printk("\r"); |
or32_exit(0); |
} |
|
void |
eth_mii_write(char phynum, short regnum, short data) |
{ |
static volatile oeth_regs *regs = (oeth_regs *)(OETH_REG_BASE); |
regs->miiaddress = (regnum << 8) | phynum; |
regs->miitx_data = data; |
regs->miicommand = OETH_MIICOMMAND_WCTRLDATA; |
regs->miicommand = 0; |
while(regs->miistatus & OETH_MIISTATUS_BUSY); |
} |
|
short |
eth_mii_read(char phynum, short regnum) |
{ |
static volatile oeth_regs *regs = (oeth_regs *)(OETH_REG_BASE); |
regs->miiaddress = (regnum << 8) | phynum; |
regs->miicommand = OETH_MIICOMMAND_RSTAT; |
regs->miicommand = 0; |
while(regs->miistatus & OETH_MIISTATUS_BUSY); |
|
return regs->miirx_data; |
} |
|
|
void ethphy_init(void) |
{ |
/* Init the Alaska 88E1111 Phy */ |
char alaska88e1111_ml501_phynum = 0x7; |
|
/* Init, reset */ |
short ctl = eth_mii_read(alaska88e1111_ml501_phynum, MII_BMCR); |
ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_SPD2|BMCR_ANENABLE); |
ctl |= BMCR_SPEED100; // 100MBit |
ctl |= BMCR_FULLDPLX; // Full duplex |
eth_mii_write(alaska88e1111_ml501_phynum, MII_BMCR, ctl); |
|
// Setup Autoneg |
short adv = eth_mii_read(alaska88e1111_ml501_phynum, MII_ADVERTISE); |
adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4 | ADVERTISE_1000XFULL |
|ADVERTISE_1000XHALF | ADVERTISE_1000XPAUSE | |
ADVERTISE_1000XPSE_ASYM); |
adv |= ADVERTISE_10HALF; |
adv |= ADVERTISE_10FULL; |
adv |= ADVERTISE_100HALF; |
adv |= ADVERTISE_100FULL; |
eth_mii_write(alaska88e1111_ml501_phynum, MII_ADVERTISE, adv); |
// Disable gigabit |
adv = eth_mii_read(alaska88e1111_ml501_phynum, MII_CTRL1000); |
adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF); |
eth_mii_write(alaska88e1111_ml501_phynum, MII_CTRL1000, adv); |
|
// Restart autoneg |
printk("Resetting phy...\n"); |
ctl = eth_mii_read(alaska88e1111_ml501_phynum, MII_BMCR); |
ctl |= (BMCR_ANENABLE | BMCR_ANRESTART); |
eth_mii_write(alaska88e1111_ml501_phynum, MII_BMCR, ctl); |
|
printk("\nOeth: PHY control reg: 0x%.4x\n",eth_mii_read(alaska88e1111_ml501_phynum, MII_BMCR)); |
printk("Oeth: PHY control reg: 0x%.4x\n",eth_mii_read(alaska88e1111_ml501_phynum, MII_BMSR)); |
printk("Oeth: PHY id0: 0x%.4x\n",eth_mii_read(alaska88e1111_ml501_phynum, MII_PHYSID1)); |
printk("Oeth: PHY id1: 0x%.4x\n",eth_mii_read(alaska88e1111_ml501_phynum, MII_PHYSID2)); |
printk("Oeth: PHY adv: 0x%.4x\n",eth_mii_read(alaska88e1111_ml501_phynum, MII_ADVERTISE)); |
printk("Oeth: PHY lpa: 0x%.4x\n",eth_mii_read(alaska88e1111_ml501_phynum, MII_LPA)); |
printk("Oeth: PHY physpec: 0x%.4x\n",eth_mii_read(alaska88e1111_ml501_phynum, MII_M1011_PHY_SPEC_CONTROL)); |
printk("Oeth: PHY expansion: 0x%.4x\n",eth_mii_read(alaska88e1111_ml501_phynum, MII_EXPANSION )); |
printk("Oeth: PHY ctrl1000: 0x%.4x\n",eth_mii_read(alaska88e1111_ml501_phynum, MII_CTRL1000)); |
printk("Oeth: PHY stat1000: 0x%.4x\n",eth_mii_read(alaska88e1111_ml501_phynum, MII_STAT1000)); |
printk("Oeth: PHY estatus: 0x%.4x\n",eth_mii_read(alaska88e1111_ml501_phynum, MII_ESTATUS)); |
|
} |
|
|
void ethmac_setup(void) |
{ |
// from arch/or32/drivers/open_eth.c |
volatile oeth_regs *regs; |
|
regs = (oeth_regs *)(OETH_REG_BASE); |
|
/*printk("\nbefore reset\n\n"); |
oeth_printregs();*/ |
|
/* Reset MII mode module */ |
regs->miimoder = OETH_MIIMODER_RST; /* MII Reset ON */ |
regs->miimoder &= ~OETH_MIIMODER_RST; /* MII Reset OFF */ |
regs->miimoder = 0x64; /* Clock divider for MII Management interface */ |
|
/* Reset the controller. |
*/ |
regs->moder = OETH_MODER_RST; /* Reset ON */ |
regs->moder &= ~OETH_MODER_RST; /* Reset OFF */ |
|
//printk("\nafter reset\n\n"); |
//oeth_printregs(); |
|
/* Setting TXBD base to OETH_TXBD_NUM. |
*/ |
regs->tx_bd_num = OETH_TXBD_NUM; |
|
|
/* Set min/max packet length |
*/ |
regs->packet_len = 0x00400600; |
|
/* Set IPGT register to recomended value |
*/ |
regs->ipgt = 0x12; |
|
/* Set IPGR1 register to recomended value |
*/ |
regs->ipgr1 = 0x0000000c; |
|
/* Set IPGR2 register to recomended value |
*/ |
regs->ipgr2 = 0x00000012; |
|
/* Set COLLCONF register to recomended value |
*/ |
regs->collconf = 0x000f003f; |
|
/* Set control module mode |
*/ |
#if 0 |
regs->ctrlmoder = OETH_CTRLMODER_TXFLOW | OETH_CTRLMODER_RXFLOW; |
#else |
regs->ctrlmoder = 0; |
#endif |
|
/* Clear MIIM registers */ |
regs->miitx_data = 0; |
regs->miiaddress = 0; |
regs->miicommand = 0; |
|
regs->mac_addr1 = ETH_MACADDR0 << 8 | ETH_MACADDR1; |
regs->mac_addr0 = ETH_MACADDR2 << 24 | ETH_MACADDR3 << 16 | ETH_MACADDR4 << 8 | ETH_MACADDR5; |
|
/* Clear all pending interrupts |
*/ |
regs->int_src = 0xffffffff; |
|
/* Promisc, IFG, CRCEn |
*/ |
regs->moder |= OETH_MODER_PRO | OETH_MODER_PAD | OETH_MODER_IFG | OETH_MODER_CRCEN | OETH_MODER_FULLD; |
|
/* Enable interrupt sources. |
*/ |
|
regs->int_mask = OETH_INT_MASK_TXB | |
OETH_INT_MASK_TXE | |
OETH_INT_MASK_RXF | |
OETH_INT_MASK_RXE | |
OETH_INT_MASK_BUSY | |
OETH_INT_MASK_TXC | |
OETH_INT_MASK_RXC; |
|
printk("\nafter config\n\n"); |
oeth_printregs(); |
|
// Buffer setup stuff |
volatile oeth_bd *tx_bd, *rx_bd; |
int i,j,k; |
|
/* Initialize TXBD pointer |
*/ |
tx_bd = (volatile oeth_bd *)OETH_BD_BASE; |
|
/* Initialize RXBD pointer |
*/ |
rx_bd = ((volatile oeth_bd *)OETH_BD_BASE) + OETH_TXBD_NUM; |
|
/* Preallocated ethernet buffer setup */ |
unsigned long mem_addr = ETH_BUFF_BASE; /* Defined at top */ |
|
/* Setup for TX buffers*/ |
for(i = 0, k = 0; i < OETH_TX_BUFF_PAGE_NUM; i++) { |
for(j = 0; j < OETH_TX_BUFF_PPGAE; j++, k++) { |
//tx_bd[k].len_status = OETH_TX_BD_PAD | OETH_TX_BD_CRC | OETH_RX_BD_IRQ; |
tx_bd[k].len_status = OETH_TX_BD_PAD | OETH_TX_BD_CRC; |
tx_bd[k].addr = mem_addr; |
mem_addr += OETH_TX_BUFF_SIZE; |
} |
} |
tx_bd[OETH_TXBD_NUM - 1].len_status |= OETH_TX_BD_WRAP; |
|
/* Setup for RX buffers */ |
for(i = 0, k = 0; i < OETH_RX_BUFF_PAGE_NUM; i++) { |
for(j = 0; j < OETH_RX_BUFF_PPGAE; j++, k++) { |
rx_bd[k].len_status = OETH_RX_BD_EMPTY | OETH_RX_BD_IRQ; /* Enable interrupt */ |
rx_bd[k].addr = mem_addr; |
mem_addr += OETH_RX_BUFF_SIZE; |
} |
} |
rx_bd[OETH_RXBD_NUM - 1].len_status |= OETH_RX_BD_WRAP; /* Final buffer has wrap bit set */ |
|
/* Enable receiver and transmiter |
*/ |
regs->moder |= OETH_MODER_RXEN | OETH_MODER_TXEN; |
|
return; |
} |
|
/* Find the next available transmit buffer */ |
struct oeth_bd* get_next_tx_bd() |
{ |
int i; |
volatile oeth_bd *tx_bd; |
tx_bd = (volatile oeth_bd *)OETH_BD_BASE; /* Search from beginning*/ |
|
/* Go through the TX buffs, search for unused one */ |
for(i = 0; i < OETH_TXBD_NUM; i++) { |
if(!(tx_bd[i].len_status & OETH_TX_BD_READY)) /* Looking for buffer NOT ready for transmit. ie we can manipulate it */ |
{ |
printk("Oeth: Using TX_bd at 0x%lx\n",(unsigned long)&tx_bd[i]); |
return (struct oeth_bd*) &tx_bd[i]; |
} |
} |
|
printk("No free tx buffers\n"); |
/* Set to null our returned buffer */ |
tx_bd = (volatile oeth_bd *) 0; |
return (struct oeth_bd*) tx_bd; |
|
} |
|
|
/* print packet contents */ |
static void |
oeth_print_packet(unsigned long add, int len) |
{ |
int i; |
printk("ipacket: add = %lx len = %d\n", add, len); |
for(i = 0; i < len; i++) { |
if(!(i % 16)) |
printk("\n"); |
printk(" %.2x", *(((unsigned char *)add) + i)); |
} |
printk("\n"); |
} |
|
/* Setup buffer descriptors with data */ |
/* length is in BYTES */ |
void tx_packet(void* data, int length) |
{ |
volatile oeth_regs *regs; |
regs = (oeth_regs *)(OETH_REG_BASE); |
|
volatile oeth_bd *tx_bd; |
volatile int i; |
|
if((tx_bd = (volatile oeth_bd *) get_next_tx_bd()) == NULL) |
{ |
printk("No more TX buffers available\n"); |
return; |
} |
printk("Oeth: TX_bd buffer address: 0x%lx\n",(unsigned long) tx_bd->addr); |
|
/* Clear all of the status flags. |
*/ |
tx_bd->len_status &= ~OETH_TX_BD_STATS; |
|
/* If the frame is short, tell CPM to pad it. |
*/ |
#define ETH_ZLEN 60 /* Min. octets in frame sans FCS */ |
if (length <= ETH_ZLEN) |
tx_bd->len_status |= OETH_TX_BD_PAD; |
else |
tx_bd->len_status &= ~OETH_TX_BD_PAD; |
|
printk("Oeth: Copying %d bytes from 0x%lx to TX_bd buffer at 0x%lx\n",length,(unsigned long) data,(unsigned long) tx_bd->addr); |
|
/* Copy the data into the transmit buffer, byte at a time */ |
char* data_p = (char*) data; |
char* data_b = (char*) tx_bd->addr; |
for(i=0;i<length;i++) |
{ |
*(data_b+i) = *(data_p+i); |
} |
printk("Oeth: Data copied to buffer\n"); |
|
/* Set the length of the packet's data in the buffer descriptor */ |
tx_bd->len_status = (tx_bd->len_status & 0x0000ffff) | |
((length&0xffff) << 16); |
|
//oeth_print_packet(tx_bd->addr, (tx_bd->len_status >> 16)); |
|
/* Send it on its way. Tell controller its ready, interrupt when sent |
* and to put the CRC on the end. |
*/ |
tx_bd->len_status |= (OETH_TX_BD_READY | OETH_TX_BD_CRC | OETH_TX_BD_IRQ); |
|
oeth_dump_bds(); |
|
printk("Oeth: MODER addr: 0x%x\n", regs->moder); |
|
printk("Oeth: TXBD Status 0x%x\n", tx_bd->len_status); |
|
i=0; |
|
/* Wait for BD READY bit to be cleared, indicating it's been sent */ |
/* Not if we've got interrupts enabled. */ |
/* |
while (OETH_TX_BD_READY & tx_bd->len_status) |
{ |
#ifndef RTLSIM |
//for(i=0;i<40000;i++); |
//printk("Oeth: TXBD Status 0x%x\n", tx_bd->len_status); |
//oeth_printregs(); |
spin_cursor(); |
if (i++%64==63) {oeth_dump_bds();} |
#endif |
} |
*/ |
|
return; |
|
|
} |
|
/* enable RX, loop waiting for arrived packets and print them out */ |
void oeth_monitor_rx(void) |
{ |
volatile oeth_regs *regs; |
regs = (oeth_regs *)(OETH_REG_BASE); |
|
/* Set RXEN in MAC MODER */ |
regs->moder = OETH_MODER_RXEN | regs->moder; |
|
|
volatile oeth_bd *rx_bd; |
rx_bd = ((volatile oeth_bd *)OETH_BD_BASE) + OETH_TXBD_NUM; |
|
volatile int i; |
|
while (1) |
{ |
|
for(i=0;i<OETH_RXBD_NUM;i++) |
{ |
if (!(rx_bd[i].len_status & OETH_RX_BD_EMPTY)) /* Not empty */ |
{ |
// Something in this buffer! |
printk("Oeth: RX in buf %d - len_status: 0x%lx\n",i, rx_bd[i].len_status); |
oeth_print_packet(rx_bd[i].addr, rx_bd[i].len_status >> 16); |
/* Clear recieved bit */ |
rx_bd[i].len_status |= OETH_RX_BD_EMPTY; |
printk("\t end of packet\n\n"); |
} |
} |
} |
} |
|
/* Print out all buffer descriptors */ |
void oeth_dump_bds() |
{ |
unsigned long* bd_base = (unsigned long*) OETH_BD_BASE; |
|
int i; |
for(i=0;i<OETH_TXBD_NUM;i++) |
{ |
printk("oeth: tx_bd%d: len_status: %lx ",i,*bd_base++); |
printk("addr: %lx\n", *bd_base++); |
} |
|
for(i=0;i<OETH_RXBD_NUM;i++) |
{ |
printk("oeth: rx_bd%d: len_status: %lx ",i,*bd_base++); |
printk("addr: %lx\n", *bd_base++); |
} |
|
} |
|
|
|
void send_packet() |
{ |
/* This should be 98 bytes big */ |
char ping_packet[] = { |
0x00, 0x24, 0xe8, 0x91, 0x7c, 0x0d, /*DST MAC*/ |
0x00, 0xe0, 0x18, 0x73, 0x1d, 0x05, /*SRC MAC*/ |
0x08, 0x00, /*TYPE*/ |
/* IP */ |
0x45, /* Version, header length*/ |
0x00, /* Differentiated services field */ |
0x00, 0x54, /* Total length */ |
0x00, 0x00, /* Identification */ |
0x40, /* Flags */ |
0x00, /* Fragment offset */ |
0x40, /* Time to live */ |
0x01, /* Protocol (0x01 = ICMP */ |
0xef, 0xf3, /* Header checksum */ |
0xc0, 0xa8, 0x64, 0xfb, /* Source IP */ |
0xc0, 0xa8, 0x64, 0x69, /* Dest. IP */ |
/* ICMP Message body */ |
0x08, 0x00, 0x9a, 0xd4, 0xc8, 0x18, 0x00, 0x01, 0xd9, 0x8c, 0x54, |
0x4a, 0x7b, 0x37, 0x01, 0x00, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, |
0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, |
0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, |
0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, |
0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37 |
}; |
|
/*Send packet */ |
tx_packet((void*) ping_packet, 98); |
|
} |
|
void printstring(char* string) |
{ |
while (*string) uart_putc(*string++); |
} |
|
|
|
/* The interrupt handler. |
*/ |
void |
oeth_interrupt(void) |
{ |
|
volatile oeth_regs *regs; |
regs = (oeth_regs *)(OETH_REG_BASE); |
|
uint int_events; |
int serviced; |
|
serviced = 0; |
|
#ifndef RTLSIM |
printk("."); |
|
printk("\n=tx_ | %x | %x | %x | %x | %x | %x | %x | %x\n", |
((oeth_bd *)(OETH_BD_BASE))->len_status, |
((oeth_bd *)(OETH_BD_BASE+8))->len_status, |
((oeth_bd *)(OETH_BD_BASE+16))->len_status, |
((oeth_bd *)(OETH_BD_BASE+24))->len_status, |
((oeth_bd *)(OETH_BD_BASE+32))->len_status, |
((oeth_bd *)(OETH_BD_BASE+40))->len_status, |
((oeth_bd *)(OETH_BD_BASE+48))->len_status, |
((oeth_bd *)(OETH_BD_BASE+56))->len_status); |
|
printk("=rx_ | %x | %x | %x | %x | %x | %x | %x | %x\n", |
((oeth_bd *)(OETH_BD_BASE+64))->len_status, |
((oeth_bd *)(OETH_BD_BASE+64+8))->len_status, |
((oeth_bd *)(OETH_BD_BASE+64+16))->len_status, |
((oeth_bd *)(OETH_BD_BASE+64+24))->len_status, |
((oeth_bd *)(OETH_BD_BASE+64+32))->len_status, |
((oeth_bd *)(OETH_BD_BASE+64+40))->len_status, |
((oeth_bd *)(OETH_BD_BASE+64+48))->len_status, |
((oeth_bd *)(OETH_BD_BASE+64+56))->len_status); |
#endif |
|
|
/* Get the interrupt events that caused us to be here. |
*/ |
int_events = regs->int_src; |
regs->int_src = int_events; |
|
/* Handle receive event in its own function. |
*/ |
if (int_events & (OETH_INT_RXF | OETH_INT_RXE)) { |
serviced |= 0x1; |
oeth_rx(); |
} |
|
/* Handle transmit event in its own function. |
*/ |
if (int_events & (OETH_INT_TXB | OETH_INT_TXE)) { |
serviced |= 0x2; |
oeth_tx(); |
|
} |
|
/* Check for receive busy, i.e. packets coming but no place to |
* put them. |
*/ |
if (int_events & OETH_INT_BUSY) { |
serviced |= 0x4; |
#ifndef RTLSIM |
printk("b"); |
#endif |
if (!(int_events & (OETH_INT_RXF | OETH_INT_RXE))) |
oeth_rx(); |
} |
|
|
#if 0 |
if (serviced == 0) { |
void die(const char * str, struct pt_regs * regs, long err); |
int show_stack(unsigned long *esp); |
printk("!"); |
// printk("unserviced irq\n"); |
// show_stack(NULL); |
// die("unserviced irq\n", regs, 801); |
} |
#endif |
|
if (serviced == 0) |
#ifdef RTLSIM |
report(0); |
#else |
printk("\neth interrupt called but nothing serviced\n"); |
#endif |
else /* Something happened ... either RX or TX */ |
#ifdef RTLSIM |
report(0xdeaddead); |
#else |
printk(" | serviced 0x%x\n", serviced); |
#endif |
|
return; |
} |
|
|
|
static void |
oeth_rx(void) |
{ |
volatile oeth_regs *regs; |
regs = (oeth_regs *)(OETH_REG_BASE); |
|
volatile oeth_bd *rx_bdp; |
int pkt_len, i; |
int bad = 0; |
|
rx_bdp = ((oeth_bd *)OETH_BD_BASE) + OETH_TXBD_NUM; |
|
printk("r"); |
|
/* Find RX buffers marked as having received data */ |
for(i = 0; i < OETH_RXBD_NUM; i++) |
{ |
if(!(rx_bdp[i].len_status & OETH_RX_BD_EMPTY)){ /* Looking for NOT empty buffers desc. */ |
/* Check status for errors. |
*/ |
if (rx_bdp[i].len_status & (OETH_RX_BD_TOOLONG | OETH_RX_BD_SHORT)) { |
bad = 1; |
} |
if (rx_bdp[i].len_status & OETH_RX_BD_DRIBBLE) { |
bad = 1; |
} |
if (rx_bdp[i].len_status & OETH_RX_BD_CRCERR) { |
bad = 1; |
} |
if (rx_bdp[i].len_status & OETH_RX_BD_OVERRUN) { |
bad = 1; |
} |
if (rx_bdp[i].len_status & OETH_RX_BD_MISS) { |
|
} |
if (rx_bdp[i].len_status & OETH_RX_BD_LATECOL) { |
bad = 1; |
} |
|
if (bad) { |
rx_bdp[i].len_status &= ~OETH_RX_BD_STATS; |
rx_bdp[i].len_status |= OETH_RX_BD_EMPTY; |
|
continue; |
} |
else { |
|
/* Process the incoming frame. |
*/ |
pkt_len = rx_bdp[i].len_status >> 16; |
|
/* Do something here with the data - copy it into userspace, perhaps. */ |
|
#ifdef RTLSIM |
report(pkt_len); |
#else |
oeth_print_packet(rx_bdp[i].addr, rx_bdp[i].len_status >> 16); |
printk("\t end of packet\n\n"); |
#endif |
|
/* finish up */ |
rx_bdp[i].len_status &= ~OETH_RX_BD_STATS; /* Clear stats */ |
rx_bdp[i].len_status |= OETH_RX_BD_EMPTY; /* Mark RX BD as empty */ |
|
|
} |
} |
} |
} |
|
|
|
static void |
oeth_tx(void) |
{ |
volatile oeth_bd *tx_bd; |
int i; |
|
tx_bd = (volatile oeth_bd *)OETH_BD_BASE; /* Search from beginning*/ |
|
/* Go through the TX buffs, search for one that was just sent */ |
for(i = 5; i < OETH_TXBD_NUM; i++) |
{ |
/* Looking for buffer NOT ready for transmit. and IRQ enabled */ |
if( (!(tx_bd[i].len_status & (OETH_TX_BD_READY))) && (tx_bd[i].len_status & (OETH_TX_BD_IRQ)) ) |
{ |
/* Single threaded so no chance we have detected a buffer that has had its IRQ bit set but not its BD_READ flag. Maybe this won't work in linux */ |
tx_bd[i].len_status &= ~OETH_TX_BD_IRQ; |
|
/* Probably good to check for TX errors here */ |
|
/* set our test variable */ |
tx_done = 1; |
|
printk("T%d",i); |
|
} |
} |
return; |
} |
|
|
|
int main () |
{ |
/* Install interrupt handler */ |
excpt_int = (unsigned long)int_main; |
|
/* Initialise handler vector */ |
int_init(); |
|
/* Install ethernet interrupt handler, it is enabled here too */ |
int_add(IRQ_ETH_0, oeth_interrupt, 0); |
|
/* Enable interrupts in supervisor register */ |
mtspr (SPR_SR, mfspr (SPR_SR) | SPR_SR_IEE); |
|
last_char=0; /* Variable init for spin_cursor() */ |
|
#ifndef RTLSIM |
uart_init(); // init the UART before we can printf |
printf("\n\teth interrupts test\n\n"); |
#endif |
|
ethmac_setup(); /* Configure MAC, TX/RX BDs and enable RX and TX in MODER */ |
|
//scan_ethphys(); /* Scan MIIM bus for PHYs */ |
#ifndef RTLSIM |
ethphy_init(); /* Attempt reset and configuration of PHY via MIIM */ |
#endif |
//ethmac_scanstatus(); /* Enable scanning of status register via MIIM */ |
|
//oeth_monitor_rx(); |
#ifdef RTLSIM |
/* clear tx_done, the tx interrupt handler will set it when it's been transmitted */ |
tx_done = 0; |
|
send_packet(); |
|
while(tx_done==0); |
|
report(0xdeaddead); |
or32_exit(0); |
#else |
while(1) |
spin_cursor(); |
#endif |
|
} |
/eth/eth_reset.S
0,0 → 1,110
/* Reset function for ml501 board */ |
#include "spr_defs.h" |
#include "board.h" |
|
.section .stack |
.space 0x30 |
_stack: |
|
.section .reset, "ax" |
|
/* .org 0x100*/ |
.org 0 |
_reset_vector: |
l.addi r2,r0,0x0 |
l.addi r3,r0,0x0 |
l.addi r4,r0,0x0 |
l.addi r5,r0,0x0 |
l.addi r6,r0,0x0 |
l.addi r7,r0,0x0 |
l.addi r8,r0,0x0 |
l.addi r9,r0,0x0 |
l.addi r10,r0,0x0 |
l.addi r11,r0,0x0 |
l.addi r12,r0,0x0 |
l.addi r13,r0,0x0 |
l.addi r14,r0,0x0 |
l.addi r15,r0,0x0 |
l.addi r16,r0,0x0 |
l.addi r17,r0,0x0 |
l.addi r18,r0,0x0 |
l.addi r19,r0,0x0 |
l.addi r20,r0,0x0 |
l.addi r21,r0,0x0 |
l.addi r22,r0,0x0 |
l.addi r23,r0,0x0 |
l.addi r24,r0,0x0 |
l.addi r25,r0,0x0 |
l.addi r26,r0,0x0 |
l.addi r27,r0,0x0 |
l.addi r28,r0,0x0 |
l.addi r29,r0,0x0 |
l.addi r30,r0,0x0 |
l.addi r31,r0,0x0 |
|
l.movhi r3,hi(_start) |
l.ori r3,r3,lo(_start) |
l.jr r3 |
l.nop |
|
.org 0x100 |
/* Jump to 0 .. where the real reset vector is*/ |
l.jr r0 |
l.nop |
|
.section .text |
|
_start: |
|
.if IC | DC |
/* Flush IC and/or DC */ |
l.addi r10,r0,0 |
l.addi r11,r0,0 |
l.addi r12,r0,0 |
.if IC |
l.addi r11,r0,IC_SIZE |
.endif |
.if DC |
l.addi r12,r0,DC_SIZE |
.endif |
l.sfleu r12,r11 |
l.bf loop |
l.nop |
l.add r11,r0,r12 |
loop: |
.if IC |
l.mtspr r0,r10,SPR_ICBIR |
.endif |
.if DC |
l.mtspr r0,r10,SPR_DCBIR |
.endif |
l.sfne r10,r11 |
l.bf loop |
l.addi r10,r10,16 |
|
/* Enable IC and/or DC */ |
l.addi r10,r0,(SPR_SR_SM) |
.if IC |
l.ori r10,r10,(SPR_SR_ICE) |
.endif |
.if DC |
l.ori r10,r10,(SPR_SR_DCE) |
.endif |
l.mtspr r0,r10,SPR_SR |
l.nop |
l.nop |
l.nop |
l.nop |
l.nop |
.endif |
|
/* Set stack pointer */ |
l.movhi r1,hi(_stack) |
l.ori r1,r1,lo(_stack) |
|
/* Jump to main */ |
l.movhi r2,hi(_main) |
l.ori r2,r2,lo(_main) |
l.jr r2 |
l.nop |
|
/eth/mii.h
0,0 → 1,145
/* Generic MII registers. */ |
|
#define MII_BMCR 0x00 /* Basic mode control register */ |
#define MII_BMSR 0x01 /* Basic mode status register */ |
#define MII_PHYSID1 0x02 /* PHYS ID 1 */ |
#define MII_PHYSID2 0x03 /* PHYS ID 2 */ |
#define MII_ADVERTISE 0x04 /* Advertisement control reg */ |
#define MII_LPA 0x05 /* Link partner ability reg */ |
#define MII_EXPANSION 0x06 /* Expansion register */ |
#define MII_CTRL1000 0x09 /* 1000BASE-T control */ |
#define MII_STAT1000 0x0a /* 1000BASE-T status */ |
#define MII_ESTATUS 0x0f /* Extended Status */ |
#define MII_DCOUNTER 0x12 /* Disconnect counter */ |
#define MII_FCSCOUNTER 0x13 /* False carrier counter */ |
#define MII_NWAYTEST 0x14 /* N-way auto-neg test reg */ |
#define MII_RERRCOUNTER 0x15 /* Receive error counter */ |
#define MII_SREVISION 0x16 /* Silicon revision */ |
#define MII_RESV1 0x17 /* Reserved... */ |
#define MII_LBRERROR 0x18 /* Lpback, rx, bypass error */ |
#define MII_PHYADDR 0x19 /* PHY address */ |
#define MII_RESV2 0x1a /* Reserved... */ |
#define MII_TPISTATUS 0x1b /* TPI status for 10mbps */ |
#define MII_NCONFIG 0x1c /* Network interface config */ |
|
/* Basic mode control register. */ |
#define BMCR_SPD2 0x0040 /* Gigabit enable? (bcm5411) */ |
#define BMCR_RESV 0x003f /* Unused... */ |
#define BMCR_SPEED1000 0x0040 /* MSB of Speed (1000) */ |
#define BMCR_CTST 0x0080 /* Collision test */ |
#define BMCR_FULLDPLX 0x0100 /* Full duplex */ |
#define BMCR_ANRESTART 0x0200 /* Auto negotiation restart */ |
#define BMCR_ISOLATE 0x0400 /* Disconnect DP83840 from MII */ |
#define BMCR_PDOWN 0x0800 /* Powerdown the DP83840 */ |
#define BMCR_ANENABLE 0x1000 /* Enable auto negotiation */ |
#define BMCR_SPEED100 0x2000 /* Select 100Mbps */ |
#define BMCR_LOOPBACK 0x4000 /* TXD loopback bits */ |
#define BMCR_RESET 0x8000 /* Reset the DP83840 */ |
|
/* Basic mode status register. */ |
#define BMSR_ERCAP 0x0001 /* Ext-reg capability */ |
#define BMSR_JCD 0x0002 /* Jabber detected */ |
#define BMSR_LSTATUS 0x0004 /* Link status */ |
#define BMSR_ANEGCAPABLE 0x0008 /* Able to do auto-negotiation */ |
#define BMSR_RFAULT 0x0010 /* Remote fault detected */ |
#define BMSR_ANEGCOMPLETE 0x0020 /* Auto-negotiation complete */ |
#define BMSR_RESV 0x00c0 /* Unused... */ |
#define BMSR_ESTATEN 0x0100 /* Extended Status in R15 */ |
#define BMSR_100HALF2 0x0200 /* Can do 100BASE-T2 HDX */ |
#define BMSR_100FULL2 0x0400 /* Can do 100BASE-T2 FDX */ |
#define BMSR_10HALF 0x0800 /* Can do 10mbps, half-duplex */ |
#define BMSR_10FULL 0x1000 /* Can do 10mbps, full-duplex */ |
#define BMSR_100HALF 0x2000 /* Can do 100mbps, half-duplex */ |
#define BMSR_100FULL 0x4000 /* Can do 100mbps, full-duplex */ |
#define BMSR_100BASE4 0x8000 /* Can do 100mbps, 4k packets */ |
|
/* Advertisement control register. */ |
#define ADVERTISE_SLCT 0x001f /* Selector bits */ |
#define ADVERTISE_CSMA 0x0001 /* Only selector supported */ |
#define ADVERTISE_10HALF 0x0020 /* Try for 10mbps half-duplex */ |
#define ADVERTISE_1000XFULL 0x0020 /* Try for 1000BASE-X full-duplex */ |
#define ADVERTISE_10FULL 0x0040 /* Try for 10mbps full-duplex */ |
#define ADVERTISE_1000XHALF 0x0040 /* Try for 1000BASE-X half-duplex */ |
#define ADVERTISE_100HALF 0x0080 /* Try for 100mbps half-duplex */ |
#define ADVERTISE_1000XPAUSE 0x0080 /* Try for 1000BASE-X pause */ |
#define ADVERTISE_100FULL 0x0100 /* Try for 100mbps full-duplex */ |
#define ADVERTISE_1000XPSE_ASYM 0x0100 /* Try for 1000BASE-X asym pause */ |
#define ADVERTISE_100BASE4 0x0200 /* Try for 100mbps 4k packets */ |
#define ADVERTISE_PAUSE_CAP 0x0400 /* Try for pause */ |
#define ADVERTISE_PAUSE_ASYM 0x0800 /* Try for asymetric pause */ |
#define ADVERTISE_RESV 0x1000 /* Unused... */ |
#define ADVERTISE_RFAULT 0x2000 /* Say we can detect faults */ |
#define ADVERTISE_LPACK 0x4000 /* Ack link partners response */ |
#define ADVERTISE_NPAGE 0x8000 /* Next page bit */ |
|
#define ADVERTISE_FULL (ADVERTISE_100FULL | ADVERTISE_10FULL | \ |
ADVERTISE_CSMA) |
#define ADVERTISE_ALL (ADVERTISE_10HALF | ADVERTISE_10FULL | \ |
ADVERTISE_100HALF | ADVERTISE_100FULL) |
|
/* Link partner ability register. */ |
#define LPA_SLCT 0x001f /* Same as advertise selector */ |
#define LPA_10HALF 0x0020 /* Can do 10mbps half-duplex */ |
#define LPA_1000XFULL 0x0020 /* Can do 1000BASE-X full-duplex */ |
#define LPA_10FULL 0x0040 /* Can do 10mbps full-duplex */ |
#define LPA_1000XHALF 0x0040 /* Can do 1000BASE-X half-duplex */ |
#define LPA_100HALF 0x0080 /* Can do 100mbps half-duplex */ |
#define LPA_1000XPAUSE 0x0080 /* Can do 1000BASE-X pause */ |
#define LPA_100FULL 0x0100 /* Can do 100mbps full-duplex */ |
#define LPA_1000XPAUSE_ASYM 0x0100 /* Can do 1000BASE-X pause asym*/ |
#define LPA_100BASE4 0x0200 /* Can do 100mbps 4k packets */ |
#define LPA_PAUSE_CAP 0x0400 /* Can pause */ |
#define LPA_PAUSE_ASYM 0x0800 /* Can pause asymetrically */ |
#define LPA_RESV 0x1000 /* Unused... */ |
#define LPA_RFAULT 0x2000 /* Link partner faulted */ |
#define LPA_LPACK 0x4000 /* Link partner acked us */ |
#define LPA_NPAGE 0x8000 /* Next page bit */ |
|
#define LPA_DUPLEX (LPA_10FULL | LPA_100FULL) |
#define LPA_100 (LPA_100FULL | LPA_100HALF | LPA_100BASE4) |
|
/* Expansion register for auto-negotiation. */ |
#define EXPANSION_NWAY 0x0001 /* Can do N-way auto-nego */ |
#define EXPANSION_LCWP 0x0002 /* Got new RX page code word */ |
#define EXPANSION_ENABLENPAGE 0x0004 /* This enables npage words */ |
#define EXPANSION_NPCAPABLE 0x0008 /* Link partner supports npage */ |
#define EXPANSION_MFAULTS 0x0010 /* Multiple faults detected */ |
#define EXPANSION_RESV 0xffe0 /* Unused... */ |
|
#define ESTATUS_1000_TFULL 0x2000 /* Can do 1000BT Full */ |
#define ESTATUS_1000_THALF 0x1000 /* Can do 1000BT Half */ |
|
/* N-way test register. */ |
#define NWAYTEST_RESV1 0x00ff /* Unused... */ |
#define NWAYTEST_LOOPBACK 0x0100 /* Enable loopback for N-way */ |
#define NWAYTEST_RESV2 0xfe00 /* Unused... */ |
|
/* 1000BASE-T Control register */ |
#define ADVERTISE_1000FULL 0x0200 /* Advertise 1000BASE-T full duplex */ |
#define ADVERTISE_1000HALF 0x0100 /* Advertise 1000BASE-T half duplex */ |
|
/* 1000BASE-T Status register */ |
#define LPA_1000LOCALRXOK 0x2000 /* Link partner local receiver status */ |
#define LPA_1000REMRXOK 0x1000 /* Link partner remote receiver status */ |
#define LPA_1000FULL 0x0800 /* Link partner 1000BASE-T full duplex */ |
#define LPA_1000HALF 0x0400 /* Link partner 1000BASE-T half duplex */ |
|
/* 1000BT control (Marvell & BCM54xx at least) */ |
#define MII_1000BASETCONTROL 0x09 |
#define MII_1000BASETCONTROL_FULLDUPLEXCAP 0x0200 |
#define MII_1000BASETCONTROL_HALFDUPLEXCAP 0x0100 |
|
/* Marvell 88E1011 PHY control */ |
#define MII_M1011_PHY_SPEC_CONTROL 0x10 |
#define MII_M1011_PHY_SPEC_CONTROL_MANUAL_MDIX 0x20 |
#define MII_M1011_PHY_SPEC_CONTROL_AUTO_MDIX 0x40 |
|
/* Marvell 88E1011 PHY status */ |
#define MII_M1011_PHY_SPEC_STATUS 0x11 |
#define MII_M1011_PHY_SPEC_STATUS_1000 0x8000 |
#define MII_M1011_PHY_SPEC_STATUS_100 0x4000 |
#define MII_M1011_PHY_SPEC_STATUS_SPD_MASK 0xc000 |
#define MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX 0x2000 |
#define MII_M1011_PHY_SPEC_STATUS_RESOLVED 0x0800 |
#define MII_M1011_PHY_SPEC_STATUS_TX_PAUSE 0x0008 |
#define MII_M1011_PHY_SPEC_STATUS_RX_PAUSE 0x0004 |
/eth/open_eth.h
0,0 → 1,147
|
typedef unsigned int uint; |
|
/* Ethernet configuration registers */ |
typedef struct _oeth_regs { |
uint moder; /* Mode Register */ |
uint int_src; /* Interrupt Source Register */ |
uint int_mask; /* Interrupt Mask Register */ |
uint ipgt; /* Back to Bak Inter Packet Gap Register */ |
uint ipgr1; /* Non Back to Back Inter Packet Gap Register 1 */ |
uint ipgr2; /* Non Back to Back Inter Packet Gap Register 2 */ |
uint packet_len; /* Packet Length Register (min. and max.) */ |
uint collconf; /* Collision and Retry Configuration Register */ |
uint tx_bd_num; /* Transmit Buffer Descriptor Number Register */ |
uint ctrlmoder; /* Control Module Mode Register */ |
uint miimoder; /* MII Mode Register */ |
uint miicommand; /* MII Command Register */ |
uint miiaddress; /* MII Address Register */ |
uint miitx_data; /* MII Transmit Data Register */ |
uint miirx_data; /* MII Receive Data Register */ |
uint miistatus; /* MII Status Register */ |
uint mac_addr0; /* MAC Individual Address Register 0 */ |
uint mac_addr1; /* MAC Individual Address Register 1 */ |
uint hash_addr0; /* Hash Register 0 */ |
uint hash_addr1; /* Hash Register 1 */ |
} oeth_regs; |
|
/* Ethernet buffer descriptor */ |
typedef struct _oeth_bd { |
#if 0 |
ushort len; /* Buffer length */ |
ushort status; /* Buffer status */ |
#else |
uint len_status; |
#endif |
uint addr; /* Buffer address */ |
} oeth_bd; |
|
|
#define OETH_REG_BASE ETH_0_BASE |
#define OETH_BD_BASE (ETH_0_BASE + 0x400) |
#define OETH_TOTAL_BD 128 |
#define OETH_MAXBUF_LEN 0x600 |
|
/* Tx BD */ |
#define OETH_TX_BD_READY 0x8000 /* Tx BD Ready */ |
#define OETH_TX_BD_IRQ 0x4000 /* Tx BD IRQ Enable */ |
#define OETH_TX_BD_WRAP 0x2000 /* Tx BD Wrap (last BD) */ |
#define OETH_TX_BD_PAD 0x1000 /* Tx BD Pad Enable */ |
#define OETH_TX_BD_CRC 0x0800 /* Tx BD CRC Enable */ |
|
#define OETH_TX_BD_UNDERRUN 0x0100 /* Tx BD Underrun Status */ |
#define OETH_TX_BD_RETRY 0x00F0 /* Tx BD Retry Status */ |
#define OETH_TX_BD_RETLIM 0x0008 /* Tx BD Retransmission Limit Status */ |
#define OETH_TX_BD_LATECOL 0x0004 /* Tx BD Late Collision Status */ |
#define OETH_TX_BD_DEFER 0x0002 /* Tx BD Defer Status */ |
#define OETH_TX_BD_CARRIER 0x0001 /* Tx BD Carrier Sense Lost Status */ |
#define OETH_TX_BD_STATS (OETH_TX_BD_UNDERRUN | \ |
OETH_TX_BD_RETRY | \ |
OETH_TX_BD_RETLIM | \ |
OETH_TX_BD_LATECOL | \ |
OETH_TX_BD_DEFER | \ |
OETH_TX_BD_CARRIER) |
|
/* Rx BD */ |
#define OETH_RX_BD_EMPTY 0x8000 /* Rx BD Empty */ |
#define OETH_RX_BD_IRQ 0x4000 /* Rx BD IRQ Enable */ |
#define OETH_RX_BD_WRAP 0x2000 /* Rx BD Wrap (last BD) */ |
|
#define OETH_RX_BD_MISS 0x0080 /* Rx BD Miss Status */ |
#define OETH_RX_BD_OVERRUN 0x0040 /* Rx BD Overrun Status */ |
#define OETH_RX_BD_INVSIMB 0x0020 /* Rx BD Invalid Symbol Status */ |
#define OETH_RX_BD_DRIBBLE 0x0010 /* Rx BD Dribble Nibble Status */ |
#define OETH_RX_BD_TOOLONG 0x0008 /* Rx BD Too Long Status */ |
#define OETH_RX_BD_SHORT 0x0004 /* Rx BD Too Short Frame Status */ |
#define OETH_RX_BD_CRCERR 0x0002 /* Rx BD CRC Error Status */ |
#define OETH_RX_BD_LATECOL 0x0001 /* Rx BD Late Collision Status */ |
#define OETH_RX_BD_STATS (OETH_RX_BD_MISS | \ |
OETH_RX_BD_OVERRUN | \ |
OETH_RX_BD_INVSIMB | \ |
OETH_RX_BD_DRIBBLE | \ |
OETH_RX_BD_TOOLONG | \ |
OETH_RX_BD_SHORT | \ |
OETH_RX_BD_CRCERR | \ |
OETH_RX_BD_LATECOL) |
|
/* MODER Register */ |
#define OETH_MODER_RXEN 0x00000001 /* Receive Enable */ |
#define OETH_MODER_TXEN 0x00000002 /* Transmit Enable */ |
#define OETH_MODER_NOPRE 0x00000004 /* No Preamble */ |
#define OETH_MODER_BRO 0x00000008 /* Reject Broadcast */ |
#define OETH_MODER_IAM 0x00000010 /* Use Individual Hash */ |
#define OETH_MODER_PRO 0x00000020 /* Promiscuous (receive all) */ |
#define OETH_MODER_IFG 0x00000040 /* Min. IFG not required */ |
#define OETH_MODER_LOOPBCK 0x00000080 /* Loop Back */ |
#define OETH_MODER_NOBCKOF 0x00000100 /* No Backoff */ |
#define OETH_MODER_EXDFREN 0x00000200 /* Excess Defer */ |
#define OETH_MODER_FULLD 0x00000400 /* Full Duplex */ |
#define OETH_MODER_RST 0x00000800 /* Reset MAC */ |
#define OETH_MODER_DLYCRCEN 0x00001000 /* Delayed CRC Enable */ |
#define OETH_MODER_CRCEN 0x00002000 /* CRC Enable */ |
#define OETH_MODER_HUGEN 0x00004000 /* Huge Enable */ |
#define OETH_MODER_PAD 0x00008000 /* Pad Enable */ |
#define OETH_MODER_RECSMALL 0x00010000 /* Receive Small */ |
|
/* Interrupt Source Register */ |
#define OETH_INT_TXB 0x00000001 /* Transmit Buffer IRQ */ |
#define OETH_INT_TXE 0x00000002 /* Transmit Error IRQ */ |
#define OETH_INT_RXF 0x00000004 /* Receive Frame IRQ */ |
#define OETH_INT_RXE 0x00000008 /* Receive Error IRQ */ |
#define OETH_INT_BUSY 0x00000010 /* Busy IRQ */ |
#define OETH_INT_TXC 0x00000020 /* Transmit Control Frame IRQ */ |
#define OETH_INT_RXC 0x00000040 /* Received Control Frame IRQ */ |
|
/* Interrupt Mask Register */ |
#define OETH_INT_MASK_TXB 0x00000001 /* Transmit Buffer IRQ Mask */ |
#define OETH_INT_MASK_TXE 0x00000002 /* Transmit Error IRQ Mask */ |
#define OETH_INT_MASK_RXF 0x00000004 /* Receive Frame IRQ Mask */ |
#define OETH_INT_MASK_RXE 0x00000008 /* Receive Error IRQ Mask */ |
#define OETH_INT_MASK_BUSY 0x00000010 /* Busy IRQ Mask */ |
#define OETH_INT_MASK_TXC 0x00000020 /* Transmit Control Frame IRQ Mask */ |
#define OETH_INT_MASK_RXC 0x00000040 /* Received Control Frame IRQ Mask */ |
|
/* Control Module Mode Register */ |
#define OETH_CTRLMODER_PASSALL 0x00000001 /* Pass Control Frames */ |
#define OETH_CTRLMODER_RXFLOW 0x00000002 /* Receive Control Flow Enable */ |
#define OETH_CTRLMODER_TXFLOW 0x00000004 /* Transmit Control Flow Enable */ |
|
/* MII Mode Register */ |
#define OETH_MIIMODER_CLKDIV 0x000000FF /* Clock Divider */ |
#define OETH_MIIMODER_NOPRE 0x00000100 /* No Preamble */ |
#define OETH_MIIMODER_RST 0x00000200 /* MIIM Reset */ |
|
/* MII Command Register */ |
#define OETH_MIICOMMAND_SCANSTAT 0x00000001 /* Scan Status */ |
#define OETH_MIICOMMAND_RSTAT 0x00000002 /* Read Status */ |
#define OETH_MIICOMMAND_WCTRLDATA 0x00000004 /* Write Control Data */ |
|
/* MII Address Register */ |
#define OETH_MIIADDRESS_FIAD 0x0000001F /* PHY Address */ |
#define OETH_MIIADDRESS_RGAD 0x00001F00 /* RGAD Address */ |
|
/* MII Status Register */ |
#define OETH_MIISTATUS_LINKFAIL 0x00000001 /* Link Fail */ |
#define OETH_MIISTATUS_BUSY 0x00000002 /* MII Busy */ |
#define OETH_MIISTATUS_NVALID 0x00000004 /* Data in MII Status Register is invalid */ |
|
/eth/except.S
0,0 → 1,183
#include "spr_defs.h" |
#include "board.h" |
|
// Linked from 0x200, so add 0x200 to the .org for the physical address |
.section .vectors, "ax" |
|
/* |
.org 0x100 |
|
_reset: |
l.nop |
l.j _reset_except |
l.nop |
*/ |
.org 0x000 |
|
_except_200: |
l.nop |
l.j _buserr_except |
l.nop |
|
.org 0x100 |
|
_except_300: |
l.nop |
l.j _dpf_except |
l.nop |
|
.org 0x200 |
|
_except_400: |
l.nop |
l.j _ipf_except |
l.nop |
|
.org 0x300 |
|
_except_500: |
l.nop |
l.j _lpint_except |
l.nop |
|
.org 0x400 |
|
_except_600: |
l.nop |
l.j _align_except |
l.nop |
|
.org 0x500 |
|
_except_700: |
l.nop |
l.j _illegal_except |
l.nop |
|
.org 0x600 |
|
_int_vector: |
l.nop |
l.addi r1,r1,-116 |
l.sw 0x18(r1),r9 |
l.jal store_regs |
l.nop |
|
l.movhi r9,hi(end_except) |
l.ori r9,r9,lo(end_except) |
l.movhi r10,hi(_excpt_int) |
l.ori r10,r10,lo(_excpt_int) |
l.lwz r10,0(r10) |
l.jr r10 |
l.nop |
|
.org 0x700 |
|
_except_900: |
l.nop |
l.j _dtlbmiss_except |
l.nop |
|
.org 0x800 |
|
_except_a00: |
l.nop |
l.j _itlbmiss_except |
l.nop |
|
.org 0x900 |
|
_except_b00: |
l.nop |
l.j _range_except |
l.nop |
|
.org 0xa00 |
|
_except_c00: |
l.nop |
l.j _syscall_except |
l.nop |
|
.org 0xb00 |
|
_except_d00: |
l.nop |
l.j _fpu_except |
l.nop |
|
|
.org 0xc00 |
_except_e00: |
l.nop |
l.j _trap_except |
l.nop |
|
|
store_regs: |
l.sw 0x00(r1),r3 |
l.sw 0x04(r1),r4 |
l.sw 0x08(r1),r5 |
l.sw 0x0c(r1),r6 |
l.sw 0x10(r1),r7 |
l.sw 0x14(r1),r8 |
l.sw 0x1c(r1),r10 |
l.sw 0x20(r1),r11 |
l.sw 0x24(r1),r12 |
l.sw 0x28(r1),r13 |
l.sw 0x2c(r1),r14 |
l.sw 0x30(r1),r15 |
l.sw 0x34(r1),r16 |
l.sw 0x38(r1),r17 |
l.sw 0x3c(r1),r18 |
l.sw 0x40(r1),r19 |
l.sw 0x44(r1),r20 |
l.sw 0x48(r1),r21 |
l.sw 0x4c(r1),r22 |
l.sw 0x50(r1),r23 |
l.sw 0x54(r1),r24 |
l.sw 0x58(r1),r25 |
l.sw 0x5c(r1),r26 |
l.sw 0x60(r1),r27 |
l.sw 0x64(r1),r28 |
l.sw 0x68(r1),r29 |
l.sw 0x6c(r1),r30 |
l.sw 0x70(r1),r31 |
l.jr r9 |
l.nop |
|
end_except: |
l.lwz r3,0x00(r1) |
l.lwz r4,0x04(r1) |
l.lwz r5,0x08(r1) |
l.lwz r6,0x0c(r1) |
l.lwz r7,0x10(r1) |
l.lwz r8,0x14(r1) |
l.lwz r9,0x18(r1) |
l.lwz r10,0x1c(r1) |
l.lwz r11,0x20(r1) |
l.lwz r12,0x24(r1) |
l.lwz r13,0x28(r1) |
l.lwz r14,0x2c(r1) |
l.lwz r15,0x30(r1) |
l.lwz r16,0x34(r1) |
l.lwz r17,0x38(r1) |
l.lwz r18,0x3c(r1) |
l.lwz r19,0x40(r1) |
l.lwz r20,0x44(r1) |
l.lwz r21,0x48(r1) |
l.lwz r22,0x4c(r1) |
l.lwz r23,0x50(r1) |
l.lwz r24,0x54(r1) |
l.lwz r25,0x58(r1) |
l.lwz r26,0x5c(r1) |
l.lwz r27,0x60(r1) |
l.lwz r28,0x64(r1) |
l.lwz r29,0x68(r1) |
l.lwz r30,0x6c(r1) |
l.lwz r31,0x70(r1) |
l.addi r1,r1,116 |
l.mtspr r0,r9,SPR_EPCR_BASE |
l.rfe |
l.nop |
|
/eth/Makefile
0,0 → 1,61
PROJECT_ROOT=../../../../.. |
|
MAIN_SW_DIR=$(PROJECT_ROOT)/sw |
|
|
|
|
SUPPORT_SOURCES=uart.c uart.h spr_defs.h support.h int.h time.h support.c syscall.c int.c vfnprintf.c time.c vfnprintf.h |
SUPPORT_C_SOURCES=$(shell for src in $(SUPPORT_SOURCES); do echo $$src | grep \.c; done) |
|
# Some extra options, if we're going to compile the software for it to be pulled in by the synthesis tool |
ifeq ($(SYNTHESIS), 1) |
SW_SYNTHESIS_OPTS=-DUART_PRINTF |
VMEM_SYNTHESIS_OPTS=-synfmt |
else |
SW_SYNTHESIS_OPTS=-DRTLSIM |
endif |
|
|
CROSS_PREFIX=or32-elf- |
CROSS_CC=$(CROSS_PREFIX)gcc |
CROSS_OBJCOPY=$(CROSS_PREFIX)objcopy |
|
APP=eth |
|
all: clean |
|
.PHONY: $(APP) |
$(APP): prepare-sw prepare-links $(APP).vmem |
|
|
$(APP).vmem: $(APP).bin |
$(MAIN_SW_DIR)/utils/bin2vmem $? $(VMEM_SYNTHESIS_OPTS) > $@ |
|
$(APP).bin: $(APP).or32 |
$(CROSS_OBJCOPY) -O binary $? $@ |
|
$(APP).or32: $(APP)_reset.o $(APP).[cS] $(SUPPORT_C_SOURCES) except.o |
$(CROSS_CC) $? -mhard-mul -g -I../. -O2 $(SW_SYNTHESIS_OPTS) -T$(APP).ld -o $@ |
|
$(APP)_reset.o: $(APP)_reset.S |
$(CROSS_CC) -c -o $@ $? -I../. |
|
prepare-links: |
for src in $(SUPPORT_SOURCES); do if [ ! -e $$src ]; then ln -s $(MAIN_SW_DIR)/support/$$src; fi; done |
|
unprepare-links: |
for src in $(SUPPORT_SOURCES); do if [ -e $$src ]; then unlink $$src; fi; done |
|
prepare-sw: |
@$(MAKE) -C $(MAIN_SW_DIR)/utils all |
|
%.o: %.S |
$(CROSS_CC) -I../. $(SW_SYNTHESIS_OPTS) -O2 -g -c -Wall $< -o $@ |
|
$(MAIN_SW_DIR)/support/libsupport.a: |
$(MAKE) -C $(MAIN_SW_DIR)/support all |
|
clean: unprepare-links |
@rm -vf *.o *.bin *.or32 *.vmem |
|
/eth/eth.ld
0,0 → 1,59
|
MEMORY |
{ |
reset : ORIGIN = 0x00000000, LENGTH = 0x00000200 |
vectors : ORIGIN = 0x00000200, LENGTH = 0x00001E00 |
ram : ORIGIN = 0x00002000, LENGTH = 0x0FFFE000 |
} |
|
SECTIONS |
{ |
.reset : |
{ |
*(.reset) |
} > reset |
|
.vectors : |
{ |
_vec_start = .; |
*(.vectors) |
_vec_end = .; |
} > vectors |
|
.text : |
{ |
*(.text) |
} > ram |
|
.rodata : |
{ |
*(.rodata) |
*(.rodata.*) |
} > ram |
|
.icm : |
{ |
_icm_start = .; |
*(.icm) |
_icm_end = .; |
} > ram |
|
.data : |
{ |
_dst_beg = .; |
*(.data) |
_dst_end = .; |
} > ram |
|
.bss : |
{ |
*(.bss) |
} > ram |
|
.stack (NOLOAD) : |
{ |
*(.stack) |
_src_addr = .; |
} > ram |
|
} |
/boot/Makefile
1,5 → 1,7
PROJECT_ROOT=../../../../.. |
|
BOARD=ml501 |
|
MAIN_SW_DIR=$(PROJECT_ROOT)/sw |
|
SUPPORT_SOURCES=uart.c uart.h spr_defs.h support.h |
8,9 → 10,15
# Some extra options, if we're going to compile the software for it to be pulled in by the synthesis tool |
ifeq ($(SYNTHESIS), 1) |
SW_SYNTHESIS_OPTS=-DSYNTHESIS |
# Expecting the bootmem to be 0x800 big - if not, change this or it won't get pulled in by synthesis properly! |
VMEM_SYNTHESIS_OPTS=-synfmt --pad-to-addr 0x800 |
# Parse the board defines file in the RTL path for the startup memory span |
STARTUP_RAM_SIZE_HEX=$(shell grep -v // ../../rtl/$(BOARD)_defines.v | grep MEMORY_STARTUP_ADDR_SPAN | cut -d 'h' -f 2) |
ifeq ($(STARTUP_RAM_SIZE_HEX),) |
RAM_PAD_COMMAND= |
else |
RAM_PAD_COMMAND=--pad-to-addr 0x$(STARTUP_RAM_SIZE_HEX) |
endif |
VMEM_SYNTHESIS_OPTS=-synfmt $(RAM_PAD_COMMAND) |
endif |
|
|
CROSS_PREFIX=or32-elf- |
/board.h
23,8 → 23,8
|
//#define SPI_BASE 0xa0000000 |
|
//#define ETH_BASE 0xD0000000 |
//#define IRQ_ETH_0 (4) /* interrupt source for Ethernet dvice 0 */ |
#define ETH_0_BASE 0x92000000 |
#define IRQ_ETH_0 (4) /* interrupt source for Ethernet dvice 0 */ |
|
#define ETH_DATA_BASE 0xa8000000 /* Address for ETH_DATA */ |
#define BOARD_DEF_IP 0x0a010185 |
/memtest/memtest.c
13,10 → 13,13
#define MEM_TEST_BASE 0x2000 |
#endif |
|
#ifdef SYNTHESIS |
#define MEM_TEST_LENGTH ((1024*1024*255)/4) |
#else |
#define MEM_TEST_LENGTH 64 |
|
#ifndef MEM_TEST_LENGTH |
#ifdef SYNTHESIS |
#define MEM_TEST_LENGTH (((1024*1024*255)/4) - (MEM_TEST_BASE/4)) |
#else |
#define MEM_TEST_LENGTH 64 |
#endif |
#endif |
|
|
/memtest/Makefile
1,5 → 1,5
PROJECT_ROOT=../../../../.. |
|
BOARD=ml501 |
MAIN_SW_DIR=$(PROJECT_ROOT)/sw |
|
SUPPORT_SOURCES=uart.c uart.h spr_defs.h support.h |
11,7 → 11,19
VMEM_SYNTHESIS_OPTS=-synfmt |
endif |
|
# Setup some user definable paramters such as test start/length |
|
# Check the board defines file for the size of the boot/low memory |
# test will start after it... |
STARTUP_RAM_SIZE_HEX=$(shell grep -v // ../../rtl/$(BOARD)_defines.v | grep MEMORY_STARTUP_ADDR_SPAN | cut -d 'h' -f 2) |
ifneq ($(STARTUP_RAM_SIZE_HEX),) |
SW_OPTS += -DMEM_TEST_BASE=0x$(STARTUP_RAM_SIZE_HEX) |
endif |
|
ifneq ($(MEM_TEST_LENGTH),) |
SW_OPTS += -DMEM_TEST_LENGTH=$(MEM_TEST_LENGTH) |
endif |
|
CROSS_PREFIX=or32-elf- |
CROSS_CC=$(CROSS_PREFIX)gcc |
CROSS_OBJCOPY=$(CROSS_PREFIX)objcopy |
21,7 → 33,7
all: clean |
|
.PHONY: $(APP) |
$(APP): prepare-sw prepare-links $(APP).vmem |
$(APP): clean prepare-sw prepare-links $(APP).vmem |
|
|
$(APP).vmem: $(APP).bin |
31,7 → 43,7
$(CROSS_OBJCOPY) -O binary $? $@ |
|
$(APP).or32: $(APP)_reset.o $(APP).[cS] $(SUPPORT_C_SOURCES) |
$(CROSS_CC) $? -nostdlib -mhard-mul -g -I../. -O2 $(SW_SYNTHESIS_OPTS) -T$(APP).ld -o $@ |
$(CROSS_CC) $? -nostdlib -mhard-mul -g -I../. -O2 $(SW_OPTS) $(SW_SYNTHESIS_OPTS) -T$(APP).ld -o $@ |
|
$(APP)_reset.o: $(APP)_reset.S |
$(CROSS_CC) -c -o $@ $? -I../. |