12439e4bfSJean-Christophe PLAGNIOL-VILLARD /*
22439e4bfSJean-Christophe PLAGNIOL-VILLARD * Freescale Three Speed Ethernet Controller driver
32439e4bfSJean-Christophe PLAGNIOL-VILLARD *
4aec84bf6SClaudiu Manoil * Copyright 2004-2011, 2013 Freescale Semiconductor, Inc.
52439e4bfSJean-Christophe PLAGNIOL-VILLARD * (C) Copyright 2003, Motorola, Inc.
62439e4bfSJean-Christophe PLAGNIOL-VILLARD * author Andy Fleming
72439e4bfSJean-Christophe PLAGNIOL-VILLARD *
89872b736SBin Meng * SPDX-License-Identifier: GPL-2.0+
92439e4bfSJean-Christophe PLAGNIOL-VILLARD */
102439e4bfSJean-Christophe PLAGNIOL-VILLARD
112439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <config.h>
122439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <common.h>
139a1d6af5SBin Meng #include <dm.h>
142439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <malloc.h>
152439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <net.h>
162439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <command.h>
17dd3d1f56SAndy Fleming #include <tsec.h>
18063c1263SAndy Fleming #include <fsl_mdio.h>
191221ce45SMasahiro Yamada #include <linux/errno.h>
20aada81deSchenhui zhao #include <asm/processor.h>
2152d00a81SAlison Wang #include <asm/io.h>
222439e4bfSJean-Christophe PLAGNIOL-VILLARD
232439e4bfSJean-Christophe PLAGNIOL-VILLARD DECLARE_GLOBAL_DATA_PTR;
242439e4bfSJean-Christophe PLAGNIOL-VILLARD
259a1d6af5SBin Meng #ifndef CONFIG_DM_ETH
2675b9d4aeSAndy Fleming /* Default initializations for TSEC controllers. */
2775b9d4aeSAndy Fleming
2875b9d4aeSAndy Fleming static struct tsec_info_struct tsec_info[] = {
2975b9d4aeSAndy Fleming #ifdef CONFIG_TSEC1
3075b9d4aeSAndy Fleming STD_TSEC_INFO(1), /* TSEC1 */
3175b9d4aeSAndy Fleming #endif
3275b9d4aeSAndy Fleming #ifdef CONFIG_TSEC2
3375b9d4aeSAndy Fleming STD_TSEC_INFO(2), /* TSEC2 */
3475b9d4aeSAndy Fleming #endif
3575b9d4aeSAndy Fleming #ifdef CONFIG_MPC85XX_FEC
3675b9d4aeSAndy Fleming {
37aec84bf6SClaudiu Manoil .regs = TSEC_GET_REGS(2, 0x2000),
3875b9d4aeSAndy Fleming .devname = CONFIG_MPC85XX_FEC_NAME,
3975b9d4aeSAndy Fleming .phyaddr = FEC_PHY_ADDR,
40063c1263SAndy Fleming .flags = FEC_FLAGS,
41063c1263SAndy Fleming .mii_devname = DEFAULT_MII_NAME
4275b9d4aeSAndy Fleming }, /* FEC */
4375b9d4aeSAndy Fleming #endif
4475b9d4aeSAndy Fleming #ifdef CONFIG_TSEC3
4575b9d4aeSAndy Fleming STD_TSEC_INFO(3), /* TSEC3 */
4675b9d4aeSAndy Fleming #endif
4775b9d4aeSAndy Fleming #ifdef CONFIG_TSEC4
4875b9d4aeSAndy Fleming STD_TSEC_INFO(4), /* TSEC4 */
4975b9d4aeSAndy Fleming #endif
5075b9d4aeSAndy Fleming };
519a1d6af5SBin Meng #endif /* CONFIG_DM_ETH */
5275b9d4aeSAndy Fleming
532abe361cSAndy Fleming #define TBIANA_SETTINGS ( \
542abe361cSAndy Fleming TBIANA_ASYMMETRIC_PAUSE \
552abe361cSAndy Fleming | TBIANA_SYMMETRIC_PAUSE \
562abe361cSAndy Fleming | TBIANA_FULL_DUPLEX \
572abe361cSAndy Fleming )
582abe361cSAndy Fleming
5990b5bf21SFelix Radensky /* By default force the TBI PHY into 1000Mbps full duplex when in SGMII mode */
6090b5bf21SFelix Radensky #ifndef CONFIG_TSEC_TBICR_SETTINGS
6172c96a68SKumar Gala #define CONFIG_TSEC_TBICR_SETTINGS ( \
622abe361cSAndy Fleming TBICR_PHY_RESET \
6372c96a68SKumar Gala | TBICR_ANEG_ENABLE \
642abe361cSAndy Fleming | TBICR_FULL_DUPLEX \
652abe361cSAndy Fleming | TBICR_SPEED1_SET \
662abe361cSAndy Fleming )
6790b5bf21SFelix Radensky #endif /* CONFIG_TSEC_TBICR_SETTINGS */
6846e91674SPeter Tyser
692abe361cSAndy Fleming /* Configure the TBI for SGMII operation */
tsec_configure_serdes(struct tsec_private * priv)702abe361cSAndy Fleming static void tsec_configure_serdes(struct tsec_private *priv)
712abe361cSAndy Fleming {
729872b736SBin Meng /*
739872b736SBin Meng * Access TBI PHY registers at given TSEC register offset as opposed
749872b736SBin Meng * to the register offset used for external PHY accesses
759872b736SBin Meng */
76063c1263SAndy Fleming tsec_local_mdio_write(priv->phyregs_sgmii, in_be32(&priv->regs->tbipa),
77063c1263SAndy Fleming 0, TBI_ANA, TBIANA_SETTINGS);
78063c1263SAndy Fleming tsec_local_mdio_write(priv->phyregs_sgmii, in_be32(&priv->regs->tbipa),
79063c1263SAndy Fleming 0, TBI_TBICON, TBICON_CLK_SELECT);
80063c1263SAndy Fleming tsec_local_mdio_write(priv->phyregs_sgmii, in_be32(&priv->regs->tbipa),
81063c1263SAndy Fleming 0, TBI_CR, CONFIG_TSEC_TBICR_SETTINGS);
822439e4bfSJean-Christophe PLAGNIOL-VILLARD }
832439e4bfSJean-Christophe PLAGNIOL-VILLARD
842439e4bfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_MCAST_TFTP
852439e4bfSJean-Christophe PLAGNIOL-VILLARD
862439e4bfSJean-Christophe PLAGNIOL-VILLARD /* CREDITS: linux gianfar driver, slightly adjusted... thanx. */
872439e4bfSJean-Christophe PLAGNIOL-VILLARD
882439e4bfSJean-Christophe PLAGNIOL-VILLARD /* Set the appropriate hash bit for the given addr */
892439e4bfSJean-Christophe PLAGNIOL-VILLARD
909872b736SBin Meng /*
919872b736SBin Meng * The algorithm works like so:
922439e4bfSJean-Christophe PLAGNIOL-VILLARD * 1) Take the Destination Address (ie the multicast address), and
932439e4bfSJean-Christophe PLAGNIOL-VILLARD * do a CRC on it (little endian), and reverse the bits of the
942439e4bfSJean-Christophe PLAGNIOL-VILLARD * result.
952439e4bfSJean-Christophe PLAGNIOL-VILLARD * 2) Use the 8 most significant bits as a hash into a 256-entry
962439e4bfSJean-Christophe PLAGNIOL-VILLARD * table. The table is controlled through 8 32-bit registers:
97876d4515SClaudiu Manoil * gaddr0-7. gaddr0's MSB is entry 0, and gaddr7's LSB is entry
98876d4515SClaudiu Manoil * 255. This means that the 3 most significant bits in the
992439e4bfSJean-Christophe PLAGNIOL-VILLARD * hash index which gaddr register to use, and the 5 other bits
1002439e4bfSJean-Christophe PLAGNIOL-VILLARD * indicate which bit (assuming an IBM numbering scheme, which
101876d4515SClaudiu Manoil * for PowerPC (tm) is usually the case) in the register holds
1029872b736SBin Meng * the entry.
1039872b736SBin Meng */
1049a1d6af5SBin Meng #ifndef CONFIG_DM_ETH
tsec_mcast_addr(struct eth_device * dev,const u8 * mcast_mac,u8 set)1059872b736SBin Meng static int tsec_mcast_addr(struct eth_device *dev, const u8 *mcast_mac, u8 set)
1069a1d6af5SBin Meng #else
1079a1d6af5SBin Meng static int tsec_mcast_addr(struct udevice *dev, const u8 *mcast_mac, int set)
1089a1d6af5SBin Meng #endif
1092439e4bfSJean-Christophe PLAGNIOL-VILLARD {
110b200204eSClaudiu Manoil struct tsec_private *priv = (struct tsec_private *)dev->priv;
111876d4515SClaudiu Manoil struct tsec __iomem *regs = priv->regs;
112876d4515SClaudiu Manoil u32 result, value;
113876d4515SClaudiu Manoil u8 whichbit, whichreg;
1142439e4bfSJean-Christophe PLAGNIOL-VILLARD
115876d4515SClaudiu Manoil result = ether_crc(MAC_ADDR_LEN, mcast_mac);
116876d4515SClaudiu Manoil whichbit = (result >> 24) & 0x1f; /* the 5 LSB = which bit to set */
117876d4515SClaudiu Manoil whichreg = result >> 29; /* the 3 MSB = which reg to set it in */
1182439e4bfSJean-Christophe PLAGNIOL-VILLARD
119876d4515SClaudiu Manoil value = 1 << (31-whichbit);
1202439e4bfSJean-Christophe PLAGNIOL-VILLARD
121876d4515SClaudiu Manoil if (set)
122876d4515SClaudiu Manoil setbits_be32(®s->hash.gaddr0 + whichreg, value);
123876d4515SClaudiu Manoil else
124876d4515SClaudiu Manoil clrbits_be32(®s->hash.gaddr0 + whichreg, value);
125876d4515SClaudiu Manoil
1262439e4bfSJean-Christophe PLAGNIOL-VILLARD return 0;
1272439e4bfSJean-Christophe PLAGNIOL-VILLARD }
1282439e4bfSJean-Christophe PLAGNIOL-VILLARD #endif /* Multicast TFTP ? */
12990751910SMingkai Hu
1309872b736SBin Meng /*
1319872b736SBin Meng * Initialized required registers to appropriate values, zeroing
13290751910SMingkai Hu * those we don't care about (unless zero is bad, in which case,
13390751910SMingkai Hu * choose a more appropriate value)
13490751910SMingkai Hu */
init_registers(struct tsec __iomem * regs)135aec84bf6SClaudiu Manoil static void init_registers(struct tsec __iomem *regs)
13690751910SMingkai Hu {
13790751910SMingkai Hu /* Clear IEVENT */
13890751910SMingkai Hu out_be32(®s->ievent, IEVENT_INIT_CLEAR);
13990751910SMingkai Hu
14090751910SMingkai Hu out_be32(®s->imask, IMASK_INIT_CLEAR);
14190751910SMingkai Hu
14290751910SMingkai Hu out_be32(®s->hash.iaddr0, 0);
14390751910SMingkai Hu out_be32(®s->hash.iaddr1, 0);
14490751910SMingkai Hu out_be32(®s->hash.iaddr2, 0);
14590751910SMingkai Hu out_be32(®s->hash.iaddr3, 0);
14690751910SMingkai Hu out_be32(®s->hash.iaddr4, 0);
14790751910SMingkai Hu out_be32(®s->hash.iaddr5, 0);
14890751910SMingkai Hu out_be32(®s->hash.iaddr6, 0);
14990751910SMingkai Hu out_be32(®s->hash.iaddr7, 0);
15090751910SMingkai Hu
15190751910SMingkai Hu out_be32(®s->hash.gaddr0, 0);
15290751910SMingkai Hu out_be32(®s->hash.gaddr1, 0);
15390751910SMingkai Hu out_be32(®s->hash.gaddr2, 0);
15490751910SMingkai Hu out_be32(®s->hash.gaddr3, 0);
15590751910SMingkai Hu out_be32(®s->hash.gaddr4, 0);
15690751910SMingkai Hu out_be32(®s->hash.gaddr5, 0);
15790751910SMingkai Hu out_be32(®s->hash.gaddr6, 0);
15890751910SMingkai Hu out_be32(®s->hash.gaddr7, 0);
15990751910SMingkai Hu
16090751910SMingkai Hu out_be32(®s->rctrl, 0x00000000);
16190751910SMingkai Hu
16290751910SMingkai Hu /* Init RMON mib registers */
16382ef75caSClaudiu Manoil memset((void *)®s->rmon, 0, sizeof(regs->rmon));
16490751910SMingkai Hu
16590751910SMingkai Hu out_be32(®s->rmon.cam1, 0xffffffff);
16690751910SMingkai Hu out_be32(®s->rmon.cam2, 0xffffffff);
16790751910SMingkai Hu
16890751910SMingkai Hu out_be32(®s->mrblr, MRBLR_INIT_SETTINGS);
16990751910SMingkai Hu
17090751910SMingkai Hu out_be32(®s->minflr, MINFLR_INIT_SETTINGS);
17190751910SMingkai Hu
17290751910SMingkai Hu out_be32(®s->attr, ATTR_INIT_SETTINGS);
17390751910SMingkai Hu out_be32(®s->attreli, ATTRELI_INIT_SETTINGS);
17490751910SMingkai Hu
17590751910SMingkai Hu }
17690751910SMingkai Hu
1779872b736SBin Meng /*
1789872b736SBin Meng * Configure maccfg2 based on negotiated speed and duplex
17990751910SMingkai Hu * reported by PHY handling code
18090751910SMingkai Hu */
adjust_link(struct tsec_private * priv,struct phy_device * phydev)181063c1263SAndy Fleming static void adjust_link(struct tsec_private *priv, struct phy_device *phydev)
18290751910SMingkai Hu {
183aec84bf6SClaudiu Manoil struct tsec __iomem *regs = priv->regs;
18490751910SMingkai Hu u32 ecntrl, maccfg2;
18590751910SMingkai Hu
186063c1263SAndy Fleming if (!phydev->link) {
187063c1263SAndy Fleming printf("%s: No link.\n", phydev->dev->name);
18890751910SMingkai Hu return;
18990751910SMingkai Hu }
19090751910SMingkai Hu
19190751910SMingkai Hu /* clear all bits relative with interface mode */
19290751910SMingkai Hu ecntrl = in_be32(®s->ecntrl);
19390751910SMingkai Hu ecntrl &= ~ECNTRL_R100;
19490751910SMingkai Hu
19590751910SMingkai Hu maccfg2 = in_be32(®s->maccfg2);
19690751910SMingkai Hu maccfg2 &= ~(MACCFG2_IF | MACCFG2_FULL_DUPLEX);
19790751910SMingkai Hu
198063c1263SAndy Fleming if (phydev->duplex)
19990751910SMingkai Hu maccfg2 |= MACCFG2_FULL_DUPLEX;
20090751910SMingkai Hu
201063c1263SAndy Fleming switch (phydev->speed) {
20290751910SMingkai Hu case 1000:
20390751910SMingkai Hu maccfg2 |= MACCFG2_GMII;
20490751910SMingkai Hu break;
20590751910SMingkai Hu case 100:
20690751910SMingkai Hu case 10:
20790751910SMingkai Hu maccfg2 |= MACCFG2_MII;
20890751910SMingkai Hu
2099872b736SBin Meng /*
2109872b736SBin Meng * Set R100 bit in all modes although
21190751910SMingkai Hu * it is only used in RGMII mode
21290751910SMingkai Hu */
213063c1263SAndy Fleming if (phydev->speed == 100)
21490751910SMingkai Hu ecntrl |= ECNTRL_R100;
21590751910SMingkai Hu break;
21690751910SMingkai Hu default:
217063c1263SAndy Fleming printf("%s: Speed was bad\n", phydev->dev->name);
21890751910SMingkai Hu break;
21990751910SMingkai Hu }
22090751910SMingkai Hu
22190751910SMingkai Hu out_be32(®s->ecntrl, ecntrl);
22290751910SMingkai Hu out_be32(®s->maccfg2, maccfg2);
22390751910SMingkai Hu
224063c1263SAndy Fleming printf("Speed: %d, %s duplex%s\n", phydev->speed,
225063c1263SAndy Fleming (phydev->duplex) ? "full" : "half",
226063c1263SAndy Fleming (phydev->port == PORT_FIBRE) ? ", fiber mode" : "");
22790751910SMingkai Hu }
22890751910SMingkai Hu
2298ba50176SBin Meng /*
2308ba50176SBin Meng * This returns the status bits of the device. The return value
2318ba50176SBin Meng * is never checked, and this is what the 8260 driver did, so we
2328ba50176SBin Meng * do the same. Presumably, this would be zero if there were no
2338ba50176SBin Meng * errors
2348ba50176SBin Meng */
2359a1d6af5SBin Meng #ifndef CONFIG_DM_ETH
tsec_send(struct eth_device * dev,void * packet,int length)2368ba50176SBin Meng static int tsec_send(struct eth_device *dev, void *packet, int length)
2379a1d6af5SBin Meng #else
2389a1d6af5SBin Meng static int tsec_send(struct udevice *dev, void *packet, int length)
2399a1d6af5SBin Meng #endif
2408ba50176SBin Meng {
2418ba50176SBin Meng struct tsec_private *priv = (struct tsec_private *)dev->priv;
2428ba50176SBin Meng struct tsec __iomem *regs = priv->regs;
2438ba50176SBin Meng uint16_t status;
2448ba50176SBin Meng int result = 0;
2458ba50176SBin Meng int i;
2468ba50176SBin Meng
2478ba50176SBin Meng /* Find an empty buffer descriptor */
2488ba50176SBin Meng for (i = 0;
2498ba50176SBin Meng in_be16(&priv->txbd[priv->tx_idx].status) & TXBD_READY;
2508ba50176SBin Meng i++) {
2518ba50176SBin Meng if (i >= TOUT_LOOP) {
2528ba50176SBin Meng debug("%s: tsec: tx buffers full\n", dev->name);
2538ba50176SBin Meng return result;
2548ba50176SBin Meng }
2558ba50176SBin Meng }
2568ba50176SBin Meng
2578ba50176SBin Meng out_be32(&priv->txbd[priv->tx_idx].bufptr, (u32)packet);
2588ba50176SBin Meng out_be16(&priv->txbd[priv->tx_idx].length, length);
2598ba50176SBin Meng status = in_be16(&priv->txbd[priv->tx_idx].status);
2608ba50176SBin Meng out_be16(&priv->txbd[priv->tx_idx].status, status |
2618ba50176SBin Meng (TXBD_READY | TXBD_LAST | TXBD_CRC | TXBD_INTERRUPT));
2628ba50176SBin Meng
2638ba50176SBin Meng /* Tell the DMA to go */
2648ba50176SBin Meng out_be32(®s->tstat, TSTAT_CLEAR_THALT);
2658ba50176SBin Meng
2668ba50176SBin Meng /* Wait for buffer to be transmitted */
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 error\n", dev->name);
2728ba50176SBin Meng return result;
2738ba50176SBin Meng }
2748ba50176SBin Meng }
2758ba50176SBin Meng
2768ba50176SBin Meng priv->tx_idx = (priv->tx_idx + 1) % TX_BUF_CNT;
2778ba50176SBin Meng result = in_be16(&priv->txbd[priv->tx_idx].status) & TXBD_STATS;
2788ba50176SBin Meng
2798ba50176SBin Meng return result;
2808ba50176SBin Meng }
2818ba50176SBin Meng
2829a1d6af5SBin Meng #ifndef CONFIG_DM_ETH
tsec_recv(struct eth_device * dev)2838ba50176SBin Meng static int tsec_recv(struct eth_device *dev)
2848ba50176SBin Meng {
2858ba50176SBin Meng struct tsec_private *priv = (struct tsec_private *)dev->priv;
2868ba50176SBin Meng struct tsec __iomem *regs = priv->regs;
2878ba50176SBin Meng
2888ba50176SBin Meng while (!(in_be16(&priv->rxbd[priv->rx_idx].status) & RXBD_EMPTY)) {
2898ba50176SBin Meng int length = in_be16(&priv->rxbd[priv->rx_idx].length);
2908ba50176SBin Meng uint16_t status = in_be16(&priv->rxbd[priv->rx_idx].status);
2918ba50176SBin Meng uchar *packet = net_rx_packets[priv->rx_idx];
2928ba50176SBin Meng
2938ba50176SBin Meng /* Send the packet up if there were no errors */
2948ba50176SBin Meng if (!(status & RXBD_STATS))
2958ba50176SBin Meng net_process_received_packet(packet, length - 4);
2968ba50176SBin Meng else
2978ba50176SBin Meng printf("Got error %x\n", (status & RXBD_STATS));
2988ba50176SBin Meng
2998ba50176SBin Meng out_be16(&priv->rxbd[priv->rx_idx].length, 0);
3008ba50176SBin Meng
3018ba50176SBin Meng status = RXBD_EMPTY;
3028ba50176SBin Meng /* Set the wrap bit if this is the last element in the list */
3038ba50176SBin Meng if ((priv->rx_idx + 1) == PKTBUFSRX)
3048ba50176SBin Meng status |= RXBD_WRAP;
3058ba50176SBin Meng out_be16(&priv->rxbd[priv->rx_idx].status, status);
3068ba50176SBin Meng
3078ba50176SBin Meng priv->rx_idx = (priv->rx_idx + 1) % PKTBUFSRX;
3088ba50176SBin Meng }
3098ba50176SBin Meng
3108ba50176SBin Meng if (in_be32(®s->ievent) & IEVENT_BSY) {
3118ba50176SBin Meng out_be32(®s->ievent, IEVENT_BSY);
3128ba50176SBin Meng out_be32(®s->rstat, RSTAT_CLEAR_RHALT);
3138ba50176SBin Meng }
3148ba50176SBin Meng
3158ba50176SBin Meng return -1;
3168ba50176SBin Meng }
3179a1d6af5SBin Meng #else
tsec_recv(struct udevice * dev,int flags,uchar ** packetp)3189a1d6af5SBin Meng static int tsec_recv(struct udevice *dev, int flags, uchar **packetp)
3199a1d6af5SBin Meng {
3209a1d6af5SBin Meng struct tsec_private *priv = (struct tsec_private *)dev->priv;
3219a1d6af5SBin Meng struct tsec __iomem *regs = priv->regs;
3229a1d6af5SBin Meng int ret = -1;
3239a1d6af5SBin Meng
3249a1d6af5SBin Meng if (!(in_be16(&priv->rxbd[priv->rx_idx].status) & RXBD_EMPTY)) {
3259a1d6af5SBin Meng int length = in_be16(&priv->rxbd[priv->rx_idx].length);
3269a1d6af5SBin Meng uint16_t status = in_be16(&priv->rxbd[priv->rx_idx].status);
3279a1d6af5SBin Meng uint32_t buf;
3289a1d6af5SBin Meng
3299a1d6af5SBin Meng /* Send the packet up if there were no errors */
3309a1d6af5SBin Meng if (!(status & RXBD_STATS)) {
3319a1d6af5SBin Meng buf = in_be32(&priv->rxbd[priv->rx_idx].bufptr);
3329a1d6af5SBin Meng *packetp = (uchar *)buf;
3339a1d6af5SBin Meng ret = length - 4;
3349a1d6af5SBin Meng } else {
3359a1d6af5SBin Meng printf("Got error %x\n", (status & RXBD_STATS));
3369a1d6af5SBin Meng }
3379a1d6af5SBin Meng }
3389a1d6af5SBin Meng
3399a1d6af5SBin Meng if (in_be32(®s->ievent) & IEVENT_BSY) {
3409a1d6af5SBin Meng out_be32(®s->ievent, IEVENT_BSY);
3419a1d6af5SBin Meng out_be32(®s->rstat, RSTAT_CLEAR_RHALT);
3429a1d6af5SBin Meng }
3439a1d6af5SBin Meng
3449a1d6af5SBin Meng return ret;
3459a1d6af5SBin Meng }
3469a1d6af5SBin Meng
tsec_free_pkt(struct udevice * dev,uchar * packet,int length)3479a1d6af5SBin Meng static int tsec_free_pkt(struct udevice *dev, uchar *packet, int length)
3489a1d6af5SBin Meng {
3499a1d6af5SBin Meng struct tsec_private *priv = (struct tsec_private *)dev->priv;
3509a1d6af5SBin Meng uint16_t status;
3519a1d6af5SBin Meng
3529a1d6af5SBin Meng out_be16(&priv->rxbd[priv->rx_idx].length, 0);
3539a1d6af5SBin Meng
3549a1d6af5SBin Meng status = RXBD_EMPTY;
3559a1d6af5SBin Meng /* Set the wrap bit if this is the last element in the list */
3569a1d6af5SBin Meng if ((priv->rx_idx + 1) == PKTBUFSRX)
3579a1d6af5SBin Meng status |= RXBD_WRAP;
3589a1d6af5SBin Meng out_be16(&priv->rxbd[priv->rx_idx].status, status);
3599a1d6af5SBin Meng
3609a1d6af5SBin Meng priv->rx_idx = (priv->rx_idx + 1) % PKTBUFSRX;
3619a1d6af5SBin Meng
3629a1d6af5SBin Meng return 0;
3639a1d6af5SBin Meng }
3649a1d6af5SBin Meng #endif
3658ba50176SBin Meng
3668ba50176SBin Meng /* Stop the interface */
3679a1d6af5SBin Meng #ifndef CONFIG_DM_ETH
tsec_halt(struct eth_device * dev)3688ba50176SBin Meng static void tsec_halt(struct eth_device *dev)
3699a1d6af5SBin Meng #else
3709a1d6af5SBin Meng static void tsec_halt(struct udevice *dev)
3719a1d6af5SBin Meng #endif
3728ba50176SBin Meng {
3738ba50176SBin Meng struct tsec_private *priv = (struct tsec_private *)dev->priv;
3748ba50176SBin Meng struct tsec __iomem *regs = priv->regs;
3758ba50176SBin Meng
3768ba50176SBin Meng clrbits_be32(®s->dmactrl, DMACTRL_GRS | DMACTRL_GTS);
3778ba50176SBin Meng setbits_be32(®s->dmactrl, DMACTRL_GRS | DMACTRL_GTS);
3788ba50176SBin Meng
3798ba50176SBin Meng while ((in_be32(®s->ievent) & (IEVENT_GRSC | IEVENT_GTSC))
3808ba50176SBin Meng != (IEVENT_GRSC | IEVENT_GTSC))
3818ba50176SBin Meng ;
3828ba50176SBin Meng
3838ba50176SBin Meng clrbits_be32(®s->maccfg1, MACCFG1_TX_EN | MACCFG1_RX_EN);
3848ba50176SBin Meng
3858ba50176SBin Meng /* Shut down the PHY, as needed */
3868ba50176SBin Meng phy_shutdown(priv->phydev);
3878ba50176SBin Meng }
3888ba50176SBin Meng
389aada81deSchenhui zhao #ifdef CONFIG_SYS_FSL_ERRATUM_NMG_ETSEC129
390aada81deSchenhui zhao /*
391aada81deSchenhui zhao * When MACCFG1[Rx_EN] is enabled during system boot as part
392aada81deSchenhui zhao * of the eTSEC port initialization sequence,
393aada81deSchenhui zhao * the eTSEC Rx logic may not be properly initialized.
394aada81deSchenhui zhao */
redundant_init(struct tsec_private * priv)39556a27a1eSBin Meng void redundant_init(struct tsec_private *priv)
396aada81deSchenhui zhao {
397aec84bf6SClaudiu Manoil struct tsec __iomem *regs = priv->regs;
398aada81deSchenhui zhao uint t, count = 0;
399aada81deSchenhui zhao int fail = 1;
400aada81deSchenhui zhao static const u8 pkt[] = {
401aada81deSchenhui zhao 0x00, 0x1e, 0x4f, 0x12, 0xcb, 0x2c, 0x00, 0x25,
402aada81deSchenhui zhao 0x64, 0xbb, 0xd1, 0xab, 0x08, 0x00, 0x45, 0x00,
403aada81deSchenhui zhao 0x00, 0x5c, 0xdd, 0x22, 0x00, 0x00, 0x80, 0x01,
404aada81deSchenhui zhao 0x1f, 0x71, 0x0a, 0xc1, 0x14, 0x22, 0x0a, 0xc1,
405aada81deSchenhui zhao 0x14, 0x6a, 0x08, 0x00, 0xef, 0x7e, 0x02, 0x00,
406aada81deSchenhui zhao 0x94, 0x05, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
407aada81deSchenhui zhao 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e,
408aada81deSchenhui zhao 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76,
409aada81deSchenhui zhao 0x77, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
410aada81deSchenhui zhao 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
411aada81deSchenhui zhao 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
412aada81deSchenhui zhao 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
413aada81deSchenhui zhao 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70,
414aada81deSchenhui zhao 0x71, 0x72};
415aada81deSchenhui zhao
416aada81deSchenhui zhao /* Enable promiscuous mode */
417aada81deSchenhui zhao setbits_be32(®s->rctrl, 0x8);
418aada81deSchenhui zhao /* Enable loopback mode */
419aada81deSchenhui zhao setbits_be32(®s->maccfg1, MACCFG1_LOOPBACK);
420aada81deSchenhui zhao /* Enable transmit and receive */
421aada81deSchenhui zhao setbits_be32(®s->maccfg1, MACCFG1_RX_EN | MACCFG1_TX_EN);
422aada81deSchenhui zhao
423aada81deSchenhui zhao /* Tell the DMA it is clear to go */
424aada81deSchenhui zhao setbits_be32(®s->dmactrl, DMACTRL_INIT_SETTINGS);
425aada81deSchenhui zhao out_be32(®s->tstat, TSTAT_CLEAR_THALT);
426aada81deSchenhui zhao out_be32(®s->rstat, RSTAT_CLEAR_RHALT);
427aada81deSchenhui zhao clrbits_be32(®s->dmactrl, DMACTRL_GRS | DMACTRL_GTS);
428aada81deSchenhui zhao
429aada81deSchenhui zhao do {
4309c9141fdSClaudiu Manoil uint16_t status;
43156a27a1eSBin Meng tsec_send(priv->dev, (void *)pkt, sizeof(pkt));
432aada81deSchenhui zhao
433aada81deSchenhui zhao /* Wait for buffer to be received */
434e677da97SBin Meng for (t = 0;
435e677da97SBin Meng in_be16(&priv->rxbd[priv->rx_idx].status) & RXBD_EMPTY;
436362b123fSBin Meng t++) {
437aada81deSchenhui zhao if (t >= 10 * TOUT_LOOP) {
43856a27a1eSBin Meng printf("%s: tsec: rx error\n", priv->dev->name);
439aada81deSchenhui zhao break;
440aada81deSchenhui zhao }
441aada81deSchenhui zhao }
442aada81deSchenhui zhao
443362b123fSBin Meng if (!memcmp(pkt, net_rx_packets[priv->rx_idx], sizeof(pkt)))
444aada81deSchenhui zhao fail = 0;
445aada81deSchenhui zhao
446e677da97SBin Meng out_be16(&priv->rxbd[priv->rx_idx].length, 0);
4479c9141fdSClaudiu Manoil status = RXBD_EMPTY;
448362b123fSBin Meng if ((priv->rx_idx + 1) == PKTBUFSRX)
4499c9141fdSClaudiu Manoil status |= RXBD_WRAP;
450e677da97SBin Meng out_be16(&priv->rxbd[priv->rx_idx].status, status);
451362b123fSBin Meng priv->rx_idx = (priv->rx_idx + 1) % PKTBUFSRX;
452aada81deSchenhui zhao
453aada81deSchenhui zhao if (in_be32(®s->ievent) & IEVENT_BSY) {
454aada81deSchenhui zhao out_be32(®s->ievent, IEVENT_BSY);
455aada81deSchenhui zhao out_be32(®s->rstat, RSTAT_CLEAR_RHALT);
456aada81deSchenhui zhao }
457aada81deSchenhui zhao if (fail) {
458aada81deSchenhui zhao printf("loopback recv packet error!\n");
459aada81deSchenhui zhao clrbits_be32(®s->maccfg1, MACCFG1_RX_EN);
460aada81deSchenhui zhao udelay(1000);
461aada81deSchenhui zhao setbits_be32(®s->maccfg1, MACCFG1_RX_EN);
462aada81deSchenhui zhao }
463aada81deSchenhui zhao } while ((count++ < 4) && (fail == 1));
464aada81deSchenhui zhao
465aada81deSchenhui zhao if (fail)
466aada81deSchenhui zhao panic("eTSEC init fail!\n");
467aada81deSchenhui zhao /* Disable promiscuous mode */
468aada81deSchenhui zhao clrbits_be32(®s->rctrl, 0x8);
469aada81deSchenhui zhao /* Disable loopback mode */
470aada81deSchenhui zhao clrbits_be32(®s->maccfg1, MACCFG1_LOOPBACK);
471aada81deSchenhui zhao }
472aada81deSchenhui zhao #endif
473aada81deSchenhui zhao
4749872b736SBin Meng /*
4759872b736SBin Meng * Set up the buffers and their descriptors, and bring up the
47690751910SMingkai Hu * interface
47790751910SMingkai Hu */
startup_tsec(struct tsec_private * priv)47856a27a1eSBin Meng static void startup_tsec(struct tsec_private *priv)
47990751910SMingkai Hu {
480aec84bf6SClaudiu Manoil struct tsec __iomem *regs = priv->regs;
4819c9141fdSClaudiu Manoil uint16_t status;
4829c9141fdSClaudiu Manoil int i;
48390751910SMingkai Hu
484063c1263SAndy Fleming /* reset the indices to zero */
485362b123fSBin Meng priv->rx_idx = 0;
486362b123fSBin Meng priv->tx_idx = 0;
487aada81deSchenhui zhao #ifdef CONFIG_SYS_FSL_ERRATUM_NMG_ETSEC129
488aada81deSchenhui zhao uint svr;
489aada81deSchenhui zhao #endif
490063c1263SAndy Fleming
49190751910SMingkai Hu /* Point to the buffer descriptors */
492e677da97SBin Meng out_be32(®s->tbase, (u32)&priv->txbd[0]);
493e677da97SBin Meng out_be32(®s->rbase, (u32)&priv->rxbd[0]);
49490751910SMingkai Hu
49590751910SMingkai Hu /* Initialize the Rx Buffer descriptors */
49690751910SMingkai Hu for (i = 0; i < PKTBUFSRX; i++) {
497e677da97SBin Meng out_be16(&priv->rxbd[i].status, RXBD_EMPTY);
498e677da97SBin Meng out_be16(&priv->rxbd[i].length, 0);
499e677da97SBin Meng out_be32(&priv->rxbd[i].bufptr, (u32)net_rx_packets[i]);
50090751910SMingkai Hu }
501e677da97SBin Meng status = in_be16(&priv->rxbd[PKTBUFSRX - 1].status);
502e677da97SBin Meng out_be16(&priv->rxbd[PKTBUFSRX - 1].status, status | RXBD_WRAP);
50390751910SMingkai Hu
50490751910SMingkai Hu /* Initialize the TX Buffer Descriptors */
50590751910SMingkai Hu for (i = 0; i < TX_BUF_CNT; i++) {
506e677da97SBin Meng out_be16(&priv->txbd[i].status, 0);
507e677da97SBin Meng out_be16(&priv->txbd[i].length, 0);
508e677da97SBin Meng out_be32(&priv->txbd[i].bufptr, 0);
50990751910SMingkai Hu }
510e677da97SBin Meng status = in_be16(&priv->txbd[TX_BUF_CNT - 1].status);
511e677da97SBin Meng out_be16(&priv->txbd[TX_BUF_CNT - 1].status, status | TXBD_WRAP);
51290751910SMingkai Hu
513aada81deSchenhui zhao #ifdef CONFIG_SYS_FSL_ERRATUM_NMG_ETSEC129
514aada81deSchenhui zhao svr = get_svr();
515aada81deSchenhui zhao if ((SVR_MAJ(svr) == 1) || IS_SVR_REV(svr, 2, 0))
51656a27a1eSBin Meng redundant_init(priv);
517aada81deSchenhui zhao #endif
51890751910SMingkai Hu /* Enable Transmit and Receive */
51990751910SMingkai Hu setbits_be32(®s->maccfg1, MACCFG1_RX_EN | MACCFG1_TX_EN);
52090751910SMingkai Hu
52190751910SMingkai Hu /* Tell the DMA it is clear to go */
52290751910SMingkai Hu setbits_be32(®s->dmactrl, DMACTRL_INIT_SETTINGS);
52390751910SMingkai Hu out_be32(®s->tstat, TSTAT_CLEAR_THALT);
52490751910SMingkai Hu out_be32(®s->rstat, RSTAT_CLEAR_RHALT);
52590751910SMingkai Hu clrbits_be32(®s->dmactrl, DMACTRL_GRS | DMACTRL_GTS);
52690751910SMingkai Hu }
52790751910SMingkai Hu
5289872b736SBin Meng /*
5299872b736SBin Meng * Initializes data structures and registers for the controller,
53090751910SMingkai Hu * and brings the interface up. Returns the link status, meaning
53190751910SMingkai Hu * that it returns success if the link is up, failure otherwise.
5329872b736SBin Meng * This allows U-Boot to find the first active controller.
53390751910SMingkai Hu */
5349a1d6af5SBin Meng #ifndef CONFIG_DM_ETH
tsec_init(struct eth_device * dev,bd_t * bd)53590751910SMingkai Hu static int tsec_init(struct eth_device *dev, bd_t * bd)
5369a1d6af5SBin Meng #else
5379a1d6af5SBin Meng static int tsec_init(struct udevice *dev)
5389a1d6af5SBin Meng #endif
53990751910SMingkai Hu {
54090751910SMingkai Hu struct tsec_private *priv = (struct tsec_private *)dev->priv;
5419a1d6af5SBin Meng #ifdef CONFIG_DM_ETH
5429a1d6af5SBin Meng struct eth_pdata *pdata = dev_get_platdata(dev);
5439a1d6af5SBin Meng #endif
544aec84bf6SClaudiu Manoil struct tsec __iomem *regs = priv->regs;
545b1690bc3SClaudiu Manoil u32 tempval;
54611af8d65STimur Tabi int ret;
54790751910SMingkai Hu
54890751910SMingkai Hu /* Make sure the controller is stopped */
54990751910SMingkai Hu tsec_halt(dev);
55090751910SMingkai Hu
55190751910SMingkai Hu /* Init MACCFG2. Defaults to GMII */
55290751910SMingkai Hu out_be32(®s->maccfg2, MACCFG2_INIT_SETTINGS);
55390751910SMingkai Hu
55490751910SMingkai Hu /* Init ECNTRL */
55590751910SMingkai Hu out_be32(®s->ecntrl, ECNTRL_INIT_SETTINGS);
55690751910SMingkai Hu
5579872b736SBin Meng /*
5589872b736SBin Meng * Copy the station address into the address registers.
559b1690bc3SClaudiu Manoil * For a station address of 0x12345678ABCD in transmission
560b1690bc3SClaudiu Manoil * order (BE), MACnADDR1 is set to 0xCDAB7856 and
561b1690bc3SClaudiu Manoil * MACnADDR2 is set to 0x34120000.
562b1690bc3SClaudiu Manoil */
5639a1d6af5SBin Meng #ifndef CONFIG_DM_ETH
564b1690bc3SClaudiu Manoil tempval = (dev->enetaddr[5] << 24) | (dev->enetaddr[4] << 16) |
565b1690bc3SClaudiu Manoil (dev->enetaddr[3] << 8) | dev->enetaddr[2];
5669a1d6af5SBin Meng #else
5679a1d6af5SBin Meng tempval = (pdata->enetaddr[5] << 24) | (pdata->enetaddr[4] << 16) |
5689a1d6af5SBin Meng (pdata->enetaddr[3] << 8) | pdata->enetaddr[2];
5699a1d6af5SBin Meng #endif
57090751910SMingkai Hu
57190751910SMingkai Hu out_be32(®s->macstnaddr1, tempval);
57290751910SMingkai Hu
5739a1d6af5SBin Meng #ifndef CONFIG_DM_ETH
574b1690bc3SClaudiu Manoil tempval = (dev->enetaddr[1] << 24) | (dev->enetaddr[0] << 16);
5759a1d6af5SBin Meng #else
5769a1d6af5SBin Meng tempval = (pdata->enetaddr[1] << 24) | (pdata->enetaddr[0] << 16);
5779a1d6af5SBin Meng #endif
57890751910SMingkai Hu
57990751910SMingkai Hu out_be32(®s->macstnaddr2, tempval);
58090751910SMingkai Hu
58190751910SMingkai Hu /* Clear out (for the most part) the other registers */
58290751910SMingkai Hu init_registers(regs);
58390751910SMingkai Hu
58490751910SMingkai Hu /* Ready the device for tx/rx */
58556a27a1eSBin Meng startup_tsec(priv);
58690751910SMingkai Hu
587063c1263SAndy Fleming /* Start up the PHY */
58811af8d65STimur Tabi ret = phy_startup(priv->phydev);
58911af8d65STimur Tabi if (ret) {
59011af8d65STimur Tabi printf("Could not initialize PHY %s\n",
59111af8d65STimur Tabi priv->phydev->dev->name);
59211af8d65STimur Tabi return ret;
59311af8d65STimur Tabi }
594063c1263SAndy Fleming
595063c1263SAndy Fleming adjust_link(priv, priv->phydev);
596063c1263SAndy Fleming
59790751910SMingkai Hu /* If there's no link, fail */
598063c1263SAndy Fleming return priv->phydev->link ? 0 : -1;
59990751910SMingkai Hu }
60090751910SMingkai Hu
tsec_get_interface(struct tsec_private * priv)601063c1263SAndy Fleming static phy_interface_t tsec_get_interface(struct tsec_private *priv)
602063c1263SAndy Fleming {
603aec84bf6SClaudiu Manoil struct tsec __iomem *regs = priv->regs;
604063c1263SAndy Fleming u32 ecntrl;
605063c1263SAndy Fleming
606063c1263SAndy Fleming ecntrl = in_be32(®s->ecntrl);
607063c1263SAndy Fleming
608063c1263SAndy Fleming if (ecntrl & ECNTRL_SGMII_MODE)
609063c1263SAndy Fleming return PHY_INTERFACE_MODE_SGMII;
610063c1263SAndy Fleming
611063c1263SAndy Fleming if (ecntrl & ECNTRL_TBI_MODE) {
612063c1263SAndy Fleming if (ecntrl & ECNTRL_REDUCED_MODE)
613063c1263SAndy Fleming return PHY_INTERFACE_MODE_RTBI;
614063c1263SAndy Fleming else
615063c1263SAndy Fleming return PHY_INTERFACE_MODE_TBI;
616063c1263SAndy Fleming }
617063c1263SAndy Fleming
618063c1263SAndy Fleming if (ecntrl & ECNTRL_REDUCED_MODE) {
619063c1263SAndy Fleming if (ecntrl & ECNTRL_REDUCED_MII_MODE)
620063c1263SAndy Fleming return PHY_INTERFACE_MODE_RMII;
621063c1263SAndy Fleming else {
622063c1263SAndy Fleming phy_interface_t interface = priv->interface;
623063c1263SAndy Fleming
624063c1263SAndy Fleming /*
625063c1263SAndy Fleming * This isn't autodetected, so it must
626063c1263SAndy Fleming * be set by the platform code.
627063c1263SAndy Fleming */
628063c1263SAndy Fleming if ((interface == PHY_INTERFACE_MODE_RGMII_ID) ||
629063c1263SAndy Fleming (interface == PHY_INTERFACE_MODE_RGMII_TXID) ||
630063c1263SAndy Fleming (interface == PHY_INTERFACE_MODE_RGMII_RXID))
631063c1263SAndy Fleming return interface;
632063c1263SAndy Fleming
633063c1263SAndy Fleming return PHY_INTERFACE_MODE_RGMII;
634063c1263SAndy Fleming }
635063c1263SAndy Fleming }
636063c1263SAndy Fleming
637063c1263SAndy Fleming if (priv->flags & TSEC_GIGABIT)
638063c1263SAndy Fleming return PHY_INTERFACE_MODE_GMII;
639063c1263SAndy Fleming
640063c1263SAndy Fleming return PHY_INTERFACE_MODE_MII;
641063c1263SAndy Fleming }
642063c1263SAndy Fleming
6439872b736SBin Meng /*
6449872b736SBin Meng * Discover which PHY is attached to the device, and configure it
64590751910SMingkai Hu * properly. If the PHY is not recognized, then return 0
64690751910SMingkai Hu * (failure). Otherwise, return 1
64790751910SMingkai Hu */
init_phy(struct tsec_private * priv)64856a27a1eSBin Meng static int init_phy(struct tsec_private *priv)
64990751910SMingkai Hu {
650063c1263SAndy Fleming struct phy_device *phydev;
651aec84bf6SClaudiu Manoil struct tsec __iomem *regs = priv->regs;
652063c1263SAndy Fleming u32 supported = (SUPPORTED_10baseT_Half |
653063c1263SAndy Fleming SUPPORTED_10baseT_Full |
654063c1263SAndy Fleming SUPPORTED_100baseT_Half |
655063c1263SAndy Fleming SUPPORTED_100baseT_Full);
656063c1263SAndy Fleming
657063c1263SAndy Fleming if (priv->flags & TSEC_GIGABIT)
658063c1263SAndy Fleming supported |= SUPPORTED_1000baseT_Full;
65990751910SMingkai Hu
66090751910SMingkai Hu /* Assign a Physical address to the TBI */
661a1c76c15SBin Meng out_be32(®s->tbipa, priv->tbiaddr);
66290751910SMingkai Hu
663063c1263SAndy Fleming priv->interface = tsec_get_interface(priv);
66490751910SMingkai Hu
665063c1263SAndy Fleming if (priv->interface == PHY_INTERFACE_MODE_SGMII)
66690751910SMingkai Hu tsec_configure_serdes(priv);
66790751910SMingkai Hu
66856a27a1eSBin Meng phydev = phy_connect(priv->bus, priv->phyaddr, priv->dev,
66956a27a1eSBin Meng priv->interface);
6707f233c05SClaudiu Manoil if (!phydev)
6717f233c05SClaudiu Manoil return 0;
67290751910SMingkai Hu
673063c1263SAndy Fleming phydev->supported &= supported;
674063c1263SAndy Fleming phydev->advertising = phydev->supported;
675063c1263SAndy Fleming
676063c1263SAndy Fleming priv->phydev = phydev;
677063c1263SAndy Fleming
678063c1263SAndy Fleming phy_config(phydev);
67990751910SMingkai Hu
68090751910SMingkai Hu return 1;
68190751910SMingkai Hu }
68290751910SMingkai Hu
6839a1d6af5SBin Meng #ifndef CONFIG_DM_ETH
6849872b736SBin Meng /*
6859872b736SBin Meng * Initialize device structure. Returns success if PHY
68690751910SMingkai Hu * initialization succeeded (i.e. if it recognizes the PHY)
68790751910SMingkai Hu */
tsec_initialize(bd_t * bis,struct tsec_info_struct * tsec_info)68890751910SMingkai Hu static int tsec_initialize(bd_t *bis, struct tsec_info_struct *tsec_info)
68990751910SMingkai Hu {
69090751910SMingkai Hu struct eth_device *dev;
69190751910SMingkai Hu int i;
69290751910SMingkai Hu struct tsec_private *priv;
69390751910SMingkai Hu
69490751910SMingkai Hu dev = (struct eth_device *)malloc(sizeof *dev);
69590751910SMingkai Hu
69690751910SMingkai Hu if (NULL == dev)
69790751910SMingkai Hu return 0;
69890751910SMingkai Hu
69990751910SMingkai Hu memset(dev, 0, sizeof *dev);
70090751910SMingkai Hu
70190751910SMingkai Hu priv = (struct tsec_private *)malloc(sizeof(*priv));
70290751910SMingkai Hu
70390751910SMingkai Hu if (NULL == priv)
70490751910SMingkai Hu return 0;
70590751910SMingkai Hu
70690751910SMingkai Hu priv->regs = tsec_info->regs;
70790751910SMingkai Hu priv->phyregs_sgmii = tsec_info->miiregs_sgmii;
70890751910SMingkai Hu
70990751910SMingkai Hu priv->phyaddr = tsec_info->phyaddr;
710a1c76c15SBin Meng priv->tbiaddr = CONFIG_SYS_TBIPA_VALUE;
71190751910SMingkai Hu priv->flags = tsec_info->flags;
71290751910SMingkai Hu
713192bc694SBen Whitten strcpy(dev->name, tsec_info->devname);
714063c1263SAndy Fleming priv->interface = tsec_info->interface;
715063c1263SAndy Fleming priv->bus = miiphy_get_dev_by_name(tsec_info->mii_devname);
71656a27a1eSBin Meng priv->dev = dev;
71790751910SMingkai Hu dev->iobase = 0;
71890751910SMingkai Hu dev->priv = priv;
71990751910SMingkai Hu dev->init = tsec_init;
72090751910SMingkai Hu dev->halt = tsec_halt;
72190751910SMingkai Hu dev->send = tsec_send;
72290751910SMingkai Hu dev->recv = tsec_recv;
72390751910SMingkai Hu #ifdef CONFIG_MCAST_TFTP
72490751910SMingkai Hu dev->mcast = tsec_mcast_addr;
72590751910SMingkai Hu #endif
72690751910SMingkai Hu
7279872b736SBin Meng /* Tell U-Boot to get the addr from the env */
72890751910SMingkai Hu for (i = 0; i < 6; i++)
72990751910SMingkai Hu dev->enetaddr[i] = 0;
73090751910SMingkai Hu
73190751910SMingkai Hu eth_register(dev);
73290751910SMingkai Hu
73390751910SMingkai Hu /* Reset the MAC */
73490751910SMingkai Hu setbits_be32(&priv->regs->maccfg1, MACCFG1_SOFT_RESET);
73590751910SMingkai Hu udelay(2); /* Soft Reset must be asserted for 3 TX clocks */
73690751910SMingkai Hu clrbits_be32(&priv->regs->maccfg1, MACCFG1_SOFT_RESET);
73790751910SMingkai Hu
73890751910SMingkai Hu /* Try to initialize PHY here, and return */
73956a27a1eSBin Meng return init_phy(priv);
74090751910SMingkai Hu }
74190751910SMingkai Hu
74290751910SMingkai Hu /*
74390751910SMingkai Hu * Initialize all the TSEC devices
74490751910SMingkai Hu *
74590751910SMingkai Hu * Returns the number of TSEC devices that were initialized
74690751910SMingkai Hu */
tsec_eth_init(bd_t * bis,struct tsec_info_struct * tsecs,int num)74790751910SMingkai Hu int tsec_eth_init(bd_t *bis, struct tsec_info_struct *tsecs, int num)
74890751910SMingkai Hu {
74990751910SMingkai Hu int i;
75090751910SMingkai Hu int ret, count = 0;
75190751910SMingkai Hu
75290751910SMingkai Hu for (i = 0; i < num; i++) {
75390751910SMingkai Hu ret = tsec_initialize(bis, &tsecs[i]);
75490751910SMingkai Hu if (ret > 0)
75590751910SMingkai Hu count += ret;
75690751910SMingkai Hu }
75790751910SMingkai Hu
75890751910SMingkai Hu return count;
75990751910SMingkai Hu }
76090751910SMingkai Hu
tsec_standard_init(bd_t * bis)76190751910SMingkai Hu int tsec_standard_init(bd_t *bis)
76290751910SMingkai Hu {
763063c1263SAndy Fleming struct fsl_pq_mdio_info info;
764063c1263SAndy Fleming
765aec84bf6SClaudiu Manoil info.regs = TSEC_GET_MDIO_REGS_BASE(1);
766063c1263SAndy Fleming info.name = DEFAULT_MII_NAME;
767063c1263SAndy Fleming
768063c1263SAndy Fleming fsl_pq_mdio_init(bis, &info);
769063c1263SAndy Fleming
77090751910SMingkai Hu return tsec_eth_init(bis, tsec_info, ARRAY_SIZE(tsec_info));
77190751910SMingkai Hu }
7729a1d6af5SBin Meng #else /* CONFIG_DM_ETH */
tsec_probe(struct udevice * dev)7739a1d6af5SBin Meng int tsec_probe(struct udevice *dev)
7749a1d6af5SBin Meng {
7759a1d6af5SBin Meng struct tsec_private *priv = dev_get_priv(dev);
7769a1d6af5SBin Meng struct eth_pdata *pdata = dev_get_platdata(dev);
7779a1d6af5SBin Meng struct fsl_pq_mdio_info mdio_info;
7789a1d6af5SBin Meng int offset = 0;
7799a1d6af5SBin Meng int reg;
7809a1d6af5SBin Meng const char *phy_mode;
7819a1d6af5SBin Meng int ret;
7829a1d6af5SBin Meng
783*a821c4afSSimon Glass pdata->iobase = (phys_addr_t)devfdt_get_addr(dev);
7849a1d6af5SBin Meng priv->regs = (struct tsec *)pdata->iobase;
7859a1d6af5SBin Meng
786e160f7d4SSimon Glass offset = fdtdec_lookup_phandle(gd->fdt_blob, dev_of_offset(dev),
7879a1d6af5SBin Meng "phy-handle");
7889a1d6af5SBin Meng if (offset > 0) {
7899a1d6af5SBin Meng reg = fdtdec_get_int(gd->fdt_blob, offset, "reg", 0);
7909a1d6af5SBin Meng priv->phyaddr = reg;
7919a1d6af5SBin Meng } else {
7929a1d6af5SBin Meng debug("phy-handle does not exist under tsec %s\n", dev->name);
7939a1d6af5SBin Meng return -ENOENT;
7949a1d6af5SBin Meng }
7959a1d6af5SBin Meng
7969a1d6af5SBin Meng offset = fdt_parent_offset(gd->fdt_blob, offset);
7979a1d6af5SBin Meng if (offset > 0) {
7989a1d6af5SBin Meng reg = fdtdec_get_int(gd->fdt_blob, offset, "reg", 0);
7999a1d6af5SBin Meng priv->phyregs_sgmii = (struct tsec_mii_mng *)(reg + 0x520);
8009a1d6af5SBin Meng } else {
8019a1d6af5SBin Meng debug("No parent node for PHY?\n");
8029a1d6af5SBin Meng return -ENOENT;
8039a1d6af5SBin Meng }
8049a1d6af5SBin Meng
805e160f7d4SSimon Glass offset = fdtdec_lookup_phandle(gd->fdt_blob, dev_of_offset(dev),
806a1c76c15SBin Meng "tbi-handle");
807a1c76c15SBin Meng if (offset > 0) {
808a1c76c15SBin Meng reg = fdtdec_get_int(gd->fdt_blob, offset, "reg",
809a1c76c15SBin Meng CONFIG_SYS_TBIPA_VALUE);
810a1c76c15SBin Meng priv->tbiaddr = reg;
811a1c76c15SBin Meng } else {
812a1c76c15SBin Meng priv->tbiaddr = CONFIG_SYS_TBIPA_VALUE;
813a1c76c15SBin Meng }
814a1c76c15SBin Meng
815e160f7d4SSimon Glass phy_mode = fdt_getprop(gd->fdt_blob, dev_of_offset(dev),
8169a1d6af5SBin Meng "phy-connection-type", NULL);
8179a1d6af5SBin Meng if (phy_mode)
8189a1d6af5SBin Meng pdata->phy_interface = phy_get_interface_by_name(phy_mode);
8199a1d6af5SBin Meng if (pdata->phy_interface == -1) {
8209a1d6af5SBin Meng debug("Invalid PHY interface '%s'\n", phy_mode);
8219a1d6af5SBin Meng return -EINVAL;
8229a1d6af5SBin Meng }
8239a1d6af5SBin Meng priv->interface = pdata->phy_interface;
8249a1d6af5SBin Meng
8259a1d6af5SBin Meng /* Initialize flags */
8269a1d6af5SBin Meng priv->flags = TSEC_GIGABIT;
8279a1d6af5SBin Meng if (priv->interface == PHY_INTERFACE_MODE_SGMII)
8289a1d6af5SBin Meng priv->flags |= TSEC_SGMII;
8299a1d6af5SBin Meng
8309a1d6af5SBin Meng mdio_info.regs = priv->phyregs_sgmii;
8319a1d6af5SBin Meng mdio_info.name = (char *)dev->name;
8329a1d6af5SBin Meng ret = fsl_pq_mdio_init(NULL, &mdio_info);
8339a1d6af5SBin Meng if (ret)
8349a1d6af5SBin Meng return ret;
8359a1d6af5SBin Meng
8369a1d6af5SBin Meng /* Reset the MAC */
8379a1d6af5SBin Meng setbits_be32(&priv->regs->maccfg1, MACCFG1_SOFT_RESET);
8389a1d6af5SBin Meng udelay(2); /* Soft Reset must be asserted for 3 TX clocks */
8399a1d6af5SBin Meng clrbits_be32(&priv->regs->maccfg1, MACCFG1_SOFT_RESET);
8409a1d6af5SBin Meng
8419a1d6af5SBin Meng priv->dev = dev;
8429a1d6af5SBin Meng priv->bus = miiphy_get_dev_by_name(dev->name);
8439a1d6af5SBin Meng
8449a1d6af5SBin Meng /* Try to initialize PHY here, and return */
8459a1d6af5SBin Meng return !init_phy(priv);
8469a1d6af5SBin Meng }
8479a1d6af5SBin Meng
tsec_remove(struct udevice * dev)8489a1d6af5SBin Meng int tsec_remove(struct udevice *dev)
8499a1d6af5SBin Meng {
8509a1d6af5SBin Meng struct tsec_private *priv = dev->priv;
8519a1d6af5SBin Meng
8529a1d6af5SBin Meng free(priv->phydev);
8539a1d6af5SBin Meng mdio_unregister(priv->bus);
8549a1d6af5SBin Meng mdio_free(priv->bus);
8559a1d6af5SBin Meng
8569a1d6af5SBin Meng return 0;
8579a1d6af5SBin Meng }
8589a1d6af5SBin Meng
8599a1d6af5SBin Meng static const struct eth_ops tsec_ops = {
8609a1d6af5SBin Meng .start = tsec_init,
8619a1d6af5SBin Meng .send = tsec_send,
8629a1d6af5SBin Meng .recv = tsec_recv,
8639a1d6af5SBin Meng .free_pkt = tsec_free_pkt,
8649a1d6af5SBin Meng .stop = tsec_halt,
8659a1d6af5SBin Meng #ifdef CONFIG_MCAST_TFTP
8669a1d6af5SBin Meng .mcast = tsec_mcast_addr,
8679a1d6af5SBin Meng #endif
8689a1d6af5SBin Meng };
8699a1d6af5SBin Meng
8709a1d6af5SBin Meng static const struct udevice_id tsec_ids[] = {
8719a1d6af5SBin Meng { .compatible = "fsl,tsec" },
8729a1d6af5SBin Meng { }
8739a1d6af5SBin Meng };
8749a1d6af5SBin Meng
8759a1d6af5SBin Meng U_BOOT_DRIVER(eth_tsec) = {
8769a1d6af5SBin Meng .name = "tsec",
8779a1d6af5SBin Meng .id = UCLASS_ETH,
8789a1d6af5SBin Meng .of_match = tsec_ids,
8799a1d6af5SBin Meng .probe = tsec_probe,
8809a1d6af5SBin Meng .remove = tsec_remove,
8819a1d6af5SBin Meng .ops = &tsec_ops,
8829a1d6af5SBin Meng .priv_auto_alloc_size = sizeof(struct tsec_private),
8839a1d6af5SBin Meng .platdata_auto_alloc_size = sizeof(struct eth_pdata),
8849a1d6af5SBin Meng .flags = DM_FLAG_ALLOC_PRIV_DMA,
8859a1d6af5SBin Meng };
8869a1d6af5SBin Meng #endif /* CONFIG_DM_ETH */
887