Thread (1 message) 1 message, 1 author, 2019-06-16
DORMANTno replies

[PATCH 3/6] net: macb: add PHY configuration in MACB PCI wrapper

From: Parshuram Thombare <hidden>
Date: 2019-06-16 07:05:19
Also in: lkml
Subsystem: atmel macb ethernet driver, networking drivers, the rest · Maintainers: Théo Lebrun, Andrew Lunn, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Linus Torvalds

Possibly related (same subject, not in this thread)

This patch add TI PHY DP83867 configuration for SGMII link in
Cadence MACB PCI wrapper.

Signed-off-by: Parshuram Thombare <redacted>
---
 drivers/net/ethernet/cadence/macb_pci.c | 225 ++++++++++++++++++++++++
 1 file changed, 225 insertions(+)
diff --git a/drivers/net/ethernet/cadence/macb_pci.c b/drivers/net/ethernet/cadence/macb_pci.c
index 248a8fc45069..1001e03191a1 100644
--- a/drivers/net/ethernet/cadence/macb_pci.c
+++ b/drivers/net/ethernet/cadence/macb_pci.c
@@ -24,6 +24,7 @@
 #include <linux/etherdevice.h>
 #include <linux/module.h>
 #include <linux/pci.h>
+#include <linux/iopoll.h>
 #include <linux/platform_data/macb.h>
 #include <linux/platform_device.h>
 #include "macb.h"
@@ -37,6 +38,224 @@
 #define GEM_PCLK_RATE 50000000
 #define GEM_HCLK_RATE 50000000
 
