All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [PATCH 0/3] Add network support for Luton SoCs
@ 2019-01-28 10:29 Horatiu Vultur
  2019-01-28 10:29 ` [U-Boot] [PATCH 1/3] MIPS: mscc: luton: Add ethernet nodes for Luton Horatiu Vultur
                   ` (2 more replies)
  0 siblings, 3 replies; 5+ messages in thread
From: Horatiu Vultur @ 2019-01-28 10:29 UTC (permalink / raw)
  To: u-boot

This series adds network support for Luton SoCs. Currently
there is not support for Luton SoCs in Linux.

Horatiu Vultur (3):
  MIPS: mscc: luton: Add ethernet nodes for Luton.
  net: add MSCC Luton switch support
  configs: mscc_luton: add network support.

 MAINTAINERS                    |   1 +
 arch/mips/dts/luton_pcb090.dts |  51 +++
 arch/mips/dts/luton_pcb091.dts |  51 +++
 arch/mips/dts/mscc,luton.dtsi  | 165 +++++++
 configs/mscc_luton_defconfig   |   1 +
 drivers/net/Kconfig            |   7 +
 drivers/net/Makefile           |   1 +
 drivers/net/luton_switch.c     | 972 +++++++++++++++++++++++++++++++++++++++++
 8 files changed, 1249 insertions(+)
 create mode 100644 drivers/net/luton_switch.c

-- 
2.7.4

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [U-Boot] [PATCH 1/3] MIPS: mscc: luton: Add ethernet nodes for Luton.
  2019-01-28 10:29 [U-Boot] [PATCH 0/3] Add network support for Luton SoCs Horatiu Vultur
@ 2019-01-28 10:29 ` Horatiu Vultur
  2019-01-28 10:29 ` [U-Boot] [PATCH 2/3] net: add MSCC Luton switch support Horatiu Vultur
  2019-01-28 10:29 ` [U-Boot] [PATCH 3/3] configs: mscc_luton: add network support Horatiu Vultur
  2 siblings, 0 replies; 5+ messages in thread
From: Horatiu Vultur @ 2019-01-28 10:29 UTC (permalink / raw)
  To: u-boot

Add nodes for pcb090 and pcb091. There is currently no support
in Linux for this SoC.

Signed-off-by: Horatiu Vultur <horatiu.vultur@microchip.com>
---
 arch/mips/dts/luton_pcb090.dts |  51 +++++++++++++
 arch/mips/dts/luton_pcb091.dts |  51 +++++++++++++
 arch/mips/dts/mscc,luton.dtsi  | 165 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 267 insertions(+)

diff --git a/arch/mips/dts/luton_pcb090.dts b/arch/mips/dts/luton_pcb090.dts
index 951d8da..315172b 100644
--- a/arch/mips/dts/luton_pcb090.dts
+++ b/arch/mips/dts/luton_pcb090.dts
@@ -55,3 +55,54 @@
 	};
 };
 
+&mdio0 {
+	status = "okay";
+};
+
+&port0 {
+	phy-handle = <&phy0>;
+};
+
+&port1 {
+	phy-handle = <&phy1>;
+};
+
+&port2 {
+	phy-handle = <&phy2>;
+};
+
+&port3 {
+	phy-handle = <&phy3>;
+};
+
+&port4 {
+	phy-handle = <&phy4>;
+};
+
+&port5 {
+	phy-handle = <&phy5>;
+};
+
+&port6 {
+	phy-handle = <&phy6>;
+};
+
+&port7 {
+	phy-handle = <&phy7>;
+};
+
+&port8 {
+	phy-handle = <&phy8>;
+};
+
+&port9 {
+	phy-handle = <&phy9>;
+};
+
+&port10 {
+	phy-handle = <&phy10>;
+};
+
+&port11 {
+	phy-handle = <&phy11>;
+};
diff --git a/arch/mips/dts/luton_pcb091.dts b/arch/mips/dts/luton_pcb091.dts
index bf638b2..9b4d628 100644
--- a/arch/mips/dts/luton_pcb091.dts
+++ b/arch/mips/dts/luton_pcb091.dts
@@ -61,3 +61,54 @@
 	};
 };
 
+&mdio0 {
+	status = "okay";
+};
+
+&port0 {
+	phy-handle = <&phy0>;
+};
+
+&port1 {
+	phy-handle = <&phy1>;
+};
+
+&port2 {
+	phy-handle = <&phy2>;
+};
+
+&port3 {
+	phy-handle = <&phy3>;
+};
+
+&port4 {
+	phy-handle = <&phy4>;
+};
+
+&port5 {
+	phy-handle = <&phy5>;
+};
+
+&port6 {
+	phy-handle = <&phy6>;
+};
+
+&port7 {
+	phy-handle = <&phy7>;
+};
+
+&port8 {
+	phy-handle = <&phy8>;
+};
+
+&port9 {
+	phy-handle = <&phy9>;
+};
+
+&port10 {
+	phy-handle = <&phy10>;
+};
+
+&port11 {
+	phy-handle = <&phy11>;
+};
diff --git a/arch/mips/dts/mscc,luton.dtsi b/arch/mips/dts/mscc,luton.dtsi
index d11ec48..de354fe 100644
--- a/arch/mips/dts/mscc,luton.dtsi
+++ b/arch/mips/dts/mscc,luton.dtsi
@@ -92,5 +92,170 @@
 			#address-cells = <1>;
 			#size-cells = <0>;
 		};
+
+		switch: switch at 1010000 {
+			compatible = "mscc,vsc7527-switch";
+			reg = <0x1e0000 0x0100>, // VTSS_TO_DEV_0
+			      <0x1f0000 0x0100>, // VTSS_TO_DEV_1
+			      <0x200000 0x0100>, // VTSS_TO_DEV_2
+			      <0x210000 0x0100>, // VTSS_TO_DEV_3
+			      <0x220000 0x0100>, // VTSS_TO_DEV_4
+			      <0x230000 0x0100>, // VTSS_TO_DEV_5
+			      <0x240000 0x0100>, // VTSS_TO_DEV_6
+			      <0x250000 0x0100>, // VTSS_TO_DEV_7
+			      <0x260000 0x0100>, // VTSS_TO_DEV_8
+			      <0x270000 0x0100>, // VTSS_TO_DEV_9
+			      <0x280000 0x0100>, // VTSS_TO_DEV_10
+			      <0x290000 0x0100>, // VTSS_TO_DEV_11
+			      <0x2a0000 0x0100>, // VTSS_TO_DEV_12
+			      <0x2b0000 0x0100>, // VTSS_TO_DEV_13
+			      <0x2c0000 0x0100>, // VTSS_TO_DEV_14
+			      <0x2d0000 0x0100>, // VTSS_TO_DEV_15
+			      <0x2e0000 0x0100>, // VTSS_TO_DEV_16
+			      <0x2f0000 0x0100>, // VTSS_TO_DEV_17
+			      <0x300000 0x0100>, // VTSS_TO_DEV_18
+			      <0x310000 0x0100>, // VTSS_TO_DEV_19
+			      <0x320000 0x0100>, // VTSS_TO_DEV_20
+			      <0x330000 0x0100>, // VTSS_TO_DEV_21
+			      <0x340000 0x0100>, // VTSS_TO_DEV_22
+			      <0x350000 0x0100>, // VTSS_TO_DEV_23
+			      <0x010000 0x1000>, // VTSS_TO_SYS
+			      <0x020000 0x1000>, // VTSS_TO_ANA
+			      <0x030000 0x1000>, // VTSS_TO_REW
+			      <0x070000 0x1000>, // VTSS_TO_DEVCPU_GCB
+			      <0x080000 0x0100>, // VTSS_TO_DEVCPU_QS
+			      <0x0a0000 0x0100>; // VTSS_TO_HSIO
+			reg-names = "port0", "port1", "port2", "port3",
+				    "port4", "port5", "port6", "port7",
+				    "port8", "port9", "port10", "port11",
+				    "port12", "port13", "port14", "port15",
+				    "port16", "port17", "port18", "port19",
+				    "port20", "port21", "port22", "port23",
+				    "sys", "ana", "rew", "gcb", "qs", "hsio";
+			status = "okay";
+
+			ethernet-ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port0: port at 0 {
+					reg = <0>;
+				};
+				port1: port at 1 {
+					reg = <1>;
+				};
+				port2: port at 2 {
+					reg = <2>;
+				};
+				port3: port at 3 {
+					reg = <3>;
+				};
+				port4: port at 4 {
+					reg = <4>;
+				};
+				port5: port at 5 {
+					reg = <5>;
+				};
+				port6: port at 6 {
+					reg = <6>;
+				};
+				port7: port at 7 {
+					reg = <7>;
+				};
+				port8: port at 8 {
+					reg = <8>;
+				};
+				port9: port at 9 {
+					reg = <9>;
+				};
+				port10: port at 10 {
+					reg = <10>;
+				};
+				port11: port at 11 {
+					reg = <11>;
+				};
+				port12: port at 12 {
+					reg = <12>;
+				};
+				port13: port at 13 {
+					reg = <13>;
+				};
+				port14: port at 14 {
+					reg = <14>;
+				};
+				port15: port at 15 {
+					reg = <15>;
+				};
+				port16: port at 16 {
+					reg = <16>;
+				};
+				port17: port at 17 {
+					reg = <17>;
+				};
+				port18: port at 18 {
+					reg = <18>;
+				};
+				port19: port at 19 {
+					reg = <19>;
+				};
+				port20: port at 20 {
+					reg = <20>;
+				};
+				port21: port at 21 {
+					reg = <21>;
+				};
+				port22: port at 22 {
+					reg = <22>;
+				};
+				port23: port at 23 {
+					reg = <23>;
+				};
+			};
+		};
+
+		mdio0: mdio at 700a0 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "mscc,luton-miim";
+			reg = <0x700a0 0x24>;
+			status = "disabled";
+
+			phy0: ethernet-phy at 0 {
+				reg = <0>;
+			};
+			phy1: ethernet-phy at 1 {
+				reg = <1>;
+			};
+			phy2: ethernet-phy at 2 {
+				reg = <2>;
+			};
+			phy3: ethernet-phy at 3 {
+				reg = <3>;
+			};
+			phy4: ethernet-phy at 4 {
+				reg = <4>;
+			};
+			phy5: ethernet-phy at 5 {
+				reg = <5>;
+			};
+			phy6: ethernet-phy at 6 {
+				reg = <6>;
+			};
+			phy7: ethernet-phy at 7 {
+				reg = <7>;
+			};
+			phy8: ethernet-phy at 8 {
+				reg = <8>;
+			};
+			phy9: ethernet-phy at 9 {
+				reg = <9>;
+			};
+			phy10: ethernet-phy at 10 {
+				reg = <10>;
+			};
+			phy11: ethernet-phy at 11 {
+				reg = <11>;
+			};
+		};
 	};
 };
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [U-Boot] [PATCH 2/3] net: add MSCC Luton switch support
  2019-01-28 10:29 [U-Boot] [PATCH 0/3] Add network support for Luton SoCs Horatiu Vultur
  2019-01-28 10:29 ` [U-Boot] [PATCH 1/3] MIPS: mscc: luton: Add ethernet nodes for Luton Horatiu Vultur
