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(®s->hash.gaddr0 + whichreg, value);
144876d4515SClaudiu Manoil else
145876d4515SClaudiu Manoil clrbits_be32(®s->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(®s->ievent, IEVENT_INIT_CLEAR);
15990751910SMingkai Hu
16090751910SMingkai Hu out_be32(®s->imask, IMASK_INIT_CLEAR);
16190751910SMingkai Hu
16290751910SMingkai Hu out_be32(®s->hash.iaddr0, 0);
16390751910SMingkai Hu out_be32(®s->hash.iaddr1, 0);
16490751910SMingkai Hu out_be32(®s->hash.iaddr2, 0);
16590751910SMingkai Hu out_be32(®s->hash.iaddr3, 0);
16690751910SMingkai Hu out_be32(®s->hash.iaddr4, 0);
16790751910SMingkai Hu out_be32(®s->hash.iaddr5, 0);
16890751910SMingkai Hu out_be32(®s->hash.iaddr6, 0);
16990751910SMingkai Hu out_be32(®s->hash.iaddr7, 0);
17090751910SMingkai Hu
17190751910SMingkai Hu out_be32(®s->hash.gaddr0, 0);
17290751910SMingkai Hu out_be32(®s->hash.gaddr1, 0);
17390751910SMingkai Hu out_be32(®s->hash.gaddr2, 0);
17490751910SMingkai Hu out_be32(®s->hash.gaddr3, 0);
17590751910SMingkai Hu out_be32(®s->hash.gaddr4, 0);
17690751910SMingkai Hu out_be32(®s->hash.gaddr5, 0);
17790751910SMingkai Hu out_be32(®s->hash.gaddr6, 0);
17890751910SMingkai Hu out_be32(®s->hash.gaddr7, 0);
17990751910SMingkai Hu
18090751910SMingkai Hu out_be32(®s->rctrl, 0x00000000);
18190751910SMingkai Hu
18290751910SMingkai Hu /* Init RMON mib registers */
18382ef75caSClaudiu Manoil memset((void *)®s->rmon, 0, sizeof(regs->rmon));
18490751910SMingkai Hu
18590751910SMingkai Hu out_be32(®s->rmon.cam1, 0xffffffff);
18690751910SMingkai Hu out_be32(®s->rmon.cam2, 0xffffffff);
18790751910SMingkai Hu
18890751910SMingkai Hu out_be32(®s->mrblr, MRBLR_INIT_SETTINGS);
18990751910SMingkai Hu
19090751910SMingkai Hu out_be32(®s->minflr, MINFLR_INIT_SETTINGS);
19190751910SMingkai Hu
19290751910SMingkai Hu out_be32(®s->attr, ATTR_INIT_SETTINGS);
19390751910SMingkai Hu out_be32(®s->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(®s->ecntrl);
21290751910SMingkai Hu ecntrl &= ~ECNTRL_R100;
21390751910SMingkai Hu
21490751910SMingkai Hu maccfg2 = in_be32(®s->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(®s->ecntrl, ecntrl);
24190751910SMingkai Hu out_be32(®s->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(®s->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(®s->ievent) & IEVENT_BSY) {
3308ba50176SBin Meng out_be32(®s->ievent, IEVENT_BSY);
3318ba50176SBin Meng out_be32(®s->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(®s->ievent) & IEVENT_BSY) {
3599a1d6af5SBin Meng out_be32(®s->ievent, IEVENT_BSY);
3609a1d6af5SBin Meng out_be32(®s->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(®s->dmactrl, DMACTRL_GRS | DMACTRL_GTS);
3968ba50176SBin Meng setbits_be32(®s->dmactrl, DMACTRL_GRS | DMACTRL_GTS);
3978ba50176SBin Meng
3988ba50176SBin Meng while ((in_be32(®s->ievent) & (IEVENT_GRSC | IEVENT_GTSC))
3998ba50176SBin Meng != (IEVENT_GRSC | IEVENT_GTSC))
4008ba50176SBin Meng ;
4018ba50176SBin Meng
4028ba50176SBin Meng clrbits_be32(®s->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(®s->rctrl, 0x8);
437aada81deSchenhui zhao /* Enable loopback mode */
438aada81deSchenhui zhao setbits_be32(®s->maccfg1, MACCFG1_LOOPBACK);
439aada81deSchenhui zhao /* Enable transmit and receive */
440aada81deSchenhui zhao setbits_be32(®s->maccfg1, MACCFG1_RX_EN | MACCFG1_TX_EN);
441aada81deSchenhui zhao
442aada81deSchenhui zhao /* Tell the DMA it is clear to go */
443aada81deSchenhui zhao setbits_be32(®s->dmactrl, DMACTRL_INIT_SETTINGS);
444aada81deSchenhui zhao out_be32(®s->tstat, TSTAT_CLEAR_THALT);
445aada81deSchenhui zhao out_be32(®s->rstat, RSTAT_CLEAR_RHALT);
446aada81deSchenhui zhao clrbits_be32(®s->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(®s->ievent) & IEVENT_BSY) {
474aada81deSchenhui zhao out_be32(®s->ievent, IEVENT_BSY);
475aada81deSchenhui zhao out_be32(®s->rstat, RSTAT_CLEAR_RHALT);
476aada81deSchenhui zhao }
477aada81deSchenhui zhao if (fail) {
478aada81deSchenhui zhao printf("loopback recv packet error!\n");
479aada81deSchenhui zhao clrbits_be32(®s->maccfg1, MACCFG1_RX_EN);
480aada81deSchenhui zhao udelay(1000);
481aada81deSchenhui zhao setbits_be32(®s->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(®s->rctrl, 0x8);
489aada81deSchenhui zhao /* Disable loopback mode */
490aada81deSchenhui zhao clrbits_be32(®s->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(®s->tbase, (u32)&priv->txbd[0]);
513e677da97SBin Meng out_be32(®s->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(®s->maccfg1, MACCFG1_RX_EN | MACCFG1_TX_EN);
54090751910SMingkai Hu
54190751910SMingkai Hu /* Tell the DMA it is clear to go */
54290751910SMingkai Hu setbits_be32(®s->dmactrl, DMACTRL_INIT_SETTINGS);
54390751910SMingkai Hu out_be32(®s->tstat, TSTAT_CLEAR_THALT);
54490751910SMingkai Hu out_be32(®s->rstat, RSTAT_CLEAR_RHALT);
54590751910SMingkai Hu clrbits_be32(®s->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(®s->maccfg2, MACCFG2_INIT_SETTINGS);
57390751910SMingkai Hu
57490751910SMingkai Hu /* Init ECNTRL */
57590751910SMingkai Hu out_be32(®s->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(®s->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(®s->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(®s->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(®s->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