|
|
|
@ -12,6 +12,7 @@ |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
#include <common.h> |
|
|
|
|
#include <dm.h> |
|
|
|
|
#include <net.h> |
|
|
|
|
#include <malloc.h> |
|
|
|
|
#include <miiphy.h> |
|
|
|
@ -55,20 +56,13 @@ static int smi_wait_ready(struct mvgbe_device *dmvgbe) |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* smi_reg_read - miiphy_read callback function. |
|
|
|
|
* |
|
|
|
|
* Returns 16bit phy register value, or -EFAULT on error |
|
|
|
|
*/ |
|
|
|
|
static int smi_reg_read(struct mii_dev *bus, int phy_adr, int devad, |
|
|
|
|
int reg_ofs) |
|
|
|
|
static int __mvgbe_mdio_read(struct mvgbe_device *dmvgbe, int phy_adr, |
|
|
|
|
int devad, int reg_ofs) |
|
|
|
|
{ |
|
|
|
|
u16 data = 0; |
|
|
|
|
struct eth_device *dev = eth_get_dev_by_name(bus->name); |
|
|
|
|
struct mvgbe_device *dmvgbe = to_mvgbe(dev); |
|
|
|
|
struct mvgbe_registers *regs = dmvgbe->regs; |
|
|
|
|
u32 smi_reg; |
|
|
|
|
u32 timeout; |
|
|
|
|
u16 data = 0; |
|
|
|
|
|
|
|
|
|
/* Phyadr read request */ |
|
|
|
|
if (phy_adr == MV_PHY_ADR_REQUEST && |
|
|
|
@ -127,15 +121,26 @@ static int smi_reg_read(struct mii_dev *bus, int phy_adr, int devad, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* smi_reg_write - miiphy_write callback function. |
|
|
|
|
* smi_reg_read - miiphy_read callback function. |
|
|
|
|
* |
|
|
|
|
* Returns 0 if write succeed, -EFAULT on error |
|
|
|
|
* Returns 16bit phy register value, or -EFAULT on error |
|
|
|
|
*/ |
|
|
|
|
static int smi_reg_write(struct mii_dev *bus, int phy_adr, int devad, |
|
|
|
|
int reg_ofs, u16 data) |
|
|
|
|
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); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int __mvgbe_mdio_write(struct mvgbe_device *dmvgbe, int phy_adr, |
|
|
|
|
int devad, int reg_ofs, u16 data) |
|
|
|
|
{ |
|
|
|
|
struct mvgbe_registers *regs = dmvgbe->regs; |
|
|
|
|
u32 smi_reg; |
|
|
|
|
|
|
|
|
@ -171,6 +176,24 @@ static int smi_reg_write(struct mii_dev *bus, int phy_adr, int devad, |
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* smi_reg_write - miiphy_write callback function. |
|
|
|
|
* |
|
|
|
|
* Returns 0 if write succeed, -EFAULT on error |
|
|
|
|
*/ |
|
|
|
|
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); |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
/* Stop and checks all queues */ |
|
|
|
@ -357,8 +380,9 @@ static int port_uc_addr(struct mvgbe_registers *regs, u8 uc_nibble, |
|
|
|
|
/*
|
|
|
|
|
* port_uc_addr_set - This function Set the port Unicast address. |
|
|
|
|
*/ |
|
|
|
|
static void port_uc_addr_set(struct mvgbe_registers *regs, u8 * p_addr) |
|
|
|
|
static void port_uc_addr_set(struct mvgbe_device *dmvgbe, u8 *p_addr) |
|
|
|
|
{ |
|
|
|
|
struct mvgbe_registers *regs = dmvgbe->regs; |
|
|
|
|
u32 mac_h; |
|
|
|
|
u32 mac_l; |
|
|
|
|
|
|
|
|
@ -400,12 +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 eth_device *dev) |
|
|
|
|
static int __mvgbe_init(struct mvgbe_device *dmvgbe, u8 *enetaddr, |
|
|
|
|
const char *name) |
|
|
|
|
{ |
|
|
|
|
struct mvgbe_device *dmvgbe = to_mvgbe(dev); |
|
|
|
|
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 |
|
|
|
@ -422,7 +447,7 @@ static int mvgbe_init(struct eth_device *dev) |
|
|
|
|
|
|
|
|
|
set_dram_access(regs); |
|
|
|
|
port_init_mac_tables(regs); |
|
|
|
|
port_uc_addr_set(regs, dmvgbe->dev.enetaddr); |
|
|
|
|
port_uc_addr_set(dmvgbe, enetaddr); |
|
|
|
|
|
|
|
|
|
/* Assign port configuration and command. */ |
|
|
|
|
MVGBE_REG_WR(regs->pxc, PRT_CFG_VAL); |
|
|
|
@ -459,28 +484,37 @@ static int mvgbe_init(struct eth_device *dev) |
|
|
|
|
|
|
|
|
|
#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(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(dev->name, phyadr)) |
|
|
|
|
if (miiphy_link(name, phyadr)) |
|
|
|
|
return 0; |
|
|
|
|
udelay(1000000); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
printf("No link on %s\n", dev->name); |
|
|
|
|
printf("No link on %s\n", name); |
|
|
|
|
return -1; |
|
|
|
|
#endif |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int mvgbe_halt(struct eth_device *dev) |
|
|
|
|
#ifndef CONFIG_DM_ETH |
|
|
|
|
static int mvgbe_init(struct eth_device *dev) |
|
|
|
|
{ |
|
|
|
|
struct mvgbe_device *dmvgbe = to_mvgbe(dev); |
|
|
|
|
|
|
|
|
|
return __mvgbe_init(dmvgbe, dmvgbe->dev.enetaddr, dmvgbe->dev.name); |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
static void __mvgbe_halt(struct mvgbe_device *dmvgbe) |
|
|
|
|
{ |
|
|
|
|
struct mvgbe_registers *regs = dmvgbe->regs; |
|
|
|
|
|
|
|
|
|
/* Disable all gigE address decoder */ |
|
|
|
@ -502,23 +536,42 @@ static int mvgbe_halt(struct eth_device *dev) |
|
|
|
|
MVGBE_REG_WR(regs->ice, 0); |
|
|
|
|
MVGBE_REG_WR(regs->pim, 0); |
|
|
|
|
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); |
|
|
|
|
|
|
|
|
|
__mvgbe_halt(dmvgbe); |
|
|
|
|
|
|
|
|
|
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); |
|
|
|
|
struct mvgbe_registers *regs = dmvgbe->regs; |
|
|
|
|
|
|
|
|
|
/* Programs net device MAC address after initialization */ |
|
|
|
|
port_uc_addr_set(regs, dmvgbe->dev.enetaddr); |
|
|
|
|
port_uc_addr_set(dmvgbe, dmvgbe->dev.enetaddr); |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
static int mvgbe_send(struct eth_device *dev, void *dataptr, int datasize) |
|
|
|
|
static int __mvgbe_send(struct mvgbe_device *dmvgbe, void *dataptr, |
|
|
|
|
int datasize) |
|
|
|
|
{ |
|
|
|
|
struct mvgbe_device *dmvgbe = to_mvgbe(dev); |
|
|
|
|
struct mvgbe_registers *regs = dmvgbe->regs; |
|
|
|
|
struct mvgbe_txdesc *p_txdesc = dmvgbe->p_txdesc; |
|
|
|
|
void *p = (void *)dataptr; |
|
|
|
@ -571,13 +624,25 @@ static int mvgbe_send(struct eth_device *dev, void *dataptr, int datasize) |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int mvgbe_recv(struct eth_device *dev) |
|
|
|
|
#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) |
|
|
|
|
{ |
|
|
|
|
struct mvgbe_rxdesc *p_rxdesc_curr = dmvgbe->p_rxdesc_curr; |
|
|
|
|
u32 cmd_sts; |
|
|
|
|
u32 timeout = 0; |
|
|
|
|
u32 rxdesc_curr_addr; |
|
|
|
|
unsigned char *data; |
|
|
|
|
int rx_bytes = 0; |
|
|
|
|
|
|
|
|
|
*packetp = NULL; |
|
|
|
|
|
|
|
|
|
/* wait untill rx packet available or timeout */ |
|
|
|
|
do { |
|
|
|
@ -621,11 +686,11 @@ static int mvgbe_recv(struct eth_device *dev) |
|
|
|
|
" upper layer (net_process_received_packet)\n", |
|
|
|
|
__func__); |
|
|
|
|
|
|
|
|
|
/* let the upper layer handle the packet */ |
|
|
|
|
net_process_received_packet((p_rxdesc_curr->buf_ptr + |
|
|
|
|
RX_BUF_OFFSET), |
|
|
|
|
(int)(p_rxdesc_curr->byte_cnt - |
|
|
|
|
RX_BUF_OFFSET)); |
|
|
|
|
data = (p_rxdesc_curr->buf_ptr + RX_BUF_OFFSET); |
|
|
|
|
rx_bytes = (int)(p_rxdesc_curr->byte_cnt - |
|
|
|
|
RX_BUF_OFFSET); |
|
|
|
|
|
|
|
|
|
*packetp = data; |
|
|
|
|
} |
|
|
|
|
/*
|
|
|
|
|
* free these descriptors and point next in the ring |
|
|
|
@ -638,10 +703,59 @@ static int mvgbe_recv(struct eth_device *dev) |
|
|
|
|
rxdesc_curr_addr = (u32)&dmvgbe->p_rxdesc_curr; |
|
|
|
|
writel((unsigned)p_rxdesc_curr->nxtdesc_p, rxdesc_curr_addr); |
|
|
|
|
|
|
|
|
|
return rx_bytes; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#ifndef CONFIG_DM_ETH |
|
|
|
|
static int mvgbe_recv(struct eth_device *dev) |
|
|
|
|
{ |
|
|
|
|
struct mvgbe_device *dmvgbe = to_mvgbe(dev); |
|
|
|
|
uchar *packet; |
|
|
|
|
int ret; |
|
|
|
|
|
|
|
|
|
ret = __mvgbe_recv(dmvgbe, &packet); |
|
|
|
|
if (ret < 0) |
|
|
|
|
return ret; |
|
|
|
|
|
|
|
|
|
net_process_received_packet(packet, ret); |
|
|
|
|
|
|
|
|
|
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; |
|
|
|
@ -664,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++) { |
|
|
|
@ -693,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; |
|
|
|
@ -783,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 */ |
|
|
|
|