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:
Chris Packham 2018-07-09 21:34:00 +12:00 committed by Joe Hershberger
parent e9bf75c9d3
commit fb73107698
3 changed files with 279 additions and 51 deletions

View File

@ -181,6 +181,7 @@ config FTMAC100
config MVGBE config MVGBE
bool "Marvell Orion5x/Kirkwood network interface support" bool "Marvell Orion5x/Kirkwood network interface support"
depends on KIRKWOOD || ORION5X depends on KIRKWOOD || ORION5X
select PHYLIB if DM_ETH
help help
This driver supports the network interface units in the This driver supports the network interface units in the
Marvell Orion5x and Kirkwood SoCs Marvell Orion5x and Kirkwood SoCs

View File

@ -12,6 +12,7 @@
*/ */
#include <common.h> #include <common.h>
#include <dm.h>
#include <net.h> #include <net.h>
#include <malloc.h> #include <malloc.h>
#include <miiphy.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, static int smi_reg_read(struct mii_dev *bus, int phy_adr, int devad,
int reg_ofs) 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 eth_device *dev = eth_get_dev_by_name(bus->name);
struct mvgbe_device *dmvgbe = to_mvgbe(dev); struct mvgbe_device *dmvgbe = to_mvgbe(dev);
#endif
return __mvgbe_mdio_read(dmvgbe, phy_adr, devad, reg_ofs); 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, static int smi_reg_write(struct mii_dev *bus, int phy_adr, int devad,
int reg_ofs, u16 data) 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 eth_device *dev = eth_get_dev_by_name(bus->name);
struct mvgbe_device *dmvgbe = to_mvgbe(dev); struct mvgbe_device *dmvgbe = to_mvgbe(dev);
#endif
return __mvgbe_mdio_write(dmvgbe, phy_adr, devad, reg_ofs, data); 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; 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; struct mvgbe_registers *regs = dmvgbe->regs;
#if (defined(CONFIG_MII) || defined(CONFIG_CMD_MII)) && \ #if (defined(CONFIG_MII) || defined(CONFIG_CMD_MII)) && \
!defined(CONFIG_PHYLIB) && \ !defined(CONFIG_PHYLIB) && \
!defined(CONFIG_DM_ETH) && \
defined(CONFIG_SYS_FAULT_ECHO_LINK_DOWN) defined(CONFIG_SYS_FAULT_ECHO_LINK_DOWN)
int i; int i;
#endif #endif
@ -436,7 +447,7 @@ static int __mvgbe_init(struct mvgbe_device *dmvgbe)
set_dram_access(regs); set_dram_access(regs);
port_init_mac_tables(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. */ /* Assign port configuration and command. */
MVGBE_REG_WR(regs->pxc, PRT_CFG_VAL); 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)) && \ #if (defined(CONFIG_MII) || defined(CONFIG_CMD_MII)) && \
!defined(CONFIG_PHYLIB) && \ !defined(CONFIG_PHYLIB) && \
!defined(CONFIG_DM_ETH) && \
defined(CONFIG_SYS_FAULT_ECHO_LINK_DOWN) defined(CONFIG_SYS_FAULT_ECHO_LINK_DOWN)
/* Wait up to 5s for the link status */ /* Wait up to 5s for the link status */
for (i = 0; i < 5; i++) { for (i = 0; i < 5; i++) {
u16 phyadr; u16 phyadr;
miiphy_read(dmvgbe->dev.name, MV_PHY_ADR_REQUEST, miiphy_read(name, MV_PHY_ADR_REQUEST,
MV_PHY_ADR_REQUEST, &phyadr); MV_PHY_ADR_REQUEST, &phyadr);
/* Return if we get link up */ /* Return if we get link up */
if (miiphy_link(dmvgbe->dev.name, phyadr)) if (miiphy_link(name, phyadr))
return 0; return 0;
udelay(1000000); udelay(1000000);
} }
printf("No link on %s\n", dmvgbe->dev.name); printf("No link on %s\n", name);
return -1; return -1;
#endif #endif
return 0; return 0;
} }
#ifndef CONFIG_DM_ETH
static int mvgbe_init(struct eth_device *dev) static int mvgbe_init(struct eth_device *dev)
{ {
struct mvgbe_device *dmvgbe = to_mvgbe(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) 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); MVGBE_REG_WR(regs->peim, 0);
} }
#ifndef CONFIG_DM_ETH
static int mvgbe_halt(struct eth_device *dev) static int mvgbe_halt(struct eth_device *dev)
{ {
struct mvgbe_device *dmvgbe = to_mvgbe(dev); struct mvgbe_device *dmvgbe = to_mvgbe(dev);
@ -532,7 +547,18 @@ static int mvgbe_halt(struct eth_device *dev)
return 0; 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) static int mvgbe_write_hwaddr(struct eth_device *dev)
{ {
struct mvgbe_device *dmvgbe = to_mvgbe(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); port_uc_addr_set(dmvgbe, dmvgbe->dev.enetaddr);
return 0; return 0;
} }
#endif
static int __mvgbe_send(struct mvgbe_device *dmvgbe, void *dataptr, static int __mvgbe_send(struct mvgbe_device *dmvgbe, void *dataptr,
int datasize) int datasize)
@ -597,12 +624,14 @@ static int __mvgbe_send(struct mvgbe_device *dmvgbe, void *dataptr,
return 0; return 0;
} }
#ifndef CONFIG_DM_ETH
static int mvgbe_send(struct eth_device *dev, void *dataptr, int datasize) static int mvgbe_send(struct eth_device *dev, void *dataptr, int datasize)
{ {
struct mvgbe_device *dmvgbe = to_mvgbe(dev); struct mvgbe_device *dmvgbe = to_mvgbe(dev);
return __mvgbe_send(dmvgbe, dataptr, datasize); return __mvgbe_send(dmvgbe, dataptr, datasize);
} }
#endif
static int __mvgbe_recv(struct mvgbe_device *dmvgbe, uchar **packetp) 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; return rx_bytes;
} }
#ifndef CONFIG_DM_ETH
static int mvgbe_recv(struct eth_device *dev) static int mvgbe_recv(struct eth_device *dev)
{ {
struct mvgbe_device *dmvgbe = to_mvgbe(dev); struct mvgbe_device *dmvgbe = to_mvgbe(dev);
@ -691,8 +721,41 @@ static int mvgbe_recv(struct eth_device *dev)
return 0; 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) int mvgbe_phylib_init(struct eth_device *dev, int phyid)
{ {
struct mii_dev *bus; struct mii_dev *bus;
@ -715,27 +778,53 @@ int mvgbe_phylib_init(struct eth_device *dev, int phyid)
return -ENOMEM; return -ENOMEM;
} }
/* Set phy address of the port */ phydev = __mvgbe_phy_init(dev, bus, PHY_INTERFACE_MODE_RGMII, phyid);
smi_reg_write(bus, MV_PHY_ADR_REQUEST, 0, MV_PHY_ADR_REQUEST, phyid); if (!phydev)
phydev = phy_connect(bus, phyid, dev, PHY_INTERFACE_MODE_RGMII);
if (!phydev) {
printf("phy_connect failed\n");
return -ENODEV; return -ENODEV;
}
phy_config(phydev);
phy_startup(phydev);
return 0; return 0;
} }
#endif #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) int mvgbe_initialize(bd_t *bis)
{ {
struct mvgbe_device *dmvgbe; struct mvgbe_device *dmvgbe;
struct eth_device *dev; struct eth_device *dev;
int devnum; int devnum;
int ret;
u8 used_ports[MAX_MVGBE_DEVS] = CONFIG_MVGBE_PORTS; u8 used_ports[MAX_MVGBE_DEVS] = CONFIG_MVGBE_PORTS;
for (devnum = 0; devnum < MAX_MVGBE_DEVS; devnum++) { for (devnum = 0; devnum < MAX_MVGBE_DEVS; devnum++) {
@ -744,45 +833,16 @@ int mvgbe_initialize(bd_t *bis)
continue; continue;
dmvgbe = malloc(sizeof(struct mvgbe_device)); dmvgbe = malloc(sizeof(struct mvgbe_device));
if (!dmvgbe) if (!dmvgbe)
goto error1; return -ENOMEM;
memset(dmvgbe, 0, sizeof(struct mvgbe_device)); memset(dmvgbe, 0, sizeof(struct mvgbe_device));
ret = mvgbe_alloc_buffers(dmvgbe);
dmvgbe->p_rxdesc = if (ret) {
(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:
printf("Err.. %s Failed to allocate memory\n", printf("Err.. %s Failed to allocate memory\n",
__func__); __func__);
return -1; free(dmvgbe);
return ret;
} }
dev = &dmvgbe->dev; dev = &dmvgbe->dev;
@ -834,3 +894,154 @@ error1:
} }
return 0; 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 */

View File

@ -30,7 +30,9 @@
#define RXUQ 0 /* Used Rx queue */ #define RXUQ 0 /* Used Rx queue */
#define TXUQ 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) #define to_mvgbe(_d) container_of(_d, struct mvgbe_device, dev)
#endif
#define MVGBE_REG_WR(adr, val) writel(val, &adr) #define MVGBE_REG_WR(adr, val) writel(val, &adr)
#define MVGBE_REG_RD(adr) readl(&adr) #define MVGBE_REG_RD(adr) readl(&adr)
#define MVGBE_REG_BITS_RESET(adr, val) writel(readl(&adr) & ~(val), &adr) #define MVGBE_REG_BITS_RESET(adr, val) writel(readl(&adr) & ~(val), &adr)
@ -479,13 +481,27 @@ struct mvgbe_txdesc {
/* port device data struct */ /* port device data struct */
struct mvgbe_device { struct mvgbe_device {
#ifndef CONFIG_DM_ETH
struct eth_device dev; struct eth_device dev;
#endif
struct mvgbe_registers *regs; struct mvgbe_registers *regs;
struct mvgbe_txdesc *p_txdesc; struct mvgbe_txdesc *p_txdesc;
struct mvgbe_rxdesc *p_rxdesc; struct mvgbe_rxdesc *p_rxdesc;
struct mvgbe_rxdesc *p_rxdesc_curr; struct mvgbe_rxdesc *p_rxdesc_curr;
u8 *p_rxbuf; u8 *p_rxbuf;
u8 *p_aligned_txbuf; 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__ */ #endif /* __MVGBE_H__ */