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> 13*9a1d6af5SBin 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> 190d071cddSKim Phillips #include <asm/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 25*9a1d6af5SBin 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 }; 51*9a1d6af5SBin 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 */ 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 */ 104*9a1d6af5SBin Meng #ifndef CONFIG_DM_ETH 1059872b736SBin Meng static int tsec_mcast_addr(struct eth_device *dev, const u8 *mcast_mac, u8 set) 106*9a1d6af5SBin Meng #else 107*9a1d6af5SBin Meng static int tsec_mcast_addr(struct udevice *dev, const u8 *mcast_mac, int set) 108*9a1d6af5SBin 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 */ 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 */ 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 */ 235*9a1d6af5SBin Meng #ifndef CONFIG_DM_ETH 2368ba50176SBin Meng static int tsec_send(struct eth_device *dev, void *packet, int length) 237*9a1d6af5SBin Meng #else 238*9a1d6af5SBin Meng static int tsec_send(struct udevice *dev, void *packet, int length) 239*9a1d6af5SBin 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 282*9a1d6af5SBin Meng #ifndef CONFIG_DM_ETH 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 } 317*9a1d6af5SBin Meng #else 318*9a1d6af5SBin Meng static int tsec_recv(struct udevice *dev, int flags, uchar **packetp) 319*9a1d6af5SBin Meng { 320*9a1d6af5SBin Meng struct tsec_private *priv = (struct tsec_private *)dev->priv; 321*9a1d6af5SBin Meng struct tsec __iomem *regs = priv->regs; 322*9a1d6af5SBin Meng int ret = -1; 323*9a1d6af5SBin Meng 324*9a1d6af5SBin Meng if (!(in_be16(&priv->rxbd[priv->rx_idx].status) & RXBD_EMPTY)) { 325*9a1d6af5SBin Meng int length = in_be16(&priv->rxbd[priv->rx_idx].length); 326*9a1d6af5SBin Meng uint16_t status = in_be16(&priv->rxbd[priv->rx_idx].status); 327*9a1d6af5SBin Meng uint32_t buf; 328*9a1d6af5SBin Meng 329*9a1d6af5SBin Meng /* Send the packet up if there were no errors */ 330*9a1d6af5SBin Meng if (!(status & RXBD_STATS)) { 331*9a1d6af5SBin Meng buf = in_be32(&priv->rxbd[priv->rx_idx].bufptr); 332*9a1d6af5SBin Meng *packetp = (uchar *)buf; 333*9a1d6af5SBin Meng ret = length - 4; 334*9a1d6af5SBin Meng } else { 335*9a1d6af5SBin Meng printf("Got error %x\n", (status & RXBD_STATS)); 336*9a1d6af5SBin Meng } 337*9a1d6af5SBin Meng } 338*9a1d6af5SBin Meng 339*9a1d6af5SBin Meng if (in_be32(®s->ievent) & IEVENT_BSY) { 340*9a1d6af5SBin Meng out_be32(®s->ievent, IEVENT_BSY); 341*9a1d6af5SBin Meng out_be32(®s->rstat, RSTAT_CLEAR_RHALT); 342*9a1d6af5SBin Meng } 343*9a1d6af5SBin Meng 344*9a1d6af5SBin Meng return ret; 345*9a1d6af5SBin Meng } 346*9a1d6af5SBin Meng 347*9a1d6af5SBin Meng static int tsec_free_pkt(struct udevice *dev, uchar *packet, int length) 348*9a1d6af5SBin Meng { 349*9a1d6af5SBin Meng struct tsec_private *priv = (struct tsec_private *)dev->priv; 350*9a1d6af5SBin Meng uint16_t status; 351*9a1d6af5SBin Meng 352*9a1d6af5SBin Meng out_be16(&priv->rxbd[priv->rx_idx].length, 0); 353*9a1d6af5SBin Meng 354*9a1d6af5SBin Meng status = RXBD_EMPTY; 355*9a1d6af5SBin Meng /* Set the wrap bit if this is the last element in the list */ 356*9a1d6af5SBin Meng if ((priv->rx_idx + 1) == PKTBUFSRX) 357*9a1d6af5SBin Meng status |= RXBD_WRAP; 358*9a1d6af5SBin Meng out_be16(&priv->rxbd[priv->rx_idx].status, status); 359*9a1d6af5SBin Meng 360*9a1d6af5SBin Meng priv->rx_idx = (priv->rx_idx + 1) % PKTBUFSRX; 361*9a1d6af5SBin Meng 362*9a1d6af5SBin Meng return 0; 363*9a1d6af5SBin Meng } 364*9a1d6af5SBin Meng #endif 3658ba50176SBin Meng 3668ba50176SBin Meng /* Stop the interface */ 367*9a1d6af5SBin Meng #ifndef CONFIG_DM_ETH 3688ba50176SBin Meng static void tsec_halt(struct eth_device *dev) 369*9a1d6af5SBin Meng #else 370*9a1d6af5SBin Meng static void tsec_halt(struct udevice *dev) 371*9a1d6af5SBin 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 */ 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 */ 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 */ 534*9a1d6af5SBin Meng #ifndef CONFIG_DM_ETH 53590751910SMingkai Hu static int tsec_init(struct eth_device *dev, bd_t * bd) 536*9a1d6af5SBin Meng #else 537*9a1d6af5SBin Meng static int tsec_init(struct udevice *dev) 538*9a1d6af5SBin Meng #endif 53990751910SMingkai Hu { 54090751910SMingkai Hu struct tsec_private *priv = (struct tsec_private *)dev->priv; 541*9a1d6af5SBin Meng #ifdef CONFIG_DM_ETH 542*9a1d6af5SBin Meng struct eth_pdata *pdata = dev_get_platdata(dev); 543*9a1d6af5SBin 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 */ 563*9a1d6af5SBin 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]; 566*9a1d6af5SBin Meng #else 567*9a1d6af5SBin Meng tempval = (pdata->enetaddr[5] << 24) | (pdata->enetaddr[4] << 16) | 568*9a1d6af5SBin Meng (pdata->enetaddr[3] << 8) | pdata->enetaddr[2]; 569*9a1d6af5SBin Meng #endif 57090751910SMingkai Hu 57190751910SMingkai Hu out_be32(®s->macstnaddr1, tempval); 57290751910SMingkai Hu 573*9a1d6af5SBin Meng #ifndef CONFIG_DM_ETH 574b1690bc3SClaudiu Manoil tempval = (dev->enetaddr[1] << 24) | (dev->enetaddr[0] << 16); 575*9a1d6af5SBin Meng #else 576*9a1d6af5SBin Meng tempval = (pdata->enetaddr[1] << 24) | (pdata->enetaddr[0] << 16); 577*9a1d6af5SBin 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 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 */ 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 */ 66190751910SMingkai Hu out_be32(®s->tbipa, CONFIG_SYS_TBIPA_VALUE); 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 683*9a1d6af5SBin 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 */ 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; 71090751910SMingkai Hu priv->flags = tsec_info->flags; 71190751910SMingkai Hu 71290751910SMingkai Hu sprintf(dev->name, tsec_info->devname); 713063c1263SAndy Fleming priv->interface = tsec_info->interface; 714063c1263SAndy Fleming priv->bus = miiphy_get_dev_by_name(tsec_info->mii_devname); 71556a27a1eSBin Meng priv->dev = dev; 71690751910SMingkai Hu dev->iobase = 0; 71790751910SMingkai Hu dev->priv = priv; 71890751910SMingkai Hu dev->init = tsec_init; 71990751910SMingkai Hu dev->halt = tsec_halt; 72090751910SMingkai Hu dev->send = tsec_send; 72190751910SMingkai Hu dev->recv = tsec_recv; 72290751910SMingkai Hu #ifdef CONFIG_MCAST_TFTP 72390751910SMingkai Hu dev->mcast = tsec_mcast_addr; 72490751910SMingkai Hu #endif 72590751910SMingkai Hu 7269872b736SBin Meng /* Tell U-Boot to get the addr from the env */ 72790751910SMingkai Hu for (i = 0; i < 6; i++) 72890751910SMingkai Hu dev->enetaddr[i] = 0; 72990751910SMingkai Hu 73090751910SMingkai Hu eth_register(dev); 73190751910SMingkai Hu 73290751910SMingkai Hu /* Reset the MAC */ 73390751910SMingkai Hu setbits_be32(&priv->regs->maccfg1, MACCFG1_SOFT_RESET); 73490751910SMingkai Hu udelay(2); /* Soft Reset must be asserted for 3 TX clocks */ 73590751910SMingkai Hu clrbits_be32(&priv->regs->maccfg1, MACCFG1_SOFT_RESET); 73690751910SMingkai Hu 73790751910SMingkai Hu /* Try to initialize PHY here, and return */ 73856a27a1eSBin Meng return init_phy(priv); 73990751910SMingkai Hu } 74090751910SMingkai Hu 74190751910SMingkai Hu /* 74290751910SMingkai Hu * Initialize all the TSEC devices 74390751910SMingkai Hu * 74490751910SMingkai Hu * Returns the number of TSEC devices that were initialized 74590751910SMingkai Hu */ 74690751910SMingkai Hu int tsec_eth_init(bd_t *bis, struct tsec_info_struct *tsecs, int num) 74790751910SMingkai Hu { 74890751910SMingkai Hu int i; 74990751910SMingkai Hu int ret, count = 0; 75090751910SMingkai Hu 75190751910SMingkai Hu for (i = 0; i < num; i++) { 75290751910SMingkai Hu ret = tsec_initialize(bis, &tsecs[i]); 75390751910SMingkai Hu if (ret > 0) 75490751910SMingkai Hu count += ret; 75590751910SMingkai Hu } 75690751910SMingkai Hu 75790751910SMingkai Hu return count; 75890751910SMingkai Hu } 75990751910SMingkai Hu 76090751910SMingkai Hu int tsec_standard_init(bd_t *bis) 76190751910SMingkai Hu { 762063c1263SAndy Fleming struct fsl_pq_mdio_info info; 763063c1263SAndy Fleming 764aec84bf6SClaudiu Manoil info.regs = TSEC_GET_MDIO_REGS_BASE(1); 765063c1263SAndy Fleming info.name = DEFAULT_MII_NAME; 766063c1263SAndy Fleming 767063c1263SAndy Fleming fsl_pq_mdio_init(bis, &info); 768063c1263SAndy Fleming 76990751910SMingkai Hu return tsec_eth_init(bis, tsec_info, ARRAY_SIZE(tsec_info)); 77090751910SMingkai Hu } 771*9a1d6af5SBin Meng #else /* CONFIG_DM_ETH */ 772*9a1d6af5SBin Meng int tsec_probe(struct udevice *dev) 773*9a1d6af5SBin Meng { 774*9a1d6af5SBin Meng struct tsec_private *priv = dev_get_priv(dev); 775*9a1d6af5SBin Meng struct eth_pdata *pdata = dev_get_platdata(dev); 776*9a1d6af5SBin Meng struct fsl_pq_mdio_info mdio_info; 777*9a1d6af5SBin Meng int offset = 0; 778*9a1d6af5SBin Meng int reg; 779*9a1d6af5SBin Meng const char *phy_mode; 780*9a1d6af5SBin Meng int ret; 781*9a1d6af5SBin Meng 782*9a1d6af5SBin Meng pdata->iobase = (phys_addr_t)dev_get_addr(dev); 783*9a1d6af5SBin Meng priv->regs = (struct tsec *)pdata->iobase; 784*9a1d6af5SBin Meng 785*9a1d6af5SBin Meng offset = fdtdec_lookup_phandle(gd->fdt_blob, dev->of_offset, 786*9a1d6af5SBin Meng "phy-handle"); 787*9a1d6af5SBin Meng if (offset > 0) { 788*9a1d6af5SBin Meng reg = fdtdec_get_int(gd->fdt_blob, offset, "reg", 0); 789*9a1d6af5SBin Meng priv->phyaddr = reg; 790*9a1d6af5SBin Meng } else { 791*9a1d6af5SBin Meng debug("phy-handle does not exist under tsec %s\n", dev->name); 792*9a1d6af5SBin Meng return -ENOENT; 793*9a1d6af5SBin Meng } 794*9a1d6af5SBin Meng 795*9a1d6af5SBin Meng offset = fdt_parent_offset(gd->fdt_blob, offset); 796*9a1d6af5SBin Meng if (offset > 0) { 797*9a1d6af5SBin Meng reg = fdtdec_get_int(gd->fdt_blob, offset, "reg", 0); 798*9a1d6af5SBin Meng priv->phyregs_sgmii = (struct tsec_mii_mng *)(reg + 0x520); 799*9a1d6af5SBin Meng } else { 800*9a1d6af5SBin Meng debug("No parent node for PHY?\n"); 801*9a1d6af5SBin Meng return -ENOENT; 802*9a1d6af5SBin Meng } 803*9a1d6af5SBin Meng 804*9a1d6af5SBin Meng phy_mode = fdt_getprop(gd->fdt_blob, dev->of_offset, 805*9a1d6af5SBin Meng "phy-connection-type", NULL); 806*9a1d6af5SBin Meng if (phy_mode) 807*9a1d6af5SBin Meng pdata->phy_interface = phy_get_interface_by_name(phy_mode); 808*9a1d6af5SBin Meng if (pdata->phy_interface == -1) { 809*9a1d6af5SBin Meng debug("Invalid PHY interface '%s'\n", phy_mode); 810*9a1d6af5SBin Meng return -EINVAL; 811*9a1d6af5SBin Meng } 812*9a1d6af5SBin Meng priv->interface = pdata->phy_interface; 813*9a1d6af5SBin Meng 814*9a1d6af5SBin Meng /* Initialize flags */ 815*9a1d6af5SBin Meng priv->flags = TSEC_GIGABIT; 816*9a1d6af5SBin Meng if (priv->interface == PHY_INTERFACE_MODE_SGMII) 817*9a1d6af5SBin Meng priv->flags |= TSEC_SGMII; 818*9a1d6af5SBin Meng 819*9a1d6af5SBin Meng mdio_info.regs = priv->phyregs_sgmii; 820*9a1d6af5SBin Meng mdio_info.name = (char *)dev->name; 821*9a1d6af5SBin Meng ret = fsl_pq_mdio_init(NULL, &mdio_info); 822*9a1d6af5SBin Meng if (ret) 823*9a1d6af5SBin Meng return ret; 824*9a1d6af5SBin Meng 825*9a1d6af5SBin Meng /* Reset the MAC */ 826*9a1d6af5SBin Meng setbits_be32(&priv->regs->maccfg1, MACCFG1_SOFT_RESET); 827*9a1d6af5SBin Meng udelay(2); /* Soft Reset must be asserted for 3 TX clocks */ 828*9a1d6af5SBin Meng clrbits_be32(&priv->regs->maccfg1, MACCFG1_SOFT_RESET); 829*9a1d6af5SBin Meng 830*9a1d6af5SBin Meng priv->dev = dev; 831*9a1d6af5SBin Meng priv->bus = miiphy_get_dev_by_name(dev->name); 832*9a1d6af5SBin Meng 833*9a1d6af5SBin Meng /* Try to initialize PHY here, and return */ 834*9a1d6af5SBin Meng return !init_phy(priv); 835*9a1d6af5SBin Meng } 836*9a1d6af5SBin Meng 837*9a1d6af5SBin Meng int tsec_remove(struct udevice *dev) 838*9a1d6af5SBin Meng { 839*9a1d6af5SBin Meng struct tsec_private *priv = dev->priv; 840*9a1d6af5SBin Meng 841*9a1d6af5SBin Meng free(priv->phydev); 842*9a1d6af5SBin Meng mdio_unregister(priv->bus); 843*9a1d6af5SBin Meng mdio_free(priv->bus); 844*9a1d6af5SBin Meng 845*9a1d6af5SBin Meng return 0; 846*9a1d6af5SBin Meng } 847*9a1d6af5SBin Meng 848*9a1d6af5SBin Meng static const struct eth_ops tsec_ops = { 849*9a1d6af5SBin Meng .start = tsec_init, 850*9a1d6af5SBin Meng .send = tsec_send, 851*9a1d6af5SBin Meng .recv = tsec_recv, 852*9a1d6af5SBin Meng .free_pkt = tsec_free_pkt, 853*9a1d6af5SBin Meng .stop = tsec_halt, 854*9a1d6af5SBin Meng #ifdef CONFIG_MCAST_TFTP 855*9a1d6af5SBin Meng .mcast = tsec_mcast_addr, 856*9a1d6af5SBin Meng #endif 857*9a1d6af5SBin Meng }; 858*9a1d6af5SBin Meng 859*9a1d6af5SBin Meng static const struct udevice_id tsec_ids[] = { 860*9a1d6af5SBin Meng { .compatible = "fsl,tsec" }, 861*9a1d6af5SBin Meng { } 862*9a1d6af5SBin Meng }; 863*9a1d6af5SBin Meng 864*9a1d6af5SBin Meng U_BOOT_DRIVER(eth_tsec) = { 865*9a1d6af5SBin Meng .name = "tsec", 866*9a1d6af5SBin Meng .id = UCLASS_ETH, 867*9a1d6af5SBin Meng .of_match = tsec_ids, 868*9a1d6af5SBin Meng .probe = tsec_probe, 869*9a1d6af5SBin Meng .remove = tsec_remove, 870*9a1d6af5SBin Meng .ops = &tsec_ops, 871*9a1d6af5SBin Meng .priv_auto_alloc_size = sizeof(struct tsec_private), 872*9a1d6af5SBin Meng .platdata_auto_alloc_size = sizeof(struct eth_pdata), 873*9a1d6af5SBin Meng .flags = DM_FLAG_ALLOC_PRIV_DMA, 874*9a1d6af5SBin Meng }; 875*9a1d6af5SBin Meng #endif /* CONFIG_DM_ETH */ 876