+#define TI_PHY_DP83867_ID	0x2000a231
+#define TI_PHY_DEVADDR		0x1f
+#define PHY_REGCR 0x0D
+#define PHY_ADDAR 0x0E
+
+#define MACB_MDIO_TIMEOUT	1000000 /* in usecs */
+
+#define MACB_REGCR_OP_OFFSET		14
+#define MACB_REGCR_OP_SIZE		2
+#define MACB_REGCR_DEVADDR_OFFSET	0
+#define MACB_REGCR_DEVADDR_SIZE		5
+
+#define MACB_REGCR_OP_ADDR	0
+#define MACB_REGCR_OP_DATA	1
+
+static int macb_mdio_wait_for_idle(void __iomem *macb_base_addr)
+{
+	u32 val;
+
+	return readx_poll_timeout(readl, macb_base_addr + MACB_NSR, val,
+				  val & MACB_BIT(IDLE), 1, MACB_MDIO_TIMEOUT);
+}
+
+static int macb_mdiobus_read(void __iomem *macb_base_addr,
+			     u32 phy_id,
+			     u32 regnum)
+{
+	u32 i;
+	int status;
+
+	if (regnum < 32) {
+		i = MACB_BF(SOF, MACB_MAN_SOF) |
+			MACB_BF(RW, MACB_MAN_READ) |
+			MACB_BF(PHYA, phy_id) |
+			MACB_BF(REGA, regnum) |
+			MACB_BF(CODE, MACB_MAN_CODE);
+
+		writel(i, macb_base_addr + MACB_MAN);
+		status = macb_mdio_wait_for_idle(macb_base_addr);
+		if (status < 0)
+			return status;
+	} else {
+		u16 reg;
+
+		reg = MACB_BF(REGCR_OP, MACB_REGCR_OP_ADDR) |
+				MACB_BF(REGCR_DEVADDR, TI_PHY_DEVADDR);
+		i = MACB_BF(SOF, MACB_MAN_SOF) |
+			MACB_BF(RW, MACB_MAN_WRITE) |
+			MACB_BF(PHYA, phy_id) |
+			MACB_BF(REGA, PHY_REGCR) |
+			MACB_BF(CODE, MACB_MAN_CODE) |
+			MACB_BF(DATA, reg);
+		writel(i, macb_base_addr + MACB_MAN);
+		status = macb_mdio_wait_for_idle(macb_base_addr);
+		if (status < 0)
+			return status;
+
+		i = MACB_BF(SOF, MACB_MAN_SOF) |
+			MACB_BF(RW, MACB_MAN_WRITE) |
+			MACB_BF(PHYA, phy_id) |
+			MACB_BF(REGA, PHY_ADDAR) |
+			MACB_BF(CODE, MACB_MAN_CODE) |
+			MACB_BF(DATA, regnum);
+		writel(i, macb_base_addr + MACB_MAN);
+		status = macb_mdio_wait_for_idle(macb_base_addr);
+		if (status < 0)
+			return status;
+
+		reg = MACB_BF(REGCR_OP, MACB_REGCR_OP_DATA) |
+				MACB_BF(REGCR_DEVADDR, TI_PHY_DEVADDR);
+		i = MACB_BF(SOF, MACB_MAN_SOF) |
+			MACB_BF(RW, MACB_MAN_WRITE) |
+			MACB_BF(PHYA, phy_id) |
+			MACB_BF(REGA, PHY_REGCR) |
+			MACB_BF(CODE, MACB_MAN_CODE) |
+			MACB_BF(DATA, reg);
+		writel(i, macb_base_addr + MACB_MAN);
+		status = macb_mdio_wait_for_idle(macb_base_addr);
+		if (status < 0)
+			return status;
+
+		i = MACB_BF(SOF, MACB_MAN_SOF) |
+			MACB_BF(RW, MACB_MAN_READ) |
+			MACB_BF(PHYA, phy_id) |
+			MACB_BF(REGA, PHY_ADDAR) |
+			MACB_BF(CODE, MACB_MAN_CODE);
+
+		writel(i, macb_base_addr + MACB_MAN);
+		status = macb_mdio_wait_for_idle(macb_base_addr);
+		if (status < 0)
+			return status;
+	}
+
+	return readl(macb_base_addr + MACB_MAN);
+}
+
+static int macb_mdiobus_write(void __iomem *macb_base_addr, u32 phy_id,
+			      u32 regnum, u16 value)
+{
+	u32 i;
+	int status;
+
+	if (regnum < 32) {
+		i = MACB_BF(SOF, MACB_MAN_SOF) |
+			MACB_BF(RW, MACB_MAN_WRITE) |
+			MACB_BF(PHYA, phy_id) |
+			MACB_BF(REGA, regnum) |
+			MACB_BF(CODE, MACB_MAN_CODE) |
+			MACB_BF(DATA, value);
+
+		writel(i, macb_base_addr + MACB_MAN);
+		status = macb_mdio_wait_for_idle(macb_base_addr);
+		if (status < 0)
+			return status;
+	} else {
+		u16 reg;
+
+		reg = MACB_BF(REGCR_OP, MACB_REGCR_OP_ADDR) |
+				MACB_BF(REGCR_DEVADDR, TI_PHY_DEVADDR);
+		i = MACB_BF(SOF, MACB_MAN_SOF) |
+			MACB_BF(RW, MACB_MAN_WRITE) |
+			MACB_BF(PHYA, phy_id) |
+			MACB_BF(REGA, PHY_REGCR) |
+			MACB_BF(CODE, MACB_MAN_CODE) |
+			MACB_BF(DATA, reg);
+		writel(i, macb_base_addr + MACB_MAN);
+		status = macb_mdio_wait_for_idle(macb_base_addr);
+		if (status < 0)
+			return status;
+
+		i = MACB_BF(SOF, MACB_MAN_SOF) |
+			MACB_BF(RW, MACB_MAN_WRITE) |
+			MACB_BF(PHYA, phy_id) |
+			MACB_BF(REGA, PHY_ADDAR) |
+			MACB_BF(CODE, MACB_MAN_CODE) |
+			MACB_BF(DATA, regnum);
+		writel(i, macb_base_addr + MACB_MAN);
+		status = macb_mdio_wait_for_idle(macb_base_addr);
+		if (status < 0)
+			return status;
+
+		reg = MACB_BF(REGCR_OP, MACB_REGCR_OP_DATA) |
+				MACB_BF(REGCR_DEVADDR, TI_PHY_DEVADDR);
+		i = MACB_BF(SOF, MACB_MAN_SOF) |
+			MACB_BF(RW, MACB_MAN_WRITE) |
+			MACB_BF(PHYA, phy_id) |
+			MACB_BF(REGA, PHY_REGCR) |
+			MACB_BF(CODE, MACB_MAN_CODE) |
+			MACB_BF(DATA, reg);
+		writel(i, macb_base_addr + MACB_MAN);
+		status = macb_mdio_wait_for_idle(macb_base_addr);
+		if (status < 0)
+			return status;
+
+		i = MACB_BF(SOF, MACB_MAN_SOF) |
+			MACB_BF(RW, MACB_MAN_WRITE) |
+			MACB_BF(PHYA, phy_id) |
+			MACB_BF(REGA, PHY_ADDAR) |
+			MACB_BF(CODE, MACB_MAN_CODE) |
+			MACB_BF(DATA, value);
+
+		writel(i, macb_base_addr + MACB_MAN);
+		status = macb_mdio_wait_for_idle(macb_base_addr);
+		if (status < 0)
+			return status;
+	}
+
+	return 0;
+}
+
+static int macb_scan_mdio(void __iomem *macb_base_addr)
+{
+	int i;
+	int phy_reg;
+	int phy_id;
+
+	for (i = 0; i < PHY_MAX_ADDR; i++) {
+		phy_reg = macb_mdiobus_read(macb_base_addr, i, MII_PHYSID1);
+		if (phy_reg < 0)
+			continue;
+
+		phy_id = (phy_reg & 0xffff) << 16;
+		phy_reg = macb_mdiobus_read(macb_base_addr, i, MII_PHYSID2);
+		if (phy_reg < 0)
+			continue;
+
+		phy_id |= (phy_reg & 0xffff);
+		if ((phy_id & 0x1fffffff) != 0x1fffffff &&
+		    phy_id == TI_PHY_DP83867_ID)
+			return i;
+	}
+
+	return -1;
+}
+
+static void macb_setup_phy(void __iomem *macb_base_addr)
+{
+	int phy_id;
+
+	// Enable MDIO
+	writel(readl(macb_base_addr + MACB_NCR) | MACB_BIT(MPE),
+	       macb_base_addr + MACB_NCR);
+
+	phy_id = macb_scan_mdio(macb_base_addr);
+	if (phy_id >= 0) {
+		if (macb_mdiobus_write(macb_base_addr, phy_id, 0xd3, 0x4000))
+			return;
+		if (macb_mdiobus_write(macb_base_addr, phy_id, 0x14, 0x29c7))
+			return;
+		if (macb_mdiobus_write(macb_base_addr, phy_id, 0x32, 0x0000))
+			return;
+		if (macb_mdiobus_write(macb_base_addr, phy_id, 0x10, 0x0800))
+			return;
+		if (macb_mdiobus_write(macb_base_addr, phy_id, 0x31, 0x1170))
+			return;
+	}
+}
+
 static int macb_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
 	int err;
@@ -44,6 +263,7 @@ static int macb_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 	struct platform_device_info plat_info;
 	struct macb_platform_data plat_data;
 	struct resource res[2];
+	void __iomem *addr;
 
 	/* enable pci device */
 	err = pcim_enable_device(pdev);
@@ -66,6 +286,11 @@ static int macb_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 
 	dev_info(&pdev->dev, "EMAC physical base addr: %pa\n",
 		 &res[0].start);
+	addr = ioremap(res[0].start, resource_size(&res[0]));
+	if (addr) {
+		macb_setup_phy(addr);
+		iounmap(addr);
+	}
 
 	/* set up macb platform data */
 	memset(&plat_data, 0, sizeof(plat_data));
-- 
2.17.1
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help