12439e4bfSJean-Christophe PLAGNIOL-VILLARD /* 22439e4bfSJean-Christophe PLAGNIOL-VILLARD * Freescale Three Speed Ethernet Controller driver 32439e4bfSJean-Christophe PLAGNIOL-VILLARD * 42439e4bfSJean-Christophe PLAGNIOL-VILLARD * This software may be used and distributed according to the 52439e4bfSJean-Christophe PLAGNIOL-VILLARD * terms of the GNU Public License, Version 2, incorporated 62439e4bfSJean-Christophe PLAGNIOL-VILLARD * herein by reference. 72439e4bfSJean-Christophe PLAGNIOL-VILLARD * 8aec84bf6SClaudiu Manoil * Copyright 2004-2011, 2013 Freescale Semiconductor, Inc. 92439e4bfSJean-Christophe PLAGNIOL-VILLARD * (C) Copyright 2003, Motorola, Inc. 102439e4bfSJean-Christophe PLAGNIOL-VILLARD * author Andy Fleming 112439e4bfSJean-Christophe PLAGNIOL-VILLARD * 122439e4bfSJean-Christophe PLAGNIOL-VILLARD */ 132439e4bfSJean-Christophe PLAGNIOL-VILLARD 142439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <config.h> 152439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <common.h> 162439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <malloc.h> 172439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <net.h> 182439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <command.h> 19dd3d1f56SAndy Fleming #include <tsec.h> 20063c1263SAndy Fleming #include <fsl_mdio.h> 210d071cddSKim Phillips #include <asm/errno.h> 22aada81deSchenhui zhao #include <asm/processor.h> 232439e4bfSJean-Christophe PLAGNIOL-VILLARD 242439e4bfSJean-Christophe PLAGNIOL-VILLARD DECLARE_GLOBAL_DATA_PTR; 252439e4bfSJean-Christophe PLAGNIOL-VILLARD 262439e4bfSJean-Christophe PLAGNIOL-VILLARD #define TX_BUF_CNT 2 272439e4bfSJean-Christophe PLAGNIOL-VILLARD 28*18b338fbSClaudiu Manoil static uint rx_idx; /* index of the current RX buffer */ 29*18b338fbSClaudiu Manoil static uint tx_idx; /* index of the current TX buffer */ 302439e4bfSJean-Christophe PLAGNIOL-VILLARD 312439e4bfSJean-Christophe PLAGNIOL-VILLARD typedef volatile struct rtxbd { 322439e4bfSJean-Christophe PLAGNIOL-VILLARD txbd8_t txbd[TX_BUF_CNT]; 332439e4bfSJean-Christophe PLAGNIOL-VILLARD rxbd8_t rxbd[PKTBUFSRX]; 342439e4bfSJean-Christophe PLAGNIOL-VILLARD } RTXBD; 352439e4bfSJean-Christophe PLAGNIOL-VILLARD 362439e4bfSJean-Christophe PLAGNIOL-VILLARD #ifdef __GNUC__ 372439e4bfSJean-Christophe PLAGNIOL-VILLARD static RTXBD rtx __attribute__ ((aligned(8))); 382439e4bfSJean-Christophe PLAGNIOL-VILLARD #else 392439e4bfSJean-Christophe PLAGNIOL-VILLARD #error "rtx must be 64-bit aligned" 402439e4bfSJean-Christophe PLAGNIOL-VILLARD #endif 412439e4bfSJean-Christophe PLAGNIOL-VILLARD 42c8a60b53SJoe Hershberger static int tsec_send(struct eth_device *dev, void *packet, int length); 43aada81deSchenhui zhao 4475b9d4aeSAndy Fleming /* Default initializations for TSEC controllers. */ 4575b9d4aeSAndy Fleming 4675b9d4aeSAndy Fleming static struct tsec_info_struct tsec_info[] = { 4775b9d4aeSAndy Fleming #ifdef CONFIG_TSEC1 4875b9d4aeSAndy Fleming STD_TSEC_INFO(1), /* TSEC1 */ 4975b9d4aeSAndy Fleming #endif 5075b9d4aeSAndy Fleming #ifdef CONFIG_TSEC2 5175b9d4aeSAndy Fleming STD_TSEC_INFO(2), /* TSEC2 */ 5275b9d4aeSAndy Fleming #endif 5375b9d4aeSAndy Fleming #ifdef CONFIG_MPC85XX_FEC 5475b9d4aeSAndy Fleming { 55aec84bf6SClaudiu Manoil .regs = TSEC_GET_REGS(2, 0x2000), 5675b9d4aeSAndy Fleming .devname = CONFIG_MPC85XX_FEC_NAME, 5775b9d4aeSAndy Fleming .phyaddr = FEC_PHY_ADDR, 58063c1263SAndy Fleming .flags = FEC_FLAGS, 59063c1263SAndy Fleming .mii_devname = DEFAULT_MII_NAME 6075b9d4aeSAndy Fleming }, /* FEC */ 6175b9d4aeSAndy Fleming #endif 6275b9d4aeSAndy Fleming #ifdef CONFIG_TSEC3 6375b9d4aeSAndy Fleming STD_TSEC_INFO(3), /* TSEC3 */ 6475b9d4aeSAndy Fleming #endif 6575b9d4aeSAndy Fleming #ifdef CONFIG_TSEC4 6675b9d4aeSAndy Fleming STD_TSEC_INFO(4), /* TSEC4 */ 6775b9d4aeSAndy Fleming #endif 6875b9d4aeSAndy Fleming }; 6975b9d4aeSAndy Fleming 702abe361cSAndy Fleming #define TBIANA_SETTINGS ( \ 712abe361cSAndy Fleming TBIANA_ASYMMETRIC_PAUSE \ 722abe361cSAndy Fleming | TBIANA_SYMMETRIC_PAUSE \ 732abe361cSAndy Fleming | TBIANA_FULL_DUPLEX \ 742abe361cSAndy Fleming ) 752abe361cSAndy Fleming 7690b5bf21SFelix Radensky /* By default force the TBI PHY into 1000Mbps full duplex when in SGMII mode */ 7790b5bf21SFelix Radensky #ifndef CONFIG_TSEC_TBICR_SETTINGS 7872c96a68SKumar Gala #define CONFIG_TSEC_TBICR_SETTINGS ( \ 792abe361cSAndy Fleming TBICR_PHY_RESET \ 8072c96a68SKumar Gala | TBICR_ANEG_ENABLE \ 812abe361cSAndy Fleming | TBICR_FULL_DUPLEX \ 822abe361cSAndy Fleming | TBICR_SPEED1_SET \ 832abe361cSAndy Fleming ) 8490b5bf21SFelix Radensky #endif /* CONFIG_TSEC_TBICR_SETTINGS */ 8546e91674SPeter Tyser 862abe361cSAndy Fleming /* Configure the TBI for SGMII operation */ 872abe361cSAndy Fleming static void tsec_configure_serdes(struct tsec_private *priv) 882abe361cSAndy Fleming { 89c6dbdfdaSPeter Tyser /* Access TBI PHY registers at given TSEC register offset as opposed 90c6dbdfdaSPeter Tyser * to the register offset used for external PHY accesses */ 91063c1263SAndy Fleming tsec_local_mdio_write(priv->phyregs_sgmii, in_be32(&priv->regs->tbipa), 92063c1263SAndy Fleming 0, TBI_ANA, TBIANA_SETTINGS); 93063c1263SAndy Fleming tsec_local_mdio_write(priv->phyregs_sgmii, in_be32(&priv->regs->tbipa), 94063c1263SAndy Fleming 0, TBI_TBICON, TBICON_CLK_SELECT); 95063c1263SAndy Fleming tsec_local_mdio_write(priv->phyregs_sgmii, in_be32(&priv->regs->tbipa), 96063c1263SAndy Fleming 0, TBI_CR, CONFIG_TSEC_TBICR_SETTINGS); 972439e4bfSJean-Christophe PLAGNIOL-VILLARD } 982439e4bfSJean-Christophe PLAGNIOL-VILLARD 992439e4bfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_MCAST_TFTP 1002439e4bfSJean-Christophe PLAGNIOL-VILLARD 1012439e4bfSJean-Christophe PLAGNIOL-VILLARD /* CREDITS: linux gianfar driver, slightly adjusted... thanx. */ 1022439e4bfSJean-Christophe PLAGNIOL-VILLARD 1032439e4bfSJean-Christophe PLAGNIOL-VILLARD /* Set the appropriate hash bit for the given addr */ 1042439e4bfSJean-Christophe PLAGNIOL-VILLARD 1052439e4bfSJean-Christophe PLAGNIOL-VILLARD /* The algorithm works like so: 1062439e4bfSJean-Christophe PLAGNIOL-VILLARD * 1) Take the Destination Address (ie the multicast address), and 1072439e4bfSJean-Christophe PLAGNIOL-VILLARD * do a CRC on it (little endian), and reverse the bits of the 1082439e4bfSJean-Christophe PLAGNIOL-VILLARD * result. 1092439e4bfSJean-Christophe PLAGNIOL-VILLARD * 2) Use the 8 most significant bits as a hash into a 256-entry 1102439e4bfSJean-Christophe PLAGNIOL-VILLARD * table. The table is controlled through 8 32-bit registers: 111876d4515SClaudiu Manoil * gaddr0-7. gaddr0's MSB is entry 0, and gaddr7's LSB is entry 112876d4515SClaudiu Manoil * 255. This means that the 3 most significant bits in the 1132439e4bfSJean-Christophe PLAGNIOL-VILLARD * hash index which gaddr register to use, and the 5 other bits 1142439e4bfSJean-Christophe PLAGNIOL-VILLARD * indicate which bit (assuming an IBM numbering scheme, which 115876d4515SClaudiu Manoil * for PowerPC (tm) is usually the case) in the register holds 1162439e4bfSJean-Christophe PLAGNIOL-VILLARD * the entry. */ 1172439e4bfSJean-Christophe PLAGNIOL-VILLARD static int 1189c4cffacSClaudiu Manoil tsec_mcast_addr(struct eth_device *dev, const u8 *mcast_mac, u8 set) 1192439e4bfSJean-Christophe PLAGNIOL-VILLARD { 120b200204eSClaudiu Manoil struct tsec_private *priv = (struct tsec_private *)dev->priv; 121876d4515SClaudiu Manoil struct tsec __iomem *regs = priv->regs; 122876d4515SClaudiu Manoil u32 result, value; 123876d4515SClaudiu Manoil u8 whichbit, whichreg; 1242439e4bfSJean-Christophe PLAGNIOL-VILLARD 125876d4515SClaudiu Manoil result = ether_crc(MAC_ADDR_LEN, mcast_mac); 126876d4515SClaudiu Manoil whichbit = (result >> 24) & 0x1f; /* the 5 LSB = which bit to set */ 127876d4515SClaudiu Manoil whichreg = result >> 29; /* the 3 MSB = which reg to set it in */ 1282439e4bfSJean-Christophe PLAGNIOL-VILLARD 129876d4515SClaudiu Manoil value = 1 << (31-whichbit); 1302439e4bfSJean-Christophe PLAGNIOL-VILLARD 131876d4515SClaudiu Manoil if (set) 132876d4515SClaudiu Manoil setbits_be32(®s->hash.gaddr0 + whichreg, value); 133876d4515SClaudiu Manoil else 134876d4515SClaudiu Manoil clrbits_be32(®s->hash.gaddr0 + whichreg, value); 135876d4515SClaudiu Manoil 1362439e4bfSJean-Christophe PLAGNIOL-VILLARD return 0; 1372439e4bfSJean-Christophe PLAGNIOL-VILLARD } 1382439e4bfSJean-Christophe PLAGNIOL-VILLARD #endif /* Multicast TFTP ? */ 13990751910SMingkai Hu 14090751910SMingkai Hu /* Initialized required registers to appropriate values, zeroing 14190751910SMingkai Hu * those we don't care about (unless zero is bad, in which case, 14290751910SMingkai Hu * choose a more appropriate value) 14390751910SMingkai Hu */ 144aec84bf6SClaudiu Manoil static void init_registers(struct tsec __iomem *regs) 14590751910SMingkai Hu { 14690751910SMingkai Hu /* Clear IEVENT */ 14790751910SMingkai Hu out_be32(®s->ievent, IEVENT_INIT_CLEAR); 14890751910SMingkai Hu 14990751910SMingkai Hu out_be32(®s->imask, IMASK_INIT_CLEAR); 15090751910SMingkai Hu 15190751910SMingkai Hu out_be32(®s->hash.iaddr0, 0); 15290751910SMingkai Hu out_be32(®s->hash.iaddr1, 0); 15390751910SMingkai Hu out_be32(®s->hash.iaddr2, 0); 15490751910SMingkai Hu out_be32(®s->hash.iaddr3, 0); 15590751910SMingkai Hu out_be32(®s->hash.iaddr4, 0); 15690751910SMingkai Hu out_be32(®s->hash.iaddr5, 0); 15790751910SMingkai Hu out_be32(®s->hash.iaddr6, 0); 15890751910SMingkai Hu out_be32(®s->hash.iaddr7, 0); 15990751910SMingkai Hu 16090751910SMingkai Hu out_be32(®s->hash.gaddr0, 0); 16190751910SMingkai Hu out_be32(®s->hash.gaddr1, 0); 16290751910SMingkai Hu out_be32(®s->hash.gaddr2, 0); 16390751910SMingkai Hu out_be32(®s->hash.gaddr3, 0); 16490751910SMingkai Hu out_be32(®s->hash.gaddr4, 0); 16590751910SMingkai Hu out_be32(®s->hash.gaddr5, 0); 16690751910SMingkai Hu out_be32(®s->hash.gaddr6, 0); 16790751910SMingkai Hu out_be32(®s->hash.gaddr7, 0); 16890751910SMingkai Hu 16990751910SMingkai Hu out_be32(®s->rctrl, 0x00000000); 17090751910SMingkai Hu 17190751910SMingkai Hu /* Init RMON mib registers */ 17290751910SMingkai Hu memset((void *)&(regs->rmon), 0, sizeof(rmon_mib_t)); 17390751910SMingkai Hu 17490751910SMingkai Hu out_be32(®s->rmon.cam1, 0xffffffff); 17590751910SMingkai Hu out_be32(®s->rmon.cam2, 0xffffffff); 17690751910SMingkai Hu 17790751910SMingkai Hu out_be32(®s->mrblr, MRBLR_INIT_SETTINGS); 17890751910SMingkai Hu 17990751910SMingkai Hu out_be32(®s->minflr, MINFLR_INIT_SETTINGS); 18090751910SMingkai Hu 18190751910SMingkai Hu out_be32(®s->attr, ATTR_INIT_SETTINGS); 18290751910SMingkai Hu out_be32(®s->attreli, ATTRELI_INIT_SETTINGS); 18390751910SMingkai Hu 18490751910SMingkai Hu } 18590751910SMingkai Hu 18690751910SMingkai Hu /* Configure maccfg2 based on negotiated speed and duplex 18790751910SMingkai Hu * reported by PHY handling code 18890751910SMingkai Hu */ 189063c1263SAndy Fleming static void adjust_link(struct tsec_private *priv, struct phy_device *phydev) 19090751910SMingkai Hu { 191aec84bf6SClaudiu Manoil struct tsec __iomem *regs = priv->regs; 19290751910SMingkai Hu u32 ecntrl, maccfg2; 19390751910SMingkai Hu 194063c1263SAndy Fleming if (!phydev->link) { 195063c1263SAndy Fleming printf("%s: No link.\n", phydev->dev->name); 19690751910SMingkai Hu return; 19790751910SMingkai Hu } 19890751910SMingkai Hu 19990751910SMingkai Hu /* clear all bits relative with interface mode */ 20090751910SMingkai Hu ecntrl = in_be32(®s->ecntrl); 20190751910SMingkai Hu ecntrl &= ~ECNTRL_R100; 20290751910SMingkai Hu 20390751910SMingkai Hu maccfg2 = in_be32(®s->maccfg2); 20490751910SMingkai Hu maccfg2 &= ~(MACCFG2_IF | MACCFG2_FULL_DUPLEX); 20590751910SMingkai Hu 206063c1263SAndy Fleming if (phydev->duplex) 20790751910SMingkai Hu maccfg2 |= MACCFG2_FULL_DUPLEX; 20890751910SMingkai Hu 209063c1263SAndy Fleming switch (phydev->speed) { 21090751910SMingkai Hu case 1000: 21190751910SMingkai Hu maccfg2 |= MACCFG2_GMII; 21290751910SMingkai Hu break; 21390751910SMingkai Hu case 100: 21490751910SMingkai Hu case 10: 21590751910SMingkai Hu maccfg2 |= MACCFG2_MII; 21690751910SMingkai Hu 21790751910SMingkai Hu /* Set R100 bit in all modes although 21890751910SMingkai Hu * it is only used in RGMII mode 21990751910SMingkai Hu */ 220063c1263SAndy Fleming if (phydev->speed == 100) 22190751910SMingkai Hu ecntrl |= ECNTRL_R100; 22290751910SMingkai Hu break; 22390751910SMingkai Hu default: 224063c1263SAndy Fleming printf("%s: Speed was bad\n", phydev->dev->name); 22590751910SMingkai Hu break; 22690751910SMingkai Hu } 22790751910SMingkai Hu 22890751910SMingkai Hu out_be32(®s->ecntrl, ecntrl); 22990751910SMingkai Hu out_be32(®s->maccfg2, maccfg2); 23090751910SMingkai Hu 231063c1263SAndy Fleming printf("Speed: %d, %s duplex%s\n", phydev->speed, 232063c1263SAndy Fleming (phydev->duplex) ? "full" : "half", 233063c1263SAndy Fleming (phydev->port == PORT_FIBRE) ? ", fiber mode" : ""); 23490751910SMingkai Hu } 23590751910SMingkai Hu 236aada81deSchenhui zhao #ifdef CONFIG_SYS_FSL_ERRATUM_NMG_ETSEC129 237aada81deSchenhui zhao /* 238aada81deSchenhui zhao * When MACCFG1[Rx_EN] is enabled during system boot as part 239aada81deSchenhui zhao * of the eTSEC port initialization sequence, 240aada81deSchenhui zhao * the eTSEC Rx logic may not be properly initialized. 241aada81deSchenhui zhao */ 242aada81deSchenhui zhao void redundant_init(struct eth_device *dev) 243aada81deSchenhui zhao { 244aada81deSchenhui zhao struct tsec_private *priv = dev->priv; 245aec84bf6SClaudiu Manoil struct tsec __iomem *regs = priv->regs; 246aada81deSchenhui zhao uint t, count = 0; 247aada81deSchenhui zhao int fail = 1; 248aada81deSchenhui zhao static const u8 pkt[] = { 249aada81deSchenhui zhao 0x00, 0x1e, 0x4f, 0x12, 0xcb, 0x2c, 0x00, 0x25, 250aada81deSchenhui zhao 0x64, 0xbb, 0xd1, 0xab, 0x08, 0x00, 0x45, 0x00, 251aada81deSchenhui zhao 0x00, 0x5c, 0xdd, 0x22, 0x00, 0x00, 0x80, 0x01, 252aada81deSchenhui zhao 0x1f, 0x71, 0x0a, 0xc1, 0x14, 0x22, 0x0a, 0xc1, 253aada81deSchenhui zhao 0x14, 0x6a, 0x08, 0x00, 0xef, 0x7e, 0x02, 0x00, 254aada81deSchenhui zhao 0x94, 0x05, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 255aada81deSchenhui zhao 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 256aada81deSchenhui zhao 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 257aada81deSchenhui zhao 0x77, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 258aada81deSchenhui zhao 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 259aada81deSchenhui zhao 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 260aada81deSchenhui zhao 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 261aada81deSchenhui zhao 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 262aada81deSchenhui zhao 0x71, 0x72}; 263aada81deSchenhui zhao 264aada81deSchenhui zhao /* Enable promiscuous mode */ 265aada81deSchenhui zhao setbits_be32(®s->rctrl, 0x8); 266aada81deSchenhui zhao /* Enable loopback mode */ 267aada81deSchenhui zhao setbits_be32(®s->maccfg1, MACCFG1_LOOPBACK); 268aada81deSchenhui zhao /* Enable transmit and receive */ 269aada81deSchenhui zhao setbits_be32(®s->maccfg1, MACCFG1_RX_EN | MACCFG1_TX_EN); 270aada81deSchenhui zhao 271aada81deSchenhui zhao /* Tell the DMA it is clear to go */ 272aada81deSchenhui zhao setbits_be32(®s->dmactrl, DMACTRL_INIT_SETTINGS); 273aada81deSchenhui zhao out_be32(®s->tstat, TSTAT_CLEAR_THALT); 274aada81deSchenhui zhao out_be32(®s->rstat, RSTAT_CLEAR_RHALT); 275aada81deSchenhui zhao clrbits_be32(®s->dmactrl, DMACTRL_GRS | DMACTRL_GTS); 276aada81deSchenhui zhao 277aada81deSchenhui zhao do { 278aada81deSchenhui zhao tsec_send(dev, (void *)pkt, sizeof(pkt)); 279aada81deSchenhui zhao 280aada81deSchenhui zhao /* Wait for buffer to be received */ 281*18b338fbSClaudiu Manoil for (t = 0; rtx.rxbd[rx_idx].status & RXBD_EMPTY; t++) { 282aada81deSchenhui zhao if (t >= 10 * TOUT_LOOP) { 283aada81deSchenhui zhao printf("%s: tsec: rx error\n", dev->name); 284aada81deSchenhui zhao break; 285aada81deSchenhui zhao } 286aada81deSchenhui zhao } 287aada81deSchenhui zhao 288*18b338fbSClaudiu Manoil if (!memcmp(pkt, (void *)NetRxPackets[rx_idx], sizeof(pkt))) 289aada81deSchenhui zhao fail = 0; 290aada81deSchenhui zhao 291*18b338fbSClaudiu Manoil rtx.rxbd[rx_idx].length = 0; 292*18b338fbSClaudiu Manoil rtx.rxbd[rx_idx].status = 293*18b338fbSClaudiu Manoil RXBD_EMPTY | (((rx_idx + 1) == PKTBUFSRX) ? RXBD_WRAP : 0); 294*18b338fbSClaudiu Manoil rx_idx = (rx_idx + 1) % PKTBUFSRX; 295aada81deSchenhui zhao 296aada81deSchenhui zhao if (in_be32(®s->ievent) & IEVENT_BSY) { 297aada81deSchenhui zhao out_be32(®s->ievent, IEVENT_BSY); 298aada81deSchenhui zhao out_be32(®s->rstat, RSTAT_CLEAR_RHALT); 299aada81deSchenhui zhao } 300aada81deSchenhui zhao if (fail) { 301aada81deSchenhui zhao printf("loopback recv packet error!\n"); 302aada81deSchenhui zhao clrbits_be32(®s->maccfg1, MACCFG1_RX_EN); 303aada81deSchenhui zhao udelay(1000); 304aada81deSchenhui zhao setbits_be32(®s->maccfg1, MACCFG1_RX_EN); 305aada81deSchenhui zhao } 306aada81deSchenhui zhao } while ((count++ < 4) && (fail == 1)); 307aada81deSchenhui zhao 308aada81deSchenhui zhao if (fail) 309aada81deSchenhui zhao panic("eTSEC init fail!\n"); 310aada81deSchenhui zhao /* Disable promiscuous mode */ 311aada81deSchenhui zhao clrbits_be32(®s->rctrl, 0x8); 312aada81deSchenhui zhao /* Disable loopback mode */ 313aada81deSchenhui zhao clrbits_be32(®s->maccfg1, MACCFG1_LOOPBACK); 314aada81deSchenhui zhao } 315aada81deSchenhui zhao #endif 316aada81deSchenhui zhao 31790751910SMingkai Hu /* Set up the buffers and their descriptors, and bring up the 31890751910SMingkai Hu * interface 31990751910SMingkai Hu */ 32090751910SMingkai Hu static void startup_tsec(struct eth_device *dev) 32190751910SMingkai Hu { 32290751910SMingkai Hu int i; 32390751910SMingkai Hu struct tsec_private *priv = (struct tsec_private *)dev->priv; 324aec84bf6SClaudiu Manoil struct tsec __iomem *regs = priv->regs; 32590751910SMingkai Hu 326063c1263SAndy Fleming /* reset the indices to zero */ 327*18b338fbSClaudiu Manoil rx_idx = 0; 328*18b338fbSClaudiu Manoil tx_idx = 0; 329aada81deSchenhui zhao #ifdef CONFIG_SYS_FSL_ERRATUM_NMG_ETSEC129 330aada81deSchenhui zhao uint svr; 331aada81deSchenhui zhao #endif 332063c1263SAndy Fleming 33390751910SMingkai Hu /* Point to the buffer descriptors */ 334*18b338fbSClaudiu Manoil out_be32(®s->tbase, (unsigned int)(&rtx.txbd[tx_idx])); 335*18b338fbSClaudiu Manoil out_be32(®s->rbase, (unsigned int)(&rtx.rxbd[rx_idx])); 33690751910SMingkai Hu 33790751910SMingkai Hu /* Initialize the Rx Buffer descriptors */ 33890751910SMingkai Hu for (i = 0; i < PKTBUFSRX; i++) { 33990751910SMingkai Hu rtx.rxbd[i].status = RXBD_EMPTY; 34090751910SMingkai Hu rtx.rxbd[i].length = 0; 341*18b338fbSClaudiu Manoil rtx.rxbd[i].bufptr = (uint) NetRxPackets[i]; 34290751910SMingkai Hu } 34390751910SMingkai Hu rtx.rxbd[PKTBUFSRX - 1].status |= RXBD_WRAP; 34490751910SMingkai Hu 34590751910SMingkai Hu /* Initialize the TX Buffer Descriptors */ 34690751910SMingkai Hu for (i = 0; i < TX_BUF_CNT; i++) { 34790751910SMingkai Hu rtx.txbd[i].status = 0; 34890751910SMingkai Hu rtx.txbd[i].length = 0; 349*18b338fbSClaudiu Manoil rtx.txbd[i].bufptr = 0; 35090751910SMingkai Hu } 35190751910SMingkai Hu rtx.txbd[TX_BUF_CNT - 1].status |= TXBD_WRAP; 35290751910SMingkai Hu 353aada81deSchenhui zhao #ifdef CONFIG_SYS_FSL_ERRATUM_NMG_ETSEC129 354aada81deSchenhui zhao svr = get_svr(); 355aada81deSchenhui zhao if ((SVR_MAJ(svr) == 1) || IS_SVR_REV(svr, 2, 0)) 356aada81deSchenhui zhao redundant_init(dev); 357aada81deSchenhui zhao #endif 35890751910SMingkai Hu /* Enable Transmit and Receive */ 35990751910SMingkai Hu setbits_be32(®s->maccfg1, MACCFG1_RX_EN | MACCFG1_TX_EN); 36090751910SMingkai Hu 36190751910SMingkai Hu /* Tell the DMA it is clear to go */ 36290751910SMingkai Hu setbits_be32(®s->dmactrl, DMACTRL_INIT_SETTINGS); 36390751910SMingkai Hu out_be32(®s->tstat, TSTAT_CLEAR_THALT); 36490751910SMingkai Hu out_be32(®s->rstat, RSTAT_CLEAR_RHALT); 36590751910SMingkai Hu clrbits_be32(®s->dmactrl, DMACTRL_GRS | DMACTRL_GTS); 36690751910SMingkai Hu } 36790751910SMingkai Hu 36890751910SMingkai Hu /* This returns the status bits of the device. The return value 36990751910SMingkai Hu * is never checked, and this is what the 8260 driver did, so we 37090751910SMingkai Hu * do the same. Presumably, this would be zero if there were no 37190751910SMingkai Hu * errors 37290751910SMingkai Hu */ 373c8a60b53SJoe Hershberger static int tsec_send(struct eth_device *dev, void *packet, int length) 37490751910SMingkai Hu { 37590751910SMingkai Hu int i; 37690751910SMingkai Hu int result = 0; 37790751910SMingkai Hu struct tsec_private *priv = (struct tsec_private *)dev->priv; 378aec84bf6SClaudiu Manoil struct tsec __iomem *regs = priv->regs; 37990751910SMingkai Hu 38090751910SMingkai Hu /* Find an empty buffer descriptor */ 381*18b338fbSClaudiu Manoil for (i = 0; rtx.txbd[tx_idx].status & TXBD_READY; i++) { 38290751910SMingkai Hu if (i >= TOUT_LOOP) { 38390751910SMingkai Hu debug("%s: tsec: tx buffers full\n", dev->name); 38490751910SMingkai Hu return result; 38590751910SMingkai Hu } 38690751910SMingkai Hu } 38790751910SMingkai Hu 388*18b338fbSClaudiu Manoil rtx.txbd[tx_idx].bufptr = (uint) packet; 389*18b338fbSClaudiu Manoil rtx.txbd[tx_idx].length = length; 390*18b338fbSClaudiu Manoil rtx.txbd[tx_idx].status |= 39190751910SMingkai Hu (TXBD_READY | TXBD_LAST | TXBD_CRC | TXBD_INTERRUPT); 39290751910SMingkai Hu 39390751910SMingkai Hu /* Tell the DMA to go */ 39490751910SMingkai Hu out_be32(®s->tstat, TSTAT_CLEAR_THALT); 39590751910SMingkai Hu 39690751910SMingkai Hu /* Wait for buffer to be transmitted */ 397*18b338fbSClaudiu Manoil for (i = 0; rtx.txbd[tx_idx].status & TXBD_READY; i++) { 39890751910SMingkai Hu if (i >= TOUT_LOOP) { 39990751910SMingkai Hu debug("%s: tsec: tx error\n", dev->name); 40090751910SMingkai Hu return result; 40190751910SMingkai Hu } 40290751910SMingkai Hu } 40390751910SMingkai Hu 404*18b338fbSClaudiu Manoil tx_idx = (tx_idx + 1) % TX_BUF_CNT; 405*18b338fbSClaudiu Manoil result = rtx.txbd[tx_idx].status & TXBD_STATS; 40690751910SMingkai Hu 40790751910SMingkai Hu return result; 40890751910SMingkai Hu } 40990751910SMingkai Hu 41090751910SMingkai Hu static int tsec_recv(struct eth_device *dev) 41190751910SMingkai Hu { 41290751910SMingkai Hu int length; 41390751910SMingkai Hu struct tsec_private *priv = (struct tsec_private *)dev->priv; 414aec84bf6SClaudiu Manoil struct tsec __iomem *regs = priv->regs; 41590751910SMingkai Hu 416*18b338fbSClaudiu Manoil while (!(rtx.rxbd[rx_idx].status & RXBD_EMPTY)) { 41790751910SMingkai Hu 418*18b338fbSClaudiu Manoil length = rtx.rxbd[rx_idx].length; 41990751910SMingkai Hu 42090751910SMingkai Hu /* Send the packet up if there were no errors */ 421*18b338fbSClaudiu Manoil if (!(rtx.rxbd[rx_idx].status & RXBD_STATS)) { 422*18b338fbSClaudiu Manoil NetReceive(NetRxPackets[rx_idx], length - 4); 42390751910SMingkai Hu } else { 42490751910SMingkai Hu printf("Got error %x\n", 425*18b338fbSClaudiu Manoil (rtx.rxbd[rx_idx].status & RXBD_STATS)); 42690751910SMingkai Hu } 42790751910SMingkai Hu 428*18b338fbSClaudiu Manoil rtx.rxbd[rx_idx].length = 0; 42990751910SMingkai Hu 43090751910SMingkai Hu /* Set the wrap bit if this is the last element in the list */ 431*18b338fbSClaudiu Manoil rtx.rxbd[rx_idx].status = 432*18b338fbSClaudiu Manoil RXBD_EMPTY | (((rx_idx + 1) == PKTBUFSRX) ? RXBD_WRAP : 0); 43390751910SMingkai Hu 434*18b338fbSClaudiu Manoil rx_idx = (rx_idx + 1) % PKTBUFSRX; 43590751910SMingkai Hu } 43690751910SMingkai Hu 43790751910SMingkai Hu if (in_be32(®s->ievent) & IEVENT_BSY) { 43890751910SMingkai Hu out_be32(®s->ievent, IEVENT_BSY); 43990751910SMingkai Hu out_be32(®s->rstat, RSTAT_CLEAR_RHALT); 44090751910SMingkai Hu } 44190751910SMingkai Hu 44290751910SMingkai Hu return -1; 44390751910SMingkai Hu 44490751910SMingkai Hu } 44590751910SMingkai Hu 44690751910SMingkai Hu /* Stop the interface */ 44790751910SMingkai Hu static void tsec_halt(struct eth_device *dev) 44890751910SMingkai Hu { 44990751910SMingkai Hu struct tsec_private *priv = (struct tsec_private *)dev->priv; 450aec84bf6SClaudiu Manoil struct tsec __iomem *regs = priv->regs; 45190751910SMingkai Hu 45290751910SMingkai Hu clrbits_be32(®s->dmactrl, DMACTRL_GRS | DMACTRL_GTS); 45390751910SMingkai Hu setbits_be32(®s->dmactrl, DMACTRL_GRS | DMACTRL_GTS); 45490751910SMingkai Hu 45590751910SMingkai Hu while ((in_be32(®s->ievent) & (IEVENT_GRSC | IEVENT_GTSC)) 45690751910SMingkai Hu != (IEVENT_GRSC | IEVENT_GTSC)) 45790751910SMingkai Hu ; 45890751910SMingkai Hu 45990751910SMingkai Hu clrbits_be32(®s->maccfg1, MACCFG1_TX_EN | MACCFG1_RX_EN); 46090751910SMingkai Hu 46190751910SMingkai Hu /* Shut down the PHY, as needed */ 462063c1263SAndy Fleming phy_shutdown(priv->phydev); 46390751910SMingkai Hu } 46490751910SMingkai Hu 46590751910SMingkai Hu /* Initializes data structures and registers for the controller, 46690751910SMingkai Hu * and brings the interface up. Returns the link status, meaning 46790751910SMingkai Hu * that it returns success if the link is up, failure otherwise. 46890751910SMingkai Hu * This allows u-boot to find the first active controller. 46990751910SMingkai Hu */ 47090751910SMingkai Hu static int tsec_init(struct eth_device *dev, bd_t * bd) 47190751910SMingkai Hu { 47290751910SMingkai Hu uint tempval; 47390751910SMingkai Hu char tmpbuf[MAC_ADDR_LEN]; 47490751910SMingkai Hu int i; 47590751910SMingkai Hu struct tsec_private *priv = (struct tsec_private *)dev->priv; 476aec84bf6SClaudiu Manoil struct tsec __iomem *regs = priv->regs; 47711af8d65STimur Tabi int ret; 47890751910SMingkai Hu 47990751910SMingkai Hu /* Make sure the controller is stopped */ 48090751910SMingkai Hu tsec_halt(dev); 48190751910SMingkai Hu 48290751910SMingkai Hu /* Init MACCFG2. Defaults to GMII */ 48390751910SMingkai Hu out_be32(®s->maccfg2, MACCFG2_INIT_SETTINGS); 48490751910SMingkai Hu 48590751910SMingkai Hu /* Init ECNTRL */ 48690751910SMingkai Hu out_be32(®s->ecntrl, ECNTRL_INIT_SETTINGS); 48790751910SMingkai Hu 48890751910SMingkai Hu /* Copy the station address into the address registers. 48990751910SMingkai Hu * Backwards, because little endian MACS are dumb */ 49090751910SMingkai Hu for (i = 0; i < MAC_ADDR_LEN; i++) 49190751910SMingkai Hu tmpbuf[MAC_ADDR_LEN - 1 - i] = dev->enetaddr[i]; 49290751910SMingkai Hu 49390751910SMingkai Hu tempval = (tmpbuf[0] << 24) | (tmpbuf[1] << 16) | (tmpbuf[2] << 8) | 49490751910SMingkai Hu tmpbuf[3]; 49590751910SMingkai Hu 49690751910SMingkai Hu out_be32(®s->macstnaddr1, tempval); 49790751910SMingkai Hu 49890751910SMingkai Hu tempval = *((uint *) (tmpbuf + 4)); 49990751910SMingkai Hu 50090751910SMingkai Hu out_be32(®s->macstnaddr2, tempval); 50190751910SMingkai Hu 50290751910SMingkai Hu /* Clear out (for the most part) the other registers */ 50390751910SMingkai Hu init_registers(regs); 50490751910SMingkai Hu 50590751910SMingkai Hu /* Ready the device for tx/rx */ 50690751910SMingkai Hu startup_tsec(dev); 50790751910SMingkai Hu 508063c1263SAndy Fleming /* Start up the PHY */ 50911af8d65STimur Tabi ret = phy_startup(priv->phydev); 51011af8d65STimur Tabi if (ret) { 51111af8d65STimur Tabi printf("Could not initialize PHY %s\n", 51211af8d65STimur Tabi priv->phydev->dev->name); 51311af8d65STimur Tabi return ret; 51411af8d65STimur Tabi } 515063c1263SAndy Fleming 516063c1263SAndy Fleming adjust_link(priv, priv->phydev); 517063c1263SAndy Fleming 51890751910SMingkai Hu /* If there's no link, fail */ 519063c1263SAndy Fleming return priv->phydev->link ? 0 : -1; 52090751910SMingkai Hu } 52190751910SMingkai Hu 522063c1263SAndy Fleming static phy_interface_t tsec_get_interface(struct tsec_private *priv) 523063c1263SAndy Fleming { 524aec84bf6SClaudiu Manoil struct tsec __iomem *regs = priv->regs; 525063c1263SAndy Fleming u32 ecntrl; 526063c1263SAndy Fleming 527063c1263SAndy Fleming ecntrl = in_be32(®s->ecntrl); 528063c1263SAndy Fleming 529063c1263SAndy Fleming if (ecntrl & ECNTRL_SGMII_MODE) 530063c1263SAndy Fleming return PHY_INTERFACE_MODE_SGMII; 531063c1263SAndy Fleming 532063c1263SAndy Fleming if (ecntrl & ECNTRL_TBI_MODE) { 533063c1263SAndy Fleming if (ecntrl & ECNTRL_REDUCED_MODE) 534063c1263SAndy Fleming return PHY_INTERFACE_MODE_RTBI; 535063c1263SAndy Fleming else 536063c1263SAndy Fleming return PHY_INTERFACE_MODE_TBI; 537063c1263SAndy Fleming } 538063c1263SAndy Fleming 539063c1263SAndy Fleming if (ecntrl & ECNTRL_REDUCED_MODE) { 540063c1263SAndy Fleming if (ecntrl & ECNTRL_REDUCED_MII_MODE) 541063c1263SAndy Fleming return PHY_INTERFACE_MODE_RMII; 542063c1263SAndy Fleming else { 543063c1263SAndy Fleming phy_interface_t interface = priv->interface; 544063c1263SAndy Fleming 545063c1263SAndy Fleming /* 546063c1263SAndy Fleming * This isn't autodetected, so it must 547063c1263SAndy Fleming * be set by the platform code. 548063c1263SAndy Fleming */ 549063c1263SAndy Fleming if ((interface == PHY_INTERFACE_MODE_RGMII_ID) || 550063c1263SAndy Fleming (interface == PHY_INTERFACE_MODE_RGMII_TXID) || 551063c1263SAndy Fleming (interface == PHY_INTERFACE_MODE_RGMII_RXID)) 552063c1263SAndy Fleming return interface; 553063c1263SAndy Fleming 554063c1263SAndy Fleming return PHY_INTERFACE_MODE_RGMII; 555063c1263SAndy Fleming } 556063c1263SAndy Fleming } 557063c1263SAndy Fleming 558063c1263SAndy Fleming if (priv->flags & TSEC_GIGABIT) 559063c1263SAndy Fleming return PHY_INTERFACE_MODE_GMII; 560063c1263SAndy Fleming 561063c1263SAndy Fleming return PHY_INTERFACE_MODE_MII; 562063c1263SAndy Fleming } 563063c1263SAndy Fleming 564063c1263SAndy Fleming 56590751910SMingkai Hu /* Discover which PHY is attached to the device, and configure it 56690751910SMingkai Hu * properly. If the PHY is not recognized, then return 0 56790751910SMingkai Hu * (failure). Otherwise, return 1 56890751910SMingkai Hu */ 56990751910SMingkai Hu static int init_phy(struct eth_device *dev) 57090751910SMingkai Hu { 57190751910SMingkai Hu struct tsec_private *priv = (struct tsec_private *)dev->priv; 572063c1263SAndy Fleming struct phy_device *phydev; 573aec84bf6SClaudiu Manoil struct tsec __iomem *regs = priv->regs; 574063c1263SAndy Fleming u32 supported = (SUPPORTED_10baseT_Half | 575063c1263SAndy Fleming SUPPORTED_10baseT_Full | 576063c1263SAndy Fleming SUPPORTED_100baseT_Half | 577063c1263SAndy Fleming SUPPORTED_100baseT_Full); 578063c1263SAndy Fleming 579063c1263SAndy Fleming if (priv->flags & TSEC_GIGABIT) 580063c1263SAndy Fleming supported |= SUPPORTED_1000baseT_Full; 58190751910SMingkai Hu 58290751910SMingkai Hu /* Assign a Physical address to the TBI */ 58390751910SMingkai Hu out_be32(®s->tbipa, CONFIG_SYS_TBIPA_VALUE); 58490751910SMingkai Hu 585063c1263SAndy Fleming priv->interface = tsec_get_interface(priv); 58690751910SMingkai Hu 587063c1263SAndy Fleming if (priv->interface == PHY_INTERFACE_MODE_SGMII) 58890751910SMingkai Hu tsec_configure_serdes(priv); 58990751910SMingkai Hu 590063c1263SAndy Fleming phydev = phy_connect(priv->bus, priv->phyaddr, dev, priv->interface); 59190751910SMingkai Hu 592063c1263SAndy Fleming phydev->supported &= supported; 593063c1263SAndy Fleming phydev->advertising = phydev->supported; 594063c1263SAndy Fleming 595063c1263SAndy Fleming priv->phydev = phydev; 596063c1263SAndy Fleming 597063c1263SAndy Fleming phy_config(phydev); 59890751910SMingkai Hu 59990751910SMingkai Hu return 1; 60090751910SMingkai Hu } 60190751910SMingkai Hu 60290751910SMingkai Hu /* Initialize device structure. Returns success if PHY 60390751910SMingkai Hu * initialization succeeded (i.e. if it recognizes the PHY) 60490751910SMingkai Hu */ 60590751910SMingkai Hu static int tsec_initialize(bd_t *bis, struct tsec_info_struct *tsec_info) 60690751910SMingkai Hu { 60790751910SMingkai Hu struct eth_device *dev; 60890751910SMingkai Hu int i; 60990751910SMingkai Hu struct tsec_private *priv; 61090751910SMingkai Hu 61190751910SMingkai Hu dev = (struct eth_device *)malloc(sizeof *dev); 61290751910SMingkai Hu 61390751910SMingkai Hu if (NULL == dev) 61490751910SMingkai Hu return 0; 61590751910SMingkai Hu 61690751910SMingkai Hu memset(dev, 0, sizeof *dev); 61790751910SMingkai Hu 61890751910SMingkai Hu priv = (struct tsec_private *)malloc(sizeof(*priv)); 61990751910SMingkai Hu 62090751910SMingkai Hu if (NULL == priv) 62190751910SMingkai Hu return 0; 62290751910SMingkai Hu 62390751910SMingkai Hu priv->regs = tsec_info->regs; 62490751910SMingkai Hu priv->phyregs_sgmii = tsec_info->miiregs_sgmii; 62590751910SMingkai Hu 62690751910SMingkai Hu priv->phyaddr = tsec_info->phyaddr; 62790751910SMingkai Hu priv->flags = tsec_info->flags; 62890751910SMingkai Hu 62990751910SMingkai Hu sprintf(dev->name, tsec_info->devname); 630063c1263SAndy Fleming priv->interface = tsec_info->interface; 631063c1263SAndy Fleming priv->bus = miiphy_get_dev_by_name(tsec_info->mii_devname); 63290751910SMingkai Hu dev->iobase = 0; 63390751910SMingkai Hu dev->priv = priv; 63490751910SMingkai Hu dev->init = tsec_init; 63590751910SMingkai Hu dev->halt = tsec_halt; 63690751910SMingkai Hu dev->send = tsec_send; 63790751910SMingkai Hu dev->recv = tsec_recv; 63890751910SMingkai Hu #ifdef CONFIG_MCAST_TFTP 63990751910SMingkai Hu dev->mcast = tsec_mcast_addr; 64090751910SMingkai Hu #endif 64190751910SMingkai Hu 64290751910SMingkai Hu /* Tell u-boot to get the addr from the env */ 64390751910SMingkai Hu for (i = 0; i < 6; i++) 64490751910SMingkai Hu dev->enetaddr[i] = 0; 64590751910SMingkai Hu 64690751910SMingkai Hu eth_register(dev); 64790751910SMingkai Hu 64890751910SMingkai Hu /* Reset the MAC */ 64990751910SMingkai Hu setbits_be32(&priv->regs->maccfg1, MACCFG1_SOFT_RESET); 65090751910SMingkai Hu udelay(2); /* Soft Reset must be asserted for 3 TX clocks */ 65190751910SMingkai Hu clrbits_be32(&priv->regs->maccfg1, MACCFG1_SOFT_RESET); 65290751910SMingkai Hu 65390751910SMingkai Hu /* Try to initialize PHY here, and return */ 65490751910SMingkai Hu return init_phy(dev); 65590751910SMingkai Hu } 65690751910SMingkai Hu 65790751910SMingkai Hu /* 65890751910SMingkai Hu * Initialize all the TSEC devices 65990751910SMingkai Hu * 66090751910SMingkai Hu * Returns the number of TSEC devices that were initialized 66190751910SMingkai Hu */ 66290751910SMingkai Hu int tsec_eth_init(bd_t *bis, struct tsec_info_struct *tsecs, int num) 66390751910SMingkai Hu { 66490751910SMingkai Hu int i; 66590751910SMingkai Hu int ret, count = 0; 66690751910SMingkai Hu 66790751910SMingkai Hu for (i = 0; i < num; i++) { 66890751910SMingkai Hu ret = tsec_initialize(bis, &tsecs[i]); 66990751910SMingkai Hu if (ret > 0) 67090751910SMingkai Hu count += ret; 67190751910SMingkai Hu } 67290751910SMingkai Hu 67390751910SMingkai Hu return count; 67490751910SMingkai Hu } 67590751910SMingkai Hu 67690751910SMingkai Hu int tsec_standard_init(bd_t *bis) 67790751910SMingkai Hu { 678063c1263SAndy Fleming struct fsl_pq_mdio_info info; 679063c1263SAndy Fleming 680aec84bf6SClaudiu Manoil info.regs = TSEC_GET_MDIO_REGS_BASE(1); 681063c1263SAndy Fleming info.name = DEFAULT_MII_NAME; 682063c1263SAndy Fleming 683063c1263SAndy Fleming fsl_pq_mdio_init(bis, &info); 684063c1263SAndy Fleming 68590751910SMingkai Hu return tsec_eth_init(bis, tsec_info, ARRAY_SIZE(tsec_info)); 68690751910SMingkai Hu } 687