xref: /openbmc/u-boot/drivers/net/mscc_eswitch/ocelot_switch.c (revision 4c66157f427ad87d683b76d6819a00138e9f71dd)
1*4c66157fSHoratiu Vultur // SPDX-License-Identifier: (GPL-2.0+ OR MIT)
2*4c66157fSHoratiu Vultur /*
3*4c66157fSHoratiu Vultur  * Copyright (c) 2018 Microsemi Corporation
4*4c66157fSHoratiu Vultur  */
5*4c66157fSHoratiu Vultur 
6*4c66157fSHoratiu Vultur #include <common.h>
7*4c66157fSHoratiu Vultur #include <config.h>
8*4c66157fSHoratiu Vultur #include <dm.h>
9*4c66157fSHoratiu Vultur #include <dm/of_access.h>
10*4c66157fSHoratiu Vultur #include <dm/of_addr.h>
11*4c66157fSHoratiu Vultur #include <fdt_support.h>
12*4c66157fSHoratiu Vultur #include <linux/io.h>
13*4c66157fSHoratiu Vultur #include <linux/ioport.h>
14*4c66157fSHoratiu Vultur #include <miiphy.h>
15*4c66157fSHoratiu Vultur #include <net.h>
16*4c66157fSHoratiu Vultur #include <wait_bit.h>
17*4c66157fSHoratiu Vultur 
18*4c66157fSHoratiu Vultur #define MIIM_STATUS			0x0
19*4c66157fSHoratiu Vultur #define		MIIM_STAT_BUSY			BIT(3)
20*4c66157fSHoratiu Vultur #define MIIM_CMD			0x8
21*4c66157fSHoratiu Vultur #define		MIIM_CMD_SCAN		BIT(0)
22*4c66157fSHoratiu Vultur #define		MIIM_CMD_OPR_WRITE	BIT(1)
23*4c66157fSHoratiu Vultur #define		MIIM_CMD_OPR_READ	BIT(2)
24*4c66157fSHoratiu Vultur #define		MIIM_CMD_SINGLE_SCAN	BIT(3)
25*4c66157fSHoratiu Vultur #define		MIIM_CMD_WRDATA(x)	((x) << 4)
26*4c66157fSHoratiu Vultur #define		MIIM_CMD_REGAD(x)	((x) << 20)
27*4c66157fSHoratiu Vultur #define		MIIM_CMD_PHYAD(x)	((x) << 25)
28*4c66157fSHoratiu Vultur #define		MIIM_CMD_VLD		BIT(31)
29*4c66157fSHoratiu Vultur #define MIIM_DATA			0xC
30*4c66157fSHoratiu Vultur #define		MIIM_DATA_ERROR		(0x2 << 16)
31*4c66157fSHoratiu Vultur 
32*4c66157fSHoratiu Vultur #define PHY_CFG				0x0
33*4c66157fSHoratiu Vultur #define PHY_CFG_ENA				0xF
34*4c66157fSHoratiu Vultur #define PHY_CFG_COMMON_RST			BIT(4)
35*4c66157fSHoratiu Vultur #define PHY_CFG_RST				(0xF << 5)
36*4c66157fSHoratiu Vultur #define PHY_STAT			0x4
37*4c66157fSHoratiu Vultur #define PHY_STAT_SUPERVISOR_COMPLETE		BIT(0)
38*4c66157fSHoratiu Vultur 
39*4c66157fSHoratiu Vultur #define ANA_PORT_VLAN_CFG(x)		(0x7000 + 0x100 * (x))
40*4c66157fSHoratiu Vultur #define		ANA_PORT_VLAN_CFG_AWARE_ENA	BIT(20)
41*4c66157fSHoratiu Vultur #define		ANA_PORT_VLAN_CFG_POP_CNT(x)	((x) << 18)
42*4c66157fSHoratiu Vultur #define ANA_PORT_PORT_CFG(x)		(0x7070 + 0x100 * (x))
43*4c66157fSHoratiu Vultur #define		ANA_PORT_PORT_CFG_RECV_ENA	BIT(6)
44*4c66157fSHoratiu Vultur #define	ANA_TABLES_MACHDATA		0x8b34
45*4c66157fSHoratiu Vultur #define	ANA_TABLES_MACLDATA		0x8b38
46*4c66157fSHoratiu Vultur #define ANA_TABLES_MACACCESS		0x8b3c
47*4c66157fSHoratiu Vultur #define		ANA_TABLES_MACACCESS_VALID	BIT(11)
48*4c66157fSHoratiu Vultur #define		ANA_TABLES_MACACCESS_ENTRYTYPE(x)   ((x) << 9)
49*4c66157fSHoratiu Vultur #define		ANA_TABLES_MACACCESS_DEST_IDX(x)    ((x) << 3)
50*4c66157fSHoratiu Vultur #define		ANA_TABLES_MACACCESS_MAC_TABLE_CMD(x)	(x)
51*4c66157fSHoratiu Vultur #define		ANA_TABLES_MACACCESS_MAC_TABLE_CMD_M	GENMASK(2, 0)
52*4c66157fSHoratiu Vultur #define		MACACCESS_CMD_IDLE                     0
53*4c66157fSHoratiu Vultur #define		MACACCESS_CMD_LEARN                    1
54*4c66157fSHoratiu Vultur #define		MACACCESS_CMD_GET_NEXT                 4
55*4c66157fSHoratiu Vultur #define ANA_PGID(x)			(0x8c00 + 4 * (x))
56*4c66157fSHoratiu Vultur 
57*4c66157fSHoratiu Vultur #define SYS_FRM_AGING			0x574
58*4c66157fSHoratiu Vultur #define		SYS_FRM_AGING_ENA		BIT(20)
59*4c66157fSHoratiu Vultur 
60*4c66157fSHoratiu Vultur #define SYS_SYSTEM_RST_CFG		0x508
61*4c66157fSHoratiu Vultur #define		SYS_SYSTEM_RST_MEM_INIT		BIT(0)
62*4c66157fSHoratiu Vultur #define		SYS_SYSTEM_RST_MEM_ENA		BIT(1)
63*4c66157fSHoratiu Vultur #define		SYS_SYSTEM_RST_CORE_ENA		BIT(2)
64*4c66157fSHoratiu Vultur #define SYS_PORT_MODE(x)		(0x514 + 0x4 * (x))
65*4c66157fSHoratiu Vultur #define		SYS_PORT_MODE_INCL_INJ_HDR(x)	((x) << 3)
66*4c66157fSHoratiu Vultur #define		SYS_PORT_MODE_INCL_INJ_HDR_M	GENMASK(4, 3)
67*4c66157fSHoratiu Vultur #define		SYS_PORT_MODE_INCL_XTR_HDR(x)	((x) << 1)
68*4c66157fSHoratiu Vultur #define		SYS_PORT_MODE_INCL_XTR_HDR_M	GENMASK(2, 1)
69*4c66157fSHoratiu Vultur #define	SYS_PAUSE_CFG(x)		(0x608 + 0x4 * (x))
70*4c66157fSHoratiu Vultur #define		SYS_PAUSE_CFG_PAUSE_ENA		BIT(0)
71*4c66157fSHoratiu Vultur 
72*4c66157fSHoratiu Vultur #define QSYS_SWITCH_PORT_MODE(x)	(0x11234 + 0x4 * (x))
73*4c66157fSHoratiu Vultur #define		QSYS_SWITCH_PORT_MODE_PORT_ENA	BIT(14)
74*4c66157fSHoratiu Vultur #define	QSYS_QMAP			0x112d8
75*4c66157fSHoratiu Vultur #define	QSYS_EGR_NO_SHARING		0x1129c
76*4c66157fSHoratiu Vultur 
77*4c66157fSHoratiu Vultur /* Port registers */
78*4c66157fSHoratiu Vultur #define DEV_CLOCK_CFG			0x0
79*4c66157fSHoratiu Vultur #define DEV_CLOCK_CFG_LINK_SPEED_1000		1
80*4c66157fSHoratiu Vultur #define DEV_MAC_ENA_CFG			0x1c
81*4c66157fSHoratiu Vultur #define		DEV_MAC_ENA_CFG_RX_ENA		BIT(4)
82*4c66157fSHoratiu Vultur #define		DEV_MAC_ENA_CFG_TX_ENA		BIT(0)
83*4c66157fSHoratiu Vultur 
84*4c66157fSHoratiu Vultur #define DEV_MAC_IFG_CFG			0x30
85*4c66157fSHoratiu Vultur #define		DEV_MAC_IFG_CFG_TX_IFG(x)	((x) << 8)
86*4c66157fSHoratiu Vultur #define		DEV_MAC_IFG_CFG_RX_IFG2(x)	((x) << 4)
87*4c66157fSHoratiu Vultur #define		DEV_MAC_IFG_CFG_RX_IFG1(x)	(x)
88*4c66157fSHoratiu Vultur 
89*4c66157fSHoratiu Vultur #define PCS1G_CFG			0x48
90*4c66157fSHoratiu Vultur #define		PCS1G_MODE_CFG_SGMII_MODE_ENA	BIT(0)
91*4c66157fSHoratiu Vultur #define PCS1G_MODE_CFG			0x4c
92*4c66157fSHoratiu Vultur #define		PCS1G_MODE_CFG_UNIDIR_MODE_ENA	BIT(4)
93*4c66157fSHoratiu Vultur #define		PCS1G_MODE_CFG_SGMII_MODE_ENA	BIT(0)
94*4c66157fSHoratiu Vultur #define PCS1G_SD_CFG			0x50
95*4c66157fSHoratiu Vultur #define PCS1G_ANEG_CFG			0x54
96*4c66157fSHoratiu Vultur #define		PCS1G_ANEG_CFG_ADV_ABILITY(x)	((x) << 16)
97*4c66157fSHoratiu Vultur 
98*4c66157fSHoratiu Vultur #define QS_XTR_GRP_CFG(x)		(4 * (x))
99*4c66157fSHoratiu Vultur #define QS_XTR_GRP_CFG_MODE(x)			((x) << 2)
100*4c66157fSHoratiu Vultur #define		QS_XTR_GRP_CFG_STATUS_WORD_POS	BIT(1)
101*4c66157fSHoratiu Vultur #define		QS_XTR_GRP_CFG_BYTE_SWAP	BIT(0)
102*4c66157fSHoratiu Vultur #define QS_XTR_RD(x)			(0x8 + 4 * (x))
103*4c66157fSHoratiu Vultur #define QS_XTR_FLUSH			0x18
104*4c66157fSHoratiu Vultur #define		QS_XTR_FLUSH_FLUSH		GENMASK(1, 0)
105*4c66157fSHoratiu Vultur #define QS_XTR_DATA_PRESENT		0x1c
106*4c66157fSHoratiu Vultur #define QS_INJ_GRP_CFG(x)		(0x24 + (x) * 4)
107*4c66157fSHoratiu Vultur #define		QS_INJ_GRP_CFG_MODE(x)		((x) << 2)
108*4c66157fSHoratiu Vultur #define		QS_INJ_GRP_CFG_BYTE_SWAP	BIT(0)
109*4c66157fSHoratiu Vultur #define QS_INJ_WR(x)			(0x2c + 4 * (x))
110*4c66157fSHoratiu Vultur #define QS_INJ_CTRL(x)			(0x34 + 4 * (x))
111*4c66157fSHoratiu Vultur #define		QS_INJ_CTRL_GAP_SIZE(x)		((x) << 21)
112*4c66157fSHoratiu Vultur #define		QS_INJ_CTRL_EOF			BIT(19)
113*4c66157fSHoratiu Vultur #define		QS_INJ_CTRL_SOF			BIT(18)
114*4c66157fSHoratiu Vultur #define		QS_INJ_CTRL_VLD_BYTES(x)	((x) << 16)
115*4c66157fSHoratiu Vultur 
116*4c66157fSHoratiu Vultur #define XTR_EOF_0     ntohl(0x80000000u)
117*4c66157fSHoratiu Vultur #define XTR_EOF_1     ntohl(0x80000001u)
118*4c66157fSHoratiu Vultur #define XTR_EOF_2     ntohl(0x80000002u)
119*4c66157fSHoratiu Vultur #define XTR_EOF_3     ntohl(0x80000003u)
120*4c66157fSHoratiu Vultur #define XTR_PRUNED    ntohl(0x80000004u)
121*4c66157fSHoratiu Vultur #define XTR_ABORT     ntohl(0x80000005u)
122*4c66157fSHoratiu Vultur #define XTR_ESCAPE    ntohl(0x80000006u)
123*4c66157fSHoratiu Vultur #define XTR_NOT_READY ntohl(0x80000007u)
124*4c66157fSHoratiu Vultur 
125*4c66157fSHoratiu Vultur #define IFH_INJ_BYPASS		BIT(31)
126*4c66157fSHoratiu Vultur #define	IFH_TAG_TYPE_C		0
127*4c66157fSHoratiu Vultur #define XTR_VALID_BYTES(x)	(4 - ((x) & 3))
128*4c66157fSHoratiu Vultur #define	MAC_VID			1
129*4c66157fSHoratiu Vultur #define CPU_PORT		11
130*4c66157fSHoratiu Vultur #define INTERNAL_PORT_MSK	0xF
131*4c66157fSHoratiu Vultur #define IFH_LEN			4
132*4c66157fSHoratiu Vultur #define OCELOT_BUF_CELL_SZ	60
133*4c66157fSHoratiu Vultur #define ETH_ALEN		6
134*4c66157fSHoratiu Vultur #define	PGID_BROADCAST		13
135*4c66157fSHoratiu Vultur #define	PGID_UNICAST		14
136*4c66157fSHoratiu Vultur #define	PGID_SRC		80
137*4c66157fSHoratiu Vultur 
138*4c66157fSHoratiu Vultur enum ocelot_target {
139*4c66157fSHoratiu Vultur 	ANA,
140*4c66157fSHoratiu Vultur 	QS,
141*4c66157fSHoratiu Vultur 	QSYS,
142*4c66157fSHoratiu Vultur 	REW,
143*4c66157fSHoratiu Vultur 	SYS,
144*4c66157fSHoratiu Vultur 	HSIO,
145*4c66157fSHoratiu Vultur 	PORT0,
146*4c66157fSHoratiu Vultur 	PORT1,
147*4c66157fSHoratiu Vultur 	PORT2,
148*4c66157fSHoratiu Vultur 	PORT3,
149*4c66157fSHoratiu Vultur 	TARGET_MAX,
150*4c66157fSHoratiu Vultur };
151*4c66157fSHoratiu Vultur 
152*4c66157fSHoratiu Vultur #define MAX_PORT (PORT3 - PORT0)
153*4c66157fSHoratiu Vultur 
154*4c66157fSHoratiu Vultur /* MAC table entry types.
155*4c66157fSHoratiu Vultur  * ENTRYTYPE_NORMAL is subject to aging.
156*4c66157fSHoratiu Vultur  * ENTRYTYPE_LOCKED is not subject to aging.
157*4c66157fSHoratiu Vultur  * ENTRYTYPE_MACv4 is not subject to aging. For IPv4 multicast.
158*4c66157fSHoratiu Vultur  * ENTRYTYPE_MACv6 is not subject to aging. For IPv6 multicast.
159*4c66157fSHoratiu Vultur  */
160*4c66157fSHoratiu Vultur enum macaccess_entry_type {
161*4c66157fSHoratiu Vultur 	ENTRYTYPE_NORMAL = 0,
162*4c66157fSHoratiu Vultur 	ENTRYTYPE_LOCKED,
163*4c66157fSHoratiu Vultur 	ENTRYTYPE_MACv4,
164*4c66157fSHoratiu Vultur 	ENTRYTYPE_MACv6,
165*4c66157fSHoratiu Vultur };
166*4c66157fSHoratiu Vultur 
167*4c66157fSHoratiu Vultur enum ocelot_mdio_target {
168*4c66157fSHoratiu Vultur 	MIIM,
169*4c66157fSHoratiu Vultur 	PHY,
170*4c66157fSHoratiu Vultur 	TARGET_MDIO_MAX,
171*4c66157fSHoratiu Vultur };
172*4c66157fSHoratiu Vultur 
173*4c66157fSHoratiu Vultur enum ocelot_phy_id {
174*4c66157fSHoratiu Vultur 	INTERNAL,
175*4c66157fSHoratiu Vultur 	EXTERNAL,
176*4c66157fSHoratiu Vultur 	NUM_PHY,
177*4c66157fSHoratiu Vultur };
178*4c66157fSHoratiu Vultur 
179*4c66157fSHoratiu Vultur struct ocelot_private {
180*4c66157fSHoratiu Vultur 	void __iomem *regs[TARGET_MAX];
181*4c66157fSHoratiu Vultur 
182*4c66157fSHoratiu Vultur 	struct mii_dev *bus[NUM_PHY];
183*4c66157fSHoratiu Vultur 	struct phy_device *phydev;
184*4c66157fSHoratiu Vultur 	int phy_mode;
185*4c66157fSHoratiu Vultur 	int max_speed;
186*4c66157fSHoratiu Vultur 
187*4c66157fSHoratiu Vultur 	int rx_pos;
188*4c66157fSHoratiu Vultur 	int rx_siz;
189*4c66157fSHoratiu Vultur 	int rx_off;
190*4c66157fSHoratiu Vultur 	int tx_num;
191*4c66157fSHoratiu Vultur 
192*4c66157fSHoratiu Vultur 	u8 tx_adj_packetbuf[PKTSIZE_ALIGN + PKTALIGN];
193*4c66157fSHoratiu Vultur 	void *tx_adj_buf;
194*4c66157fSHoratiu Vultur };
195*4c66157fSHoratiu Vultur 
196*4c66157fSHoratiu Vultur struct mscc_miim_dev {
197*4c66157fSHoratiu Vultur 	void __iomem *regs;
198*4c66157fSHoratiu Vultur 	void __iomem *phy_regs;
199*4c66157fSHoratiu Vultur };
200*4c66157fSHoratiu Vultur 
201*4c66157fSHoratiu Vultur struct mscc_miim_dev miim[NUM_PHY];
202*4c66157fSHoratiu Vultur 
203*4c66157fSHoratiu Vultur static int mscc_miim_wait_ready(struct mscc_miim_dev *miim)
204*4c66157fSHoratiu Vultur {
205*4c66157fSHoratiu Vultur 	return wait_for_bit_le32(miim->regs + MIIM_STATUS, MIIM_STAT_BUSY,
206*4c66157fSHoratiu Vultur 				 false, 250, false);
207*4c66157fSHoratiu Vultur }
208*4c66157fSHoratiu Vultur 
209*4c66157fSHoratiu Vultur static int mscc_miim_reset(struct mii_dev *bus)
210*4c66157fSHoratiu Vultur {
211*4c66157fSHoratiu Vultur 	struct mscc_miim_dev *miim = (struct mscc_miim_dev *)bus->priv;
212*4c66157fSHoratiu Vultur 
213*4c66157fSHoratiu Vultur 	if (miim->phy_regs) {
214*4c66157fSHoratiu Vultur 		writel(0, miim->phy_regs + PHY_CFG);
215*4c66157fSHoratiu Vultur 		writel(PHY_CFG_RST | PHY_CFG_COMMON_RST
216*4c66157fSHoratiu Vultur 		       | PHY_CFG_ENA, miim->phy_regs + PHY_CFG);
217*4c66157fSHoratiu Vultur 		mdelay(500);
218*4c66157fSHoratiu Vultur 	}
219*4c66157fSHoratiu Vultur 
220*4c66157fSHoratiu Vultur 	return 0;
221*4c66157fSHoratiu Vultur }
222*4c66157fSHoratiu Vultur 
223*4c66157fSHoratiu Vultur static int mscc_miim_read(struct mii_dev *bus, int addr, int devad, int reg)
224*4c66157fSHoratiu Vultur {
225*4c66157fSHoratiu Vultur 	struct mscc_miim_dev *miim = (struct mscc_miim_dev *)bus->priv;
226*4c66157fSHoratiu Vultur 	u32 val;
227*4c66157fSHoratiu Vultur 	int ret;
228*4c66157fSHoratiu Vultur 
229*4c66157fSHoratiu Vultur 	ret = mscc_miim_wait_ready(miim);
230*4c66157fSHoratiu Vultur 	if (ret)
231*4c66157fSHoratiu Vultur 		goto out;
232*4c66157fSHoratiu Vultur 
233*4c66157fSHoratiu Vultur 	writel(MIIM_CMD_VLD | MIIM_CMD_PHYAD(addr) |
234*4c66157fSHoratiu Vultur 	       MIIM_CMD_REGAD(reg) | MIIM_CMD_OPR_READ,
235*4c66157fSHoratiu Vultur 	       miim->regs + MIIM_CMD);
236*4c66157fSHoratiu Vultur 
237*4c66157fSHoratiu Vultur 	ret = mscc_miim_wait_ready(miim);
238*4c66157fSHoratiu Vultur 	if (ret)
239*4c66157fSHoratiu Vultur 		goto out;
240*4c66157fSHoratiu Vultur 
241*4c66157fSHoratiu Vultur 	val = readl(miim->regs + MIIM_DATA);
242*4c66157fSHoratiu Vultur 	if (val & MIIM_DATA_ERROR) {
243*4c66157fSHoratiu Vultur 		ret = -EIO;
244*4c66157fSHoratiu Vultur 		goto out;
245*4c66157fSHoratiu Vultur 	}
246*4c66157fSHoratiu Vultur 
247*4c66157fSHoratiu Vultur 	ret = val & 0xFFFF;
248*4c66157fSHoratiu Vultur  out:
249*4c66157fSHoratiu Vultur 	return ret;
250*4c66157fSHoratiu Vultur }
251*4c66157fSHoratiu Vultur 
252*4c66157fSHoratiu Vultur static int mscc_miim_write(struct mii_dev *bus, int addr, int devad, int reg,
253*4c66157fSHoratiu Vultur 			   u16 val)
254*4c66157fSHoratiu Vultur {
255*4c66157fSHoratiu Vultur 	struct mscc_miim_dev *miim = (struct mscc_miim_dev *)bus->priv;
256*4c66157fSHoratiu Vultur 	int ret;
257*4c66157fSHoratiu Vultur 
258*4c66157fSHoratiu Vultur 	ret = mscc_miim_wait_ready(miim);
259*4c66157fSHoratiu Vultur 	if (ret < 0)
260*4c66157fSHoratiu Vultur 		goto out;
261*4c66157fSHoratiu Vultur 
262*4c66157fSHoratiu Vultur 	writel(MIIM_CMD_VLD | MIIM_CMD_PHYAD(addr) |
263*4c66157fSHoratiu Vultur 	       MIIM_CMD_REGAD(reg) | MIIM_CMD_WRDATA(val) |
264*4c66157fSHoratiu Vultur 	       MIIM_CMD_OPR_WRITE, miim->regs + MIIM_CMD);
265*4c66157fSHoratiu Vultur  out:
266*4c66157fSHoratiu Vultur 	return ret;
267*4c66157fSHoratiu Vultur }
268*4c66157fSHoratiu Vultur 
269*4c66157fSHoratiu Vultur /* For now only setup the internal mdio bus */
270*4c66157fSHoratiu Vultur static struct mii_dev *ocelot_mdiobus_init(struct udevice *dev)
271*4c66157fSHoratiu Vultur {
272*4c66157fSHoratiu Vultur 	unsigned long phy_size[TARGET_MAX];
273*4c66157fSHoratiu Vultur 	phys_addr_t phy_base[TARGET_MAX];
274*4c66157fSHoratiu Vultur 	struct ofnode_phandle_args phandle;
275*4c66157fSHoratiu Vultur 	ofnode eth_node, node, mdio_node;
276*4c66157fSHoratiu Vultur 	struct resource res;
277*4c66157fSHoratiu Vultur 	struct mii_dev *bus;
278*4c66157fSHoratiu Vultur 	fdt32_t faddr;
279*4c66157fSHoratiu Vultur 	int i;
280*4c66157fSHoratiu Vultur 
281*4c66157fSHoratiu Vultur 	bus = mdio_alloc();
282*4c66157fSHoratiu Vultur 
283*4c66157fSHoratiu Vultur 	if (!bus)
284*4c66157fSHoratiu Vultur 		return NULL;
285*4c66157fSHoratiu Vultur 
286*4c66157fSHoratiu Vultur 	/* gathered only the first mdio bus */
287*4c66157fSHoratiu Vultur 	eth_node = dev_read_first_subnode(dev);
288*4c66157fSHoratiu Vultur 	node = ofnode_first_subnode(eth_node);
289*4c66157fSHoratiu Vultur 	ofnode_parse_phandle_with_args(node, "phy-handle", NULL, 0, 0,
290*4c66157fSHoratiu Vultur 				       &phandle);
291*4c66157fSHoratiu Vultur 	mdio_node = ofnode_get_parent(phandle.node);
292*4c66157fSHoratiu Vultur 
293*4c66157fSHoratiu Vultur 	for (i = 0; i < TARGET_MDIO_MAX; i++) {
294*4c66157fSHoratiu Vultur 		if (ofnode_read_resource(mdio_node, i, &res)) {
295*4c66157fSHoratiu Vultur 			pr_err("%s: get OF resource failed\n", __func__);
296*4c66157fSHoratiu Vultur 			return NULL;
297*4c66157fSHoratiu Vultur 		}
298*4c66157fSHoratiu Vultur 		faddr = cpu_to_fdt32(res.start);
299*4c66157fSHoratiu Vultur 		phy_base[i] = ofnode_translate_address(mdio_node, &faddr);
300*4c66157fSHoratiu Vultur 		phy_size[i] = res.end - res.start;
301*4c66157fSHoratiu Vultur 	}
302*4c66157fSHoratiu Vultur 
303*4c66157fSHoratiu Vultur 	strcpy(bus->name, "miim-internal");
304*4c66157fSHoratiu Vultur 	miim[INTERNAL].phy_regs = ioremap(phy_base[PHY], phy_size[PHY]);
305*4c66157fSHoratiu Vultur 	miim[INTERNAL].regs = ioremap(phy_base[MIIM], phy_size[MIIM]);
306*4c66157fSHoratiu Vultur 	bus->priv = &miim[INTERNAL];
307*4c66157fSHoratiu Vultur 	bus->reset = mscc_miim_reset;
308*4c66157fSHoratiu Vultur 	bus->read = mscc_miim_read;
309*4c66157fSHoratiu Vultur 	bus->write = mscc_miim_write;
310*4c66157fSHoratiu Vultur 
311*4c66157fSHoratiu Vultur 	if (mdio_register(bus))
312*4c66157fSHoratiu Vultur 		return NULL;
313*4c66157fSHoratiu Vultur 	else
314*4c66157fSHoratiu Vultur 		return bus;
315*4c66157fSHoratiu Vultur }
316*4c66157fSHoratiu Vultur 
317*4c66157fSHoratiu Vultur __weak void mscc_switch_reset(void)
318*4c66157fSHoratiu Vultur {
319*4c66157fSHoratiu Vultur }
320*4c66157fSHoratiu Vultur 
321*4c66157fSHoratiu Vultur static void ocelot_stop(struct udevice *dev)
322*4c66157fSHoratiu Vultur {
323*4c66157fSHoratiu Vultur 	struct ocelot_private *priv = dev_get_priv(dev);
324*4c66157fSHoratiu Vultur 	int i;
325*4c66157fSHoratiu Vultur 
326*4c66157fSHoratiu Vultur 	mscc_switch_reset();
327*4c66157fSHoratiu Vultur 	for (i = 0; i < NUM_PHY; i++)
328*4c66157fSHoratiu Vultur 		if (priv->bus[i])
329*4c66157fSHoratiu Vultur 			mscc_miim_reset(priv->bus[i]);
330*4c66157fSHoratiu Vultur }
331*4c66157fSHoratiu Vultur 
332*4c66157fSHoratiu Vultur static void ocelot_cpu_capture_setup(struct ocelot_private *priv)
333*4c66157fSHoratiu Vultur {
334*4c66157fSHoratiu Vultur 	int i;
335*4c66157fSHoratiu Vultur 
336*4c66157fSHoratiu Vultur 	/* map the 8 CPU extraction queues to CPU port 11 */
337*4c66157fSHoratiu Vultur 	writel(0, priv->regs[QSYS] + QSYS_QMAP);
338*4c66157fSHoratiu Vultur 
339*4c66157fSHoratiu Vultur 	for (i = 0; i <= 1; i++) {
340*4c66157fSHoratiu Vultur 		/*
341*4c66157fSHoratiu Vultur 		 * Do byte-swap and expect status after last data word
342*4c66157fSHoratiu Vultur 		 * Extraction: Mode: manual extraction) | Byte_swap
343*4c66157fSHoratiu Vultur 		 */
344*4c66157fSHoratiu Vultur 		writel(QS_XTR_GRP_CFG_MODE(1) | QS_XTR_GRP_CFG_BYTE_SWAP,
345*4c66157fSHoratiu Vultur 		       priv->regs[QS] + QS_XTR_GRP_CFG(i));
346*4c66157fSHoratiu Vultur 		/*
347*4c66157fSHoratiu Vultur 		 * Injection: Mode: manual extraction | Byte_swap
348*4c66157fSHoratiu Vultur 		 */
349*4c66157fSHoratiu Vultur 		writel(QS_INJ_GRP_CFG_MODE(1) | QS_INJ_GRP_CFG_BYTE_SWAP,
350*4c66157fSHoratiu Vultur 		       priv->regs[QS] + QS_INJ_GRP_CFG(i));
351*4c66157fSHoratiu Vultur 	}
352*4c66157fSHoratiu Vultur 
353*4c66157fSHoratiu Vultur 	for (i = 0; i <= 1; i++)
354*4c66157fSHoratiu Vultur 		/* Enable IFH insertion/parsing on CPU ports */
355*4c66157fSHoratiu Vultur 		writel(SYS_PORT_MODE_INCL_INJ_HDR(1) |
356*4c66157fSHoratiu Vultur 		       SYS_PORT_MODE_INCL_XTR_HDR(1),
357*4c66157fSHoratiu Vultur 		       priv->regs[SYS] + SYS_PORT_MODE(CPU_PORT + i));
358*4c66157fSHoratiu Vultur 	/*
359*4c66157fSHoratiu Vultur 	 * Setup the CPU port as VLAN aware to support switching frames
360*4c66157fSHoratiu Vultur 	 * based on tags
361*4c66157fSHoratiu Vultur 	 */
362*4c66157fSHoratiu Vultur 	writel(ANA_PORT_VLAN_CFG_AWARE_ENA | ANA_PORT_VLAN_CFG_POP_CNT(1) |
363*4c66157fSHoratiu Vultur 	       MAC_VID, priv->regs[ANA] + ANA_PORT_VLAN_CFG(CPU_PORT));
364*4c66157fSHoratiu Vultur 
365*4c66157fSHoratiu Vultur 	/* Disable learning (only RECV_ENA must be set) */
366*4c66157fSHoratiu Vultur 	writel(ANA_PORT_PORT_CFG_RECV_ENA,
367*4c66157fSHoratiu Vultur 	       priv->regs[ANA] + ANA_PORT_PORT_CFG(CPU_PORT));
368*4c66157fSHoratiu Vultur 
369*4c66157fSHoratiu Vultur 	/* Enable switching to/from cpu port */
370*4c66157fSHoratiu Vultur 	setbits_le32(priv->regs[QSYS] + QSYS_SWITCH_PORT_MODE(CPU_PORT),
371*4c66157fSHoratiu Vultur 		     QSYS_SWITCH_PORT_MODE_PORT_ENA);
372*4c66157fSHoratiu Vultur 
373*4c66157fSHoratiu Vultur 	/* No pause on CPU port - not needed (off by default) */
374*4c66157fSHoratiu Vultur 	clrbits_le32(priv->regs[SYS] + SYS_PAUSE_CFG(CPU_PORT),
375*4c66157fSHoratiu Vultur 		     SYS_PAUSE_CFG_PAUSE_ENA);
376*4c66157fSHoratiu Vultur 
377*4c66157fSHoratiu Vultur 	setbits_le32(priv->regs[QSYS] + QSYS_EGR_NO_SHARING, BIT(CPU_PORT));
378*4c66157fSHoratiu Vultur }
379*4c66157fSHoratiu Vultur 
380*4c66157fSHoratiu Vultur static void ocelot_port_init(struct ocelot_private *priv, int port)
381*4c66157fSHoratiu Vultur {
382*4c66157fSHoratiu Vultur 	void __iomem *regs = priv->regs[port];
383*4c66157fSHoratiu Vultur 
384*4c66157fSHoratiu Vultur 	/* Enable PCS */
385*4c66157fSHoratiu Vultur 	writel(PCS1G_MODE_CFG_SGMII_MODE_ENA, regs + PCS1G_CFG);
386*4c66157fSHoratiu Vultur 
387*4c66157fSHoratiu Vultur 	/* Disable Signal Detect */
388*4c66157fSHoratiu Vultur 	writel(0, regs + PCS1G_SD_CFG);
389*4c66157fSHoratiu Vultur 
390*4c66157fSHoratiu Vultur 	/* Enable MAC RX and TX */
391*4c66157fSHoratiu Vultur 	writel(DEV_MAC_ENA_CFG_RX_ENA | DEV_MAC_ENA_CFG_TX_ENA,
392*4c66157fSHoratiu Vultur 	       regs + DEV_MAC_ENA_CFG);
393*4c66157fSHoratiu Vultur 
394*4c66157fSHoratiu Vultur 	/* Clear sgmii_mode_ena */
395*4c66157fSHoratiu Vultur 	writel(0, regs + PCS1G_MODE_CFG);
396*4c66157fSHoratiu Vultur 
397*4c66157fSHoratiu Vultur 	/*
398*4c66157fSHoratiu Vultur 	 * Clear sw_resolve_ena(bit 0) and set adv_ability to
399*4c66157fSHoratiu Vultur 	 * something meaningful just in case
400*4c66157fSHoratiu Vultur 	 */
401*4c66157fSHoratiu Vultur 	writel(PCS1G_ANEG_CFG_ADV_ABILITY(0x20), regs + PCS1G_ANEG_CFG);
402*4c66157fSHoratiu Vultur 
403*4c66157fSHoratiu Vultur 	/* Set MAC IFG Gaps */
404*4c66157fSHoratiu Vultur 	writel(DEV_MAC_IFG_CFG_TX_IFG(5) | DEV_MAC_IFG_CFG_RX_IFG1(5) |
405*4c66157fSHoratiu Vultur 	       DEV_MAC_IFG_CFG_RX_IFG2(1), regs + DEV_MAC_IFG_CFG);
406*4c66157fSHoratiu Vultur 
407*4c66157fSHoratiu Vultur 	/* Set link speed and release all resets */
408*4c66157fSHoratiu Vultur 	writel(DEV_CLOCK_CFG_LINK_SPEED_1000, regs + DEV_CLOCK_CFG);
409*4c66157fSHoratiu Vultur 
410*4c66157fSHoratiu Vultur 	/* Make VLAN aware for CPU traffic */
411*4c66157fSHoratiu Vultur 	writel(ANA_PORT_VLAN_CFG_AWARE_ENA | ANA_PORT_VLAN_CFG_POP_CNT(1) |
412*4c66157fSHoratiu Vultur 	       MAC_VID, priv->regs[ANA] + ANA_PORT_VLAN_CFG(port - PORT0));
413*4c66157fSHoratiu Vultur 
414*4c66157fSHoratiu Vultur 	/* Enable the port in the core */
415*4c66157fSHoratiu Vultur 	setbits_le32(priv->regs[QSYS] + QSYS_SWITCH_PORT_MODE(port - PORT0),
416*4c66157fSHoratiu Vultur 		     QSYS_SWITCH_PORT_MODE_PORT_ENA);
417*4c66157fSHoratiu Vultur }
418*4c66157fSHoratiu Vultur 
419*4c66157fSHoratiu Vultur static int ocelot_switch_init(struct ocelot_private *priv)
420*4c66157fSHoratiu Vultur {
421*4c66157fSHoratiu Vultur 	/* Reset switch & memories */
422*4c66157fSHoratiu Vultur 	writel(SYS_SYSTEM_RST_MEM_ENA | SYS_SYSTEM_RST_MEM_INIT,
423*4c66157fSHoratiu Vultur 	       priv->regs[SYS] + SYS_SYSTEM_RST_CFG);
424*4c66157fSHoratiu Vultur 
425*4c66157fSHoratiu Vultur 	/* Wait to complete */
426*4c66157fSHoratiu Vultur 	if (wait_for_bit_le32(priv->regs[SYS] + SYS_SYSTEM_RST_CFG,
427*4c66157fSHoratiu Vultur 			      SYS_SYSTEM_RST_MEM_INIT, false, 2000, false)) {
428*4c66157fSHoratiu Vultur 		pr_err("Timeout in memory reset\n");
429*4c66157fSHoratiu Vultur 		return -EIO;
430*4c66157fSHoratiu Vultur 	}
431*4c66157fSHoratiu Vultur 
432*4c66157fSHoratiu Vultur 	/* Enable switch core */
433*4c66157fSHoratiu Vultur 	setbits_le32(priv->regs[SYS] + SYS_SYSTEM_RST_CFG,
434*4c66157fSHoratiu Vultur 		     SYS_SYSTEM_RST_CORE_ENA);
435*4c66157fSHoratiu Vultur 
436*4c66157fSHoratiu Vultur 	return 0;
437*4c66157fSHoratiu Vultur }
438*4c66157fSHoratiu Vultur 
439*4c66157fSHoratiu Vultur static void ocelot_switch_flush(struct ocelot_private *priv)
440*4c66157fSHoratiu Vultur {
441*4c66157fSHoratiu Vultur 	/* All Queues flush */
442*4c66157fSHoratiu Vultur 	setbits_le32(priv->regs[QS] + QS_XTR_FLUSH, QS_XTR_FLUSH_FLUSH);
443*4c66157fSHoratiu Vultur 	/* Allow to drain */
444*4c66157fSHoratiu Vultur 	mdelay(1);
445*4c66157fSHoratiu Vultur 	/* All Queues normal */
446*4c66157fSHoratiu Vultur 	clrbits_le32(priv->regs[QS] + QS_XTR_FLUSH, QS_XTR_FLUSH_FLUSH);
447*4c66157fSHoratiu Vultur }
448*4c66157fSHoratiu Vultur 
449*4c66157fSHoratiu Vultur static int ocelot_initialize(struct ocelot_private *priv)
450*4c66157fSHoratiu Vultur {
451*4c66157fSHoratiu Vultur 	int ret, i;
452*4c66157fSHoratiu Vultur 
453*4c66157fSHoratiu Vultur 	/* Initialize switch memories, enable core */
454*4c66157fSHoratiu Vultur 	ret = ocelot_switch_init(priv);
455*4c66157fSHoratiu Vultur 	if (ret)
456*4c66157fSHoratiu Vultur 		return ret;
457*4c66157fSHoratiu Vultur 	/*
458*4c66157fSHoratiu Vultur 	 * Disable port-to-port by switching
459*4c66157fSHoratiu Vultur 	 * Put fron ports in "port isolation modes" - i.e. they cant send
460*4c66157fSHoratiu Vultur 	 * to other ports - via the PGID sorce masks.
461*4c66157fSHoratiu Vultur 	 */
462*4c66157fSHoratiu Vultur 	for (i = 0; i <= MAX_PORT; i++)
463*4c66157fSHoratiu Vultur 		writel(0, priv->regs[ANA] + ANA_PGID(PGID_SRC + i));
464*4c66157fSHoratiu Vultur 
465*4c66157fSHoratiu Vultur 	/* Flush queues */
466*4c66157fSHoratiu Vultur 	ocelot_switch_flush(priv);
467*4c66157fSHoratiu Vultur 
468*4c66157fSHoratiu Vultur 	/* Setup frame ageing - "2 sec" - The unit is 6.5us on Ocelot */
469*4c66157fSHoratiu Vultur 	writel(SYS_FRM_AGING_ENA | (20000000 / 65),
470*4c66157fSHoratiu Vultur 	       priv->regs[SYS] + SYS_FRM_AGING);
471*4c66157fSHoratiu Vultur 
472*4c66157fSHoratiu Vultur 	for (i = PORT0; i <= PORT3; i++)
473*4c66157fSHoratiu Vultur 		ocelot_port_init(priv, i);
474*4c66157fSHoratiu Vultur 
475*4c66157fSHoratiu Vultur 	ocelot_cpu_capture_setup(priv);
476*4c66157fSHoratiu Vultur 
477*4c66157fSHoratiu Vultur 	debug("Ports enabled\n");
478*4c66157fSHoratiu Vultur 
479*4c66157fSHoratiu Vultur 	return 0;
480*4c66157fSHoratiu Vultur }
481*4c66157fSHoratiu Vultur 
482*4c66157fSHoratiu Vultur static inline int ocelot_vlant_wait_for_completion(struct ocelot_private *priv)
483*4c66157fSHoratiu Vultur {
484*4c66157fSHoratiu Vultur 	unsigned int val, timeout = 10;
485*4c66157fSHoratiu Vultur 
486*4c66157fSHoratiu Vultur 	/* Wait for the issued mac table command to be completed, or timeout.
487*4c66157fSHoratiu Vultur 	 * When the command read from ANA_TABLES_MACACCESS is
488*4c66157fSHoratiu Vultur 	 * MACACCESS_CMD_IDLE, the issued command completed successfully.
489*4c66157fSHoratiu Vultur 	 */
490*4c66157fSHoratiu Vultur 	do {
491*4c66157fSHoratiu Vultur 		val = readl(priv->regs[ANA] + ANA_TABLES_MACACCESS);
492*4c66157fSHoratiu Vultur 		val &= ANA_TABLES_MACACCESS_MAC_TABLE_CMD_M;
493*4c66157fSHoratiu Vultur 	} while (val != MACACCESS_CMD_IDLE && timeout--);
494*4c66157fSHoratiu Vultur 
495*4c66157fSHoratiu Vultur 	if (!timeout)
496*4c66157fSHoratiu Vultur 		return -ETIMEDOUT;
497*4c66157fSHoratiu Vultur 
498*4c66157fSHoratiu Vultur 	return 0;
499*4c66157fSHoratiu Vultur }
500*4c66157fSHoratiu Vultur 
501*4c66157fSHoratiu Vultur static int ocelot_mac_table_add(struct ocelot_private *priv,
502*4c66157fSHoratiu Vultur 				const unsigned char mac[ETH_ALEN], int pgid)
503*4c66157fSHoratiu Vultur {
504*4c66157fSHoratiu Vultur 	u32 macl = 0, mach = 0;
505*4c66157fSHoratiu Vultur 	int ret;
506*4c66157fSHoratiu Vultur 
507*4c66157fSHoratiu Vultur 	/* Set the MAC address to handle and the vlan associated in a format
508*4c66157fSHoratiu Vultur 	 * understood by the hardware.
509*4c66157fSHoratiu Vultur 	 */
510*4c66157fSHoratiu Vultur 	mach |= MAC_VID << 16;
511*4c66157fSHoratiu Vultur 	mach |= ((u32)mac[0]) << 8;
512*4c66157fSHoratiu Vultur 	mach |= ((u32)mac[1]) << 0;
513*4c66157fSHoratiu Vultur 	macl |= ((u32)mac[2]) << 24;
514*4c66157fSHoratiu Vultur 	macl |= ((u32)mac[3]) << 16;
515*4c66157fSHoratiu Vultur 	macl |= ((u32)mac[4]) << 8;
516*4c66157fSHoratiu Vultur 	macl |= ((u32)mac[5]) << 0;
517*4c66157fSHoratiu Vultur 
518*4c66157fSHoratiu Vultur 	writel(macl, priv->regs[ANA] + ANA_TABLES_MACLDATA);
519*4c66157fSHoratiu Vultur 	writel(mach, priv->regs[ANA] + ANA_TABLES_MACHDATA);
520*4c66157fSHoratiu Vultur 
521*4c66157fSHoratiu Vultur 	writel(ANA_TABLES_MACACCESS_VALID |
522*4c66157fSHoratiu Vultur 	       ANA_TABLES_MACACCESS_DEST_IDX(pgid) |
523*4c66157fSHoratiu Vultur 	       ANA_TABLES_MACACCESS_ENTRYTYPE(ENTRYTYPE_LOCKED) |
524*4c66157fSHoratiu Vultur 	       ANA_TABLES_MACACCESS_MAC_TABLE_CMD(MACACCESS_CMD_LEARN),
525*4c66157fSHoratiu Vultur 	       priv->regs[ANA] + ANA_TABLES_MACACCESS);
526*4c66157fSHoratiu Vultur 
527*4c66157fSHoratiu Vultur 	ret = ocelot_vlant_wait_for_completion(priv);
528*4c66157fSHoratiu Vultur 
529*4c66157fSHoratiu Vultur 	return ret;
530*4c66157fSHoratiu Vultur }
531*4c66157fSHoratiu Vultur 
532*4c66157fSHoratiu Vultur static int ocelot_write_hwaddr(struct udevice *dev)
533*4c66157fSHoratiu Vultur {
534*4c66157fSHoratiu Vultur 	struct ocelot_private *priv = dev_get_priv(dev);
535*4c66157fSHoratiu Vultur 	struct eth_pdata *pdata = dev_get_platdata(dev);
536*4c66157fSHoratiu Vultur 
537*4c66157fSHoratiu Vultur 	ocelot_mac_table_add(priv, pdata->enetaddr, PGID_UNICAST);
538*4c66157fSHoratiu Vultur 
539*4c66157fSHoratiu Vultur 	writel(BIT(CPU_PORT), priv->regs[ANA] + ANA_PGID(PGID_UNICAST));
540*4c66157fSHoratiu Vultur 
541*4c66157fSHoratiu Vultur 	return 0;
542*4c66157fSHoratiu Vultur }
543*4c66157fSHoratiu Vultur 
544*4c66157fSHoratiu Vultur static int ocelot_start(struct udevice *dev)
545*4c66157fSHoratiu Vultur {
546*4c66157fSHoratiu Vultur 	struct ocelot_private *priv = dev_get_priv(dev);
547*4c66157fSHoratiu Vultur 	struct eth_pdata *pdata = dev_get_platdata(dev);
548*4c66157fSHoratiu Vultur 	const unsigned char mac[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff,
549*4c66157fSHoratiu Vultur 					      0xff };
550*4c66157fSHoratiu Vultur 	int ret;
551*4c66157fSHoratiu Vultur 
552*4c66157fSHoratiu Vultur 	ret = ocelot_initialize(priv);
553*4c66157fSHoratiu Vultur 	if (ret)
554*4c66157fSHoratiu Vultur 		return ret;
555*4c66157fSHoratiu Vultur 
556*4c66157fSHoratiu Vultur 	/* Set MAC address tables entries for CPU redirection */
557*4c66157fSHoratiu Vultur 	ocelot_mac_table_add(priv, mac, PGID_BROADCAST);
558*4c66157fSHoratiu Vultur 
559*4c66157fSHoratiu Vultur 	writel(BIT(CPU_PORT) | INTERNAL_PORT_MSK,
560*4c66157fSHoratiu Vultur 	       priv->regs[ANA] + ANA_PGID(PGID_BROADCAST));
561*4c66157fSHoratiu Vultur 
562*4c66157fSHoratiu Vultur 	/* It should be setup latter in ocelot_write_hwaddr */
563*4c66157fSHoratiu Vultur 	ocelot_mac_table_add(priv, pdata->enetaddr, PGID_UNICAST);
564*4c66157fSHoratiu Vultur 
565*4c66157fSHoratiu Vultur 	writel(BIT(CPU_PORT), priv->regs[ANA] + ANA_PGID(PGID_UNICAST));
566*4c66157fSHoratiu Vultur 
567*4c66157fSHoratiu Vultur 	return 0;
568*4c66157fSHoratiu Vultur }
569*4c66157fSHoratiu Vultur 
570*4c66157fSHoratiu Vultur static int ocelot_send(struct udevice *dev, void *packet, int length)
571*4c66157fSHoratiu Vultur {
572*4c66157fSHoratiu Vultur 	struct ocelot_private *priv = dev_get_priv(dev);
573*4c66157fSHoratiu Vultur 	u32 ifh[IFH_LEN];
574*4c66157fSHoratiu Vultur 	int port = BIT(0);	/* use port 0 */
575*4c66157fSHoratiu Vultur 	u8 grp = 0;		/* Send everything on CPU group 0 */
576*4c66157fSHoratiu Vultur 	int i, count = (length + 3) / 4, last = length % 4;
577*4c66157fSHoratiu Vultur 	u32 *buf = packet;
578*4c66157fSHoratiu Vultur 
579*4c66157fSHoratiu Vultur 	writel(QS_INJ_CTRL_GAP_SIZE(1) | QS_INJ_CTRL_SOF,
580*4c66157fSHoratiu Vultur 	       priv->regs[QS] + QS_INJ_CTRL(grp));
581*4c66157fSHoratiu Vultur 
582*4c66157fSHoratiu Vultur 	/*
583*4c66157fSHoratiu Vultur 	 * Generate the IFH for frame injection
584*4c66157fSHoratiu Vultur 	 *
585*4c66157fSHoratiu Vultur 	 * The IFH is a 128bit-value
586*4c66157fSHoratiu Vultur 	 * bit 127: bypass the analyzer processing
587*4c66157fSHoratiu Vultur 	 * bit 56-67: destination mask
588*4c66157fSHoratiu Vultur 	 * bit 28-29: pop_cnt: 3 disables all rewriting of the frame
589*4c66157fSHoratiu Vultur 	 * bit 20-27: cpu extraction queue mask
590*4c66157fSHoratiu Vultur 	 * bit 16: tag type 0: C-tag, 1: S-tag
591*4c66157fSHoratiu Vultur 	 * bit 0-11: VID
592*4c66157fSHoratiu Vultur 	 */
593*4c66157fSHoratiu Vultur 	ifh[0] = IFH_INJ_BYPASS;
594*4c66157fSHoratiu Vultur 	ifh[1] = (0xf00 & port) >> 8;
595*4c66157fSHoratiu Vultur 	ifh[2] = (0xff & port) << 24;
596*4c66157fSHoratiu Vultur 	ifh[3] = (IFH_TAG_TYPE_C << 16);
597*4c66157fSHoratiu Vultur 
598*4c66157fSHoratiu Vultur 	for (i = 0; i < IFH_LEN; i++)
599*4c66157fSHoratiu Vultur 		writel(ifh[i], priv->regs[QS] + QS_INJ_WR(grp));
600*4c66157fSHoratiu Vultur 
601*4c66157fSHoratiu Vultur 	for (i = 0; i < count; i++)
602*4c66157fSHoratiu Vultur 		writel(buf[i], priv->regs[QS] + QS_INJ_WR(grp));
603*4c66157fSHoratiu Vultur 
604*4c66157fSHoratiu Vultur 	/* Add padding */
605*4c66157fSHoratiu Vultur 	while (i < (OCELOT_BUF_CELL_SZ / 4)) {
606*4c66157fSHoratiu Vultur 		writel(0, priv->regs[QS] + QS_INJ_WR(grp));
607*4c66157fSHoratiu Vultur 		i++;
608*4c66157fSHoratiu Vultur 	}
609*4c66157fSHoratiu Vultur 
610*4c66157fSHoratiu Vultur 	/* Indicate EOF and valid bytes in last word */
611*4c66157fSHoratiu Vultur 	writel(QS_INJ_CTRL_GAP_SIZE(1) |
612*4c66157fSHoratiu Vultur 	       QS_INJ_CTRL_VLD_BYTES(length < OCELOT_BUF_CELL_SZ ? 0 : last) |
613*4c66157fSHoratiu Vultur 	       QS_INJ_CTRL_EOF, priv->regs[QS] + QS_INJ_CTRL(grp));
614*4c66157fSHoratiu Vultur 
615*4c66157fSHoratiu Vultur 	/* Add dummy CRC */
616*4c66157fSHoratiu Vultur 	writel(0, priv->regs[QS] + QS_INJ_WR(grp));
617*4c66157fSHoratiu Vultur 
618*4c66157fSHoratiu Vultur 	return 0;
619*4c66157fSHoratiu Vultur }
620*4c66157fSHoratiu Vultur 
621*4c66157fSHoratiu Vultur static int ocelot_recv(struct udevice *dev, int flags, uchar **packetp)
622*4c66157fSHoratiu Vultur {
623*4c66157fSHoratiu Vultur 	struct ocelot_private *priv = dev_get_priv(dev);
624*4c66157fSHoratiu Vultur 	u8 grp = 0;		/* Send everything on CPU group 0 */
625*4c66157fSHoratiu Vultur 	u32 *rxbuf = (u32 *)net_rx_packets[0];
626*4c66157fSHoratiu Vultur 	int i, byte_cnt = 0;
627*4c66157fSHoratiu Vultur 	bool eof_flag = false, pruned_flag = false, abort_flag = false;
628*4c66157fSHoratiu Vultur 
629*4c66157fSHoratiu Vultur 	if (!(readl(priv->regs[QS] + QS_XTR_DATA_PRESENT) & BIT(grp)))
630*4c66157fSHoratiu Vultur 		return -EAGAIN;
631*4c66157fSHoratiu Vultur 
632*4c66157fSHoratiu Vultur 	/* skip IFH */
633*4c66157fSHoratiu Vultur 	for (i = 0; i < IFH_LEN; i++)
634*4c66157fSHoratiu Vultur 		readl(priv->regs[QS] + QS_XTR_RD(grp));
635*4c66157fSHoratiu Vultur 
636*4c66157fSHoratiu Vultur 	while (!eof_flag) {
637*4c66157fSHoratiu Vultur 		u32 val = readl(priv->regs[QS] + QS_XTR_RD(grp));
638*4c66157fSHoratiu Vultur 
639*4c66157fSHoratiu Vultur 		switch (val) {
640*4c66157fSHoratiu Vultur 		case XTR_NOT_READY:
641*4c66157fSHoratiu Vultur 			debug("%d NOT_READY...?\n", byte_cnt);
642*4c66157fSHoratiu Vultur 			break;
643*4c66157fSHoratiu Vultur 		case XTR_ABORT:
644*4c66157fSHoratiu Vultur 			/* really nedeed?? not done in linux */
645*4c66157fSHoratiu Vultur 			*rxbuf = readl(priv->regs[QS] + QS_XTR_RD(grp));
646*4c66157fSHoratiu Vultur 			abort_flag = true;
647*4c66157fSHoratiu Vultur 			eof_flag = true;
648*4c66157fSHoratiu Vultur 			debug("XTR_ABORT\n");
649*4c66157fSHoratiu Vultur 			break;
650*4c66157fSHoratiu Vultur 		case XTR_EOF_0:
651*4c66157fSHoratiu Vultur 		case XTR_EOF_1:
652*4c66157fSHoratiu Vultur 		case XTR_EOF_2:
653*4c66157fSHoratiu Vultur 		case XTR_EOF_3:
654*4c66157fSHoratiu Vultur 			byte_cnt += XTR_VALID_BYTES(val);
655*4c66157fSHoratiu Vultur 			*rxbuf = readl(priv->regs[QS] + QS_XTR_RD(grp));
656*4c66157fSHoratiu Vultur 			eof_flag = true;
657*4c66157fSHoratiu Vultur 			debug("EOF\n");
658*4c66157fSHoratiu Vultur 			break;
659*4c66157fSHoratiu Vultur 		case XTR_PRUNED:
660*4c66157fSHoratiu Vultur 			/* But get the last 4 bytes as well */
661*4c66157fSHoratiu Vultur 			eof_flag = true;
662*4c66157fSHoratiu Vultur 			pruned_flag = true;
663*4c66157fSHoratiu Vultur 			debug("PRUNED\n");
664*4c66157fSHoratiu Vultur 			/* fallthrough */
665*4c66157fSHoratiu Vultur 		case XTR_ESCAPE:
666*4c66157fSHoratiu Vultur 			*rxbuf = readl(priv->regs[QS] + QS_XTR_RD(grp));
667*4c66157fSHoratiu Vultur 			byte_cnt += 4;
668*4c66157fSHoratiu Vultur 			rxbuf++;
669*4c66157fSHoratiu Vultur 			debug("ESCAPED\n");
670*4c66157fSHoratiu Vultur 			break;
671*4c66157fSHoratiu Vultur 		default:
672*4c66157fSHoratiu Vultur 			*rxbuf = val;
673*4c66157fSHoratiu Vultur 			byte_cnt += 4;
674*4c66157fSHoratiu Vultur 			rxbuf++;
675*4c66157fSHoratiu Vultur 		}
676*4c66157fSHoratiu Vultur 	}
677*4c66157fSHoratiu Vultur 
678*4c66157fSHoratiu Vultur 	if (abort_flag || pruned_flag || !eof_flag) {
679*4c66157fSHoratiu Vultur 		debug("Discarded frame: abort:%d pruned:%d eof:%d\n",
680*4c66157fSHoratiu Vultur 		      abort_flag, pruned_flag, eof_flag);
681*4c66157fSHoratiu Vultur 		return -EAGAIN;
682*4c66157fSHoratiu Vultur 	}
683*4c66157fSHoratiu Vultur 
684*4c66157fSHoratiu Vultur 	*packetp = net_rx_packets[0];
685*4c66157fSHoratiu Vultur 
686*4c66157fSHoratiu Vultur 	return byte_cnt;
687*4c66157fSHoratiu Vultur }
688*4c66157fSHoratiu Vultur 
689*4c66157fSHoratiu Vultur static int ocelot_probe(struct udevice *dev)
690*4c66157fSHoratiu Vultur {
691*4c66157fSHoratiu Vultur 	struct ocelot_private *priv = dev_get_priv(dev);
692*4c66157fSHoratiu Vultur 	int ret, i;
693*4c66157fSHoratiu Vultur 
694*4c66157fSHoratiu Vultur 	struct {
695*4c66157fSHoratiu Vultur 		enum ocelot_target id;
696*4c66157fSHoratiu Vultur 		char *name;
697*4c66157fSHoratiu Vultur 	} reg[] = {
698*4c66157fSHoratiu Vultur 		{ SYS, "sys" },
699*4c66157fSHoratiu Vultur 		{ REW, "rew" },
700*4c66157fSHoratiu Vultur 		{ QSYS, "qsys" },
701*4c66157fSHoratiu Vultur 		{ ANA, "ana" },
702*4c66157fSHoratiu Vultur 		{ QS, "qs" },
703*4c66157fSHoratiu Vultur 		{ HSIO, "hsio" },
704*4c66157fSHoratiu Vultur 		{ PORT0, "port0" },
705*4c66157fSHoratiu Vultur 		{ PORT1, "port1" },
706*4c66157fSHoratiu Vultur 		{ PORT2, "port2" },
707*4c66157fSHoratiu Vultur 		{ PORT3, "port3" },
708*4c66157fSHoratiu Vultur 	};
709*4c66157fSHoratiu Vultur 
710*4c66157fSHoratiu Vultur 	for (i = 0; i < ARRAY_SIZE(reg); i++) {
711*4c66157fSHoratiu Vultur 		priv->regs[reg[i].id] = dev_remap_addr_name(dev, reg[i].name);
712*4c66157fSHoratiu Vultur 		if (!priv->regs[reg[i].id]) {
713*4c66157fSHoratiu Vultur 			pr_err
714*4c66157fSHoratiu Vultur 			    ("Error %d: can't get regs base addresses for %s\n",
715*4c66157fSHoratiu Vultur 			     ret, reg[i].name);
716*4c66157fSHoratiu Vultur 			return -ENOMEM;
717*4c66157fSHoratiu Vultur 		}
718*4c66157fSHoratiu Vultur 	}
719*4c66157fSHoratiu Vultur 
720*4c66157fSHoratiu Vultur 	priv->bus[INTERNAL] = ocelot_mdiobus_init(dev);
721*4c66157fSHoratiu Vultur 
722*4c66157fSHoratiu Vultur 	for (i = 0; i < 4; i++) {
723*4c66157fSHoratiu Vultur 		phy_connect(priv->bus[INTERNAL], i, dev,
724*4c66157fSHoratiu Vultur 			    PHY_INTERFACE_MODE_NONE);
725*4c66157fSHoratiu Vultur 	}
726*4c66157fSHoratiu Vultur 
727*4c66157fSHoratiu Vultur 	return 0;
728*4c66157fSHoratiu Vultur }
729*4c66157fSHoratiu Vultur 
730*4c66157fSHoratiu Vultur static int ocelot_remove(struct udevice *dev)
731*4c66157fSHoratiu Vultur {
732*4c66157fSHoratiu Vultur 	struct ocelot_private *priv = dev_get_priv(dev);
733*4c66157fSHoratiu Vultur 	int i;
734*4c66157fSHoratiu Vultur 
735*4c66157fSHoratiu Vultur 	for (i = 0; i < NUM_PHY; i++) {
736*4c66157fSHoratiu Vultur 		mdio_unregister(priv->bus[i]);
737*4c66157fSHoratiu Vultur 		mdio_free(priv->bus[i]);
738*4c66157fSHoratiu Vultur 	}
739*4c66157fSHoratiu Vultur 
740*4c66157fSHoratiu Vultur 	return 0;
741*4c66157fSHoratiu Vultur }
742*4c66157fSHoratiu Vultur 
743*4c66157fSHoratiu Vultur static const struct eth_ops ocelot_ops = {
744*4c66157fSHoratiu Vultur 	.start        = ocelot_start,
745*4c66157fSHoratiu Vultur 	.stop         = ocelot_stop,
746*4c66157fSHoratiu Vultur 	.send         = ocelot_send,
747*4c66157fSHoratiu Vultur 	.recv         = ocelot_recv,
748*4c66157fSHoratiu Vultur 	.write_hwaddr = ocelot_write_hwaddr,
749*4c66157fSHoratiu Vultur };
750*4c66157fSHoratiu Vultur 
751*4c66157fSHoratiu Vultur static const struct udevice_id mscc_ocelot_ids[] = {
752*4c66157fSHoratiu Vultur 	{.compatible = "mscc,vsc7514-switch"},
753*4c66157fSHoratiu Vultur 	{ /* Sentinel */ }
754*4c66157fSHoratiu Vultur };
755*4c66157fSHoratiu Vultur 
756*4c66157fSHoratiu Vultur U_BOOT_DRIVER(ocelot) = {
757*4c66157fSHoratiu Vultur 	.name     = "ocelot-switch",
758*4c66157fSHoratiu Vultur 	.id       = UCLASS_ETH,
759*4c66157fSHoratiu Vultur 	.of_match = mscc_ocelot_ids,
760*4c66157fSHoratiu Vultur 	.probe	  = ocelot_probe,
761*4c66157fSHoratiu Vultur 	.remove	  = ocelot_remove,
762*4c66157fSHoratiu Vultur 	.ops	  = &ocelot_ops,
763*4c66157fSHoratiu Vultur 	.priv_auto_alloc_size = sizeof(struct ocelot_private),
764*4c66157fSHoratiu Vultur 	.platdata_auto_alloc_size = sizeof(struct eth_pdata),
765*4c66157fSHoratiu Vultur };
766