xref: /openbmc/u-boot/drivers/net/bcm6368-eth.c (revision 9622972a)
1*9622972aSÁlvaro Fernández Rojas // SPDX-License-Identifier: GPL-2.0+
2*9622972aSÁlvaro Fernández Rojas /*
3*9622972aSÁlvaro Fernández Rojas  * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
4*9622972aSÁlvaro Fernández Rojas  *
5*9622972aSÁlvaro Fernández Rojas  * Derived from linux/drivers/net/ethernet/broadcom/bcm63xx_enet.c:
6*9622972aSÁlvaro Fernández Rojas  *	Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
7*9622972aSÁlvaro Fernández Rojas  */
8*9622972aSÁlvaro Fernández Rojas 
9*9622972aSÁlvaro Fernández Rojas #include <common.h>
10*9622972aSÁlvaro Fernández Rojas #include <clk.h>
11*9622972aSÁlvaro Fernández Rojas #include <dm.h>
12*9622972aSÁlvaro Fernández Rojas #include <dma.h>
13*9622972aSÁlvaro Fernández Rojas #include <miiphy.h>
14*9622972aSÁlvaro Fernández Rojas #include <net.h>
15*9622972aSÁlvaro Fernández Rojas #include <reset.h>
16*9622972aSÁlvaro Fernández Rojas #include <wait_bit.h>
17*9622972aSÁlvaro Fernández Rojas #include <asm/io.h>
18*9622972aSÁlvaro Fernández Rojas 
19*9622972aSÁlvaro Fernández Rojas #define ETH_PORT_STR			"brcm,enetsw-port"
20*9622972aSÁlvaro Fernández Rojas 
21*9622972aSÁlvaro Fernández Rojas #define ETH_RX_DESC			PKTBUFSRX
22*9622972aSÁlvaro Fernández Rojas #define ETH_ZLEN			60
23*9622972aSÁlvaro Fernández Rojas #define ETH_TIMEOUT			100
24*9622972aSÁlvaro Fernández Rojas 
25*9622972aSÁlvaro Fernández Rojas #define ETH_MAX_PORT			8
26*9622972aSÁlvaro Fernández Rojas #define ETH_RGMII_PORT0			4
27*9622972aSÁlvaro Fernández Rojas 
28*9622972aSÁlvaro Fernández Rojas /* Port traffic control */
29*9622972aSÁlvaro Fernández Rojas #define ETH_PTCTRL_REG(x)		(0x0 + (x))
30*9622972aSÁlvaro Fernández Rojas #define ETH_PTCTRL_RXDIS_SHIFT		0
31*9622972aSÁlvaro Fernández Rojas #define ETH_PTCTRL_RXDIS_MASK		(1 << ETH_PTCTRL_RXDIS_SHIFT)
32*9622972aSÁlvaro Fernández Rojas #define ETH_PTCTRL_TXDIS_SHIFT		1
33*9622972aSÁlvaro Fernández Rojas #define ETH_PTCTRL_TXDIS_MASK		(1 << ETH_PTCTRL_TXDIS_SHIFT)
34*9622972aSÁlvaro Fernández Rojas 
35*9622972aSÁlvaro Fernández Rojas /* Switch mode register */
36*9622972aSÁlvaro Fernández Rojas #define ETH_SWMODE_REG			0xb
37*9622972aSÁlvaro Fernández Rojas #define ETH_SWMODE_FWD_EN_SHIFT		1
38*9622972aSÁlvaro Fernández Rojas #define ETH_SWMODE_FWD_EN_MASK		(1 << ETH_SWMODE_FWD_EN_SHIFT)
39*9622972aSÁlvaro Fernández Rojas 
40*9622972aSÁlvaro Fernández Rojas /* IMP override Register */
41*9622972aSÁlvaro Fernández Rojas #define ETH_IMPOV_REG			0xe
42*9622972aSÁlvaro Fernández Rojas #define ETH_IMPOV_LINKUP_SHIFT		0
43*9622972aSÁlvaro Fernández Rojas #define ETH_IMPOV_LINKUP_MASK		(1 << ETH_IMPOV_LINKUP_SHIFT)
44*9622972aSÁlvaro Fernández Rojas #define ETH_IMPOV_FDX_SHIFT		1
45*9622972aSÁlvaro Fernández Rojas #define ETH_IMPOV_FDX_MASK		(1 << ETH_IMPOV_FDX_SHIFT)
46*9622972aSÁlvaro Fernández Rojas #define ETH_IMPOV_100_SHIFT		2
47*9622972aSÁlvaro Fernández Rojas #define ETH_IMPOV_100_MASK		(1 << ETH_IMPOV_100_SHIFT)
48*9622972aSÁlvaro Fernández Rojas #define ETH_IMPOV_1000_SHIFT		3
49*9622972aSÁlvaro Fernández Rojas #define ETH_IMPOV_1000_MASK		(1 << ETH_IMPOV_1000_SHIFT)
50*9622972aSÁlvaro Fernández Rojas #define ETH_IMPOV_RXFLOW_SHIFT		4
51*9622972aSÁlvaro Fernández Rojas #define ETH_IMPOV_RXFLOW_MASK		(1 << ETH_IMPOV_RXFLOW_SHIFT)
52*9622972aSÁlvaro Fernández Rojas #define ETH_IMPOV_TXFLOW_SHIFT		5
53*9622972aSÁlvaro Fernández Rojas #define ETH_IMPOV_TXFLOW_MASK		(1 << ETH_IMPOV_TXFLOW_SHIFT)
54*9622972aSÁlvaro Fernández Rojas #define ETH_IMPOV_FORCE_SHIFT		7
55*9622972aSÁlvaro Fernández Rojas #define ETH_IMPOV_FORCE_MASK		(1 << ETH_IMPOV_FORCE_SHIFT)
56*9622972aSÁlvaro Fernández Rojas 
57*9622972aSÁlvaro Fernández Rojas /* Port override Register */
58*9622972aSÁlvaro Fernández Rojas #define ETH_PORTOV_REG(x)		(0x58 + (x))
59*9622972aSÁlvaro Fernández Rojas #define ETH_PORTOV_LINKUP_SHIFT		0
60*9622972aSÁlvaro Fernández Rojas #define ETH_PORTOV_LINKUP_MASK		(1 << ETH_PORTOV_LINKUP_SHIFT)
61*9622972aSÁlvaro Fernández Rojas #define ETH_PORTOV_FDX_SHIFT		1
62*9622972aSÁlvaro Fernández Rojas #define ETH_PORTOV_FDX_MASK		(1 << ETH_PORTOV_FDX_SHIFT)
63*9622972aSÁlvaro Fernández Rojas #define ETH_PORTOV_100_SHIFT		2
64*9622972aSÁlvaro Fernández Rojas #define ETH_PORTOV_100_MASK		(1 << ETH_PORTOV_100_SHIFT)
65*9622972aSÁlvaro Fernández Rojas #define ETH_PORTOV_1000_SHIFT		3
66*9622972aSÁlvaro Fernández Rojas #define ETH_PORTOV_1000_MASK		(1 << ETH_PORTOV_1000_SHIFT)
67*9622972aSÁlvaro Fernández Rojas #define ETH_PORTOV_RXFLOW_SHIFT		4
68*9622972aSÁlvaro Fernández Rojas #define ETH_PORTOV_RXFLOW_MASK		(1 << ETH_PORTOV_RXFLOW_SHIFT)
69*9622972aSÁlvaro Fernández Rojas #define ETH_PORTOV_TXFLOW_SHIFT		5
70*9622972aSÁlvaro Fernández Rojas #define ETH_PORTOV_TXFLOW_MASK		(1 << ETH_PORTOV_TXFLOW_SHIFT)
71*9622972aSÁlvaro Fernández Rojas #define ETH_PORTOV_ENABLE_SHIFT		6
72*9622972aSÁlvaro Fernández Rojas #define ETH_PORTOV_ENABLE_MASK		(1 << ETH_PORTOV_ENABLE_SHIFT)
73*9622972aSÁlvaro Fernández Rojas 
74*9622972aSÁlvaro Fernández Rojas /* Port RGMII control register */
75*9622972aSÁlvaro Fernández Rojas #define ETH_RGMII_CTRL_REG(x)		(0x60 + (x))
76*9622972aSÁlvaro Fernández Rojas #define ETH_RGMII_CTRL_GMII_CLK_EN	(1 << 7)
77*9622972aSÁlvaro Fernández Rojas #define ETH_RGMII_CTRL_MII_OVERRIDE_EN	(1 << 6)
78*9622972aSÁlvaro Fernández Rojas #define ETH_RGMII_CTRL_MII_MODE_MASK	(3 << 4)
79*9622972aSÁlvaro Fernández Rojas #define ETH_RGMII_CTRL_RGMII_MODE	(0 << 4)
80*9622972aSÁlvaro Fernández Rojas #define ETH_RGMII_CTRL_MII_MODE		(1 << 4)
81*9622972aSÁlvaro Fernández Rojas #define ETH_RGMII_CTRL_RVMII_MODE	(2 << 4)
82*9622972aSÁlvaro Fernández Rojas #define ETH_RGMII_CTRL_TIMING_SEL_EN	(1 << 0)
83*9622972aSÁlvaro Fernández Rojas 
84*9622972aSÁlvaro Fernández Rojas /* Port RGMII timing register */
85*9622972aSÁlvaro Fernández Rojas #define ENETSW_RGMII_TIMING_REG(x)	(0x68 + (x))
86*9622972aSÁlvaro Fernández Rojas 
87*9622972aSÁlvaro Fernández Rojas /* MDIO control register */
88*9622972aSÁlvaro Fernández Rojas #define MII_SC_REG			0xb0
89*9622972aSÁlvaro Fernández Rojas #define MII_SC_EXT_SHIFT		16
90*9622972aSÁlvaro Fernández Rojas #define MII_SC_EXT_MASK			(1 << MII_SC_EXT_SHIFT)
91*9622972aSÁlvaro Fernández Rojas #define MII_SC_REG_SHIFT		20
92*9622972aSÁlvaro Fernández Rojas #define MII_SC_PHYID_SHIFT		25
93*9622972aSÁlvaro Fernández Rojas #define MII_SC_RD_SHIFT			30
94*9622972aSÁlvaro Fernández Rojas #define MII_SC_RD_MASK			(1 << MII_SC_RD_SHIFT)
95*9622972aSÁlvaro Fernández Rojas #define MII_SC_WR_SHIFT			31
96*9622972aSÁlvaro Fernández Rojas #define MII_SC_WR_MASK			(1 << MII_SC_WR_SHIFT)
97*9622972aSÁlvaro Fernández Rojas 
98*9622972aSÁlvaro Fernández Rojas /* MDIO data register */
99*9622972aSÁlvaro Fernández Rojas #define MII_DAT_REG			0xb4
100*9622972aSÁlvaro Fernández Rojas 
101*9622972aSÁlvaro Fernández Rojas /* Global Management Configuration Register */
102*9622972aSÁlvaro Fernández Rojas #define ETH_GMCR_REG			0x200
103*9622972aSÁlvaro Fernández Rojas #define ETH_GMCR_RST_MIB_SHIFT		0
104*9622972aSÁlvaro Fernández Rojas #define ETH_GMCR_RST_MIB_MASK		(1 << ETH_GMCR_RST_MIB_SHIFT)
105*9622972aSÁlvaro Fernández Rojas 
106*9622972aSÁlvaro Fernández Rojas /* Jumbo control register port mask register */
107*9622972aSÁlvaro Fernández Rojas #define ETH_JMBCTL_PORT_REG		0x4004
108*9622972aSÁlvaro Fernández Rojas 
109*9622972aSÁlvaro Fernández Rojas /* Jumbo control mib good frame register */
110*9622972aSÁlvaro Fernández Rojas #define ETH_JMBCTL_MAXSIZE_REG		0x4008
111*9622972aSÁlvaro Fernández Rojas 
112*9622972aSÁlvaro Fernández Rojas /* ETH port data */
113*9622972aSÁlvaro Fernández Rojas struct bcm_enetsw_port {
114*9622972aSÁlvaro Fernández Rojas 	bool used;
115*9622972aSÁlvaro Fernández Rojas 	const char *name;
116*9622972aSÁlvaro Fernández Rojas 	/* Config */
117*9622972aSÁlvaro Fernández Rojas 	bool bypass_link;
118*9622972aSÁlvaro Fernández Rojas 	int force_speed;
119*9622972aSÁlvaro Fernández Rojas 	bool force_duplex_full;
120*9622972aSÁlvaro Fernández Rojas 	/* PHY */
121*9622972aSÁlvaro Fernández Rojas 	int phy_id;
122*9622972aSÁlvaro Fernández Rojas };
123*9622972aSÁlvaro Fernández Rojas 
124*9622972aSÁlvaro Fernández Rojas /* ETH data */
125*9622972aSÁlvaro Fernández Rojas struct bcm6368_eth_priv {
126*9622972aSÁlvaro Fernández Rojas 	void __iomem *base;
127*9622972aSÁlvaro Fernández Rojas 	/* DMA */
128*9622972aSÁlvaro Fernández Rojas 	struct dma rx_dma;
129*9622972aSÁlvaro Fernández Rojas 	struct dma tx_dma;
130*9622972aSÁlvaro Fernández Rojas 	/* Ports */
131*9622972aSÁlvaro Fernández Rojas 	uint8_t num_ports;
132*9622972aSÁlvaro Fernández Rojas 	struct bcm_enetsw_port used_ports[ETH_MAX_PORT];
133*9622972aSÁlvaro Fernández Rojas 	int sw_port_link[ETH_MAX_PORT];
134*9622972aSÁlvaro Fernández Rojas 	bool rgmii_override;
135*9622972aSÁlvaro Fernández Rojas 	bool rgmii_timing;
136*9622972aSÁlvaro Fernández Rojas 	/* PHY */
137*9622972aSÁlvaro Fernández Rojas 	int phy_id;
138*9622972aSÁlvaro Fernández Rojas };
139*9622972aSÁlvaro Fernández Rojas 
140*9622972aSÁlvaro Fernández Rojas static inline bool bcm_enet_port_is_rgmii(int portid)
141*9622972aSÁlvaro Fernández Rojas {
142*9622972aSÁlvaro Fernández Rojas 	return portid >= ETH_RGMII_PORT0;
143*9622972aSÁlvaro Fernández Rojas }
144*9622972aSÁlvaro Fernández Rojas 
145*9622972aSÁlvaro Fernández Rojas static int bcm6368_mdio_read(struct bcm6368_eth_priv *priv, uint8_t ext,
146*9622972aSÁlvaro Fernández Rojas 			     int phy_id, int reg)
147*9622972aSÁlvaro Fernández Rojas {
148*9622972aSÁlvaro Fernández Rojas 	uint32_t val;
149*9622972aSÁlvaro Fernández Rojas 
150*9622972aSÁlvaro Fernández Rojas 	writel_be(0, priv->base + MII_SC_REG);
151*9622972aSÁlvaro Fernández Rojas 
152*9622972aSÁlvaro Fernández Rojas 	val = MII_SC_RD_MASK |
153*9622972aSÁlvaro Fernández Rojas 	      (phy_id << MII_SC_PHYID_SHIFT) |
154*9622972aSÁlvaro Fernández Rojas 	      (reg << MII_SC_REG_SHIFT);
155*9622972aSÁlvaro Fernández Rojas 
156*9622972aSÁlvaro Fernández Rojas 	if (ext)
157*9622972aSÁlvaro Fernández Rojas 		val |= MII_SC_EXT_MASK;
158*9622972aSÁlvaro Fernández Rojas 
159*9622972aSÁlvaro Fernández Rojas 	writel_be(val, priv->base + MII_SC_REG);
160*9622972aSÁlvaro Fernández Rojas 	udelay(50);
161*9622972aSÁlvaro Fernández Rojas 
162*9622972aSÁlvaro Fernández Rojas 	return readw_be(priv->base + MII_DAT_REG);
163*9622972aSÁlvaro Fernández Rojas }
164*9622972aSÁlvaro Fernández Rojas 
165*9622972aSÁlvaro Fernández Rojas static int bcm6368_mdio_write(struct bcm6368_eth_priv *priv, uint8_t ext,
166*9622972aSÁlvaro Fernández Rojas 			      int phy_id, int reg, u16 data)
167*9622972aSÁlvaro Fernández Rojas {
168*9622972aSÁlvaro Fernández Rojas 	uint32_t val;
169*9622972aSÁlvaro Fernández Rojas 
170*9622972aSÁlvaro Fernández Rojas 	writel_be(0, priv->base + MII_SC_REG);
171*9622972aSÁlvaro Fernández Rojas 
172*9622972aSÁlvaro Fernández Rojas 	val = MII_SC_WR_MASK |
173*9622972aSÁlvaro Fernández Rojas 	      (phy_id << MII_SC_PHYID_SHIFT) |
174*9622972aSÁlvaro Fernández Rojas 	      (reg << MII_SC_REG_SHIFT);
175*9622972aSÁlvaro Fernández Rojas 
176*9622972aSÁlvaro Fernández Rojas 	if (ext)
177*9622972aSÁlvaro Fernández Rojas 		val |= MII_SC_EXT_MASK;
178*9622972aSÁlvaro Fernández Rojas 
179*9622972aSÁlvaro Fernández Rojas 	val |= data;
180*9622972aSÁlvaro Fernández Rojas 
181*9622972aSÁlvaro Fernández Rojas 	writel_be(val, priv->base + MII_SC_REG);
182*9622972aSÁlvaro Fernández Rojas 	udelay(50);
183*9622972aSÁlvaro Fernández Rojas 
184*9622972aSÁlvaro Fernández Rojas 	return 0;
185*9622972aSÁlvaro Fernández Rojas }
186*9622972aSÁlvaro Fernández Rojas 
187*9622972aSÁlvaro Fernández Rojas static int bcm6368_eth_free_pkt(struct udevice *dev, uchar *packet, int len)
188*9622972aSÁlvaro Fernández Rojas {
189*9622972aSÁlvaro Fernández Rojas 	struct bcm6368_eth_priv *priv = dev_get_priv(dev);
190*9622972aSÁlvaro Fernández Rojas 
191*9622972aSÁlvaro Fernández Rojas 	return dma_prepare_rcv_buf(&priv->rx_dma, packet, len);
192*9622972aSÁlvaro Fernández Rojas }
193*9622972aSÁlvaro Fernández Rojas 
194*9622972aSÁlvaro Fernández Rojas static int bcm6368_eth_recv(struct udevice *dev, int flags, uchar **packetp)
195*9622972aSÁlvaro Fernández Rojas {
196*9622972aSÁlvaro Fernández Rojas 	struct bcm6368_eth_priv *priv = dev_get_priv(dev);
197*9622972aSÁlvaro Fernández Rojas 
198*9622972aSÁlvaro Fernández Rojas 	return dma_receive(&priv->rx_dma, (void**)packetp, NULL);
199*9622972aSÁlvaro Fernández Rojas }
200*9622972aSÁlvaro Fernández Rojas 
201*9622972aSÁlvaro Fernández Rojas static int bcm6368_eth_send(struct udevice *dev, void *packet, int length)
202*9622972aSÁlvaro Fernández Rojas {
203*9622972aSÁlvaro Fernández Rojas 	struct bcm6368_eth_priv *priv = dev_get_priv(dev);
204*9622972aSÁlvaro Fernández Rojas 
205*9622972aSÁlvaro Fernández Rojas 	/* pad packets smaller than ETH_ZLEN */
206*9622972aSÁlvaro Fernández Rojas 	if (length < ETH_ZLEN) {
207*9622972aSÁlvaro Fernández Rojas 		memset(packet + length, 0, ETH_ZLEN - length);
208*9622972aSÁlvaro Fernández Rojas 		length = ETH_ZLEN;
209*9622972aSÁlvaro Fernández Rojas 	}
210*9622972aSÁlvaro Fernández Rojas 
211*9622972aSÁlvaro Fernández Rojas 	return dma_send(&priv->tx_dma, packet, length, NULL);
212*9622972aSÁlvaro Fernández Rojas }
213*9622972aSÁlvaro Fernández Rojas 
214*9622972aSÁlvaro Fernández Rojas static int bcm6368_eth_adjust_link(struct udevice *dev)
215*9622972aSÁlvaro Fernández Rojas {
216*9622972aSÁlvaro Fernández Rojas 	struct bcm6368_eth_priv *priv = dev_get_priv(dev);
217*9622972aSÁlvaro Fernández Rojas 	unsigned int i;
218*9622972aSÁlvaro Fernández Rojas 
219*9622972aSÁlvaro Fernández Rojas 	for (i = 0; i < priv->num_ports; i++) {
220*9622972aSÁlvaro Fernández Rojas 		struct bcm_enetsw_port *port;
221*9622972aSÁlvaro Fernández Rojas 		int val, j, up, adv, lpa, speed, duplex, media;
222*9622972aSÁlvaro Fernández Rojas 		int external_phy = bcm_enet_port_is_rgmii(i);
223*9622972aSÁlvaro Fernández Rojas 		u8 override;
224*9622972aSÁlvaro Fernández Rojas 
225*9622972aSÁlvaro Fernández Rojas 		port = &priv->used_ports[i];
226*9622972aSÁlvaro Fernández Rojas 		if (!port->used)
227*9622972aSÁlvaro Fernández Rojas 			continue;
228*9622972aSÁlvaro Fernández Rojas 
229*9622972aSÁlvaro Fernández Rojas 		if (port->bypass_link)
230*9622972aSÁlvaro Fernández Rojas 			continue;
231*9622972aSÁlvaro Fernández Rojas 
232*9622972aSÁlvaro Fernández Rojas 		/* dummy read to clear */
233*9622972aSÁlvaro Fernández Rojas 		for (j = 0; j < 2; j++)
234*9622972aSÁlvaro Fernández Rojas 			val = bcm6368_mdio_read(priv, external_phy,
235*9622972aSÁlvaro Fernández Rojas 						port->phy_id, MII_BMSR);
236*9622972aSÁlvaro Fernández Rojas 
237*9622972aSÁlvaro Fernández Rojas 		if (val == 0xffff)
238*9622972aSÁlvaro Fernández Rojas 			continue;
239*9622972aSÁlvaro Fernández Rojas 
240*9622972aSÁlvaro Fernández Rojas 		up = (val & BMSR_LSTATUS) ? 1 : 0;
241*9622972aSÁlvaro Fernández Rojas 		if (!(up ^ priv->sw_port_link[i]))
242*9622972aSÁlvaro Fernández Rojas 			continue;
243*9622972aSÁlvaro Fernández Rojas 
244*9622972aSÁlvaro Fernández Rojas 		priv->sw_port_link[i] = up;
245*9622972aSÁlvaro Fernández Rojas 
246*9622972aSÁlvaro Fernández Rojas 		/* link changed */
247*9622972aSÁlvaro Fernández Rojas 		if (!up) {
248*9622972aSÁlvaro Fernández Rojas 			dev_info(&priv->pdev->dev, "link DOWN on %s\n",
249*9622972aSÁlvaro Fernández Rojas 				 port->name);
250*9622972aSÁlvaro Fernández Rojas 			writeb_be(ETH_PORTOV_ENABLE_MASK,
251*9622972aSÁlvaro Fernández Rojas 				  priv->base + ETH_PORTOV_REG(i));
252*9622972aSÁlvaro Fernández Rojas 			writeb_be(ETH_PTCTRL_RXDIS_MASK |
253*9622972aSÁlvaro Fernández Rojas 				  ETH_PTCTRL_TXDIS_MASK,
254*9622972aSÁlvaro Fernández Rojas 				  priv->base + ETH_PTCTRL_REG(i));
255*9622972aSÁlvaro Fernández Rojas 			continue;
256*9622972aSÁlvaro Fernández Rojas 		}
257*9622972aSÁlvaro Fernández Rojas 
258*9622972aSÁlvaro Fernández Rojas 		adv = bcm6368_mdio_read(priv, external_phy,
259*9622972aSÁlvaro Fernández Rojas 					port->phy_id, MII_ADVERTISE);
260*9622972aSÁlvaro Fernández Rojas 
261*9622972aSÁlvaro Fernández Rojas 		lpa = bcm6368_mdio_read(priv, external_phy, port->phy_id,
262*9622972aSÁlvaro Fernández Rojas 					MII_LPA);
263*9622972aSÁlvaro Fernández Rojas 
264*9622972aSÁlvaro Fernández Rojas 		/* figure out media and duplex from advertise and LPA values */
265*9622972aSÁlvaro Fernández Rojas 		media = mii_nway_result(lpa & adv);
266*9622972aSÁlvaro Fernández Rojas 		duplex = (media & ADVERTISE_FULL) ? 1 : 0;
267*9622972aSÁlvaro Fernández Rojas 
268*9622972aSÁlvaro Fernández Rojas 		if (media & (ADVERTISE_100FULL | ADVERTISE_100HALF))
269*9622972aSÁlvaro Fernández Rojas 			speed = 100;
270*9622972aSÁlvaro Fernández Rojas 		else
271*9622972aSÁlvaro Fernández Rojas 			speed = 10;
272*9622972aSÁlvaro Fernández Rojas 
273*9622972aSÁlvaro Fernández Rojas 		if (val & BMSR_ESTATEN) {
274*9622972aSÁlvaro Fernández Rojas 			adv = bcm6368_mdio_read(priv, external_phy,
275*9622972aSÁlvaro Fernández Rojas 						port->phy_id, MII_CTRL1000);
276*9622972aSÁlvaro Fernández Rojas 
277*9622972aSÁlvaro Fernández Rojas 			lpa = bcm6368_mdio_read(priv, external_phy,
278*9622972aSÁlvaro Fernández Rojas 						port->phy_id, MII_STAT1000);
279*9622972aSÁlvaro Fernández Rojas 
280*9622972aSÁlvaro Fernández Rojas 			if ((adv & (ADVERTISE_1000FULL | ADVERTISE_1000HALF)) &&
281*9622972aSÁlvaro Fernández Rojas 			    (lpa & (LPA_1000FULL | LPA_1000HALF))) {
282*9622972aSÁlvaro Fernández Rojas 				speed = 1000;
283*9622972aSÁlvaro Fernández Rojas 				duplex = (lpa & LPA_1000FULL);
284*9622972aSÁlvaro Fernández Rojas 			}
285*9622972aSÁlvaro Fernández Rojas 		}
286*9622972aSÁlvaro Fernández Rojas 
287*9622972aSÁlvaro Fernández Rojas 		pr_alert("link UP on %s, %dMbps, %s-duplex\n",
288*9622972aSÁlvaro Fernández Rojas 			 port->name, speed, duplex ? "full" : "half");
289*9622972aSÁlvaro Fernández Rojas 
290*9622972aSÁlvaro Fernández Rojas 		override = ETH_PORTOV_ENABLE_MASK |
291*9622972aSÁlvaro Fernández Rojas 			   ETH_PORTOV_LINKUP_MASK;
292*9622972aSÁlvaro Fernández Rojas 
293*9622972aSÁlvaro Fernández Rojas 		if (speed == 1000)
294*9622972aSÁlvaro Fernández Rojas 			override |= ETH_PORTOV_1000_MASK;
295*9622972aSÁlvaro Fernández Rojas 		else if (speed == 100)
296*9622972aSÁlvaro Fernández Rojas 			override |= ETH_PORTOV_100_MASK;
297*9622972aSÁlvaro Fernández Rojas 		if (duplex)
298*9622972aSÁlvaro Fernández Rojas 			override |= ETH_PORTOV_FDX_MASK;
299*9622972aSÁlvaro Fernández Rojas 
300*9622972aSÁlvaro Fernández Rojas 		writeb_be(override, priv->base + ETH_PORTOV_REG(i));
301*9622972aSÁlvaro Fernández Rojas 		writeb_be(0, priv->base + ETH_PTCTRL_REG(i));
302*9622972aSÁlvaro Fernández Rojas 	}
303*9622972aSÁlvaro Fernández Rojas 
304*9622972aSÁlvaro Fernández Rojas 	return 0;
305*9622972aSÁlvaro Fernández Rojas }
306*9622972aSÁlvaro Fernández Rojas 
307*9622972aSÁlvaro Fernández Rojas static int bcm6368_eth_start(struct udevice *dev)
308*9622972aSÁlvaro Fernández Rojas {
309*9622972aSÁlvaro Fernández Rojas 	struct bcm6368_eth_priv *priv = dev_get_priv(dev);
310*9622972aSÁlvaro Fernández Rojas 	uint8_t i;
311*9622972aSÁlvaro Fernández Rojas 
312*9622972aSÁlvaro Fernández Rojas 	/* prepare rx dma buffers */
313*9622972aSÁlvaro Fernández Rojas 	for (i = 0; i < ETH_RX_DESC; i++) {
314*9622972aSÁlvaro Fernández Rojas 		int ret = dma_prepare_rcv_buf(&priv->rx_dma, net_rx_packets[i],
315*9622972aSÁlvaro Fernández Rojas 					      PKTSIZE_ALIGN);
316*9622972aSÁlvaro Fernández Rojas 		if (ret < 0)
317*9622972aSÁlvaro Fernández Rojas 			break;
318*9622972aSÁlvaro Fernández Rojas 	}
319*9622972aSÁlvaro Fernández Rojas 
320*9622972aSÁlvaro Fernández Rojas 	/* enable dma rx channel */
321*9622972aSÁlvaro Fernández Rojas 	dma_enable(&priv->rx_dma);
322*9622972aSÁlvaro Fernández Rojas 
323*9622972aSÁlvaro Fernández Rojas 	/* enable dma tx channel */
324*9622972aSÁlvaro Fernández Rojas 	dma_enable(&priv->tx_dma);
325*9622972aSÁlvaro Fernández Rojas 
326*9622972aSÁlvaro Fernández Rojas 	/* apply override config for bypass_link ports here. */
327*9622972aSÁlvaro Fernández Rojas 	for (i = 0; i < priv->num_ports; i++) {
328*9622972aSÁlvaro Fernández Rojas 		struct bcm_enetsw_port *port;
329*9622972aSÁlvaro Fernández Rojas 		u8 override;
330*9622972aSÁlvaro Fernández Rojas 
331*9622972aSÁlvaro Fernández Rojas 		port = &priv->used_ports[i];
332*9622972aSÁlvaro Fernández Rojas 		if (!port->used)
333*9622972aSÁlvaro Fernández Rojas 			continue;
334*9622972aSÁlvaro Fernández Rojas 
335*9622972aSÁlvaro Fernández Rojas 		if (!port->bypass_link)
336*9622972aSÁlvaro Fernández Rojas 			continue;
337*9622972aSÁlvaro Fernández Rojas 
338*9622972aSÁlvaro Fernández Rojas 		override = ETH_PORTOV_ENABLE_MASK |
339*9622972aSÁlvaro Fernández Rojas 			   ETH_PORTOV_LINKUP_MASK;
340*9622972aSÁlvaro Fernández Rojas 
341*9622972aSÁlvaro Fernández Rojas 		switch (port->force_speed) {
342*9622972aSÁlvaro Fernández Rojas 		case 1000:
343*9622972aSÁlvaro Fernández Rojas 			override |= ETH_PORTOV_1000_MASK;
344*9622972aSÁlvaro Fernández Rojas 			break;
345*9622972aSÁlvaro Fernández Rojas 		case 100:
346*9622972aSÁlvaro Fernández Rojas 			override |= ETH_PORTOV_100_MASK;
347*9622972aSÁlvaro Fernández Rojas 			break;
348*9622972aSÁlvaro Fernández Rojas 		case 10:
349*9622972aSÁlvaro Fernández Rojas 			break;
350*9622972aSÁlvaro Fernández Rojas 		default:
351*9622972aSÁlvaro Fernández Rojas 			pr_warn("%s: invalid forced speed on port %s\n",
352*9622972aSÁlvaro Fernández Rojas 				__func__, port->name);
353*9622972aSÁlvaro Fernández Rojas 			break;
354*9622972aSÁlvaro Fernández Rojas 		}
355*9622972aSÁlvaro Fernández Rojas 
356*9622972aSÁlvaro Fernández Rojas 		if (port->force_duplex_full)
357*9622972aSÁlvaro Fernández Rojas 			override |= ETH_PORTOV_FDX_MASK;
358*9622972aSÁlvaro Fernández Rojas 
359*9622972aSÁlvaro Fernández Rojas 		writeb_be(override, priv->base + ETH_PORTOV_REG(i));
360*9622972aSÁlvaro Fernández Rojas 		writeb_be(0, priv->base + ETH_PTCTRL_REG(i));
361*9622972aSÁlvaro Fernández Rojas 	}
362*9622972aSÁlvaro Fernández Rojas 
363*9622972aSÁlvaro Fernández Rojas 	bcm6368_eth_adjust_link(dev);
364*9622972aSÁlvaro Fernández Rojas 
365*9622972aSÁlvaro Fernández Rojas 	return 0;
366*9622972aSÁlvaro Fernández Rojas }
367*9622972aSÁlvaro Fernández Rojas 
368*9622972aSÁlvaro Fernández Rojas static void bcm6368_eth_stop(struct udevice *dev)
369*9622972aSÁlvaro Fernández Rojas {
370*9622972aSÁlvaro Fernández Rojas 	struct bcm6368_eth_priv *priv = dev_get_priv(dev);
371*9622972aSÁlvaro Fernández Rojas 
372*9622972aSÁlvaro Fernández Rojas 	/* disable dma rx channel */
373*9622972aSÁlvaro Fernández Rojas 	dma_disable(&priv->rx_dma);
374*9622972aSÁlvaro Fernández Rojas 
375*9622972aSÁlvaro Fernández Rojas 	/* disable dma tx channel */
376*9622972aSÁlvaro Fernández Rojas 	dma_disable(&priv->tx_dma);
377*9622972aSÁlvaro Fernández Rojas }
378*9622972aSÁlvaro Fernández Rojas 
379*9622972aSÁlvaro Fernández Rojas static const struct eth_ops bcm6368_eth_ops = {
380*9622972aSÁlvaro Fernández Rojas 	.free_pkt = bcm6368_eth_free_pkt,
381*9622972aSÁlvaro Fernández Rojas 	.recv = bcm6368_eth_recv,
382*9622972aSÁlvaro Fernández Rojas 	.send = bcm6368_eth_send,
383*9622972aSÁlvaro Fernández Rojas 	.start = bcm6368_eth_start,
384*9622972aSÁlvaro Fernández Rojas 	.stop = bcm6368_eth_stop,
385*9622972aSÁlvaro Fernández Rojas };
386*9622972aSÁlvaro Fernández Rojas 
387*9622972aSÁlvaro Fernández Rojas static const struct udevice_id bcm6368_eth_ids[] = {
388*9622972aSÁlvaro Fernández Rojas 	{ .compatible = "brcm,bcm6368-enet", },
389*9622972aSÁlvaro Fernández Rojas 	{ /* sentinel */ }
390*9622972aSÁlvaro Fernández Rojas };
391*9622972aSÁlvaro Fernández Rojas 
392*9622972aSÁlvaro Fernández Rojas static bool bcm6368_phy_is_external(struct bcm6368_eth_priv *priv, int phy_id)
393*9622972aSÁlvaro Fernández Rojas {
394*9622972aSÁlvaro Fernández Rojas 	uint8_t i;
395*9622972aSÁlvaro Fernández Rojas 
396*9622972aSÁlvaro Fernández Rojas 	for (i = 0; i < priv->num_ports; ++i) {
397*9622972aSÁlvaro Fernández Rojas 		if (!priv->used_ports[i].used)
398*9622972aSÁlvaro Fernández Rojas 			continue;
399*9622972aSÁlvaro Fernández Rojas 		if (priv->used_ports[i].phy_id == phy_id)
400*9622972aSÁlvaro Fernández Rojas 			return bcm_enet_port_is_rgmii(i);
401*9622972aSÁlvaro Fernández Rojas 	}
402*9622972aSÁlvaro Fernández Rojas 
403*9622972aSÁlvaro Fernández Rojas 	return true;
404*9622972aSÁlvaro Fernández Rojas }
405*9622972aSÁlvaro Fernández Rojas 
406*9622972aSÁlvaro Fernández Rojas static int bcm6368_mii_mdio_read(struct mii_dev *bus, int addr, int devaddr,
407*9622972aSÁlvaro Fernández Rojas 				 int reg)
408*9622972aSÁlvaro Fernández Rojas {
409*9622972aSÁlvaro Fernández Rojas 	struct bcm6368_eth_priv *priv = bus->priv;
410*9622972aSÁlvaro Fernández Rojas 	bool ext = bcm6368_phy_is_external(priv, addr);
411*9622972aSÁlvaro Fernández Rojas 
412*9622972aSÁlvaro Fernández Rojas 	return bcm6368_mdio_read(priv, ext, addr, reg);
413*9622972aSÁlvaro Fernández Rojas }
414*9622972aSÁlvaro Fernández Rojas 
415*9622972aSÁlvaro Fernández Rojas static int bcm6368_mii_mdio_write(struct mii_dev *bus, int addr, int devaddr,
416*9622972aSÁlvaro Fernández Rojas 				  int reg, u16 data)
417*9622972aSÁlvaro Fernández Rojas {
418*9622972aSÁlvaro Fernández Rojas 	struct bcm6368_eth_priv *priv = bus->priv;
419*9622972aSÁlvaro Fernández Rojas 	bool ext = bcm6368_phy_is_external(priv, addr);
420*9622972aSÁlvaro Fernández Rojas 
421*9622972aSÁlvaro Fernández Rojas 	return bcm6368_mdio_write(priv, ext, addr, reg, data);
422*9622972aSÁlvaro Fernández Rojas }
423*9622972aSÁlvaro Fernández Rojas 
424*9622972aSÁlvaro Fernández Rojas static int bcm6368_mdio_init(const char *name, struct bcm6368_eth_priv *priv)
425*9622972aSÁlvaro Fernández Rojas {
426*9622972aSÁlvaro Fernández Rojas 	struct mii_dev *bus;
427*9622972aSÁlvaro Fernández Rojas 
428*9622972aSÁlvaro Fernández Rojas 	bus = mdio_alloc();
429*9622972aSÁlvaro Fernández Rojas 	if (!bus) {
430*9622972aSÁlvaro Fernández Rojas 		pr_err("%s: failed to allocate MDIO bus\n", __func__);
431*9622972aSÁlvaro Fernández Rojas 		return -ENOMEM;
432*9622972aSÁlvaro Fernández Rojas 	}
433*9622972aSÁlvaro Fernández Rojas 
434*9622972aSÁlvaro Fernández Rojas 	bus->read = bcm6368_mii_mdio_read;
435*9622972aSÁlvaro Fernández Rojas 	bus->write = bcm6368_mii_mdio_write;
436*9622972aSÁlvaro Fernández Rojas 	bus->priv = priv;
437*9622972aSÁlvaro Fernández Rojas 	snprintf(bus->name, sizeof(bus->name), "%s", name);
438*9622972aSÁlvaro Fernández Rojas 
439*9622972aSÁlvaro Fernández Rojas 	return mdio_register(bus);
440*9622972aSÁlvaro Fernández Rojas }
441*9622972aSÁlvaro Fernández Rojas 
442*9622972aSÁlvaro Fernández Rojas static int bcm6368_eth_probe(struct udevice *dev)
443*9622972aSÁlvaro Fernández Rojas {
444*9622972aSÁlvaro Fernández Rojas 	struct eth_pdata *pdata = dev_get_platdata(dev);
445*9622972aSÁlvaro Fernández Rojas 	struct bcm6368_eth_priv *priv = dev_get_priv(dev);
446*9622972aSÁlvaro Fernández Rojas 	int num_ports, ret, i;
447*9622972aSÁlvaro Fernández Rojas 	uint32_t val;
448*9622972aSÁlvaro Fernández Rojas 	ofnode node;
449*9622972aSÁlvaro Fernández Rojas 
450*9622972aSÁlvaro Fernández Rojas 	/* get base address */
451*9622972aSÁlvaro Fernández Rojas 	priv->base = dev_remap_addr(dev);
452*9622972aSÁlvaro Fernández Rojas 	if (!priv->base)
453*9622972aSÁlvaro Fernández Rojas 		return -EINVAL;
454*9622972aSÁlvaro Fernández Rojas 	pdata->iobase = (phys_addr_t) priv->base;
455*9622972aSÁlvaro Fernández Rojas 
456*9622972aSÁlvaro Fernández Rojas 	/* get number of ports */
457*9622972aSÁlvaro Fernández Rojas 	num_ports = dev_read_u32_default(dev, "brcm,num-ports", ETH_MAX_PORT);
458*9622972aSÁlvaro Fernández Rojas 	if (!num_ports || num_ports > ETH_MAX_PORT)
459*9622972aSÁlvaro Fernández Rojas 		return -EINVAL;
460*9622972aSÁlvaro Fernández Rojas 
461*9622972aSÁlvaro Fernández Rojas 	/* get dma channels */
462*9622972aSÁlvaro Fernández Rojas 	ret = dma_get_by_name(dev, "tx", &priv->tx_dma);
463*9622972aSÁlvaro Fernández Rojas 	if (ret)
464*9622972aSÁlvaro Fernández Rojas 		return -EINVAL;
465*9622972aSÁlvaro Fernández Rojas 
466*9622972aSÁlvaro Fernández Rojas 	ret = dma_get_by_name(dev, "rx", &priv->rx_dma);
467*9622972aSÁlvaro Fernández Rojas 	if (ret)
468*9622972aSÁlvaro Fernández Rojas 		return -EINVAL;
469*9622972aSÁlvaro Fernández Rojas 
470*9622972aSÁlvaro Fernández Rojas 	/* try to enable clocks */
471*9622972aSÁlvaro Fernández Rojas 	for (i = 0; ; i++) {
472*9622972aSÁlvaro Fernández Rojas 		struct clk clk;
473*9622972aSÁlvaro Fernández Rojas 		int ret;
474*9622972aSÁlvaro Fernández Rojas 
475*9622972aSÁlvaro Fernández Rojas 		ret = clk_get_by_index(dev, i, &clk);
476*9622972aSÁlvaro Fernández Rojas 		if (ret < 0)
477*9622972aSÁlvaro Fernández Rojas 			break;
478*9622972aSÁlvaro Fernández Rojas 
479*9622972aSÁlvaro Fernández Rojas 		ret = clk_enable(&clk);
480*9622972aSÁlvaro Fernández Rojas 		if (ret < 0) {
481*9622972aSÁlvaro Fernández Rojas 			pr_err("%s: error enabling clock %d\n", __func__, i);
482*9622972aSÁlvaro Fernández Rojas 			return ret;
483*9622972aSÁlvaro Fernández Rojas 		}
484*9622972aSÁlvaro Fernández Rojas 
485*9622972aSÁlvaro Fernández Rojas 		ret = clk_free(&clk);
486*9622972aSÁlvaro Fernández Rojas 		if (ret < 0) {
487*9622972aSÁlvaro Fernández Rojas 			pr_err("%s: error freeing clock %d\n", __func__, i);
488*9622972aSÁlvaro Fernández Rojas 			return ret;
489*9622972aSÁlvaro Fernández Rojas 		}
490*9622972aSÁlvaro Fernández Rojas 	}
491*9622972aSÁlvaro Fernández Rojas 
492*9622972aSÁlvaro Fernández Rojas 	/* try to perform resets */
493*9622972aSÁlvaro Fernández Rojas 	for (i = 0; ; i++) {
494*9622972aSÁlvaro Fernández Rojas 		struct reset_ctl reset;
495*9622972aSÁlvaro Fernández Rojas 		int ret;
496*9622972aSÁlvaro Fernández Rojas 
497*9622972aSÁlvaro Fernández Rojas 		ret = reset_get_by_index(dev, i, &reset);
498*9622972aSÁlvaro Fernández Rojas 		if (ret < 0)
499*9622972aSÁlvaro Fernández Rojas 			break;
500*9622972aSÁlvaro Fernández Rojas 
501*9622972aSÁlvaro Fernández Rojas 		ret = reset_deassert(&reset);
502*9622972aSÁlvaro Fernández Rojas 		if (ret < 0) {
503*9622972aSÁlvaro Fernández Rojas 			pr_err("%s: error deasserting reset %d\n", __func__, i);
504*9622972aSÁlvaro Fernández Rojas 			return ret;
505*9622972aSÁlvaro Fernández Rojas 		}
506*9622972aSÁlvaro Fernández Rojas 
507*9622972aSÁlvaro Fernández Rojas 		ret = reset_free(&reset);
508*9622972aSÁlvaro Fernández Rojas 		if (ret < 0) {
509*9622972aSÁlvaro Fernández Rojas 			pr_err("%s: error freeing reset %d\n", __func__, i);
510*9622972aSÁlvaro Fernández Rojas 			return ret;
511*9622972aSÁlvaro Fernández Rojas 		}
512*9622972aSÁlvaro Fernández Rojas 	}
513*9622972aSÁlvaro Fernández Rojas 
514*9622972aSÁlvaro Fernández Rojas 	/* set priv data */
515*9622972aSÁlvaro Fernández Rojas 	priv->num_ports = num_ports;
516*9622972aSÁlvaro Fernández Rojas 	if (dev_read_bool(dev, "brcm,rgmii-override"))
517*9622972aSÁlvaro Fernández Rojas 		priv->rgmii_override = true;
518*9622972aSÁlvaro Fernández Rojas 	if (dev_read_bool(dev, "brcm,rgmii-timing"))
519*9622972aSÁlvaro Fernández Rojas 		priv->rgmii_timing = true;
520*9622972aSÁlvaro Fernández Rojas 
521*9622972aSÁlvaro Fernández Rojas 	/* get ports */
522*9622972aSÁlvaro Fernández Rojas 	dev_for_each_subnode(node, dev) {
523*9622972aSÁlvaro Fernández Rojas 		const char *comp;
524*9622972aSÁlvaro Fernández Rojas 		const char *label;
525*9622972aSÁlvaro Fernández Rojas 		unsigned int p;
526*9622972aSÁlvaro Fernández Rojas 		int phy_id;
527*9622972aSÁlvaro Fernández Rojas 		int speed;
528*9622972aSÁlvaro Fernández Rojas 
529*9622972aSÁlvaro Fernández Rojas 		comp = ofnode_read_string(node, "compatible");
530*9622972aSÁlvaro Fernández Rojas 		if (!comp || memcmp(comp, ETH_PORT_STR, sizeof(ETH_PORT_STR)))
531*9622972aSÁlvaro Fernández Rojas 			continue;
532*9622972aSÁlvaro Fernández Rojas 
533*9622972aSÁlvaro Fernández Rojas 		p = ofnode_read_u32_default(node, "reg", ETH_MAX_PORT);
534*9622972aSÁlvaro Fernández Rojas 		if (p >= num_ports)
535*9622972aSÁlvaro Fernández Rojas 			return -EINVAL;
536*9622972aSÁlvaro Fernández Rojas 
537*9622972aSÁlvaro Fernández Rojas 		label = ofnode_read_string(node, "label");
538*9622972aSÁlvaro Fernández Rojas 		if (!label) {
539*9622972aSÁlvaro Fernández Rojas 			debug("%s: node %s has no label\n", __func__,
540*9622972aSÁlvaro Fernández Rojas 			      ofnode_get_name(node));
541*9622972aSÁlvaro Fernández Rojas 			return -EINVAL;
542*9622972aSÁlvaro Fernández Rojas 		}
543*9622972aSÁlvaro Fernández Rojas 
544*9622972aSÁlvaro Fernández Rojas 		phy_id = ofnode_read_u32_default(node, "brcm,phy-id", -1);
545*9622972aSÁlvaro Fernández Rojas 
546*9622972aSÁlvaro Fernández Rojas 		priv->used_ports[p].used = true;
547*9622972aSÁlvaro Fernández Rojas 		priv->used_ports[p].name = label;
548*9622972aSÁlvaro Fernández Rojas 		priv->used_ports[p].phy_id = phy_id;
549*9622972aSÁlvaro Fernández Rojas 
550*9622972aSÁlvaro Fernández Rojas 		if (ofnode_read_bool(node, "full-duplex"))
551*9622972aSÁlvaro Fernández Rojas 			priv->used_ports[p].force_duplex_full = true;
552*9622972aSÁlvaro Fernández Rojas 		if (ofnode_read_bool(node, "bypass-link"))
553*9622972aSÁlvaro Fernández Rojas 			priv->used_ports[p].bypass_link = true;
554*9622972aSÁlvaro Fernández Rojas 		speed = ofnode_read_u32_default(node, "speed", 0);
555*9622972aSÁlvaro Fernández Rojas 		if (speed)
556*9622972aSÁlvaro Fernández Rojas 			priv->used_ports[p].force_speed = speed;
557*9622972aSÁlvaro Fernández Rojas 	}
558*9622972aSÁlvaro Fernández Rojas 
559*9622972aSÁlvaro Fernández Rojas 	/* init mii bus */
560*9622972aSÁlvaro Fernández Rojas 	ret = bcm6368_mdio_init(dev->name, priv);
561*9622972aSÁlvaro Fernández Rojas 	if (ret)
562*9622972aSÁlvaro Fernández Rojas 		return ret;
563*9622972aSÁlvaro Fernández Rojas 
564*9622972aSÁlvaro Fernández Rojas 	/* disable all ports */
565*9622972aSÁlvaro Fernández Rojas 	for (i = 0; i < priv->num_ports; i++) {
566*9622972aSÁlvaro Fernández Rojas 		writeb_be(ETH_PORTOV_ENABLE_MASK,
567*9622972aSÁlvaro Fernández Rojas 			      priv->base + ETH_PORTOV_REG(i));
568*9622972aSÁlvaro Fernández Rojas 		writeb_be(ETH_PTCTRL_RXDIS_MASK |
569*9622972aSÁlvaro Fernández Rojas 			      ETH_PTCTRL_TXDIS_MASK,
570*9622972aSÁlvaro Fernández Rojas 			      priv->base + ETH_PTCTRL_REG(i));
571*9622972aSÁlvaro Fernández Rojas 
572*9622972aSÁlvaro Fernández Rojas 		priv->sw_port_link[i] = 0;
573*9622972aSÁlvaro Fernández Rojas 	}
574*9622972aSÁlvaro Fernández Rojas 
575*9622972aSÁlvaro Fernández Rojas 	/* enable external ports */
576*9622972aSÁlvaro Fernández Rojas 	for (i = ETH_RGMII_PORT0; i < priv->num_ports; i++) {
577*9622972aSÁlvaro Fernández Rojas 		u8 rgmii_ctrl;
578*9622972aSÁlvaro Fernández Rojas 
579*9622972aSÁlvaro Fernández Rojas 		if (!priv->used_ports[i].used)
580*9622972aSÁlvaro Fernández Rojas 			continue;
581*9622972aSÁlvaro Fernández Rojas 
582*9622972aSÁlvaro Fernández Rojas 		rgmii_ctrl = readb_be(priv->base + ETH_RGMII_CTRL_REG(i));
583*9622972aSÁlvaro Fernández Rojas 		rgmii_ctrl |= ETH_RGMII_CTRL_GMII_CLK_EN;
584*9622972aSÁlvaro Fernández Rojas 		if (priv->rgmii_override)
585*9622972aSÁlvaro Fernández Rojas 			rgmii_ctrl |= ETH_RGMII_CTRL_MII_OVERRIDE_EN;
586*9622972aSÁlvaro Fernández Rojas 		if (priv->rgmii_timing)
587*9622972aSÁlvaro Fernández Rojas 			rgmii_ctrl |= ETH_RGMII_CTRL_TIMING_SEL_EN;
588*9622972aSÁlvaro Fernández Rojas 		writeb_be(rgmii_ctrl, priv->base + ETH_RGMII_CTRL_REG(i));
589*9622972aSÁlvaro Fernández Rojas 	}
590*9622972aSÁlvaro Fernández Rojas 
591*9622972aSÁlvaro Fernández Rojas 	/* reset mib */
592*9622972aSÁlvaro Fernández Rojas 	val = readb_be(priv->base + ETH_GMCR_REG);
593*9622972aSÁlvaro Fernández Rojas 	val |= ETH_GMCR_RST_MIB_MASK;
594*9622972aSÁlvaro Fernández Rojas 	writeb_be(val, priv->base + ETH_GMCR_REG);
595*9622972aSÁlvaro Fernández Rojas 	mdelay(1);
596*9622972aSÁlvaro Fernández Rojas 	val &= ~ETH_GMCR_RST_MIB_MASK;
597*9622972aSÁlvaro Fernández Rojas 	writeb_be(val, priv->base + ETH_GMCR_REG);
598*9622972aSÁlvaro Fernández Rojas 	mdelay(1);
599*9622972aSÁlvaro Fernández Rojas 
600*9622972aSÁlvaro Fernández Rojas 	/* force CPU port state */
601*9622972aSÁlvaro Fernández Rojas 	val = readb_be(priv->base + ETH_IMPOV_REG);
602*9622972aSÁlvaro Fernández Rojas 	val |= ETH_IMPOV_FORCE_MASK | ETH_IMPOV_LINKUP_MASK;
603*9622972aSÁlvaro Fernández Rojas 	writeb_be(val, priv->base + ETH_IMPOV_REG);
604*9622972aSÁlvaro Fernández Rojas 
605*9622972aSÁlvaro Fernández Rojas 	/* enable switch forward engine */
606*9622972aSÁlvaro Fernández Rojas 	val = readb_be(priv->base + ETH_SWMODE_REG);
607*9622972aSÁlvaro Fernández Rojas 	val |= ETH_SWMODE_FWD_EN_MASK;
608*9622972aSÁlvaro Fernández Rojas 	writeb_be(val, priv->base + ETH_SWMODE_REG);
609*9622972aSÁlvaro Fernández Rojas 
610*9622972aSÁlvaro Fernández Rojas 	/* enable jumbo on all ports */
611*9622972aSÁlvaro Fernández Rojas 	writel_be(0x1ff, priv->base + ETH_JMBCTL_PORT_REG);
612*9622972aSÁlvaro Fernández Rojas 	writew_be(9728, priv->base + ETH_JMBCTL_MAXSIZE_REG);
613*9622972aSÁlvaro Fernández Rojas 
614*9622972aSÁlvaro Fernández Rojas 	return 0;
615*9622972aSÁlvaro Fernández Rojas }
616*9622972aSÁlvaro Fernández Rojas 
617*9622972aSÁlvaro Fernández Rojas U_BOOT_DRIVER(bcm6368_eth) = {
618*9622972aSÁlvaro Fernández Rojas 	.name = "bcm6368_eth",
619*9622972aSÁlvaro Fernández Rojas 	.id = UCLASS_ETH,
620*9622972aSÁlvaro Fernández Rojas 	.of_match = bcm6368_eth_ids,
621*9622972aSÁlvaro Fernández Rojas 	.ops = &bcm6368_eth_ops,
622*9622972aSÁlvaro Fernández Rojas 	.platdata_auto_alloc_size = sizeof(struct eth_pdata),
623*9622972aSÁlvaro Fernández Rojas 	.priv_auto_alloc_size = sizeof(struct bcm6368_eth_priv),
624*9622972aSÁlvaro Fernández Rojas 	.probe = bcm6368_eth_probe,
625*9622972aSÁlvaro Fernández Rojas };
626