@ 2019-01-28 10:29 ` Horatiu Vultur
  2019-01-28 13:22   ` Gregory CLEMENT
  2019-01-28 10:29 ` [U-Boot] [PATCH 3/3] configs: mscc_luton: add network support Horatiu Vultur
  2 siblings, 1 reply; 5+ messages in thread
From: Horatiu Vultur @ 2019-01-28 10:29 UTC (permalink / raw)
  To: u-boot

Add network driver for Microsemi Ethernet switch is present
on Luton SoCs.

Signed-off-by: Horatiu Vultur <horatiu.vultur@microchip.com>
---
 MAINTAINERS                |   1 +
 drivers/net/Kconfig        |   7 +
 drivers/net/Makefile       |   1 +
 drivers/net/luton_switch.c | 972 +++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 981 insertions(+)
 create mode 100644 drivers/net/luton_switch.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 1cb092e..253274b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -540,6 +540,7 @@ F:	drivers/spi/mscc_bb_spi.c
 F:	include/configs/vcoreiii.h
 F:	drivers/pinctrl/mscc/
 F:	drivers/net/ocelot_switch.c
+F:	drivers/net/luton_switch.c
 
 MIPS JZ4780
 M:	Ezequiel Garcia <ezequiel@collabora.com>
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 39ce4e8..d82037d 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -439,6 +439,13 @@ config MSCC_OCELOT_SWITCH
 	help
 	  This driver supports the Ocelot network switch device.
 
+config MSCC_LUTON_SWITCH
+	bool "Luton switch driver"
+	depends on DM_ETH && ARCH_MSCC
+	select PHYLIB
+	help
+	  This driver supports the Luton network switch device.
+
 config ETHER_ON_FEC1
 	bool "FEC1"
 	depends on MPC8XX_FEC
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index e38c164..470660d 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -76,3 +76,4 @@ obj-$(CONFIG_SNI_AVE) += sni_ave.o
 obj-y += ti/
 obj-$(CONFIG_MEDIATEK_ETH) += mtk_eth.o
 obj-$(CONFIG_MSCC_OCELOT_SWITCH) += ocelot_switch.o
+obj-$(CONFIG_MSCC_LUTON_SWITCH) += luton_switch.o
diff --git a/drivers/net/luton_switch.c b/drivers/net/luton_switch.c
new file mode 100644
index 0000000..816b5fe
--- /dev/null
+++ b/drivers/net/luton_switch.c
@@ -0,0 +1,972 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2019 Microsemi Corporation
+ */
+
+#include <common.h>
+#include <config.h>
+#include <dm.h>
+#include <dm/of_access.h>
+#include <dm/of_addr.h>
+#include <fdt_support.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <miiphy.h>
+#include <net.h>
+#include <wait_bit.h>
+
+#define MIIM_STATUS		0x0
+#define		MIIM_STATUS_BUSY		BIT(3)
+#define MIIM_CMD		0x8
+#define		MIIM_CMD_SCAN		BIT(0)
+#define		MIIM_CMD_OPR_WRITE		BIT(1)
+#define		MIIM_CMD_OPR_READ		BIT(2)
+#define		MIIM_CMD_SINGLE_SCAN	BIT(3)
+#define		MIIM_CMD_WRDATA(x)		((x) << 4)
+#define		MIIM_CMD_REGAD(x)		((x) << 20)
+#define		MIIM_CMD_PHYAD(x)		((x) << 25)
+#define		MIIM_CMD_VLD		BIT(31)
+#define MIIM_DATA		0xC
+#define		MIIM_DATA_ERROR		(0x3 << 16)
+
+#define ANA_PORT_VLAN_CFG(x)		(0x00 + 0x80 * (x))
+#define		ANA_PORT_VLAN_CFG_AWARE_ENA	BIT(20)
+#define		ANA_PORT_VLAN_CFG_POP_CNT(x)	((x) << 18)
+#define ANA_PORT_CPU_FWD_CFG(x)		(0x50 + 0x80 * (x))
+#define		ANA_PORT_CPU_FWD_CFG_SRC_COPY_ENA	BIT(1)
+#define ANA_PORT_PORT_CFG(x)		(0x60 + 0x80 * (x))
+#define		ANA_PORT_PORT_CFG_RECV_ENA	BIT(5)
+#define ANA_TABLES_MACHDATA		0x11b0
+#define ANA_TABLES_MACLDATA		0x11b4
+#define ANA_TABLES_MACACCESS		0x11b8
+#define		ANA_TABLES_MACACCESS_MAC_CPU_COPY	BIT(15)
+#define		ANA_TABLES_MACACCESS_VALID		BIT(11)
+#define		ANA_TABLES_MACACCESS_ENTRYTYPE(x)	((x) << 9)
+#define		ANA_TABLES_MACACCESS_DEST_IDX(x)	((x) << 3)
+#define		ANA_TABLES_MACACCESS_MAC_TABLE_CMD(x)	(x)
+#define		ANA_TABLES_MACACCESS_MAC_TABLE_CMD_M	GENMASK(2, 0)
+#define		MACACCESS_CMD_IDLE		0
+#define		MACACCESS_CMD_LEARN		1
+#define ANA_PGID(x)			(0x1000 + 4 * (x))
+
+#define SYS_FRM_AGING			0x8300
+
+#define SYS_SYSTEM_RST_CFG		0x81b0
+#define		SYS_SYSTEM_RST_MEM_INIT		BIT(0)
+#define		SYS_SYSTEM_RST_MEM_ENA		BIT(1)
+#define		SYS_SYSTEM_RST_CORE_ENA		BIT(2)
+#define SYS_PORT_MODE(x)		(0x81bc + 0x4 * (x))
+#define		SYS_PORT_MODE_INCL_INJ_HDR	BIT(0)
+#define SYS_SWITCH_PORT_MODE(x)		(0x8294 + 0x4 * (x))
+#define		SYS_SWITCH_PORT_MODE_PORT_ENA	BIT(3)
+#define SYS_EGR_NO_SHARING		0x8378
+#define SYS_SCH_CPU			0x85a0
+
+#define REW_PORT_CFG(x)			(0x8 + 0x80 * (x))
+#define		REW_PORT_CFG_IFH_INSERT_ENA	BIT(7)
+
+#define GCB_DEVCPU_RST_SOFT_CHIP_RST	0x90
+#define		GCB_DEVCPU_RST_SOFT_CHIP_RST_SOFT_PHY	BIT(1)
+#define GCB_MISC_STAT			0x11c
+#define		GCB_MISC_STAT_PHY_READY			BIT(3)
+
+#define	QS_XTR_MAP(x)			(0x10 + 4 * (x))
+#define		QS_XTR_MAP_GRP			BIT(4)
+#define		QS_XTR_MAP_ENA			BIT(0)
+#define QS_XTR_RD(x)			(0x18 + 4 * (x))
+#define QS_XTR_FLUSH			0x28
+#define		QS_XTR_FLUSH_FLUSH		BIT(0)
+#define QS_XTR_DATA_PRESENT		0x2c
+#define QS_INJ_WR(x)			(0x3c + 4 * (x))
+#define QS_INJ_CTRL(x)			(0x44 + 4 * (x))
+#define		QS_INJ_CTRL_GAP_SIZE(x)		((x) << 21)
+#define		QS_INJ_CTRL_EOF			BIT(19)
+#define		QS_INJ_CTRL_SOF			BIT(18)
+#define		QS_INJ_CTRL_VLD_BYTES(x)	((x) << 16)
+
+#define HSIO_PLL5G_CFG_PLL5G_CFG2	0x8
+
+#define HSIO_RCOMP_CFG_CFG0		0x20
+#define		HSIO_RCOMP_CFG_CFG0_MODE_SEL(x)			((x) << 8)
+#define		HSIO_RCOMP_CFG_CFG0_RUN_CAL			BIT(12)
+#define HSIO_RCOMP_STATUS		0x24
+#define		HSIO_RCOMP_STATUS_BUSY				BIT(12)
+#define		HSIO_RCOMP_STATUS_RCOMP_M			GENMASK(3, 0)
+#define HSIO_SERDES6G_ANA_CFG_DES_CFG	0x64
+#define		HSIO_SERDES6G_ANA_CFG_DES_CFG_BW_ANA(x)		((x) << 1)
+#define		HSIO_SERDES6G_ANA_CFG_DES_CFG_BW_HYST(x)	((x) << 5)
+#define		HSIO_SERDES6G_ANA_CFG_DES_CFG_MBTR_CTRL(x)	((x) << 10)
+#define		HSIO_SERDES6G_ANA_CFG_DES_CFG_PHS_CTRL(x)	((x) << 13)
+#define HSIO_SERDES6G_ANA_CFG_IB_CFG	0x68
+#define		HSIO_SERDES6G_ANA_CFG_IB_CFG_RESISTOR_CTRL(x)	(x)
+#define		HSIO_SERDES6G_ANA_CFG_IB_CFG_VBCOM(x)		((x) << 4)
+#define		HSIO_SERDES6G_ANA_CFG_IB_CFG_VBAC(x)		((x) << 7)
+#define		HSIO_SERDES6G_ANA_CFG_IB_CFG_RT(x)		((x) << 9)
+#define		HSIO_SERDES6G_ANA_CFG_IB_CFG_RF(x)		((x) << 14)
+#define HSIO_SERDES6G_ANA_CFG_IB_CFG1	0x6c
+#define		HSIO_SERDES6G_ANA_CFG_IB_CFG1_RST		BIT(0)
+#define		HSIO_SERDES6G_ANA_CFG_IB_CFG1_ENA_OFFSDC	BIT(2)
+#define		HSIO_SERDES6G_ANA_CFG_IB_CFG1_ENA_OFFSAC	BIT(3)
+#define		HSIO_SERDES6G_ANA_CFG_IB_CFG1_ANEG_MODE	BIT(6)
+#define		HSIO_SERDES6G_ANA_CFG_IB_CFG1_CHF		BIT(7)
+#define		HSIO_SERDES6G_ANA_CFG_IB_CFG1_C(x)		((x) << 8)
+#define HSIO_SERDES6G_ANA_CFG_OB_CFG	0x70
+#define		HSIO_SERDES6G_ANA_CFG_OB_CFG_SR(x)		((x) << 4)
+#define		HSIO_SERDES6G_ANA_CFG_OB_CFG_SR_H		BIT(8)
+#define		HSIO_SERDES6G_ANA_CFG_OB_CFG_POST0(x)		((x) << 23)
+#define		HSIO_SERDES6G_ANA_CFG_OB_CFG_POL		BIT(29)
+#define		HSIO_SERDES6G_ANA_CFG_OB_CFG_ENA1V_MODE	BIT(30)
+#define HSIO_SERDES6G_ANA_CFG_OB_CFG1	0x74
+#define		HSIO_SERDES6G_ANA_CFG_OB_CFG1_LEV(x)		(x)
+#define		HSIO_SERDES6G_ANA_CFG_OB_CFG1_ENA_CAS(x)	((x) << 6)
+#define HSIO_SERDES6G_ANA_CFG_COMMON_CFG 0x7c
+#define		HSIO_SERDES6G_ANA_CFG_COMMON_CFG_IF_MODE(x)	(x)
+#define		HSIO_SERDES6G_ANA_CFG_COMMON_CFG_ENA_LANE	BIT(18)
+#define		HSIO_SERDES6G_ANA_CFG_COMMON_CFG_SYS_RST	BIT(31)
+#define HSIO_SERDES6G_ANA_CFG_PLL_CFG	0x80
+#define		HSIO_SERDES6G_ANA_CFG_PLL_CFG_FSM_ENA		BIT(7)
+#define		HSIO_SERDES6G_ANA_CFG_PLL_CFG_FSM_CTRL_DATA(x)	((x) << 8)
+#define HSIO_SERDES6G_ANA_CFG_SER_CFG	0x84
+#define HSIO_SERDES6G_DIG_CFG_MISC_CFG	0x88
+#define		HSIO_SERDES6G_DIG_CFG_MISC_CFG_LANE_RST		BIT(0)
+#define HSIO_MCB_SERDES6G_CFG		0xac
+#define		HSIO_MCB_SERDES6G_CFG_WR_ONE_SHOT		BIT(31)
+#define		HSIO_MCB_SERDES6G_CFG_ADDR(x)			(x)
+
+#define DEV_GMII_PORT_MODE_CLK		0x0
+#define		DEV_GMII_PORT_MODE_CLK_PHY_RST	BIT(0)
+#define DEV_GMII_MAC_CFG_MAC_ENA	0xc
+#define		DEV_GMII_MAC_CFG_MAC_ENA_RX_ENA		BIT(4)
+#define		DEV_GMII_MAC_CFG_MAC_ENA_TX_ENA		BIT(0)
+
+#define DEV_PORT_MODE_CLK		0x4
+#define		DEV_PORT_MODE_CLK_PHY_RST		BIT(2)
+#define		DEV_PORT_MODE_CLK_LINK_SPEED_1000	1
+#define DEV_MAC_CFG_MAC_ENA		0x10
+#define		DEV_MAC_CFG_MAC_ENA_RX_ENA		BIT(4)
+#define		DEV_MAC_CFG_MAC_ENA_TX_ENA		BIT(0)
+#define DEV_MAC_CFG_MAC_IFG		0x24
+#define		DEV_MAC_CFG_MAC_IFG_TX_IFG(x)		((x) << 8)
+#define		DEV_MAC_CFG_MAC_IFG_RX_IFG2(x)		((x) << 4)
+#define		DEV_MAC_CFG_MAC_IFG_RX_IFG1(x)		(x)
+#define DEV_PCS1G_CFG_PCS1G_CFG		0x40
+#define		DEV_PCS1G_CFG_PCS1G_CFG_PCS_ENA		BIT(0)
+#define DEV_PCS1G_CFG_PCS1G_MODE	0x44
+#define DEV_PCS1G_CFG_PCS1G_SD		0x48
+#define DEV_PCS1G_CFG_PCS1G_ANEG	0x4c
+#define		DEV_PCS1G_CFG_PCS1G_ANEG_ADV_ABILITY(x)	((x) << 16)
+
+#define XTR_EOF_0     (0x80000000u)
+#define XTR_EOF_1     (0x80000001u)
+#define XTR_EOF_2     (0x80000002u)
+#define XTR_EOF_3     (0x80000003u)
+#define XTR_PRUNED    (0x80000004u)
+#define XTR_ABORT     (0x80000005u)
+#define XTR_ESCAPE    (0x80000006u)
+#define XTR_NOT_READY (0x80000007u)
+
+#define IFH_INJ_BYPASS		BIT(31)
+#define IFH_TAG_TYPE_C		0
+#define XTR_VALID_BYTES(x)	(4 - ((x) & 3))
+#define MAC_VID			1
+#define CPU_PORT		26
+#define INTERNAL_PORT_MSK	0xFFFFFF
+#define IFH_LEN			2
+#define LUTON_BUF_CELL_SZ	60
+#define ETH_ALEN		6
+#define PGID_BROADCAST		28
+#define PGID_UNICAST		29
+#define PGID_SRC		80
+
+enum luton_target {
+	PORT0,
+	PORT1,
+	PORT2,
+	PORT3,
+	PORT4,
+	PORT5,
+	PORT6,
+	PORT7,
+	PORT8,
+	PORT9,
+	PORT10,
+	PORT11,
+	PORT12,
+	PORT13,
+	PORT14,
+	PORT15,
+	PORT16,
+	PORT17,
+	PORT18,
+	PORT19,
+	PORT20,
+	PORT21,
+	PORT22,
+	PORT23,
+	SYS,
+	ANA,
+	REW,
+	GCB,
+	QS,
+	HSIO,
+	TARGET_MAX,
+};
+
+#define MAX_PORT (PORT23 - PORT0 + 1)
+
+#define MIN_INT_PORT PORT0
+#define MAX_INT_PORT (PORT11 - PORT0  + 1)
+#define MIN_EXT_PORT PORT12
+#define MAX_EXT_PORT MAX_PORT
+
+/* MAC table entry types.
+ * ENTRYTYPE_NORMAL is subject to aging.
+ * ENTRYTYPE_LOCKED is not subject to aging.
+ */
+enum macaccess_entry_type {
+	ENTRYTYPE_NORMAL = 0,
+	ENTRYTYPE_LOCKED,
+};
+
+enum luton_mdio_target {
+	MIIM,
+	TARGET_MDIO_MAX,
+};
+
+enum luton_phy_id {
+	INTERNAL,
+	EXTERNAL,
+	NUM_PHY,
+};
+
+struct luton_private {
+	void __iomem *regs[TARGET_MAX];
+	struct mii_dev *bus[NUM_PHY];
+	struct luton_soc_data *data;
+};
+
+struct mscc_miim_dev {
+	void __iomem *regs;
+	void __iomem *phy_regs;
+};
+
+struct mscc_miim_dev miim[NUM_PHY];
+
+static int mscc_miim_wait_ready(struct mscc_miim_dev *miim)
+{
+	return wait_for_bit_le32(miim->regs + MIIM_STATUS, MIIM_STATUS_BUSY,
+				 false, 250, false);
+}
+
+static int mscc_miim_read(struct mii_dev *bus, int addr, int devad, int reg)
+{
+	struct mscc_miim_dev *miim = (struct mscc_miim_dev *)bus->priv;
+	u32 val;
+	int ret;
+
+	ret = mscc_miim_wait_ready(miim);
+	if (ret)
+		goto out;
+
+	writel(MIIM_CMD_VLD | MIIM_CMD_PHYAD(addr) |
+	       MIIM_CMD_REGAD(reg) | MIIM_CMD_OPR_READ,
+	       miim->regs + MIIM_CMD);
+
+	ret = mscc_miim_wait_ready(miim);
+	if (ret)
+		goto out;
+
+	val = readl(miim->regs + MIIM_DATA);
+	if (val & MIIM_DATA_ERROR) {
+		ret = -EIO;
+		goto out;
+	}
+
+	ret = val & 0xFFFF;
+ out:
+	return ret;
+}
+
+static int mscc_miim_write(struct mii_dev *bus, int addr, int devad, int reg,
+			   u16 val)
+{
+	struct mscc_miim_dev *miim = (struct mscc_miim_dev *)bus->priv;
+	int ret;
+
+	ret = mscc_miim_wait_ready(miim);
+	if (ret < 0)
+		goto out;
+
+	writel(MIIM_CMD_VLD | MIIM_CMD_PHYAD(addr) |
+	       MIIM_CMD_REGAD(reg) | MIIM_CMD_WRDATA(val) |
+	       MIIM_CMD_OPR_WRITE, miim->regs + MIIM_CMD);
+
+ out:
+	return ret;
+}
+
+static struct mii_dev *luton_mdiobus_init(struct udevice *dev,
+					  int mdiobus_id)
+{
+	unsigned long phy_size[NUM_PHY];
+	phys_addr_t phy_base[NUM_PHY];
+	struct ofnode_phandle_args phandle;
+	ofnode eth_node, node, mdio_node;
+	struct resource res;
+	struct mii_dev *bus;
+	fdt32_t faddr;
+	int i;
+
+	bus = mdio_alloc();
+	if (!bus)
+		return NULL;
+
+	/* gather only the first mdio bus */
+	eth_node = dev_read_first_subnode(dev);
+	node = ofnode_first_subnode(eth_node);
+	ofnode_parse_phandle_with_args(node, "phy-handle", NULL, 0, 0,
+				       &phandle);
+	mdio_node = ofnode_get_parent(phandle.node);
+
+	for (i = 0; i < TARGET_MDIO_MAX; i++) {
+		if (ofnode_read_resource(mdio_node, i, &res)) {
+			pr_err("%s: get OF resource failed\n", __func__);
+			return NULL;
+		}
+
+		faddr = cpu_to_fdt32(res.start);
+		phy_base[i] = ofnode_translate_address(mdio_node, &faddr);
+		phy_size[i] = res.end - res.start;
+	}
+
+	strcpy(bus->name, "miim-internal");
+	miim[mdiobus_id].regs = ioremap(phy_base[mdiobus_id],
+					phy_size[mdiobus_id]);
+	bus->priv = &miim[mdiobus_id];
+	bus->read = mscc_miim_read;
+	bus->write = mscc_miim_write;
+
+	if (mdio_register(bus))
+		return NULL;
+	else
+		return bus;
+}
+
+static void luton_cpu_capture_setup(struct luton_private *priv)
+{
+	int i;
+
+	/* map the 8 CPU extraction queues to CPU port 26 */
+	writel(0x0, priv->regs[SYS] + SYS_SCH_CPU);
+
+	for (i = 0; i <= 1; i++) {
+		/*
+		 * One to one mapping from CPU Queue number to Group extraction
+		 * number
+		 */
+		writel(QS_XTR_MAP_ENA | (QS_XTR_MAP_GRP * i),
+		       priv->regs[QS] + QS_XTR_MAP(i));
+
+		/* Enable IFH insertion/parsing on CPU ports */
+		setbits_le32(priv->regs[REW] + REW_PORT_CFG(CPU_PORT + i),
+			     REW_PORT_CFG_IFH_INSERT_ENA);
+
+		/* Enable IFH parsing on CPU port 0 and 1 */
+		setbits_le32(priv->regs[SYS] + SYS_PORT_MODE(CPU_PORT + i),
+			     SYS_PORT_MODE_INCL_INJ_HDR);
+	}
+
+	/* Make VLAN aware for CPU traffic */
+	writel(ANA_PORT_VLAN_CFG_AWARE_ENA |
+	       ANA_PORT_VLAN_CFG_POP_CNT(1) |
+	       MAC_VID,
+	       priv->regs[ANA] + ANA_PORT_VLAN_CFG(CPU_PORT));
+
+	/* Disable learning (only RECV_ENA must be set) */
+	writel(ANA_PORT_PORT_CFG_RECV_ENA,
+	       priv->regs[ANA] + ANA_PORT_PORT_CFG(CPU_PORT));
+
+	/* Enable switching to/from cpu port */
+	setbits_le32(priv->regs[SYS] + SYS_SWITCH_PORT_MODE(CPU_PORT),
+		     SYS_SWITCH_PORT_MODE_PORT_ENA);
+
+	setbits_le32(priv->regs[SYS] + SYS_EGR_NO_SHARING, BIT(CPU_PORT));
+}
+
+static void luton_gmii_port_init(struct luton_private *priv, int port)
+{
+	void __iomem *regs = priv->regs[port];
+
+	writel(0, regs + DEV_GMII_PORT_MODE_CLK);
+
+	/* Enable MAC RX and TX */
+	writel(DEV_GMII_MAC_CFG_MAC_ENA_RX_ENA |
+	       DEV_GMII_MAC_CFG_MAC_ENA_TX_ENA,
+	       regs + DEV_GMII_MAC_CFG_MAC_ENA);
+
+	/* Make VLAN aware for CPU traffic */
+	writel(ANA_PORT_VLAN_CFG_AWARE_ENA |
+	       ANA_PORT_VLAN_CFG_POP_CNT(1) |
+	       MAC_VID,
+	       priv->regs[ANA] + ANA_PORT_VLAN_CFG(port - PORT0));
+
+	/* Enable switching to/from port */
+	setbits_le32(priv->regs[SYS] + SYS_SWITCH_PORT_MODE(port - PORT0),
+		     SYS_SWITCH_PORT_MODE_PORT_ENA);
+}
+
+static void luton_port_init(struct luton_private *priv, int port)
+{
+	void __iomem *regs = priv->regs[port];
+
+	writel(0, regs + DEV_PORT_MODE_CLK);
+
+	/* Enable MAC RX and TX */
+	writel(DEV_MAC_CFG_MAC_ENA_RX_ENA |
+	       DEV_MAC_CFG_MAC_ENA_TX_ENA,
+	       regs + DEV_MAC_CFG_MAC_ENA);
+
+	/* Make VLAN aware for CPU traffic */
+	writel(ANA_PORT_VLAN_CFG_AWARE_ENA |
+	       ANA_PORT_VLAN_CFG_POP_CNT(1) |
+	       MAC_VID,
+	       priv->regs[ANA] + ANA_PORT_VLAN_CFG(port - PORT0));
+
+	/* Enable switching to/from port */
+	setbits_le32(priv->regs[SYS] + SYS_SWITCH_PORT_MODE(port - PORT0),
+		     SYS_SWITCH_PORT_MODE_PORT_ENA);
+}
+
+static void luton_ext_port_init(struct luton_private *priv, int port)
+{
+	void __iomem *regs = priv->regs[port];
+
+	/* Enable PCS */
+	writel(DEV_PCS1G_CFG_PCS1G_CFG_PCS_ENA,
+	       regs + DEV_PCS1G_CFG_PCS1G_CFG);
+
+	/* Disable Signal Detect */
+	writel(0, regs + DEV_PCS1G_CFG_PCS1G_SD);
+
+	/* Enable MAC RX and TX */
+	writel(DEV_MAC_CFG_MAC_ENA_RX_ENA |
+	       DEV_MAC_CFG_MAC_ENA_TX_ENA,
+	       regs + DEV_MAC_CFG_MAC_ENA);
+
+	/* Clear sgmii_mode_ena */
+	writel(0, regs + DEV_PCS1G_CFG_PCS1G_MODE);
+
+	/*
+	 * Clear sw_resolve_ena(bit 0) and set adv_ability to
+	 * something meaningful just in case
+	 */
+	writel(DEV_PCS1G_CFG_PCS1G_ANEG_ADV_ABILITY(0x20),
+	       regs + DEV_PCS1G_CFG_PCS1G_ANEG);
+
+	/* Set MAC IFG Gaps */
+	writel(DEV_MAC_CFG_MAC_IFG_TX_IFG(7) |
+	       DEV_MAC_CFG_MAC_IFG_RX_IFG1(1) |
+	       DEV_MAC_CFG_MAC_IFG_RX_IFG2(5),
+	       regs + DEV_MAC_CFG_MAC_IFG);
+
+	/* Set link speed and release all resets */
+	writel(DEV_PORT_MODE_CLK_LINK_SPEED_1000,
+	       regs + DEV_PORT_MODE_CLK);
+
+	/* Make VLAN aware for CPU traffic */
+	writel(ANA_PORT_VLAN_CFG_AWARE_ENA |
+	       ANA_PORT_VLAN_CFG_POP_CNT(1) |
+	       MAC_VID,
+	       priv->regs[ANA] + ANA_PORT_VLAN_CFG(port - PORT0));
+
+	/* Enable switching to/from port */
+	setbits_le32(priv->regs[SYS] + SYS_SWITCH_PORT_MODE(port - PORT0),
+		     SYS_SWITCH_PORT_MODE_PORT_ENA);
+}
+
+static void serdes6g_write(struct luton_private *priv, u32 addr)
+{
+	u32 data;
+
+	writel(HSIO_MCB_SERDES6G_CFG_WR_ONE_SHOT |
+	       HSIO_MCB_SERDES6G_CFG_ADDR(addr),
+	       priv->regs[HSIO] + HSIO_MCB_SERDES6G_CFG);
+
+	do {
+		data = readl(priv->regs[HSIO] + HSIO_MCB_SERDES6G_CFG);
+	} while (data & HSIO_MCB_SERDES6G_CFG_WR_ONE_SHOT);
+
+	mdelay(100);
+}
+
+static void serdes6g_cfg(struct luton_private *priv)
+{
+	writel(HSIO_RCOMP_CFG_CFG0_MODE_SEL(0x3) |
+	       HSIO_RCOMP_CFG_CFG0_RUN_CAL,
+	       priv->regs[HSIO] + HSIO_RCOMP_CFG_CFG0);
+
+	while (readl(priv->regs[HSIO] + HSIO_RCOMP_STATUS) &
+	       HSIO_RCOMP_STATUS_BUSY)
+		;
+
+	writel(HSIO_SERDES6G_ANA_CFG_OB_CFG_SR(0xb) |
+	       HSIO_SERDES6G_ANA_CFG_OB_CFG_SR_H |
+	       HSIO_SERDES6G_ANA_CFG_OB_CFG_POST0(0x10) |
+	       HSIO_SERDES6G_ANA_CFG_OB_CFG_POL |
+	       HSIO_SERDES6G_ANA_CFG_OB_CFG_ENA1V_MODE,
+	       priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_OB_CFG);
+	writel(HSIO_SERDES6G_ANA_CFG_OB_CFG1_LEV(0x18) |
+	       HSIO_SERDES6G_ANA_CFG_OB_CFG1_ENA_CAS(0x1),
+	       priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_OB_CFG1);
+	writel(HSIO_SERDES6G_ANA_CFG_IB_CFG_RESISTOR_CTRL(0xc) |
+	       HSIO_SERDES6G_ANA_CFG_IB_CFG_VBCOM(0x4) |
+	       HSIO_SERDES6G_ANA_CFG_IB_CFG_VBAC(0x5) |
+	       HSIO_SERDES6G_ANA_CFG_IB_CFG_RT(0xf) |
+	       HSIO_SERDES6G_ANA_CFG_IB_CFG_RF(0x4),
+	       priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_IB_CFG);
+	writel(HSIO_SERDES6G_ANA_CFG_IB_CFG1_RST |
+	       HSIO_SERDES6G_ANA_CFG_IB_CFG1_ENA_OFFSDC |
+	       HSIO_SERDES6G_ANA_CFG_IB_CFG1_ENA_OFFSAC |
+	       HSIO_SERDES6G_ANA_CFG_IB_CFG1_ANEG_MODE |
+	       HSIO_SERDES6G_ANA_CFG_IB_CFG1_CHF |
+	       HSIO_SERDES6G_ANA_CFG_IB_CFG1_C(0x4),
+	       priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_IB_CFG1);
+	writel(HSIO_SERDES6G_ANA_CFG_DES_CFG_BW_ANA(0x5) |
+	       HSIO_SERDES6G_ANA_CFG_DES_CFG_BW_HYST(0x5) |
+	       HSIO_SERDES6G_ANA_CFG_DES_CFG_MBTR_CTRL(0x2) |
+	       HSIO_SERDES6G_ANA_CFG_DES_CFG_PHS_CTRL(0x6),
+	       priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_DES_CFG);
+	writel(HSIO_SERDES6G_ANA_CFG_PLL_CFG_FSM_ENA |
+	       HSIO_SERDES6G_ANA_CFG_PLL_CFG_FSM_CTRL_DATA(0x78),
+	       priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_PLL_CFG);
+	writel(HSIO_SERDES6G_ANA_CFG_COMMON_CFG_IF_MODE(0x30) |
+	       HSIO_SERDES6G_ANA_CFG_COMMON_CFG_ENA_LANE,
+	       priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_COMMON_CFG);
+	/*
+	 * There are 4 serdes6g, configure all except serdes6g0, therefore
+	 * the address is b1110
+	 */
+	serdes6g_write(priv, 0xe);
+
+	writel(readl(priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_COMMON_CFG) |
+	       HSIO_SERDES6G_ANA_CFG_COMMON_CFG_SYS_RST,
+	       priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_COMMON_CFG);
+	serdes6g_write(priv, 0xe);
+
+	clrbits_le32(priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_IB_CFG1,
+		     HSIO_SERDES6G_ANA_CFG_IB_CFG1_RST);
+	writel(HSIO_SERDES6G_DIG_CFG_MISC_CFG_LANE_RST,
+	       priv->regs[HSIO] + HSIO_SERDES6G_DIG_CFG_MISC_CFG);
+	serdes6g_write(priv, 0xe);
+}
+
+static int luton_switch_init(struct luton_private *priv)
+{
+	setbits_le32(priv->regs[HSIO] + HSIO_PLL5G_CFG_PLL5G_CFG2, BIT(1));
+	clrbits_le32(priv->regs[HSIO] + HSIO_PLL5G_CFG_PLL5G_CFG2, BIT(1));
+
+	/* Reset switch & memories */
+	writel(SYS_SYSTEM_RST_MEM_ENA | SYS_SYSTEM_RST_MEM_INIT,
+	       priv->regs[SYS] + SYS_SYSTEM_RST_CFG);
+
+	/* Wait to complete */
+	if (wait_for_bit_le32(priv->regs[SYS] + SYS_SYSTEM_RST_CFG,
+			      SYS_SYSTEM_RST_MEM_INIT, false, 2000, false)) {
+		printf("Timeout in memory reset\n");
+	}
+
+	/* Enable switch core */
+	setbits_le32(priv->regs[SYS] + SYS_SYSTEM_RST_CFG,
+		     SYS_SYSTEM_RST_CORE_ENA);
+
+	/* Setup the Serdes6g macros */
+	serdes6g_cfg(priv);
+
+	return 0;
+}
+
+static void luton_switch_flush(struct luton_private *priv)
+{
+	/* All Queues flush */
+	setbits_le32(priv->regs[QS] + QS_XTR_FLUSH, QS_XTR_FLUSH_FLUSH);
+
+	/* Allow to drain */
+	mdelay(1);
+
+	/* All Queues normal */
+	clrbits_le32(priv->regs[QS] + QS_XTR_FLUSH, QS_XTR_FLUSH_FLUSH);
+}
+
+static int luton_initialize(struct luton_private *priv)
+{
+	int ret, i;
+
+	/* Initialize switch memories, enable core */
+	ret = luton_switch_init(priv);
+	if (ret)
+		return ret;
+
+	/*
+	 * Disable port-to-port by switching
+	 * Put front ports in "port isolation modes" - i.e. they can't send
+	 * to other ports - via the PGID sorce masks.
+	 */
+	for (i = 0; i < MAX_PORT; i++)
+		writel(0, priv->regs[ANA] + ANA_PGID(PGID_SRC + i));
+
+	/* Flush queues */
+	luton_switch_flush(priv);
+
+	/* Setup frame ageing - "2 sec" - The unit is 4ns on Luton*/
+	writel(2000000000 / 4,
+	       priv->regs[SYS] + SYS_FRM_AGING);
+
+	for (i = PORT0; i < MAX_PORT; i++) {
+		if (i < PORT10)
+			luton_gmii_port_init(priv, i);
+		else
+			if (i == PORT10 || i == PORT11)
+				luton_port_init(priv, i);
+			else
+				luton_ext_port_init(priv, i);
+	}
+
+	luton_cpu_capture_setup(priv);
+
+	return 0;
+}
+
+static inline int luton_vlant_wait_for_completion(struct luton_private *priv)
+{
+	unsigned int val, timeout = 10;
+
+	/*
+	 * Wait for the issued mac table command to be completed, or timeout.
+	 * When the command read from ANA_TABLES_MACACCESS is
+	 * MACACCESS_CMD_IDLE, the issued command completed successfully.
+	 */
+	do {
+		val = readl(priv->regs[ANA] + ANA_TABLES_MACACCESS);
+		val &= ANA_TABLES_MACACCESS_MAC_TABLE_CMD_M;
+	} while (val != MACACCESS_CMD_IDLE && timeout--);
+
+	if (!timeout)
+		return -ETIMEDOUT;
+
+	return 0;
+}
+
+static int luton_mac_table_add(struct luton_private *priv,
+			       const unsigned char mac[ETH_ALEN], int pgid)
+{
+	u32 macl = 0, mach = 0;
+	int ret;
+
+	/*
+	 * Set the MAC address to handle and the vlan associated in a format
+	 * understood by the hardware.
+	 */
+	mach |= MAC_VID << 16;
+	mach |= ((u32)mac[0]) << 8;
+	mach |= ((u32)mac[1]) << 0;
+	macl |= ((u32)mac[2]) << 24;
+	macl |= ((u32)mac[3]) << 16;
+	macl |= ((u32)mac[4]) << 8;
+	macl |= ((u32)mac[5]) << 0;
+
+	writel(macl, priv->regs[ANA] + ANA_TABLES_MACLDATA);
+	writel(mach, priv->regs[ANA] + ANA_TABLES_MACHDATA);
+
+	writel(ANA_TABLES_MACACCESS_VALID |
+	       ANA_TABLES_MACACCESS_DEST_IDX(pgid) |
+	       ANA_TABLES_MACACCESS_ENTRYTYPE(ENTRYTYPE_LOCKED) |
+	       ANA_TABLES_MACACCESS_MAC_TABLE_CMD(MACACCESS_CMD_LEARN),
+	       priv->regs[ANA] + ANA_TABLES_MACACCESS);
+
+	ret = luton_vlant_wait_for_completion(priv);
+
+	return ret;
+}
+
+static int luton_write_hwaddr(struct udevice *dev)
+{
+	struct luton_private *priv = dev_get_priv(dev);
+	struct eth_pdata *pdata = dev_get_platdata(dev);
+
+	luton_mac_table_add(priv, pdata->enetaddr, PGID_UNICAST);
+
+	writel(BIT(CPU_PORT), priv->regs[ANA] + ANA_PGID(PGID_UNICAST));
+
+	return 0;
+}
+
+static int luton_start(struct udevice *dev)
+{
+	struct luton_private *priv = dev_get_priv(dev);
+	struct eth_pdata *pdata = dev_get_platdata(dev);
+	const unsigned char mac[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff,
+					      0xff };
+	int ret;
+
+	ret = luton_initialize(priv);
+	if (ret)
+		return ret;
+
+	/* Set MAC address tables entries for CPU redirection */
+	luton_mac_table_add(priv, mac, PGID_BROADCAST);
+
+	writel(BIT(CPU_PORT) | INTERNAL_PORT_MSK,
+	       priv->regs[ANA] + ANA_PGID(PGID_BROADCAST));
+
+	luton_mac_table_add(priv, pdata->enetaddr, PGID_UNICAST);
+
+	writel(BIT(CPU_PORT), priv->regs[ANA] + ANA_PGID(PGID_UNICAST));
+
+	return 0;
+}
+
+static void luton_stop(struct udevice *dev)
+{
+	struct luton_private *priv = dev_get_priv(dev);
+
+	/*
+	 * Switch core only reset affects VCORE-III bus and MIPS frequency
+	 * and thereby also the DDR SDRAM controller. The workaround is to
+	 * not to redirect any trafic to the CPU after the data transfer.
+	 */
+	writel(GENMASK(9, 2), priv->regs[SYS] + SYS_SCH_CPU);
+}
+
+static int luton_send(struct udevice *dev, void *packet, int length)
+{
+	struct luton_private *priv = dev_get_priv(dev);
+	u32 ifh[IFH_LEN];
+	int port = BIT(0);	/* use port 0 */
+	u8 grp = 0;		/* Send everything on CPU group 0 */
+	int i, count = (length + 3) / 4, last = length % 4;
+	u32 *buf = packet;
+
+	writel(QS_INJ_CTRL_GAP_SIZE(1) | QS_INJ_CTRL_SOF,
+	       priv->regs[QS] + QS_INJ_CTRL(grp));
+
+	ifh[0] = IFH_INJ_BYPASS | port;
+	ifh[1] = (IFH_TAG_TYPE_C << 16);
+
+	for (i = 0; i < IFH_LEN; i++)
+		writel(ifh[i], priv->regs[QS] + QS_INJ_WR(grp));
+
+	for (i = 0; i < count; i++)
+		writel(buf[i], priv->regs[QS] + QS_INJ_WR(grp));
+
+	/* Add padding */
+	while (i < (LUTON_BUF_CELL_SZ / 4)) {
+		writel(0, priv->regs[QS] + QS_INJ_WR(grp));
+		i++;
+	}
+
+	/* Indicate EOF and valid bytes in last word */
+	writel(QS_INJ_CTRL_GAP_SIZE(1) |
+	       QS_INJ_CTRL_VLD_BYTES(length < LUTON_BUF_CELL_SZ ? 0 : last) |
+	       QS_INJ_CTRL_EOF, priv->regs[QS] + QS_INJ_CTRL(grp));
+
+	/* Add dummy CRC */
+	writel(0, priv->regs[QS] + QS_INJ_WR(grp));
+
+	return 0;
+}
+
+static int luton_recv(struct udevice *dev, int flags, uchar **packetp)
+{
+	struct luton_private *priv = dev_get_priv(dev);
+	u8 grp = 0;		/* Recv everything on CPU group 0 */
+	u32 *rxbuf = (u32 *)net_rx_packets[0];
+	int byte_cnt = 0;
+	int i = 0;
+	bool eof_flag = false, pruned_flag = false, abort_flag = false;
+
+	if (!(readl(priv->regs[QS] + QS_XTR_DATA_PRESENT) & BIT(grp)))
+		return -EAGAIN;
+
+	/* skip IFH */
+	for (i = 0; i < IFH_LEN; i++)
+		readl(priv->regs[QS] + QS_XTR_RD(grp));
+
+	while (!eof_flag) {
+		u32 val = readl(priv->regs[QS] + QS_XTR_RD(grp));
+
+		switch (val) {
+		case XTR_NOT_READY:
+			debug("%d NOT_READY...?\n", byte_cnt);
+			break;
+		case XTR_ABORT:
+			/* really nedeed?? not done in linux */
+			*rxbuf = readl(priv->regs[QS] + QS_XTR_RD(grp));
+			abort_flag = true;
+			eof_flag = true;
+			debug("XTR_ABORT\n");
+			break;
+		case XTR_EOF_0:
+		case XTR_EOF_1:
+		case XTR_EOF_2:
+		case XTR_EOF_3:
+			byte_cnt += XTR_VALID_BYTES(val);
+			*rxbuf = readl(priv->regs[QS] + QS_XTR_RD(grp));
+			eof_flag = true;
+			debug("EOF\n");
+			break;
+		case XTR_PRUNED:
+			/* But get the last 4 bytes as well */
+			eof_flag = true;
+			pruned_flag = true;
+			debug("PRUNED\n");
+			/* fallthrough */
+		case XTR_ESCAPE:
+			*rxbuf = readl(priv->regs[QS] + QS_XTR_RD(grp));
+			byte_cnt += 4;
+			rxbuf++;
+			debug("ESCAPED\n");
+			break;
+		default:
+			*rxbuf = val;
+			byte_cnt += 4;
+			rxbuf++;
+		}
+	}
+
+	if (abort_flag || pruned_flag || !eof_flag) {
+		debug("Discarded frame: abort:%d pruned:%d eof:%d\n",
+		      abort_flag, pruned_flag, eof_flag);
+		return -EAGAIN;
+	}
+
+	*packetp = net_rx_packets[0];
+
+	return byte_cnt;
+}
+
+static int luton_probe(struct udevice *dev)
+{
+	struct luton_private *priv = dev_get_priv(dev);
+	int i;
+
+	struct {
+		enum luton_target id;
+		char *name;
+	} reg[] = {
+		{ PORT0, "port0" },
+		{ PORT1, "port1" },
+		{ PORT2, "port2" },
+		{ PORT3, "port3" },
+		{ PORT4, "port4" },
+		{ PORT5, "port5" },
+		{ PORT6, "port6" },
+		{ PORT7, "port7" },
+		{ PORT8, "port8" },
+		{ PORT9, "port9" },
+		{ PORT10, "port10" },
+		{ PORT11, "port11" },
+		{ PORT12, "port12" },
+		{ PORT13, "port13" },
+		{ PORT14, "port14" },
+		{ PORT15, "port15" },
+		{ PORT16, "port16" },
+		{ PORT17, "port17" },
+		{ PORT18, "port18" },
+		{ PORT19, "port19" },
+		{ PORT20, "port20" },
+		{ PORT21, "port21" },
+		{ PORT22, "port22" },
+		{ PORT23, "port23" },
+		{ SYS, "sys" },
+		{ ANA, "ana" },
+		{ REW, "rew" },
+		{ GCB, "gcb" },
+		{ QS, "qs" },
+		{ HSIO, "hsio" },
+	};
+
+	if (!priv)
+		return -EINVAL;
+
+	for (i = 0; i < ARRAY_SIZE(reg); i++) {
+		priv->regs[reg[i].id] = dev_remap_addr_name(dev, reg[i].name);
+		if (!priv->regs[reg[i].id]) {
+			debug
+			    ("Error can't get regs base addresses for %s\n",
+			     reg[i].name);
+			return -ENOMEM;
+		}
+	}
+
+	/* Release reset in the CU-PHY */
+	writel(0, priv->regs[GCB] + GCB_DEVCPU_RST_SOFT_CHIP_RST);
+
+	/* Ports with ext phy don't need to reset clk */
+	for (i = PORT0; i < MAX_INT_PORT; i++) {
+		if (i < PORT10)
+			clrbits_le32(priv->regs[i] + DEV_GMII_PORT_MODE_CLK,
+				     DEV_GMII_PORT_MODE_CLK_PHY_RST);
+		else
+			clrbits_le32(priv->regs[i] + DEV_PORT_MODE_CLK,
+				     DEV_PORT_MODE_CLK_PHY_RST);
+	}
+
+	/* Wait for internal PHY to be ready */
+	if (wait_for_bit_le32(priv->regs[GCB] + GCB_MISC_STAT,
+			      GCB_MISC_STAT_PHY_READY, true, 500, false))
+		return -EACCES;
+
+	priv->bus[INTERNAL] = luton_mdiobus_init(dev, INTERNAL);
+
+	for (i = 0; i < MAX_INT_PORT; i++) {
+		phy_connect(priv->bus[INTERNAL], i, dev,
+			    PHY_INTERFACE_MODE_NONE);
+	}
+
+	/*
+	 * coma_mode is need on only one phy, because all the other phys
+	 * will be affected.
+	 */
+	mscc_miim_write(priv->bus[INTERNAL], 0, 0, 31, 0x10);
+	mscc_miim_write(priv->bus[INTERNAL], 0, 0, 14, 0x800);
+	mscc_miim_write(priv->bus[INTERNAL], 0, 0, 31, 0);
+
+	return 0;
+}
+
+static int luton_remove(struct udevice *dev)
+{
+	struct luton_private *priv = dev_get_priv(dev);
+	int i;
+
+	for (i = 0; i < NUM_PHY; i++) {
+		mdio_unregister(priv->bus[i]);
+		mdio_free(priv->bus[i]);
+	}
+
+	return 0;
+}
+
+static const struct eth_ops luton_ops = {
+	.start        = luton_start,
+	.stop         = luton_stop,
+	.send         = luton_send,
+	.recv         = luton_recv,
+	.write_hwaddr = luton_write_hwaddr,
+};
+
+static const struct udevice_id mscc_luton_ids[] = {
+	{.compatible = "mscc,vsc7527-switch", },
+	{ /* Sentinel */ }
+};
+
+U_BOOT_DRIVER(luton) = {
+	.name     = "luton-switch",
+	.id       = UCLASS_ETH,
+	.of_match = mscc_luton_ids,
+	.probe	  = luton_probe,
+	.remove	  = luton_remove,
+	.ops	  = &luton_ops,
+	.priv_auto_alloc_size = sizeof(struct luton_private),
+	.platdata_auto_alloc_size = sizeof(struct eth_pdata),
+};
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [U-Boot] [PATCH 3/3] configs: mscc_luton: add network support.
  2019-01-28 10:29 [U-Boot] [PATCH 0/3] Add network support for Luton SoCs Horatiu Vultur
  2019-01-28 10:29 ` [U-Boot] [PATCH 1/3] MIPS: mscc: luton: Add ethernet nodes for Luton Horatiu Vultur
  2019-01-28 10:29 ` [U-Boot] [PATCH 2/3] net: add MSCC Luton switch support Horatiu Vultur
@ 2019-01-28 10:29 ` Horatiu Vultur
  2 siblings, 0 replies; 5+ messages in thread
