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

This commit is contained in:
Wolfgang Denk 2008-01-23 14:20:49 +01:00
commit 2468592d79
10 changed files with 273 additions and 122 deletions

4
README
View file

@ -2699,6 +2699,10 @@ Some configuration options can be set using Environment Variables:
=> setenv ethact SCC ETHERNET => setenv ethact SCC ETHERNET
=> ping 10.0.0.1 # traffic sent on SCC ETHERNET => ping 10.0.0.1 # traffic sent on SCC ETHERNET
ethrotate - When set to "no" U-Boot does not go through all
available network interfaces.
It just stays at the currently selected interface.
netretry - When set to "no" each network operation will netretry - When set to "no" each network operation will
either succeed or fail without retrying. either succeed or fail without retrying.
When set to "once" the network operation will When set to "once" the network operation will

View file

@ -30,8 +30,25 @@
#include <command.h> #include <command.h>
#include <asm/blackfin.h> #include <asm/blackfin.h>
#include <asm/io.h> #include <asm/io.h>
#include <net.h>
#include "ether_bf537.h" #include "ether_bf537.h"
/**
* is_valid_ether_addr - Determine if the given Ethernet address is valid
* @addr: Pointer to a six-byte array containing the Ethernet address
*
* Check that the Ethernet address (MAC) is not 00:00:00:00:00:00, is not
* a multicast address, and is not FF:FF:FF:FF:FF:FF.
*
* Return true if the address is valid.
*/
static inline int is_valid_ether_addr(const u8 * addr)
{
/* FF:FF:FF:FF:FF:FF is a multicast address so we don't need to
* explicitly check for it here. */
return !is_multicast_ether_addr(addr) && !is_zero_ether_addr(addr);
}
DECLARE_GLOBAL_DATA_PTR; DECLARE_GLOBAL_DATA_PTR;
#define POST_WORD_ADDR 0xFF903FFC #define POST_WORD_ADDR 0xFF903FFC

View file

@ -69,42 +69,3 @@ void SoftResetPHY(void);
void DumpPHYRegs(void); void DumpPHYRegs(void);
int SetupSystemRegs(int *opmode); int SetupSystemRegs(int *opmode);
/**
* is_zero_ether_addr - Determine if give Ethernet address is all zeros.
* @addr: Pointer to a six-byte array containing the Ethernet address
*
* Return true if the address is all zeroes.
*/
static inline int is_zero_ether_addr(const u8 * addr)
{
return !(addr[0] | addr[1] | addr[2] | addr[3] | addr[4] | addr[5]);
}
/**
* is_multicast_ether_addr - Determine if the Ethernet address is a multicast.
* @addr: Pointer to a six-byte array containing the Ethernet address
*
* Return true if the address is a multicast address.
* By definition the broadcast address is also a multicast address.
*/
static inline int is_multicast_ether_addr(const u8 * addr)
{
return (0x01 & addr[0]);
}
/**
* is_valid_ether_addr - Determine if the given Ethernet address is valid
* @addr: Pointer to a six-byte array containing the Ethernet address
*
* Check that the Ethernet address (MAC) is not 00:00:00:00:00:00, is not
* a multicast address, and is not FF:FF:FF:FF:FF:FF.
*
* Return true if the address is valid.
*/
static inline int is_valid_ether_addr(const u8 * addr)
{
/* FF:FF:FF:FF:FF:FF is a multicast address so we don't need to
* explicitly check for it here. */
return !is_multicast_ether_addr(addr) && !is_zero_ether_addr(addr);
}

View file

