sunxi: emac: port to phylib

This is a preparation-patch for adding device-model support to the emac
driver.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Acked-by: Ian Campbell <ijc@hellion.org.uk>
Reviewed-by: Stefan Roese <sr@denx.de>
This commit is contained in:
Hans de Goede 2015-04-16 21:47:06 +02:00
parent aab096401c
commit 8145dea468
2 changed files with 71 additions and 42 deletions

View File

@ -156,9 +156,9 @@ struct sunxi_sramc_regs {
#define DMA_CPU_TRRESHOLD 2000 #define DMA_CPU_TRRESHOLD 2000
struct emac_eth_dev { struct emac_eth_dev {
u32 speed; struct emac_regs *regs;
u32 duplex; struct mii_dev *bus;
u32 phy_configured; struct phy_device *phydev;
int link_printed; int link_printed;
}; };
@ -195,11 +195,10 @@ static void emac_outblk_32bit(void *reg, void *data, int count)
} }
/* Read a word from phyxcer */ /* Read a word from phyxcer */
static int emac_phy_read(const char *devname, unsigned char addr, static int emac_mdio_read(struct mii_dev *bus, int addr, int devad, int reg)
unsigned char reg, unsigned short *value)
{ {
struct eth_device *dev = eth_get_dev_by_name(devname); struct emac_eth_dev *priv = bus->priv;
struct emac_regs *regs = (struct emac_regs *)dev->iobase; struct emac_regs *regs = priv->regs;
/* issue the phy address and reg */ /* issue the phy address and reg */
writel(addr << 8 | reg, &regs->mac_madr); writel(addr << 8 | reg, &regs->mac_madr);
@ -213,18 +212,16 @@ static int emac_phy_read(const char *devname, unsigned char addr,
/* push down the phy io line */ /* push down the phy io line */
writel(0x0, &regs->mac_mcmd); writel(0x0, &regs->mac_mcmd);
/* and write data */ /* And read data */
*value = readl(&regs->mac_mrdd); return readl(&regs->mac_mrdd);
return 0;
} }
/* Write a word to phyxcer */ /* Write a word to phyxcer */
static int emac_phy_write(const char *devname, unsigned char addr, static int emac_mdio_write(struct mii_dev *bus, int addr, int devad, int reg,
unsigned char reg, unsigned short value) u16 value)
{ {
struct eth_device *dev = eth_get_dev_by_name(devname); struct emac_eth_dev *priv = bus->priv;
struct emac_regs *regs = (struct emac_regs *)dev->iobase; struct emac_regs *regs = priv->regs;
/* issue the phy address and reg */ /* issue the phy address and reg */
writel(addr << 8 | reg, &regs->mac_madr); writel(addr << 8 | reg, &regs->mac_madr);
@ -244,12 +241,44 @@ static int emac_phy_write(const char *devname, unsigned char addr,
return 0; return 0;
} }
static void emac_setup(struct eth_device *dev) static int sunxi_emac_init_phy(struct emac_eth_dev *priv, void *dev)
{ {
struct emac_regs *regs = (struct emac_regs *)dev->iobase; int ret, mask = 0xffffffff;
#ifdef CONFIG_PHY_ADDR
mask = 1 << CONFIG_PHY_ADDR;
#endif
priv->bus = mdio_alloc();
if (!priv->bus) {
printf("Failed to allocate MDIO bus\n");
return -ENOMEM;
}
priv->bus->read = emac_mdio_read;
priv->bus->write = emac_mdio_write;
priv->bus->priv = priv;
strcpy(priv->bus->name, "emac");
ret = mdio_register(priv->bus);
if (ret)
return ret;
priv->phydev = phy_find_by_mask(priv->bus, mask,
PHY_INTERFACE_MODE_MII);
if (!priv->phydev)
return -ENODEV;
phy_connect_dev(priv->phydev, dev);
phy_config(priv->phydev);
return 0;
}
static void emac_setup(struct emac_eth_dev *priv)
{
struct emac_regs *regs = priv->regs;
u32 reg_val; u32 reg_val;
u16 phy_val;
u32 duplex_flag;
/* Set up TX */ /* Set up TX */
writel(EMAC_TX_SETUP, &regs->tx_mode); writel(EMAC_TX_SETUP, &regs->tx_mode);
@ -262,12 +291,8 @@ static void emac_setup(struct eth_device *dev)
writel(EMAC_MAC_CTL0_SETUP, &regs->mac_ctl0); writel(EMAC_MAC_CTL0_SETUP, &regs->mac_ctl0);
/* Set MAC CTL1 */ /* Set MAC CTL1 */
emac_phy_read(dev->name, 1, 0, &phy_val);
debug("PHY SETUP, reg 0 value: %x\n", phy_val);
duplex_flag = !!(phy_val & (1 << 8));
reg_val = 0; reg_val = 0;
if (duplex_flag) if (priv->phydev->duplex == DUPLEX_FULL)
reg_val = (0x1 << 0); reg_val = (0x1 << 0);
writel(EMAC_MAC_CTL1_SETUP | reg_val, &regs->mac_ctl1); writel(EMAC_MAC_CTL1_SETUP | reg_val, &regs->mac_ctl1);
@ -302,7 +327,7 @@ static int sunxi_emac_eth_init(struct eth_device *dev, bd_t *bd)
{ {
struct emac_regs *regs = (struct emac_regs *)dev->iobase; struct emac_regs *regs = (struct emac_regs *)dev->iobase;
struct emac_eth_dev *priv = dev->priv; struct emac_eth_dev *priv = dev->priv;
u16 phy_reg; int ret;
/* Init EMAC */ /* Init EMAC */
@ -320,7 +345,7 @@ static int sunxi_emac_eth_init(struct eth_device *dev, bd_t *bd)
udelay(1); udelay(1);
/* Set up EMAC */ /* Set up EMAC */
emac_setup(dev); emac_setup(priv);
writel(dev->enetaddr[0] << 16 | dev->enetaddr[1] << 8 | writel(dev->enetaddr[0] << 16 | dev->enetaddr[1] << 8 |
dev->enetaddr[2], &regs->mac_a1); dev->enetaddr[2], &regs->mac_a1);
@ -332,29 +357,32 @@ static int sunxi_emac_eth_init(struct eth_device *dev, bd_t *bd)
emac_reset(dev); emac_reset(dev);
/* PHY POWER UP */ /* PHY POWER UP */
emac_phy_read(dev->name, 1, 0, &phy_reg); ret = phy_startup(priv->phydev);
emac_phy_write(dev->name, 1, 0, phy_reg & (~(0x1 << 11))); if (ret) {
mdelay(1); printf("Could not initialize PHY %s\n",
priv->phydev->dev->name);
emac_phy_read(dev->name, 1, 0, &phy_reg); return ret;
}
priv->speed = miiphy_speed(dev->name, 0);
priv->duplex = miiphy_duplex(dev->name, 0);
/* Print link status only once */ /* Print link status only once */
if (!priv->link_printed) { if (!priv->link_printed) {
printf("ENET Speed is %d Mbps - %s duplex connection\n", printf("ENET Speed is %d Mbps - %s duplex connection\n",
priv->speed, (priv->duplex == HALF) ? "HALF" : "FULL"); priv->phydev->speed,
priv->phydev->duplex ? "FULL" : "HALF");
priv->link_printed = 1; priv->link_printed = 1;
} }
/* Set EMAC SPEED depend on PHY */ /* Set EMAC SPEED depend on PHY */
clrsetbits_le32(&regs->mac_supp, 1 << 8, if (priv->phydev->speed == SPEED_100)
((phy_reg & (0x1 << 13)) >> 13) << 8); setbits_le32(&regs->mac_supp, 1 << 8);
else
clrbits_le32(&regs->mac_supp, 1 << 8);
/* Set duplex depend on phy */ /* Set duplex depend on phy */
clrsetbits_le32(&regs->mac_ctl1, 1 << 0, if (priv->phydev->duplex == DUPLEX_FULL)
((phy_reg & (0x1 << 8)) >> 8) << 0); setbits_le32(&regs->mac_ctl1, 1 << 0);
else
clrbits_le32(&regs->mac_ctl1, 1 << 0);
/* Enable RX/TX */ /* Enable RX/TX */
setbits_le32(&regs->ctl, 0x7); setbits_le32(&regs->ctl, 0x7);
@ -505,6 +533,7 @@ int sunxi_emac_initialize(void)
/* Set MII clock */ /* Set MII clock */
clrsetbits_le32(&regs->mac_mcfg, 0xf << 2, 0xd << 2); clrsetbits_le32(&regs->mac_mcfg, 0xf << 2, 0xd << 2);
priv->regs = regs;
dev->iobase = (int)regs; dev->iobase = (int)regs;
dev->priv = priv; dev->priv = priv;
dev->init = sunxi_emac_eth_init; dev->init = sunxi_emac_eth_init;
@ -515,7 +544,5 @@ int sunxi_emac_initialize(void)
eth_register(dev); eth_register(dev);
miiphy_register(dev->name, emac_phy_read, emac_phy_write); return sunxi_emac_init_phy(priv, dev);
return 0;
} }

View File

@ -283,7 +283,9 @@ extern int soft_i2c_gpio_scl;
/* Ethernet support */ /* Ethernet support */
#ifdef CONFIG_SUNXI_EMAC #ifdef CONFIG_SUNXI_EMAC
#define CONFIG_PHY_ADDR 1
#define CONFIG_MII /* MII PHY management */ #define CONFIG_MII /* MII PHY management */
#define CONFIG_PHYLIB
#endif #endif
#ifdef CONFIG_SUNXI_GMAC #ifdef CONFIG_SUNXI_GMAC