From: Horatiu Vultur @ 2019-01-28 10:29 UTC (permalink / raw)
  To: u-boot

Update default config to use network driver for Luton SoC.

Signed-off-by: Horatiu Vultur <horatiu.vultur@microchip.com>
---
 configs/mscc_luton_defconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/configs/mscc_luton_defconfig b/configs/mscc_luton_defconfig
index 7154e97..0fdd9b8 100644
--- a/configs/mscc_luton_defconfig
+++ b/configs/mscc_luton_defconfig
@@ -60,6 +60,7 @@ CONFIG_SPI_FLASH_STMICRO=y
 CONFIG_SPI_FLASH_WINBOND=y
 CONFIG_SPI_FLASH_MTD=y
 CONFIG_DM_ETH=y
+CONFIG_MSCC_LUTON_SWITCH=y
 CONFIG_PINCTRL=y
 CONFIG_PINCONF=y
 CONFIG_DM_SERIAL=y
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [U-Boot] [PATCH 2/3] net: add MSCC Luton switch support
  2019-01-28 10:29 ` [U-Boot] [PATCH 2/3] net: add MSCC Luton switch support Horatiu Vultur
@ 2019-01-28 13:22   ` Gregory CLEMENT
  0 siblings, 0 replies; 5+ messages in thread
