net: designware: Add npcm8xx sgmii pcs support
The PCS exists only in GMAC1 and relates to SGMII interface and
is used to control the SGMII PHY.
Signed-off-by: Jim Liu <JJLIU0@nuvoton.com>
[trini: Adjust slightly for white space and to move 'start' to within if
block]
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 0000000..f84eedd
--- /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 0a1fff3..2ab0301 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)
{
@@ -352,10 +355,35 @@
(phydev->port == PORT_FIBRE) ? ", fiber mode" : "");
#ifdef CONFIG_ARCH_NPCM8XX
+ if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
+ unsigned int start;
+
+ /* 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));
-
#endif
+
return 0;
}