xref: /openbmc/u-boot/drivers/net/tsec.c (revision 87f78478)
183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
22439e4bfSJean-Christophe PLAGNIOL-VILLARD /*
32439e4bfSJean-Christophe PLAGNIOL-VILLARD  * Freescale Three Speed Ethernet Controller driver
42439e4bfSJean-Christophe PLAGNIOL-VILLARD  *
5aec84bf6SClaudiu Manoil  * Copyright 2004-2011, 2013 Freescale Semiconductor, Inc.
62439e4bfSJean-Christophe PLAGNIOL-VILLARD  * (C) Copyright 2003, Motorola, Inc.
72439e4bfSJean-Christophe PLAGNIOL-VILLARD  * author Andy Fleming
82439e4bfSJean-Christophe PLAGNIOL-VILLARD  */
92439e4bfSJean-Christophe PLAGNIOL-VILLARD 
102439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <config.h>
112439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <common.h>
129a1d6af5SBin Meng #include <dm.h>
132439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <malloc.h>
142439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <net.h>
152439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <command.h>
16dd3d1f56SAndy Fleming #include <tsec.h>
17063c1263SAndy Fleming #include <fsl_mdio.h>
181221ce45SMasahiro Yamada #include <linux/errno.h>
19aada81deSchenhui zhao #include <asm/processor.h>
2052d00a81SAlison Wang #include <asm/io.h>
212439e4bfSJean-Christophe PLAGNIOL-VILLARD 
229a1d6af5SBin Meng #ifndef CONFIG_DM_ETH
2375b9d4aeSAndy Fleming /* Default initializations for TSEC controllers. */
2475b9d4aeSAndy Fleming 
2575b9d4aeSAndy Fleming static struct tsec_info_struct tsec_info[] = {
2675b9d4aeSAndy Fleming #ifdef CONFIG_TSEC1
2775b9d4aeSAndy Fleming 	STD_TSEC_INFO(1),	/* TSEC1 */
2875b9d4aeSAndy Fleming #endif
2975b9d4aeSAndy Fleming #ifdef CONFIG_TSEC2
3075b9d4aeSAndy Fleming 	STD_TSEC_INFO(2),	/* TSEC2 */
3175b9d4aeSAndy Fleming #endif
3275b9d4aeSAndy Fleming #ifdef CONFIG_MPC85XX_FEC
3375b9d4aeSAndy Fleming 	{
34aec84bf6SClaudiu Manoil 		.regs = TSEC_GET_REGS(2, 0x2000),
3575b9d4aeSAndy Fleming 		.devname = CONFIG_MPC85XX_FEC_NAME,
3675b9d4aeSAndy Fleming 		.phyaddr = FEC_PHY_ADDR,
37063c1263SAndy Fleming 		.flags = FEC_FLAGS,
38063c1263SAndy Fleming 		.mii_devname = DEFAULT_MII_NAME
3975b9d4aeSAndy Fleming 	},			/* FEC */
4075b9d4aeSAndy Fleming #endif
4175b9d4aeSAndy Fleming #ifdef CONFIG_TSEC3
4275b9d4aeSAndy Fleming 	STD_TSEC_INFO(3),	/* TSEC3 */
4375b9d4aeSAndy Fleming #endif
4475b9d4aeSAndy Fleming #ifdef CONFIG_TSEC4
4575b9d4aeSAndy Fleming 	STD_TSEC_INFO(4),	/* TSEC4 */
4675b9d4aeSAndy Fleming #endif
4775b9d4aeSAndy Fleming };
489a1d6af5SBin Meng #endif /* CONFIG_DM_ETH */
4975b9d4aeSAndy Fleming 
502abe361cSAndy Fleming #define TBIANA_SETTINGS ( \
512abe361cSAndy Fleming 		TBIANA_ASYMMETRIC_PAUSE \
522abe361cSAndy Fleming 		| TBIANA_SYMMETRIC_PAUSE \
532abe361cSAndy Fleming 		| TBIANA_FULL_DUPLEX \
542abe361cSAndy Fleming 		)
552abe361cSAndy Fleming 
5690b5bf21SFelix Radensky /* By default force the TBI PHY into 1000Mbps full duplex when in SGMII mode */
5790b5bf21SFelix Radensky #ifndef CONFIG_TSEC_TBICR_SETTINGS
5872c96a68SKumar Gala #define CONFIG_TSEC_TBICR_SETTINGS ( \
592abe361cSAndy Fleming 		TBICR_PHY_RESET \
6072c96a68SKumar Gala 		| TBICR_ANEG_ENABLE \
612abe361cSAndy Fleming 		| TBICR_FULL_DUPLEX \
622abe361cSAndy Fleming 		| TBICR_SPEED1_SET \
632abe361cSAndy Fleming 		)
6490b5bf21SFelix Radensky #endif /* CONFIG_TSEC_TBICR_SETTINGS */
6546e91674SPeter Tyser 
662abe361cSAndy Fleming /* Configure the TBI for SGMII operation */
tsec_configure_serdes(struct tsec_private * priv)672abe361cSAndy Fleming static void tsec_configure_serdes(struct tsec_private *priv)
682abe361cSAndy Fleming {
699872b736SBin Meng 	/*
709872b736SBin Meng 	 * Access TBI PHY registers at given TSEC register offset as opposed
719872b736SBin Meng 	 * to the register offset used for external PHY accesses
729872b736SBin Meng 	 */
73063c1263SAndy Fleming 	tsec_local_mdio_write(priv->phyregs_sgmii, in_be32(&priv->regs->tbipa),
74063c1263SAndy Fleming 			      0, TBI_ANA, TBIANA_SETTINGS);
75063c1263SAndy Fleming 	tsec_local_mdio_write(priv->phyregs_sgmii, in_be32(&priv->regs->tbipa),
76063c1263SAndy Fleming 			      0, TBI_TBICON, TBICON_CLK_SELECT);
77063c1263SAndy Fleming 	tsec_local_mdio_write(priv->phyregs_sgmii, in_be32(&priv->regs->tbipa),
78063c1263SAndy Fleming 			      0, TBI_CR, CONFIG_TSEC_TBICR_SETTINGS);
792439e4bfSJean-Christophe PLAGNIOL-VILLARD }
802439e4bfSJean-Christophe PLAGNIOL-VILLARD 
811a4af5c5SChris Packham /* the 'way' for ethernet-CRC-32. Spliced in from Linux lib/crc32.c
821a4af5c5SChris Packham  * and this is the ethernet-crc method needed for TSEC -- and perhaps
831a4af5c5SChris Packham  * some other adapter -- hash tables
841a4af5c5SChris Packham  */
851a4af5c5SChris Packham #define CRCPOLY_LE 0xedb88320
ether_crc(size_t len,unsigned char const * p)861a4af5c5SChris Packham static u32 ether_crc(size_t len, unsigned char const *p)
871a4af5c5SChris Packham {
881a4af5c5SChris Packham 	int i;
891a4af5c5SChris Packham 	u32 crc;
901a4af5c5SChris Packham 
911a4af5c5SChris Packham 	crc = ~0;
921a4af5c5SChris Packham 	while (len--) {
931a4af5c5SChris Packham 		crc ^= *p++;
941a4af5c5SChris Packham 		for (i = 0; i < 8; i++)
951a4af5c5SChris Packham 			crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
961a4af5c5SChris Packham 	}
971a4af5c5SChris Packham 	/* an reverse the bits, cuz of way they arrive -- last-first */
981a4af5c5SChris Packham 	crc = (crc >> 16) | (crc << 16);
991a4af5c5SChris Packham 	crc = (crc >> 8 & 0x00ff00ff) | (crc << 8 & 0xff00ff00);
1001a4af5c5SChris Packham 	crc = (crc >> 4 & 0x0f0f0f0f) | (crc << 4 & 0xf0f0f0f0);
1011a4af5c5SChris Packham 	crc = (crc >> 2 & 0x33333333) | (crc << 2 & 0xcccccccc);
1021a4af5c5SChris Packham 	crc = (crc >> 1 & 0x55555555) | (crc << 1 & 0xaaaaaaaa);
1031a4af5c5SChris Packham 	return crc;
1041a4af5c5SChris Packham }
1051a4af5c5SChris Packham 
1062439e4bfSJean-Christophe PLAGNIOL-VILLARD /* CREDITS: linux gianfar driver, slightly adjusted... thanx. */
1072439e4bfSJean-Christophe PLAGNIOL-VILLARD 
1082439e4bfSJean-Christophe PLAGNIOL-VILLARD /* Set the appropriate hash bit for the given addr */
1092439e4bfSJean-Christophe PLAGNIOL-VILLARD 
1109872b736SBin Meng /*
1119872b736SBin Meng  * The algorithm works like so:
1122439e4bfSJean-Christophe PLAGNIOL-VILLARD  * 1) Take the Destination Address (ie the multicast address), and
1132439e4bfSJean-Christophe PLAGNIOL-VILLARD  * do a CRC on it (little endian), and reverse the bits of the
1142439e4bfSJean-Christophe PLAGNIOL-VILLARD  * result.
1152439e4bfSJean-Christophe PLAGNIOL-VILLARD  * 2) Use the 8 most significant bits as a hash into a 256-entry
1162439e4bfSJean-Christophe PLAGNIOL-VILLARD  * table.  The table is controlled through 8 32-bit registers:
117876d4515SClaudiu Manoil  * gaddr0-7.  gaddr0's MSB is entry 0, and gaddr7's LSB is entry
118876d4515SClaudiu Manoil  * 255.  This means that the 3 most significant bits in the
1192439e4bfSJean-Christophe PLAGNIOL-VILLARD  * hash index which gaddr register to use, and the 5 other bits
1202439e4bfSJean-Christophe PLAGNIOL-VILLARD  * indicate which bit (assuming an IBM numbering scheme, which
121876d4515SClaudiu Manoil  * for PowerPC (tm) is usually the case) in the register holds
1229872b736SBin Meng  * the entry.
1239872b736SBin Meng  */
1249a1d6af5SBin Meng #ifndef CONFIG_DM_ETH
tsec_mcast_addr(struct eth_device * dev,const u8 * mcast_mac,int join)125*67bb9842SChris Packham static int tsec_mcast_addr(struct eth_device *dev, const u8 *mcast_mac,
126*67bb9842SChris Packham 			   int join)
1279a1d6af5SBin Meng #else
128*67bb9842SChris Packham static int tsec_mcast_addr(struct udevice *dev, const u8 *mcast_mac, int join)
1299a1d6af5SBin Meng #endif
1302439e4bfSJean-Christophe PLAGNIOL-VILLARD {
131b200204eSClaudiu Manoil 	struct tsec_private *priv = (struct tsec_private *)dev->priv;
132876d4515SClaudiu Manoil 	struct tsec __iomem *regs = priv->regs;
133876d4515SClaudiu Manoil 	u32 result, value;
134876d4515SClaudiu Manoil 	u8 whichbit, whichreg;
1352439e4bfSJean-Christophe PLAGNIOL-VILLARD 
136876d4515SClaudiu Manoil 	result = ether_crc(MAC_ADDR_LEN, mcast_mac);
137876d4515SClaudiu Manoil 	whichbit = (result >> 24) & 0x1f; /* the 5 LSB = which bit to set */
138876d4515SClaudiu Manoil 	whichreg = result >> 29; /* the 3 MSB = which reg to set it in */
1392439e4bfSJean-Christophe PLAGNIOL-VILLARD 
140d38de338SMario Six 	value = BIT(31 - whichbit);
1412439e4bfSJean-Christophe PLAGNIOL-VILLARD 
142*67bb9842SChris Packham 	if (join)
143876d4515SClaudiu Manoil 		setbits_be32(&regs->hash.gaddr0 + whichreg, value);
144876d4515SClaudiu Manoil 	else
145876d4515SClaudiu Manoil 		clrbits_be32(&regs->hash.gaddr0 + whichreg, value);
146876d4515SClaudiu Manoil 
1472439e4bfSJean-Christophe PLAGNIOL-VILLARD 	return 0;
1482439e4bfSJean-Christophe PLAGNIOL-VILLARD }
14990751910SMingkai Hu 
1509872b736SBin Meng /*
1519872b736SBin Meng  * Initialized required registers to appropriate values, zeroing
15290751910SMingkai Hu  * those we don't care about (unless zero is bad, in which case,
15390751910SMingkai Hu  * choose a more appropriate value)
15490751910SMingkai Hu  */
init_registers(struct tsec __iomem * regs)155aec84bf6SClaudiu Manoil static void init_registers(struct tsec __iomem *regs)
15690751910SMingkai Hu {
15790751910SMingkai Hu 	/* Clear IEVENT */
15890751910SMingkai Hu 	out_be32(&regs->ievent, IEVENT_INIT_CLEAR);
15990751910SMingkai Hu 
16090751910SMingkai Hu 	out_be32(&regs->imask, IMASK_INIT_CLEAR);
16190751910SMingkai Hu 
16290751910SMingkai Hu 	out_be32(&regs->hash.iaddr0, 0);
16390751910SMingkai Hu 	out_be32(&regs->hash.iaddr1, 0);
16490751910SMingkai Hu 	out_be32(&regs->hash.iaddr2, 0);
16590751910SMingkai Hu 	out_be32(&regs->hash.iaddr3, 0);
16690751910SMingkai Hu 	out_be32(&regs->hash.iaddr4, 0);
16790751910SMingkai Hu 	out_be32(&regs->hash.iaddr5, 0);
16890751910SMingkai Hu 	out_be32(&regs->hash.iaddr6, 0);
16990751910SMingkai Hu 	out_be32(&regs->hash.iaddr7, 0);
17090751910SMingkai Hu 
17190751910SMingkai Hu 	out_be32(&regs->hash.gaddr0, 0);
17290751910SMingkai Hu 	out_be32(&regs->hash.gaddr1, 0);
17390751910SMingkai Hu 	out_be32(&regs->hash.gaddr2, 0);
17490751910SMingkai Hu 	out_be32(&regs->hash.gaddr3, 0);
17590751910SMingkai Hu 	out_be32(&regs->hash.gaddr4, 0);
17690751910SMingkai Hu 	out_be32(&regs->hash.gaddr5, 0);
17790751910SMingkai Hu 	out_be32(&regs->hash.gaddr6, 0);
17890751910SMingkai Hu 	out_be32(&regs->hash.gaddr7, 0);
17990751910SMingkai Hu 
18090751910SMingkai Hu 	out_be32(&regs->rctrl, 0x00000000);
18190751910SMingkai Hu 
18290751910SMingkai Hu 	/* Init RMON mib registers */
18382ef75caSClaudiu Manoil 	memset((void *)&regs->rmon, 0, sizeof(regs->rmon));
18490751910SMingkai Hu 
18590751910SMingkai Hu 	out_be32(&regs->rmon.cam1, 0xffffffff);
18690751910SMingkai Hu 	out_be32(&regs->rmon.cam2, 0xffffffff);
18790751910SMingkai Hu 
18890751910SMingkai Hu 	out_be32(&regs->mrblr, MRBLR_INIT_SETTINGS);
18990751910SMingkai Hu 
19090751910SMingkai Hu 	out_be32(&regs->minflr, MINFLR_INIT_SETTINGS);
19190751910SMingkai Hu 
19290751910SMingkai Hu 	out_be32(&regs->attr, ATTR_INIT_SETTINGS);
19390751910SMingkai Hu 	out_be32(&regs->attreli, ATTRELI_INIT_SETTINGS);
19490751910SMingkai Hu }
19590751910SMingkai Hu 
1969872b736SBin Meng /*
1979872b736SBin Meng  * Configure maccfg2 based on negotiated speed and duplex
19890751910SMingkai Hu  * reported by PHY handling code
19990751910SMingkai Hu  */
adjust_link(struct tsec_private * priv,struct phy_device * phydev)200063c1263SAndy Fleming static void adjust_link(struct tsec_private *priv, struct phy_device *phydev)
20190751910SMingkai Hu {
202aec84bf6SClaudiu Manoil 	struct tsec __iomem *regs = priv->regs;
20390751910SMingkai Hu 	u32 ecntrl, maccfg2;
20490751910SMingkai Hu 
205063c1263SAndy Fleming 	if (!phydev->link) {
206063c1263SAndy Fleming 		printf("%s: No link.\n", phydev->dev->name);
20790751910SMingkai Hu 		return;
20890751910SMingkai Hu 	}
20990751910SMingkai Hu 
21090751910SMingkai Hu 	/* clear all bits relative with interface mode */
21190751910SMingkai Hu 	ecntrl = in_be32(&regs->ecntrl);
21290751910SMingkai Hu 	ecntrl &= ~ECNTRL_R100;
21390751910SMingkai Hu 
21490751910SMingkai Hu 	maccfg2 = in_be32(&regs->maccfg2);
21590751910SMingkai Hu 	maccfg2 &= ~(MACCFG2_IF | MACCFG2_FULL_DUPLEX);
21690751910SMingkai Hu 
217063c1263SAndy Fleming 	if (phydev->duplex)
21890751910SMingkai Hu 		maccfg2 |= MACCFG2_FULL_DUPLEX;
21990751910SMingkai Hu 
220063c1263SAndy Fleming 	switch (phydev->speed) {
22190751910SMingkai Hu 	case 1000:
22290751910SMingkai Hu 		maccfg2 |= MACCFG2_GMII;
22390751910SMingkai Hu 		break;
22490751910SMingkai Hu 	case 100:
22590751910SMingkai Hu 	case 10:
22690751910SMingkai Hu 		maccfg2 |= MACCFG2_MII;
22790751910SMingkai Hu 
2289872b736SBin Meng 		/*
2299872b736SBin Meng 		 * Set R100 bit in all modes although
23090751910SMingkai Hu 		 * it is only used in RGMII mode
23190751910SMingkai Hu 		 */
232063c1263SAndy Fleming 		if (phydev->speed == 100)
23390751910SMingkai Hu 			ecntrl |= ECNTRL_R100;
23490751910SMingkai Hu 		break;
23590751910SMingkai Hu 	default:
236063c1263SAndy Fleming 		printf("%s: Speed was bad\n", phydev->dev->name);
23790751910SMingkai Hu 		break;
23890751910SMingkai Hu 	}
23990751910SMingkai Hu 
24090751910SMingkai Hu 	out_be32(&regs->ecntrl, ecntrl);
24190751910SMingkai Hu 	out_be32(&regs->maccfg2, maccfg2);
24290751910SMingkai Hu 
243063c1263SAndy Fleming 	printf("Speed: %d, %s duplex%s\n", phydev->speed,
244063c1263SAndy Fleming 	       (phydev->duplex) ? "full" : "half",
245063c1263SAndy Fleming 	       (phydev->port == PORT_FIBRE) ? ", fiber mode" : "");
24690751910SMingkai Hu }
24790751910SMingkai Hu 
2488ba50176SBin Meng /*
2498ba50176SBin Meng  * This returns the status bits of the device. The return value
2508ba50176SBin Meng  * is never checked, and this is what the 8260 driver did, so we
2518ba50176SBin Meng  * do the same. Presumably, this would be zero if there were no
2528ba50176SBin Meng  * errors
2538ba50176SBin Meng  */
2549a1d6af5SBin Meng #ifndef CONFIG_DM_ETH
tsec_send(struct eth_device * dev,void * packet,int length)2558ba50176SBin Meng static int tsec_send(struct eth_device *dev, void *packet, int length)
2569a1d6af5SBin Meng #else
2579a1d6af5SBin Meng static int tsec_send(struct udevice *dev, void *packet, int length)
2589a1d6af5SBin Meng #endif
2598ba50176SBin Meng {
2608ba50176SBin Meng 	struct tsec_private *priv = (struct tsec_private *)dev->priv;
2618ba50176SBin Meng 	struct tsec __iomem *regs = priv->regs;
262d38de338SMario Six 	u16 status;
2638ba50176SBin Meng 	int result = 0;
2648ba50176SBin Meng 	int i;
2658ba50176SBin Meng 
2668ba50176SBin Meng 	/* Find an empty buffer descriptor */
2678ba50176SBin Meng 	for (i = 0;
2688ba50176SBin Meng 	     in_be16(&priv->txbd[priv->tx_idx].status) & TXBD_READY;
2698ba50176SBin Meng 	     i++) {
2708ba50176SBin Meng 		if (i >= TOUT_LOOP) {
2718ba50176SBin Meng 			debug("%s: tsec: tx buffers full\n", dev->name);
2728ba50176SBin Meng 			return result;
2738ba50176SBin Meng 		}
2748ba50176SBin Meng 	}
2758ba50176SBin Meng 
2768ba50176SBin Meng 	out_be32(&priv->txbd[priv->tx_idx].bufptr, (u32)packet);
2778ba50176SBin Meng 	out_be16(&priv->txbd[priv->tx_idx].length, length);
2788ba50176SBin Meng 	status = in_be16(&priv->txbd[priv->tx_idx].status);
2798ba50176SBin Meng 	out_be16(&priv->txbd[priv->tx_idx].status, status |
2808ba50176SBin Meng 		(TXBD_READY | TXBD_LAST | TXBD_CRC | TXBD_INTERRUPT));
2818ba50176SBin Meng 
2828ba50176SBin Meng 	/* Tell the DMA to go */
2838ba50176SBin Meng 	out_be32(&regs->tstat, TSTAT_CLEAR_THALT);
2848ba50176SBin Meng 
2858ba50176SBin Meng 	/* Wait for buffer to be transmitted */
2868ba50176SBin Meng 	for (i = 0;
2878ba50176SBin Meng 	     in_be16(&priv->txbd[priv->tx_idx].status) & TXBD_READY;
2888ba50176SBin Meng 	     i++) {
2898ba50176SBin Meng 		if (i >= TOUT_LOOP) {
2908ba50176SBin Meng 			debug("%s: tsec: tx error\n", dev->name);
2918ba50176SBin Meng 			return result;
2928ba50176SBin Meng 		}
2938ba50176SBin Meng 	}
2948ba50176SBin Meng 
2958ba50176SBin Meng 	priv->tx_idx = (priv->tx_idx + 1) % TX_BUF_CNT;
2968ba50176SBin Meng 	result = in_be16(&priv->txbd[priv->tx_idx].status) & TXBD_STATS;
2978ba50176SBin Meng 
2988ba50176SBin Meng 	return result;
2998ba50176SBin Meng }
3008ba50176SBin Meng 
3019a1d6af5SBin Meng #ifndef CONFIG_DM_ETH
tsec_recv(struct eth_device * dev)3028ba50176SBin Meng static int tsec_recv(struct eth_device *dev)
3038ba50176SBin Meng {
3048ba50176SBin Meng 	struct tsec_private *priv = (struct tsec_private *)dev->priv;
3058ba50176SBin Meng 	struct tsec __iomem *regs = priv->regs;
3068ba50176SBin Meng 
3078ba50176SBin Meng 	while (!(in_be16(&priv->rxbd[priv->rx_idx].status) & RXBD_EMPTY)) {
3088ba50176SBin Meng 		int length = in_be16(&priv->rxbd[priv->rx_idx].length);
309d38de338SMario Six 		u16 status = in_be16(&priv->rxbd[priv->rx_idx].status);
3108ba50176SBin Meng 		uchar *packet = net_rx_packets[priv->rx_idx];
3118ba50176SBin Meng 
3128ba50176SBin Meng 		/* Send the packet up if there were no errors */
3138ba50176SBin Meng 		if (!(status & RXBD_STATS))
3148ba50176SBin Meng 			net_process_received_packet(packet, length - 4);
3158ba50176SBin Meng 		else
3168ba50176SBin Meng 			printf("Got error %x\n", (status & RXBD_STATS));
3178ba50176SBin Meng 
3188ba50176SBin Meng 		out_be16(&priv->rxbd[priv->rx_idx].length, 0);
3198ba50176SBin Meng 
3208ba50176SBin Meng 		status = RXBD_EMPTY;
3218ba50176SBin Meng 		/* Set the wrap bit if this is the last element in the list */
3228ba50176SBin Meng 		if ((priv->rx_idx + 1) == PKTBUFSRX)
3238ba50176SBin Meng 			status |= RXBD_WRAP;
3248ba50176SBin Meng 		out_be16(&priv->rxbd[priv->rx_idx].status, status);
3258ba50176SBin Meng 
3268ba50176SBin Meng 		priv->rx_idx = (priv->rx_idx + 1) % PKTBUFSRX;
3278ba50176SBin Meng 	}
3288ba50176SBin Meng 
3298ba50176SBin Meng 	if (in_be32(&regs->ievent) & IEVENT_BSY) {
3308ba50176SBin Meng 		out_be32(&regs->ievent, IEVENT_BSY);
3318ba50176SBin Meng 		out_be32(&regs->rstat, RSTAT_CLEAR_RHALT);
3328ba50176SBin Meng 	}
3338ba50176SBin Meng 
3348ba50176SBin Meng 	return -1;
3358ba50176SBin Meng }
3369a1d6af5SBin Meng #else
tsec_recv(struct udevice * dev,int flags,uchar ** packetp)3379a1d6af5SBin Meng static int tsec_recv(struct udevice *dev, int flags, uchar **packetp)
3389a1d6af5SBin Meng {
3399a1d6af5SBin Meng 	struct tsec_private *priv = (struct tsec_private *)dev->priv;
3409a1d6af5SBin Meng 	struct tsec __iomem *regs = priv->regs;
3419a1d6af5SBin Meng 	int ret = -1;
3429a1d6af5SBin Meng 
3439a1d6af5SBin Meng 	if (!(in_be16(&priv->rxbd[priv->rx_idx].status) & RXBD_EMPTY)) {
3449a1d6af5SBin Meng 		int length = in_be16(&priv->rxbd[priv->rx_idx].length);
345d38de338SMario Six 		u16 status = in_be16(&priv->rxbd[priv->rx_idx].status);
346d38de338SMario Six 		u32 buf;
3479a1d6af5SBin Meng 
3489a1d6af5SBin Meng 		/* Send the packet up if there were no errors */
3499a1d6af5SBin Meng 		if (!(status & RXBD_STATS)) {
3509a1d6af5SBin Meng 			buf = in_be32(&priv->rxbd[priv->rx_idx].bufptr);
3519a1d6af5SBin Meng 			*packetp = (uchar *)buf;
3529a1d6af5SBin Meng 			ret = length - 4;
3539a1d6af5SBin Meng 		} else {
3549a1d6af5SBin Meng 			printf("Got error %x\n", (status & RXBD_STATS));
3559a1d6af5SBin Meng 		}
3569a1d6af5SBin Meng 	}
3579a1d6af5SBin Meng 
3589a1d6af5SBin Meng 	if (in_be32(&regs->ievent) & IEVENT_BSY) {
3599a1d6af5SBin Meng 		out_be32(&regs->ievent, IEVENT_BSY);
3609a1d6af5SBin Meng 		out_be32(&regs->rstat, RSTAT_CLEAR_RHALT);
3619a1d6af5SBin Meng 	}
3629a1d6af5SBin Meng 
3639a1d6af5SBin Meng 	return ret;
3649a1d6af5SBin Meng }
3659a1d6af5SBin Meng 
tsec_free_pkt(struct udevice * dev,uchar * packet,int length)3669a1d6af5SBin Meng static int tsec_free_pkt(struct udevice *dev, uchar *packet, int length)
3679a1d6af5SBin Meng {
3689a1d6af5SBin Meng 	struct tsec_private *priv = (struct tsec_private *)dev->priv;
369d38de338SMario Six 	u16 status;
3709a1d6af5SBin Meng 
3719a1d6af5SBin Meng 	out_be16(&priv->rxbd[priv->rx_idx].length, 0);
3729a1d6af5SBin Meng 
3739a1d6af5SBin Meng 	status = RXBD_EMPTY;
3749a1d6af5SBin Meng 	/* Set the wrap bit if this is the last element in the list */
3759a1d6af5SBin Meng 	if ((priv->rx_idx + 1) == PKTBUFSRX)
3769a1d6af5SBin Meng 		status |= RXBD_WRAP;
3779a1d6af5SBin Meng 	out_be16(&priv->rxbd[priv->rx_idx].status, status);
3789a1d6af5SBin Meng 
3799a1d6af5SBin Meng 	priv->rx_idx = (priv->rx_idx + 1) % PKTBUFSRX;
3809a1d6af5SBin Meng 
3819a1d6af5SBin Meng 	return 0;
3829a1d6af5SBin Meng }
3839a1d6af5SBin Meng #endif
3848ba50176SBin Meng 
3858ba50176SBin Meng /* Stop the interface */
3869a1d6af5SBin Meng #ifndef CONFIG_DM_ETH
tsec_halt(struct eth_device * dev)3878ba50176SBin Meng static void tsec_halt(struct eth_device *dev)
3889a1d6af5SBin Meng #else
3899a1d6af5SBin Meng static void tsec_halt(struct udevice *dev)
3909a1d6af5SBin Meng #endif
3918ba50176SBin Meng {
3928ba50176SBin Meng 	struct tsec_private *priv = (struct tsec_private *)dev->priv;
3938ba50176SBin Meng 	struct tsec __iomem *regs = priv->regs;
3948ba50176SBin Meng 
3958ba50176SBin Meng 	clrbits_be32(&regs->dmactrl, DMACTRL_GRS | DMACTRL_GTS);
3968ba50176SBin Meng 	setbits_be32(&regs->dmactrl, DMACTRL_GRS | DMACTRL_GTS);
3978ba50176SBin Meng 
3988ba50176SBin Meng 	while ((in_be32(&regs->ievent) & (IEVENT_GRSC | IEVENT_GTSC))
3998ba50176SBin Meng 			!= (IEVENT_GRSC | IEVENT_GTSC))
4008ba50176SBin Meng 		;
4018ba50176SBin Meng 
4028ba50176SBin Meng 	clrbits_be32(&regs->maccfg1, MACCFG1_TX_EN | MACCFG1_RX_EN);
4038ba50176SBin Meng 
4048ba50176SBin Meng 	/* Shut down the PHY, as needed */
4058ba50176SBin Meng 	phy_shutdown(priv->phydev);
4068ba50176SBin Meng }
4078ba50176SBin Meng 
408aada81deSchenhui zhao #ifdef CONFIG_SYS_FSL_ERRATUM_NMG_ETSEC129
409aada81deSchenhui zhao /*
410aada81deSchenhui zhao  * When MACCFG1[Rx_EN] is enabled during system boot as part
411aada81deSchenhui zhao  * of the eTSEC port initialization sequence,
412aada81deSchenhui zhao  * the eTSEC Rx logic may not be properly initialized.
413aada81deSchenhui zhao  */
redundant_init(struct tsec_private * priv)41456a27a1eSBin Meng void redundant_init(struct tsec_private *priv)
415aada81deSchenhui zhao {
416aec84bf6SClaudiu Manoil 	struct tsec __iomem *regs = priv->regs;
417aada81deSchenhui zhao 	uint t, count = 0;
418aada81deSchenhui zhao 	int fail = 1;
419aada81deSchenhui zhao 	static const u8 pkt[] = {
420aada81deSchenhui zhao 		0x00, 0x1e, 0x4f, 0x12, 0xcb, 0x2c, 0x00, 0x25,
421aada81deSchenhui zhao 		0x64, 0xbb, 0xd1, 0xab, 0x08, 0x00, 0x45, 0x00,
422aada81deSchenhui zhao 		0x00, 0x5c, 0xdd, 0x22, 0x00, 0x00, 0x80, 0x01,
423aada81deSchenhui zhao 		0x1f, 0x71, 0x0a, 0xc1, 0x14, 0x22, 0x0a, 0xc1,
424aada81deSchenhui zhao 		0x14, 0x6a, 0x08, 0x00, 0xef, 0x7e, 0x02, 0x00,
425aada81deSchenhui zhao 		0x94, 0x05, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
426aada81deSchenhui zhao 		0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e,
427aada81deSchenhui zhao 		0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76,
428aada81deSchenhui zhao 		0x77, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
429aada81deSchenhui zhao 		0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
430aada81deSchenhui zhao 		0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
431aada81deSchenhui zhao 		0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
432aada81deSchenhui zhao 		0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70,
433aada81deSchenhui zhao 		0x71, 0x72};
434aada81deSchenhui zhao 
435aada81deSchenhui zhao 	/* Enable promiscuous mode */
436aada81deSchenhui zhao 	setbits_be32(&regs->rctrl, 0x8);
437aada81deSchenhui zhao 	/* Enable loopback mode */
438aada81deSchenhui zhao 	setbits_be32(&regs->maccfg1, MACCFG1_LOOPBACK);
439aada81deSchenhui zhao 	/* Enable transmit and receive */
440aada81deSchenhui zhao 	setbits_be32(&regs->maccfg1, MACCFG1_RX_EN | MACCFG1_TX_EN);
441aada81deSchenhui zhao 
442aada81deSchenhui zhao 	/* Tell the DMA it is clear to go */
443aada81deSchenhui zhao 	setbits_be32(&regs->dmactrl, DMACTRL_INIT_SETTINGS);
444aada81deSchenhui zhao 	out_be32(&regs->tstat, TSTAT_CLEAR_THALT);
445aada81deSchenhui zhao 	out_be32(&regs->rstat, RSTAT_CLEAR_RHALT);
446aada81deSchenhui zhao 	clrbits_be32(&regs->dmactrl, DMACTRL_GRS | DMACTRL_GTS);
447aada81deSchenhui zhao 
448aada81deSchenhui zhao 	do {
449d38de338SMario Six 		u16 status;
450d38de338SMario Six 
45156a27a1eSBin Meng 		tsec_send(priv->dev, (void *)pkt, sizeof(pkt));
452aada81deSchenhui zhao 
453aada81deSchenhui zhao 		/* Wait for buffer to be received */
454e677da97SBin Meng 		for (t = 0;
455e677da97SBin Meng 		     in_be16(&priv->rxbd[priv->rx_idx].status) & RXBD_EMPTY;
456362b123fSBin Meng 		     t++) {
457aada81deSchenhui zhao 			if (t >= 10 * TOUT_LOOP) {
45856a27a1eSBin Meng 				printf("%s: tsec: rx error\n", priv->dev->name);
459aada81deSchenhui zhao 				break;
460aada81deSchenhui zhao 			}
461aada81deSchenhui zhao 		}
462aada81deSchenhui zhao 
463362b123fSBin Meng 		if (!memcmp(pkt, net_rx_packets[priv->rx_idx], sizeof(pkt)))
464aada81deSchenhui zhao 			fail = 0;
465aada81deSchenhui zhao 
466e677da97SBin Meng 		out_be16(&priv->rxbd[priv->rx_idx].length, 0);
4679c9141fdSClaudiu Manoil 		status = RXBD_EMPTY;
468362b123fSBin Meng 		if ((priv->rx_idx + 1) == PKTBUFSRX)
4699c9141fdSClaudiu Manoil 			status |= RXBD_WRAP;
470e677da97SBin Meng 		out_be16(&priv->rxbd[priv->rx_idx].status, status);
471362b123fSBin Meng 		priv->rx_idx = (priv->rx_idx + 1) % PKTBUFSRX;
472aada81deSchenhui zhao 
473aada81deSchenhui zhao 		if (in_be32(&regs->ievent) & IEVENT_BSY) {
474aada81deSchenhui zhao 			out_be32(&regs->ievent, IEVENT_BSY);
475aada81deSchenhui zhao 			out_be32(&regs->rstat, RSTAT_CLEAR_RHALT);
476aada81deSchenhui zhao 		}
477aada81deSchenhui zhao 		if (fail) {
478aada81deSchenhui zhao 			printf("loopback recv packet error!\n");
479aada81deSchenhui zhao 			clrbits_be32(&regs->maccfg1, MACCFG1_RX_EN);
480aada81deSchenhui zhao 			udelay(1000);
481aada81deSchenhui zhao 			setbits_be32(&regs->maccfg1, MACCFG1_RX_EN);
482aada81deSchenhui zhao 		}
483aada81deSchenhui zhao 	} while ((count++ < 4) && (fail == 1));
484aada81deSchenhui zhao 
485aada81deSchenhui zhao 	if (fail)
486aada81deSchenhui zhao 		panic("eTSEC init fail!\n");
487aada81deSchenhui zhao 	/* Disable promiscuous mode */
488aada81deSchenhui zhao 	clrbits_be32(&regs->rctrl, 0x8);
489aada81deSchenhui zhao 	/* Disable loopback mode */
490aada81deSchenhui zhao 	clrbits_be32(&regs->maccfg1, MACCFG1_LOOPBACK);
491aada81deSchenhui zhao }
492aada81deSchenhui zhao #endif
493aada81deSchenhui zhao 
4949872b736SBin Meng /*
4959872b736SBin Meng  * Set up the buffers and their descriptors, and bring up the
49690751910SMingkai Hu  * interface
49790751910SMingkai Hu  */
startup_tsec(struct tsec_private * priv)49856a27a1eSBin Meng static void startup_tsec(struct tsec_private *priv)
49990751910SMingkai Hu {
500aec84bf6SClaudiu Manoil 	struct tsec __iomem *regs = priv->regs;
501d38de338SMario Six 	u16 status;
5029c9141fdSClaudiu Manoil 	int i;
50390751910SMingkai Hu 
504063c1263SAndy Fleming 	/* reset the indices to zero */
505362b123fSBin Meng 	priv->rx_idx = 0;
506362b123fSBin Meng 	priv->tx_idx = 0;
507aada81deSchenhui zhao #ifdef CONFIG_SYS_FSL_ERRATUM_NMG_ETSEC129
508aada81deSchenhui zhao 	uint svr;
509aada81deSchenhui zhao #endif
510063c1263SAndy Fleming 
51190751910SMingkai Hu 	/* Point to the buffer descriptors */
512e677da97SBin Meng 	out_be32(&regs->tbase, (u32)&priv->txbd[0]);
513e677da97SBin Meng 	out_be32(&regs->rbase, (u32)&priv->rxbd[0]);
51490751910SMingkai Hu 
51590751910SMingkai Hu 	/* Initialize the Rx Buffer descriptors */
51690751910SMingkai Hu 	for (i = 0; i < PKTBUFSRX; i++) {
517e677da97SBin Meng 		out_be16(&priv->rxbd[i].status, RXBD_EMPTY);
518e677da97SBin Meng 		out_be16(&priv->rxbd[i].length, 0);
519e677da97SBin Meng 		out_be32(&priv->rxbd[i].bufptr, (u32)net_rx_packets[i]);
52090751910SMingkai Hu 	}
521e677da97SBin Meng 	status = in_be16(&priv->rxbd[PKTBUFSRX - 1].status);
522e677da97SBin Meng 	out_be16(&priv->rxbd[PKTBUFSRX - 1].status, status | RXBD_WRAP);
52390751910SMingkai Hu 
52490751910SMingkai Hu 	/* Initialize the TX Buffer Descriptors */
52590751910SMingkai Hu 	for (i = 0; i < TX_BUF_CNT; i++) {
526e677da97SBin Meng 		out_be16(&priv->txbd[i].status, 0);
527e677da97SBin Meng 		out_be16(&priv->txbd[i].length, 0);
528e677da97SBin Meng 		out_be32(&priv->txbd[i].bufptr, 0);
52990751910SMingkai Hu 	}
530e677da97SBin Meng 	status = in_be16(&priv->txbd[TX_BUF_CNT - 1].status);
531e677da97SBin Meng 	out_be16(&priv->txbd[TX_BUF_CNT - 1].status, status | TXBD_WRAP);
53290751910SMingkai Hu 
533aada81deSchenhui zhao #ifdef CONFIG_SYS_FSL_ERRATUM_NMG_ETSEC129
534aada81deSchenhui zhao 	svr = get_svr();
535aada81deSchenhui zhao 	if ((SVR_MAJ(svr) == 1) || IS_SVR_REV(svr, 2, 0))
53656a27a1eSBin Meng 		redundant_init(priv);
537aada81deSchenhui zhao #endif
53890751910SMingkai Hu 	/* Enable Transmit and Receive */
53990751910SMingkai Hu 	setbits_be32(&regs->maccfg1, MACCFG1_RX_EN | MACCFG1_TX_EN);
54090751910SMingkai Hu 
54190751910SMingkai Hu 	/* Tell the DMA it is clear to go */
54290751910SMingkai Hu 	setbits_be32(&regs->dmactrl, DMACTRL_INIT_SETTINGS);
54390751910SMingkai Hu 	out_be32(&regs->tstat, TSTAT_CLEAR_THALT);
54490751910SMingkai Hu 	out_be32(&regs->rstat, RSTAT_CLEAR_RHALT);
54590751910SMingkai Hu 	clrbits_be32(&regs->dmactrl, DMACTRL_GRS | DMACTRL_GTS);
54690751910SMingkai Hu }
54790751910SMingkai Hu 
5489872b736SBin Meng /*
5499872b736SBin Meng  * Initializes data structures and registers for the controller,
55090751910SMingkai Hu  * and brings the interface up. Returns the link status, meaning
55190751910SMingkai Hu  * that it returns success if the link is up, failure otherwise.
5529872b736SBin Meng  * This allows U-Boot to find the first active controller.
55390751910SMingkai Hu  */
5549a1d6af5SBin Meng #ifndef CONFIG_DM_ETH
tsec_init(struct eth_device * dev,bd_t * bd)55590751910SMingkai Hu static int tsec_init(struct eth_device *dev, bd_t *bd)
5569a1d6af5SBin Meng #else
5579a1d6af5SBin Meng static int tsec_init(struct udevice *dev)
5589a1d6af5SBin Meng #endif
55990751910SMingkai Hu {
56090751910SMingkai Hu 	struct tsec_private *priv = (struct tsec_private *)dev->priv;
5619a1d6af5SBin Meng #ifdef CONFIG_DM_ETH
5629a1d6af5SBin Meng 	struct eth_pdata *pdata = dev_get_platdata(dev);
5639a1d6af5SBin Meng #endif
564aec84bf6SClaudiu Manoil 	struct tsec __iomem *regs = priv->regs;
565b1690bc3SClaudiu Manoil 	u32 tempval;
56611af8d65STimur Tabi 	int ret;
56790751910SMingkai Hu 
56890751910SMingkai Hu 	/* Make sure the controller is stopped */
56990751910SMingkai Hu 	tsec_halt(dev);
57090751910SMingkai Hu 
57190751910SMingkai Hu 	/* Init MACCFG2.  Defaults to GMII */
57290751910SMingkai Hu 	out_be32(&regs->maccfg2, MACCFG2_INIT_SETTINGS);
57390751910SMingkai Hu 
57490751910SMingkai Hu 	/* Init ECNTRL */
57590751910SMingkai Hu 	out_be32(&regs->ecntrl, ECNTRL_INIT_SETTINGS);
57690751910SMingkai Hu 
5779872b736SBin Meng 	/*
5789872b736SBin Meng 	 * Copy the station address into the address registers.
579b1690bc3SClaudiu Manoil 	 * For a station address of 0x12345678ABCD in transmission
580b1690bc3SClaudiu Manoil 	 * order (BE), MACnADDR1 is set to 0xCDAB7856 and
581b1690bc3SClaudiu Manoil 	 * MACnADDR2 is set to 0x34120000.
582b1690bc3SClaudiu Manoil 	 */
5839a1d6af5SBin Meng #ifndef CONFIG_DM_ETH
584b1690bc3SClaudiu Manoil 	tempval = (dev->enetaddr[5] << 24) | (dev->enetaddr[4] << 16) |
585b1690bc3SClaudiu Manoil 		  (dev->enetaddr[3] << 8)  |  dev->enetaddr[2];
5869a1d6af5SBin Meng #else
5879a1d6af5SBin Meng 	tempval = (pdata->enetaddr[5] << 24) | (pdata->enetaddr[4] << 16) |
5889a1d6af5SBin Meng 		  (pdata->enetaddr[3] << 8)  |  pdata->enetaddr[2];
5899a1d6af5SBin Meng #endif
59090751910SMingkai Hu 
59190751910SMingkai Hu 	out_be32(&regs->macstnaddr1, tempval);
59290751910SMingkai Hu 
5939a1d6af5SBin Meng #ifndef CONFIG_DM_ETH
594b1690bc3SClaudiu Manoil 	tempval = (dev->enetaddr[1] << 24) | (dev->enetaddr[0] << 16);
5959a1d6af5SBin Meng #else
5969a1d6af5SBin Meng 	tempval = (pdata->enetaddr[1] << 24) | (pdata->enetaddr[0] << 16);
5979a1d6af5SBin Meng #endif
59890751910SMingkai Hu 
59990751910SMingkai Hu 	out_be32(&regs->macstnaddr2, tempval);
60090751910SMingkai Hu 
60190751910SMingkai Hu 	/* Clear out (for the most part) the other registers */
60290751910SMingkai Hu 	init_registers(regs);
60390751910SMingkai Hu 
60490751910SMingkai Hu 	/* Ready the device for tx/rx */
60556a27a1eSBin Meng 	startup_tsec(priv);
60690751910SMingkai Hu 
607063c1263SAndy Fleming 	/* Start up the PHY */
60811af8d65STimur Tabi 	ret = phy_startup(priv->phydev);
60911af8d65STimur Tabi 	if (ret) {
61011af8d65STimur Tabi 		printf("Could not initialize PHY %s\n",
61111af8d65STimur Tabi 		       priv->phydev->dev->name);
61211af8d65STimur Tabi 		return ret;
61311af8d65STimur Tabi 	}
614063c1263SAndy Fleming 
615063c1263SAndy Fleming 	adjust_link(priv, priv->phydev);
616063c1263SAndy Fleming 
61790751910SMingkai Hu 	/* If there's no link, fail */
618063c1263SAndy Fleming 	return priv->phydev->link ? 0 : -1;
61990751910SMingkai Hu }
62090751910SMingkai Hu 
tsec_get_interface(struct tsec_private * priv)621063c1263SAndy Fleming static phy_interface_t tsec_get_interface(struct tsec_private *priv)
622063c1263SAndy Fleming {
623aec84bf6SClaudiu Manoil 	struct tsec __iomem *regs = priv->regs;
624063c1263SAndy Fleming 	u32 ecntrl;
625063c1263SAndy Fleming 
626063c1263SAndy Fleming 	ecntrl = in_be32(&regs->ecntrl);
627063c1263SAndy Fleming 
628063c1263SAndy Fleming 	if (ecntrl & ECNTRL_SGMII_MODE)
629063c1263SAndy Fleming 		return PHY_INTERFACE_MODE_SGMII;
630063c1263SAndy Fleming 
631063c1263SAndy Fleming 	if (ecntrl & ECNTRL_TBI_MODE) {
632063c1263SAndy Fleming 		if (ecntrl & ECNTRL_REDUCED_MODE)
633063c1263SAndy Fleming 			return PHY_INTERFACE_MODE_RTBI;
634063c1263SAndy Fleming 		else
635063c1263SAndy Fleming 			return PHY_INTERFACE_MODE_TBI;
636063c1263SAndy Fleming 	}
637063c1263SAndy Fleming 
638063c1263SAndy Fleming 	if (ecntrl & ECNTRL_REDUCED_MODE) {
639d38de338SMario Six 		phy_interface_t interface;
640d38de338SMario Six 
641063c1263SAndy Fleming 		if (ecntrl & ECNTRL_REDUCED_MII_MODE)
642063c1263SAndy Fleming 			return PHY_INTERFACE_MODE_RMII;
643d38de338SMario Six 
644d38de338SMario Six 		interface = priv->interface;
645063c1263SAndy Fleming 
646063c1263SAndy Fleming 		/*
647063c1263SAndy Fleming 		 * This isn't autodetected, so it must
648063c1263SAndy Fleming 		 * be set by the platform code.
649063c1263SAndy Fleming 		 */
650d38de338SMario Six 		if (interface == PHY_INTERFACE_MODE_RGMII_ID ||
651d38de338SMario Six 		    interface == PHY_INTERFACE_MODE_RGMII_TXID ||
652d38de338SMario Six 		    interface == PHY_INTERFACE_MODE_RGMII_RXID)
653063c1263SAndy Fleming 			return interface;
654063c1263SAndy Fleming 
655063c1263SAndy Fleming 		return PHY_INTERFACE_MODE_RGMII;
656063c1263SAndy Fleming 	}
657063c1263SAndy Fleming 
658063c1263SAndy Fleming 	if (priv->flags & TSEC_GIGABIT)
659063c1263SAndy Fleming 		return PHY_INTERFACE_MODE_GMII;
660063c1263SAndy Fleming 
661063c1263SAndy Fleming 	return PHY_INTERFACE_MODE_MII;
662063c1263SAndy Fleming }
663063c1263SAndy Fleming 
6649872b736SBin Meng /*
6659872b736SBin Meng  * Discover which PHY is attached to the device, and configure it
66690751910SMingkai Hu  * properly.  If the PHY is not recognized, then return 0
66790751910SMingkai Hu  * (failure).  Otherwise, return 1
66890751910SMingkai Hu  */
init_phy(struct tsec_private * priv)66956a27a1eSBin Meng static int init_phy(struct tsec_private *priv)
67090751910SMingkai Hu {
671063c1263SAndy Fleming 	struct phy_device *phydev;
672aec84bf6SClaudiu Manoil 	struct tsec __iomem *regs = priv->regs;
673063c1263SAndy Fleming 	u32 supported = (SUPPORTED_10baseT_Half |
674063c1263SAndy Fleming 			SUPPORTED_10baseT_Full |
675063c1263SAndy Fleming 			SUPPORTED_100baseT_Half |
676063c1263SAndy Fleming 			SUPPORTED_100baseT_Full);
677063c1263SAndy Fleming 
678063c1263SAndy Fleming 	if (priv->flags & TSEC_GIGABIT)
679063c1263SAndy Fleming 		supported |= SUPPORTED_1000baseT_Full;
68090751910SMingkai Hu 
68190751910SMingkai Hu 	/* Assign a Physical address to the TBI */
682a1c76c15SBin Meng 	out_be32(&regs->tbipa, priv->tbiaddr);
68390751910SMingkai Hu 
684063c1263SAndy Fleming 	priv->interface = tsec_get_interface(priv);
68590751910SMingkai Hu 
686063c1263SAndy Fleming 	if (priv->interface == PHY_INTERFACE_MODE_SGMII)
68790751910SMingkai Hu 		tsec_configure_serdes(priv);
68890751910SMingkai Hu 
68956a27a1eSBin Meng 	phydev = phy_connect(priv->bus, priv->phyaddr, priv->dev,
69056a27a1eSBin Meng 			     priv->interface);
6917f233c05SClaudiu Manoil 	if (!phydev)
6927f233c05SClaudiu Manoil 		return 0;
69390751910SMingkai Hu 
694063c1263SAndy Fleming 	phydev->supported &= supported;
695063c1263SAndy Fleming 	phydev->advertising = phydev->supported;
696063c1263SAndy Fleming 
697063c1263SAndy Fleming 	priv->phydev = phydev;
698063c1263SAndy Fleming 
699063c1263SAndy Fleming 	phy_config(phydev);
70090751910SMingkai Hu 
70190751910SMingkai Hu 	return 1;
70290751910SMingkai Hu }
70390751910SMingkai Hu 
7049a1d6af5SBin Meng #ifndef CONFIG_DM_ETH
7059872b736SBin Meng /*
7069872b736SBin Meng  * Initialize device structure. Returns success if PHY
70790751910SMingkai Hu  * initialization succeeded (i.e. if it recognizes the PHY)
70890751910SMingkai Hu  */
tsec_initialize(bd_t * bis,struct tsec_info_struct * tsec_info)70990751910SMingkai Hu static int tsec_initialize(bd_t *bis, struct tsec_info_struct *tsec_info)
71090751910SMingkai Hu {
71190751910SMingkai Hu 	struct eth_device *dev;
71290751910SMingkai Hu 	int i;
71390751910SMingkai Hu 	struct tsec_private *priv;
71490751910SMingkai Hu 
715d38de338SMario Six 	dev = (struct eth_device *)malloc(sizeof(*dev));
71690751910SMingkai Hu 
717d38de338SMario Six 	if (!dev)
71890751910SMingkai Hu 		return 0;
71990751910SMingkai Hu 
720d38de338SMario Six 	memset(dev, 0, sizeof(*dev));
72190751910SMingkai Hu 
72290751910SMingkai Hu 	priv = (struct tsec_private *)malloc(sizeof(*priv));
72390751910SMingkai Hu 
7245775f00eSMario Six 	if (!priv) {
7255775f00eSMario Six 		free(dev);
72690751910SMingkai Hu 		return 0;
7275775f00eSMario Six 	}
72890751910SMingkai Hu 
72990751910SMingkai Hu 	priv->regs = tsec_info->regs;
73090751910SMingkai Hu 	priv->phyregs_sgmii = tsec_info->miiregs_sgmii;
73190751910SMingkai Hu 
73290751910SMingkai Hu 	priv->phyaddr = tsec_info->phyaddr;
733a1c76c15SBin Meng 	priv->tbiaddr = CONFIG_SYS_TBIPA_VALUE;
73490751910SMingkai Hu 	priv->flags = tsec_info->flags;
73590751910SMingkai Hu 
736192bc694SBen Whitten 	strcpy(dev->name, tsec_info->devname);
737063c1263SAndy Fleming 	priv->interface = tsec_info->interface;
738063c1263SAndy Fleming 	priv->bus = miiphy_get_dev_by_name(tsec_info->mii_devname);
73956a27a1eSBin Meng 	priv->dev = dev;
74090751910SMingkai Hu 	dev->iobase = 0;
74190751910SMingkai Hu 	dev->priv = priv;
74290751910SMingkai Hu 	dev->init = tsec_init;
74390751910SMingkai Hu 	dev->halt = tsec_halt;
74490751910SMingkai Hu 	dev->send = tsec_send;
74590751910SMingkai Hu 	dev->recv = tsec_recv;
74690751910SMingkai Hu 	dev->mcast = tsec_mcast_addr;
74790751910SMingkai Hu 
7489872b736SBin Meng 	/* Tell U-Boot to get the addr from the env */
74990751910SMingkai Hu 	for (i = 0; i < 6; i++)
75090751910SMingkai Hu 		dev->enetaddr[i] = 0;
75190751910SMingkai Hu 
75290751910SMingkai Hu 	eth_register(dev);
75390751910SMingkai Hu 
75490751910SMingkai Hu 	/* Reset the MAC */
75590751910SMingkai Hu 	setbits_be32(&priv->regs->maccfg1, MACCFG1_SOFT_RESET);
75690751910SMingkai Hu 	udelay(2);  /* Soft Reset must be asserted for 3 TX clocks */
75790751910SMingkai Hu 	clrbits_be32(&priv->regs->maccfg1, MACCFG1_SOFT_RESET);
75890751910SMingkai Hu 
75990751910SMingkai Hu 	/* Try to initialize PHY here, and return */
76056a27a1eSBin Meng 	return init_phy(priv);
76190751910SMingkai Hu }
76290751910SMingkai Hu 
76390751910SMingkai Hu /*
76490751910SMingkai Hu  * Initialize all the TSEC devices
76590751910SMingkai Hu  *
76690751910SMingkai Hu  * Returns the number of TSEC devices that were initialized
76790751910SMingkai Hu  */
tsec_eth_init(bd_t * bis,struct tsec_info_struct * tsecs,int num)76890751910SMingkai Hu int tsec_eth_init(bd_t *bis, struct tsec_info_struct *tsecs, int num)
76990751910SMingkai Hu {
77090751910SMingkai Hu 	int i;
771d38de338SMario Six 	int count = 0;
77290751910SMingkai Hu 
77390751910SMingkai Hu 	for (i = 0; i < num; i++) {
774d38de338SMario Six 		int ret = tsec_initialize(bis, &tsecs[i]);
775d38de338SMario Six 
77690751910SMingkai Hu 		if (ret > 0)
77790751910SMingkai Hu 			count += ret;
77890751910SMingkai Hu 	}
77990751910SMingkai Hu 
78090751910SMingkai Hu 	return count;
78190751910SMingkai Hu }
78290751910SMingkai Hu 
tsec_standard_init(bd_t * bis)78390751910SMingkai Hu int tsec_standard_init(bd_t *bis)
78490751910SMingkai Hu {
785063c1263SAndy Fleming 	struct fsl_pq_mdio_info info;
786063c1263SAndy Fleming 
787aec84bf6SClaudiu Manoil 	info.regs = TSEC_GET_MDIO_REGS_BASE(1);
788063c1263SAndy Fleming 	info.name = DEFAULT_MII_NAME;
789063c1263SAndy Fleming 
790063c1263SAndy Fleming 	fsl_pq_mdio_init(bis, &info);
791063c1263SAndy Fleming 
79290751910SMingkai Hu 	return tsec_eth_init(bis, tsec_info, ARRAY_SIZE(tsec_info));
79390751910SMingkai Hu }
7949a1d6af5SBin Meng #else /* CONFIG_DM_ETH */
tsec_probe(struct udevice * dev)7959a1d6af5SBin Meng int tsec_probe(struct udevice *dev)
7969a1d6af5SBin Meng {
7979a1d6af5SBin Meng 	struct tsec_private *priv = dev_get_priv(dev);
7989a1d6af5SBin Meng 	struct eth_pdata *pdata = dev_get_platdata(dev);
7999a1d6af5SBin Meng 	struct fsl_pq_mdio_info mdio_info;
8001313aaf0SMario Six 	struct ofnode_phandle_args phandle_args;
8011313aaf0SMario Six 	ofnode parent;
8029a1d6af5SBin Meng 	const char *phy_mode;
8039a1d6af5SBin Meng 	int ret;
8049a1d6af5SBin Meng 
8051313aaf0SMario Six 	pdata->iobase = (phys_addr_t)dev_read_addr(dev);
8069a1d6af5SBin Meng 	priv->regs = (struct tsec *)pdata->iobase;
8079a1d6af5SBin Meng 
8081313aaf0SMario Six 	if (dev_read_phandle_with_args(dev, "phy-handle", NULL, 0, 0,
8091313aaf0SMario Six 				       &phandle_args)) {
8109a1d6af5SBin Meng 		debug("phy-handle does not exist under tsec %s\n", dev->name);
8119a1d6af5SBin Meng 		return -ENOENT;
8121313aaf0SMario Six 	} else {
8131313aaf0SMario Six 		int reg = ofnode_read_u32_default(phandle_args.node, "reg", 0);
8141313aaf0SMario Six 
8151313aaf0SMario Six 		priv->phyaddr = reg;
8169a1d6af5SBin Meng 	}
8179a1d6af5SBin Meng 
8181313aaf0SMario Six 	parent = ofnode_get_parent(phandle_args.node);
8191313aaf0SMario Six 	if (ofnode_valid(parent)) {
8205e9d9abeSMario Six 		int reg = ofnode_get_addr_index(parent, 0);
8215e9d9abeSMario Six 
8225e9d9abeSMario Six 		priv->phyregs_sgmii = (struct tsec_mii_mng *)reg;
8239a1d6af5SBin Meng 	} else {
8249a1d6af5SBin Meng 		debug("No parent node for PHY?\n");
8259a1d6af5SBin Meng 		return -ENOENT;
8269a1d6af5SBin Meng 	}
8279a1d6af5SBin Meng 
8281313aaf0SMario Six 	if (dev_read_phandle_with_args(dev, "tbi-handle", NULL, 0, 0,
8291313aaf0SMario Six 				       &phandle_args)) {
8301313aaf0SMario Six 		priv->tbiaddr = CONFIG_SYS_TBIPA_VALUE;
8311313aaf0SMario Six 	} else {
8321313aaf0SMario Six 		int reg = ofnode_read_u32_default(phandle_args.node, "reg",
833a1c76c15SBin Meng 						  CONFIG_SYS_TBIPA_VALUE);
834a1c76c15SBin Meng 		priv->tbiaddr = reg;
835a1c76c15SBin Meng 	}
836a1c76c15SBin Meng 
8371313aaf0SMario Six 	phy_mode = dev_read_prop(dev, "phy-connection-type", NULL);
8389a1d6af5SBin Meng 	if (phy_mode)
8399a1d6af5SBin Meng 		pdata->phy_interface = phy_get_interface_by_name(phy_mode);
8409a1d6af5SBin Meng 	if (pdata->phy_interface == -1) {
8419a1d6af5SBin Meng 		debug("Invalid PHY interface '%s'\n", phy_mode);
8429a1d6af5SBin Meng 		return -EINVAL;
8439a1d6af5SBin Meng 	}
8449a1d6af5SBin Meng 	priv->interface = pdata->phy_interface;
8459a1d6af5SBin Meng 
8469a1d6af5SBin Meng 	/* Initialize flags */
8479a1d6af5SBin Meng 	priv->flags = TSEC_GIGABIT;
8489a1d6af5SBin Meng 	if (priv->interface == PHY_INTERFACE_MODE_SGMII)
8499a1d6af5SBin Meng 		priv->flags |= TSEC_SGMII;
8509a1d6af5SBin Meng 
8519a1d6af5SBin Meng 	mdio_info.regs = priv->phyregs_sgmii;
8529a1d6af5SBin Meng 	mdio_info.name = (char *)dev->name;
8539a1d6af5SBin Meng 	ret = fsl_pq_mdio_init(NULL, &mdio_info);
8549a1d6af5SBin Meng 	if (ret)
8559a1d6af5SBin Meng 		return ret;
8569a1d6af5SBin Meng 
8579a1d6af5SBin Meng 	/* Reset the MAC */
8589a1d6af5SBin Meng 	setbits_be32(&priv->regs->maccfg1, MACCFG1_SOFT_RESET);
8599a1d6af5SBin Meng 	udelay(2);  /* Soft Reset must be asserted for 3 TX clocks */
8609a1d6af5SBin Meng 	clrbits_be32(&priv->regs->maccfg1, MACCFG1_SOFT_RESET);
8619a1d6af5SBin Meng 
8629a1d6af5SBin Meng 	priv->dev = dev;
8639a1d6af5SBin Meng 	priv->bus = miiphy_get_dev_by_name(dev->name);
8649a1d6af5SBin Meng 
8659a1d6af5SBin Meng 	/* Try to initialize PHY here, and return */
8669a1d6af5SBin Meng 	return !init_phy(priv);
8679a1d6af5SBin Meng }
8689a1d6af5SBin Meng 
tsec_remove(struct udevice * dev)8699a1d6af5SBin Meng int tsec_remove(struct udevice *dev)
8709a1d6af5SBin Meng {
8719a1d6af5SBin Meng 	struct tsec_private *priv = dev->priv;
8729a1d6af5SBin Meng 
8739a1d6af5SBin Meng 	free(priv->phydev);
8749a1d6af5SBin Meng 	mdio_unregister(priv->bus);
8759a1d6af5SBin Meng 	mdio_free(priv->bus);
8769a1d6af5SBin Meng 
8779a1d6af5SBin Meng 	return 0;
8789a1d6af5SBin Meng }
8799a1d6af5SBin Meng 
8809a1d6af5SBin Meng static const struct eth_ops tsec_ops = {
8819a1d6af5SBin Meng 	.start = tsec_init,
8829a1d6af5SBin Meng 	.send = tsec_send,
8839a1d6af5SBin Meng 	.recv = tsec_recv,
8849a1d6af5SBin Meng 	.free_pkt = tsec_free_pkt,
8859a1d6af5SBin Meng 	.stop = tsec_halt,
8869a1d6af5SBin Meng 	.mcast = tsec_mcast_addr,
8879a1d6af5SBin Meng };
8889a1d6af5SBin Meng 
8899a1d6af5SBin Meng static const struct udevice_id tsec_ids[] = {
8909a1d6af5SBin Meng 	{ .compatible = "fsl,tsec" },
8919a1d6af5SBin Meng 	{ }
8929a1d6af5SBin Meng };
8939a1d6af5SBin Meng 
8949a1d6af5SBin Meng U_BOOT_DRIVER(eth_tsec) = {
8959a1d6af5SBin Meng 	.name = "tsec",
8969a1d6af5SBin Meng 	.id = UCLASS_ETH,
8979a1d6af5SBin Meng 	.of_match = tsec_ids,
8989a1d6af5SBin Meng 	.probe = tsec_probe,
8999a1d6af5SBin Meng 	.remove = tsec_remove,
9009a1d6af5SBin Meng 	.ops = &tsec_ops,
9019a1d6af5SBin Meng 	.priv_auto_alloc_size = sizeof(struct tsec_private),
9029a1d6af5SBin Meng 	.platdata_auto_alloc_size = sizeof(struct eth_pdata),
9039a1d6af5SBin Meng 	.flags = DM_FLAG_ALLOC_PRIV_DMA,
9049a1d6af5SBin Meng };
9059a1d6af5SBin Meng #endif /* CONFIG_DM_ETH */
906