@ -17,7 +17,75 @@
# include <asm/io.h>
# include "designware.h"
static int configure_phy ( struct eth_device * dev ) ;
# if !defined(CONFIG_PHYLIB)
# error "DesignWare Ether MAC requires PHYLIB - missing CONFIG_PHYLIB"
# endif
static int dw_mdio_read ( struct mii_dev * bus , int addr , int devad , int reg )
{
struct eth_mac_regs * mac_p = bus - > priv ;
ulong start ;
u16 miiaddr ;
int timeout = CONFIG_MDIO_TIMEOUT ;
miiaddr = ( ( addr < < MIIADDRSHIFT ) & MII_ADDRMSK ) |
( ( reg < < MIIREGSHIFT ) & MII_REGMSK ) ;
writel ( miiaddr | MII_CLKRANGE_150_250M | MII_BUSY , & mac_p - > miiaddr ) ;
start = get_timer ( 0 ) ;
while ( get_timer ( start ) < timeout ) {
if ( ! ( readl ( & mac_p - > miiaddr ) & MII_BUSY ) )
return readl ( & mac_p - > miidata ) ;
udelay ( 10 ) ;
} ;
return - 1 ;
}
static int dw_mdio_write ( struct mii_dev * bus , int addr , int devad , int reg ,
u16 val )
{
struct eth_mac_regs * mac_p = bus - > priv ;
ulong start ;
u16 miiaddr ;
int ret = - 1 , timeout = CONFIG_MDIO_TIMEOUT ;
writel ( val , & mac_p - > miidata ) ;
miiaddr = ( ( addr < < MIIADDRSHIFT ) & MII_ADDRMSK ) |
( ( reg < < MIIREGSHIFT ) & MII_REGMSK ) | MII_WRITE ;
writel ( miiaddr | MII_CLKRANGE_150_250M | MII_BUSY , & mac_p - > miiaddr ) ;
start = get_timer ( 0 ) ;
while ( get_timer ( start ) < timeout ) {
if ( ! ( readl ( & mac_p - > miiaddr ) & MII_BUSY ) ) {
ret = 0 ;
break ;
}
udelay ( 10 ) ;
} ;
return ret ;
}
static int dw_mdio_init ( char * name , struct eth_mac_regs * mac_regs_p )
{
struct mii_dev * bus = mdio_alloc ( ) ;
if ( ! bus ) {
printf ( " Failed to allocate MDIO bus \n " ) ;
return - 1 ;
}
bus - > read = dw_mdio_read ;
bus - > write = dw_mdio_write ;
sprintf ( bus - > name , name ) ;
bus - > priv = ( void * ) mac_regs_p ;
return mdio_register ( bus ) ;
}
static void tx_descs_init ( struct eth_device * dev )
{
@ -83,53 +151,59 @@ static void rx_descs_init(struct eth_device *dev)
priv - > rx_currdescnum = 0 ;
}
static void descs_init ( struct eth_device * dev )
static int dw_write_hwaddr ( struct eth_device * dev )
{
tx_descs_init ( dev ) ;
rx_descs_init ( dev ) ;
struct dw_eth_dev * priv = dev - > priv ;
struct eth_mac_regs * mac_p = priv - > mac_regs_p ;
u32 macid_lo , macid_hi ;
u8 * mac_id = & dev - > enetaddr [ 0 ] ;
macid_lo = mac_id [ 0 ] + ( mac_id [ 1 ] < < 8 ) + ( mac_id [ 2 ] < < 16 ) +
( mac_id [ 3 ] < < 24 ) ;
macid_hi = mac_id [ 4 ] + ( mac_id [ 5 ] < < 8 ) ;
writel ( macid_hi , & mac_p - > macaddr0hi ) ;
writel ( macid_lo , & mac_p - > macaddr0lo ) ;
return 0 ;
}
static int mac_reset ( struct eth_device * dev )
static void dw_adjust_link ( struct eth_mac_regs * mac_p ,
struct phy_device * phydev )
{
struct dw_eth_dev * priv = dev - > priv ;
struct eth_mac_regs * mac_p = priv - > mac_regs_p ;
struct eth_dma_regs * dma_p = priv - > dma_regs_p ;
u32 conf = readl ( & mac_p - > conf ) | FRAMEBURSTENABLE | DISABLERXOWN ;
ulong start ;
int timeout = CONFIG_MACRESET_TIMEOUT ;
if ( ! phydev - > link ) {
printf ( " %s: No link. \n " , phydev - > dev - > name ) ;
return ;
}
writel ( readl ( & dma_p - > busmode ) | DMAMAC_SRST , & dma_p - > busmode ) ;
if ( phydev - > speed ! = 1000 )
conf | = MII_PORTSELECT ;
if ( priv - > interface ! = PHY_INTERFACE_MODE_RGMII )
writel ( MII_PORTSELECT , & mac_p - > conf ) ;
if ( phydev - > speed = = 100 )
conf | = FES_100 ;
start = get_timer ( 0 ) ;
while ( get_timer ( start ) < timeout ) {
if ( ! ( readl ( & dma_p - > busmode ) & DMAMAC_SRST ) )
return 0 ;
if ( phydev - > duplex )
conf | = FULLDPLXMODE ;
/* Try again after 10usec */
udelay ( 10 ) ;
} ;
writel ( conf , & mac_p - > conf ) ;
return - 1 ;
printf ( " Speed: %d, %s duplex%s \n " , phydev - > speed ,
( phydev - > duplex ) ? " full " : " half " ,
( phydev - > port = = PORT_FIBRE ) ? " , fiber mode " : " " ) ;
}
static int dw_write_hwaddr ( struct eth_device * dev )
static void dw_eth_halt ( struct eth_device * dev )
{
struct dw_eth_dev * priv = dev - > priv ;
struct eth_mac_regs * mac_p = priv - > mac_regs_p ;
u32 macid_lo , macid_hi ;
u8 * mac_id = & dev - > enetaddr [ 0 ] ;
struct eth_dma_regs * dma_p = priv - > dma_regs_p ;
macid_lo = mac_id [ 0 ] + ( mac_id [ 1 ] < < 8 ) + \
( mac_id [ 2 ] < < 16 ) + ( mac_id [ 3 ] < < 24 ) ;
macid_hi = mac_id [ 4 ] + ( mac_id [ 5 ] < < 8 ) ;
writel ( readl ( & mac_p - > conf ) & ~ ( RXENABLE | TXENABLE ) , & mac_p - > conf ) ;
writel ( readl ( & dma_p - > opmode ) & ~ ( RXSTART | TXSTART ) , & dma_p - > opmode ) ;
writel ( macid_hi , & mac_p - > macaddr0hi ) ;
writel ( macid_lo , & mac_p - > macaddr0lo ) ;
return 0 ;
phy_shutdown ( priv - > phydev ) ;
}
static int dw_eth_init ( struct eth_device * dev , bd_t * bis )
@ -137,55 +211,43 @@ static int dw_eth_init(struct eth_device *dev, bd_t *bis)
struct dw_eth_dev * priv = dev - > priv ;
struct eth_mac_regs * mac_p = priv - > mac_regs_p ;
struct eth_dma_regs * dma_p = priv - > dma_regs_p ;
u32 conf ;
unsigned int start ;
if ( priv - > phy_configured ! = 1 )
configure_phy ( dev ) ;
writel ( readl ( & dma_p - > busmode ) | DMAMAC_SRST , & dma_p - > busmode ) ;
/* Print link status only once */
if ( ! priv - > link_printed ) {
printf ( " ENET Speed is %d Mbps - %s duplex connection \n " ,
priv - > speed , ( priv - > duplex = = HALF ) ? " HALF " : " FULL " ) ;
priv - > link_printed = 1 ;
}
start = get_timer ( 0 ) ;
while ( readl ( & dma_p - > busmode ) & DMAMAC_SRST ) {
if ( get_timer ( start ) > = CONFIG_MACRESET_TIMEOUT )
return - 1 ;
/* Reset ethernet hardware */
if ( mac_reset ( dev ) < 0 )
return - 1 ;
mdelay ( 100 ) ;
} ;
/* Resore the HW MAC address as it has been lost during MAC reset */
/* Soft reset above clears HW address registers.
* So we have to set it here once again */
dw_write_hwaddr ( dev ) ;
writel ( FIXEDBURST | PRIORXTX_41 | BURST_16 ,
& dma_p - > busmode ) ;
writel ( readl ( & dma_p - > opmode ) | FLUSHTXFIFO | STOREFORWARD |
TXSECONDFRAME , & dma_p - > opmode ) ;
rx_descs_init ( dev ) ;
tx_descs_init ( dev ) ;
conf = FRAMEBURSTENABLE | DISABLERXOWN ;
writel ( FIXEDBURST | PRIORXTX_41 | BURST_16 , & dma_p - > busmode ) ;
if ( priv - > speed ! = 1000 )
conf | = MII_PORTSELECT ;
writel ( readl ( & dma_p - > opmode ) | FLUSHTXFIFO | STOREFORWARD ,
& dma_p - > opmode ) ;
if ( ( priv - > interface ! = PHY_INTERFACE_MODE_MII ) & &
( priv - > interface ! = PHY_INTERFACE_MODE_GMII ) ) {
writel ( readl ( & dma_p - > opmode ) | RXSTART | TXSTART , & dma_p - > opmode ) ;
if ( priv - > speed = = 100 )
conf | = FES_100 ;
/* Start up the PHY */
if ( phy_startup ( priv - > phydev ) ) {
printf ( " Could not initialize PHY %s \n " ,
priv - > phydev - > dev - > name ) ;
return - 1 ;
}
if ( priv - > duplex = = FULL )
conf | = FULLDPLXMODE ;
writel ( conf , & mac_p - > conf ) ;
dw_adjust_link ( mac_p , priv - > phydev ) ;
descs_init ( dev ) ;
/*
* Start / Enable xfer at dma as well as mac level
*/
writel ( readl ( & dma_p - > opmode ) | RXSTART , & dma_p - > opmode ) ;
writel ( readl ( & dma_p - > opmode ) | TXSTART , & dma_p - > opmode ) ;
if ( ! priv - > phydev - > link )
return - 1 ;
writel ( readl ( & mac_p - > conf ) | RXENABLE | TXENABLE , & mac_p - > conf ) ;
@ -267,251 +329,30 @@ static int dw_eth_recv(struct eth_device *dev)
return length ;
}
static void dw_eth_halt ( struct eth_device * dev )
{
struct dw_eth_dev * priv = dev - > priv ;
mac_reset ( dev ) ;
priv - > tx_currdescnum = priv - > rx_currdescnum = 0 ;
}
static int eth_mdio_read ( struct eth_device * dev , u8 addr , u8 reg , u16 * val )
static int dw_phy_init ( struct eth_device * dev )
{
struct dw_eth_dev * priv = dev - > priv ;
struct eth_mac_regs * mac_p = priv - > mac_regs_p ;
ulong start ;
u32 miiaddr ;
int timeout = CONFIG_MDIO_TIMEOUT ;
miiaddr = ( ( addr < < MIIADDRSHIFT ) & MII_ADDRMSK ) | \
( ( reg < < MIIREGSHIFT ) & MII_REGMSK ) ;
writel ( miiaddr | MII_CLKRANGE_150_250M | MII_BUSY , & mac_p - > miiaddr ) ;
start = get_timer ( 0 ) ;
while ( get_timer ( start ) < timeout ) {
if ( ! ( readl ( & mac_p - > miiaddr ) & MII_BUSY ) ) {
* val = readl ( & mac_p - > miidata ) ;
return 0 ;
}
struct phy_device * phydev ;
int mask = 0xffffffff ;
/* Try again after 10usec */
udelay ( 10 ) ;
} ;
return - 1 ;
}
static int eth_mdio_write ( struct eth_device * dev , u8 addr , u8 reg , u16 val )
{
struct dw_eth_dev * priv = dev - > priv ;
struct eth_mac_regs * mac_p = priv - > mac_regs_p ;
ulong start ;
u32 miiaddr ;
int ret = - 1 , timeout = CONFIG_MDIO_TIMEOUT ;
u16 value ;
writel ( val , & mac_p - > miidata ) ;
miiaddr = ( ( addr < < MIIADDRSHIFT ) & MII_ADDRMSK ) | \
( ( reg < < MIIREGSHIFT ) & MII_REGMSK ) | MII_WRITE ;
writel ( miiaddr | MII_CLKRANGE_150_250M | MII_BUSY , & mac_p - > miiaddr ) ;
start = get_timer ( 0 ) ;
while ( get_timer ( start ) < timeout ) {
if ( ! ( readl ( & mac_p - > miiaddr ) & MII_BUSY ) ) {
ret = 0 ;
break ;
}
/* Try again after 10usec */
udelay ( 10 ) ;
} ;
/* Needed as a fix for ST-Phy */
eth_mdio_read ( dev , addr , reg , & value ) ;
return ret ;
}
# if defined(CONFIG_DW_SEARCH_PHY)
static int find_phy ( struct eth_device * dev )
{
int phy_addr = 0 ;
u16 ctrl , oldctrl ;
do {
eth_mdio_read ( dev , phy_addr , MII_BMCR , & ctrl ) ;
oldctrl = ctrl & BMCR_ANENABLE ;
ctrl ^ = BMCR_ANENABLE ;
eth_mdio_write ( dev , phy_addr , MII_BMCR , ctrl ) ;
eth_mdio_read ( dev , phy_addr , MII_BMCR , & ctrl ) ;
ctrl & = BMCR_ANENABLE ;
if ( ctrl = = oldctrl ) {
phy_addr + + ;
} else {
ctrl ^ = BMCR_ANENABLE ;
eth_mdio_write ( dev , phy_addr , MII_BMCR , ctrl ) ;
return phy_addr ;
}
} while ( phy_addr < 32 ) ;
return - 1 ;
}
# ifdef CONFIG_PHY_ADDR
mask = 1 < < CONFIG_PHY_ADDR ;
# endif
static int dw_reset_phy ( struct eth_device * dev )
{
struct dw_eth_dev * priv = dev - > priv ;
u16 ctrl ;
ulong start ;
int timeout = CONFIG_PHYRESET_TIMEOUT ;
u32 phy_addr = priv - > address ;
eth_mdio_write ( dev , phy_addr , MII_BMCR , BMCR_RESET ) ;
start = get_timer ( 0 ) ;
while ( get_timer ( start ) < timeout ) {
eth_mdio_read ( dev , phy_addr , MII_BMCR , & ctrl ) ;
if ( ! ( ctrl & BMCR_RESET ) )
break ;
/* Try again after 10usec */
udelay ( 10 ) ;
} ;
if ( get_timer ( start ) > = CONFIG_PHYRESET_TIMEOUT )
phydev = phy_find_by_mask ( priv - > bus , mask , priv - > interface ) ;
if ( ! phydev )
return - 1 ;
# ifdef CONFIG_PHY_RESET_DELAY
udelay ( CONFIG_PHY_RESET_DELAY ) ;
# endif
return 0 ;
}
phydev - > supported & = PHY_GBIT_FEATURES ;
phydev - > advertising = phydev - > supported ;
/*
* Add weak default function for board specific PHY configuration
*/
int __weak designware_board_phy_init ( struct eth_device * dev , int phy_addr ,
int ( * mii_write ) ( struct eth_device * , u8 , u8 , u16 ) ,
int dw_reset_phy ( struct eth_device * ) )
{
return 0 ;
}
priv - > phydev = phydev ;
phy_config ( phydev ) ;
static int configure_phy ( struct eth_device * dev )
{
struct dw_eth_dev * priv = dev - > priv ;
int phy_addr ;
u16 bmcr ;
# if defined(CONFIG_DW_AUTONEG)
u16 bmsr ;
u32 timeout ;
ulong start ;
# endif
# if defined(CONFIG_DW_SEARCH_PHY)
phy_addr = find_phy ( dev ) ;
if ( phy_addr > = 0 )
priv - > address = phy_addr ;
else
return - 1 ;
# else
phy_addr = priv - > address ;
# endif
/*
* Some boards need board specific PHY initialization . This is
* after the main driver init code but before the auto negotiation
* is run .
*/
if ( designware_board_phy_init ( dev , phy_addr ,
eth_mdio_write , dw_reset_phy ) < 0 )
return - 1 ;
if ( dw_reset_phy ( dev ) < 0 )
return - 1 ;
# if defined(CONFIG_DW_AUTONEG)
/* Set Auto-Neg Advertisement capabilities to 10/100 half/full */
eth_mdio_write ( dev , phy_addr , MII_ADVERTISE , 0x1E1 ) ;
bmcr = BMCR_ANENABLE | BMCR_ANRESTART ;
# else
bmcr = BMCR_SPEED100 | BMCR_FULLDPLX ;
# if defined(CONFIG_DW_SPEED10M)
bmcr & = ~ BMCR_SPEED100 ;
# endif
# if defined(CONFIG_DW_DUPLEXHALF)
bmcr & = ~ BMCR_FULLDPLX ;
# endif
# endif
if ( eth_mdio_write ( dev , phy_addr , MII_BMCR , bmcr ) < 0 )
return - 1 ;
/* Read the phy status register and populate priv structure */
# if defined(CONFIG_DW_AUTONEG)
timeout = CONFIG_AUTONEG_TIMEOUT ;
start = get_timer ( 0 ) ;
puts ( " Waiting for PHY auto negotiation to complete " ) ;
while ( get_timer ( start ) < timeout ) {
eth_mdio_read ( dev , phy_addr , MII_BMSR , & bmsr ) ;
if ( bmsr & BMSR_ANEGCOMPLETE ) {
priv - > phy_configured = 1 ;
break ;
}
/* Print dot all 1s to show progress */
if ( ( get_timer ( start ) % 1000 ) = = 0 )
putc ( ' . ' ) ;
/* Try again after 1msec */
udelay ( 1000 ) ;
} ;
if ( ! ( bmsr & BMSR_ANEGCOMPLETE ) )
puts ( " TIMEOUT! \n " ) ;
else
puts ( " done \n " ) ;
# else
priv - > phy_configured = 1 ;
# endif
priv - > speed = miiphy_speed ( dev - > name , phy_addr ) ;
priv - > duplex = miiphy_duplex ( dev - > name , phy_addr ) ;
return 0 ;
}
# if defined(CONFIG_MII)
static int dw_mii_read ( const char * devname , u8 addr , u8 reg , u16 * val )
{
struct eth_device * dev ;
dev = eth_get_dev_by_name ( devname ) ;
if ( dev )
eth_mdio_read ( dev , addr , reg , val ) ;
return 0 ;
}
static int dw_mii_write ( const char * devname , u8 addr , u8 reg , u16 val )
{
struct eth_device * dev ;
dev = eth_get_dev_by_name ( devname ) ;
if ( dev )
eth_mdio_write ( dev , addr , reg , val ) ;
return 0 ;
return 1 ;
}
# endif
int designware_initialize ( u32 id , u long base_addr , u32 phy _addr , u32 interface )
int designware_initialize ( ulong base_addr , u32 interface )
{
struct eth_device * dev ;
struct dw_eth_dev * priv ;
@ -533,19 +374,14 @@ int designware_initialize(u32 id, ulong base_addr, u32 phy_addr, u32 interface)
memset ( dev , 0 , sizeof ( struct eth_device ) ) ;
memset ( priv , 0 , sizeof ( struct dw_eth_dev ) ) ;
sprintf ( dev - > name , " mii%d " , id ) ;
sprintf ( dev - > name , " dwmac.%lx " , base_addr ) ;
dev - > iobase = ( int ) base_addr ;
dev - > priv = priv ;
eth_getenv_enetaddr_by_index ( " eth " , id , & dev - > enetaddr [ 0 ] ) ;
priv - > dev = dev ;
priv - > mac_regs_p = ( struct eth_mac_regs * ) base_addr ;
priv - > dma_regs_p = ( struct eth_dma_regs * ) ( base_addr +
DW_DMA_BASE_OFFSET ) ;
priv - > address = phy_addr ;
priv - > phy_configured = 0 ;
priv - > interface = interface ;
dev - > init = dw_eth_init ;
dev - > send = dw_eth_send ;
@ -555,8 +391,10 @@ int designware_initialize(u32 id, ulong base_addr, u32 phy_addr, u32 interface)
eth_register ( dev ) ;
# if defined(CONFIG_MII)
miiphy_register ( dev - > name , dw_mii_read , dw_mii_write ) ;
# endif
return 1 ;
priv - > interface = interface ;
dw_mdio_init ( dev - > name , priv - > mac_regs_p ) ;
priv - > bus = miiphy_get_dev_by_name ( dev - > name ) ;
return dw_phy_init ( dev ) ;
}