#define ZYNQ_GEM_NWCFG_SPEED1000 0x000000400 /* 1Gbps operation */
#define ZYNQ_GEM_NWCFG_FDEN 0x000000002 /* Full Duplex mode */
#define ZYNQ_GEM_NWCFG_FSREM 0x000020000 /* FCS removal */
+#define ZYNQ_GEM_NWCFG_SGMII_ENBL 0x080000000 /* SGMII Enable */
+#define ZYNQ_GEM_NWCFG_PCS_SEL 0x000000800 /* PCS select */
#ifdef CONFIG_ARM64
#define ZYNQ_GEM_NWCFG_MDCCLKDIV 0x000100000 /* Div pclk by 64, max 160MHz */
#else
#define ZYNQ_GEM_TSR_DONE 0x00000020 /* Tx done mask */
+#define ZYNQ_GEM_PCS_CTL_ANEG_ENBL 0x1000
+
/* Use MII register 1 (MII status register) to detect PHY */
#define PHY_DETECT_REG 1
u32 reserved6[18];
#define STAT_SIZE 44
u32 stat[STAT_SIZE]; /* 0x100 - Octects transmitted Low reg */
- u32 reserved7[164];
+ u32 reserved9[20];
+ u32 pcscntrl;
+ u32 reserved7[143];
u32 transmit_q1_ptr; /* 0x440 - Transmit priority queue 1 */
u32 reserved8[15];
u32 receive_q1_ptr; /* 0x480 - Receive priority queue 1 */
struct zynq_gem_regs *iobase;
phy_interface_t interface;
struct phy_device *phydev;
+ int phy_of_handle;
struct mii_dev *bus;
};
/* Enable only MDIO bus */
writel(ZYNQ_GEM_NWCTRL_MDEN_MASK, ®s->nwctrl);
- ret = phy_detection(dev);
- if (ret) {
- printf("GEM PHY init failed\n");
- return ret;
+ if (priv->interface != PHY_INTERFACE_MODE_SGMII) {
+ ret = phy_detection(dev);
+ if (ret) {
+ printf("GEM PHY init failed\n");
+ return ret;
+ }
}
priv->phydev = phy_connect(priv->bus, priv->phyaddr, dev,
priv->phydev->supported = supported | ADVERTISED_Pause |
ADVERTISED_Asym_Pause;
priv->phydev->advertising = priv->phydev->supported;
- phy_config(priv->phydev);
- return 0;
+ if (priv->phy_of_handle > 0)
+ priv->phydev->dev->of_offset = priv->phy_of_handle;
+
+ return phy_config(priv->phydev);
}
static int zynq_gem_init(struct udevice *dev)
{
- u32 i;
+ u32 i, nwconfig;
+ int ret;
unsigned long clk_rate = 0;
struct zynq_gem_priv *priv = dev_get_priv(dev);
struct zynq_gem_regs *regs = priv->iobase;
priv->init++;
}
- phy_startup(priv->phydev);
+ ret = phy_startup(priv->phydev);
+ if (ret)
+ return ret;
if (!priv->phydev->link) {
printf("%s: No link.\n", priv->phydev->dev->name);
return -1;
}
+ nwconfig = ZYNQ_GEM_NWCFG_INIT;
+
+ if (priv->interface == PHY_INTERFACE_MODE_SGMII) {
+ nwconfig |= ZYNQ_GEM_NWCFG_SGMII_ENBL |
+ ZYNQ_GEM_NWCFG_PCS_SEL;
+#ifdef CONFIG_ARM64
+ writel(readl(®s->pcscntrl) | ZYNQ_GEM_PCS_CTL_ANEG_ENBL,
+ ®s->pcscntrl);
+#endif
+ }
+
switch (priv->phydev->speed) {
case SPEED_1000:
- writel(ZYNQ_GEM_NWCFG_INIT | ZYNQ_GEM_NWCFG_SPEED1000,
+ writel(nwconfig | ZYNQ_GEM_NWCFG_SPEED1000,
®s->nwcfg);
clk_rate = ZYNQ_GEM_FREQUENCY_1000;
break;
case SPEED_100:
- writel(ZYNQ_GEM_NWCFG_INIT | ZYNQ_GEM_NWCFG_SPEED100,
+ writel(nwconfig | ZYNQ_GEM_NWCFG_SPEED100,
®s->nwcfg);
clk_rate = ZYNQ_GEM_FREQUENCY_100;
break;
ZYNQ_GEM_NWCTRL_TXEN_MASK, 0);
}
+__weak int zynq_board_read_rom_ethaddr(unsigned char *ethaddr)
+{
+ return -ENOSYS;
+}
+
+static int zynq_gem_read_rom_mac(struct udevice *dev)
+{
+ int retval;
+ struct eth_pdata *pdata = dev_get_platdata(dev);
+
+ retval = zynq_board_read_rom_ethaddr(pdata->enetaddr);
+ if (retval == -ENOSYS)
+ retval = 0;
+
+ return retval;
+}
+
static int zynq_gem_miiphy_read(struct mii_dev *bus, int addr,
int devad, int reg)
{
if (ret)
return ret;
- zynq_phy_init(dev);
-
- return 0;
+ return zynq_phy_init(dev);
}
static int zynq_gem_remove(struct udevice *dev)
.free_pkt = zynq_gem_free_pkt,
.stop = zynq_gem_halt,
.write_hwaddr = zynq_gem_setup_mac,
+ .read_rom_hwaddr = zynq_gem_read_rom_mac,
};
static int zynq_gem_ofdata_to_platdata(struct udevice *dev)
{
struct eth_pdata *pdata = dev_get_platdata(dev);
struct zynq_gem_priv *priv = dev_get_priv(dev);
- int offset = 0;
const char *phy_mode;
pdata->iobase = (phys_addr_t)dev_get_addr(dev);
priv->emio = 0;
priv->phyaddr = -1;
- offset = fdtdec_lookup_phandle(gd->fdt_blob, dev->of_offset,
- "phy-handle");
- if (offset > 0)
- priv->phyaddr = fdtdec_get_int(gd->fdt_blob, offset, "reg", -1);
+ priv->phy_of_handle = fdtdec_lookup_phandle(gd->fdt_blob,
+ dev->of_offset, "phy-handle");
+ if (priv->phy_of_handle > 0)
+ priv->phyaddr = fdtdec_get_int(gd->fdt_blob,
+ priv->phy_of_handle, "reg", -1);
phy_mode = fdt_getprop(gd->fdt_blob, dev->of_offset, "phy-mode", NULL);
if (phy_mode)
}
priv->interface = pdata->phy_interface;
+ priv->emio = fdtdec_get_bool(gd->fdt_blob, dev->of_offset, "xlnx,emio");
+
printf("ZYNQ GEM: %lx, phyaddr %d, interface %s\n", (ulong)priv->iobase,
priv->phyaddr, phy_string_for_interface(priv->interface));