xref: /openbmc/u-boot/drivers/net/mscc_eswitch/ocelot_switch.c (revision 544d5e98f3657e4ac1966be8971586aa42dad8c4)
14c66157fSHoratiu Vultur // SPDX-License-Identifier: (GPL-2.0+ OR MIT)
24c66157fSHoratiu Vultur /*
34c66157fSHoratiu Vultur  * Copyright (c) 2018 Microsemi Corporation
44c66157fSHoratiu Vultur  */
54c66157fSHoratiu Vultur 
64c66157fSHoratiu Vultur #include <common.h>
74c66157fSHoratiu Vultur #include <config.h>
84c66157fSHoratiu Vultur #include <dm.h>
94c66157fSHoratiu Vultur #include <dm/of_access.h>
104c66157fSHoratiu Vultur #include <dm/of_addr.h>
114c66157fSHoratiu Vultur #include <fdt_support.h>
124c66157fSHoratiu Vultur #include <linux/io.h>
134c66157fSHoratiu Vultur #include <linux/ioport.h>
144c66157fSHoratiu Vultur #include <miiphy.h>
154c66157fSHoratiu Vultur #include <net.h>
164c66157fSHoratiu Vultur #include <wait_bit.h>
174c66157fSHoratiu Vultur 
182fff4a9bSHoratiu Vultur #include "mscc_miim.h"
1936d04f52SHoratiu Vultur #include "mscc_xfer.h"
2045f2748cSHoratiu Vultur #include "mscc_mac_table.h"
214c66157fSHoratiu Vultur 
224c66157fSHoratiu Vultur #define PHY_CFG				0x0
234c66157fSHoratiu Vultur #define PHY_CFG_ENA				0xF
244c66157fSHoratiu Vultur #define PHY_CFG_COMMON_RST			BIT(4)
254c66157fSHoratiu Vultur #define PHY_CFG_RST				(0xF << 5)
264c66157fSHoratiu Vultur #define PHY_STAT			0x4
274c66157fSHoratiu Vultur #define PHY_STAT_SUPERVISOR_COMPLETE		BIT(0)
284c66157fSHoratiu Vultur 
294c66157fSHoratiu Vultur #define ANA_PORT_VLAN_CFG(x)		(0x7000 + 0x100 * (x))
304c66157fSHoratiu Vultur #define		ANA_PORT_VLAN_CFG_AWARE_ENA	BIT(20)
314c66157fSHoratiu Vultur #define		ANA_PORT_VLAN_CFG_POP_CNT(x)	((x) << 18)
324c66157fSHoratiu Vultur #define ANA_PORT_PORT_CFG(x)		(0x7070 + 0x100 * (x))
334c66157fSHoratiu Vultur #define		ANA_PORT_PORT_CFG_RECV_ENA	BIT(6)
344c66157fSHoratiu Vultur #define ANA_PGID(x)			(0x8c00 + 4 * (x))
354c66157fSHoratiu Vultur 
364c66157fSHoratiu Vultur #define SYS_FRM_AGING			0x574
374c66157fSHoratiu Vultur #define		SYS_FRM_AGING_ENA		BIT(20)
384c66157fSHoratiu Vultur 
394c66157fSHoratiu Vultur #define SYS_SYSTEM_RST_CFG		0x508
404c66157fSHoratiu Vultur #define		SYS_SYSTEM_RST_MEM_INIT		BIT(0)
414c66157fSHoratiu Vultur #define		SYS_SYSTEM_RST_MEM_ENA		BIT(1)
424c66157fSHoratiu Vultur #define		SYS_SYSTEM_RST_CORE_ENA		BIT(2)
434c66157fSHoratiu Vultur #define SYS_PORT_MODE(x)		(0x514 + 0x4 * (x))
444c66157fSHoratiu Vultur #define		SYS_PORT_MODE_INCL_INJ_HDR(x)	((x) << 3)
454c66157fSHoratiu Vultur #define		SYS_PORT_MODE_INCL_INJ_HDR_M	GENMASK(4, 3)
464c66157fSHoratiu Vultur #define		SYS_PORT_MODE_INCL_XTR_HDR(x)	((x) << 1)
474c66157fSHoratiu Vultur #define		SYS_PORT_MODE_INCL_XTR_HDR_M	GENMASK(2, 1)
484c66157fSHoratiu Vultur #define	SYS_PAUSE_CFG(x)		(0x608 + 0x4 * (x))
494c66157fSHoratiu Vultur #define		SYS_PAUSE_CFG_PAUSE_ENA		BIT(0)
504c66157fSHoratiu Vultur 
514c66157fSHoratiu Vultur #define QSYS_SWITCH_PORT_MODE(x)	(0x11234 + 0x4 * (x))
524c66157fSHoratiu Vultur #define		QSYS_SWITCH_PORT_MODE_PORT_ENA	BIT(14)
534c66157fSHoratiu Vultur #define	QSYS_QMAP			0x112d8
544c66157fSHoratiu Vultur #define	QSYS_EGR_NO_SHARING		0x1129c
554c66157fSHoratiu Vultur 
564c66157fSHoratiu Vultur /* Port registers */
574c66157fSHoratiu Vultur #define DEV_CLOCK_CFG			0x0
584c66157fSHoratiu Vultur #define DEV_CLOCK_CFG_LINK_SPEED_1000		1
594c66157fSHoratiu Vultur #define DEV_MAC_ENA_CFG			0x1c
604c66157fSHoratiu Vultur #define		DEV_MAC_ENA_CFG_RX_ENA		BIT(4)
614c66157fSHoratiu Vultur #define		DEV_MAC_ENA_CFG_TX_ENA		BIT(0)
624c66157fSHoratiu Vultur 
634c66157fSHoratiu Vultur #define DEV_MAC_IFG_CFG			0x30
644c66157fSHoratiu Vultur #define		DEV_MAC_IFG_CFG_TX_IFG(x)	((x) << 8)
654c66157fSHoratiu Vultur #define		DEV_MAC_IFG_CFG_RX_IFG2(x)	((x) << 4)
664c66157fSHoratiu Vultur #define		DEV_MAC_IFG_CFG_RX_IFG1(x)	(x)
674c66157fSHoratiu Vultur 
684c66157fSHoratiu Vultur #define PCS1G_CFG			0x48
694c66157fSHoratiu Vultur #define		PCS1G_MODE_CFG_SGMII_MODE_ENA	BIT(0)
704c66157fSHoratiu Vultur #define PCS1G_MODE_CFG			0x4c
714c66157fSHoratiu Vultur #define		PCS1G_MODE_CFG_UNIDIR_MODE_ENA	BIT(4)
724c66157fSHoratiu Vultur #define		PCS1G_MODE_CFG_SGMII_MODE_ENA	BIT(0)
734c66157fSHoratiu Vultur #define PCS1G_SD_CFG			0x50
744c66157fSHoratiu Vultur #define PCS1G_ANEG_CFG			0x54
754c66157fSHoratiu Vultur #define		PCS1G_ANEG_CFG_ADV_ABILITY(x)	((x) << 16)
764c66157fSHoratiu Vultur 
774c66157fSHoratiu Vultur #define QS_XTR_GRP_CFG(x)		(4 * (x))
784c66157fSHoratiu Vultur #define QS_XTR_GRP_CFG_MODE(x)			((x) << 2)
794c66157fSHoratiu Vultur #define		QS_XTR_GRP_CFG_STATUS_WORD_POS	BIT(1)
804c66157fSHoratiu Vultur #define		QS_XTR_GRP_CFG_BYTE_SWAP	BIT(0)
814c66157fSHoratiu Vultur #define QS_INJ_GRP_CFG(x)		(0x24 + (x) * 4)
824c66157fSHoratiu Vultur #define		QS_INJ_GRP_CFG_MODE(x)		((x) << 2)
834c66157fSHoratiu Vultur #define		QS_INJ_GRP_CFG_BYTE_SWAP	BIT(0)
844c66157fSHoratiu Vultur 
854c66157fSHoratiu Vultur #define IFH_INJ_BYPASS		BIT(31)
864c66157fSHoratiu Vultur #define	IFH_TAG_TYPE_C		0
874c66157fSHoratiu Vultur #define	MAC_VID			1
884c66157fSHoratiu Vultur #define CPU_PORT		11
894c66157fSHoratiu Vultur #define INTERNAL_PORT_MSK	0xF
904c66157fSHoratiu Vultur #define IFH_LEN			4
914c66157fSHoratiu Vultur #define ETH_ALEN		6
924c66157fSHoratiu Vultur #define	PGID_BROADCAST		13
934c66157fSHoratiu Vultur #define	PGID_UNICAST		14
944c66157fSHoratiu Vultur #define	PGID_SRC		80
954c66157fSHoratiu Vultur 
964c66157fSHoratiu Vultur enum ocelot_target {
974c66157fSHoratiu Vultur 	ANA,
984c66157fSHoratiu Vultur 	QS,
994c66157fSHoratiu Vultur 	QSYS,
1004c66157fSHoratiu Vultur 	REW,
1014c66157fSHoratiu Vultur 	SYS,
1024c66157fSHoratiu Vultur 	HSIO,
1034c66157fSHoratiu Vultur 	PORT0,
1044c66157fSHoratiu Vultur 	PORT1,
1054c66157fSHoratiu Vultur 	PORT2,
1064c66157fSHoratiu Vultur 	PORT3,
1074c66157fSHoratiu Vultur 	TARGET_MAX,
1084c66157fSHoratiu Vultur };
1094c66157fSHoratiu Vultur 
1104c66157fSHoratiu Vultur #define MAX_PORT (PORT3 - PORT0)
1114c66157fSHoratiu Vultur 
1124c66157fSHoratiu Vultur enum ocelot_mdio_target {
1134c66157fSHoratiu Vultur 	MIIM,
1144c66157fSHoratiu Vultur 	PHY,
1154c66157fSHoratiu Vultur 	TARGET_MDIO_MAX,
1164c66157fSHoratiu Vultur };
1174c66157fSHoratiu Vultur 
1184c66157fSHoratiu Vultur enum ocelot_phy_id {
1194c66157fSHoratiu Vultur 	INTERNAL,
1204c66157fSHoratiu Vultur 	EXTERNAL,
1214c66157fSHoratiu Vultur 	NUM_PHY,
1224c66157fSHoratiu Vultur };
1234c66157fSHoratiu Vultur 
1244c66157fSHoratiu Vultur struct ocelot_private {
1254c66157fSHoratiu Vultur 	void __iomem *regs[TARGET_MAX];
1264c66157fSHoratiu Vultur 	struct mii_dev *bus[NUM_PHY];
1274c66157fSHoratiu Vultur };
1284c66157fSHoratiu Vultur 
12936d04f52SHoratiu Vultur static const unsigned long ocelot_regs_qs[] = {
13036d04f52SHoratiu Vultur 	[MSCC_QS_XTR_RD] = 0x8,
13136d04f52SHoratiu Vultur 	[MSCC_QS_XTR_FLUSH] = 0x18,
13236d04f52SHoratiu Vultur 	[MSCC_QS_XTR_DATA_PRESENT] = 0x1c,
13336d04f52SHoratiu Vultur 	[MSCC_QS_INJ_WR] = 0x2c,
13436d04f52SHoratiu Vultur 	[MSCC_QS_INJ_CTRL] = 0x34,
13536d04f52SHoratiu Vultur };
13636d04f52SHoratiu Vultur 
13745f2748cSHoratiu Vultur static const unsigned long ocelot_regs_ana_table[] = {
13845f2748cSHoratiu Vultur 	[MSCC_ANA_TABLES_MACHDATA] = 0x8b34,
13945f2748cSHoratiu Vultur 	[MSCC_ANA_TABLES_MACLDATA] = 0x8b38,
14045f2748cSHoratiu Vultur 	[MSCC_ANA_TABLES_MACACCESS] = 0x8b3c,
14145f2748cSHoratiu Vultur };
14245f2748cSHoratiu Vultur 
143*0b8f34dcSHoratiu Vultur static struct mscc_miim_dev miim[NUM_PHY];
1444c66157fSHoratiu Vultur 
mscc_miim_reset(struct mii_dev * bus)1454c66157fSHoratiu Vultur static int mscc_miim_reset(struct mii_dev *bus)
1464c66157fSHoratiu Vultur {
1474c66157fSHoratiu Vultur 	struct mscc_miim_dev *miim = (struct mscc_miim_dev *)bus->priv;
1484c66157fSHoratiu Vultur 
1494c66157fSHoratiu Vultur 	if (miim->phy_regs) {
1504c66157fSHoratiu Vultur 		writel(0, miim->phy_regs + PHY_CFG);
1514c66157fSHoratiu Vultur 		writel(PHY_CFG_RST | PHY_CFG_COMMON_RST
1524c66157fSHoratiu Vultur 		       | PHY_CFG_ENA, miim->phy_regs + PHY_CFG);
1534c66157fSHoratiu Vultur 		mdelay(500);
1544c66157fSHoratiu Vultur 	}
1554c66157fSHoratiu Vultur 
1564c66157fSHoratiu Vultur 	return 0;
1574c66157fSHoratiu Vultur }
1584c66157fSHoratiu Vultur 
1594c66157fSHoratiu Vultur /* For now only setup the internal mdio bus */
ocelot_mdiobus_init(struct udevice * dev)1604c66157fSHoratiu Vultur static struct mii_dev *ocelot_mdiobus_init(struct udevice *dev)
1614c66157fSHoratiu Vultur {
1624c66157fSHoratiu Vultur 	unsigned long phy_size[TARGET_MAX];
1634c66157fSHoratiu Vultur 	phys_addr_t phy_base[TARGET_MAX];
1644c66157fSHoratiu Vultur 	struct ofnode_phandle_args phandle;
1654c66157fSHoratiu Vultur 	ofnode eth_node, node, mdio_node;
1664c66157fSHoratiu Vultur 	struct resource res;
1674c66157fSHoratiu Vultur 	struct mii_dev *bus;
1684c66157fSHoratiu Vultur 	fdt32_t faddr;
1694c66157fSHoratiu Vultur 	int i;
1704c66157fSHoratiu Vultur 
1714c66157fSHoratiu Vultur 	bus = mdio_alloc();
1724c66157fSHoratiu Vultur 
1734c66157fSHoratiu Vultur 	if (!bus)
1744c66157fSHoratiu Vultur 		return NULL;
1754c66157fSHoratiu Vultur 
1764c66157fSHoratiu Vultur 	/* gathered only the first mdio bus */
1774c66157fSHoratiu Vultur 	eth_node = dev_read_first_subnode(dev);
1784c66157fSHoratiu Vultur 	node = ofnode_first_subnode(eth_node);
1794c66157fSHoratiu Vultur 	ofnode_parse_phandle_with_args(node, "phy-handle", NULL, 0, 0,
1804c66157fSHoratiu Vultur 				       &phandle);
1814c66157fSHoratiu Vultur 	mdio_node = ofnode_get_parent(phandle.node);
1824c66157fSHoratiu Vultur 
1834c66157fSHoratiu Vultur 	for (i = 0; i < TARGET_MDIO_MAX; i++) {
1844c66157fSHoratiu Vultur 		if (ofnode_read_resource(mdio_node, i, &res)) {
1854c66157fSHoratiu Vultur 			pr_err("%s: get OF resource failed\n", __func__);
1864c66157fSHoratiu Vultur 			return NULL;
1874c66157fSHoratiu Vultur 		}
1884c66157fSHoratiu Vultur 		faddr = cpu_to_fdt32(res.start);
1894c66157fSHoratiu Vultur 		phy_base[i] = ofnode_translate_address(mdio_node, &faddr);
1904c66157fSHoratiu Vultur 		phy_size[i] = res.end - res.start;
1914c66157fSHoratiu Vultur 	}
1924c66157fSHoratiu Vultur 
1934c66157fSHoratiu Vultur 	strcpy(bus->name, "miim-internal");
1944c66157fSHoratiu Vultur 	miim[INTERNAL].phy_regs = ioremap(phy_base[PHY], phy_size[PHY]);
1954c66157fSHoratiu Vultur 	miim[INTERNAL].regs = ioremap(phy_base[MIIM], phy_size[MIIM]);
1964c66157fSHoratiu Vultur 	bus->priv = &miim[INTERNAL];
1974c66157fSHoratiu Vultur 	bus->reset = mscc_miim_reset;
1984c66157fSHoratiu Vultur 	bus->read = mscc_miim_read;
1994c66157fSHoratiu Vultur 	bus->write = mscc_miim_write;
2004c66157fSHoratiu Vultur 
2014c66157fSHoratiu Vultur 	if (mdio_register(bus))
2024c66157fSHoratiu Vultur 		return NULL;
2034c66157fSHoratiu Vultur 	else
2044c66157fSHoratiu Vultur 		return bus;
2054c66157fSHoratiu Vultur }
2064c66157fSHoratiu Vultur 
mscc_switch_reset(void)2074c66157fSHoratiu Vultur __weak void mscc_switch_reset(void)
2084c66157fSHoratiu Vultur {
2094c66157fSHoratiu Vultur }
2104c66157fSHoratiu Vultur 
ocelot_stop(struct udevice * dev)2114c66157fSHoratiu Vultur static void ocelot_stop(struct udevice *dev)
2124c66157fSHoratiu Vultur {
2134c66157fSHoratiu Vultur 	struct ocelot_private *priv = dev_get_priv(dev);
2144c66157fSHoratiu Vultur 	int i;
2154c66157fSHoratiu Vultur 
2164c66157fSHoratiu Vultur 	mscc_switch_reset();
2174c66157fSHoratiu Vultur 	for (i = 0; i < NUM_PHY; i++)
2184c66157fSHoratiu Vultur 		if (priv->bus[i])
2194c66157fSHoratiu Vultur 			mscc_miim_reset(priv->bus[i]);
2204c66157fSHoratiu Vultur }
2214c66157fSHoratiu Vultur 
ocelot_cpu_capture_setup(struct ocelot_private * priv)2224c66157fSHoratiu Vultur static void ocelot_cpu_capture_setup(struct ocelot_private *priv)
2234c66157fSHoratiu Vultur {
2244c66157fSHoratiu Vultur 	int i;
2254c66157fSHoratiu Vultur 
2264c66157fSHoratiu Vultur 	/* map the 8 CPU extraction queues to CPU port 11 */
2274c66157fSHoratiu Vultur 	writel(0, priv->regs[QSYS] + QSYS_QMAP);
2284c66157fSHoratiu Vultur 
2294c66157fSHoratiu Vultur 	for (i = 0; i <= 1; i++) {
2304c66157fSHoratiu Vultur 		/*
2314c66157fSHoratiu Vultur 		 * Do byte-swap and expect status after last data word
2324c66157fSHoratiu Vultur 		 * Extraction: Mode: manual extraction) | Byte_swap
2334c66157fSHoratiu Vultur 		 */
2344c66157fSHoratiu Vultur 		writel(QS_XTR_GRP_CFG_MODE(1) | QS_XTR_GRP_CFG_BYTE_SWAP,
2354c66157fSHoratiu Vultur 		       priv->regs[QS] + QS_XTR_GRP_CFG(i));
2364c66157fSHoratiu Vultur 		/*
2374c66157fSHoratiu Vultur 		 * Injection: Mode: manual extraction | Byte_swap
2384c66157fSHoratiu Vultur 		 */
2394c66157fSHoratiu Vultur 		writel(QS_INJ_GRP_CFG_MODE(1) | QS_INJ_GRP_CFG_BYTE_SWAP,
2404c66157fSHoratiu Vultur 		       priv->regs[QS] + QS_INJ_GRP_CFG(i));
2414c66157fSHoratiu Vultur 	}
2424c66157fSHoratiu Vultur 
2434c66157fSHoratiu Vultur 	for (i = 0; i <= 1; i++)
2444c66157fSHoratiu Vultur 		/* Enable IFH insertion/parsing on CPU ports */
2454c66157fSHoratiu Vultur 		writel(SYS_PORT_MODE_INCL_INJ_HDR(1) |
2464c66157fSHoratiu Vultur 		       SYS_PORT_MODE_INCL_XTR_HDR(1),
2474c66157fSHoratiu Vultur 		       priv->regs[SYS] + SYS_PORT_MODE(CPU_PORT + i));
2484c66157fSHoratiu Vultur 	/*
2494c66157fSHoratiu Vultur 	 * Setup the CPU port as VLAN aware to support switching frames
2504c66157fSHoratiu Vultur 	 * based on tags
2514c66157fSHoratiu Vultur 	 */
2524c66157fSHoratiu Vultur 	writel(ANA_PORT_VLAN_CFG_AWARE_ENA | ANA_PORT_VLAN_CFG_POP_CNT(1) |
2534c66157fSHoratiu Vultur 	       MAC_VID, priv->regs[ANA] + ANA_PORT_VLAN_CFG(CPU_PORT));
2544c66157fSHoratiu Vultur 
2554c66157fSHoratiu Vultur 	/* Disable learning (only RECV_ENA must be set) */
2564c66157fSHoratiu Vultur 	writel(ANA_PORT_PORT_CFG_RECV_ENA,
2574c66157fSHoratiu Vultur 	       priv->regs[ANA] + ANA_PORT_PORT_CFG(CPU_PORT));
2584c66157fSHoratiu Vultur 
2594c66157fSHoratiu Vultur 	/* Enable switching to/from cpu port */
2604c66157fSHoratiu Vultur 	setbits_le32(priv->regs[QSYS] + QSYS_SWITCH_PORT_MODE(CPU_PORT),
2614c66157fSHoratiu Vultur 		     QSYS_SWITCH_PORT_MODE_PORT_ENA);
2624c66157fSHoratiu Vultur 
2634c66157fSHoratiu Vultur 	/* No pause on CPU port - not needed (off by default) */
2644c66157fSHoratiu Vultur 	clrbits_le32(priv->regs[SYS] + SYS_PAUSE_CFG(CPU_PORT),
2654c66157fSHoratiu Vultur 		     SYS_PAUSE_CFG_PAUSE_ENA);
2664c66157fSHoratiu Vultur 
2674c66157fSHoratiu Vultur 	setbits_le32(priv->regs[QSYS] + QSYS_EGR_NO_SHARING, BIT(CPU_PORT));
2684c66157fSHoratiu Vultur }
2694c66157fSHoratiu Vultur 
ocelot_port_init(struct ocelot_private * priv,int port)2704c66157fSHoratiu Vultur static void ocelot_port_init(struct ocelot_private *priv, int port)
2714c66157fSHoratiu Vultur {
2724c66157fSHoratiu Vultur 	void __iomem *regs = priv->regs[port];
2734c66157fSHoratiu Vultur 
2744c66157fSHoratiu Vultur 	/* Enable PCS */
2754c66157fSHoratiu Vultur 	writel(PCS1G_MODE_CFG_SGMII_MODE_ENA, regs + PCS1G_CFG);
2764c66157fSHoratiu Vultur 
2774c66157fSHoratiu Vultur 	/* Disable Signal Detect */
2784c66157fSHoratiu Vultur 	writel(0, regs + PCS1G_SD_CFG);
2794c66157fSHoratiu Vultur 
2804c66157fSHoratiu Vultur 	/* Enable MAC RX and TX */
2814c66157fSHoratiu Vultur 	writel(DEV_MAC_ENA_CFG_RX_ENA | DEV_MAC_ENA_CFG_TX_ENA,
2824c66157fSHoratiu Vultur 	       regs + DEV_MAC_ENA_CFG);
2834c66157fSHoratiu Vultur 
2844c66157fSHoratiu Vultur 	/* Clear sgmii_mode_ena */
2854c66157fSHoratiu Vultur 	writel(0, regs + PCS1G_MODE_CFG);
2864c66157fSHoratiu Vultur 
2874c66157fSHoratiu Vultur 	/*
2884c66157fSHoratiu Vultur 	 * Clear sw_resolve_ena(bit 0) and set adv_ability to
2894c66157fSHoratiu Vultur 	 * something meaningful just in case
2904c66157fSHoratiu Vultur 	 */
2914c66157fSHoratiu Vultur 	writel(PCS1G_ANEG_CFG_ADV_ABILITY(0x20), regs + PCS1G_ANEG_CFG);
2924c66157fSHoratiu Vultur 
2934c66157fSHoratiu Vultur 	/* Set MAC IFG Gaps */
2944c66157fSHoratiu Vultur 	writel(DEV_MAC_IFG_CFG_TX_IFG(5) | DEV_MAC_IFG_CFG_RX_IFG1(5) |
2954c66157fSHoratiu Vultur 	       DEV_MAC_IFG_CFG_RX_IFG2(1), regs + DEV_MAC_IFG_CFG);
2964c66157fSHoratiu Vultur 
2974c66157fSHoratiu Vultur 	/* Set link speed and release all resets */
2984c66157fSHoratiu Vultur 	writel(DEV_CLOCK_CFG_LINK_SPEED_1000, regs + DEV_CLOCK_CFG);
2994c66157fSHoratiu Vultur 
3004c66157fSHoratiu Vultur 	/* Make VLAN aware for CPU traffic */
3014c66157fSHoratiu Vultur 	writel(ANA_PORT_VLAN_CFG_AWARE_ENA | ANA_PORT_VLAN_CFG_POP_CNT(1) |
3024c66157fSHoratiu Vultur 	       MAC_VID, priv->regs[ANA] + ANA_PORT_VLAN_CFG(port - PORT0));
3034c66157fSHoratiu Vultur 
3044c66157fSHoratiu Vultur 	/* Enable the port in the core */
3054c66157fSHoratiu Vultur 	setbits_le32(priv->regs[QSYS] + QSYS_SWITCH_PORT_MODE(port - PORT0),
3064c66157fSHoratiu Vultur 		     QSYS_SWITCH_PORT_MODE_PORT_ENA);
3074c66157fSHoratiu Vultur }
3084c66157fSHoratiu Vultur 
ocelot_switch_init(struct ocelot_private * priv)3094c66157fSHoratiu Vultur static int ocelot_switch_init(struct ocelot_private *priv)
3104c66157fSHoratiu Vultur {
3114c66157fSHoratiu Vultur 	/* Reset switch & memories */
3124c66157fSHoratiu Vultur 	writel(SYS_SYSTEM_RST_MEM_ENA | SYS_SYSTEM_RST_MEM_INIT,
3134c66157fSHoratiu Vultur 	       priv->regs[SYS] + SYS_SYSTEM_RST_CFG);
3144c66157fSHoratiu Vultur 
3154c66157fSHoratiu Vultur 	/* Wait to complete */
3164c66157fSHoratiu Vultur 	if (wait_for_bit_le32(priv->regs[SYS] + SYS_SYSTEM_RST_CFG,
3174c66157fSHoratiu Vultur 			      SYS_SYSTEM_RST_MEM_INIT, false, 2000, false)) {
3184c66157fSHoratiu Vultur 		pr_err("Timeout in memory reset\n");
3194c66157fSHoratiu Vultur 		return -EIO;
3204c66157fSHoratiu Vultur 	}
3214c66157fSHoratiu Vultur 
3224c66157fSHoratiu Vultur 	/* Enable switch core */
3234c66157fSHoratiu Vultur 	setbits_le32(priv->regs[SYS] + SYS_SYSTEM_RST_CFG,
3244c66157fSHoratiu Vultur 		     SYS_SYSTEM_RST_CORE_ENA);
3254c66157fSHoratiu Vultur 
3264c66157fSHoratiu Vultur 	return 0;
3274c66157fSHoratiu Vultur }
3284c66157fSHoratiu Vultur 
ocelot_initialize(struct ocelot_private * priv)3294c66157fSHoratiu Vultur static int ocelot_initialize(struct ocelot_private *priv)
3304c66157fSHoratiu Vultur {
3314c66157fSHoratiu Vultur 	int ret, i;
3324c66157fSHoratiu Vultur 
3334c66157fSHoratiu Vultur 	/* Initialize switch memories, enable core */
3344c66157fSHoratiu Vultur 	ret = ocelot_switch_init(priv);
3354c66157fSHoratiu Vultur 	if (ret)
3364c66157fSHoratiu Vultur 		return ret;
3374c66157fSHoratiu Vultur 	/*
3384c66157fSHoratiu Vultur 	 * Disable port-to-port by switching
3394c66157fSHoratiu Vultur 	 * Put fron ports in "port isolation modes" - i.e. they cant send
3404c66157fSHoratiu Vultur 	 * to other ports - via the PGID sorce masks.
3414c66157fSHoratiu Vultur 	 */
3424c66157fSHoratiu Vultur 	for (i = 0; i <= MAX_PORT; i++)
3434c66157fSHoratiu Vultur 		writel(0, priv->regs[ANA] + ANA_PGID(PGID_SRC + i));
3444c66157fSHoratiu Vultur 
3454c66157fSHoratiu Vultur 	/* Flush queues */
34636d04f52SHoratiu Vultur 	mscc_flush(priv->regs[QS], ocelot_regs_qs);
3474c66157fSHoratiu Vultur 
3484c66157fSHoratiu Vultur 	/* Setup frame ageing - "2 sec" - The unit is 6.5us on Ocelot */
3494c66157fSHoratiu Vultur 	writel(SYS_FRM_AGING_ENA | (20000000 / 65),
3504c66157fSHoratiu Vultur 	       priv->regs[SYS] + SYS_FRM_AGING);
3514c66157fSHoratiu Vultur 
3524c66157fSHoratiu Vultur 	for (i = PORT0; i <= PORT3; i++)
3534c66157fSHoratiu Vultur 		ocelot_port_init(priv, i);
3544c66157fSHoratiu Vultur 
3554c66157fSHoratiu Vultur 	ocelot_cpu_capture_setup(priv);
3564c66157fSHoratiu Vultur 
3574c66157fSHoratiu Vultur 	debug("Ports enabled\n");
3584c66157fSHoratiu Vultur 
3594c66157fSHoratiu Vultur 	return 0;
3604c66157fSHoratiu Vultur }
3614c66157fSHoratiu Vultur 
ocelot_write_hwaddr(struct udevice * dev)3624c66157fSHoratiu Vultur static int ocelot_write_hwaddr(struct udevice *dev)
3634c66157fSHoratiu Vultur {
3644c66157fSHoratiu Vultur 	struct ocelot_private *priv = dev_get_priv(dev);
3654c66157fSHoratiu Vultur 	struct eth_pdata *pdata = dev_get_platdata(dev);
3664c66157fSHoratiu Vultur 
36745f2748cSHoratiu Vultur 	mscc_mac_table_add(priv->regs[ANA], ocelot_regs_ana_table,
36845f2748cSHoratiu Vultur 			   pdata->enetaddr, PGID_UNICAST);
3694c66157fSHoratiu Vultur 
3704c66157fSHoratiu Vultur 	writel(BIT(CPU_PORT), priv->regs[ANA] + ANA_PGID(PGID_UNICAST));
3714c66157fSHoratiu Vultur 
3724c66157fSHoratiu Vultur 	return 0;
3734c66157fSHoratiu Vultur }
3744c66157fSHoratiu Vultur 
ocelot_start(struct udevice * dev)3754c66157fSHoratiu Vultur static int ocelot_start(struct udevice *dev)
3764c66157fSHoratiu Vultur {
3774c66157fSHoratiu Vultur 	struct ocelot_private *priv = dev_get_priv(dev);
3784c66157fSHoratiu Vultur 	struct eth_pdata *pdata = dev_get_platdata(dev);
3794c66157fSHoratiu Vultur 	const unsigned char mac[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff,
3804c66157fSHoratiu Vultur 					      0xff };
3814c66157fSHoratiu Vultur 	int ret;
3824c66157fSHoratiu Vultur 
3834c66157fSHoratiu Vultur 	ret = ocelot_initialize(priv);
3844c66157fSHoratiu Vultur 	if (ret)
3854c66157fSHoratiu Vultur 		return ret;
3864c66157fSHoratiu Vultur 
3874c66157fSHoratiu Vultur 	/* Set MAC address tables entries for CPU redirection */
38845f2748cSHoratiu Vultur 	mscc_mac_table_add(priv->regs[ANA], ocelot_regs_ana_table, mac,
38945f2748cSHoratiu Vultur 			   PGID_BROADCAST);
3904c66157fSHoratiu Vultur 
3914c66157fSHoratiu Vultur 	writel(BIT(CPU_PORT) | INTERNAL_PORT_MSK,
3924c66157fSHoratiu Vultur 	       priv->regs[ANA] + ANA_PGID(PGID_BROADCAST));
3934c66157fSHoratiu Vultur 
3944c66157fSHoratiu Vultur 	/* It should be setup latter in ocelot_write_hwaddr */
39545f2748cSHoratiu Vultur 	mscc_mac_table_add(priv->regs[ANA], ocelot_regs_ana_table,
39645f2748cSHoratiu Vultur 			   pdata->enetaddr, PGID_UNICAST);
3974c66157fSHoratiu Vultur 
3984c66157fSHoratiu Vultur 	writel(BIT(CPU_PORT), priv->regs[ANA] + ANA_PGID(PGID_UNICAST));
3994c66157fSHoratiu Vultur 
4004c66157fSHoratiu Vultur 	return 0;
4014c66157fSHoratiu Vultur }
4024c66157fSHoratiu Vultur 
ocelot_send(struct udevice * dev,void * packet,int length)4034c66157fSHoratiu Vultur static int ocelot_send(struct udevice *dev, void *packet, int length)
4044c66157fSHoratiu Vultur {
4054c66157fSHoratiu Vultur 	struct ocelot_private *priv = dev_get_priv(dev);
4064c66157fSHoratiu Vultur 	u32 ifh[IFH_LEN];
4074c66157fSHoratiu Vultur 	int port = BIT(0);	/* use port 0 */
4084c66157fSHoratiu Vultur 	u32 *buf = packet;
4094c66157fSHoratiu Vultur 
4104c66157fSHoratiu Vultur 	/*
4114c66157fSHoratiu Vultur 	 * Generate the IFH for frame injection
4124c66157fSHoratiu Vultur 	 *
4134c66157fSHoratiu Vultur 	 * The IFH is a 128bit-value
4144c66157fSHoratiu Vultur 	 * bit 127: bypass the analyzer processing
4154c66157fSHoratiu Vultur 	 * bit 56-67: destination mask
4164c66157fSHoratiu Vultur 	 * bit 28-29: pop_cnt: 3 disables all rewriting of the frame
4174c66157fSHoratiu Vultur 	 * bit 20-27: cpu extraction queue mask
4184c66157fSHoratiu Vultur 	 * bit 16: tag type 0: C-tag, 1: S-tag
4194c66157fSHoratiu Vultur 	 * bit 0-11: VID
4204c66157fSHoratiu Vultur 	 */
4214c66157fSHoratiu Vultur 	ifh[0] = IFH_INJ_BYPASS;
4224c66157fSHoratiu Vultur 	ifh[1] = (0xf00 & port) >> 8;
4234c66157fSHoratiu Vultur 	ifh[2] = (0xff & port) << 24;
4244c66157fSHoratiu Vultur 	ifh[3] = (IFH_TAG_TYPE_C << 16);
4254c66157fSHoratiu Vultur 
42636d04f52SHoratiu Vultur 	return mscc_send(priv->regs[QS], ocelot_regs_qs,
42736d04f52SHoratiu Vultur 			 ifh, IFH_LEN, buf, length);
4284c66157fSHoratiu Vultur }
4294c66157fSHoratiu Vultur 
ocelot_recv(struct udevice * dev,int flags,uchar ** packetp)4304c66157fSHoratiu Vultur static int ocelot_recv(struct udevice *dev, int flags, uchar **packetp)
4314c66157fSHoratiu Vultur {
4324c66157fSHoratiu Vultur 	struct ocelot_private *priv = dev_get_priv(dev);
4334c66157fSHoratiu Vultur 	u32 *rxbuf = (u32 *)net_rx_packets[0];
43436d04f52SHoratiu Vultur 	int byte_cnt;
4354c66157fSHoratiu Vultur 
43636d04f52SHoratiu Vultur 	byte_cnt = mscc_recv(priv->regs[QS], ocelot_regs_qs, rxbuf, IFH_LEN,
43736d04f52SHoratiu Vultur 			     false);
4384c66157fSHoratiu Vultur 
4394c66157fSHoratiu Vultur 	*packetp = net_rx_packets[0];
4404c66157fSHoratiu Vultur 
4414c66157fSHoratiu Vultur 	return byte_cnt;
4424c66157fSHoratiu Vultur }
4434c66157fSHoratiu Vultur 
ocelot_probe(struct udevice * dev)4444c66157fSHoratiu Vultur static int ocelot_probe(struct udevice *dev)
4454c66157fSHoratiu Vultur {
4464c66157fSHoratiu Vultur 	struct ocelot_private *priv = dev_get_priv(dev);
4474c66157fSHoratiu Vultur 	int ret, i;
4484c66157fSHoratiu Vultur 
4494c66157fSHoratiu Vultur 	struct {
4504c66157fSHoratiu Vultur 		enum ocelot_target id;
4514c66157fSHoratiu Vultur 		char *name;
4524c66157fSHoratiu Vultur 	} reg[] = {
4534c66157fSHoratiu Vultur 		{ SYS, "sys" },
4544c66157fSHoratiu Vultur 		{ REW, "rew" },
4554c66157fSHoratiu Vultur 		{ QSYS, "qsys" },
4564c66157fSHoratiu Vultur 		{ ANA, "ana" },
4574c66157fSHoratiu Vultur 		{ QS, "qs" },
4584c66157fSHoratiu Vultur 		{ HSIO, "hsio" },
4594c66157fSHoratiu Vultur 		{ PORT0, "port0" },
4604c66157fSHoratiu Vultur 		{ PORT1, "port1" },
4614c66157fSHoratiu Vultur 		{ PORT2, "port2" },
4624c66157fSHoratiu Vultur 		{ PORT3, "port3" },
4634c66157fSHoratiu Vultur 	};
4644c66157fSHoratiu Vultur 
4654c66157fSHoratiu Vultur 	for (i = 0; i < ARRAY_SIZE(reg); i++) {
4664c66157fSHoratiu Vultur 		priv->regs[reg[i].id] = dev_remap_addr_name(dev, reg[i].name);
4674c66157fSHoratiu Vultur 		if (!priv->regs[reg[i].id]) {
4684c66157fSHoratiu Vultur 			pr_err
4694c66157fSHoratiu Vultur 			    ("Error %d: can't get regs base addresses for %s\n",
4704c66157fSHoratiu Vultur 			     ret, reg[i].name);
4714c66157fSHoratiu Vultur 			return -ENOMEM;
4724c66157fSHoratiu Vultur 		}
4734c66157fSHoratiu Vultur 	}
4744c66157fSHoratiu Vultur 
4754c66157fSHoratiu Vultur 	priv->bus[INTERNAL] = ocelot_mdiobus_init(dev);
4764c66157fSHoratiu Vultur 
4774c66157fSHoratiu Vultur 	for (i = 0; i < 4; i++) {
4784c66157fSHoratiu Vultur 		phy_connect(priv->bus[INTERNAL], i, dev,
4794c66157fSHoratiu Vultur 			    PHY_INTERFACE_MODE_NONE);
4804c66157fSHoratiu Vultur 	}
4814c66157fSHoratiu Vultur 
4824c66157fSHoratiu Vultur 	return 0;
4834c66157fSHoratiu Vultur }
4844c66157fSHoratiu Vultur 
ocelot_remove(struct udevice * dev)4854c66157fSHoratiu Vultur static int ocelot_remove(struct udevice *dev)
4864c66157fSHoratiu Vultur {
4874c66157fSHoratiu Vultur 	struct ocelot_private *priv = dev_get_priv(dev);
4884c66157fSHoratiu Vultur 	int i;
4894c66157fSHoratiu Vultur 
4904c66157fSHoratiu Vultur 	for (i = 0; i < NUM_PHY; i++) {
4914c66157fSHoratiu Vultur 		mdio_unregister(priv->bus[i]);
4924c66157fSHoratiu Vultur 		mdio_free(priv->bus[i]);
4934c66157fSHoratiu Vultur 	}
4944c66157fSHoratiu Vultur 
4954c66157fSHoratiu Vultur 	return 0;
4964c66157fSHoratiu Vultur }
4974c66157fSHoratiu Vultur 
4984c66157fSHoratiu Vultur static const struct eth_ops ocelot_ops = {
4994c66157fSHoratiu Vultur 	.start        = ocelot_start,
5004c66157fSHoratiu Vultur 	.stop         = ocelot_stop,
5014c66157fSHoratiu Vultur 	.send         = ocelot_send,
5024c66157fSHoratiu Vultur 	.recv         = ocelot_recv,
5034c66157fSHoratiu Vultur 	.write_hwaddr = ocelot_write_hwaddr,
5044c66157fSHoratiu Vultur };
5054c66157fSHoratiu Vultur 
5064c66157fSHoratiu Vultur static const struct udevice_id mscc_ocelot_ids[] = {
5074c66157fSHoratiu Vultur 	{.compatible = "mscc,vsc7514-switch"},
5084c66157fSHoratiu Vultur 	{ /* Sentinel */ }
5094c66157fSHoratiu Vultur };
5104c66157fSHoratiu Vultur 
5114c66157fSHoratiu Vultur U_BOOT_DRIVER(ocelot) = {
5124c66157fSHoratiu Vultur 	.name     = "ocelot-switch",
5134c66157fSHoratiu Vultur 	.id       = UCLASS_ETH,
5144c66157fSHoratiu Vultur 	.of_match = mscc_ocelot_ids,
5154c66157fSHoratiu Vultur 	.probe	  = ocelot_probe,
5164c66157fSHoratiu Vultur 	.remove	  = ocelot_remove,
5174c66157fSHoratiu Vultur 	.ops	  = &ocelot_ops,
5184c66157fSHoratiu Vultur 	.priv_auto_alloc_size = sizeof(struct ocelot_private),
5194c66157fSHoratiu Vultur 	.platdata_auto_alloc_size = sizeof(struct eth_pdata),
5204c66157fSHoratiu Vultur };
521