|
@@ -22,6 +22,12 @@
|
|
|
#define memac_setbits_32(a, v) setbits_be32(a, v)
|
|
|
#endif
|
|
|
|
|
|
+#ifdef CONFIG_DM_ETH
|
|
|
+struct fm_mdio_priv {
|
|
|
+ struct memac_mdio_controller *regs;
|
|
|
+};
|
|
|
+#endif
|
|
|
+
|
|
|
static u32 memac_in_32(u32 *reg)
|
|
|
{
|
|
|
#ifdef CONFIG_SYS_MEMAC_LITTLE_ENDIAN
|
|
@@ -39,10 +45,23 @@ static u32 memac_in_32(u32 *reg)
|
|
|
int memac_mdio_write(struct mii_dev *bus, int port_addr, int dev_addr,
|
|
|
int regnum, u16 value)
|
|
|
{
|
|
|
+ struct memac_mdio_controller *regs;
|
|
|
u32 mdio_ctl;
|
|
|
- struct memac_mdio_controller *regs = bus->priv;
|
|
|
u32 c45 = 1; /* Default to 10G interface */
|
|
|
|
|
|
+#ifndef CONFIG_DM_ETH
|
|
|
+ regs = bus->priv;
|
|
|
+#else
|
|
|
+ struct fm_mdio_priv *priv;
|
|
|
+
|
|
|
+ if (!bus->priv)
|
|
|
+ return -EINVAL;
|
|
|
+ priv = dev_get_priv(bus->priv);
|
|
|
+ regs = priv->regs;
|
|
|
+ debug("memac_mdio_write(regs %p, port %d, dev %d, reg %d, val %#x)\n",
|
|
|
+ regs, port_addr, dev_addr, regnum, value);
|
|
|
+#endif
|
|
|
+
|
|
|
if (dev_addr == MDIO_DEVAD_NONE) {
|
|
|
c45 = 0; /* clause 22 */
|
|
|
dev_addr = regnum & 0x1f;
|
|
@@ -84,13 +103,26 @@ int memac_mdio_write(struct mii_dev *bus, int port_addr, int dev_addr,
|
|
|
int memac_mdio_read(struct mii_dev *bus, int port_addr, int dev_addr,
|
|
|
int regnum)
|
|
|
{
|
|
|
+ struct memac_mdio_controller *regs;
|
|
|
u32 mdio_ctl;
|
|
|
- struct memac_mdio_controller *regs = bus->priv;
|
|
|
u32 c45 = 1;
|
|
|
|
|
|
+#ifndef CONFIG_DM_ETH
|
|
|
+ regs = bus->priv;
|
|
|
+#else
|
|
|
+ struct fm_mdio_priv *priv;
|
|
|
+
|
|
|
+ if (!bus->priv)
|
|
|
+ return -EINVAL;
|
|
|
+ priv = dev_get_priv(bus->priv);
|
|
|
+ regs = priv->regs;
|
|
|
+#endif
|
|
|
+
|
|
|
if (dev_addr == MDIO_DEVAD_NONE) {
|
|
|
+#ifndef CONFIG_DM_ETH
|
|
|
if (!strcmp(bus->name, DEFAULT_FM_TGEC_MDIO_NAME))
|
|
|
return 0xffff;
|
|
|
+#endif
|
|
|
c45 = 0; /* clause 22 */
|
|
|
dev_addr = regnum & 0x1f;
|
|
|
memac_clrbits_32(®s->mdio_stat, MDIO_STAT_ENC);
|
|
@@ -133,6 +165,7 @@ int memac_mdio_reset(struct mii_dev *bus)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+#ifndef CONFIG_DM_ETH
|
|
|
int fm_memac_mdio_init(bd_t *bis, struct memac_mdio_info *info)
|
|
|
{
|
|
|
struct mii_dev *bus = mdio_alloc();
|
|
@@ -167,3 +200,105 @@ int fm_memac_mdio_init(bd_t *bis, struct memac_mdio_info *info)
|
|
|
|
|
|
return mdio_register(bus);
|
|
|
}
|
|
|
+
|
|
|
+#else /* CONFIG_DM_ETH */
|
|
|
+#if defined(CONFIG_PHYLIB) && defined(CONFIG_DM_MDIO)
|
|
|
+static int fm_mdio_read(struct udevice *dev, int addr, int devad, int reg)
|
|
|
+{
|
|
|
+ struct mdio_perdev_priv *pdata = (dev) ? dev_get_uclass_priv(dev) :
|
|
|
+ NULL;
|
|
|
+
|
|
|
+ if (pdata && pdata->mii_bus)
|
|
|
+ return memac_mdio_read(pdata->mii_bus, addr, devad, reg);
|
|
|
+
|
|
|
+ return -1;
|
|
|
+}
|
|
|
+
|
|
|
+static int fm_mdio_write(struct udevice *dev, int addr, int devad, int reg,
|
|
|
+ u16 val)
|
|
|
+{
|
|
|
+ struct mdio_perdev_priv *pdata = (dev) ? dev_get_uclass_priv(dev) :
|
|
|
+ NULL;
|
|
|
+
|
|
|
+ if (pdata && pdata->mii_bus)
|
|
|
+ return memac_mdio_write(pdata->mii_bus, addr, devad, reg, val);
|
|
|
+
|
|
|
+ return -1;
|
|
|
+}
|
|
|
+
|
|
|
+static int fm_mdio_reset(struct udevice *dev)
|
|
|
+{
|
|
|
+ struct mdio_perdev_priv *pdata = (dev) ? dev_get_uclass_priv(dev) :
|
|
|
+ NULL;
|
|
|
+
|
|
|
+ if (pdata && pdata->mii_bus)
|
|
|
+ return memac_mdio_reset(pdata->mii_bus);
|
|
|
+
|
|
|
+ return -1;
|
|
|
+}
|
|
|
+
|
|
|
+static const struct mdio_ops fm_mdio_ops = {
|
|
|
+ .read = fm_mdio_read,
|
|
|
+ .write = fm_mdio_write,
|
|
|
+ .reset = fm_mdio_reset,
|
|
|
+};
|
|
|
+
|
|
|
+static const struct udevice_id fm_mdio_ids[] = {
|
|
|
+ { .compatible = "fsl,fman-memac-mdio" },
|
|
|
+ {}
|
|
|
+};
|
|
|
+
|
|
|
+static int fm_mdio_probe(struct udevice *dev)
|
|
|
+{
|
|
|
+ struct fm_mdio_priv *priv = (dev) ? dev_get_priv(dev) : NULL;
|
|
|
+ struct mdio_perdev_priv *pdata = (dev) ? dev_get_uclass_priv(dev) :
|
|
|
+ NULL;
|
|
|
+
|
|
|
+ if (!dev) {
|
|
|
+ printf("%s dev = NULL\n", __func__);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ if (!priv) {
|
|
|
+ printf("dev_get_priv(dev %p) = NULL\n", dev);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ priv->regs = (void *)(uintptr_t)dev_read_addr(dev);
|
|
|
+ debug("%s priv %p @ regs %p, pdata %p\n", __func__,
|
|
|
+ priv, priv->regs, pdata);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * On some platforms like B4860, default value of MDIO_CLK_DIV bits
|
|
|
+ * in mdio_stat(mdio_cfg) register generates MDIO clock too high
|
|
|
+ * (much higher than 2.5MHz), violating the IEEE specs.
|
|
|
+ * On other platforms like T1040, default value of MDIO_CLK_DIV bits
|
|
|
+ * is zero, so MDIO clock is disabled.
|
|
|
+ * So, for proper functioning of MDIO, MDIO_CLK_DIV bits needs to
|
|
|
+ * be properly initialized.
|
|
|
+ * The default NEG bit should be '1' as per FMANv3 RM, but on platforms
|
|
|
+ * like T2080QDS, this bit default is '0', which leads to MDIO failure
|
|
|
+ * on XAUI PHY, so set this bit definitely.
|
|
|
+ */
|
|
|
+ if (priv && priv->regs && priv->regs->mdio_stat)
|
|
|
+ memac_setbits_32(&priv->regs->mdio_stat,
|
|
|
+ MDIO_STAT_CLKDIV(258) | MDIO_STAT_NEG);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int fm_mdio_remove(struct udevice *dev)
|
|
|
+{
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+U_BOOT_DRIVER(fman_mdio) = {
|
|
|
+ .name = "fman_mdio",
|
|
|
+ .id = UCLASS_MDIO,
|
|
|
+ .of_match = fm_mdio_ids,
|
|
|
+ .probe = fm_mdio_probe,
|
|
|
+ .remove = fm_mdio_remove,
|
|
|
+ .ops = &fm_mdio_ops,
|
|
|
+ .priv_auto_alloc_size = sizeof(struct fm_mdio_priv),
|
|
|
+ .platdata_auto_alloc_size = sizeof(struct mdio_perdev_priv),
|
|
|
+};
|
|
|
+#endif /* CONFIG_PHYLIB && CONFIG_DM_MDIO */
|
|
|
+#endif /* CONFIG_DM_ETH */
|