Merge branch 'master' of git://www.denx.de/git/u-boot-net

This commit is contained in:
Wolfgang Denk 2008-04-08 00:11:22 +02:00
commit f9eabcb357
14 changed files with 993 additions and 17 deletions

17
README
View File

@ -751,6 +751,9 @@ The following options need to be configured:
CONFIG_E1000
Support for Intel 8254x gigabit chips.
CONFIG_E1000_FALLBACK_MAC
default MAC for empty eeprom after production.
CONFIG_EEPRO100
Support for Intel 82557/82559/82559ER chips.
Optional CONFIG_EEPRO100_SROM_WRITE enables eeprom
@ -1151,6 +1154,20 @@ The following options need to be configured:
of the "hostname" environment variable is passed as
option 12 to the DHCP server.
CONFIG_BOOTP_DHCP_REQUEST_DELAY
A 32bit value in microseconds for a delay between
receiving a "DHCP Offer" and sending the "DHCP Request".
This fixes a problem with certain DHCP servers that don't
respond 100% of the time to a "DHCP request". E.g. On an
AT91RM9200 processor running at 180MHz, this delay needed
to be *at least* 15,000 usec before a Windows Server 2003
DHCP server would reply 100% of the time. I recommend at
least 50,000 usec to be safe. The alternative is to hope
that one of the retries will be successful but note that
the DHCP timeout and retry process takes a longer than
this delay.
- CDP Options:
CONFIG_CDP_DEVICE_ID

View File

@ -306,7 +306,7 @@ int do_mii (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
return 1;
}
#if defined(CONFIG_8xx) || defined(CONFIG_MCF532x)
#if defined(CONFIG_8xx) || defined(CONFIG_MCF532x) || defined(CONFIG_MII_INIT)
mii_init ();
#endif

View File

@ -35,6 +35,7 @@ COBJS-y += e1000.o
COBJS-y += eepro100.o
COBJS-y += enc28j60.o
COBJS-y += fsl_mcdmafec.o
COBJS-$(CONFIG_GRETH) += greth.o
COBJS-y += inca-ip_sw.o
COBJS-y += ks8695eth.o
COBJS-y += lan91c96.o

View File