@ -87,7 +87,7 @@ int do_nfs (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
U_BOOT_CMD( U_BOOT_CMD(
nfs, 3, 1, do_nfs, nfs, 3, 1, do_nfs,
"nfs\t- boot image via network using NFS protocol\n", "nfs\t- boot image via network using NFS protocol\n",
"[loadAddress] [host ip addr:bootfilename]\n" "[loadAddress] [[hostIPaddr:]bootfilename]\n"
); );
#endif #endif

View file

@ -80,10 +80,7 @@
#if defined(CONFIG_CMD_NET) && defined(CONFIG_NET_MULTI) && \ #if defined(CONFIG_CMD_NET) && defined(CONFIG_NET_MULTI) && \
defined(CONFIG_RTL8139) defined(CONFIG_RTL8139)
#define TICKS_PER_SEC CFG_HZ #define RTL_TIMEOUT 100000
#define TICKS_PER_MS (TICKS_PER_SEC/1000)
#define RTL_TIMEOUT (1*TICKS_PER_SEC)
#define ETH_FRAME_LEN 1514 #define ETH_FRAME_LEN 1514
#define ETH_ALEN 6 #define ETH_ALEN 6
@ -392,6 +389,7 @@ static void rtl_reset(struct eth_device *dev)
#ifdef DEBUG_RX #ifdef DEBUG_RX
printf("rx ring address is %X\n",(unsigned long)rx_ring); printf("rx ring address is %X\n",(unsigned long)rx_ring);
#endif #endif
flush_cache((unsigned long)rx_ring, RX_BUF_LEN);
outl(phys_to_bus((int)rx_ring), ioaddr + RxBuf); outl(phys_to_bus((int)rx_ring), ioaddr + RxBuf);
/* If we add multicast support, the MAR0 register would have to be /* If we add multicast support, the MAR0 register would have to be
@ -414,9 +412,10 @@ static void rtl_reset(struct eth_device *dev)
static int rtl_transmit(struct eth_device *dev, volatile void *packet, int length) static int rtl_transmit(struct eth_device *dev, volatile void *packet, int length)
{ {
unsigned int status, to; unsigned int status;
unsigned long txstatus; unsigned long txstatus;
unsigned int len = length; unsigned int len = length;
int i = 0;
ioaddr = dev->iobase; ioaddr = dev->iobase;
@ -432,12 +431,11 @@ static int rtl_transmit(struct eth_device *dev, volatile void *packet, int lengt
tx_buffer[len++] = '\0'; tx_buffer[len++] = '\0';
} }
flush_cache((unsigned long)tx_buffer, length);
outl(phys_to_bus((int)tx_buffer), ioaddr + TxAddr0 + cur_tx*4); outl(phys_to_bus((int)tx_buffer), ioaddr + TxAddr0 + cur_tx*4);
outl(((TX_FIFO_THRESH<<11) & 0x003f0000) | len, outl(((TX_FIFO_THRESH<<11) & 0x003f0000) | len,
ioaddr + TxStatus0 + cur_tx*4); ioaddr + TxStatus0 + cur_tx*4);
to = currticks() + RTL_TIMEOUT;
do { do {
status = inw(ioaddr + IntrStatus); status = inw(ioaddr + IntrStatus);
/* Only acknlowledge interrupt sources we can properly handle /* Only acknlowledge interrupt sources we can properly handle
@ -445,7 +443,8 @@ static int rtl_transmit(struct eth_device *dev, volatile void *packet, int lengt
* rtl_poll() function. */ * rtl_poll() function. */
outw(status & (TxOK | TxErr | PCIErr), ioaddr + IntrStatus); outw(status & (TxOK | TxErr | PCIErr), ioaddr + IntrStatus);
if ((status & (TxOK | TxErr | PCIErr)) != 0) break; if ((status & (TxOK | TxErr | PCIErr)) != 0) break;
} while (currticks() < to); udelay(10);
} while (i++ < RTL_TIMEOUT);
txstatus = inl(ioaddr + TxStatus0 + cur_tx*4); txstatus = inl(ioaddr + TxStatus0 + cur_tx*4);
@ -458,8 +457,8 @@ static int rtl_transmit(struct eth_device *dev, volatile void *packet, int lengt
return length; return length;
} else { } else {
#ifdef DEBUG_TX #ifdef DEBUG_TX
printf("tx timeout/error (%d ticks), status %hX txstatus %X\n", printf("tx timeout/error (%d usecs), status %hX txstatus %X\n",
currticks()-to, status, txstatus); 10*i, status, txstatus);
#endif #endif
rtl_reset(dev); rtl_reset(dev);
@ -489,7 +488,8 @@ static int rtl_poll(struct eth_device *dev)
#endif #endif
ring_offs = cur_rx % RX_BUF_LEN; ring_offs = cur_rx % RX_BUF_LEN;
rx_status = *(unsigned int*)KSEG1ADDR((rx_ring + ring_offs)); /* ring_offs is guaranteed being 4-byte aligned */
rx_status = le32_to_cpu(*(unsigned int *)(rx_ring + ring_offs));
rx_size = rx_status >> 16; rx_size = rx_status >> 16;
rx_status &= 0xffff; rx_status &= 0xffff;
@ -519,6 +519,7 @@ static int rtl_poll(struct eth_device *dev)
printf("rx packet %d bytes", rx_size-4); printf("rx packet %d bytes", rx_size-4);
#endif #endif
} }
flush_cache((unsigned long)rx_ring, RX_BUF_LEN);
cur_rx = (cur_rx + rx_size + 4 + 3) & ~3; cur_rx = (cur_rx + rx_size + 4 + 3) & ~3;
outw(cur_rx - 16, ioaddr + RxBufPtr); outw(cur_rx - 16, ioaddr + RxBufPtr);

