xref: /openbmc/u-boot/drivers/net/bcm6368-eth.c (revision 77c07e7e)
19622972aSÁlvaro Fernández Rojas // SPDX-License-Identifier: GPL-2.0+
29622972aSÁlvaro Fernández Rojas /*
39622972aSÁlvaro Fernández Rojas  * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
49622972aSÁlvaro Fernández Rojas  *
59622972aSÁlvaro Fernández Rojas  * Derived from linux/drivers/net/ethernet/broadcom/bcm63xx_enet.c:
69622972aSÁlvaro Fernández Rojas  *	Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
79622972aSÁlvaro Fernández Rojas  */
89622972aSÁlvaro Fernández Rojas 
99622972aSÁlvaro Fernández Rojas #include <common.h>
109622972aSÁlvaro Fernández Rojas #include <clk.h>
119622972aSÁlvaro Fernández Rojas #include <dm.h>
129622972aSÁlvaro Fernández Rojas #include <dma.h>
139622972aSÁlvaro Fernández Rojas #include <miiphy.h>
149622972aSÁlvaro Fernández Rojas #include <net.h>
159622972aSÁlvaro Fernández Rojas #include <reset.h>
169622972aSÁlvaro Fernández Rojas #include <wait_bit.h>
179622972aSÁlvaro Fernández Rojas #include <asm/io.h>
189622972aSÁlvaro Fernández Rojas 
199622972aSÁlvaro Fernández Rojas #define ETH_PORT_STR			"brcm,enetsw-port"
209622972aSÁlvaro Fernández Rojas 
219622972aSÁlvaro Fernández Rojas #define ETH_RX_DESC			PKTBUFSRX
229622972aSÁlvaro Fernández Rojas #define ETH_ZLEN			60
239622972aSÁlvaro Fernández Rojas #define ETH_TIMEOUT			100
249622972aSÁlvaro Fernández Rojas 
259622972aSÁlvaro Fernández Rojas #define ETH_MAX_PORT			8
269622972aSÁlvaro Fernández Rojas #define ETH_RGMII_PORT0			4
279622972aSÁlvaro Fernández Rojas 
289622972aSÁlvaro Fernández Rojas /* Port traffic control */
299622972aSÁlvaro Fernández Rojas #define ETH_PTCTRL_REG(x)		(0x0 + (x))
309622972aSÁlvaro Fernández Rojas #define ETH_PTCTRL_RXDIS_SHIFT		0
319622972aSÁlvaro Fernández Rojas #define ETH_PTCTRL_RXDIS_MASK		(1 << ETH_PTCTRL_RXDIS_SHIFT)
329622972aSÁlvaro Fernández Rojas #define ETH_PTCTRL_TXDIS_SHIFT		1
339622972aSÁlvaro Fernández Rojas #define ETH_PTCTRL_TXDIS_MASK		(1 << ETH_PTCTRL_TXDIS_SHIFT)
349622972aSÁlvaro Fernández Rojas 
359622972aSÁlvaro Fernández Rojas /* Switch mode register */
369622972aSÁlvaro Fernández Rojas #define ETH_SWMODE_REG			0xb
379622972aSÁlvaro Fernández Rojas #define ETH_SWMODE_FWD_EN_SHIFT		1
389622972aSÁlvaro Fernández Rojas #define ETH_SWMODE_FWD_EN_MASK		(1 << ETH_SWMODE_FWD_EN_SHIFT)
399622972aSÁlvaro Fernández Rojas 
409622972aSÁlvaro Fernández Rojas /* IMP override Register */
419622972aSÁlvaro Fernández Rojas #define ETH_IMPOV_REG			0xe
429622972aSÁlvaro Fernández Rojas #define ETH_IMPOV_LINKUP_SHIFT		0
439622972aSÁlvaro Fernández Rojas #define ETH_IMPOV_LINKUP_MASK		(1 << ETH_IMPOV_LINKUP_SHIFT)
449622972aSÁlvaro Fernández Rojas #define ETH_IMPOV_FDX_SHIFT		1
459622972aSÁlvaro Fernández Rojas #define ETH_IMPOV_FDX_MASK		(1 << ETH_IMPOV_FDX_SHIFT)
469622972aSÁlvaro Fernández Rojas #define ETH_IMPOV_100_SHIFT		2
479622972aSÁlvaro Fernández Rojas #define ETH_IMPOV_100_MASK		(1 << ETH_IMPOV_100_SHIFT)
489622972aSÁlvaro Fernández Rojas #define ETH_IMPOV_1000_SHIFT		3
499622972aSÁlvaro Fernández Rojas #define ETH_IMPOV_1000_MASK		(1 << ETH_IMPOV_1000_SHIFT)
509622972aSÁlvaro Fernández Rojas #define ETH_IMPOV_RXFLOW_SHIFT		4
519622972aSÁlvaro Fernández Rojas #define ETH_IMPOV_RXFLOW_MASK		(1 << ETH_IMPOV_RXFLOW_SHIFT)
529622972aSÁlvaro Fernández Rojas #define ETH_IMPOV_TXFLOW_SHIFT		5
539622972aSÁlvaro Fernández Rojas #define ETH_IMPOV_TXFLOW_MASK		(1 << ETH_IMPOV_TXFLOW_SHIFT)
549622972aSÁlvaro Fernández Rojas #define ETH_IMPOV_FORCE_SHIFT		7
559622972aSÁlvaro Fernández Rojas #define ETH_IMPOV_FORCE_MASK		(1 << ETH_IMPOV_FORCE_SHIFT)
569622972aSÁlvaro Fernández Rojas 
579622972aSÁlvaro Fernández Rojas /* Port override Register */
589622972aSÁlvaro Fernández Rojas #define ETH_PORTOV_REG(x)		(0x58 + (x))
599622972aSÁlvaro Fernández Rojas #define ETH_PORTOV_LINKUP_SHIFT		0
609622972aSÁlvaro Fernández Rojas #define ETH_PORTOV_LINKUP_MASK		(1 << ETH_PORTOV_LINKUP_SHIFT)
619622972aSÁlvaro Fernández Rojas #define ETH_PORTOV_FDX_SHIFT		1
629622972aSÁlvaro Fernández Rojas #define ETH_PORTOV_FDX_MASK		(1 << ETH_PORTOV_FDX_SHIFT)
639622972aSÁlvaro Fernández Rojas #define ETH_PORTOV_100_SHIFT		2
649622972aSÁlvaro Fernández Rojas #define ETH_PORTOV_100_MASK		(1 << ETH_PORTOV_100_SHIFT)
659622972aSÁlvaro Fernández Rojas #define ETH_PORTOV_1000_SHIFT		3
669622972aSÁlvaro Fernández Rojas #define ETH_PORTOV_1000_MASK		(1 << ETH_PORTOV_1000_SHIFT)
679622972aSÁlvaro Fernández Rojas #define ETH_PORTOV_RXFLOW_SHIFT		4
689622972aSÁlvaro Fernández Rojas #define ETH_PORTOV_RXFLOW_MASK		(1 << ETH_PORTOV_RXFLOW_SHIFT)
699622972aSÁlvaro Fernández Rojas #define ETH_PORTOV_TXFLOW_SHIFT		5
709622972aSÁlvaro Fernández Rojas #define ETH_PORTOV_TXFLOW_MASK		(1 << ETH_PORTOV_TXFLOW_SHIFT)
719622972aSÁlvaro Fernández Rojas #define ETH_PORTOV_ENABLE_SHIFT		6
729622972aSÁlvaro Fernández Rojas #define ETH_PORTOV_ENABLE_MASK		(1 << ETH_PORTOV_ENABLE_SHIFT)
739622972aSÁlvaro Fernández Rojas 
749622972aSÁlvaro Fernández Rojas /* Port RGMII control register */
759622972aSÁlvaro Fernández Rojas #define ETH_RGMII_CTRL_REG(x)		(0x60 + (x))
769622972aSÁlvaro Fernández Rojas #define ETH_RGMII_CTRL_GMII_CLK_EN	(1 << 7)
779622972aSÁlvaro Fernández Rojas #define ETH_RGMII_CTRL_MII_OVERRIDE_EN	(1 << 6)
789622972aSÁlvaro Fernández Rojas #define ETH_RGMII_CTRL_MII_MODE_MASK	(3 << 4)
799622972aSÁlvaro Fernández Rojas #define ETH_RGMII_CTRL_RGMII_MODE	(0 << 4)
809622972aSÁlvaro Fernández Rojas #define ETH_RGMII_CTRL_MII_MODE		(1 << 4)
819622972aSÁlvaro Fernández Rojas #define ETH_RGMII_CTRL_RVMII_MODE	(2 << 4)
829622972aSÁlvaro Fernández Rojas #define ETH_RGMII_CTRL_TIMING_SEL_EN	(1 << 0)
839622972aSÁlvaro Fernández Rojas 
849622972aSÁlvaro Fernández Rojas /* Port RGMII timing register */
859622972aSÁlvaro Fernández Rojas #define ENETSW_RGMII_TIMING_REG(x)	(0x68 + (x))
869622972aSÁlvaro Fernández Rojas 
879622972aSÁlvaro Fernández Rojas /* MDIO control register */
889622972aSÁlvaro Fernández Rojas #define MII_SC_REG			0xb0
899622972aSÁlvaro Fernández Rojas #define MII_SC_EXT_SHIFT		16
909622972aSÁlvaro Fernández Rojas #define MII_SC_EXT_MASK			(1 << MII_SC_EXT_SHIFT)
919622972aSÁlvaro Fernández Rojas #define MII_SC_REG_SHIFT		20
929622972aSÁlvaro Fernández Rojas #define MII_SC_PHYID_SHIFT		25
939622972aSÁlvaro Fernández Rojas #define MII_SC_RD_SHIFT			30
949622972aSÁlvaro Fernández Rojas #define MII_SC_RD_MASK			(1 << MII_SC_RD_SHIFT)
959622972aSÁlvaro Fernández Rojas #define MII_SC_WR_SHIFT			31
969622972aSÁlvaro Fernández Rojas #define MII_SC_WR_MASK			(1 << MII_SC_WR_SHIFT)
979622972aSÁlvaro Fernández Rojas 
989622972aSÁlvaro Fernández Rojas /* MDIO data register */
999622972aSÁlvaro Fernández Rojas #define MII_DAT_REG			0xb4
1009622972aSÁlvaro Fernández Rojas 
1019622972aSÁlvaro Fernández Rojas /* Global Management Configuration Register */
1029622972aSÁlvaro Fernández Rojas #define ETH_GMCR_REG			0x200
1039622972aSÁlvaro Fernández Rojas #define ETH_GMCR_RST_MIB_SHIFT		0
1049622972aSÁlvaro Fernández Rojas #define ETH_GMCR_RST_MIB_MASK		(1 << ETH_GMCR_RST_MIB_SHIFT)
1059622972aSÁlvaro Fernández Rojas 
1069622972aSÁlvaro Fernández Rojas /* Jumbo control register port mask register */
1079622972aSÁlvaro Fernández Rojas #define ETH_JMBCTL_PORT_REG		0x4004
1089622972aSÁlvaro Fernández Rojas 
1099622972aSÁlvaro Fernández Rojas /* Jumbo control mib good frame register */
1109622972aSÁlvaro Fernández Rojas #define ETH_JMBCTL_MAXSIZE_REG		0x4008
1119622972aSÁlvaro Fernández Rojas 
1129622972aSÁlvaro Fernández Rojas /* ETH port data */
1139622972aSÁlvaro Fernández Rojas struct bcm_enetsw_port {
1149622972aSÁlvaro Fernández Rojas 	bool used;
1159622972aSÁlvaro Fernández Rojas 	const char *name;
1169622972aSÁlvaro Fernández Rojas 	/* Config */
1179622972aSÁlvaro Fernández Rojas 	bool bypass_link;
1189622972aSÁlvaro Fernández Rojas 	int force_speed;
1199622972aSÁlvaro Fernández Rojas 	bool force_duplex_full;
1209622972aSÁlvaro Fernández Rojas 	/* PHY */
1219622972aSÁlvaro Fernández Rojas 	int phy_id;
1229622972aSÁlvaro Fernández Rojas };
1239622972aSÁlvaro Fernández Rojas 
1249622972aSÁlvaro Fernández Rojas /* ETH data */
1259622972aSÁlvaro Fernández Rojas struct bcm6368_eth_priv {
1269622972aSÁlvaro Fernández Rojas 	void __iomem *base;
1279622972aSÁlvaro Fernández Rojas 	/* DMA */
1289622972aSÁlvaro Fernández Rojas 	struct dma rx_dma;
1299622972aSÁlvaro Fernández Rojas 	struct dma tx_dma;
1309622972aSÁlvaro Fernández Rojas 	/* Ports */
1319622972aSÁlvaro Fernández Rojas 	uint8_t num_ports;
1329622972aSÁlvaro Fernández Rojas 	struct bcm_enetsw_port used_ports[ETH_MAX_PORT];
1339622972aSÁlvaro Fernández Rojas 	int sw_port_link[ETH_MAX_PORT];
1349622972aSÁlvaro Fernández Rojas 	bool rgmii_override;
1359622972aSÁlvaro Fernández Rojas 	bool rgmii_timing;
1369622972aSÁlvaro Fernández Rojas 	/* PHY */
1379622972aSÁlvaro Fernández Rojas 	int phy_id;
1389622972aSÁlvaro Fernández Rojas };
1399622972aSÁlvaro Fernández Rojas 
bcm_enet_port_is_rgmii(int portid)1409622972aSÁlvaro Fernández Rojas static inline bool bcm_enet_port_is_rgmii(int portid)
1419622972aSÁlvaro Fernández Rojas {
1429622972aSÁlvaro Fernández Rojas 	return portid >= ETH_RGMII_PORT0;
1439622972aSÁlvaro Fernández Rojas }
1449622972aSÁlvaro Fernández Rojas 
bcm6368_mdio_read(struct bcm6368_eth_priv * priv,uint8_t ext,int phy_id,int reg)1459622972aSÁlvaro Fernández Rojas static int bcm6368_mdio_read(struct bcm6368_eth_priv *priv, uint8_t ext,
1469622972aSÁlvaro Fernández Rojas 			     int phy_id, int reg)
1479622972aSÁlvaro Fernández Rojas {
1489622972aSÁlvaro Fernández Rojas 	uint32_t val;
1499622972aSÁlvaro Fernández Rojas 
1509622972aSÁlvaro Fernández Rojas 	writel_be(0, priv->base + MII_SC_REG);
1519622972aSÁlvaro Fernández Rojas 
1529622972aSÁlvaro Fernández Rojas 	val = MII_SC_RD_MASK |
1539622972aSÁlvaro Fernández Rojas 	      (phy_id << MII_SC_PHYID_SHIFT) |
1549622972aSÁlvaro Fernández Rojas 	      (reg << MII_SC_REG_SHIFT);
1559622972aSÁlvaro Fernández Rojas 
1569622972aSÁlvaro Fernández Rojas 	if (ext)
1579622972aSÁlvaro Fernández Rojas 		val |= MII_SC_EXT_MASK;
1589622972aSÁlvaro Fernández Rojas 
1599622972aSÁlvaro Fernández Rojas 	writel_be(val, priv->base + MII_SC_REG);
1609622972aSÁlvaro Fernández Rojas 	udelay(50);
1619622972aSÁlvaro Fernández Rojas 
1629622972aSÁlvaro Fernández Rojas 	return readw_be(priv->base + MII_DAT_REG);
1639622972aSÁlvaro Fernández Rojas }
1649622972aSÁlvaro Fernández Rojas 
bcm6368_mdio_write(struct bcm6368_eth_priv * priv,uint8_t ext,int phy_id,int reg,u16 data)1659622972aSÁlvaro Fernández Rojas static int bcm6368_mdio_write(struct bcm6368_eth_priv *priv, uint8_t ext,
1669622972aSÁlvaro Fernández Rojas 			      int phy_id, int reg, u16 data)
1679622972aSÁlvaro Fernández Rojas {
1689622972aSÁlvaro Fernández Rojas 	uint32_t val;
1699622972aSÁlvaro Fernández Rojas 
1709622972aSÁlvaro Fernández Rojas 	writel_be(0, priv->base + MII_SC_REG);
1719622972aSÁlvaro Fernández Rojas 
1729622972aSÁlvaro Fernández Rojas 	val = MII_SC_WR_MASK |
1739622972aSÁlvaro Fernández Rojas 	      (phy_id << MII_SC_PHYID_SHIFT) |
1749622972aSÁlvaro Fernández Rojas 	      (reg << MII_SC_REG_SHIFT);
1759622972aSÁlvaro Fernández Rojas 
1769622972aSÁlvaro Fernández Rojas 	if (ext)
1779622972aSÁlvaro Fernández Rojas 		val |= MII_SC_EXT_MASK;
1789622972aSÁlvaro Fernández Rojas 
1799622972aSÁlvaro Fernández Rojas 	val |= data;
1809622972aSÁlvaro Fernández Rojas 
1819622972aSÁlvaro Fernández Rojas 	writel_be(val, priv->base + MII_SC_REG);
1829622972aSÁlvaro Fernández Rojas 	udelay(50);
1839622972aSÁlvaro Fernández Rojas 
1849622972aSÁlvaro Fernández Rojas 	return 0;
1859622972aSÁlvaro Fernández Rojas }
1869622972aSÁlvaro Fernández Rojas 
bcm6368_eth_free_pkt(struct udevice * dev,uchar * packet,int len)1879622972aSÁlvaro Fernández Rojas static int bcm6368_eth_free_pkt(struct udevice *dev, uchar *packet, int len)
1889622972aSÁlvaro Fernández Rojas {
1899622972aSÁlvaro Fernández Rojas 	struct bcm6368_eth_priv *priv = dev_get_priv(dev);
1909622972aSÁlvaro Fernández Rojas 
1919622972aSÁlvaro Fernández Rojas 	return dma_prepare_rcv_buf(&priv->rx_dma, packet, len);
1929622972aSÁlvaro Fernández Rojas }
1939622972aSÁlvaro Fernández Rojas 
bcm6368_eth_recv(struct udevice * dev,int flags,uchar ** packetp)1949622972aSÁlvaro Fernández Rojas static int bcm6368_eth_recv(struct udevice *dev, int flags, uchar **packetp)
1959622972aSÁlvaro Fernández Rojas {
1969622972aSÁlvaro Fernández Rojas 	struct bcm6368_eth_priv *priv = dev_get_priv(dev);
1979622972aSÁlvaro Fernández Rojas 
1989622972aSÁlvaro Fernández Rojas 	return dma_receive(&priv->rx_dma, (void**)packetp, NULL);
1999622972aSÁlvaro Fernández Rojas }
2009622972aSÁlvaro Fernández Rojas 
bcm6368_eth_send(struct udevice * dev,void * packet,int length)2019622972aSÁlvaro Fernández Rojas static int bcm6368_eth_send(struct udevice *dev, void *packet, int length)
2029622972aSÁlvaro Fernández Rojas {
2039622972aSÁlvaro Fernández Rojas 	struct bcm6368_eth_priv *priv = dev_get_priv(dev);
2049622972aSÁlvaro Fernández Rojas 
2059622972aSÁlvaro Fernández Rojas 	/* pad packets smaller than ETH_ZLEN */
2069622972aSÁlvaro Fernández Rojas 	if (length < ETH_ZLEN) {
2079622972aSÁlvaro Fernández Rojas 		memset(packet + length, 0, ETH_ZLEN - length);
2089622972aSÁlvaro Fernández Rojas 		length = ETH_ZLEN;
2099622972aSÁlvaro Fernández Rojas 	}
2109622972aSÁlvaro Fernández Rojas 
2119622972aSÁlvaro Fernández Rojas 	return dma_send(&priv->tx_dma, packet, length, NULL);
2129622972aSÁlvaro Fernández Rojas }
2139622972aSÁlvaro Fernández Rojas 
bcm6368_eth_adjust_link(struct udevice * dev)2149622972aSÁlvaro Fernández Rojas static int bcm6368_eth_adjust_link(struct udevice *dev)
2159622972aSÁlvaro Fernández Rojas {
2169622972aSÁlvaro Fernández Rojas 	struct bcm6368_eth_priv *priv = dev_get_priv(dev);
2179622972aSÁlvaro Fernández Rojas 	unsigned int i;
2189622972aSÁlvaro Fernández Rojas 
2199622972aSÁlvaro Fernández Rojas 	for (i = 0; i < priv->num_ports; i++) {
2209622972aSÁlvaro Fernández Rojas 		struct bcm_enetsw_port *port;
2219622972aSÁlvaro Fernández Rojas 		int val, j, up, adv, lpa, speed, duplex, media;
2229622972aSÁlvaro Fernández Rojas 		int external_phy = bcm_enet_port_is_rgmii(i);
2239622972aSÁlvaro Fernández Rojas 		u8 override;
2249622972aSÁlvaro Fernández Rojas 
2259622972aSÁlvaro Fernández Rojas 		port = &priv->used_ports[i];
2269622972aSÁlvaro Fernández Rojas 		if (!port->used)
2279622972aSÁlvaro Fernández Rojas 			continue;
2289622972aSÁlvaro Fernández Rojas 
2299622972aSÁlvaro Fernández Rojas 		if (port->bypass_link)
2309622972aSÁlvaro Fernández Rojas 			continue;
2319622972aSÁlvaro Fernández Rojas 
2329622972aSÁlvaro Fernández Rojas 		/* dummy read to clear */
2339622972aSÁlvaro Fernández Rojas 		for (j = 0; j < 2; j++)
2349622972aSÁlvaro Fernández Rojas 			val = bcm6368_mdio_read(priv, external_phy,
2359622972aSÁlvaro Fernández Rojas 						port->phy_id, MII_BMSR);
2369622972aSÁlvaro Fernández Rojas 
2379622972aSÁlvaro Fernández Rojas 		if (val == 0xffff)
2389622972aSÁlvaro Fernández Rojas 			continue;
2399622972aSÁlvaro Fernández Rojas 
2409622972aSÁlvaro Fernández Rojas 		up = (val & BMSR_LSTATUS) ? 1 : 0;
2419622972aSÁlvaro Fernández Rojas 		if (!(up ^ priv->sw_port_link[i]))
2429622972aSÁlvaro Fernández Rojas 			continue;
2439622972aSÁlvaro Fernández Rojas 
2449622972aSÁlvaro Fernández Rojas 		priv->sw_port_link[i] = up;
2459622972aSÁlvaro Fernández Rojas 
2469622972aSÁlvaro Fernández Rojas 		/* link changed */
2479622972aSÁlvaro Fernández Rojas 		if (!up) {
2489622972aSÁlvaro Fernández Rojas 			dev_info(&priv->pdev->dev, "link DOWN on %s\n",
2499622972aSÁlvaro Fernández Rojas 				 port->name);
2509622972aSÁlvaro Fernández Rojas 			writeb_be(ETH_PORTOV_ENABLE_MASK,
2519622972aSÁlvaro Fernández Rojas 				  priv->base + ETH_PORTOV_REG(i));
2529622972aSÁlvaro Fernández Rojas 			writeb_be(ETH_PTCTRL_RXDIS_MASK |
2539622972aSÁlvaro Fernández Rojas 				  ETH_PTCTRL_TXDIS_MASK,
2549622972aSÁlvaro Fernández Rojas 				  priv->base + ETH_PTCTRL_REG(i));
2559622972aSÁlvaro Fernández Rojas 			continue;
2569622972aSÁlvaro Fernández Rojas 		}
2579622972aSÁlvaro Fernández Rojas 
2589622972aSÁlvaro Fernández Rojas 		adv = bcm6368_mdio_read(priv, external_phy,
2599622972aSÁlvaro Fernández Rojas 					port->phy_id, MII_ADVERTISE);
2609622972aSÁlvaro Fernández Rojas 
2619622972aSÁlvaro Fernández Rojas 		lpa = bcm6368_mdio_read(priv, external_phy, port->phy_id,
2629622972aSÁlvaro Fernández Rojas 					MII_LPA);
2639622972aSÁlvaro Fernández Rojas 
2649622972aSÁlvaro Fernández Rojas 		/* figure out media and duplex from advertise and LPA values */
2659622972aSÁlvaro Fernández Rojas 		media = mii_nway_result(lpa & adv);
2669622972aSÁlvaro Fernández Rojas 		duplex = (media & ADVERTISE_FULL) ? 1 : 0;
2679622972aSÁlvaro Fernández Rojas 
2689622972aSÁlvaro Fernández Rojas 		if (media & (ADVERTISE_100FULL | ADVERTISE_100HALF))
2699622972aSÁlvaro Fernández Rojas 			speed = 100;
2709622972aSÁlvaro Fernández Rojas 		else
2719622972aSÁlvaro Fernández Rojas 			speed = 10;
2729622972aSÁlvaro Fernández Rojas 
2739622972aSÁlvaro Fernández Rojas 		if (val & BMSR_ESTATEN) {
2749622972aSÁlvaro Fernández Rojas 			adv = bcm6368_mdio_read(priv, external_phy,
2759622972aSÁlvaro Fernández Rojas 						port->phy_id, MII_CTRL1000);
2769622972aSÁlvaro Fernández Rojas 
2779622972aSÁlvaro Fernández Rojas 			lpa = bcm6368_mdio_read(priv, external_phy,
2789622972aSÁlvaro Fernández Rojas 						port->phy_id, MII_STAT1000);
2799622972aSÁlvaro Fernández Rojas 
2809622972aSÁlvaro Fernández Rojas 			if ((adv & (ADVERTISE_1000FULL | ADVERTISE_1000HALF)) &&
2819622972aSÁlvaro Fernández Rojas 			    (lpa & (LPA_1000FULL | LPA_1000HALF))) {
2829622972aSÁlvaro Fernández Rojas 				speed = 1000;
2839622972aSÁlvaro Fernández Rojas 				duplex = (lpa & LPA_1000FULL);
2849622972aSÁlvaro Fernández Rojas 			}
2859622972aSÁlvaro Fernández Rojas 		}
2869622972aSÁlvaro Fernández Rojas 
2879622972aSÁlvaro Fernández Rojas 		pr_alert("link UP on %s, %dMbps, %s-duplex\n",
2889622972aSÁlvaro Fernández Rojas 			 port->name, speed, duplex ? "full" : "half");
2899622972aSÁlvaro Fernández Rojas 
2909622972aSÁlvaro Fernández Rojas 		override = ETH_PORTOV_ENABLE_MASK |
2919622972aSÁlvaro Fernández Rojas 			   ETH_PORTOV_LINKUP_MASK;
2929622972aSÁlvaro Fernández Rojas 
2939622972aSÁlvaro Fernández Rojas 		if (speed == 1000)
2949622972aSÁlvaro Fernández Rojas 			override |= ETH_PORTOV_1000_MASK;
2959622972aSÁlvaro Fernández Rojas 		else if (speed == 100)
2969622972aSÁlvaro Fernández Rojas 			override |= ETH_PORTOV_100_MASK;
2979622972aSÁlvaro Fernández Rojas 		if (duplex)
2989622972aSÁlvaro Fernández Rojas 			override |= ETH_PORTOV_FDX_MASK;
2999622972aSÁlvaro Fernández Rojas 
3009622972aSÁlvaro Fernández Rojas 		writeb_be(override, priv->base + ETH_PORTOV_REG(i));
3019622972aSÁlvaro Fernández Rojas 		writeb_be(0, priv->base + ETH_PTCTRL_REG(i));
3029622972aSÁlvaro Fernández Rojas 	}
3039622972aSÁlvaro Fernández Rojas 
3049622972aSÁlvaro Fernández Rojas 	return 0;
3059622972aSÁlvaro Fernández Rojas }
3069622972aSÁlvaro Fernández Rojas 
bcm6368_eth_start(struct udevice * dev)3079622972aSÁlvaro Fernández Rojas static int bcm6368_eth_start(struct udevice *dev)
3089622972aSÁlvaro Fernández Rojas {
3099622972aSÁlvaro Fernández Rojas 	struct bcm6368_eth_priv *priv = dev_get_priv(dev);
3109622972aSÁlvaro Fernández Rojas 	uint8_t i;
3119622972aSÁlvaro Fernández Rojas 
312*a4ae4225SÁlvaro Fernández Rojas 	/* disable all ports */
313*a4ae4225SÁlvaro Fernández Rojas 	for (i = 0; i < priv->num_ports; i++) {
314*a4ae4225SÁlvaro Fernández Rojas 		setbits_8(priv->base + ETH_PORTOV_REG(i),
315*a4ae4225SÁlvaro Fernández Rojas 			  ETH_PORTOV_ENABLE_MASK);
316*a4ae4225SÁlvaro Fernández Rojas 		setbits_8(priv->base + ETH_PTCTRL_REG(i),
317*a4ae4225SÁlvaro Fernández Rojas 			  ETH_PTCTRL_RXDIS_MASK | ETH_PTCTRL_TXDIS_MASK);
318*a4ae4225SÁlvaro Fernández Rojas 		priv->sw_port_link[i] = 0;
319*a4ae4225SÁlvaro Fernández Rojas 	}
320*a4ae4225SÁlvaro Fernández Rojas 
321*a4ae4225SÁlvaro Fernández Rojas 	/* enable external ports */
322*a4ae4225SÁlvaro Fernández Rojas 	for (i = ETH_RGMII_PORT0; i < priv->num_ports; i++) {
323*a4ae4225SÁlvaro Fernández Rojas 		u8 rgmii_ctrl = ETH_RGMII_CTRL_GMII_CLK_EN;
324*a4ae4225SÁlvaro Fernández Rojas 
325*a4ae4225SÁlvaro Fernández Rojas 		if (!priv->used_ports[i].used)
326*a4ae4225SÁlvaro Fernández Rojas 			continue;
327*a4ae4225SÁlvaro Fernández Rojas 
328*a4ae4225SÁlvaro Fernández Rojas 		if (priv->rgmii_override)
329*a4ae4225SÁlvaro Fernández Rojas 			rgmii_ctrl |= ETH_RGMII_CTRL_MII_OVERRIDE_EN;
330*a4ae4225SÁlvaro Fernández Rojas 		if (priv->rgmii_timing)
331*a4ae4225SÁlvaro Fernández Rojas 			rgmii_ctrl |= ETH_RGMII_CTRL_TIMING_SEL_EN;
332*a4ae4225SÁlvaro Fernández Rojas 
333*a4ae4225SÁlvaro Fernández Rojas 		setbits_8(priv->base + ETH_RGMII_CTRL_REG(i), rgmii_ctrl);
334*a4ae4225SÁlvaro Fernández Rojas 	}
335*a4ae4225SÁlvaro Fernández Rojas 
336*a4ae4225SÁlvaro Fernández Rojas 	/* reset mib */
337*a4ae4225SÁlvaro Fernández Rojas 	setbits_8(priv->base + ETH_GMCR_REG, ETH_GMCR_RST_MIB_MASK);
338*a4ae4225SÁlvaro Fernández Rojas 	mdelay(1);
339*a4ae4225SÁlvaro Fernández Rojas 	clrbits_8(priv->base + ETH_GMCR_REG, ETH_GMCR_RST_MIB_MASK);
340*a4ae4225SÁlvaro Fernández Rojas 	mdelay(1);
341*a4ae4225SÁlvaro Fernández Rojas 
342*a4ae4225SÁlvaro Fernández Rojas 	/* force CPU port state */
343*a4ae4225SÁlvaro Fernández Rojas 	setbits_8(priv->base + ETH_IMPOV_REG,
344*a4ae4225SÁlvaro Fernández Rojas 		  ETH_IMPOV_FORCE_MASK | ETH_IMPOV_LINKUP_MASK);
345*a4ae4225SÁlvaro Fernández Rojas 
346*a4ae4225SÁlvaro Fernández Rojas 	/* enable switch forward engine */
347*a4ae4225SÁlvaro Fernández Rojas 	setbits_8(priv->base + ETH_SWMODE_REG, ETH_SWMODE_FWD_EN_MASK);
348*a4ae4225SÁlvaro Fernández Rojas 
3499622972aSÁlvaro Fernández Rojas 	/* prepare rx dma buffers */
3509622972aSÁlvaro Fernández Rojas 	for (i = 0; i < ETH_RX_DESC; i++) {
3519622972aSÁlvaro Fernández Rojas 		int ret = dma_prepare_rcv_buf(&priv->rx_dma, net_rx_packets[i],
3529622972aSÁlvaro Fernández Rojas 					      PKTSIZE_ALIGN);
3539622972aSÁlvaro Fernández Rojas 		if (ret < 0)
3549622972aSÁlvaro Fernández Rojas 			break;
3559622972aSÁlvaro Fernández Rojas 	}
3569622972aSÁlvaro Fernández Rojas 
3579622972aSÁlvaro Fernández Rojas 	/* enable dma rx channel */
3589622972aSÁlvaro Fernández Rojas 	dma_enable(&priv->rx_dma);
3599622972aSÁlvaro Fernández Rojas 
3609622972aSÁlvaro Fernández Rojas 	/* enable dma tx channel */
3619622972aSÁlvaro Fernández Rojas 	dma_enable(&priv->tx_dma);
3629622972aSÁlvaro Fernández Rojas 
3639622972aSÁlvaro Fernández Rojas 	/* apply override config for bypass_link ports here. */
3649622972aSÁlvaro Fernández Rojas 	for (i = 0; i < priv->num_ports; i++) {
3659622972aSÁlvaro Fernández Rojas 		struct bcm_enetsw_port *port;
3669622972aSÁlvaro Fernández Rojas 		u8 override;
3679622972aSÁlvaro Fernández Rojas 
3689622972aSÁlvaro Fernández Rojas 		port = &priv->used_ports[i];
3699622972aSÁlvaro Fernández Rojas 		if (!port->used)
3709622972aSÁlvaro Fernández Rojas 			continue;
3719622972aSÁlvaro Fernández Rojas 
3729622972aSÁlvaro Fernández Rojas 		if (!port->bypass_link)
3739622972aSÁlvaro Fernández Rojas 			continue;
3749622972aSÁlvaro Fernández Rojas 
3759622972aSÁlvaro Fernández Rojas 		override = ETH_PORTOV_ENABLE_MASK |
3769622972aSÁlvaro Fernández Rojas 			   ETH_PORTOV_LINKUP_MASK;
3779622972aSÁlvaro Fernández Rojas 
3789622972aSÁlvaro Fernández Rojas 		switch (port->force_speed) {
3799622972aSÁlvaro Fernández Rojas 		case 1000:
3809622972aSÁlvaro Fernández Rojas 			override |= ETH_PORTOV_1000_MASK;
3819622972aSÁlvaro Fernández Rojas 			break;
3829622972aSÁlvaro Fernández Rojas 		case 100:
3839622972aSÁlvaro Fernández Rojas 			override |= ETH_PORTOV_100_MASK;
3849622972aSÁlvaro Fernández Rojas 			break;
3859622972aSÁlvaro Fernández Rojas 		case 10:
3869622972aSÁlvaro Fernández Rojas 			break;
3879622972aSÁlvaro Fernández Rojas 		default:
3889622972aSÁlvaro Fernández Rojas 			pr_warn("%s: invalid forced speed on port %s\n",
3899622972aSÁlvaro Fernández Rojas 				__func__, port->name);
3909622972aSÁlvaro Fernández Rojas 			break;
3919622972aSÁlvaro Fernández Rojas 		}
3929622972aSÁlvaro Fernández Rojas 
3939622972aSÁlvaro Fernández Rojas 		if (port->force_duplex_full)
3949622972aSÁlvaro Fernández Rojas 			override |= ETH_PORTOV_FDX_MASK;
3959622972aSÁlvaro Fernández Rojas 
3969622972aSÁlvaro Fernández Rojas 		writeb_be(override, priv->base + ETH_PORTOV_REG(i));
3979622972aSÁlvaro Fernández Rojas 		writeb_be(0, priv->base + ETH_PTCTRL_REG(i));
3989622972aSÁlvaro Fernández Rojas 	}
3999622972aSÁlvaro Fernández Rojas 
4009622972aSÁlvaro Fernández Rojas 	bcm6368_eth_adjust_link(dev);
4019622972aSÁlvaro Fernández Rojas 
4029622972aSÁlvaro Fernández Rojas 	return 0;
4039622972aSÁlvaro Fernández Rojas }
4049622972aSÁlvaro Fernández Rojas 
bcm6368_eth_stop(struct udevice * dev)4059622972aSÁlvaro Fernández Rojas static void bcm6368_eth_stop(struct udevice *dev)
4069622972aSÁlvaro Fernández Rojas {
4079622972aSÁlvaro Fernández Rojas 	struct bcm6368_eth_priv *priv = dev_get_priv(dev);
408*a4ae4225SÁlvaro Fernández Rojas 	uint8_t i;
409*a4ae4225SÁlvaro Fernández Rojas 
410*a4ae4225SÁlvaro Fernández Rojas 	/* disable all ports */
411*a4ae4225SÁlvaro Fernández Rojas 	for (i = 0; i < priv->num_ports; i++) {
412*a4ae4225SÁlvaro Fernández Rojas 		setbits_8(priv->base + ETH_PORTOV_REG(i),
413*a4ae4225SÁlvaro Fernández Rojas 			  ETH_PORTOV_ENABLE_MASK);
414*a4ae4225SÁlvaro Fernández Rojas 		setbits_8(priv->base + ETH_PTCTRL_REG(i),
415*a4ae4225SÁlvaro Fernández Rojas 			  ETH_PTCTRL_RXDIS_MASK | ETH_PTCTRL_TXDIS_MASK);
416*a4ae4225SÁlvaro Fernández Rojas 	}
417*a4ae4225SÁlvaro Fernández Rojas 
418*a4ae4225SÁlvaro Fernández Rojas 	/* disable external ports */
419*a4ae4225SÁlvaro Fernández Rojas 	for (i = ETH_RGMII_PORT0; i < priv->num_ports; i++) {
420*a4ae4225SÁlvaro Fernández Rojas 		if (!priv->used_ports[i].used)
421*a4ae4225SÁlvaro Fernández Rojas 			continue;
422*a4ae4225SÁlvaro Fernández Rojas 
423*a4ae4225SÁlvaro Fernández Rojas 		clrbits_8(priv->base + ETH_RGMII_CTRL_REG(i),
424*a4ae4225SÁlvaro Fernández Rojas 			  ETH_RGMII_CTRL_GMII_CLK_EN);
425*a4ae4225SÁlvaro Fernández Rojas 	}
426*a4ae4225SÁlvaro Fernández Rojas 
427*a4ae4225SÁlvaro Fernández Rojas 	/* disable CPU port */
428*a4ae4225SÁlvaro Fernández Rojas 	clrbits_8(priv->base + ETH_IMPOV_REG,
429*a4ae4225SÁlvaro Fernández Rojas 		  ETH_IMPOV_FORCE_MASK | ETH_IMPOV_LINKUP_MASK);
430*a4ae4225SÁlvaro Fernández Rojas 
431*a4ae4225SÁlvaro Fernández Rojas 	/* disable switch forward engine */
432*a4ae4225SÁlvaro Fernández Rojas 	clrbits_8(priv->base + ETH_SWMODE_REG, ETH_SWMODE_FWD_EN_MASK);
4339622972aSÁlvaro Fernández Rojas 
4349622972aSÁlvaro Fernández Rojas 	/* disable dma rx channel */
4359622972aSÁlvaro Fernández Rojas 	dma_disable(&priv->rx_dma);
4369622972aSÁlvaro Fernández Rojas 
4379622972aSÁlvaro Fernández Rojas 	/* disable dma tx channel */
4389622972aSÁlvaro Fernández Rojas 	dma_disable(&priv->tx_dma);
4399622972aSÁlvaro Fernández Rojas }
4409622972aSÁlvaro Fernández Rojas 
4419622972aSÁlvaro Fernández Rojas static const struct eth_ops bcm6368_eth_ops = {
4429622972aSÁlvaro Fernández Rojas 	.free_pkt = bcm6368_eth_free_pkt,
4439622972aSÁlvaro Fernández Rojas 	.recv = bcm6368_eth_recv,
4449622972aSÁlvaro Fernández Rojas 	.send = bcm6368_eth_send,
4459622972aSÁlvaro Fernández Rojas 	.start = bcm6368_eth_start,
4469622972aSÁlvaro Fernández Rojas 	.stop = bcm6368_eth_stop,
4479622972aSÁlvaro Fernández Rojas };
4489622972aSÁlvaro Fernández Rojas 
4499622972aSÁlvaro Fernández Rojas static const struct udevice_id bcm6368_eth_ids[] = {
4509622972aSÁlvaro Fernández Rojas 	{ .compatible = "brcm,bcm6368-enet", },
4519622972aSÁlvaro Fernández Rojas 	{ /* sentinel */ }
4529622972aSÁlvaro Fernández Rojas };
4539622972aSÁlvaro Fernández Rojas 
bcm6368_phy_is_external(struct bcm6368_eth_priv * priv,int phy_id)4549622972aSÁlvaro Fernández Rojas static bool bcm6368_phy_is_external(struct bcm6368_eth_priv *priv, int phy_id)
4559622972aSÁlvaro Fernández Rojas {
4569622972aSÁlvaro Fernández Rojas 	uint8_t i;
4579622972aSÁlvaro Fernández Rojas 
4589622972aSÁlvaro Fernández Rojas 	for (i = 0; i < priv->num_ports; ++i) {
4599622972aSÁlvaro Fernández Rojas 		if (!priv->used_ports[i].used)
4609622972aSÁlvaro Fernández Rojas 			continue;
4619622972aSÁlvaro Fernández Rojas 		if (priv->used_ports[i].phy_id == phy_id)
4629622972aSÁlvaro Fernández Rojas 			return bcm_enet_port_is_rgmii(i);
4639622972aSÁlvaro Fernández Rojas 	}
4649622972aSÁlvaro Fernández Rojas 
4659622972aSÁlvaro Fernández Rojas 	return true;
4669622972aSÁlvaro Fernández Rojas }
4679622972aSÁlvaro Fernández Rojas 
bcm6368_mii_mdio_read(struct mii_dev * bus,int addr,int devaddr,int reg)4689622972aSÁlvaro Fernández Rojas static int bcm6368_mii_mdio_read(struct mii_dev *bus, int addr, int devaddr,
4699622972aSÁlvaro Fernández Rojas 				 int reg)
4709622972aSÁlvaro Fernández Rojas {
4719622972aSÁlvaro Fernández Rojas 	struct bcm6368_eth_priv *priv = bus->priv;
4729622972aSÁlvaro Fernández Rojas 	bool ext = bcm6368_phy_is_external(priv, addr);
4739622972aSÁlvaro Fernández Rojas 
4749622972aSÁlvaro Fernández Rojas 	return bcm6368_mdio_read(priv, ext, addr, reg);
4759622972aSÁlvaro Fernández Rojas }
4769622972aSÁlvaro Fernández Rojas 
bcm6368_mii_mdio_write(struct mii_dev * bus,int addr,int devaddr,int reg,u16 data)4779622972aSÁlvaro Fernández Rojas static int bcm6368_mii_mdio_write(struct mii_dev *bus, int addr, int devaddr,
4789622972aSÁlvaro Fernández Rojas 				  int reg, u16 data)
4799622972aSÁlvaro Fernández Rojas {
4809622972aSÁlvaro Fernández Rojas 	struct bcm6368_eth_priv *priv = bus->priv;
4819622972aSÁlvaro Fernández Rojas 	bool ext = bcm6368_phy_is_external(priv, addr);
4829622972aSÁlvaro Fernández Rojas 
4839622972aSÁlvaro Fernández Rojas 	return bcm6368_mdio_write(priv, ext, addr, reg, data);
4849622972aSÁlvaro Fernández Rojas }
4859622972aSÁlvaro Fernández Rojas 
bcm6368_mdio_init(const char * name,struct bcm6368_eth_priv * priv)4869622972aSÁlvaro Fernández Rojas static int bcm6368_mdio_init(const char *name, struct bcm6368_eth_priv *priv)
4879622972aSÁlvaro Fernández Rojas {
4889622972aSÁlvaro Fernández Rojas 	struct mii_dev *bus;
4899622972aSÁlvaro Fernández Rojas 
4909622972aSÁlvaro Fernández Rojas 	bus = mdio_alloc();
4919622972aSÁlvaro Fernández Rojas 	if (!bus) {
4929622972aSÁlvaro Fernández Rojas 		pr_err("%s: failed to allocate MDIO bus\n", __func__);
4939622972aSÁlvaro Fernández Rojas 		return -ENOMEM;
4949622972aSÁlvaro Fernández Rojas 	}
4959622972aSÁlvaro Fernández Rojas 
4969622972aSÁlvaro Fernández Rojas 	bus->read = bcm6368_mii_mdio_read;
4979622972aSÁlvaro Fernández Rojas 	bus->write = bcm6368_mii_mdio_write;
4989622972aSÁlvaro Fernández Rojas 	bus->priv = priv;
4999622972aSÁlvaro Fernández Rojas 	snprintf(bus->name, sizeof(bus->name), "%s", name);
5009622972aSÁlvaro Fernández Rojas 
5019622972aSÁlvaro Fernández Rojas 	return mdio_register(bus);
5029622972aSÁlvaro Fernández Rojas }
5039622972aSÁlvaro Fernández Rojas 
bcm6368_eth_probe(struct udevice * dev)5049622972aSÁlvaro Fernández Rojas static int bcm6368_eth_probe(struct udevice *dev)
5059622972aSÁlvaro Fernández Rojas {
5069622972aSÁlvaro Fernández Rojas 	struct eth_pdata *pdata = dev_get_platdata(dev);
5079622972aSÁlvaro Fernández Rojas 	struct bcm6368_eth_priv *priv = dev_get_priv(dev);
5089622972aSÁlvaro Fernández Rojas 	int num_ports, ret, i;
5099622972aSÁlvaro Fernández Rojas 	ofnode node;
5109622972aSÁlvaro Fernández Rojas 
5119622972aSÁlvaro Fernández Rojas 	/* get base address */
5129622972aSÁlvaro Fernández Rojas 	priv->base = dev_remap_addr(dev);
5139622972aSÁlvaro Fernández Rojas 	if (!priv->base)
5149622972aSÁlvaro Fernández Rojas 		return -EINVAL;
5159622972aSÁlvaro Fernández Rojas 	pdata->iobase = (phys_addr_t) priv->base;
5169622972aSÁlvaro Fernández Rojas 
5179622972aSÁlvaro Fernández Rojas 	/* get number of ports */
5189622972aSÁlvaro Fernández Rojas 	num_ports = dev_read_u32_default(dev, "brcm,num-ports", ETH_MAX_PORT);
5199622972aSÁlvaro Fernández Rojas 	if (!num_ports || num_ports > ETH_MAX_PORT)
5209622972aSÁlvaro Fernández Rojas 		return -EINVAL;
5219622972aSÁlvaro Fernández Rojas 
5229622972aSÁlvaro Fernández Rojas 	/* get dma channels */
5239622972aSÁlvaro Fernández Rojas 	ret = dma_get_by_name(dev, "tx", &priv->tx_dma);
5249622972aSÁlvaro Fernández Rojas 	if (ret)
5259622972aSÁlvaro Fernández Rojas 		return -EINVAL;
5269622972aSÁlvaro Fernández Rojas 
5279622972aSÁlvaro Fernández Rojas 	ret = dma_get_by_name(dev, "rx", &priv->rx_dma);
5289622972aSÁlvaro Fernández Rojas 	if (ret)
5299622972aSÁlvaro Fernández Rojas 		return -EINVAL;
5309622972aSÁlvaro Fernández Rojas 
5319622972aSÁlvaro Fernández Rojas 	/* try to enable clocks */
5329622972aSÁlvaro Fernández Rojas 	for (i = 0; ; i++) {
5339622972aSÁlvaro Fernández Rojas 		struct clk clk;
5349622972aSÁlvaro Fernández Rojas 		int ret;
5359622972aSÁlvaro Fernández Rojas 
5369622972aSÁlvaro Fernández Rojas 		ret = clk_get_by_index(dev, i, &clk);
5379622972aSÁlvaro Fernández Rojas 		if (ret < 0)
5389622972aSÁlvaro Fernández Rojas 			break;
5399622972aSÁlvaro Fernández Rojas 
5409622972aSÁlvaro Fernández Rojas 		ret = clk_enable(&clk);
5419622972aSÁlvaro Fernández Rojas 		if (ret < 0) {
5429622972aSÁlvaro Fernández Rojas 			pr_err("%s: error enabling clock %d\n", __func__, i);
5439622972aSÁlvaro Fernández Rojas 			return ret;
5449622972aSÁlvaro Fernández Rojas 		}
5459622972aSÁlvaro Fernández Rojas 
5469622972aSÁlvaro Fernández Rojas 		ret = clk_free(&clk);
5479622972aSÁlvaro Fernández Rojas 		if (ret < 0) {
5489622972aSÁlvaro Fernández Rojas 			pr_err("%s: error freeing clock %d\n", __func__, i);
5499622972aSÁlvaro Fernández Rojas 			return ret;
5509622972aSÁlvaro Fernández Rojas 		}
5519622972aSÁlvaro Fernández Rojas 	}
5529622972aSÁlvaro Fernández Rojas 
5539622972aSÁlvaro Fernández Rojas 	/* try to perform resets */
5549622972aSÁlvaro Fernández Rojas 	for (i = 0; ; i++) {
5559622972aSÁlvaro Fernández Rojas 		struct reset_ctl reset;
5569622972aSÁlvaro Fernández Rojas 		int ret;
5579622972aSÁlvaro Fernández Rojas 
5589622972aSÁlvaro Fernández Rojas 		ret = reset_get_by_index(dev, i, &reset);
5599622972aSÁlvaro Fernández Rojas 		if (ret < 0)
5609622972aSÁlvaro Fernández Rojas 			break;
5619622972aSÁlvaro Fernández Rojas 
5629622972aSÁlvaro Fernández Rojas 		ret = reset_deassert(&reset);
5639622972aSÁlvaro Fernández Rojas 		if (ret < 0) {
5649622972aSÁlvaro Fernández Rojas 			pr_err("%s: error deasserting reset %d\n", __func__, i);
5659622972aSÁlvaro Fernández Rojas 			return ret;
5669622972aSÁlvaro Fernández Rojas 		}
5679622972aSÁlvaro Fernández Rojas 
5689622972aSÁlvaro Fernández Rojas 		ret = reset_free(&reset);
5699622972aSÁlvaro Fernández Rojas 		if (ret < 0) {
5709622972aSÁlvaro Fernández Rojas 			pr_err("%s: error freeing reset %d\n", __func__, i);
5719622972aSÁlvaro Fernández Rojas 			return ret;
5729622972aSÁlvaro Fernández Rojas 		}
5739622972aSÁlvaro Fernández Rojas 	}
5749622972aSÁlvaro Fernández Rojas 
5759622972aSÁlvaro Fernández Rojas 	/* set priv data */
5769622972aSÁlvaro Fernández Rojas 	priv->num_ports = num_ports;
5779622972aSÁlvaro Fernández Rojas 	if (dev_read_bool(dev, "brcm,rgmii-override"))
5789622972aSÁlvaro Fernández Rojas 		priv->rgmii_override = true;
5799622972aSÁlvaro Fernández Rojas 	if (dev_read_bool(dev, "brcm,rgmii-timing"))
5809622972aSÁlvaro Fernández Rojas 		priv->rgmii_timing = true;
5819622972aSÁlvaro Fernández Rojas 
5829622972aSÁlvaro Fernández Rojas 	/* get ports */
5839622972aSÁlvaro Fernández Rojas 	dev_for_each_subnode(node, dev) {
5849622972aSÁlvaro Fernández Rojas 		const char *comp;
5859622972aSÁlvaro Fernández Rojas 		const char *label;
5869622972aSÁlvaro Fernández Rojas 		unsigned int p;
5879622972aSÁlvaro Fernández Rojas 		int phy_id;
5889622972aSÁlvaro Fernández Rojas 		int speed;
5899622972aSÁlvaro Fernández Rojas 
5909622972aSÁlvaro Fernández Rojas 		comp = ofnode_read_string(node, "compatible");
5919622972aSÁlvaro Fernández Rojas 		if (!comp || memcmp(comp, ETH_PORT_STR, sizeof(ETH_PORT_STR)))
5929622972aSÁlvaro Fernández Rojas 			continue;
5939622972aSÁlvaro Fernández Rojas 
5949622972aSÁlvaro Fernández Rojas 		p = ofnode_read_u32_default(node, "reg", ETH_MAX_PORT);
5959622972aSÁlvaro Fernández Rojas 		if (p >= num_ports)
5969622972aSÁlvaro Fernández Rojas 			return -EINVAL;
5979622972aSÁlvaro Fernández Rojas 
5989622972aSÁlvaro Fernández Rojas 		label = ofnode_read_string(node, "label");
5999622972aSÁlvaro Fernández Rojas 		if (!label) {
6009622972aSÁlvaro Fernández Rojas 			debug("%s: node %s has no label\n", __func__,
6019622972aSÁlvaro Fernández Rojas 			      ofnode_get_name(node));
6029622972aSÁlvaro Fernández Rojas 			return -EINVAL;
6039622972aSÁlvaro Fernández Rojas 		}
6049622972aSÁlvaro Fernández Rojas 
6059622972aSÁlvaro Fernández Rojas 		phy_id = ofnode_read_u32_default(node, "brcm,phy-id", -1);
6069622972aSÁlvaro Fernández Rojas 
6079622972aSÁlvaro Fernández Rojas 		priv->used_ports[p].used = true;
6089622972aSÁlvaro Fernández Rojas 		priv->used_ports[p].name = label;
6099622972aSÁlvaro Fernández Rojas 		priv->used_ports[p].phy_id = phy_id;
6109622972aSÁlvaro Fernández Rojas 
6119622972aSÁlvaro Fernández Rojas 		if (ofnode_read_bool(node, "full-duplex"))
6129622972aSÁlvaro Fernández Rojas 			priv->used_ports[p].force_duplex_full = true;
6139622972aSÁlvaro Fernández Rojas 		if (ofnode_read_bool(node, "bypass-link"))
6149622972aSÁlvaro Fernández Rojas 			priv->used_ports[p].bypass_link = true;
6159622972aSÁlvaro Fernández Rojas 		speed = ofnode_read_u32_default(node, "speed", 0);
6169622972aSÁlvaro Fernández Rojas 		if (speed)
6179622972aSÁlvaro Fernández Rojas 			priv->used_ports[p].force_speed = speed;
6189622972aSÁlvaro Fernández Rojas 	}
6199622972aSÁlvaro Fernández Rojas 
6209622972aSÁlvaro Fernández Rojas 	/* init mii bus */
6219622972aSÁlvaro Fernández Rojas 	ret = bcm6368_mdio_init(dev->name, priv);
6229622972aSÁlvaro Fernández Rojas 	if (ret)
6239622972aSÁlvaro Fernández Rojas 		return ret;
6249622972aSÁlvaro Fernández Rojas 
6259622972aSÁlvaro Fernández Rojas 	/* enable jumbo on all ports */
6269622972aSÁlvaro Fernández Rojas 	writel_be(0x1ff, priv->base + ETH_JMBCTL_PORT_REG);
6279622972aSÁlvaro Fernández Rojas 	writew_be(9728, priv->base + ETH_JMBCTL_MAXSIZE_REG);
6289622972aSÁlvaro Fernández Rojas 
6299622972aSÁlvaro Fernández Rojas 	return 0;
6309622972aSÁlvaro Fernández Rojas }
6319622972aSÁlvaro Fernández Rojas 
6329622972aSÁlvaro Fernández Rojas U_BOOT_DRIVER(bcm6368_eth) = {
6339622972aSÁlvaro Fernández Rojas 	.name = "bcm6368_eth",
6349622972aSÁlvaro Fernández Rojas 	.id = UCLASS_ETH,
6359622972aSÁlvaro Fernández Rojas 	.of_match = bcm6368_eth_ids,
6369622972aSÁlvaro Fernández Rojas 	.ops = &bcm6368_eth_ops,
6379622972aSÁlvaro Fernández Rojas 	.platdata_auto_alloc_size = sizeof(struct eth_pdata),
6389622972aSÁlvaro Fernández Rojas 	.priv_auto_alloc_size = sizeof(struct bcm6368_eth_priv),
6399622972aSÁlvaro Fernández Rojas 	.probe = bcm6368_eth_probe,
6409622972aSÁlvaro Fernández Rojas };
641