mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-28 07:31:15 +00:00
net: mvgbe: convert to DM
Add driver model support to the mvgbe driver. As a temporary measure both DM and non-DM uses are supported. Once all the users have been converted the non-DM support can be dropped. Signed-off-by: Chris Packham <judge.packham@gmail.com> Tested-by: Michael Walle <michael@walle.cc> Acked-by: Joe Hershberger <joe.hershberger@ni.com>
This commit is contained in:
parent
e9bf75c9d3
commit
fb73107698
3 changed files with 279 additions and 51 deletions
|
@ -181,6 +181,7 @@ config FTMAC100
|
|||
config MVGBE
|
||||
bool "Marvell Orion5x/Kirkwood network interface support"
|
||||
depends on KIRKWOOD || ORION5X
|
||||
select PHYLIB if DM_ETH
|
||||
help
|
||||
This driver supports the network interface units in the
|
||||
Marvell Orion5x and Kirkwood SoCs
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -30,7 +30,9 @@
|
|||
#define RXUQ 0 /* Used Rx queue */
|
||||
#define TXUQ 0 /* Used Rx queue */
|
||||
|
||||
#ifndef CONFIG_DM_ETH
|
||||
#define to_mvgbe(_d) container_of(_d, struct mvgbe_device, dev)
|
||||
#endif
|
||||
#define MVGBE_REG_WR(adr, val) writel(val, &adr)
|
||||
#define MVGBE_REG_RD(adr) readl(&adr)
|
||||
#define MVGBE_REG_BITS_RESET(adr, val) writel(readl(&adr) & ~(val), &adr)
|
||||
|
@ -479,13 +481,27 @@ struct mvgbe_txdesc {
|
|||
|
||||
/* port device data struct */
|
||||
struct mvgbe_device {
|
||||
#ifndef CONFIG_DM_ETH
|
||||
struct eth_device dev;
|
||||
#endif
|
||||
struct mvgbe_registers *regs;
|
||||
struct mvgbe_txdesc *p_txdesc;
|
||||
struct mvgbe_rxdesc *p_rxdesc;
|
||||
struct mvgbe_rxdesc *p_rxdesc_curr;
|
||||
u8 *p_rxbuf;
|
||||
u8 *p_aligned_txbuf;
|
||||
|
||||
#ifdef CONFIG_DM_ETH
|
||||
phy_interface_t phy_interface;
|
||||
unsigned int link;
|
||||
unsigned int duplex;
|
||||
unsigned int speed;
|
||||
|
||||
int init;
|
||||
int phyaddr;
|
||||
struct phy_device *phydev;
|
||||
struct mii_dev *bus;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif /* __MVGBE_H__ */
|
||||
|
|
Loading…
Reference in a new issue