View file

@ -241,10 +241,9 @@ int tsec_init(struct eth_device *dev, bd_t * bd)
* It will wait for the write to be done (or for a timeout to * It will wait for the write to be done (or for a timeout to
* expire) before exiting * expire) before exiting
*/ */
void write_phy_reg(struct tsec_private *priv, uint regnum, uint value) void write_any_phy_reg(struct tsec_private *priv, uint phyid, uint regnum, uint value)
{ {
volatile tsec_t *regbase = priv->phyregs; volatile tsec_t *regbase = priv->phyregs;
uint phyid = priv->phyaddr;
int timeout = 1000000; int timeout = 1000000;
regbase->miimadd = (phyid << 8) | regnum; regbase->miimadd = (phyid << 8) | regnum;
@ -255,17 +254,19 @@ void write_phy_reg(struct tsec_private *priv, uint regnum, uint value)
while ((regbase->miimind & MIIMIND_BUSY) && timeout--) ; while ((regbase->miimind & MIIMIND_BUSY) && timeout--) ;
} }
/* #define to provide old write_phy_reg functionality without duplicating code */
#define write_phy_reg(priv, regnum, value) write_any_phy_reg(priv,priv->phyaddr,regnum,value)
/* Reads register regnum on the device's PHY through the /* Reads register regnum on the device's PHY through the
* registers specified in priv. It lowers and raises the read * registers specified in priv. It lowers and raises the read
* command, and waits for the data to become valid (miimind * command, and waits for the data to become valid (miimind
* notvalid bit cleared), and the bus to cease activity (miimind * notvalid bit cleared), and the bus to cease activity (miimind
* busy bit cleared), and then returns the value * busy bit cleared), and then returns the value
*/ */
uint read_phy_reg(struct tsec_private *priv, uint regnum) uint read_any_phy_reg(struct tsec_private *priv, uint phyid, uint regnum)
{ {
uint value; uint value;
volatile tsec_t *regbase = priv->phyregs; volatile tsec_t *regbase = priv->phyregs;
uint phyid = priv->phyaddr;
/* Put the address of the phy, and the register /* Put the address of the phy, and the register
* number into MIIMADD */ * number into MIIMADD */
@ -288,6 +289,9 @@ uint read_phy_reg(struct tsec_private *priv, uint regnum)
return value; return value;
} }
/* #define to provide old read_phy_reg functionality without duplicating code */
#define read_phy_reg(priv,regnum) read_any_phy_reg(priv,priv->phyaddr,regnum)
/* Discover which PHY is attached to the device, and configure it /* Discover which PHY is attached to the device, and configure it
* properly. If the PHY is not recognized, then return 0 * properly. If the PHY is not recognized, then return 0
* (failure). Otherwise, return 1 * (failure). Otherwise, return 1
@ -571,6 +575,63 @@ uint mii_parse_88E1011_psr(uint mii_reg, struct tsec_private * priv)
return 0; return 0;
} }
/* Parse the RTL8211B's status register for speed and duplex
* information
*/
uint mii_parse_RTL8211B_sr(uint mii_reg, struct tsec_private * priv)
{
uint speed;
mii_reg = read_phy_reg(priv, MIIM_RTL8211B_PHY_STATUS);
if ((mii_reg & MIIM_RTL8211B_PHYSTAT_LINK) &&
!(mii_reg & MIIM_RTL8211B_PHYSTAT_SPDDONE)) {
int i = 0;
puts("Waiting for PHY realtime link");
while (!(mii_reg & MIIM_RTL8211B_PHYSTAT_SPDDONE)) {
/* Timeout reached ? */
if (i > PHY_AUTONEGOTIATE_TIMEOUT) {
puts(" TIMEOUT !\n");
priv->link = 0;
break;
}
if ((i++ % 1000) == 0) {
putc('.');
}
udelay(1000); /* 1 ms */
mii_reg = read_phy_reg(priv, MIIM_RTL8211B_PHY_STATUS);
}
puts(" done\n");
udelay(500000); /* another 500 ms (results in faster booting) */
} else {
if (mii_reg & MIIM_RTL8211B_PHYSTAT_LINK)
priv->link = 1;
else
priv->link = 0;
}
if (mii_reg & MIIM_RTL8211B_PHYSTAT_DUPLEX)
priv->duplexity = 1;
else
priv->duplexity = 0;
speed = (mii_reg & MIIM_RTL8211B_PHYSTAT_SPEED);
switch (speed) {
case MIIM_RTL8211B_PHYSTAT_GBIT:
priv->speed = 1000;
break;
case MIIM_RTL8211B_PHYSTAT_100:
priv->speed = 100;
break;
default:
priv->speed = 10;
}
return 0;
}
/* Parse the cis8201's status register for speed and duplex /* Parse the cis8201's status register for speed and duplex
* information * information
*/ */
@ -1361,6 +1422,33 @@ struct phy_info phy_info_dp83865 = {
}, },
}; };
struct phy_info phy_info_rtl8211b = {
0x001cc91,
"RealTek RTL8211B",
4,
(struct phy_cmd[]){ /* config */
/* Reset and configure the PHY */
{MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
{MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL},
{MIIM_ANAR, MIIM_ANAR_INIT, NULL},
{MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
{MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
{miim_end,}
},
(struct phy_cmd[]){ /* startup */
/* Status is read once to clear old link state */
{MIIM_STATUS, miim_read, NULL},
/* Auto-negotiate */
{MIIM_STATUS, miim_read, &mii_parse_sr},
/* Read the status */
{MIIM_RTL8211B_PHY_STATUS, miim_read, &mii_parse_RTL8211B_sr},
{miim_end,}
},
(struct phy_cmd[]){ /* shutdown */
{miim_end,}
},
};
struct phy_info *phy_info[] = { struct phy_info *phy_info[] = {
&phy_info_cis8204, &phy_info_cis8204,
&phy_info_cis8201, &phy_info_cis8201,
@ -1374,6 +1462,7 @@ struct phy_info *phy_info[] = {
&phy_info_lxt971, &phy_info_lxt971,
&phy_info_VSC8244, &phy_info_VSC8244,
&phy_info_dp83865, &phy_info_dp83865,
&phy_info_rtl8211b,
&phy_info_generic, &phy_info_generic,
NULL NULL
}; };
@ -1497,18 +1586,6 @@ static void relocate_cmds(void)
#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) \ #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) \
&& !defined(BITBANGMII) && !defined(BITBANGMII)
struct tsec_private *get_priv_for_phy(unsigned char phyaddr)
{
int i;
for (i = 0; i < MAXCONTROLLERS; i++) {
if (privlist[i]->phyaddr == phyaddr)
return privlist[i];
}
return NULL;
}
/* /*
* Read a MII PHY register. * Read a MII PHY register.
* *
@ -1519,14 +1596,14 @@ static int tsec_miiphy_read(char *devname, unsigned char addr,
unsigned char reg, unsigned short *value) unsigned char reg, unsigned short *value)
{ {
unsigned short ret; unsigned short ret;
struct tsec_private *priv = get_priv_for_phy(addr); struct tsec_private *priv = privlist[0];
if (NULL == priv) { if (NULL == priv) {
printf("Can't read PHY at address %d\n", addr); printf("Can't read PHY at address %d\n", addr);
return -1; return -1;
} }
ret = (unsigned short)read_phy_reg(priv, reg); ret = (unsigned short)read_any_phy_reg(priv, addr, reg);
*value = ret; *value = ret;
return 0; return 0;
@ -1541,14 +1618,14 @@ static int tsec_miiphy_read(char *devname, unsigned char addr,
static int tsec_miiphy_write(char *devname, unsigned char addr, static int tsec_miiphy_write(char *devname, unsigned char addr,
unsigned char reg, unsigned short value) unsigned char reg, unsigned short value)
{ {
struct tsec_private *priv = get_priv_for_phy(addr); struct tsec_private *priv = privlist[0];
if (NULL == priv) { if (NULL == priv) {
printf("Can't write PHY at address %d\n", addr); printf("Can't write PHY at address %d\n", addr);
return -1; return -1;
} }
write_phy_reg(priv, reg, value); write_any_phy_reg(priv, addr, reg, value);
return 0; return 0;
} }

View file

@ -184,6 +184,14 @@
#define MIIM_88E1145_PHY_PAGE 29 #define MIIM_88E1145_PHY_PAGE 29
#define MIIM_88E1145_PHY_CAL_OV 30 #define MIIM_88E1145_PHY_CAL_OV 30
/* RTL8211B PHY Status Register */
#define MIIM_RTL8211B_PHY_STATUS 0x11
#define MIIM_RTL8211B_PHYSTAT_SPEED 0xc000
#define MIIM_RTL8211B_PHYSTAT_GBIT 0x8000
#define MIIM_RTL8211B_PHYSTAT_100 0x4000
#define MIIM_RTL8211B_PHYSTAT_DUPLEX 0x2000
#define MIIM_RTL8211B_PHYSTAT_SPDDONE 0x0800
#define MIIM_RTL8211B_PHYSTAT_LINK 0x0400
/* DM9161 Control register values */ /* DM9161 Control register values */
#define MIIM_DM9161_CR_STOP 0x0400 #define MIIM_DM9161_CR_STOP 0x0400

View file

@ -40,8 +40,13 @@ static uec_info_t eth1_uec_info = {
.tx_clock = CFG_UEC1_TX_CLK, .tx_clock = CFG_UEC1_TX_CLK,
.eth_type = CFG_UEC1_ETH_TYPE, .eth_type = CFG_UEC1_ETH_TYPE,
}, },
#if (CFG_UEC1_ETH_TYPE == FAST_ETH)
.num_threads_tx = UEC_NUM_OF_THREADS_1,
.num_threads_rx = UEC_NUM_OF_THREADS_1,
#else
.num_threads_tx = UEC_NUM_OF_THREADS_4, .num_threads_tx = UEC_NUM_OF_THREADS_4,
.num_threads_rx = UEC_NUM_OF_THREADS_4, .num_threads_rx = UEC_NUM_OF_THREADS_4,
#endif
.riscTx = QE_RISC_ALLOCATION_RISC1_AND_RISC2, .riscTx = QE_RISC_ALLOCATION_RISC1_AND_RISC2,
.riscRx = QE_RISC_ALLOCATION_RISC1_AND_RISC2, .riscRx = QE_RISC_ALLOCATION_RISC1_AND_RISC2,
.tx_bd_ring_len = 16, .tx_bd_ring_len = 16,
@ -58,8 +63,13 @@ static uec_info_t eth2_uec_info = {
.tx_clock = CFG_UEC2_TX_CLK, .tx_clock = CFG_UEC2_TX_CLK,
.eth_type = CFG_UEC2_ETH_TYPE, .eth_type = CFG_UEC2_ETH_TYPE,
}, },
#if (CFG_UEC2_ETH_TYPE == FAST_ETH)
.num_threads_tx = UEC_NUM_OF_THREADS_1,
.num_threads_rx = UEC_NUM_OF_THREADS_1,
#else
.num_threads_tx = UEC_NUM_OF_THREADS_4, .num_threads_tx = UEC_NUM_OF_THREADS_4,
.num_threads_rx = UEC_NUM_OF_THREADS_4, .num_threads_rx = UEC_NUM_OF_THREADS_4,
#endif
.riscTx = QE_RISC_ALLOCATION_RISC1_AND_RISC2, .riscTx = QE_RISC_ALLOCATION_RISC1_AND_RISC2,
.riscRx = QE_RISC_ALLOCATION_RISC1_AND_RISC2, .riscRx = QE_RISC_ALLOCATION_RISC1_AND_RISC2,
.tx_bd_ring_len = 16, .tx_bd_ring_len = 16,
@ -68,7 +78,6 @@ static uec_info_t eth2_uec_info = {
.enet_interface = CFG_UEC2_INTERFACE_MODE, .enet_interface = CFG_UEC2_INTERFACE_MODE,
}; };
#endif #endif
#ifdef CONFIG_UEC_ETH3 #ifdef CONFIG_UEC_ETH3
static uec_info_t eth3_uec_info = { static uec_info_t eth3_uec_info = {
.uf_info = { .uf_info = {
@ -77,8 +86,13 @@ static uec_info_t eth3_uec_info = {
.tx_clock = CFG_UEC3_TX_CLK, .tx_clock = CFG_UEC3_TX_CLK,
.eth_type = CFG_UEC3_ETH_TYPE, .eth_type = CFG_UEC3_ETH_TYPE,
}, },
#if (CFG_UEC3_ETH_TYPE == FAST_ETH)
.num_threads_tx = UEC_NUM_OF_THREADS_1,
.num_threads_rx = UEC_NUM_OF_THREADS_1,
#else
.num_threads_tx = UEC_NUM_OF_THREADS_4, .num_threads_tx = UEC_NUM_OF_THREADS_4,
.num_threads_rx = UEC_NUM_OF_THREADS_4, .num_threads_rx = UEC_NUM_OF_THREADS_4,
#endif
.riscTx = QE_RISC_ALLOCATION_RISC1_AND_RISC2, .riscTx = QE_RISC_ALLOCATION_RISC1_AND_RISC2,
.riscRx = QE_RISC_ALLOCATION_RISC1_AND_RISC2, .riscRx = QE_RISC_ALLOCATION_RISC1_AND_RISC2,
.tx_bd_ring_len = 16, .tx_bd_ring_len = 16,
@ -87,6 +101,29 @@ static uec_info_t eth3_uec_info = {
.enet_interface = CFG_UEC3_INTERFACE_MODE, .enet_interface = CFG_UEC3_INTERFACE_MODE,
}; };
#endif #endif
#ifdef CONFIG_UEC_ETH4
static uec_info_t eth4_uec_info = {
.uf_info = {
.ucc_num = CFG_UEC4_UCC_NUM,
.rx_clock = CFG_UEC4_RX_CLK,
.tx_clock = CFG_UEC4_TX_CLK,
.eth_type = CFG_UEC4_ETH_TYPE,
},
#if (CFG_UEC4_ETH_TYPE == FAST_ETH)
.num_threads_tx = UEC_NUM_OF_THREADS_1,
.num_threads_rx = UEC_NUM_OF_THREADS_1,
#else
.num_threads_tx = UEC_NUM_OF_THREADS_4,
.num_threads_rx = UEC_NUM_OF_THREADS_4,
#endif
.riscTx = QE_RISC_ALLOCATION_RISC1_AND_RISC2,
.riscRx = QE_RISC_ALLOCATION_RISC1_AND_RISC2,
.tx_bd_ring_len = 16,
.rx_bd_ring_len = 16,
.phy_address = CFG_UEC4_PHY_ADDR,
.enet_interface = CFG_UEC4_INTERFACE_MODE,
};
#endif
static int uec_mac_enable(uec_private_t *uec, comm_dir_e mode) static int uec_mac_enable(uec_private_t *uec, comm_dir_e mode)
{ {
@ -475,6 +512,8 @@ static int init_phy(struct eth_device *dev)
uec->mii_info = mii_info; uec->mii_info = mii_info;
qe_set_mii_clk_src(uec->uec_info->uf_info.ucc_num);
if (init_mii_management_configuration(umii_regs)) { if (init_mii_management_configuration(umii_regs)) {
printf("%s: The MII Bus is stuck!", dev->name); printf("%s: The MII Bus is stuck!", dev->name);
err = -1; err = -1;
@ -581,21 +620,12 @@ static void adjust_link(struct eth_device *dev)
static void phy_change(struct eth_device *dev) static void phy_change(struct eth_device *dev)
{ {
uec_private_t *uec = (uec_private_t *)dev->priv; uec_private_t *uec = (uec_private_t *)dev->priv;
uec_t *uec_regs;
int result = 0;
uec_regs = uec->uec_regs;
/* Delay 5s to give the PHY a chance to change the register state */
udelay(5000000);
/* Update the link, speed, duplex */ /* Update the link, speed, duplex */
result = uec->mii_info->phyinfo->read_status(uec->mii_info); uec->mii_info->phyinfo->read_status(uec->mii_info);
/* Adjust the interface according to speed */ /* Adjust the interface according to speed */
if ((0 == result) || (uec->mii_info->link == 0)) { adjust_link(dev);
adjust_link(dev);
}
} }
static int uec_set_mac_address(uec_private_t *uec, u8 *mac_addr) static int uec_set_mac_address(uec_private_t *uec, u8 *mac_addr)
@ -1120,27 +1150,59 @@ static int uec_startup(uec_private_t *uec)
static int uec_init(struct eth_device* dev, bd_t *bd) static int uec_init(struct eth_device* dev, bd_t *bd)
{ {
uec_private_t *uec; uec_private_t *uec;
int err; int err, i;
struct phy_info *curphy;
uec = (uec_private_t *)dev->priv; uec = (uec_private_t *)dev->priv;
if (uec->the_first_run == 0) { if (uec->the_first_run == 0) {
/* Set up the MAC address */ err = init_phy(dev);
if (dev->enetaddr[0] & 0x01) { if (err) {
printf("%s: MacAddress is multcast address\n", printf("%s: Cannot initialize PHY, aborting.\n",
__FUNCTION__); dev->name);
return -1; return err;
} }
uec_set_mac_address(uec, dev->enetaddr);
curphy = uec->mii_info->phyinfo;
if (curphy->config_aneg) {
err = curphy->config_aneg(uec->mii_info);
if (err) {
printf("%s: Can't negotiate PHY\n", dev->name);
return err;
}
}
/* Give PHYs up to 5 sec to report a link */
i = 50;
do {
err = curphy->read_status(uec->mii_info);
udelay(100000);
} while (((i-- > 0) && !uec->mii_info->link) || err);
if (err || i <= 0)
printf("warning: %s: timeout on PHY link\n", dev->name);
uec->the_first_run = 1; uec->the_first_run = 1;
} }
/* Set up the MAC address */
if (dev->enetaddr[0] & 0x01) {
printf("%s: MacAddress is multcast address\n",
__FUNCTION__);
return -1;
}
uec_set_mac_address(uec, dev->enetaddr);
err = uec_open(uec, COMM_DIR_RX_AND_TX); err = uec_open(uec, COMM_DIR_RX_AND_TX);
if (err) { if (err) {
printf("%s: cannot enable UEC device\n", dev->name); printf("%s: cannot enable UEC device\n", dev->name);
return -1; return -1;
} }
phy_change(dev);
return (uec->mii_info->link ? 0 : -1); return (uec->mii_info->link ? 0 : -1);
} }
@ -1261,6 +1323,10 @@ int uec_initialize(int index)
} else if (index == 2) { } else if (index == 2) {
#ifdef CONFIG_UEC_ETH3 #ifdef CONFIG_UEC_ETH3
uec_info = &eth3_uec_info; uec_info = &eth3_uec_info;
#endif
} else if (index == 3) {
#ifdef CONFIG_UEC_ETH4
uec_info = &eth4_uec_info;
#endif #endif
} else { } else {
printf("%s: index is illegal.\n", __FUNCTION__); printf("%s: index is illegal.\n", __FUNCTION__);
@ -1289,14 +1355,6 @@ int uec_initialize(int index)
return err; return err;
} }
err = init_phy(dev);
if (err) {
printf("%s: Cannot initialize PHY, aborting.\n", dev->name);
return err;
}
phy_change(dev);
return 1; return 1;
} }
#endif /* CONFIG_QE */ #endif /* CONFIG_QE */

View file

@ -28,7 +28,6 @@
#if defined(CONFIG_QE) #if defined(CONFIG_QE)
#define UEC_VERBOSE_DEBUG
#define ugphy_printk(format, arg...) \ #define ugphy_printk(format, arg...) \
printf(format "\n", ## arg) printf(format "\n", ## arg)
@ -77,11 +76,10 @@ void uec_write_phy_reg (struct eth_device *dev, int mii_id, int regnum, int valu
/* Setting up the MII Mangement Control Register with the value */ /* Setting up the MII Mangement Control Register with the value */
out_be32 (&ug_regs->miimcon, (u32) value); out_be32 (&ug_regs->miimcon, (u32) value);
sync();
/* Wait till MII management write is complete */ /* Wait till MII management write is complete */
while ((in_be32 (&ug_regs->miimind)) & MIIMIND_BUSY); while ((in_be32 (&ug_regs->miimind)) & MIIMIND_BUSY);
udelay (100000);
} }
/* Reads from register regnum in the PHY for device dev, */ /* Reads from register regnum in the PHY for device dev, */
@ -101,20 +99,21 @@ int uec_read_phy_reg (struct eth_device *dev, int mii_id, int regnum)
tmp_reg = ((u32) mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | mii_reg; tmp_reg = ((u32) mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | mii_reg;
out_be32 (&ug_regs->miimadd, tmp_reg); out_be32 (&ug_regs->miimadd, tmp_reg);
/* Perform an MII management read cycle */ /* clear MII management command cycle */
out_be32 (&ug_regs->miimcom, 0); out_be32 (&ug_regs->miimcom, 0);
sync();
/* Perform an MII management read cycle */
out_be32 (&ug_regs->miimcom, MIIMCOM_READ_CYCLE); out_be32 (&ug_regs->miimcom, MIIMCOM_READ_CYCLE);
/* Wait till MII management write is complete */ /* Wait till MII management write is complete */
while ((in_be32 (&ug_regs->miimind)) & while ((in_be32 (&ug_regs->miimind)) &
(MIIMIND_NOT_VALID | MIIMIND_BUSY)); (MIIMIND_NOT_VALID | MIIMIND_BUSY));
udelay (100000);
/* Read MII management status */ /* Read MII management status */
value = (u16) in_be32 (&ug_regs->miimstat); value = (u16) in_be32 (&ug_regs->miimstat);
if (value == 0xffff) if (value == 0xffff)
ugphy_warn ugphy_vdbg
("read wrong value : mii_id %d,mii_reg %d, base %08x", ("read wrong value : mii_id %d,mii_reg %d, base %08x",
mii_id, mii_reg, (u32) & (ug_regs->miimcfg)); mii_id, mii_reg, (u32) & (ug_regs->miimcfg));
@ -270,20 +269,38 @@ static int genmii_update_link (struct uec_mii_info *mii_info)
{ {
u16 status; u16 status;
/* Do a fake read */ /* Status is read once to clear old link state */
phy_read (mii_info, PHY_BMSR); phy_read (mii_info, PHY_BMSR);
/* Read link and autonegotiation status */ /*
status = phy_read (mii_info, PHY_BMSR); * Wait if the link is up, and autonegotiation is in progress
if ((status & PHY_BMSR_LS) == 0) * (ie - we're capable and it's not done)
mii_info->link = 0; */
else status = phy_read(mii_info, PHY_BMSR);
mii_info->link = 1; if ((status & PHY_BMSR_LS) && (status & PHY_BMSR_AUTN_ABLE)
&& !(status & PHY_BMSR_AUTN_COMP)) {
int i = 0;
/* If we are autonegotiating, and not done, while (!(status & PHY_BMSR_AUTN_COMP)) {
* return an error */ /*
if (mii_info->autoneg && !(status & PHY_BMSR_AUTN_COMP)) * Timeout reached ?
return -EAGAIN; */
if (i > UGETH_AN_TIMEOUT) {
mii_info->link = 0;
return 0;
}
udelay(1000); /* 1 ms */
status = phy_read(mii_info, PHY_BMSR);
}
mii_info->link = 1;
udelay(500000); /* another 500 ms (results in faster booting) */
} else {
if (status & PHY_BMSR_LS)
mii_info->link = 1;
else
mii_info->link = 0;
}
return 0; return 0;
} }
@ -389,16 +406,12 @@ static int dm9161_init (struct uec_mii_info *mii_info)
/* PHY and MAC connect */ /* PHY and MAC connect */
phy_write (mii_info, PHY_BMCR, phy_read (mii_info, PHY_BMCR) & phy_write (mii_info, PHY_BMCR, phy_read (mii_info, PHY_BMCR) &
~PHY_BMCR_ISO); ~PHY_BMCR_ISO);
#ifdef CONFIG_RMII_MODE
phy_write (mii_info, MII_DM9161_SCR, MII_DM9161_SCR_RMII_INIT);
#else
phy_write (mii_info, MII_DM9161_SCR, MII_DM9161_SCR_INIT); phy_write (mii_info, MII_DM9161_SCR, MII_DM9161_SCR_INIT);
#endif
config_genmii_advert (mii_info); config_genmii_advert (mii_info);
/* Start/restart aneg */ /* Start/restart aneg */
genmii_config_aneg (mii_info); genmii_config_aneg (mii_info);
/* Delay to wait the aneg compeleted */
udelay (3000000);
return 0; return 0;
} }

View file

@ -217,6 +217,9 @@ int eth_initialize(bd_t *bis)
#if defined(CONFIG_UEC_ETH3) #if defined(CONFIG_UEC_ETH3)
uec_initialize(2); uec_initialize(2);
#endif #endif
#if defined(CONFIG_UEC_ETH4)
uec_initialize(3);
#endif
#if defined(FEC_ENET) || defined(CONFIG_ETHER_ON_FCC) #if defined(FEC_ENET) || defined(CONFIG_ETHER_ON_FCC)
fec_initialize(bis); fec_initialize(bis);
@ -522,6 +525,15 @@ int eth_receive(volatile void *packet, int length)
void eth_try_another(int first_restart) void eth_try_another(int first_restart)
{ {
static struct eth_device *first_failed = NULL; static struct eth_device *first_failed = NULL;
char *ethrotate;
/*
* Do not rotate between network interfaces when
* 'ethrotate' variable is set to 'no'.
*/
if (((ethrotate = getenv ("ethrotate")) != NULL) &&
(strcmp(ethrotate, "no") == 0))
return;
if (!eth_current) if (!eth_current)
return; return;