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> 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> 180d071cddSKim Phillips #include <asm/errno.h> 19aada81deSchenhui zhao #include <asm/processor.h> 2052d00a81SAlison Wang #include <asm/io.h> 212439e4bfSJean-Christophe PLAGNIOL-VILLARD 222439e4bfSJean-Christophe PLAGNIOL-VILLARD DECLARE_GLOBAL_DATA_PTR; 232439e4bfSJean-Christophe PLAGNIOL-VILLARD 24c8a60b53SJoe Hershberger static int tsec_send(struct eth_device *dev, void *packet, int length); 25aada81deSchenhui zhao 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 }; 5175b9d4aeSAndy Fleming 522abe361cSAndy Fleming #define TBIANA_SETTINGS ( \ 532abe361cSAndy Fleming TBIANA_ASYMMETRIC_PAUSE \ 542abe361cSAndy Fleming | TBIANA_SYMMETRIC_PAUSE \ 552abe361cSAndy Fleming | TBIANA_FULL_DUPLEX \ 562abe361cSAndy Fleming ) 572abe361cSAndy Fleming 5890b5bf21SFelix Radensky /* By default force the TBI PHY into 1000Mbps full duplex when in SGMII mode */ 5990b5bf21SFelix Radensky #ifndef CONFIG_TSEC_TBICR_SETTINGS 6072c96a68SKumar Gala #define CONFIG_TSEC_TBICR_SETTINGS ( \ 612abe361cSAndy Fleming TBICR_PHY_RESET \ 6272c96a68SKumar Gala | TBICR_ANEG_ENABLE \ 632abe361cSAndy Fleming | TBICR_FULL_DUPLEX \ 642abe361cSAndy Fleming | TBICR_SPEED1_SET \ 652abe361cSAndy Fleming ) 6690b5bf21SFelix Radensky #endif /* CONFIG_TSEC_TBICR_SETTINGS */ 6746e91674SPeter Tyser 682abe361cSAndy Fleming /* Configure the TBI for SGMII operation */ 692abe361cSAndy Fleming static void tsec_configure_serdes(struct tsec_private *priv) 702abe361cSAndy Fleming { 719872b736SBin Meng /* 729872b736SBin Meng * Access TBI PHY registers at given TSEC register offset as opposed 739872b736SBin Meng * to the register offset used for external PHY accesses 749872b736SBin Meng */ 75063c1263SAndy Fleming tsec_local_mdio_write(priv->phyregs_sgmii, in_be32(&priv->regs->tbipa), 76063c1263SAndy Fleming 0, TBI_ANA, TBIANA_SETTINGS); 77063c1263SAndy Fleming tsec_local_mdio_write(priv->phyregs_sgmii, in_be32(&priv->regs->tbipa), 78063c1263SAndy Fleming 0, TBI_TBICON, TBICON_CLK_SELECT); 79063c1263SAndy Fleming tsec_local_mdio_write(priv->phyregs_sgmii, in_be32(&priv->regs->tbipa), 80063c1263SAndy Fleming 0, TBI_CR, CONFIG_TSEC_TBICR_SETTINGS); 812439e4bfSJean-Christophe PLAGNIOL-VILLARD } 822439e4bfSJean-Christophe PLAGNIOL-VILLARD 832439e4bfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_MCAST_TFTP 842439e4bfSJean-Christophe PLAGNIOL-VILLARD 852439e4bfSJean-Christophe PLAGNIOL-VILLARD /* CREDITS: linux gianfar driver, slightly adjusted... thanx. */ 862439e4bfSJean-Christophe PLAGNIOL-VILLARD 872439e4bfSJean-Christophe PLAGNIOL-VILLARD /* Set the appropriate hash bit for the given addr */ 882439e4bfSJean-Christophe PLAGNIOL-VILLARD 899872b736SBin Meng /* 909872b736SBin Meng * The algorithm works like so: 912439e4bfSJean-Christophe PLAGNIOL-VILLARD * 1) Take the Destination Address (ie the multicast address), and 922439e4bfSJean-Christophe PLAGNIOL-VILLARD * do a CRC on it (little endian), and reverse the bits of the 932439e4bfSJean-Christophe PLAGNIOL-VILLARD * result. 942439e4bfSJean-Christophe PLAGNIOL-VILLARD * 2) Use the 8 most significant bits as a hash into a 256-entry 952439e4bfSJean-Christophe PLAGNIOL-VILLARD * table. The table is controlled through 8 32-bit registers: 96876d4515SClaudiu Manoil * gaddr0-7. gaddr0's MSB is entry 0, and gaddr7's LSB is entry 97876d4515SClaudiu Manoil * 255. This means that the 3 most significant bits in the 982439e4bfSJean-Christophe PLAGNIOL-VILLARD * hash index which gaddr register to use, and the 5 other bits 992439e4bfSJean-Christophe PLAGNIOL-VILLARD * indicate which bit (assuming an IBM numbering scheme, which 100876d4515SClaudiu Manoil * for PowerPC (tm) is usually the case) in the register holds 1019872b736SBin Meng * the entry. 1029872b736SBin Meng */ 1039872b736SBin Meng static int tsec_mcast_addr(struct eth_device *dev, const u8 *mcast_mac, u8 set) 1042439e4bfSJean-Christophe PLAGNIOL-VILLARD { 105b200204eSClaudiu Manoil struct tsec_private *priv = (struct tsec_private *)dev->priv; 106876d4515SClaudiu Manoil struct tsec __iomem *regs = priv->regs; 107876d4515SClaudiu Manoil u32 result, value; 108876d4515SClaudiu Manoil u8 whichbit, whichreg; 1092439e4bfSJean-Christophe PLAGNIOL-VILLARD 110876d4515SClaudiu Manoil result = ether_crc(MAC_ADDR_LEN, mcast_mac); 111876d4515SClaudiu Manoil whichbit = (result >> 24) & 0x1f; /* the 5 LSB = which bit to set */ 112876d4515SClaudiu Manoil whichreg = result >> 29; /* the 3 MSB = which reg to set it in */ 1132439e4bfSJean-Christophe PLAGNIOL-VILLARD 114876d4515SClaudiu Manoil value = 1 << (31-whichbit); 1152439e4bfSJean-Christophe PLAGNIOL-VILLARD 116876d4515SClaudiu Manoil if (set) 117876d4515SClaudiu Manoil setbits_be32(®s->hash.gaddr0 + whichreg, value); 118876d4515SClaudiu Manoil else 119876d4515SClaudiu Manoil clrbits_be32(®s->hash.gaddr0 + whichreg, value); 120876d4515SClaudiu Manoil 1212439e4bfSJean-Christophe PLAGNIOL-VILLARD return 0; 1222439e4bfSJean-Christophe PLAGNIOL-VILLARD } 1232439e4bfSJean-Christophe PLAGNIOL-VILLARD #endif /* Multicast TFTP ? */ 12490751910SMingkai Hu 1259872b736SBin Meng /* 1269872b736SBin Meng * Initialized required registers to appropriate values, zeroing 12790751910SMingkai Hu * those we don't care about (unless zero is bad, in which case, 12890751910SMingkai Hu * choose a more appropriate value) 12990751910SMingkai Hu */ 130aec84bf6SClaudiu Manoil static void init_registers(struct tsec __iomem *regs) 13190751910SMingkai Hu { 13290751910SMingkai Hu /* Clear IEVENT */ 13390751910SMingkai Hu out_be32(®s->ievent, IEVENT_INIT_CLEAR); 13490751910SMingkai Hu 13590751910SMingkai Hu out_be32(®s->imask, IMASK_INIT_CLEAR); 13690751910SMingkai Hu 13790751910SMingkai Hu out_be32(®s->hash.iaddr0, 0); 13890751910SMingkai Hu out_be32(®s->hash.iaddr1, 0); 13990751910SMingkai Hu out_be32(®s->hash.iaddr2, 0); 14090751910SMingkai Hu out_be32(®s->hash.iaddr3, 0); 14190751910SMingkai Hu out_be32(®s->hash.iaddr4, 0); 14290751910SMingkai Hu out_be32(®s->hash.iaddr5, 0); 14390751910SMingkai Hu out_be32(®s->hash.iaddr6, 0); 14490751910SMingkai Hu out_be32(®s->hash.iaddr7, 0); 14590751910SMingkai Hu 14690751910SMingkai Hu out_be32(®s->hash.gaddr0, 0); 14790751910SMingkai Hu out_be32(®s->hash.gaddr1, 0); 14890751910SMingkai Hu out_be32(®s->hash.gaddr2, 0); 14990751910SMingkai Hu out_be32(®s->hash.gaddr3, 0); 15090751910SMingkai Hu out_be32(®s->hash.gaddr4, 0); 15190751910SMingkai Hu out_be32(®s->hash.gaddr5, 0); 15290751910SMingkai Hu out_be32(®s->hash.gaddr6, 0); 15390751910SMingkai Hu out_be32(®s->hash.gaddr7, 0); 15490751910SMingkai Hu 15590751910SMingkai Hu out_be32(®s->rctrl, 0x00000000); 15690751910SMingkai Hu 15790751910SMingkai Hu /* Init RMON mib registers */ 15882ef75caSClaudiu Manoil memset((void *)®s->rmon, 0, sizeof(regs->rmon)); 15990751910SMingkai Hu 16090751910SMingkai Hu out_be32(®s->rmon.cam1, 0xffffffff); 16190751910SMingkai Hu out_be32(®s->rmon.cam2, 0xffffffff); 16290751910SMingkai Hu 16390751910SMingkai Hu out_be32(®s->mrblr, MRBLR_INIT_SETTINGS); 16490751910SMingkai Hu 16590751910SMingkai Hu out_be32(®s->minflr, MINFLR_INIT_SETTINGS); 16690751910SMingkai Hu 16790751910SMingkai Hu out_be32(®s->attr, ATTR_INIT_SETTINGS); 16890751910SMingkai Hu out_be32(®s->attreli, ATTRELI_INIT_SETTINGS); 16990751910SMingkai Hu 17090751910SMingkai Hu } 17190751910SMingkai Hu 1729872b736SBin Meng /* 1739872b736SBin Meng * Configure maccfg2 based on negotiated speed and duplex 17490751910SMingkai Hu * reported by PHY handling code 17590751910SMingkai Hu */ 176063c1263SAndy Fleming static void adjust_link(struct tsec_private *priv, struct phy_device *phydev) 17790751910SMingkai Hu { 178aec84bf6SClaudiu Manoil struct tsec __iomem *regs = priv->regs; 17990751910SMingkai Hu u32 ecntrl, maccfg2; 18090751910SMingkai Hu 181063c1263SAndy Fleming if (!phydev->link) { 182063c1263SAndy Fleming printf("%s: No link.\n", phydev->dev->name); 18390751910SMingkai Hu return; 18490751910SMingkai Hu } 18590751910SMingkai Hu 18690751910SMingkai Hu /* clear all bits relative with interface mode */ 18790751910SMingkai Hu ecntrl = in_be32(®s->ecntrl); 18890751910SMingkai Hu ecntrl &= ~ECNTRL_R100; 18990751910SMingkai Hu 19090751910SMingkai Hu maccfg2 = in_be32(®s->maccfg2); 19190751910SMingkai Hu maccfg2 &= ~(MACCFG2_IF | MACCFG2_FULL_DUPLEX); 19290751910SMingkai Hu 193063c1263SAndy Fleming if (phydev->duplex) 19490751910SMingkai Hu maccfg2 |= MACCFG2_FULL_DUPLEX; 19590751910SMingkai Hu 196063c1263SAndy Fleming switch (phydev->speed) { 19790751910SMingkai Hu case 1000: 19890751910SMingkai Hu maccfg2 |= MACCFG2_GMII; 19990751910SMingkai Hu break; 20090751910SMingkai Hu case 100: 20190751910SMingkai Hu case 10: 20290751910SMingkai Hu maccfg2 |= MACCFG2_MII; 20390751910SMingkai Hu 2049872b736SBin Meng /* 2059872b736SBin Meng * Set R100 bit in all modes although 20690751910SMingkai Hu * it is only used in RGMII mode 20790751910SMingkai Hu */ 208063c1263SAndy Fleming if (phydev->speed == 100) 20990751910SMingkai Hu ecntrl |= ECNTRL_R100; 21090751910SMingkai Hu break; 21190751910SMingkai Hu default: 212063c1263SAndy Fleming printf("%s: Speed was bad\n", phydev->dev->name); 21390751910SMingkai Hu break; 21490751910SMingkai Hu } 21590751910SMingkai Hu 21690751910SMingkai Hu out_be32(®s->ecntrl, ecntrl); 21790751910SMingkai Hu out_be32(®s->maccfg2, maccfg2); 21890751910SMingkai Hu 219063c1263SAndy Fleming printf("Speed: %d, %s duplex%s\n", phydev->speed, 220063c1263SAndy Fleming (phydev->duplex) ? "full" : "half", 221063c1263SAndy Fleming (phydev->port == PORT_FIBRE) ? ", fiber mode" : ""); 22290751910SMingkai Hu } 22390751910SMingkai Hu 224aada81deSchenhui zhao #ifdef CONFIG_SYS_FSL_ERRATUM_NMG_ETSEC129 225aada81deSchenhui zhao /* 226aada81deSchenhui zhao * When MACCFG1[Rx_EN] is enabled during system boot as part 227aada81deSchenhui zhao * of the eTSEC port initialization sequence, 228aada81deSchenhui zhao * the eTSEC Rx logic may not be properly initialized. 229aada81deSchenhui zhao */ 230aada81deSchenhui zhao void redundant_init(struct eth_device *dev) 231aada81deSchenhui zhao { 232aada81deSchenhui zhao struct tsec_private *priv = dev->priv; 233aec84bf6SClaudiu Manoil struct tsec __iomem *regs = priv->regs; 234aada81deSchenhui zhao uint t, count = 0; 235aada81deSchenhui zhao int fail = 1; 236aada81deSchenhui zhao static const u8 pkt[] = { 237aada81deSchenhui zhao 0x00, 0x1e, 0x4f, 0x12, 0xcb, 0x2c, 0x00, 0x25, 238aada81deSchenhui zhao 0x64, 0xbb, 0xd1, 0xab, 0x08, 0x00, 0x45, 0x00, 239aada81deSchenhui zhao 0x00, 0x5c, 0xdd, 0x22, 0x00, 0x00, 0x80, 0x01, 240aada81deSchenhui zhao 0x1f, 0x71, 0x0a, 0xc1, 0x14, 0x22, 0x0a, 0xc1, 241aada81deSchenhui zhao 0x14, 0x6a, 0x08, 0x00, 0xef, 0x7e, 0x02, 0x00, 242aada81deSchenhui zhao 0x94, 0x05, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 243aada81deSchenhui zhao 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 244aada81deSchenhui zhao 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 245aada81deSchenhui zhao 0x77, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 246aada81deSchenhui zhao 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 247aada81deSchenhui zhao 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 248aada81deSchenhui zhao 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 249aada81deSchenhui zhao 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 250aada81deSchenhui zhao 0x71, 0x72}; 251aada81deSchenhui zhao 252aada81deSchenhui zhao /* Enable promiscuous mode */ 253aada81deSchenhui zhao setbits_be32(®s->rctrl, 0x8); 254aada81deSchenhui zhao /* Enable loopback mode */ 255aada81deSchenhui zhao setbits_be32(®s->maccfg1, MACCFG1_LOOPBACK); 256aada81deSchenhui zhao /* Enable transmit and receive */ 257aada81deSchenhui zhao setbits_be32(®s->maccfg1, MACCFG1_RX_EN | MACCFG1_TX_EN); 258aada81deSchenhui zhao 259aada81deSchenhui zhao /* Tell the DMA it is clear to go */ 260aada81deSchenhui zhao setbits_be32(®s->dmactrl, DMACTRL_INIT_SETTINGS); 261aada81deSchenhui zhao out_be32(®s->tstat, TSTAT_CLEAR_THALT); 262aada81deSchenhui zhao out_be32(®s->rstat, RSTAT_CLEAR_RHALT); 263aada81deSchenhui zhao clrbits_be32(®s->dmactrl, DMACTRL_GRS | DMACTRL_GTS); 264aada81deSchenhui zhao 265aada81deSchenhui zhao do { 2669c9141fdSClaudiu Manoil uint16_t status; 267aada81deSchenhui zhao tsec_send(dev, (void *)pkt, sizeof(pkt)); 268aada81deSchenhui zhao 269aada81deSchenhui zhao /* Wait for buffer to be received */ 270*e677da97SBin Meng for (t = 0; 271*e677da97SBin Meng in_be16(&priv->rxbd[priv->rx_idx].status) & RXBD_EMPTY; 272362b123fSBin Meng t++) { 273aada81deSchenhui zhao if (t >= 10 * TOUT_LOOP) { 274aada81deSchenhui zhao printf("%s: tsec: rx error\n", dev->name); 275aada81deSchenhui zhao break; 276aada81deSchenhui zhao } 277aada81deSchenhui zhao } 278aada81deSchenhui zhao 279362b123fSBin Meng if (!memcmp(pkt, net_rx_packets[priv->rx_idx], sizeof(pkt))) 280aada81deSchenhui zhao fail = 0; 281aada81deSchenhui zhao 282*e677da97SBin Meng out_be16(&priv->rxbd[priv->rx_idx].length, 0); 2839c9141fdSClaudiu Manoil status = RXBD_EMPTY; 284362b123fSBin Meng if ((priv->rx_idx + 1) == PKTBUFSRX) 2859c9141fdSClaudiu Manoil status |= RXBD_WRAP; 286*e677da97SBin Meng out_be16(&priv->rxbd[priv->rx_idx].status, status); 287362b123fSBin Meng priv->rx_idx = (priv->rx_idx + 1) % PKTBUFSRX; 288aada81deSchenhui zhao 289aada81deSchenhui zhao if (in_be32(®s->ievent) & IEVENT_BSY) { 290aada81deSchenhui zhao out_be32(®s->ievent, IEVENT_BSY); 291aada81deSchenhui zhao out_be32(®s->rstat, RSTAT_CLEAR_RHALT); 292aada81deSchenhui zhao } 293aada81deSchenhui zhao if (fail) { 294aada81deSchenhui zhao printf("loopback recv packet error!\n"); 295aada81deSchenhui zhao clrbits_be32(®s->maccfg1, MACCFG1_RX_EN); 296aada81deSchenhui zhao udelay(1000); 297aada81deSchenhui zhao setbits_be32(®s->maccfg1, MACCFG1_RX_EN); 298aada81deSchenhui zhao } 299aada81deSchenhui zhao } while ((count++ < 4) && (fail == 1)); 300aada81deSchenhui zhao 301aada81deSchenhui zhao if (fail) 302aada81deSchenhui zhao panic("eTSEC init fail!\n"); 303aada81deSchenhui zhao /* Disable promiscuous mode */ 304aada81deSchenhui zhao clrbits_be32(®s->rctrl, 0x8); 305aada81deSchenhui zhao /* Disable loopback mode */ 306aada81deSchenhui zhao clrbits_be32(®s->maccfg1, MACCFG1_LOOPBACK); 307aada81deSchenhui zhao } 308aada81deSchenhui zhao #endif 309aada81deSchenhui zhao 3109872b736SBin Meng /* 3119872b736SBin Meng * Set up the buffers and their descriptors, and bring up the 31290751910SMingkai Hu * interface 31390751910SMingkai Hu */ 31490751910SMingkai Hu static void startup_tsec(struct eth_device *dev) 31590751910SMingkai Hu { 31690751910SMingkai Hu struct tsec_private *priv = (struct tsec_private *)dev->priv; 317aec84bf6SClaudiu Manoil struct tsec __iomem *regs = priv->regs; 3189c9141fdSClaudiu Manoil uint16_t status; 3199c9141fdSClaudiu Manoil int i; 32090751910SMingkai Hu 321063c1263SAndy Fleming /* reset the indices to zero */ 322362b123fSBin Meng priv->rx_idx = 0; 323362b123fSBin Meng priv->tx_idx = 0; 324aada81deSchenhui zhao #ifdef CONFIG_SYS_FSL_ERRATUM_NMG_ETSEC129 325aada81deSchenhui zhao uint svr; 326aada81deSchenhui zhao #endif 327063c1263SAndy Fleming 32890751910SMingkai Hu /* Point to the buffer descriptors */ 329*e677da97SBin Meng out_be32(®s->tbase, (u32)&priv->txbd[0]); 330*e677da97SBin Meng out_be32(®s->rbase, (u32)&priv->rxbd[0]); 33190751910SMingkai Hu 33290751910SMingkai Hu /* Initialize the Rx Buffer descriptors */ 33390751910SMingkai Hu for (i = 0; i < PKTBUFSRX; i++) { 334*e677da97SBin Meng out_be16(&priv->rxbd[i].status, RXBD_EMPTY); 335*e677da97SBin Meng out_be16(&priv->rxbd[i].length, 0); 336*e677da97SBin Meng out_be32(&priv->rxbd[i].bufptr, (u32)net_rx_packets[i]); 33790751910SMingkai Hu } 338*e677da97SBin Meng status = in_be16(&priv->rxbd[PKTBUFSRX - 1].status); 339*e677da97SBin Meng out_be16(&priv->rxbd[PKTBUFSRX - 1].status, status | RXBD_WRAP); 34090751910SMingkai Hu 34190751910SMingkai Hu /* Initialize the TX Buffer Descriptors */ 34290751910SMingkai Hu for (i = 0; i < TX_BUF_CNT; i++) { 343*e677da97SBin Meng out_be16(&priv->txbd[i].status, 0); 344*e677da97SBin Meng out_be16(&priv->txbd[i].length, 0); 345*e677da97SBin Meng out_be32(&priv->txbd[i].bufptr, 0); 34690751910SMingkai Hu } 347*e677da97SBin Meng status = in_be16(&priv->txbd[TX_BUF_CNT - 1].status); 348*e677da97SBin Meng out_be16(&priv->txbd[TX_BUF_CNT - 1].status, status | TXBD_WRAP); 34990751910SMingkai Hu 350aada81deSchenhui zhao #ifdef CONFIG_SYS_FSL_ERRATUM_NMG_ETSEC129 351aada81deSchenhui zhao svr = get_svr(); 352aada81deSchenhui zhao if ((SVR_MAJ(svr) == 1) || IS_SVR_REV(svr, 2, 0)) 353aada81deSchenhui zhao redundant_init(dev); 354aada81deSchenhui zhao #endif 35590751910SMingkai Hu /* Enable Transmit and Receive */ 35690751910SMingkai Hu setbits_be32(®s->maccfg1, MACCFG1_RX_EN | MACCFG1_TX_EN); 35790751910SMingkai Hu 35890751910SMingkai Hu /* Tell the DMA it is clear to go */ 35990751910SMingkai Hu setbits_be32(®s->dmactrl, DMACTRL_INIT_SETTINGS); 36090751910SMingkai Hu out_be32(®s->tstat, TSTAT_CLEAR_THALT); 36190751910SMingkai Hu out_be32(®s->rstat, RSTAT_CLEAR_RHALT); 36290751910SMingkai Hu clrbits_be32(®s->dmactrl, DMACTRL_GRS | DMACTRL_GTS); 36390751910SMingkai Hu } 36490751910SMingkai Hu 3659872b736SBin Meng /* 3669872b736SBin Meng * This returns the status bits of the device. The return value 36790751910SMingkai Hu * is never checked, and this is what the 8260 driver did, so we 36890751910SMingkai Hu * do the same. Presumably, this would be zero if there were no 36990751910SMingkai Hu * errors 37090751910SMingkai Hu */ 371c8a60b53SJoe Hershberger static int tsec_send(struct eth_device *dev, void *packet, int length) 37290751910SMingkai Hu { 37390751910SMingkai Hu struct tsec_private *priv = (struct tsec_private *)dev->priv; 374aec84bf6SClaudiu Manoil struct tsec __iomem *regs = priv->regs; 3759c9141fdSClaudiu Manoil uint16_t status; 3769c9141fdSClaudiu Manoil int result = 0; 3779c9141fdSClaudiu Manoil int i; 37890751910SMingkai Hu 37990751910SMingkai Hu /* Find an empty buffer descriptor */ 380*e677da97SBin Meng for (i = 0; 381*e677da97SBin Meng in_be16(&priv->txbd[priv->tx_idx].status) & TXBD_READY; 382*e677da97SBin Meng i++) { 38390751910SMingkai Hu if (i >= TOUT_LOOP) { 38490751910SMingkai Hu debug("%s: tsec: tx buffers full\n", dev->name); 38590751910SMingkai Hu return result; 38690751910SMingkai Hu } 38790751910SMingkai Hu } 38890751910SMingkai Hu 389*e677da97SBin Meng out_be32(&priv->txbd[priv->tx_idx].bufptr, (u32)packet); 390*e677da97SBin Meng out_be16(&priv->txbd[priv->tx_idx].length, length); 391*e677da97SBin Meng status = in_be16(&priv->txbd[priv->tx_idx].status); 392*e677da97SBin Meng out_be16(&priv->txbd[priv->tx_idx].status, status | 3939c9141fdSClaudiu Manoil (TXBD_READY | TXBD_LAST | TXBD_CRC | TXBD_INTERRUPT)); 39490751910SMingkai Hu 39590751910SMingkai Hu /* Tell the DMA to go */ 39690751910SMingkai Hu out_be32(®s->tstat, TSTAT_CLEAR_THALT); 39790751910SMingkai Hu 39890751910SMingkai Hu /* Wait for buffer to be transmitted */ 399*e677da97SBin Meng for (i = 0; 400*e677da97SBin Meng in_be16(&priv->txbd[priv->tx_idx].status) & TXBD_READY; 401*e677da97SBin Meng i++) { 40290751910SMingkai Hu if (i >= TOUT_LOOP) { 40390751910SMingkai Hu debug("%s: tsec: tx error\n", dev->name); 40490751910SMingkai Hu return result; 40590751910SMingkai Hu } 40690751910SMingkai Hu } 40790751910SMingkai Hu 408362b123fSBin Meng priv->tx_idx = (priv->tx_idx + 1) % TX_BUF_CNT; 409*e677da97SBin Meng result = in_be16(&priv->txbd[priv->tx_idx].status) & TXBD_STATS; 41090751910SMingkai Hu 41190751910SMingkai Hu return result; 41290751910SMingkai Hu } 41390751910SMingkai Hu 41490751910SMingkai Hu static int tsec_recv(struct eth_device *dev) 41590751910SMingkai Hu { 41690751910SMingkai Hu struct tsec_private *priv = (struct tsec_private *)dev->priv; 417aec84bf6SClaudiu Manoil struct tsec __iomem *regs = priv->regs; 41890751910SMingkai Hu 419*e677da97SBin Meng while (!(in_be16(&priv->rxbd[priv->rx_idx].status) & RXBD_EMPTY)) { 420*e677da97SBin Meng int length = in_be16(&priv->rxbd[priv->rx_idx].length); 421*e677da97SBin Meng uint16_t status = in_be16(&priv->rxbd[priv->rx_idx].status); 422362b123fSBin Meng uchar *packet = net_rx_packets[priv->rx_idx]; 42390751910SMingkai Hu 42490751910SMingkai Hu /* Send the packet up if there were no errors */ 4259c9141fdSClaudiu Manoil if (!(status & RXBD_STATS)) 426362b123fSBin Meng net_process_received_packet(packet, length - 4); 4279c9141fdSClaudiu Manoil else 4289c9141fdSClaudiu Manoil printf("Got error %x\n", (status & RXBD_STATS)); 42990751910SMingkai Hu 430*e677da97SBin Meng out_be16(&priv->rxbd[priv->rx_idx].length, 0); 43190751910SMingkai Hu 4329c9141fdSClaudiu Manoil status = RXBD_EMPTY; 43390751910SMingkai Hu /* Set the wrap bit if this is the last element in the list */ 434362b123fSBin Meng if ((priv->rx_idx + 1) == PKTBUFSRX) 4359c9141fdSClaudiu Manoil status |= RXBD_WRAP; 436*e677da97SBin Meng out_be16(&priv->rxbd[priv->rx_idx].status, status); 43790751910SMingkai Hu 438362b123fSBin Meng priv->rx_idx = (priv->rx_idx + 1) % PKTBUFSRX; 43990751910SMingkai Hu } 44090751910SMingkai Hu 44190751910SMingkai Hu if (in_be32(®s->ievent) & IEVENT_BSY) { 44290751910SMingkai Hu out_be32(®s->ievent, IEVENT_BSY); 44390751910SMingkai Hu out_be32(®s->rstat, RSTAT_CLEAR_RHALT); 44490751910SMingkai Hu } 44590751910SMingkai Hu 44690751910SMingkai Hu return -1; 44790751910SMingkai Hu } 44890751910SMingkai Hu 44990751910SMingkai Hu /* Stop the interface */ 45090751910SMingkai Hu static void tsec_halt(struct eth_device *dev) 45190751910SMingkai Hu { 45290751910SMingkai Hu struct tsec_private *priv = (struct tsec_private *)dev->priv; 453aec84bf6SClaudiu Manoil struct tsec __iomem *regs = priv->regs; 45490751910SMingkai Hu 45590751910SMingkai Hu clrbits_be32(®s->dmactrl, DMACTRL_GRS | DMACTRL_GTS); 45690751910SMingkai Hu setbits_be32(®s->dmactrl, DMACTRL_GRS | DMACTRL_GTS); 45790751910SMingkai Hu 45890751910SMingkai Hu while ((in_be32(®s->ievent) & (IEVENT_GRSC | IEVENT_GTSC)) 45990751910SMingkai Hu != (IEVENT_GRSC | IEVENT_GTSC)) 46090751910SMingkai Hu ; 46190751910SMingkai Hu 46290751910SMingkai Hu clrbits_be32(®s->maccfg1, MACCFG1_TX_EN | MACCFG1_RX_EN); 46390751910SMingkai Hu 46490751910SMingkai Hu /* Shut down the PHY, as needed */ 465063c1263SAndy Fleming phy_shutdown(priv->phydev); 46690751910SMingkai Hu } 46790751910SMingkai Hu 4689872b736SBin Meng /* 4699872b736SBin Meng * Initializes data structures and registers for the controller, 47090751910SMingkai Hu * and brings the interface up. Returns the link status, meaning 47190751910SMingkai Hu * that it returns success if the link is up, failure otherwise. 4729872b736SBin Meng * This allows U-Boot to find the first active controller. 47390751910SMingkai Hu */ 47490751910SMingkai Hu static int tsec_init(struct eth_device *dev, bd_t * bd) 47590751910SMingkai Hu { 47690751910SMingkai Hu struct tsec_private *priv = (struct tsec_private *)dev->priv; 477aec84bf6SClaudiu Manoil struct tsec __iomem *regs = priv->regs; 478b1690bc3SClaudiu Manoil u32 tempval; 47911af8d65STimur Tabi int ret; 48090751910SMingkai Hu 48190751910SMingkai Hu /* Make sure the controller is stopped */ 48290751910SMingkai Hu tsec_halt(dev); 48390751910SMingkai Hu 48490751910SMingkai Hu /* Init MACCFG2. Defaults to GMII */ 48590751910SMingkai Hu out_be32(®s->maccfg2, MACCFG2_INIT_SETTINGS); 48690751910SMingkai Hu 48790751910SMingkai Hu /* Init ECNTRL */ 48890751910SMingkai Hu out_be32(®s->ecntrl, ECNTRL_INIT_SETTINGS); 48990751910SMingkai Hu 4909872b736SBin Meng /* 4919872b736SBin Meng * Copy the station address into the address registers. 492b1690bc3SClaudiu Manoil * For a station address of 0x12345678ABCD in transmission 493b1690bc3SClaudiu Manoil * order (BE), MACnADDR1 is set to 0xCDAB7856 and 494b1690bc3SClaudiu Manoil * MACnADDR2 is set to 0x34120000. 495b1690bc3SClaudiu Manoil */ 496b1690bc3SClaudiu Manoil tempval = (dev->enetaddr[5] << 24) | (dev->enetaddr[4] << 16) | 497b1690bc3SClaudiu Manoil (dev->enetaddr[3] << 8) | dev->enetaddr[2]; 49890751910SMingkai Hu 49990751910SMingkai Hu out_be32(®s->macstnaddr1, tempval); 50090751910SMingkai Hu 501b1690bc3SClaudiu Manoil tempval = (dev->enetaddr[1] << 24) | (dev->enetaddr[0] << 16); 50290751910SMingkai Hu 50390751910SMingkai Hu out_be32(®s->macstnaddr2, tempval); 50490751910SMingkai Hu 50590751910SMingkai Hu /* Clear out (for the most part) the other registers */ 50690751910SMingkai Hu init_registers(regs); 50790751910SMingkai Hu 50890751910SMingkai Hu /* Ready the device for tx/rx */ 50990751910SMingkai Hu startup_tsec(dev); 51090751910SMingkai Hu 511063c1263SAndy Fleming /* Start up the PHY */ 51211af8d65STimur Tabi ret = phy_startup(priv->phydev); 51311af8d65STimur Tabi if (ret) { 51411af8d65STimur Tabi printf("Could not initialize PHY %s\n", 51511af8d65STimur Tabi priv->phydev->dev->name); 51611af8d65STimur Tabi return ret; 51711af8d65STimur Tabi } 518063c1263SAndy Fleming 519063c1263SAndy Fleming adjust_link(priv, priv->phydev); 520063c1263SAndy Fleming 52190751910SMingkai Hu /* If there's no link, fail */ 522063c1263SAndy Fleming return priv->phydev->link ? 0 : -1; 52390751910SMingkai Hu } 52490751910SMingkai Hu 525063c1263SAndy Fleming static phy_interface_t tsec_get_interface(struct tsec_private *priv) 526063c1263SAndy Fleming { 527aec84bf6SClaudiu Manoil struct tsec __iomem *regs = priv->regs; 528063c1263SAndy Fleming u32 ecntrl; 529063c1263SAndy Fleming 530063c1263SAndy Fleming ecntrl = in_be32(®s->ecntrl); 531063c1263SAndy Fleming 532063c1263SAndy Fleming if (ecntrl & ECNTRL_SGMII_MODE) 533063c1263SAndy Fleming return PHY_INTERFACE_MODE_SGMII; 534063c1263SAndy Fleming 535063c1263SAndy Fleming if (ecntrl & ECNTRL_TBI_MODE) { 536063c1263SAndy Fleming if (ecntrl & ECNTRL_REDUCED_MODE) 537063c1263SAndy Fleming return PHY_INTERFACE_MODE_RTBI; 538063c1263SAndy Fleming else 539063c1263SAndy Fleming return PHY_INTERFACE_MODE_TBI; 540063c1263SAndy Fleming } 541063c1263SAndy Fleming 542063c1263SAndy Fleming if (ecntrl & ECNTRL_REDUCED_MODE) { 543063c1263SAndy Fleming if (ecntrl & ECNTRL_REDUCED_MII_MODE) 544063c1263SAndy Fleming return PHY_INTERFACE_MODE_RMII; 545063c1263SAndy Fleming else { 546063c1263SAndy Fleming phy_interface_t interface = priv->interface; 547063c1263SAndy Fleming 548063c1263SAndy Fleming /* 549063c1263SAndy Fleming * This isn't autodetected, so it must 550063c1263SAndy Fleming * be set by the platform code. 551063c1263SAndy Fleming */ 552063c1263SAndy Fleming if ((interface == PHY_INTERFACE_MODE_RGMII_ID) || 553063c1263SAndy Fleming (interface == PHY_INTERFACE_MODE_RGMII_TXID) || 554063c1263SAndy Fleming (interface == PHY_INTERFACE_MODE_RGMII_RXID)) 555063c1263SAndy Fleming return interface; 556063c1263SAndy Fleming 557063c1263SAndy Fleming return PHY_INTERFACE_MODE_RGMII; 558063c1263SAndy Fleming } 559063c1263SAndy Fleming } 560063c1263SAndy Fleming 561063c1263SAndy Fleming if (priv->flags & TSEC_GIGABIT) 562063c1263SAndy Fleming return PHY_INTERFACE_MODE_GMII; 563063c1263SAndy Fleming 564063c1263SAndy Fleming return PHY_INTERFACE_MODE_MII; 565063c1263SAndy Fleming } 566063c1263SAndy Fleming 5679872b736SBin Meng /* 5689872b736SBin Meng * Discover which PHY is attached to the device, and configure it 56990751910SMingkai Hu * properly. If the PHY is not recognized, then return 0 57090751910SMingkai Hu * (failure). Otherwise, return 1 57190751910SMingkai Hu */ 57290751910SMingkai Hu static int init_phy(struct eth_device *dev) 57390751910SMingkai Hu { 57490751910SMingkai Hu struct tsec_private *priv = (struct tsec_private *)dev->priv; 575063c1263SAndy Fleming struct phy_device *phydev; 576aec84bf6SClaudiu Manoil struct tsec __iomem *regs = priv->regs; 577063c1263SAndy Fleming u32 supported = (SUPPORTED_10baseT_Half | 578063c1263SAndy Fleming SUPPORTED_10baseT_Full | 579063c1263SAndy Fleming SUPPORTED_100baseT_Half | 580063c1263SAndy Fleming SUPPORTED_100baseT_Full); 581063c1263SAndy Fleming 582063c1263SAndy Fleming if (priv->flags & TSEC_GIGABIT) 583063c1263SAndy Fleming supported |= SUPPORTED_1000baseT_Full; 58490751910SMingkai Hu 58590751910SMingkai Hu /* Assign a Physical address to the TBI */ 58690751910SMingkai Hu out_be32(®s->tbipa, CONFIG_SYS_TBIPA_VALUE); 58790751910SMingkai Hu 588063c1263SAndy Fleming priv->interface = tsec_get_interface(priv); 58990751910SMingkai Hu 590063c1263SAndy Fleming if (priv->interface == PHY_INTERFACE_MODE_SGMII) 59190751910SMingkai Hu tsec_configure_serdes(priv); 59290751910SMingkai Hu 593063c1263SAndy Fleming phydev = phy_connect(priv->bus, priv->phyaddr, dev, priv->interface); 5947f233c05SClaudiu Manoil if (!phydev) 5957f233c05SClaudiu Manoil return 0; 59690751910SMingkai Hu 597063c1263SAndy Fleming phydev->supported &= supported; 598063c1263SAndy Fleming phydev->advertising = phydev->supported; 599063c1263SAndy Fleming 600063c1263SAndy Fleming priv->phydev = phydev; 601063c1263SAndy Fleming 602063c1263SAndy Fleming phy_config(phydev); 60390751910SMingkai Hu 60490751910SMingkai Hu return 1; 60590751910SMingkai Hu } 60690751910SMingkai Hu 6079872b736SBin Meng /* 6089872b736SBin Meng * Initialize device structure. Returns success if PHY 60990751910SMingkai Hu * initialization succeeded (i.e. if it recognizes the PHY) 61090751910SMingkai Hu */ 61190751910SMingkai Hu static int tsec_initialize(bd_t *bis, struct tsec_info_struct *tsec_info) 61290751910SMingkai Hu { 61390751910SMingkai Hu struct eth_device *dev; 61490751910SMingkai Hu int i; 61590751910SMingkai Hu struct tsec_private *priv; 61690751910SMingkai Hu 61790751910SMingkai Hu dev = (struct eth_device *)malloc(sizeof *dev); 61890751910SMingkai Hu 61990751910SMingkai Hu if (NULL == dev) 62090751910SMingkai Hu return 0; 62190751910SMingkai Hu 62290751910SMingkai Hu memset(dev, 0, sizeof *dev); 62390751910SMingkai Hu 62490751910SMingkai Hu priv = (struct tsec_private *)malloc(sizeof(*priv)); 62590751910SMingkai Hu 62690751910SMingkai Hu if (NULL == priv) 62790751910SMingkai Hu return 0; 62890751910SMingkai Hu 62990751910SMingkai Hu priv->regs = tsec_info->regs; 63090751910SMingkai Hu priv->phyregs_sgmii = tsec_info->miiregs_sgmii; 63190751910SMingkai Hu 63290751910SMingkai Hu priv->phyaddr = tsec_info->phyaddr; 63390751910SMingkai Hu priv->flags = tsec_info->flags; 63490751910SMingkai Hu 63590751910SMingkai Hu sprintf(dev->name, tsec_info->devname); 636063c1263SAndy Fleming priv->interface = tsec_info->interface; 637063c1263SAndy Fleming priv->bus = miiphy_get_dev_by_name(tsec_info->mii_devname); 63890751910SMingkai Hu dev->iobase = 0; 63990751910SMingkai Hu dev->priv = priv; 64090751910SMingkai Hu dev->init = tsec_init; 64190751910SMingkai Hu dev->halt = tsec_halt; 64290751910SMingkai Hu dev->send = tsec_send; 64390751910SMingkai Hu dev->recv = tsec_recv; 64490751910SMingkai Hu #ifdef CONFIG_MCAST_TFTP 64590751910SMingkai Hu dev->mcast = tsec_mcast_addr; 64690751910SMingkai Hu #endif 64790751910SMingkai Hu 6489872b736SBin Meng /* Tell U-Boot to get the addr from the env */ 64990751910SMingkai Hu for (i = 0; i < 6; i++) 65090751910SMingkai Hu dev->enetaddr[i] = 0; 65190751910SMingkai Hu 65290751910SMingkai Hu eth_register(dev); 65390751910SMingkai Hu 65490751910SMingkai Hu /* Reset the MAC */ 65590751910SMingkai Hu setbits_be32(&priv->regs->maccfg1, MACCFG1_SOFT_RESET); 65690751910SMingkai Hu udelay(2); /* Soft Reset must be asserted for 3 TX clocks */ 65790751910SMingkai Hu clrbits_be32(&priv->regs->maccfg1, MACCFG1_SOFT_RESET); 65890751910SMingkai Hu 65990751910SMingkai Hu /* Try to initialize PHY here, and return */ 66090751910SMingkai Hu return init_phy(dev); 66190751910SMingkai Hu } 66290751910SMingkai Hu 66390751910SMingkai Hu /* 66490751910SMingkai Hu * Initialize all the TSEC devices 66590751910SMingkai Hu * 66690751910SMingkai Hu * Returns the number of TSEC devices that were initialized 66790751910SMingkai Hu */ 66890751910SMingkai Hu int tsec_eth_init(bd_t *bis, struct tsec_info_struct *tsecs, int num) 66990751910SMingkai Hu { 67090751910SMingkai Hu int i; 67190751910SMingkai Hu int ret, count = 0; 67290751910SMingkai Hu 67390751910SMingkai Hu for (i = 0; i < num; i++) { 67490751910SMingkai Hu ret = tsec_initialize(bis, &tsecs[i]); 67590751910SMingkai Hu if (ret > 0) 67690751910SMingkai Hu count += ret; 67790751910SMingkai Hu } 67890751910SMingkai Hu 67990751910SMingkai Hu return count; 68090751910SMingkai Hu } 68190751910SMingkai Hu 68290751910SMingkai Hu int tsec_standard_init(bd_t *bis) 68390751910SMingkai Hu { 684063c1263SAndy Fleming struct fsl_pq_mdio_info info; 685063c1263SAndy Fleming 686aec84bf6SClaudiu Manoil info.regs = TSEC_GET_MDIO_REGS_BASE(1); 687063c1263SAndy Fleming info.name = DEFAULT_MII_NAME; 688063c1263SAndy Fleming 689063c1263SAndy Fleming fsl_pq_mdio_init(bis, &info); 690063c1263SAndy Fleming 69190751910SMingkai Hu return tsec_eth_init(bis, tsec_info, ARRAY_SIZE(tsec_info)); 69290751910SMingkai Hu } 693