@ -1,5 +1,5 @@
/**************************************************************************
Inter Pro 1000 for ppcboot/das-u-boot
Intel Pro 1000 for ppcboot/das-u-boot
Drivers are port from Intel's Linux driver e1000-4.3.15
and from Etherboot pro 1000 driver by mrakes at vivato dot net
tested on both gig copper and gig fiber boards
@ -82,6 +82,7 @@ static struct pci_device_id supported[] = {
{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82545EM_FIBER},
{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82546EB_FIBER},
{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82540EM_LOM},
{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82541ER},
};
/* Function forward declarations */
@ -512,6 +513,11 @@ e1000_read_mac_addr(struct eth_device *nic)
/* Invert the last bit if this is the second device */
nic->enetaddr[5] += 1;
}
#ifdef CONFIG_E1000_FALLBACK_MAC
if ( *(u32*)(nic->enetaddr) == 0 || *(u32*)(nic->enetaddr) == ~0 )
for ( i=0; i < NODE_ADDRESS_SIZE; i++ )
nic->enetaddr[i] = (CONFIG_E1000_FALLBACK_MAC >> (8*(5-i))) & 0xff;
#endif
#else
/*
* The AP1000's e1000 has no eeprom; the MAC address is stored in the
@ -639,6 +645,9 @@ e1000_set_mac_type(struct e1000_hw *hw)
case E1000_DEV_ID_82546EB_FIBER:
hw->mac_type = e1000_82546;
break;
case E1000_DEV_ID_82541ER:
hw->mac_type = e1000_82541_rev_2;
break;
default:
/* Should never have loaded on this device */
return -E1000_ERR_MAC_TYPE;
@ -2485,6 +2494,36 @@ e1000_phy_reset(struct e1000_hw *hw)
return 0;
}
static int
e1000_set_phy_type(struct e1000_hw *hw)
{
DEBUGFUNC();
if(hw->mac_type == e1000_undefined)
return -E1000_ERR_PHY_TYPE;
switch(hw->phy_id) {
case M88E1000_E_PHY_ID:
case M88E1000_I_PHY_ID:
case M88E1011_I_PHY_ID:
hw->phy_type = e1000_phy_m88;
break;
case IGP01E1000_I_PHY_ID:
if(hw->mac_type == e1000_82541 ||
hw->mac_type == e1000_82541_rev_2) {
hw->phy_type = e1000_phy_igp;
break;
}
/* Fall Through */
default:
/* Should never have loaded on this device */
hw->phy_type = e1000_phy_undefined;
return -E1000_ERR_PHY_TYPE;
}
return E1000_SUCCESS;
}
/******************************************************************************
* Probes the expected PHY address for known PHY IDs
*
@ -2493,6 +2532,7 @@ e1000_phy_reset(struct e1000_hw *hw)
static int
e1000_detect_gig_phy(struct e1000_hw *hw)
{
int32_t phy_init_status;
uint16_t phy_id_high, phy_id_low;
int match = FALSE;
@ -2526,11 +2566,19 @@ e1000_detect_gig_phy(struct e1000_hw *hw)
if (hw->phy_id == M88E1011_I_PHY_ID)
match = TRUE;
break;
case e1000_82541_rev_2:
if(hw->phy_id == IGP01E1000_I_PHY_ID)
match = TRUE;
break;
default:
DEBUGOUT("Invalid MAC type %d\n", hw->mac_type);
return -E1000_ERR_CONFIG;
}
if (match) {
phy_init_status = e1000_set_phy_type(hw);
if ((match) && (phy_init_status == E1000_SUCCESS)) {
DEBUGOUT("PHY ID 0x%X detected\n", hw->phy_id);
return 0;
}
@ -2985,7 +3033,7 @@ e1000_initialize(bd_t * bis)
free(nic);
return 0;
}
#ifndef CONFIG_AP1000
#if !(defined(CONFIG_AP1000) || defined(CONFIG_MVBC_1G))
if (e1000_validate_eeprom_checksum(nic) < 0) {
printf("The EEPROM Checksum Is Not Valid\n");
free(hw);

View File

@ -71,6 +71,8 @@ typedef enum {
e1000_82540,
e1000_82545,
e1000_82546,
e1000_82541,
e1000_82541_rev_2,
e1000_num_macs
} e1000_mac_type;
@ -168,6 +170,13 @@ typedef enum {
e1000_1000t_rx_status_undefined = 0xFF
} e1000_1000t_rx_status;
typedef enum {
e1000_phy_m88 = 0,
e1000_phy_igp,
e1000_phy_igp_2,
e1000_phy_undefined = 0xFF
} e1000_phy_type;
struct e1000_phy_info {
e1000_cable_length cable_length;
e1000_10bt_ext_dist_enable extended_10bt_distance;
@ -184,14 +193,19 @@ struct e1000_phy_stats {
};
/* Error Codes */
#define E1000_SUCCESS 0
#define E1000_ERR_EEPROM 1
#define E1000_ERR_PHY 2
#define E1000_ERR_CONFIG 3
#define E1000_ERR_PARAM 4
#define E1000_ERR_MAC_TYPE 5
#define E1000_ERR_NOLINK 6
#define E1000_ERR_TIMEOUT 7
#define E1000_SUCCESS 0
#define E1000_ERR_EEPROM 1
#define E1000_ERR_PHY 2
#define E1000_ERR_CONFIG 3
#define E1000_ERR_PARAM 4
#define E1000_ERR_MAC_TYPE 5
#define E1000_ERR_PHY_TYPE 6
#define E1000_ERR_NOLINK 7
#define E1000_ERR_TIMEOUT 8
#define E1000_ERR_RESET 9
#define E1000_ERR_MASTER_REQUESTS_PENDING 10
#define E1000_ERR_HOST_INTERFACE_COMMAND 11
#define E1000_BLK_PHY_RESET 12
/* PCI Device IDs */
#define E1000_DEV_ID_82542 0x1000
@ -207,7 +221,8 @@ struct e1000_phy_stats {
#define E1000_DEV_ID_82545EM_FIBER 0x1011
#define E1000_DEV_ID_82546EB_COPPER 0x1010
#define E1000_DEV_ID_82546EB_FIBER 0x1012
#define NUM_DEV_IDS 13
#define E1000_DEV_ID_82541ER 0x1078
#define NUM_DEV_IDS 14
#define NODE_ADDRESS_SIZE 6
#define ETH_LENGTH_OF_ADDRESS 6
@ -799,6 +814,8 @@ struct e1000_hw {
pci_dev_t pdev;
uint8_t *hw_addr;
e1000_mac_type mac_type;
e1000_phy_type phy_type;
uint32_t phy_init_script;
e1000_media_type media_type;
e1000_lan_loc lan_loc;
e1000_fc_type fc;
@ -1517,7 +1534,22 @@ struct e1000_hw {
#define M88E1000_EXT_PHY_SPEC_CTRL 0x14 /* Extended PHY Specific Control */
#define M88E1000_RX_ERR_CNTR 0x15 /* Receive Error Counter */
#define MAX_PHY_REG_ADDRESS 0x1F /* 5 bit address bus (0-0x1F) */
#define MAX_PHY_REG_ADDRESS 0x1F /* 5 bit address bus (0-0x1F) */
/* IGP01E1000 specifics */
#define IGP01E1000_IEEE_REGS_PAGE 0x0000
#define IGP01E1000_IEEE_RESTART_AUTONEG 0x3300
#define IGP01E1000_IEEE_FORCE_GIGA 0x0140
/* IGP01E1000 Specific Registers */
#define IGP01E1000_PHY_PORT_CONFIG 0x10 /* PHY Specific Port Config Register */
#define IGP01E1000_PHY_PORT_STATUS 0x11 /* PHY Specific Status Register */
#define IGP01E1000_PHY_PORT_CTRL 0x12 /* PHY Specific Control Register */
#define IGP01E1000_PHY_LINK_HEALTH 0x13 /* PHY Link Health Register */
#define IGP01E1000_GMII_FIFO 0x14 /* GMII FIFO Register */
#define IGP01E1000_PHY_CHANNEL_QUALITY 0x15 /* PHY Channel Quality Register */
#define IGP02E1000_PHY_POWER_MGMT 0x19
#define IGP01E1000_PHY_PAGE_SELECT 0x1F /* PHY Page Select Core Register */
/* PHY Control Register */
#define MII_CR_SPEED_SELECT_MSB 0x0040 /* bits 6,13: 10=1000, 01=100, 00=10 */
@ -1729,6 +1761,7 @@ struct e1000_hw {
#define M88E1011_I_PHY_ID 0x01410C20
#define M88E1000_12_PHY_ID M88E1000_E_PHY_ID
#define M88E1000_14_PHY_ID M88E1000_E_PHY_ID
#define IGP01E1000_I_PHY_ID 0x02A80380
/* Miscellaneous PHY bit definitions. */
#define PHY_PREAMBLE 0xFFFFFFFF

661
drivers/net/greth.c Normal file
View File

@ -0,0 +1,661 @@
/* Gaisler.com GRETH 10/100/1000 Ethernet MAC driver
*
* Driver use polling mode (no Interrupt)
*
* (C) Copyright 2007
* Daniel Hellstrom, Gaisler Research, daniel@gaisler.com
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#include <common.h>
#include <command.h>
#include <net.h>
#include <malloc.h>
#include <asm/processor.h>
#include <ambapp.h>
#include <asm/leon.h>
/* #define DEBUG */
#include "greth.h"
/* Default to 3s timeout on autonegotiation */
#ifndef GRETH_PHY_TIMEOUT_MS
#define GRETH_PHY_TIMEOUT_MS 3000
#endif
/* ByPass Cache when reading regs */
#define GRETH_REGLOAD(addr) SPARC_NOCACHE_READ(addr)
/* Write-through cache ==> no bypassing needed on writes */
#define GRETH_REGSAVE(addr,data) (*(unsigned int *)(addr) = (data))
#define GRETH_REGORIN(addr,data) GRETH_REGSAVE(addr,GRETH_REGLOAD(addr)|data)
#define GRETH_REGANDIN(addr,data) GRETH_REGSAVE(addr,GRETH_REGLOAD(addr)&data)
#define GRETH_RXBD_CNT 4
#define GRETH_TXBD_CNT 1
#define GRETH_RXBUF_SIZE 1540
#define GRETH_BUF_ALIGN 4
#define GRETH_RXBUF_EFF_SIZE \
( (GRETH_RXBUF_SIZE&~(GRETH_BUF_ALIGN-1))+GRETH_BUF_ALIGN )
typedef struct {
greth_regs *regs;
int irq;
struct eth_device *dev;
/* Hardware info */
unsigned char phyaddr;
int gbit_mac;
/* Current operating Mode */
int gb; /* GigaBit */
int fd; /* Full Duplex */
int sp; /* 10/100Mbps speed (1=100,0=10) */
int auto_neg; /* Auto negotiate done */
unsigned char hwaddr[6]; /* MAC Address */
/* Descriptors */
greth_bd *rxbd_base, *rxbd_max;
greth_bd *txbd_base, *txbd_max;
greth_bd *rxbd_curr;
/* rx buffers in rx descriptors */
void *rxbuf_base; /* (GRETH_RXBUF_SIZE+ALIGNBYTES) * GRETH_RXBD_CNT */
/* unused for gbit_mac, temp buffer for sending packets with unligned
* start.
* Pointer to packet allocated with malloc.
*/
void *txbuf;
struct {
/* rx status */
unsigned int rx_packets,
rx_crc_errors, rx_frame_errors, rx_length_errors, rx_errors;
/* tx stats */
unsigned int tx_packets,
tx_latecol_errors,
tx_underrun_errors, tx_limit_errors, tx_errors;
} stats;
} greth_priv;
/* Read MII register 'addr' from core 'regs' */
static int read_mii(int addr, volatile greth_regs * regs)
{
while (GRETH_REGLOAD(&regs->mdio) & GRETH_MII_BUSY) {
}
GRETH_REGSAVE(&regs->mdio, (0 << 11) | ((addr & 0x1F) << 6) | 2);
while (GRETH_REGLOAD(&regs->mdio) & GRETH_MII_BUSY) {
}
if (!(GRETH_REGLOAD(&regs->mdio) & GRETH_MII_NVALID)) {
return (GRETH_REGLOAD(&regs->mdio) >> 16) & 0xFFFF;
} else {
return -1;
}
}
static void write_mii(int addr, int data, volatile greth_regs * regs)
{
while (GRETH_REGLOAD(&regs->mdio) & GRETH_MII_BUSY) {
}
GRETH_REGSAVE(&regs->mdio,
((data & 0xFFFF) << 16) | (0 << 11) | ((addr & 0x1F) << 6)
| 1);
while (GRETH_REGLOAD(&regs->mdio) & GRETH_MII_BUSY) {
}
}
/* init/start hardware and allocate descriptor buffers for rx side
*
*/
int greth_init(struct eth_device *dev, bd_t * bis)
{
int i;
greth_priv *greth = dev->priv;
greth_regs *regs = greth->regs;
#ifdef DEBUG
printf("greth_init\n");
#endif
GRETH_REGSAVE(&regs->control, 0);
if (!greth->rxbd_base) {
/* allocate descriptors */
greth->rxbd_base = (greth_bd *)
memalign(0x1000, GRETH_RXBD_CNT * sizeof(greth_bd));
greth->txbd_base = (greth_bd *)
memalign(0x1000, GRETH_RXBD_CNT * sizeof(greth_bd));
/* allocate buffers to all descriptors */
greth->rxbuf_base =
malloc(GRETH_RXBUF_EFF_SIZE * GRETH_RXBD_CNT);
}
/* initate rx decriptors */
for (i = 0; i < GRETH_RXBD_CNT; i++) {
greth->rxbd_base[i].addr = (unsigned int)
greth->rxbuf_base + (GRETH_RXBUF_EFF_SIZE * i);
/* enable desciptor & set wrap bit if last descriptor */
if (i >= (GRETH_RXBD_CNT - 1)) {
greth->rxbd_base[i].stat = GRETH_BD_EN | GRETH_BD_WR;
} else {
greth->rxbd_base[i].stat = GRETH_BD_EN;
}
}
/* initiate indexes */
greth->rxbd_curr = greth->rxbd_base;
greth->rxbd_max = greth->rxbd_base + (GRETH_RXBD_CNT - 1);
greth->txbd_max = greth->txbd_base + (GRETH_TXBD_CNT - 1);
/*
* greth->txbd_base->addr = 0;
* greth->txbd_base->stat = GRETH_BD_WR;
*/
/* initate tx decriptors */
for (i = 0; i < GRETH_TXBD_CNT; i++) {
greth->txbd_base[i].addr = 0;
/* enable desciptor & set wrap bit if last descriptor */
if (i >= (GRETH_RXBD_CNT - 1)) {
greth->txbd_base[i].stat = GRETH_BD_WR;
} else {
greth->txbd_base[i].stat = 0;
}
}
/**** SET HARDWARE REGS ****/
/* Set pointer to tx/rx descriptor areas */
GRETH_REGSAVE(&regs->rx_desc_p, (unsigned int)&greth->rxbd_base[0]);
GRETH_REGSAVE(&regs->tx_desc_p, (unsigned int)&greth->txbd_base[0]);
/* Enable Transmitter, GRETH will now scan descriptors for packets
* to transmitt */
#ifdef DEBUG
printf("greth_init: enabling receiver\n");
#endif
GRETH_REGORIN(&regs->control, GRETH_RXEN);
return 0;
}
/* Initiate PHY to a relevant speed
* return:
* - 0 = success
* - 1 = timeout/fail
*/
int greth_init_phy(greth_priv * dev, bd_t * bis)
{
greth_regs *regs = dev->regs;
int tmp, tmp1, tmp2, i;
unsigned int start, timeout;
/* X msecs to ticks */
timeout = usec2ticks(GRETH_PHY_TIMEOUT_MS * 1000);
/* Get system timer0 current value
* Total timeout is 5s
*/
start = get_timer(0);
/* get phy control register default values */
while ((tmp = read_mii(0, regs)) & 0x8000) {
if (get_timer(start) > timeout)
return 1; /* Fail */
}
/* reset PHY and wait for completion */
write_mii(0, 0x8000 | tmp, regs);
while (((tmp = read_mii(0, regs))) & 0x8000) {
if (get_timer(start) > timeout)
return 1; /* Fail */
}
/* Check if PHY is autoneg capable and then determine operating
* mode, otherwise force it to 10 Mbit halfduplex
*/
dev->gb = 0;
dev->fd = 0;
dev->sp = 0;
dev->auto_neg = 0;
if (!((tmp >> 12) & 1)) {
write_mii(0, 0, regs);
} else {
/* wait for auto negotiation to complete and then check operating mode */
dev->auto_neg = 1;
i = 0;
while (!(((tmp = read_mii(1, regs)) >> 5) & 1)) {
if (get_timer(start) > timeout) {
printf("Auto negotiation timed out. "
"Selecting default config\n");
tmp = read_mii(0, regs);
dev->gb = ((tmp >> 6) & 1)
&& !((tmp >> 13) & 1);
dev->sp = !((tmp >> 6) & 1)
&& ((tmp >> 13) & 1);
dev->fd = (tmp >> 8) & 1;
goto auto_neg_done;
}
}
if ((tmp >> 8) & 1) {
tmp1 = read_mii(9, regs);
tmp2 = read_mii(10, regs);
if ((tmp1 & GRETH_MII_EXTADV_1000FD) &&
(tmp2 & GRETH_MII_EXTPRT_1000FD)) {
dev->gb = 1;
dev->fd = 1;
}
if ((tmp1 & GRETH_MII_EXTADV_1000HD) &&
(tmp2 & GRETH_MII_EXTPRT_1000HD)) {
dev->gb = 1;
dev->fd = 0;
}
}
if ((dev->gb == 0) || ((dev->gb == 1) && (dev->gbit_mac == 0))) {
tmp1 = read_mii(4, regs);
tmp2 = read_mii(5, regs);
if ((tmp1 & GRETH_MII_100TXFD) &&
(tmp2 & GRETH_MII_100TXFD)) {
dev->sp = 1;
dev->fd = 1;
}
if ((tmp1 & GRETH_MII_100TXHD) &&
(tmp2 & GRETH_MII_100TXHD)) {
dev->sp = 1;
dev->fd = 0;
}
if ((tmp1 & GRETH_MII_10FD) && (tmp2 & GRETH_MII_10FD)) {
dev->fd = 1;
}
if ((dev->gb == 1) && (dev->gbit_mac == 0)) {
dev->gb = 0;
dev->fd = 0;
write_mii(0, dev->sp << 13, regs);
}
}
}
auto_neg_done:
#ifdef DEBUG
printf("%s GRETH Ethermac at [0x%x] irq %d. Running \
%d Mbps %s duplex\n", dev->gbit_mac ? "10/100/1000" : "10/100", (unsigned int)(regs), (unsigned int)(dev->irq), dev->gb ? 1000 : (dev->sp ? 100 : 10), dev->fd ? "full" : "half");
#endif
/* Read out PHY info if extended registers are available */
if (tmp & 1) {
tmp1 = read_mii(2, regs);
tmp2 = read_mii(3, regs);
tmp1 = (tmp1 << 6) | ((tmp2 >> 10) & 0x3F);
tmp = tmp2 & 0xF;
tmp2 = (tmp2 >> 4) & 0x3F;
#ifdef DEBUG
printf("PHY: Vendor %x Device %x Revision %d\n", tmp1,
tmp2, tmp);
#endif
} else {
printf("PHY info not available\n");
}
/* set speed and duplex bits in control register */
GRETH_REGORIN(&regs->control,
(dev->gb << 8) | (dev->sp << 7) | (dev->fd << 4));
return 0;
}
void greth_halt(struct eth_device *dev)
{
greth_priv *greth;
greth_regs *regs;
int i;
#ifdef DEBUG
printf("greth_halt\n");
#endif
if (!dev || !dev->priv)
return;
greth = dev->priv;
regs = greth->regs;
if (!regs)
return;
/* disable receiver/transmitter by clearing the enable bits */
GRETH_REGANDIN(&regs->control, ~(GRETH_RXEN | GRETH_TXEN));
/* reset rx/tx descriptors */
if (greth->rxbd_base) {
for (i = 0; i < GRETH_RXBD_CNT; i++) {
greth->rxbd_base[i].stat =
(i >= (GRETH_RXBD_CNT - 1)) ? GRETH_BD_WR : 0;
}
}
if (greth->txbd_base) {
for (i = 0; i < GRETH_TXBD_CNT; i++) {
greth->txbd_base[i].stat =
(i >= (GRETH_TXBD_CNT - 1)) ? GRETH_BD_WR : 0;
}
}
}
int greth_send(struct eth_device *dev, volatile void *eth_data, int data_length)
{
greth_priv *greth = dev->priv;
greth_regs *regs = greth->regs;
greth_bd *txbd;
void *txbuf;
unsigned int status;
#ifdef DEBUG
printf("greth_send\n");
#endif
/* send data, wait for data to be sent, then return */
if (((unsigned int)eth_data & (GRETH_BUF_ALIGN - 1))
&& !greth->gbit_mac) {
/* data not aligned as needed by GRETH 10/100, solve this by allocating 4 byte aligned buffer
* and copy data to before giving it to GRETH.
*/
if (!greth->txbuf) {
greth->txbuf = malloc(GRETH_RXBUF_SIZE);
#ifdef DEBUG
printf("GRETH: allocated aligned tx-buf\n");
#endif
}
txbuf = greth->txbuf;
/* copy data info buffer */
memcpy((char *)txbuf, (char *)eth_data, data_length);
/* keep buffer to next time */
} else {
txbuf = (void *)eth_data;
}
/* get descriptor to use, only 1 supported... hehe easy */
txbd = greth->txbd_base;
/* setup descriptor to wrap around to it self */
txbd->addr = (unsigned int)txbuf;
txbd->stat = GRETH_BD_EN | GRETH_BD_WR | data_length;
/* Remind Core which descriptor to use when sending */
GRETH_REGSAVE(&regs->tx_desc_p, (unsigned int)txbd);
/* initate send by enabling transmitter */
GRETH_REGORIN(&regs->control, GRETH_TXEN);
/* Wait for data to be sent */
while ((status = GRETH_REGLOAD(&txbd->stat)) & GRETH_BD_EN) {
;
}
/* was the packet transmitted succesfully? */
if (status & GRETH_TXBD_ERR_AL) {
greth->stats.tx_limit_errors++;
}
if (status & GRETH_TXBD_ERR_UE) {
greth->stats.tx_underrun_errors++;
}
if (status & GRETH_TXBD_ERR_LC) {
greth->stats.tx_latecol_errors++;
}
if (status &
(GRETH_TXBD_ERR_LC | GRETH_TXBD_ERR_UE | GRETH_TXBD_ERR_AL)) {
/* any error */
greth->stats.tx_errors++;
return -1;
}
/* bump tx packet counter */
greth->stats.tx_packets++;
/* return succefully */
return 0;
}
int greth_recv(struct eth_device *dev)
{
greth_priv *greth = dev->priv;
greth_regs *regs = greth->regs;
greth_bd *rxbd;
unsigned int status, len = 0, bad;
unsigned char *d;
int enable = 0;
int i;
#ifdef DEBUG
/* printf("greth_recv\n"); */
#endif
/* Receive One packet only, but clear as many error packets as there are
* available.
*/
{
/* current receive descriptor */
rxbd = greth->rxbd_curr;
/* get status of next received packet */
status = GRETH_REGLOAD(&rxbd->stat);
bad = 0;
/* stop if no more packets received */
if (status & GRETH_BD_EN) {
goto done;
}
#ifdef DEBUG
printf("greth_recv: packet 0x%lx, 0x%lx, len: %d\n",
(unsigned int)rxbd, status, status & GRETH_BD_LEN);
#endif
/* Check status for errors.
*/
if (status & GRETH_RXBD_ERR_FT) {
greth->stats.rx_length_errors++;
bad = 1;
}
if (status & (GRETH_RXBD_ERR_AE | GRETH_RXBD_ERR_OE)) {
greth->stats.rx_frame_errors++;
bad = 1;
}
if (status & GRETH_RXBD_ERR_CRC) {
greth->stats.rx_crc_errors++;
bad = 1;
}
if (bad) {
greth->stats.rx_errors++;
printf
("greth_recv: Bad packet (%d, %d, %d, 0x%08x, %d)\n",
greth->stats.rx_length_errors,
greth->stats.rx_frame_errors,
greth->stats.rx_crc_errors, status,
greth->stats.rx_packets);
/* print all rx descriptors */
for (i = 0; i < GRETH_RXBD_CNT; i++) {
printf("[%d]: Stat=0x%lx, Addr=0x%lx\n", i,
GRETH_REGLOAD(&greth->rxbd_base[i].stat),
GRETH_REGLOAD(&greth->rxbd_base[i].
addr));
}
} else {
/* Process the incoming packet. */
len = status & GRETH_BD_LEN;
d = (char *)rxbd->addr;
#ifdef DEBUG
printf
("greth_recv: new packet, length: %d. data: %x %x %x %x %x %x %x %x\n",
len, d[0], d[1], d[2], d[3], d[4], d[5], d[6],
d[7]);
#endif
/* flush all data cache to make sure we're not reading old packet data */
sparc_dcache_flush_all();
/* pass packet on to network subsystem */
NetReceive((void *)d, len);
/* bump stats counters */
greth->stats.rx_packets++;
/* bad is now 0 ==> will stop loop */
}
/* reenable descriptor to receive more packet with this descriptor, wrap around if needed */
rxbd->stat =
GRETH_BD_EN |
(((unsigned int)greth->rxbd_curr >=
(unsigned int)greth->rxbd_max) ? GRETH_BD_WR : 0);
enable = 1;
/* increase index */
greth->rxbd_curr =
((unsigned int)greth->rxbd_curr >=
(unsigned int)greth->rxbd_max) ? greth->
rxbd_base : (greth->rxbd_curr + 1);
};
if (enable) {
GRETH_REGORIN(&regs->control, GRETH_RXEN);
}
done:
/* return positive length of packet or 0 if non recieved */
return len;
}
void greth_set_hwaddr(greth_priv * greth, unsigned char *mac)
{
/* save new MAC address */
greth->dev->enetaddr[0] = greth->hwaddr[0] = mac[0];
greth->dev->enetaddr[1] = greth->hwaddr[1] = mac[1];
greth->dev->enetaddr[2] = greth->hwaddr[2] = mac[2];
greth->dev->enetaddr[3] = greth->hwaddr[3] = mac[3];
greth->dev->enetaddr[4] = greth->hwaddr[4] = mac[4];
greth->dev->enetaddr[5] = greth->hwaddr[5] = mac[5];
greth->regs->esa_msb = (mac[0] << 8) | mac[1];
greth->regs->esa_lsb =
(mac[2] << 24) | (mac[3] << 16) | (mac[4] << 8) | mac[5];
#ifdef DEBUG
printf("GRETH: New MAC address: %02x:%02x:%02x:%02x:%02x:%02x\n",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
#endif
}
int greth_initialize(bd_t * bis)
{
greth_priv *greth;
ambapp_apbdev apbdev;
struct eth_device *dev;
int i;
char *addr_str, *end;
unsigned char addr[6];
#ifdef DEBUG
printf("Scanning for GRETH\n");
#endif
/* Find Device & IRQ via AMBA Plug&Play information */
if (ambapp_apb_first(VENDOR_GAISLER, GAISLER_ETHMAC, &apbdev) != 1) {
return -1; /* GRETH not found */
}
greth = (greth_priv *) malloc(sizeof(greth_priv));
dev = (struct eth_device *)malloc(sizeof(struct eth_device));
memset(dev, 0, sizeof(struct eth_device));
memset(greth, 0, sizeof(greth_priv));
greth->regs = (greth_regs *) apbdev.address;
greth->irq = apbdev.irq;
#ifdef DEBUG
printf("Found GRETH at 0x%lx, irq %d\n", greth->regs, greth->irq);
#endif
dev->priv = (void *)greth;
dev->iobase = (unsigned int)greth->regs;
dev->init = greth_init;
dev->halt = greth_halt;
dev->send = greth_send;
dev->recv = greth_recv;
greth->dev = dev;
/* Reset Core */
GRETH_REGSAVE(&greth->regs->control, GRETH_RESET);
/* Wait for core to finish reset cycle */
while (GRETH_REGLOAD(&greth->regs->control) & GRETH_RESET) ;
/* Get the phy address which assumed to have been set
correctly with the reset value in hardware */
greth->phyaddr = (GRETH_REGLOAD(&greth->regs->mdio) >> 11) & 0x1F;
/* Check if mac is gigabit capable */
greth->gbit_mac = (GRETH_REGLOAD(&greth->regs->control) >> 27) & 1;
/* Make descriptor string */
if (greth->gbit_mac) {
sprintf(dev->name, "GRETH 10/100/GB");
} else {
sprintf(dev->name, "GRETH 10/100");
}
/* initiate PHY, select speed/duplex depending on connected PHY */
if (greth_init_phy(greth, bis)) {
/* Failed to init PHY (timedout) */
return -1;
}
/* Register Device to EtherNet subsystem */
eth_register(dev);
/* Get MAC address */
if ((addr_str = getenv("ethaddr")) != NULL) {
for (i = 0; i < 6; i++) {
addr[i] =
addr_str ? simple_strtoul(addr_str, &end, 16) : 0;
if (addr_str) {
addr_str = (*end) ? end + 1 : end;
}
}
} else {
/* HW Address not found in environment, Set default HW address */
addr[0] = GRETH_HWADDR_0; /* MSB */
addr[1] = GRETH_HWADDR_1;
addr[2] = GRETH_HWADDR_2;
addr[3] = GRETH_HWADDR_3;
addr[4] = GRETH_HWADDR_4;
addr[5] = GRETH_HWADDR_5; /* LSB */
}
/* set and remember MAC address */
greth_set_hwaddr(greth, addr);
return 1;
}

97
drivers/net/greth.h Normal file
View File

@ -0,0 +1,97 @@
/* Gaisler.com GRETH 10/100/1000 Ethernet MAC driver
*
* (C) Copyright 2007
* Daniel Hellstrom, Gaisler Research, daniel@gaisler.com
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#define GRETH_FD 0x10
#define GRETH_RESET 0x40
#define GRETH_MII_BUSY 0x8
#define GRETH_MII_NVALID 0x10
/* MII registers */
#define GRETH_MII_EXTADV_1000FD 0x00000200
#define GRETH_MII_EXTADV_1000HD 0x00000100
#define GRETH_MII_EXTPRT_1000FD 0x00000800
#define GRETH_MII_EXTPRT_1000HD 0x00000400
#define GRETH_MII_100T4 0x00000200
#define GRETH_MII_100TXFD 0x00000100
#define GRETH_MII_100TXHD 0x00000080
#define GRETH_MII_10FD 0x00000040
#define GRETH_MII_10HD 0x00000020
#define GRETH_BD_EN 0x800
#define GRETH_BD_WR 0x1000
#define GRETH_BD_IE 0x2000
#define GRETH_BD_LEN 0x7FF
#define GRETH_TXEN 0x1
#define GRETH_INT_TX 0x8
#define GRETH_TXI 0x4
#define GRETH_TXBD_STATUS 0x0001C000
#define GRETH_TXBD_MORE 0x20000
#define GRETH_TXBD_IPCS 0x40000
#define GRETH_TXBD_TCPCS 0x80000
#define GRETH_TXBD_UDPCS 0x100000
#define GRETH_TXBD_ERR_LC 0x10000
#define GRETH_TXBD_ERR_UE 0x4000
#define GRETH_TXBD_ERR_AL 0x8000
#define GRETH_TXBD_NUM 128
#define GRETH_TXBD_NUM_MASK (GRETH_TXBD_NUM-1)
#define GRETH_TX_BUF_SIZE 2048
#define GRETH_INT_RX 0x4
#define GRETH_RXEN 0x2
#define GRETH_RXI 0x8
#define GRETH_RXBD_STATUS 0xFFFFC000
#define GRETH_RXBD_ERR_AE 0x4000
#define GRETH_RXBD_ERR_FT 0x8000
#define GRETH_RXBD_ERR_CRC 0x10000
#define GRETH_RXBD_ERR_OE 0x20000
#define GRETH_RXBD_ERR_LE 0x40000
#define GRETH_RXBD_IP_DEC 0x80000
#define GRETH_RXBD_IP_CSERR 0x100000
#define GRETH_RXBD_UDP_DEC 0x200000
#define GRETH_RXBD_UDP_CSERR 0x400000
#define GRETH_RXBD_TCP_DEC 0x800000
#define GRETH_RXBD_TCP_CSERR 0x1000000
#define GRETH_RXBD_NUM 128
#define GRETH_RXBD_NUM_MASK (GRETH_RXBD_NUM-1)
#define GRETH_RX_BUF_SIZE 2048
/* Ethernet configuration registers */
typedef struct _greth_regs {
volatile unsigned int control;
volatile unsigned int status;
volatile unsigned int esa_msb;
volatile unsigned int esa_lsb;
volatile unsigned int mdio;
volatile unsigned int tx_desc_p;
volatile unsigned int rx_desc_p;
} greth_regs;
/* Ethernet buffer descriptor */
typedef struct _greth_bd {
volatile unsigned int stat;
unsigned int addr; /* Buffer address not changed by HW */
} greth_bd;

View File

@ -166,6 +166,13 @@ int fec_send(struct eth_device *dev, volatile void *packet, int length)
/* Activate transmit Buffer Descriptor polling */
fecp->tdar = 0x01000000; /* Descriptor polling active */
/* FEC fix for MCF5275, FEC unable to initial transmit data packet.
* A nop will ensure the descriptor polling active completed.
*/
#ifdef CONFIG_M5275
__asm__ ("nop");
#endif
#ifdef CFG_UNIFY_CACHE
icache_invalid();
#endif

View File

@ -79,7 +79,7 @@ typedef unsigned long int dword;
#ifdef CONFIG_XSENGINE
#define SMC_inl(r) (*((volatile dword *)(SMC_BASE_ADDRESS+(r<<1))))
#define SMC_inw(r) (*((volatile word *)(SMC_BASE_ADDRESS+(r<<1))))
#define SMC_inb(p) ({ \
#define SMC_inb(p) ({ \
unsigned int __p = (unsigned int)(SMC_BASE_ADDRESS + (p<<1)); \
unsigned int __v = *(volatile unsigned short *)((__p) & ~2); \
if (__p & 2) __v >>= 8; \
@ -176,7 +176,76 @@ typedef unsigned long int dword;
}; \
})
#else /* if not CONFIG_PXA250 */
#elif defined(CONFIG_LEON) /* if not CONFIG_PXA250 */
#define SMC_LEON_SWAP16(_x_) ({ word _x = (_x_); ((_x << 8) | (_x >> 8)); })
#define SMC_LEON_SWAP32(_x_) \
({ dword _x = (_x_); \
((_x << 24) | \
((0x0000FF00UL & _x) << 8) | \
((0x00FF0000UL & _x) >> 8) | \
(_x >> 24)); })
#define SMC_inl(r) (SMC_LEON_SWAP32((*(volatile dword *)(SMC_BASE_ADDRESS+((r)<<0)))))
#define SMC_inl_nosw(r) ((*(volatile dword *)(SMC_BASE_ADDRESS+((r)<<0))))
#define SMC_inw(r) (SMC_LEON_SWAP16((*(volatile word *)(SMC_BASE_ADDRESS+((r)<<0)))))
#define SMC_inw_nosw(r) ((*(volatile word *)(SMC_BASE_ADDRESS+((r)<<0))))
#define SMC_inb(p) ({ \
word ___v = SMC_inw((p) & ~1); \
if ((p) & 1) ___v >>= 8; \
else ___v &= 0xff; \
___v; })
#define SMC_outl(d,r) (*(volatile dword *)(SMC_BASE_ADDRESS+((r)<<0))=SMC_LEON_SWAP32(d))
#define SMC_outl_nosw(d,r) (*(volatile dword *)(SMC_BASE_ADDRESS+((r)<<0))=(d))
#define SMC_outw(d,r) (*(volatile word *)(SMC_BASE_ADDRESS+((r)<<0))=SMC_LEON_SWAP16(d))
#define SMC_outw_nosw(d,r) (*(volatile word *)(SMC_BASE_ADDRESS+((r)<<0))=(d))
#define SMC_outb(d,r) do{ word __d = (byte)(d); \
word __w = SMC_inw((r)&~1); \
__w &= ((r)&1) ? 0x00FF : 0xFF00; \
__w |= ((r)&1) ? __d<<8 : __d; \
SMC_outw(__w,(r)&~1); \
}while(0)
#define SMC_outsl(r,b,l) do{ int __i; \
dword *__b2; \
__b2 = (dword *) b; \
for (__i = 0; __i < l; __i++) { \
SMC_outl_nosw( *(__b2 + __i), r); \
} \
}while(0)
#define SMC_outsw(r,b,l) do{ int __i; \
word *__b2; \
__b2 = (word *) b; \
for (__i = 0; __i < l; __i++) { \
SMC_outw_nosw( *(__b2 + __i), r); \
} \
}while(0)
#define SMC_insl(r,b,l) do{ int __i ; \
dword *__b2; \
__b2 = (dword *) b; \
for (__i = 0; __i < l; __i++) { \
*(__b2 + __i) = SMC_inl_nosw(r); \
}; \
}while(0)
#define SMC_insw(r,b,l) do{ int __i ; \
word *__b2; \
__b2 = (word *) b; \
for (__i = 0; __i < l; __i++) { \
*(__b2 + __i) = SMC_inw_nosw(r); \
}; \
}while(0)
#define SMC_insb(r,b,l) do{ int __i ; \
byte *__b2; \
__b2 = (byte *) b; \
for (__i = 0; __i < l; __i++) { \
*(__b2 + __i) = SMC_inb(r); \
}; \
}while(0)
#else /* if not CONFIG_PXA250 and not CONFIG_LEON */
#ifndef CONFIG_SMC_USE_IOFUNCS /* these macros don't work on some boards */
/*

View File

@ -1267,6 +1267,35 @@ struct phy_info phy_info_VSC8244 = {
},
};
struct phy_info phy_info_VSC8601 = {
0x00007042,
"Vitesse VSC8601",
4,
(struct phy_cmd[]){ /* config */
/* Override PHY config settings */
/* Configure some basic stuff */
{MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
#ifdef CFG_VSC8601_SKEWFIX
{MIIM_VSC8601_EPHY_CON,MIIM_VSC8601_EPHY_CON_INIT_SKEW,NULL},
#endif
{miim_end,}
},
(struct phy_cmd[]){ /* startup */
/* Read the Status (2x to make sure link is right) */
{MIIM_STATUS, miim_read, NULL},
/* Auto-negotiate */
{MIIM_STATUS, miim_read, &mii_parse_sr},
/* Read the status */
{MIIM_VSC8244_AUX_CONSTAT, miim_read,
&mii_parse_vsc8244},
{miim_end,}
},
(struct phy_cmd[]){ /* shutdown */
{miim_end,}
},
};
struct phy_info phy_info_dm9161 = {
0x0181b88,
"Davicom DM9161E",
@ -1462,6 +1491,7 @@ struct phy_info *phy_info[] = {
&phy_info_dm9161,
&phy_info_lxt971,
&phy_info_VSC8244,
&phy_info_VSC8601,
&phy_info_dp83865,
&phy_info_rtl8211b,
&phy_info_generic,

View File

@ -159,6 +159,11 @@
#define MIIM_VSC8244_LED_CON 0x1b
#define MIIM_VSC8244_LEDCON_INIT 0xF011
/* Entry for Vitesse VSC8601 regs starts here (Not complete) */
/* Vitesse VSC8601 Extended PHY Control Register 1 */
#define MIIM_VSC8601_EPHY_CON 0x17
#define MIIM_VSC8601_EPHY_CON_INIT_SKEW 0x1120
/* 88E1011 PHY Status Register */
#define MIIM_88E1011_PHY_STATUS 0x11
#define MIIM_88E1011_PHYSTAT_SPEED 0xc000

View File

@ -1810,6 +1810,7 @@
#define PCI_DEVICE_ID_INTEL_82434 0x04a3
#define PCI_DEVICE_ID_INTEL_I960 0x0960
#define PCI_DEVICE_ID_INTEL_I960RM 0x0962
#define PCI_DEVICE_ID_INTEL_82541ER 0x1078
#define PCI_DEVICE_ID_INTEL_82542 0x1000
#define PCI_DEVICE_ID_INTEL_82543GC_FIBER 0x1001
#define PCI_DEVICE_ID_INTEL_82543GC_COPPER 0x1004

View File

@ -879,7 +879,10 @@ static void DhcpSendRequestPkt(Bootp_t *bp_offer)
iplen = BOOTP_HDR_SIZE - sizeof(bp->bp_vend) + extlen;
NetSetIP(iphdr, 0xFFFFFFFFL, PORT_BOOTPS, PORT_BOOTPC, iplen);
debug ("Transmitting DHCPREQUEST packet: len = %d\n", pktlen);
debug ("Transmitting DHCPREQUEST packet: len = %d\n", pktlen);
#ifdef CONFIG_BOOTP_DHCP_REQUEST_DELAY
udelay(CONFIG_BOOTP_DHCP_REQUEST_DELAY);
#endif /* CONFIG_BOOTP_DHCP_REQUEST_DELAY */
NetSendPacket(NetTxPacket, pktlen);
}

View File

@ -60,6 +60,7 @@ extern int npe_initialize(bd_t *);
extern int uec_initialize(int);
extern int bfin_EMAC_initialize(bd_t *);
extern int atstk1000_eth_initialize(bd_t *);
extern int greth_initialize(bd_t *);
extern int atngw100_eth_initialize(bd_t *);
extern int mcffec_initialize(bd_t*);
extern int mcdmafec_initialize(bd_t*);
@ -275,6 +276,9 @@ int eth_initialize(bd_t *bis)
#if defined(CONFIG_ATSTK1000)
atstk1000_eth_initialize(bis);
#endif
#if defined(CONFIG_GRETH)
greth_initialize(bis);
#endif
#if defined(CONFIG_ATNGW100)
atngw100_eth_initialize(bis);
#endif