@ -12,6 +12,7 @@
*/
# include <common.h>
# include <dm.h>
# include <net.h>
# include <malloc.h>
# include <miiphy.h>
@ -127,8 +128,12 @@ static int __mvgbe_mdio_read(struct mvgbe_device *dmvgbe, int phy_adr,
static int smi_reg_read ( struct mii_dev * bus , int phy_adr , int devad ,
int reg_ofs )
{
# ifdef CONFIG_DM_ETH
struct mvgbe_device * dmvgbe = bus - > priv ;
# else
struct eth_device * dev = eth_get_dev_by_name ( bus - > name ) ;
struct mvgbe_device * dmvgbe = to_mvgbe ( dev ) ;
# endif
return __mvgbe_mdio_read ( dmvgbe , phy_adr , devad , reg_ofs ) ;
}
@ -180,8 +185,12 @@ static int __mvgbe_mdio_write(struct mvgbe_device *dmvgbe, int phy_adr,
static int smi_reg_write ( struct mii_dev * bus , int phy_adr , int devad ,
int reg_ofs , u16 data )
{
# ifdef CONFIG_DM_ETH
struct mvgbe_device * dmvgbe = bus - > priv ;
# else
struct eth_device * dev = eth_get_dev_by_name ( bus - > name ) ;
struct mvgbe_device * dmvgbe = to_mvgbe ( dev ) ;
# endif
return __mvgbe_mdio_write ( dmvgbe , phy_adr , devad , reg_ofs , data ) ;
}
@ -415,11 +424,13 @@ static void mvgbe_init_rx_desc_ring(struct mvgbe_device *dmvgbe)
dmvgbe - > p_rxdesc_curr = dmvgbe - > p_rxdesc ;
}
static int __mvgbe_init ( struct mvgbe_device * dmvgbe )
static int __mvgbe_init ( struct mvgbe_device * dmvgbe , u8 * enetaddr ,
const char * name )
{
struct mvgbe_registers * regs = dmvgbe - > regs ;
# if (defined(CONFIG_MII) || defined(CONFIG_CMD_MII)) && \
! defined ( CONFIG_PHYLIB ) & & \
! defined ( CONFIG_DM_ETH ) & & \
defined ( CONFIG_SYS_FAULT_ECHO_LINK_DOWN )
int i ;
# endif
@ -436,7 +447,7 @@ static int __mvgbe_init(struct mvgbe_device *dmvgbe)
set_dram_access ( regs ) ;
port_init_mac_tables ( regs ) ;
port_uc_addr_set ( dmvgbe , dmvgbe - > dev . enetaddr ) ;
port_uc_addr_set ( dmvgbe , enetaddr ) ;
/* Assign port configuration and command. */
MVGBE_REG_WR ( regs - > pxc , PRT_CFG_VAL ) ;
@ -473,31 +484,34 @@ static int __mvgbe_init(struct mvgbe_device *dmvgbe)
# if (defined(CONFIG_MII) || defined(CONFIG_CMD_MII)) && \
! defined ( CONFIG_PHYLIB ) & & \
! defined ( CONFIG_DM_ETH ) & & \
defined ( CONFIG_SYS_FAULT_ECHO_LINK_DOWN )
/* Wait up to 5s for the link status */
for ( i = 0 ; i < 5 ; i + + ) {
u16 phyadr ;
miiphy_read ( dmvgbe - > dev . name , MV_PHY_ADR_REQUEST ,
miiphy_read ( name , MV_PHY_ADR_REQUEST ,
MV_PHY_ADR_REQUEST , & phyadr ) ;
/* Return if we get link up */
if ( miiphy_link ( dmvgbe - > dev . name , phyadr ) )
if ( miiphy_link ( name , phyadr ) )
return 0 ;
udelay ( 1000000 ) ;
}
printf ( " No link on %s \n " , dmvgbe - > dev . name ) ;
printf ( " No link on %s \n " , name ) ;
return - 1 ;
# endif
return 0 ;
}
# ifndef CONFIG_DM_ETH
static int mvgbe_init ( struct eth_device * dev )
{
struct mvgbe_device * dmvgbe = to_mvgbe ( dev ) ;
return __mvgbe_init ( dmvgbe ) ;
return __mvgbe_init ( dmvgbe , dmvgbe - > dev . enetaddr , dmvgbe - > dev . name ) ;
}
# endif
static void __mvgbe_halt ( struct mvgbe_device * dmvgbe )
{
@ -524,6 +538,7 @@ static void __mvgbe_halt(struct mvgbe_device *dmvgbe)
MVGBE_REG_WR ( regs - > peim , 0 ) ;
}
# ifndef CONFIG_DM_ETH
static int mvgbe_halt ( struct eth_device * dev )
{
struct mvgbe_device * dmvgbe = to_mvgbe ( dev ) ;
@ -532,7 +547,18 @@ static int mvgbe_halt(struct eth_device *dev)
return 0 ;
}
# endif
# ifdef CONFIG_DM_ETH
static int mvgbe_write_hwaddr ( struct udevice * dev )
{
struct eth_pdata * pdata = dev_get_platdata ( dev ) ;
port_uc_addr_set ( dev_get_priv ( dev ) , pdata - > enetaddr ) ;
return 0 ;
}
# else
static int mvgbe_write_hwaddr ( struct eth_device * dev )
{
struct mvgbe_device * dmvgbe = to_mvgbe ( dev ) ;
@ -541,6 +567,7 @@ static int mvgbe_write_hwaddr(struct eth_device *dev)
port_uc_addr_set ( dmvgbe , dmvgbe - > dev . enetaddr ) ;
return 0 ;
}
# endif
static int __mvgbe_send ( struct mvgbe_device * dmvgbe , void * dataptr ,
int datasize )
@ -597,12 +624,14 @@ static int __mvgbe_send(struct mvgbe_device *dmvgbe, void *dataptr,
return 0 ;
}
# ifndef CONFIG_DM_ETH
static int mvgbe_send ( struct eth_device * dev , void * dataptr , int datasize )
{
struct mvgbe_device * dmvgbe = to_mvgbe ( dev ) ;
return __mvgbe_send ( dmvgbe , dataptr , datasize ) ;
}
# endif
static int __mvgbe_recv ( struct mvgbe_device * dmvgbe , uchar * * packetp )
{
@ -677,6 +706,7 @@ static int __mvgbe_recv(struct mvgbe_device *dmvgbe, uchar **packetp)
return rx_bytes ;
}
# ifndef CONFIG_DM_ETH
static int mvgbe_recv ( struct eth_device * dev )
{
struct mvgbe_device * dmvgbe = to_mvgbe ( dev ) ;
@ -691,8 +721,41 @@ static int mvgbe_recv(struct eth_device *dev)
return 0 ;
}
# endif
# if defined(CONFIG_PHYLIB)
# if defined(CONFIG_PHYLIB) || defined(CONFIG_DM_ETH)
# if defined(CONFIG_DM_ETH)
static struct phy_device * __mvgbe_phy_init ( struct udevice * dev ,
struct mii_dev * bus ,
phy_interface_t phy_interface ,
int phyid )
# else
static struct phy_device * __mvgbe_phy_init ( struct eth_device * dev ,
struct mii_dev * bus ,
phy_interface_t phy_interface ,
int phyid )
# endif
{
struct phy_device * phydev ;
/* Set phy address of the port */
miiphy_write ( dev - > name , MV_PHY_ADR_REQUEST , MV_PHY_ADR_REQUEST ,
phyid ) ;
phydev = phy_connect ( bus , phyid , dev , phy_interface ) ;
if ( ! phydev ) {
printf ( " phy_connect failed \n " ) ;
return NULL ;
}
phy_config ( phydev ) ;
phy_startup ( phydev ) ;
return phydev ;
}
# endif /* CONFIG_PHYLIB || CONFIG_DM_ETH */
# if defined(CONFIG_PHYLIB) && !defined(CONFIG_DM_ETH)
int mvgbe_phylib_init ( struct eth_device * dev , int phyid )
{
struct mii_dev * bus ;
@ -715,27 +778,53 @@ int mvgbe_phylib_init(struct eth_device *dev, int phyid)
return - ENOMEM ;
}
/* Set phy address of the port */
smi_reg_write ( bus , MV_PHY_ADR_REQUEST , 0 , MV_PHY_ADR_REQUEST , phyid ) ;
phydev = phy_connect ( bus , phyid , dev , PHY_INTERFACE_MODE_RGMII ) ;
if ( ! phydev ) {
printf ( " phy_connect failed \n " ) ;
phydev = __mvgbe_phy_init ( dev , bus , PHY_INTERFACE_MODE_RGMII , phyid ) ;
if ( ! phydev )
return - ENODEV ;
}
phy_config ( phydev ) ;
phy_startup ( phydev ) ;
return 0 ;
}
# endif
static int mvgbe_alloc_buffers ( struct mvgbe_device * dmvgbe )
{
dmvgbe - > p_rxdesc = memalign ( PKTALIGN ,
MV_RXQ_DESC_ALIGNED_SIZE * RINGSZ + 1 ) ;
if ( ! dmvgbe - > p_rxdesc )
goto error1 ;
dmvgbe - > p_rxbuf = memalign ( PKTALIGN ,
RINGSZ * PKTSIZE_ALIGN + 1 ) ;
if ( ! dmvgbe - > p_rxbuf )
goto error2 ;
dmvgbe - > p_aligned_txbuf = memalign ( 8 , PKTSIZE_ALIGN ) ;
if ( ! dmvgbe - > p_aligned_txbuf )
goto error3 ;
dmvgbe - > p_txdesc = memalign ( PKTALIGN , sizeof ( struct mvgbe_txdesc ) + 1 ) ;
if ( ! dmvgbe - > p_txdesc )
goto error4 ;
return 0 ;
error4 :
free ( dmvgbe - > p_aligned_txbuf ) ;
error3 :
free ( dmvgbe - > p_rxbuf ) ;
error2 :
free ( dmvgbe - > p_rxdesc ) ;
error1 :
return - ENOMEM ;
}
# ifndef CONFIG_DM_ETH
int mvgbe_initialize ( bd_t * bis )
{
struct mvgbe_device * dmvgbe ;
struct eth_device * dev ;
int devnum ;
int ret ;
u8 used_ports [ MAX_MVGBE_DEVS ] = CONFIG_MVGBE_PORTS ;
for ( devnum = 0 ; devnum < MAX_MVGBE_DEVS ; devnum + + ) {
@ -744,45 +833,16 @@ int mvgbe_initialize(bd_t *bis)
continue ;
dmvgbe = malloc ( sizeof ( struct mvgbe_device ) ) ;
if ( ! dmvgbe )
goto error1 ;
return - ENOMEM ;
memset ( dmvgbe , 0 , sizeof ( struct mvgbe_device ) ) ;
dmvgbe - > p_rxdesc =
( struct mvgbe_rxdesc * ) memalign ( PKTALIGN ,
MV_RXQ_DESC_ALIGNED_SIZE * RINGSZ + 1 ) ;
if ( ! dmvgbe - > p_rxdesc )
goto error2 ;
dmvgbe - > p_rxbuf = ( u8 * ) memalign ( PKTALIGN ,
RINGSZ * PKTSIZE_ALIGN + 1 ) ;
if ( ! dmvgbe - > p_rxbuf )
goto error3 ;
dmvgbe - > p_aligned_txbuf = memalign ( 8 , PKTSIZE_ALIGN ) ;
if ( ! dmvgbe - > p_aligned_txbuf )
goto error4 ;
dmvgbe - > p_txdesc = ( struct mvgbe_txdesc * ) memalign (
PKTALIGN , sizeof ( struct mvgbe_txdesc ) + 1 ) ;
if ( ! dmvgbe - > p_txdesc ) {
free ( dmvgbe - > p_aligned_txbuf ) ;
error4 :
free ( dmvgbe - > p_rxbuf ) ;
error3 :
free ( dmvgbe - > p_rxdesc ) ;
error2 :
free ( dmvgbe ) ;
error1 :
ret = mvgbe_alloc_buffers ( dmvgbe ) ;
if ( ret ) {
printf ( " Err.. %s Failed to allocate memory \n " ,
__func__ ) ;
return - 1 ;
free ( dmvgbe ) ;
return ret ;
}
dev = & dmvgbe - > dev ;
@ -834,3 +894,154 @@ error1:
}
return 0 ;
}
# endif
# ifdef CONFIG_DM_ETH
static int mvgbe_port_is_fixed_link ( struct mvgbe_device * dmvgbe )
{
return dmvgbe - > phyaddr > PHY_MAX_ADDR ;
}
static int mvgbe_start ( struct udevice * dev )
{
struct eth_pdata * pdata = dev_get_platdata ( dev ) ;
struct mvgbe_device * dmvgbe = dev_get_priv ( dev ) ;
int ret ;
ret = __mvgbe_init ( dmvgbe , pdata - > enetaddr , dev - > name ) ;
if ( ret )
return ret ;
if ( ! mvgbe_port_is_fixed_link ( dmvgbe ) ) {
dmvgbe - > phydev = __mvgbe_phy_init ( dev , dmvgbe - > bus ,
dmvgbe - > phy_interface ,
dmvgbe - > phyaddr ) ;
if ( ! dmvgbe - > phydev )
return - ENODEV ;
}
return 0 ;
}
static int mvgbe_send ( struct udevice * dev , void * packet , int length )
{
struct mvgbe_device * dmvgbe = dev_get_priv ( dev ) ;
return __mvgbe_send ( dmvgbe , packet , length ) ;
}
static int mvgbe_recv ( struct udevice * dev , int flags , uchar * * packetp )
{
struct mvgbe_device * dmvgbe = dev_get_priv ( dev ) ;
return __mvgbe_recv ( dmvgbe , packetp ) ;
}
static void mvgbe_stop ( struct udevice * dev )
{
struct mvgbe_device * dmvgbe = dev_get_priv ( dev ) ;
__mvgbe_halt ( dmvgbe ) ;
}
static int mvgbe_probe ( struct udevice * dev )
{
struct eth_pdata * pdata = dev_get_platdata ( dev ) ;
struct mvgbe_device * dmvgbe = dev_get_priv ( dev ) ;
struct mii_dev * bus ;
int ret ;
ret = mvgbe_alloc_buffers ( dmvgbe ) ;
if ( ret )
return ret ;
dmvgbe - > regs = ( void __iomem * ) pdata - > iobase ;
bus = mdio_alloc ( ) ;
if ( ! bus ) {
printf ( " Failed to allocate MDIO bus \n " ) ;
return - ENOMEM ;
}
bus - > read = smi_reg_read ;
bus - > write = smi_reg_write ;
snprintf ( bus - > name , sizeof ( bus - > name ) , dev - > name ) ;
bus - > priv = dmvgbe ;
dmvgbe - > bus = bus ;
ret = mdio_register ( bus ) ;
if ( ret < 0 )
return ret ;
return 0 ;
}
static const struct eth_ops mvgbe_ops = {
. start = mvgbe_start ,
. send = mvgbe_send ,
. recv = mvgbe_recv ,
. stop = mvgbe_stop ,
. write_hwaddr = mvgbe_write_hwaddr ,
} ;
static int mvgbe_ofdata_to_platdata ( struct udevice * dev )
{
struct eth_pdata * pdata = dev_get_platdata ( dev ) ;
struct mvgbe_device * dmvgbe = dev_get_priv ( dev ) ;
void * blob = ( void * ) gd - > fdt_blob ;
int node = dev_of_offset ( dev ) ;
const char * phy_mode ;
int fl_node ;
int pnode ;
unsigned long addr ;
pdata - > iobase = devfdt_get_addr ( dev ) ;
pdata - > phy_interface = - 1 ;
pnode = fdt_node_offset_by_compatible ( blob , node ,
" marvell,kirkwood-eth-port " ) ;
/* Get phy-mode / phy_interface from DT */
phy_mode = fdt_getprop ( gd - > fdt_blob , pnode , " phy-mode " , NULL ) ;
if ( phy_mode )
pdata - > phy_interface = phy_get_interface_by_name ( phy_mode ) ;
if ( pdata - > phy_interface = = - 1 ) {
debug ( " %s: Invalid PHY interface '%s' \n " , __func__ , phy_mode ) ;
return - EINVAL ;
}
dmvgbe - > phy_interface = pdata - > phy_interface ;
/* fetch 'fixed-link' property */
fl_node = fdt_subnode_offset ( blob , pnode , " fixed-link " ) ;
if ( fl_node ! = - FDT_ERR_NOTFOUND ) {
/* set phy_addr to invalid value for fixed link */
dmvgbe - > phyaddr = PHY_MAX_ADDR + 1 ;
dmvgbe - > duplex = fdtdec_get_bool ( blob , fl_node , " full-duplex " ) ;
dmvgbe - > speed = fdtdec_get_int ( blob , fl_node , " speed " , 0 ) ;
} else {
/* Now read phyaddr from DT */
addr = fdtdec_lookup_phandle ( blob , pnode , " phy-handle " ) ;
if ( addr > 0 )
dmvgbe - > phyaddr = fdtdec_get_int ( blob , addr , " reg " , 0 ) ;
}
return 0 ;
}
static const struct udevice_id mvgbe_ids [ ] = {
{ . compatible = " marvell,kirkwood-eth " } ,
{ }
} ;
U_BOOT_DRIVER ( mvgbe ) = {
. name = " mvgbe " ,
. id = UCLASS_ETH ,
. of_match = mvgbe_ids ,
. ofdata_to_platdata = mvgbe_ofdata_to_platdata ,
. probe = mvgbe_probe ,
. ops = & mvgbe_ops ,
. priv_auto_alloc_size = sizeof ( struct mvgbe_device ) ,
. platdata_auto_alloc_size = sizeof ( struct eth_pdata ) ,
} ;
# endif /* CONFIG_DM_ETH */