From: Gregory CLEMENT @ 2019-01-28 13:22 UTC (permalink / raw)
  To: u-boot

Hi Horatiu,
 
 On lun., janv. 28 2019, Horatiu Vultur <horatiu.vultur@microchip.com> wrote:

> Add network driver for Microsemi Ethernet switch is present
> on Luton SoCs.
>
> Signed-off-by: Horatiu Vultur <horatiu.vultur@microchip.com>
> ---
>  MAINTAINERS                |   1 +
>  drivers/net/Kconfig        |   7 +
>  drivers/net/Makefile       |   1 +
>  drivers/net/luton_switch.c | 972 +++++++++++++++++++++++++++++++++++++++++++++

This file is pretty similar to drivers/net/ocelot_switch.c that means
that the support of luton should be merged in this driver as it was done
for the pinctrl.

Gregory

>  4 files changed, 981 insertions(+)
>  create mode 100644 drivers/net/luton_switch.c
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 1cb092e..253274b 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -540,6 +540,7 @@ F:	drivers/spi/mscc_bb_spi.c
>  F:	include/configs/vcoreiii.h
>  F:	drivers/pinctrl/mscc/
>  F:	drivers/net/ocelot_switch.c
> +F:	drivers/net/luton_switch.c
>  
>  MIPS JZ4780
>  M:	Ezequiel Garcia <ezequiel@collabora.com>
> diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
> index 39ce4e8..d82037d 100644
> --- a/drivers/net/Kconfig
> +++ b/drivers/net/Kconfig
> @@ -439,6 +439,13 @@ config MSCC_OCELOT_SWITCH
>  	help
>  	  This driver supports the Ocelot network switch device.
>  
> +config MSCC_LUTON_SWITCH
> +	bool "Luton switch driver"
> +	depends on DM_ETH && ARCH_MSCC
> +	select PHYLIB
> +	help
> +	  This driver supports the Luton network switch device.
> +
>  config ETHER_ON_FEC1
>  	bool "FEC1"
>  	depends on MPC8XX_FEC
> diff --git a/drivers/net/Makefile b/drivers/net/Makefile
> index e38c164..470660d 100644
> --- a/drivers/net/Makefile
> +++ b/drivers/net/Makefile
> @@ -76,3 +76,4 @@ obj-$(CONFIG_SNI_AVE) += sni_ave.o
>  obj-y += ti/
>  obj-$(CONFIG_MEDIATEK_ETH) += mtk_eth.o
>  obj-$(CONFIG_MSCC_OCELOT_SWITCH) += ocelot_switch.o
> +obj-$(CONFIG_MSCC_LUTON_SWITCH) += luton_switch.o
> diff --git a/drivers/net/luton_switch.c b/drivers/net/luton_switch.c
> new file mode 100644
> index 0000000..816b5fe
> --- /dev/null
> +++ b/drivers/net/luton_switch.c
> @@ -0,0 +1,972 @@
> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> +/*
> + * Copyright (c) 2019 Microsemi Corporation
> + */
> +
> +#include <common.h>
> +#include <config.h>
> +#include <dm.h>
> +#include <dm/of_access.h>
> +#include <dm/of_addr.h>
> +#include <fdt_support.h>
> +#include <linux/io.h>
> +#include <linux/ioport.h>
> +#include <miiphy.h>
> +#include <net.h>
> +#include <wait_bit.h>
> +
> +#define MIIM_STATUS		0x0
> +#define		MIIM_STATUS_BUSY		BIT(3)
> +#define MIIM_CMD		0x8
> +#define		MIIM_CMD_SCAN		BIT(0)
> +#define		MIIM_CMD_OPR_WRITE		BIT(1)
> +#define		MIIM_CMD_OPR_READ		BIT(2)
> +#define		MIIM_CMD_SINGLE_SCAN	BIT(3)
> +#define		MIIM_CMD_WRDATA(x)		((x) << 4)
> +#define		MIIM_CMD_REGAD(x)		((x) << 20)
> +#define		MIIM_CMD_PHYAD(x)		((x) << 25)
> +#define		MIIM_CMD_VLD		BIT(31)
> +#define MIIM_DATA		0xC
> +#define		MIIM_DATA_ERROR		(0x3 << 16)
> +
> +#define ANA_PORT_VLAN_CFG(x)		(0x00 + 0x80 * (x))
> +#define		ANA_PORT_VLAN_CFG_AWARE_ENA	BIT(20)
> +#define		ANA_PORT_VLAN_CFG_POP_CNT(x)	((x) << 18)
> +#define ANA_PORT_CPU_FWD_CFG(x)		(0x50 + 0x80 * (x))
> +#define		ANA_PORT_CPU_FWD_CFG_SRC_COPY_ENA	BIT(1)
> +#define ANA_PORT_PORT_CFG(x)		(0x60 + 0x80 * (x))
> +#define		ANA_PORT_PORT_CFG_RECV_ENA	BIT(5)
> +#define ANA_TABLES_MACHDATA		0x11b0
> +#define ANA_TABLES_MACLDATA		0x11b4
> +#define ANA_TABLES_MACACCESS		0x11b8
> +#define		ANA_TABLES_MACACCESS_MAC_CPU_COPY	BIT(15)
> +#define		ANA_TABLES_MACACCESS_VALID		BIT(11)
> +#define		ANA_TABLES_MACACCESS_ENTRYTYPE(x)	((x) << 9)
> +#define		ANA_TABLES_MACACCESS_DEST_IDX(x)	((x) << 3)
> +#define		ANA_TABLES_MACACCESS_MAC_TABLE_CMD(x)	(x)
> +#define		ANA_TABLES_MACACCESS_MAC_TABLE_CMD_M	GENMASK(2, 0)
> +#define		MACACCESS_CMD_IDLE		0
> +#define		MACACCESS_CMD_LEARN		1
> +#define ANA_PGID(x)			(0x1000 + 4 * (x))
> +
> +#define SYS_FRM_AGING			0x8300
> +
> +#define SYS_SYSTEM_RST_CFG		0x81b0
> +#define		SYS_SYSTEM_RST_MEM_INIT		BIT(0)
> +#define		SYS_SYSTEM_RST_MEM_ENA		BIT(1)
> +#define		SYS_SYSTEM_RST_CORE_ENA		BIT(2)
> +#define SYS_PORT_MODE(x)		(0x81bc + 0x4 * (x))
> +#define		SYS_PORT_MODE_INCL_INJ_HDR	BIT(0)
> +#define SYS_SWITCH_PORT_MODE(x)		(0x8294 + 0x4 * (x))
> +#define		SYS_SWITCH_PORT_MODE_PORT_ENA	BIT(3)
> +#define SYS_EGR_NO_SHARING		0x8378
> +#define SYS_SCH_CPU			0x85a0
> +
> +#define REW_PORT_CFG(x)			(0x8 + 0x80 * (x))
> +#define		REW_PORT_CFG_IFH_INSERT_ENA	BIT(7)
> +
> +#define GCB_DEVCPU_RST_SOFT_CHIP_RST	0x90
> +#define		GCB_DEVCPU_RST_SOFT_CHIP_RST_SOFT_PHY	BIT(1)
> +#define GCB_MISC_STAT			0x11c
> +#define		GCB_MISC_STAT_PHY_READY			BIT(3)
> +
> +#define	QS_XTR_MAP(x)			(0x10 + 4 * (x))
> +#define		QS_XTR_MAP_GRP			BIT(4)
> +#define		QS_XTR_MAP_ENA			BIT(0)
> +#define QS_XTR_RD(x)			(0x18 + 4 * (x))
> +#define QS_XTR_FLUSH			0x28
> +#define		QS_XTR_FLUSH_FLUSH		BIT(0)
> +#define QS_XTR_DATA_PRESENT		0x2c
> +#define QS_INJ_WR(x)			(0x3c + 4 * (x))
> +#define QS_INJ_CTRL(x)			(0x44 + 4 * (x))
> +#define		QS_INJ_CTRL_GAP_SIZE(x)		((x) << 21)
> +#define		QS_INJ_CTRL_EOF			BIT(19)
> +#define		QS_INJ_CTRL_SOF			BIT(18)
> +#define		QS_INJ_CTRL_VLD_BYTES(x)	((x) << 16)
> +
> +#define HSIO_PLL5G_CFG_PLL5G_CFG2	0x8
> +
> +#define HSIO_RCOMP_CFG_CFG0		0x20
> +#define		HSIO_RCOMP_CFG_CFG0_MODE_SEL(x)			((x) << 8)
> +#define		HSIO_RCOMP_CFG_CFG0_RUN_CAL			BIT(12)
> +#define HSIO_RCOMP_STATUS		0x24
> +#define		HSIO_RCOMP_STATUS_BUSY				BIT(12)
> +#define		HSIO_RCOMP_STATUS_RCOMP_M			GENMASK(3, 0)
> +#define HSIO_SERDES6G_ANA_CFG_DES_CFG	0x64
> +#define		HSIO_SERDES6G_ANA_CFG_DES_CFG_BW_ANA(x)		((x) << 1)
> +#define		HSIO_SERDES6G_ANA_CFG_DES_CFG_BW_HYST(x)	((x) << 5)
> +#define		HSIO_SERDES6G_ANA_CFG_DES_CFG_MBTR_CTRL(x)	((x) << 10)
> +#define		HSIO_SERDES6G_ANA_CFG_DES_CFG_PHS_CTRL(x)	((x) << 13)
> +#define HSIO_SERDES6G_ANA_CFG_IB_CFG	0x68
> +#define		HSIO_SERDES6G_ANA_CFG_IB_CFG_RESISTOR_CTRL(x)	(x)
> +#define		HSIO_SERDES6G_ANA_CFG_IB_CFG_VBCOM(x)		((x) << 4)
> +#define		HSIO_SERDES6G_ANA_CFG_IB_CFG_VBAC(x)		((x) << 7)
> +#define		HSIO_SERDES6G_ANA_CFG_IB_CFG_RT(x)		((x) << 9)
> +#define		HSIO_SERDES6G_ANA_CFG_IB_CFG_RF(x)		((x) << 14)
> +#define HSIO_SERDES6G_ANA_CFG_IB_CFG1	0x6c
> +#define		HSIO_SERDES6G_ANA_CFG_IB_CFG1_RST		BIT(0)
> +#define		HSIO_SERDES6G_ANA_CFG_IB_CFG1_ENA_OFFSDC	BIT(2)
> +#define		HSIO_SERDES6G_ANA_CFG_IB_CFG1_ENA_OFFSAC	BIT(3)
> +#define		HSIO_SERDES6G_ANA_CFG_IB_CFG1_ANEG_MODE	BIT(6)
> +#define		HSIO_SERDES6G_ANA_CFG_IB_CFG1_CHF		BIT(7)
> +#define		HSIO_SERDES6G_ANA_CFG_IB_CFG1_C(x)		((x) << 8)
> +#define HSIO_SERDES6G_ANA_CFG_OB_CFG	0x70
> +#define		HSIO_SERDES6G_ANA_CFG_OB_CFG_SR(x)		((x) << 4)
> +#define		HSIO_SERDES6G_ANA_CFG_OB_CFG_SR_H		BIT(8)
> +#define		HSIO_SERDES6G_ANA_CFG_OB_CFG_POST0(x)		((x) << 23)
> +#define		HSIO_SERDES6G_ANA_CFG_OB_CFG_POL		BIT(29)
> +#define		HSIO_SERDES6G_ANA_CFG_OB_CFG_ENA1V_MODE	BIT(30)
> +#define HSIO_SERDES6G_ANA_CFG_OB_CFG1	0x74
> +#define		HSIO_SERDES6G_ANA_CFG_OB_CFG1_LEV(x)		(x)
> +#define		HSIO_SERDES6G_ANA_CFG_OB_CFG1_ENA_CAS(x)	((x) << 6)
> +#define HSIO_SERDES6G_ANA_CFG_COMMON_CFG 0x7c
> +#define		HSIO_SERDES6G_ANA_CFG_COMMON_CFG_IF_MODE(x)	(x)
> +#define		HSIO_SERDES6G_ANA_CFG_COMMON_CFG_ENA_LANE	BIT(18)
> +#define		HSIO_SERDES6G_ANA_CFG_COMMON_CFG_SYS_RST	BIT(31)
> +#define HSIO_SERDES6G_ANA_CFG_PLL_CFG	0x80
> +#define		HSIO_SERDES6G_ANA_CFG_PLL_CFG_FSM_ENA		BIT(7)
> +#define		HSIO_SERDES6G_ANA_CFG_PLL_CFG_FSM_CTRL_DATA(x)	((x) << 8)
> +#define HSIO_SERDES6G_ANA_CFG_SER_CFG	0x84
> +#define HSIO_SERDES6G_DIG_CFG_MISC_CFG	0x88
> +#define		HSIO_SERDES6G_DIG_CFG_MISC_CFG_LANE_RST		BIT(0)
> +#define HSIO_MCB_SERDES6G_CFG		0xac
> +#define		HSIO_MCB_SERDES6G_CFG_WR_ONE_SHOT		BIT(31)
> +#define		HSIO_MCB_SERDES6G_CFG_ADDR(x)			(x)
> +
> +#define DEV_GMII_PORT_MODE_CLK		0x0
> +#define		DEV_GMII_PORT_MODE_CLK_PHY_RST	BIT(0)
> +#define DEV_GMII_MAC_CFG_MAC_ENA	0xc
> +#define		DEV_GMII_MAC_CFG_MAC_ENA_RX_ENA		BIT(4)
> +#define		DEV_GMII_MAC_CFG_MAC_ENA_TX_ENA		BIT(0)
> +
> +#define DEV_PORT_MODE_CLK		0x4
> +#define		DEV_PORT_MODE_CLK_PHY_RST		BIT(2)
> +#define		DEV_PORT_MODE_CLK_LINK_SPEED_1000	1
> +#define DEV_MAC_CFG_MAC_ENA		0x10
> +#define		DEV_MAC_CFG_MAC_ENA_RX_ENA		BIT(4)
> +#define		DEV_MAC_CFG_MAC_ENA_TX_ENA		BIT(0)
> +#define DEV_MAC_CFG_MAC_IFG		0x24
> +#define		DEV_MAC_CFG_MAC_IFG_TX_IFG(x)		((x) << 8)
> +#define		DEV_MAC_CFG_MAC_IFG_RX_IFG2(x)		((x) << 4)
> +#define		DEV_MAC_CFG_MAC_IFG_RX_IFG1(x)		(x)
> +#define DEV_PCS1G_CFG_PCS1G_CFG		0x40
> +#define		DEV_PCS1G_CFG_PCS1G_CFG_PCS_ENA		BIT(0)
> +#define DEV_PCS1G_CFG_PCS1G_MODE	0x44
> +#define DEV_PCS1G_CFG_PCS1G_SD		0x48
> +#define DEV_PCS1G_CFG_PCS1G_ANEG	0x4c
> +#define		DEV_PCS1G_CFG_PCS1G_ANEG_ADV_ABILITY(x)	((x) << 16)
> +
> +#define XTR_EOF_0     (0x80000000u)
> +#define XTR_EOF_1     (0x80000001u)
> +#define XTR_EOF_2     (0x80000002u)
> +#define XTR_EOF_3     (0x80000003u)
> +#define XTR_PRUNED    (0x80000004u)
> +#define XTR_ABORT     (0x80000005u)
> +#define XTR_ESCAPE    (0x80000006u)
> +#define XTR_NOT_READY (0x80000007u)
> +
> +#define IFH_INJ_BYPASS		BIT(31)
> +#define IFH_TAG_TYPE_C		0
> +#define XTR_VALID_BYTES(x)	(4 - ((x) & 3))
> +#define MAC_VID			1
> +#define CPU_PORT		26
> +#define INTERNAL_PORT_MSK	0xFFFFFF
> +#define IFH_LEN			2
> +#define LUTON_BUF_CELL_SZ	60
> +#define ETH_ALEN		6
> +#define PGID_BROADCAST		28
> +#define PGID_UNICAST		29
> +#define PGID_SRC		80
> +
> +enum luton_target {
> +	PORT0,
> +	PORT1,
> +	PORT2,
> +	PORT3,
> +	PORT4,
> +	PORT5,
> +	PORT6,
> +	PORT7,
> +	PORT8,
> +	PORT9,
> +	PORT10,
> +	PORT11,
> +	PORT12,
> +	PORT13,
> +	PORT14,
> +	PORT15,
> +	PORT16,
> +	PORT17,
> +	PORT18,
> +	PORT19,
> +	PORT20,
> +	PORT21,
> +	PORT22,
> +	PORT23,
> +	SYS,
> +	ANA,
> +	REW,
> +	GCB,
> +	QS,
> +	HSIO,
> +	TARGET_MAX,
> +};
> +
> +#define MAX_PORT (PORT23 - PORT0 + 1)
> +
> +#define MIN_INT_PORT PORT0
> +#define MAX_INT_PORT (PORT11 - PORT0  + 1)
> +#define MIN_EXT_PORT PORT12
> +#define MAX_EXT_PORT MAX_PORT
> +
> +/* MAC table entry types.
> + * ENTRYTYPE_NORMAL is subject to aging.
> + * ENTRYTYPE_LOCKED is not subject to aging.
> + */
> +enum macaccess_entry_type {
> +	ENTRYTYPE_NORMAL = 0,
> +	ENTRYTYPE_LOCKED,
> +};
> +
> +enum luton_mdio_target {
> +	MIIM,
> +	TARGET_MDIO_MAX,
> +};
> +
> +enum luton_phy_id {
> +	INTERNAL,
> +	EXTERNAL,
> +	NUM_PHY,
> +};
> +
> +struct luton_private {
> +	void __iomem *regs[TARGET_MAX];
> +	struct mii_dev *bus[NUM_PHY];
> +	struct luton_soc_data *data;
> +};
> +
> +struct mscc_miim_dev {
> +	void __iomem *regs;
> +	void __iomem *phy_regs;
> +};
> +
> +struct mscc_miim_dev miim[NUM_PHY];
> +
> +static int mscc_miim_wait_ready(struct mscc_miim_dev *miim)
> +{
> +	return wait_for_bit_le32(miim->regs + MIIM_STATUS, MIIM_STATUS_BUSY,
> +				 false, 250, false);
> +}
> +
> +static int mscc_miim_read(struct mii_dev *bus, int addr, int devad, int reg)
> +{
> +	struct mscc_miim_dev *miim = (struct mscc_miim_dev *)bus->priv;
> +	u32 val;
> +	int ret;
> +
> +	ret = mscc_miim_wait_ready(miim);
> +	if (ret)
> +		goto out;
> +
> +	writel(MIIM_CMD_VLD | MIIM_CMD_PHYAD(addr) |
> +	       MIIM_CMD_REGAD(reg) | MIIM_CMD_OPR_READ,
> +	       miim->regs + MIIM_CMD);
> +
> +	ret = mscc_miim_wait_ready(miim);
> +	if (ret)
> +		goto out;
> +
> +	val = readl(miim->regs + MIIM_DATA);
> +	if (val & MIIM_DATA_ERROR) {
> +		ret = -EIO;
> +		goto out;
> +	}
> +
> +	ret = val & 0xFFFF;
> + out:
> +	return ret;
> +}
> +
> +static int mscc_miim_write(struct mii_dev *bus, int addr, int devad, int reg,
> +			   u16 val)
> +{
> +	struct mscc_miim_dev *miim = (struct mscc_miim_dev *)bus->priv;
> +	int ret;
> +
> +	ret = mscc_miim_wait_ready(miim);
> +	if (ret < 0)
> +		goto out;
> +
> +	writel(MIIM_CMD_VLD | MIIM_CMD_PHYAD(addr) |
> +	       MIIM_CMD_REGAD(reg) | MIIM_CMD_WRDATA(val) |
> +	       MIIM_CMD_OPR_WRITE, miim->regs + MIIM_CMD);
> +
> + out:
> +	return ret;
> +}
> +
> +static struct mii_dev *luton_mdiobus_init(struct udevice *dev,
> +					  int mdiobus_id)
> +{
> +	unsigned long phy_size[NUM_PHY];
> +	phys_addr_t phy_base[NUM_PHY];
> +	struct ofnode_phandle_args phandle;
> +	ofnode eth_node, node, mdio_node;
> +	struct resource res;
> +	struct mii_dev *bus;
> +	fdt32_t faddr;
> +	int i;
> +
> +	bus = mdio_alloc();
> +	if (!bus)
> +		return NULL;
> +
> +	/* gather only the first mdio bus */
> +	eth_node = dev_read_first_subnode(dev);
> +	node = ofnode_first_subnode(eth_node);
> +	ofnode_parse_phandle_with_args(node, "phy-handle", NULL, 0, 0,
> +				       &phandle);
> +	mdio_node = ofnode_get_parent(phandle.node);
> +
> +	for (i = 0; i < TARGET_MDIO_MAX; i++) {
> +		if (ofnode_read_resource(mdio_node, i, &res)) {
> +			pr_err("%s: get OF resource failed\n", __func__);
> +			return NULL;
> +		}
> +
> +		faddr = cpu_to_fdt32(res.start);
> +		phy_base[i] = ofnode_translate_address(mdio_node, &faddr);
> +		phy_size[i] = res.end - res.start;
> +	}
> +
> +	strcpy(bus->name, "miim-internal");
> +	miim[mdiobus_id].regs = ioremap(phy_base[mdiobus_id],
> +					phy_size[mdiobus_id]);
> +	bus->priv = &miim[mdiobus_id];
> +	bus->read = mscc_miim_read;
> +	bus->write = mscc_miim_write;
> +
> +	if (mdio_register(bus))
> +		return NULL;
> +	else
> +		return bus;
> +}
> +
> +static void luton_cpu_capture_setup(struct luton_private *priv)
> +{
> +	int i;
> +
> +	/* map the 8 CPU extraction queues to CPU port 26 */
> +	writel(0x0, priv->regs[SYS] + SYS_SCH_CPU);
> +
> +	for (i = 0; i <= 1; i++) {
> +		/*
> +		 * One to one mapping from CPU Queue number to Group extraction
> +		 * number
> +		 */
> +		writel(QS_XTR_MAP_ENA | (QS_XTR_MAP_GRP * i),
> +		       priv->regs[QS] + QS_XTR_MAP(i));
> +
> +		/* Enable IFH insertion/parsing on CPU ports */
> +		setbits_le32(priv->regs[REW] + REW_PORT_CFG(CPU_PORT + i),
> +			     REW_PORT_CFG_IFH_INSERT_ENA);
> +
> +		/* Enable IFH parsing on CPU port 0 and 1 */
> +		setbits_le32(priv->regs[SYS] + SYS_PORT_MODE(CPU_PORT + i),
> +			     SYS_PORT_MODE_INCL_INJ_HDR);
> +	}
> +
> +	/* Make VLAN aware for CPU traffic */
> +	writel(ANA_PORT_VLAN_CFG_AWARE_ENA |
> +	       ANA_PORT_VLAN_CFG_POP_CNT(1) |
> +	       MAC_VID,
> +	       priv->regs[ANA] + ANA_PORT_VLAN_CFG(CPU_PORT));
> +
> +	/* Disable learning (only RECV_ENA must be set) */
> +	writel(ANA_PORT_PORT_CFG_RECV_ENA,
> +	       priv->regs[ANA] + ANA_PORT_PORT_CFG(CPU_PORT));
> +
> +	/* Enable switching to/from cpu port */
> +	setbits_le32(priv->regs[SYS] + SYS_SWITCH_PORT_MODE(CPU_PORT),
> +		     SYS_SWITCH_PORT_MODE_PORT_ENA);
> +
> +	setbits_le32(priv->regs[SYS] + SYS_EGR_NO_SHARING, BIT(CPU_PORT));
> +}
> +
> +static void luton_gmii_port_init(struct luton_private *priv, int port)
> +{
> +	void __iomem *regs = priv->regs[port];
> +
> +	writel(0, regs + DEV_GMII_PORT_MODE_CLK);
> +
> +	/* Enable MAC RX and TX */
> +	writel(DEV_GMII_MAC_CFG_MAC_ENA_RX_ENA |
> +	       DEV_GMII_MAC_CFG_MAC_ENA_TX_ENA,
> +	       regs + DEV_GMII_MAC_CFG_MAC_ENA);
> +
> +	/* Make VLAN aware for CPU traffic */
> +	writel(ANA_PORT_VLAN_CFG_AWARE_ENA |
> +	       ANA_PORT_VLAN_CFG_POP_CNT(1) |
> +	       MAC_VID,
> +	       priv->regs[ANA] + ANA_PORT_VLAN_CFG(port - PORT0));
> +
> +	/* Enable switching to/from port */
> +	setbits_le32(priv->regs[SYS] + SYS_SWITCH_PORT_MODE(port - PORT0),
> +		     SYS_SWITCH_PORT_MODE_PORT_ENA);
> +}
> +
> +static void luton_port_init(struct luton_private *priv, int port)
> +{
> +	void __iomem *regs = priv->regs[port];
> +
> +	writel(0, regs + DEV_PORT_MODE_CLK);
> +
> +	/* Enable MAC RX and TX */
> +	writel(DEV_MAC_CFG_MAC_ENA_RX_ENA |
> +	       DEV_MAC_CFG_MAC_ENA_TX_ENA,
> +	       regs + DEV_MAC_CFG_MAC_ENA);
> +
> +	/* Make VLAN aware for CPU traffic */
> +	writel(ANA_PORT_VLAN_CFG_AWARE_ENA |
> +	       ANA_PORT_VLAN_CFG_POP_CNT(1) |
> +	       MAC_VID,
> +	       priv->regs[ANA] + ANA_PORT_VLAN_CFG(port - PORT0));
> +
> +	/* Enable switching to/from port */
> +	setbits_le32(priv->regs[SYS] + SYS_SWITCH_PORT_MODE(port - PORT0),
> +		     SYS_SWITCH_PORT_MODE_PORT_ENA);
> +}
> +
> +static void luton_ext_port_init(struct luton_private *priv, int port)
> +{
> +	void __iomem *regs = priv->regs[port];
> +
> +	/* Enable PCS */
> +	writel(DEV_PCS1G_CFG_PCS1G_CFG_PCS_ENA,
> +	       regs + DEV_PCS1G_CFG_PCS1G_CFG);
> +
> +	/* Disable Signal Detect */
> +	writel(0, regs + DEV_PCS1G_CFG_PCS1G_SD);
> +
> +	/* Enable MAC RX and TX */
> +	writel(DEV_MAC_CFG_MAC_ENA_RX_ENA |
> +	       DEV_MAC_CFG_MAC_ENA_TX_ENA,
> +	       regs + DEV_MAC_CFG_MAC_ENA);
> +
> +	/* Clear sgmii_mode_ena */
> +	writel(0, regs + DEV_PCS1G_CFG_PCS1G_MODE);
> +
> +	/*
> +	 * Clear sw_resolve_ena(bit 0) and set adv_ability to
> +	 * something meaningful just in case
> +	 */
> +	writel(DEV_PCS1G_CFG_PCS1G_ANEG_ADV_ABILITY(0x20),
> +	       regs + DEV_PCS1G_CFG_PCS1G_ANEG);
> +
> +	/* Set MAC IFG Gaps */
> +	writel(DEV_MAC_CFG_MAC_IFG_TX_IFG(7) |
> +	       DEV_MAC_CFG_MAC_IFG_RX_IFG1(1) |
> +	       DEV_MAC_CFG_MAC_IFG_RX_IFG2(5),
> +	       regs + DEV_MAC_CFG_MAC_IFG);
> +
> +	/* Set link speed and release all resets */
> +	writel(DEV_PORT_MODE_CLK_LINK_SPEED_1000,
> +	       regs + DEV_PORT_MODE_CLK);
> +
> +	/* Make VLAN aware for CPU traffic */
> +	writel(ANA_PORT_VLAN_CFG_AWARE_ENA |
> +	       ANA_PORT_VLAN_CFG_POP_CNT(1) |
> +	       MAC_VID,
> +	       priv->regs[ANA] + ANA_PORT_VLAN_CFG(port - PORT0));
> +
> +	/* Enable switching to/from port */
> +	setbits_le32(priv->regs[SYS] + SYS_SWITCH_PORT_MODE(port - PORT0),
> +		     SYS_SWITCH_PORT_MODE_PORT_ENA);
> +}
> +
> +static void serdes6g_write(struct luton_private *priv, u32 addr)
> +{
> +	u32 data;
> +
> +	writel(HSIO_MCB_SERDES6G_CFG_WR_ONE_SHOT |
> +	       HSIO_MCB_SERDES6G_CFG_ADDR(addr),
> +	       priv->regs[HSIO] + HSIO_MCB_SERDES6G_CFG);
> +
> +	do {
> +		data = readl(priv->regs[HSIO] + HSIO_MCB_SERDES6G_CFG);
> +	} while (data & HSIO_MCB_SERDES6G_CFG_WR_ONE_SHOT);
> +
> +	mdelay(100);
> +}
> +
> +static void serdes6g_cfg(struct luton_private *priv)
> +{
> +	writel(HSIO_RCOMP_CFG_CFG0_MODE_SEL(0x3) |
> +	       HSIO_RCOMP_CFG_CFG0_RUN_CAL,
> +	       priv->regs[HSIO] + HSIO_RCOMP_CFG_CFG0);
> +
> +	while (readl(priv->regs[HSIO] + HSIO_RCOMP_STATUS) &
> +	       HSIO_RCOMP_STATUS_BUSY)
> +		;
> +
> +	writel(HSIO_SERDES6G_ANA_CFG_OB_CFG_SR(0xb) |
> +	       HSIO_SERDES6G_ANA_CFG_OB_CFG_SR_H |
> +	       HSIO_SERDES6G_ANA_CFG_OB_CFG_POST0(0x10) |
> +	       HSIO_SERDES6G_ANA_CFG_OB_CFG_POL |
> +	       HSIO_SERDES6G_ANA_CFG_OB_CFG_ENA1V_MODE,
> +	       priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_OB_CFG);
> +	writel(HSIO_SERDES6G_ANA_CFG_OB_CFG1_LEV(0x18) |
> +	       HSIO_SERDES6G_ANA_CFG_OB_CFG1_ENA_CAS(0x1),
> +	       priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_OB_CFG1);
> +	writel(HSIO_SERDES6G_ANA_CFG_IB_CFG_RESISTOR_CTRL(0xc) |
> +	       HSIO_SERDES6G_ANA_CFG_IB_CFG_VBCOM(0x4) |
> +	       HSIO_SERDES6G_ANA_CFG_IB_CFG_VBAC(0x5) |
> +	       HSIO_SERDES6G_ANA_CFG_IB_CFG_RT(0xf) |
> +	       HSIO_SERDES6G_ANA_CFG_IB_CFG_RF(0x4),
> +	       priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_IB_CFG);
> +	writel(HSIO_SERDES6G_ANA_CFG_IB_CFG1_RST |
> +	       HSIO_SERDES6G_ANA_CFG_IB_CFG1_ENA_OFFSDC |
> +	       HSIO_SERDES6G_ANA_CFG_IB_CFG1_ENA_OFFSAC |
> +	       HSIO_SERDES6G_ANA_CFG_IB_CFG1_ANEG_MODE |
> +	       HSIO_SERDES6G_ANA_CFG_IB_CFG1_CHF |
> +	       HSIO_SERDES6G_ANA_CFG_IB_CFG1_C(0x4),
> +	       priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_IB_CFG1);
> +	writel(HSIO_SERDES6G_ANA_CFG_DES_CFG_BW_ANA(0x5) |
> +	       HSIO_SERDES6G_ANA_CFG_DES_CFG_BW_HYST(0x5) |
> +	       HSIO_SERDES6G_ANA_CFG_DES_CFG_MBTR_CTRL(0x2) |
> +	       HSIO_SERDES6G_ANA_CFG_DES_CFG_PHS_CTRL(0x6),
> +	       priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_DES_CFG);
> +	writel(HSIO_SERDES6G_ANA_CFG_PLL_CFG_FSM_ENA |
> +	       HSIO_SERDES6G_ANA_CFG_PLL_CFG_FSM_CTRL_DATA(0x78),
> +	       priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_PLL_CFG);
> +	writel(HSIO_SERDES6G_ANA_CFG_COMMON_CFG_IF_MODE(0x30) |
> +	       HSIO_SERDES6G_ANA_CFG_COMMON_CFG_ENA_LANE,
> +	       priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_COMMON_CFG);
> +	/*
> +	 * There are 4 serdes6g, configure all except serdes6g0, therefore
> +	 * the address is b1110
> +	 */
> +	serdes6g_write(priv, 0xe);
> +
> +	writel(readl(priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_COMMON_CFG) |
> +	       HSIO_SERDES6G_ANA_CFG_COMMON_CFG_SYS_RST,
> +	       priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_COMMON_CFG);
> +	serdes6g_write(priv, 0xe);
> +
> +	clrbits_le32(priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_IB_CFG1,
> +		     HSIO_SERDES6G_ANA_CFG_IB_CFG1_RST);
> +	writel(HSIO_SERDES6G_DIG_CFG_MISC_CFG_LANE_RST,
> +	       priv->regs[HSIO] + HSIO_SERDES6G_DIG_CFG_MISC_CFG);
> +	serdes6g_write(priv, 0xe);
> +}
> +
> +static int luton_switch_init(struct luton_private *priv)
> +{
> +	setbits_le32(priv->regs[HSIO] + HSIO_PLL5G_CFG_PLL5G_CFG2, BIT(1));
> +	clrbits_le32(priv->regs[HSIO] + HSIO_PLL5G_CFG_PLL5G_CFG2, BIT(1));
> +
> +	/* Reset switch & memories */
> +	writel(SYS_SYSTEM_RST_MEM_ENA | SYS_SYSTEM_RST_MEM_INIT,
> +	       priv->regs[SYS] + SYS_SYSTEM_RST_CFG);
> +
> +	/* Wait to complete */
> +	if (wait_for_bit_le32(priv->regs[SYS] + SYS_SYSTEM_RST_CFG,
> +			      SYS_SYSTEM_RST_MEM_INIT, false, 2000, false)) {
> +		printf("Timeout in memory reset\n");
> +	}
> +
> +	/* Enable switch core */
> +	setbits_le32(priv->regs[SYS] + SYS_SYSTEM_RST_CFG,
> +		     SYS_SYSTEM_RST_CORE_ENA);
> +
> +	/* Setup the Serdes6g macros */
> +	serdes6g_cfg(priv);
> +
> +	return 0;
> +}
> +
> +static void luton_switch_flush(struct luton_private *priv)
> +{
> +	/* All Queues flush */
> +	setbits_le32(priv->regs[QS] + QS_XTR_FLUSH, QS_XTR_FLUSH_FLUSH);
> +
> +	/* Allow to drain */
> +	mdelay(1);
> +
> +	/* All Queues normal */
> +	clrbits_le32(priv->regs[QS] + QS_XTR_FLUSH, QS_XTR_FLUSH_FLUSH);
> +}
> +
> +static int luton_initialize(struct luton_private *priv)
> +{
> +	int ret, i;
> +
> +	/* Initialize switch memories, enable core */
> +	ret = luton_switch_init(priv);
> +	if (ret)
> +		return ret;
> +
> +	/*
> +	 * Disable port-to-port by switching
> +	 * Put front ports in "port isolation modes" - i.e. they can't send
> +	 * to other ports - via the PGID sorce masks.
> +	 */
> +	for (i = 0; i < MAX_PORT; i++)
> +		writel(0, priv->regs[ANA] + ANA_PGID(PGID_SRC + i));
> +
> +	/* Flush queues */
> +	luton_switch_flush(priv);
> +
> +	/* Setup frame ageing - "2 sec" - The unit is 4ns on Luton*/
> +	writel(2000000000 / 4,
> +	       priv->regs[SYS] + SYS_FRM_AGING);
> +
> +	for (i = PORT0; i < MAX_PORT; i++) {
> +		if (i < PORT10)
> +			luton_gmii_port_init(priv, i);
> +		else
> +			if (i == PORT10 || i == PORT11)
> +				luton_port_init(priv, i);
> +			else
> +				luton_ext_port_init(priv, i);
> +	}
> +
> +	luton_cpu_capture_setup(priv);
> +
> +	return 0;
> +}
> +
> +static inline int luton_vlant_wait_for_completion(struct luton_private *priv)
> +{
> +	unsigned int val, timeout = 10;
> +
> +	/*
> +	 * Wait for the issued mac table command to be completed, or timeout.
> +	 * When the command read from ANA_TABLES_MACACCESS is
> +	 * MACACCESS_CMD_IDLE, the issued command completed successfully.
> +	 */
> +	do {
> +		val = readl(priv->regs[ANA] + ANA_TABLES_MACACCESS);
> +		val &= ANA_TABLES_MACACCESS_MAC_TABLE_CMD_M;
> +	} while (val != MACACCESS_CMD_IDLE && timeout--);
> +
> +	if (!timeout)
> +		return -ETIMEDOUT;
> +
> +	return 0;
> +}
> +
> +static int luton_mac_table_add(struct luton_private *priv,
> +			       const unsigned char mac[ETH_ALEN], int pgid)
> +{
> +	u32 macl = 0, mach = 0;
> +	int ret;
> +
> +	/*
> +	 * Set the MAC address to handle and the vlan associated in a format
> +	 * understood by the hardware.
> +	 */
> +	mach |= MAC_VID << 16;
> +	mach |= ((u32)mac[0]) << 8;
> +	mach |= ((u32)mac[1]) << 0;
> +	macl |= ((u32)mac[2]) << 24;
> +	macl |= ((u32)mac[3]) << 16;
> +	macl |= ((u32)mac[4]) << 8;
> +	macl |= ((u32)mac[5]) << 0;
> +
> +	writel(macl, priv->regs[ANA] + ANA_TABLES_MACLDATA);
> +	writel(mach, priv->regs[ANA] + ANA_TABLES_MACHDATA);
> +
> +	writel(ANA_TABLES_MACACCESS_VALID |
> +	       ANA_TABLES_MACACCESS_DEST_IDX(pgid) |
> +	       ANA_TABLES_MACACCESS_ENTRYTYPE(ENTRYTYPE_LOCKED) |
> +	       ANA_TABLES_MACACCESS_MAC_TABLE_CMD(MACACCESS_CMD_LEARN),
> +	       priv->regs[ANA] + ANA_TABLES_MACACCESS);
> +
> +	ret = luton_vlant_wait_for_completion(priv);
> +
> +	return ret;
> +}
> +
> +static int luton_write_hwaddr(struct udevice *dev)
> +{
> +	struct luton_private *priv = dev_get_priv(dev);
> +	struct eth_pdata *pdata = dev_get_platdata(dev);
> +
> +	luton_mac_table_add(priv, pdata->enetaddr, PGID_UNICAST);
> +
> +	writel(BIT(CPU_PORT), priv->regs[ANA] + ANA_PGID(PGID_UNICAST));
> +
> +	return 0;
> +}
> +
> +static int luton_start(struct udevice *dev)
> +{
> +	struct luton_private *priv = dev_get_priv(dev);
> +	struct eth_pdata *pdata = dev_get_platdata(dev);
> +	const unsigned char mac[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff,
> +					      0xff };
> +	int ret;
> +
> +	ret = luton_initialize(priv);
> +	if (ret)
> +		return ret;
> +
> +	/* Set MAC address tables entries for CPU redirection */
> +	luton_mac_table_add(priv, mac, PGID_BROADCAST);
> +
> +	writel(BIT(CPU_PORT) | INTERNAL_PORT_MSK,
> +	       priv->regs[ANA] + ANA_PGID(PGID_BROADCAST));
> +
> +	luton_mac_table_add(priv, pdata->enetaddr, PGID_UNICAST);
> +
> +	writel(BIT(CPU_PORT), priv->regs[ANA] + ANA_PGID(PGID_UNICAST));
> +
> +	return 0;
> +}
> +
> +static void luton_stop(struct udevice *dev)
> +{
> +	struct luton_private *priv = dev_get_priv(dev);
> +
> +	/*
> +	 * Switch core only reset affects VCORE-III bus and MIPS frequency
> +	 * and thereby also the DDR SDRAM controller. The workaround is to
> +	 * not to redirect any trafic to the CPU after the data transfer.
> +	 */
> +	writel(GENMASK(9, 2), priv->regs[SYS] + SYS_SCH_CPU);
> +}
> +
> +static int luton_send(struct udevice *dev, void *packet, int length)
> +{
> +	struct luton_private *priv = dev_get_priv(dev);
> +	u32 ifh[IFH_LEN];
> +	int port = BIT(0);	/* use port 0 */
> +	u8 grp = 0;		/* Send everything on CPU group 0 */
> +	int i, count = (length + 3) / 4, last = length % 4;
> +	u32 *buf = packet;
> +
> +	writel(QS_INJ_CTRL_GAP_SIZE(1) | QS_INJ_CTRL_SOF,
> +	       priv->regs[QS] + QS_INJ_CTRL(grp));
> +
> +	ifh[0] = IFH_INJ_BYPASS | port;
> +	ifh[1] = (IFH_TAG_TYPE_C << 16);
> +
> +	for (i = 0; i < IFH_LEN; i++)
> +		writel(ifh[i], priv->regs[QS] + QS_INJ_WR(grp));
> +
> +	for (i = 0; i < count; i++)
> +		writel(buf[i], priv->regs[QS] + QS_INJ_WR(grp));
> +
> +	/* Add padding */
> +	while (i < (LUTON_BUF_CELL_SZ / 4)) {
> +		writel(0, priv->regs[QS] + QS_INJ_WR(grp));
> +		i++;
> +	}
> +
> +	/* Indicate EOF and valid bytes in last word */
> +	writel(QS_INJ_CTRL_GAP_SIZE(1) |
> +	       QS_INJ_CTRL_VLD_BYTES(length < LUTON_BUF_CELL_SZ ? 0 : last) |
> +	       QS_INJ_CTRL_EOF, priv->regs[QS] + QS_INJ_CTRL(grp));
> +
> +	/* Add dummy CRC */
> +	writel(0, priv->regs[QS] + QS_INJ_WR(grp));
> +
> +	return 0;
> +}
> +
> +static int luton_recv(struct udevice *dev, int flags, uchar **packetp)
> +{
> +	struct luton_private *priv = dev_get_priv(dev);
> +	u8 grp = 0;		/* Recv everything on CPU group 0 */
> +	u32 *rxbuf = (u32 *)net_rx_packets[0];
> +	int byte_cnt = 0;
> +	int i = 0;
> +	bool eof_flag = false, pruned_flag = false, abort_flag = false;
> +
> +	if (!(readl(priv->regs[QS] + QS_XTR_DATA_PRESENT) & BIT(grp)))
> +		return -EAGAIN;
> +
> +	/* skip IFH */
> +	for (i = 0; i < IFH_LEN; i++)
> +		readl(priv->regs[QS] + QS_XTR_RD(grp));
> +
> +	while (!eof_flag) {
> +		u32 val = readl(priv->regs[QS] + QS_XTR_RD(grp));
> +
> +		switch (val) {
> +		case XTR_NOT_READY:
> +			debug("%d NOT_READY...?\n", byte_cnt);
> +			break;
> +		case XTR_ABORT:
> +			/* really nedeed?? not done in linux */
> +			*rxbuf = readl(priv->regs[QS] + QS_XTR_RD(grp));
> +			abort_flag = true;
> +			eof_flag = true;
> +			debug("XTR_ABORT\n");
> +			break;
> +		case XTR_EOF_0:
> +		case XTR_EOF_1:
> +		case XTR_EOF_2:
> +		case XTR_EOF_3:
> +			byte_cnt += XTR_VALID_BYTES(val);
> +			*rxbuf = readl(priv->regs[QS] + QS_XTR_RD(grp));
> +			eof_flag = true;
> +			debug("EOF\n");
> +			break;
> +		case XTR_PRUNED:
> +			/* But get the last 4 bytes as well */
> +			eof_flag = true;
> +			pruned_flag = true;
> +			debug("PRUNED\n");
> +			/* fallthrough */
> +		case XTR_ESCAPE:
> +			*rxbuf = readl(priv->regs[QS] + QS_XTR_RD(grp));
> +			byte_cnt += 4;
> +			rxbuf++;
> +			debug("ESCAPED\n");
> +			break;
> +		default:
> +			*rxbuf = val;
> +			byte_cnt += 4;
> +			rxbuf++;
> +		}
> +	}
> +
> +	if (abort_flag || pruned_flag || !eof_flag) {
> +		debug("Discarded frame: abort:%d pruned:%d eof:%d\n",
> +		      abort_flag, pruned_flag, eof_flag);
> +		return -EAGAIN;
> +	}
> +
> +	*packetp = net_rx_packets[0];
> +
> +	return byte_cnt;
> +}
> +
> +static int luton_probe(struct udevice *dev)
> +{
> +	struct luton_private *priv = dev_get_priv(dev);
> +	int i;
> +
> +	struct {
> +		enum luton_target id;
> +		char *name;
> +	} reg[] = {
> +		{ PORT0, "port0" },
> +		{ PORT1, "port1" },
> +		{ PORT2, "port2" },
> +		{ PORT3, "port3" },
> +		{ PORT4, "port4" },
> +		{ PORT5, "port5" },
> +		{ PORT6, "port6" },
> +		{ PORT7, "port7" },
> +		{ PORT8, "port8" },
> +		{ PORT9, "port9" },
> +		{ PORT10, "port10" },
> +		{ PORT11, "port11" },
> +		{ PORT12, "port12" },
> +		{ PORT13, "port13" },
> +		{ PORT14, "port14" },
> +		{ PORT15, "port15" },
> +		{ PORT16, "port16" },
> +		{ PORT17, "port17" },
> +		{ PORT18, "port18" },
> +		{ PORT19, "port19" },
> +		{ PORT20, "port20" },
> +		{ PORT21, "port21" },
> +		{ PORT22, "port22" },
> +		{ PORT23, "port23" },
> +		{ SYS, "sys" },
> +		{ ANA, "ana" },
> +		{ REW, "rew" },
> +		{ GCB, "gcb" },
> +		{ QS, "qs" },
> +		{ HSIO, "hsio" },
> +	};
> +
> +	if (!priv)
> +		return -EINVAL;
> +
> +	for (i = 0; i < ARRAY_SIZE(reg); i++) {
> +		priv->regs[reg[i].id] = dev_remap_addr_name(dev, reg[i].name);
> +		if (!priv->regs[reg[i].id]) {
> +			debug
> +			    ("Error can't get regs base addresses for %s\n",
> +			     reg[i].name);
> +			return -ENOMEM;
> +		}
> +	}
> +
> +	/* Release reset in the CU-PHY */
> +	writel(0, priv->regs[GCB] + GCB_DEVCPU_RST_SOFT_CHIP_RST);
> +
> +	/* Ports with ext phy don't need to reset clk */
> +	for (i = PORT0; i < MAX_INT_PORT; i++) {
> +		if (i < PORT10)
> +			clrbits_le32(priv->regs[i] + DEV_GMII_PORT_MODE_CLK,
> +				     DEV_GMII_PORT_MODE_CLK_PHY_RST);
> +		else
> +			clrbits_le32(priv->regs[i] + DEV_PORT_MODE_CLK,
> +				     DEV_PORT_MODE_CLK_PHY_RST);
> +	}
> +
> +	/* Wait for internal PHY to be ready */
> +	if (wait_for_bit_le32(priv->regs[GCB] + GCB_MISC_STAT,
> +			      GCB_MISC_STAT_PHY_READY, true, 500, false))
> +		return -EACCES;
> +
> +	priv->bus[INTERNAL] = luton_mdiobus_init(dev, INTERNAL);
> +
> +	for (i = 0; i < MAX_INT_PORT; i++) {
> +		phy_connect(priv->bus[INTERNAL], i, dev,
> +			    PHY_INTERFACE_MODE_NONE);
> +	}
> +
> +	/*
> +	 * coma_mode is need on only one phy, because all the other phys
> +	 * will be affected.
> +	 */
> +	mscc_miim_write(priv->bus[INTERNAL], 0, 0, 31, 0x10);
> +	mscc_miim_write(priv->bus[INTERNAL], 0, 0, 14, 0x800);
> +	mscc_miim_write(priv->bus[INTERNAL], 0, 0, 31, 0);
> +
> +	return 0;
> +}
> +
> +static int luton_remove(struct udevice *dev)
> +{
> +	struct luton_private *priv = dev_get_priv(dev);
> +	int i;
> +
> +	for (i = 0; i < NUM_PHY; i++) {
> +		mdio_unregister(priv->bus[i]);
> +		mdio_free(priv->bus[i]);
> +	}
> +
> +	return 0;
> +}
> +
> +static const struct eth_ops luton_ops = {
> +	.start        = luton_start,
> +	.stop         = luton_stop,
> +	.send         = luton_send,
> +	.recv         = luton_recv,
> +	.write_hwaddr = luton_write_hwaddr,
> +};
> +
> +static const struct udevice_id mscc_luton_ids[] = {
> +	{.compatible = "mscc,vsc7527-switch", },
> +	{ /* Sentinel */ }
> +};
> +
> +U_BOOT_DRIVER(luton) = {
> +	.name     = "luton-switch",
> +	.id       = UCLASS_ETH,
> +	.of_match = mscc_luton_ids,
> +	.probe	  = luton_probe,
> +	.remove	  = luton_remove,
> +	.ops	  = &luton_ops,
> +	.priv_auto_alloc_size = sizeof(struct luton_private),
> +	.platdata_auto_alloc_size = sizeof(struct eth_pdata),
> +};
> -- 
> 2.7.4
>

-- 
Gregory Clement, Bootlin
Embedded Linux and Kernel engineering
http://bootlin.com

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2019-01-28 13:22 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-01-28 10:29 [U-Boot] [PATCH 0/3] Add network support for Luton SoCs Horatiu Vultur
2019-01-28 10:29 ` [U-Boot] [PATCH 1/3] MIPS: mscc: luton: Add ethernet nodes for Luton Horatiu Vultur
2019-01-28 10:29 ` [U-Boot] [PATCH 2/3] net: add MSCC Luton switch support Horatiu Vultur
2019-01-28 13:22   ` Gregory CLEMENT
2019-01-28 10:29 ` [U-Boot] [PATCH 3/3] configs: mscc_luton: add network support Horatiu Vultur

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.