The PCS exists only in GMAC1 and relates to SGMII interface and
is used to control the SGMII PHY.

Signed-off-by: Jim Liu <jjl...@nuvoton.com>
---
 arch/arm/include/asm/arch-npcm8xx/gmac.h | 18 ++++++++++++++++
 drivers/net/designware.c                 | 27 ++++++++++++++++++++++++
 2 files changed, 45 insertions(+)
 create mode 100644 arch/arm/include/asm/arch-npcm8xx/gmac.h

diff --git a/arch/arm/include/asm/arch-npcm8xx/gmac.h 
b/arch/arm/include/asm/arch-npcm8xx/gmac.h
new file mode 100644
index 00000000000..f84eedddc22
--- /dev/null
+++ b/arch/arm/include/asm/arch-npcm8xx/gmac.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+
+#ifndef _NPCM_GMAC_H_
+#define _NPCM_GMAC_H_
+
+/* PCS registers */
+#define PCS_BA                 0xF0780000
+#define PCS_IND_AC             0x1FE
+#define SR_MII_MMD             0x3E0000
+#define SR_MII_MMD_CTRL                0x0
+#define SR_MII_MMD_STS         0x2
+#define VR_MII_MMD             0x3F0000
+#define VR_MII_MMD_CTRL1       0x0
+#define VR_MII_MMD_AN_CTRL     0x2
+
+#define LINK_UP_TIMEOUT                (3 * CONFIG_SYS_HZ)
+
+#endif
diff --git a/drivers/net/designware.c b/drivers/net/designware.c
index 0a1fff38727..771c1672ae9 100644
--- a/drivers/net/designware.c
+++ b/drivers/net/designware.c
@@ -33,6 +33,9 @@
 #include <linux/printk.h>
 #include <power/regulator.h>
 #include "designware.h"
+#if IS_ENABLED(CONFIG_ARCH_NPCM8XX)
+#include <asm/arch/gmac.h>
+#endif
 
 static int dw_mdio_read(struct mii_dev *bus, int addr, int devad, int reg)
 {
@@ -328,6 +331,7 @@ static int dw_adjust_link(struct dw_eth_dev *priv, struct 
eth_mac_regs *mac_p,
                          struct phy_device *phydev)
 {
        u32 conf = readl(&mac_p->conf) | FRAMEBURSTENABLE | DISABLERXOWN;
+       unsigned int start;
 
        if (!phydev->link) {
                printf("%s: No link.\n", phydev->dev->name);
@@ -352,6 +356,29 @@ static int dw_adjust_link(struct dw_eth_dev *priv, struct 
eth_mac_regs *mac_p,
               (phydev->port == PORT_FIBRE) ? ", fiber mode" : "");
 
 #ifdef CONFIG_ARCH_NPCM8XX
+       if( phydev->interface == PHY_INTERFACE_MODE_SGMII) {
+               /* Indirect access to VR_MII_MMD registers */
+               writew((VR_MII_MMD >> 9), PCS_BA + PCS_IND_AC);
+               /* Set PCS_Mode to SGMII */
+               clrsetbits_le16(PCS_BA + VR_MII_MMD_AN_CTRL, BIT(1), BIT(2));
+               /* Set Auto Speed Mode Change */
+               setbits_le16(PCS_BA + VR_MII_MMD_CTRL1, BIT(9));
+               /* Indirect access to SR_MII_MMD registers */
+               writew((SR_MII_MMD >> 9), PCS_BA + PCS_IND_AC);
+               /* Restart Auto-Negotiation */
+               setbits_le16(PCS_BA + SR_MII_MMD_CTRL, BIT(9) | BIT(12));
+
+               printf("SGMII PHY Wait for link up \n");
+               /* SGMII PHY Wait for link up */
+               start = get_timer(0);
+               while (!(readw(PCS_BA + SR_MII_MMD_STS) & BIT(2))) {
+                       if (get_timer(start) >= LINK_UP_TIMEOUT) {
+                               printf("PHY link up timeout\n");
+                               return -ETIMEDOUT;
+                       }
+                       mdelay(1);
+               };
+       }
        /* Pass all Multicast Frames */
        setbits_le32(&mac_p->framefilt, BIT(4));
 
-- 
2.34.1

Reply via email to