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> 2352d00a81SAlison Wang #include <asm/io.h> 242439e4bfSJean-Christophe PLAGNIOL-VILLARD 252439e4bfSJean-Christophe PLAGNIOL-VILLARD DECLARE_GLOBAL_DATA_PTR; 262439e4bfSJean-Christophe PLAGNIOL-VILLARD 272439e4bfSJean-Christophe PLAGNIOL-VILLARD #define TX_BUF_CNT 2 282439e4bfSJean-Christophe PLAGNIOL-VILLARD 2918b338fbSClaudiu Manoil static uint rx_idx; /* index of the current RX buffer */ 3018b338fbSClaudiu Manoil static uint tx_idx; /* index of the current TX buffer */ 312439e4bfSJean-Christophe PLAGNIOL-VILLARD 322439e4bfSJean-Christophe PLAGNIOL-VILLARD #ifdef __GNUC__ 339c9141fdSClaudiu Manoil static struct txbd8 __iomem txbd[TX_BUF_CNT] __aligned(8); 349c9141fdSClaudiu Manoil static struct rxbd8 __iomem rxbd[PKTBUFSRX] __aligned(8); 359c9141fdSClaudiu Manoil 362439e4bfSJean-Christophe PLAGNIOL-VILLARD #else 372439e4bfSJean-Christophe PLAGNIOL-VILLARD #error "rtx must be 64-bit aligned" 382439e4bfSJean-Christophe PLAGNIOL-VILLARD #endif 392439e4bfSJean-Christophe PLAGNIOL-VILLARD 40c8a60b53SJoe Hershberger static int tsec_send(struct eth_device *dev, void *packet, int length); 41aada81deSchenhui zhao 4275b9d4aeSAndy Fleming /* Default initializations for TSEC controllers. */ 4375b9d4aeSAndy Fleming 4475b9d4aeSAndy Fleming static struct tsec_info_struct tsec_info[] = { 4575b9d4aeSAndy Fleming #ifdef CONFIG_TSEC1 4675b9d4aeSAndy Fleming STD_TSEC_INFO(1), /* TSEC1 */ 4775b9d4aeSAndy Fleming #endif 4875b9d4aeSAndy Fleming #ifdef CONFIG_TSEC2 4975b9d4aeSAndy Fleming STD_TSEC_INFO(2), /* TSEC2 */ 5075b9d4aeSAndy Fleming #endif 5175b9d4aeSAndy Fleming #ifdef CONFIG_MPC85XX_FEC 5275b9d4aeSAndy Fleming { 53aec84bf6SClaudiu Manoil .regs = TSEC_GET_REGS(2, 0x2000), 5475b9d4aeSAndy Fleming .devname = CONFIG_MPC85XX_FEC_NAME, 5575b9d4aeSAndy Fleming .phyaddr = FEC_PHY_ADDR, 56063c1263SAndy Fleming .flags = FEC_FLAGS, 57063c1263SAndy Fleming .mii_devname = DEFAULT_MII_NAME 5875b9d4aeSAndy Fleming }, /* FEC */ 5975b9d4aeSAndy Fleming #endif 6075b9d4aeSAndy Fleming #ifdef CONFIG_TSEC3 6175b9d4aeSAndy Fleming STD_TSEC_INFO(3), /* TSEC3 */ 6275b9d4aeSAndy Fleming #endif 6375b9d4aeSAndy Fleming #ifdef CONFIG_TSEC4 6475b9d4aeSAndy Fleming STD_TSEC_INFO(4), /* TSEC4 */ 6575b9d4aeSAndy Fleming #endif 6675b9d4aeSAndy Fleming }; 6775b9d4aeSAndy Fleming 682abe361cSAndy Fleming #define TBIANA_SETTINGS ( \ 692abe361cSAndy Fleming TBIANA_ASYMMETRIC_PAUSE \ 702abe361cSAndy Fleming | TBIANA_SYMMETRIC_PAUSE \ 712abe361cSAndy Fleming | TBIANA_FULL_DUPLEX \ 722abe361cSAndy Fleming ) 732abe361cSAndy Fleming 7490b5bf21SFelix Radensky /* By default force the TBI PHY into 1000Mbps full duplex when in SGMII mode */ 7590b5bf21SFelix Radensky #ifndef CONFIG_TSEC_TBICR_SETTINGS 7672c96a68SKumar Gala #define CONFIG_TSEC_TBICR_SETTINGS ( \ 772abe361cSAndy Fleming TBICR_PHY_RESET \ 7872c96a68SKumar Gala | TBICR_ANEG_ENABLE \ 792abe361cSAndy Fleming | TBICR_FULL_DUPLEX \ 802abe361cSAndy Fleming | TBICR_SPEED1_SET \ 812abe361cSAndy Fleming ) 8290b5bf21SFelix Radensky #endif /* CONFIG_TSEC_TBICR_SETTINGS */ 8346e91674SPeter Tyser 842abe361cSAndy Fleming /* Configure the TBI for SGMII operation */ 852abe361cSAndy Fleming static void tsec_configure_serdes(struct tsec_private *priv) 862abe361cSAndy Fleming { 87c6dbdfdaSPeter Tyser /* Access TBI PHY registers at given TSEC register offset as opposed 88c6dbdfdaSPeter Tyser * to the register offset used for external PHY accesses */ 89063c1263SAndy Fleming tsec_local_mdio_write(priv->phyregs_sgmii, in_be32(&priv->regs->tbipa), 90063c1263SAndy Fleming 0, TBI_ANA, TBIANA_SETTINGS); 91063c1263SAndy Fleming tsec_local_mdio_write(priv->phyregs_sgmii, in_be32(&priv->regs->tbipa), 92063c1263SAndy Fleming 0, TBI_TBICON, TBICON_CLK_SELECT); 93063c1263SAndy Fleming tsec_local_mdio_write(priv->phyregs_sgmii, in_be32(&priv->regs->tbipa), 94063c1263SAndy Fleming 0, TBI_CR, CONFIG_TSEC_TBICR_SETTINGS); 952439e4bfSJean-Christophe PLAGNIOL-VILLARD } 962439e4bfSJean-Christophe PLAGNIOL-VILLARD 972439e4bfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_MCAST_TFTP 982439e4bfSJean-Christophe PLAGNIOL-VILLARD 992439e4bfSJean-Christophe PLAGNIOL-VILLARD /* CREDITS: linux gianfar driver, slightly adjusted... thanx. */ 1002439e4bfSJean-Christophe PLAGNIOL-VILLARD 1012439e4bfSJean-Christophe PLAGNIOL-VILLARD /* Set the appropriate hash bit for the given addr */ 1022439e4bfSJean-Christophe PLAGNIOL-VILLARD 1032439e4bfSJean-Christophe PLAGNIOL-VILLARD /* The algorithm works like so: 1042439e4bfSJean-Christophe PLAGNIOL-VILLARD * 1) Take the Destination Address (ie the multicast address), and 1052439e4bfSJean-Christophe PLAGNIOL-VILLARD * do a CRC on it (little endian), and reverse the bits of the 1062439e4bfSJean-Christophe PLAGNIOL-VILLARD * result. 1072439e4bfSJean-Christophe PLAGNIOL-VILLARD * 2) Use the 8 most significant bits as a hash into a 256-entry 1082439e4bfSJean-Christophe PLAGNIOL-VILLARD * table. The table is controlled through 8 32-bit registers: 109876d4515SClaudiu Manoil * gaddr0-7. gaddr0's MSB is entry 0, and gaddr7's LSB is entry 110876d4515SClaudiu Manoil * 255. This means that the 3 most significant bits in the 1112439e4bfSJean-Christophe PLAGNIOL-VILLARD * hash index which gaddr register to use, and the 5 other bits 1122439e4bfSJean-Christophe PLAGNIOL-VILLARD * indicate which bit (assuming an IBM numbering scheme, which 113876d4515SClaudiu Manoil * for PowerPC (tm) is usually the case) in the register holds 1142439e4bfSJean-Christophe PLAGNIOL-VILLARD * the entry. */ 1152439e4bfSJean-Christophe PLAGNIOL-VILLARD static int 1169c4cffacSClaudiu Manoil tsec_mcast_addr(struct eth_device *dev, const u8 *mcast_mac, u8 set) 1172439e4bfSJean-Christophe PLAGNIOL-VILLARD { 118b200204eSClaudiu Manoil struct tsec_private *priv = (struct tsec_private *)dev->priv; 119876d4515SClaudiu Manoil struct tsec __iomem *regs = priv->regs; 120876d4515SClaudiu Manoil u32 result, value; 121876d4515SClaudiu Manoil u8 whichbit, whichreg; 1222439e4bfSJean-Christophe PLAGNIOL-VILLARD 123876d4515SClaudiu Manoil result = ether_crc(MAC_ADDR_LEN, mcast_mac); 124876d4515SClaudiu Manoil whichbit = (result >> 24) & 0x1f; /* the 5 LSB = which bit to set */ 125876d4515SClaudiu Manoil whichreg = result >> 29; /* the 3 MSB = which reg to set it in */ 1262439e4bfSJean-Christophe PLAGNIOL-VILLARD 127876d4515SClaudiu Manoil value = 1 << (31-whichbit); 1282439e4bfSJean-Christophe PLAGNIOL-VILLARD 129876d4515SClaudiu Manoil if (set) 130876d4515SClaudiu Manoil setbits_be32(®s->hash.gaddr0 + whichreg, value); 131876d4515SClaudiu Manoil else 132876d4515SClaudiu Manoil clrbits_be32(®s->hash.gaddr0 + whichreg, value); 133876d4515SClaudiu Manoil 1342439e4bfSJean-Christophe PLAGNIOL-VILLARD return 0; 1352439e4bfSJean-Christophe PLAGNIOL-VILLARD } 1362439e4bfSJean-Christophe PLAGNIOL-VILLARD #endif /* Multicast TFTP ? */ 13790751910SMingkai Hu 13890751910SMingkai Hu /* Initialized required registers to appropriate values, zeroing 13990751910SMingkai Hu * those we don't care about (unless zero is bad, in which case, 14090751910SMingkai Hu * choose a more appropriate value) 14190751910SMingkai Hu */ 142aec84bf6SClaudiu Manoil static void init_registers(struct tsec __iomem *regs) 14390751910SMingkai Hu { 14490751910SMingkai Hu /* Clear IEVENT */ 14590751910SMingkai Hu out_be32(®s->ievent, IEVENT_INIT_CLEAR); 14690751910SMingkai Hu 14790751910SMingkai Hu out_be32(®s->imask, IMASK_INIT_CLEAR); 14890751910SMingkai Hu 14990751910SMingkai Hu out_be32(®s->hash.iaddr0, 0); 15090751910SMingkai Hu out_be32(®s->hash.iaddr1, 0); 15190751910SMingkai Hu out_be32(®s->hash.iaddr2, 0); 15290751910SMingkai Hu out_be32(®s->hash.iaddr3, 0); 15390751910SMingkai Hu out_be32(®s->hash.iaddr4, 0); 15490751910SMingkai Hu out_be32(®s->hash.iaddr5, 0); 15590751910SMingkai Hu out_be32(®s->hash.iaddr6, 0); 15690751910SMingkai Hu out_be32(®s->hash.iaddr7, 0); 15790751910SMingkai Hu 15890751910SMingkai Hu out_be32(®s->hash.gaddr0, 0); 15990751910SMingkai Hu out_be32(®s->hash.gaddr1, 0); 16090751910SMingkai Hu out_be32(®s->hash.gaddr2, 0); 16190751910SMingkai Hu out_be32(®s->hash.gaddr3, 0); 16290751910SMingkai Hu out_be32(®s->hash.gaddr4, 0); 16390751910SMingkai Hu out_be32(®s->hash.gaddr5, 0); 16490751910SMingkai Hu out_be32(®s->hash.gaddr6, 0); 16590751910SMingkai Hu out_be32(®s->hash.gaddr7, 0); 16690751910SMingkai Hu 16790751910SMingkai Hu out_be32(®s->rctrl, 0x00000000); 16890751910SMingkai Hu 16990751910SMingkai Hu /* Init RMON mib registers */ 17082ef75caSClaudiu Manoil memset((void *)®s->rmon, 0, sizeof(regs->rmon)); 17190751910SMingkai Hu 17290751910SMingkai Hu out_be32(®s->rmon.cam1, 0xffffffff); 17390751910SMingkai Hu out_be32(®s->rmon.cam2, 0xffffffff); 17490751910SMingkai Hu 17590751910SMingkai Hu out_be32(®s->mrblr, MRBLR_INIT_SETTINGS); 17690751910SMingkai Hu 17790751910SMingkai Hu out_be32(®s->minflr, MINFLR_INIT_SETTINGS); 17890751910SMingkai Hu 17990751910SMingkai Hu out_be32(®s->attr, ATTR_INIT_SETTINGS); 18090751910SMingkai Hu out_be32(®s->attreli, ATTRELI_INIT_SETTINGS); 18190751910SMingkai Hu 18290751910SMingkai Hu } 18390751910SMingkai Hu 18490751910SMingkai Hu /* Configure maccfg2 based on negotiated speed and duplex 18590751910SMingkai Hu * reported by PHY handling code 18690751910SMingkai Hu */ 187063c1263SAndy Fleming static void adjust_link(struct tsec_private *priv, struct phy_device *phydev) 18890751910SMingkai Hu { 189aec84bf6SClaudiu Manoil struct tsec __iomem *regs = priv->regs; 19090751910SMingkai Hu u32 ecntrl, maccfg2; 19190751910SMingkai Hu 192063c1263SAndy Fleming if (!phydev->link) { 193063c1263SAndy Fleming printf("%s: No link.\n", phydev->dev->name); 19490751910SMingkai Hu return; 19590751910SMingkai Hu } 19690751910SMingkai Hu 19790751910SMingkai Hu /* clear all bits relative with interface mode */ 19890751910SMingkai Hu ecntrl = in_be32(®s->ecntrl); 19990751910SMingkai Hu ecntrl &= ~ECNTRL_R100; 20090751910SMingkai Hu 20190751910SMingkai Hu maccfg2 = in_be32(®s->maccfg2); 20290751910SMingkai Hu maccfg2 &= ~(MACCFG2_IF | MACCFG2_FULL_DUPLEX); 20390751910SMingkai Hu 204063c1263SAndy Fleming if (phydev->duplex) 20590751910SMingkai Hu maccfg2 |= MACCFG2_FULL_DUPLEX; 20690751910SMingkai Hu 207063c1263SAndy Fleming switch (phydev->speed) { 20890751910SMingkai Hu case 1000: 20990751910SMingkai Hu maccfg2 |= MACCFG2_GMII; 21090751910SMingkai Hu break; 21190751910SMingkai Hu case 100: 21290751910SMingkai Hu case 10: 21390751910SMingkai Hu maccfg2 |= MACCFG2_MII; 21490751910SMingkai Hu 21590751910SMingkai Hu /* Set R100 bit in all modes although 21690751910SMingkai Hu * it is only used in RGMII mode 21790751910SMingkai Hu */ 218063c1263SAndy Fleming if (phydev->speed == 100) 21990751910SMingkai Hu ecntrl |= ECNTRL_R100; 22090751910SMingkai Hu break; 22190751910SMingkai Hu default: 222063c1263SAndy Fleming printf("%s: Speed was bad\n", phydev->dev->name); 22390751910SMingkai Hu break; 22490751910SMingkai Hu } 22590751910SMingkai Hu 22690751910SMingkai Hu out_be32(®s->ecntrl, ecntrl); 22790751910SMingkai Hu out_be32(®s->maccfg2, maccfg2); 22890751910SMingkai Hu 229063c1263SAndy Fleming printf("Speed: %d, %s duplex%s\n", phydev->speed, 230063c1263SAndy Fleming (phydev->duplex) ? "full" : "half", 231063c1263SAndy Fleming (phydev->port == PORT_FIBRE) ? ", fiber mode" : ""); 23290751910SMingkai Hu } 23390751910SMingkai Hu 234aada81deSchenhui zhao #ifdef CONFIG_SYS_FSL_ERRATUM_NMG_ETSEC129 235aada81deSchenhui zhao /* 236aada81deSchenhui zhao * When MACCFG1[Rx_EN] is enabled during system boot as part 237aada81deSchenhui zhao * of the eTSEC port initialization sequence, 238aada81deSchenhui zhao * the eTSEC Rx logic may not be properly initialized. 239aada81deSchenhui zhao */ 240aada81deSchenhui zhao void redundant_init(struct eth_device *dev) 241aada81deSchenhui zhao { 242aada81deSchenhui zhao struct tsec_private *priv = dev->priv; 243aec84bf6SClaudiu Manoil struct tsec __iomem *regs = priv->regs; 244aada81deSchenhui zhao uint t, count = 0; 245aada81deSchenhui zhao int fail = 1; 246aada81deSchenhui zhao static const u8 pkt[] = { 247aada81deSchenhui zhao 0x00, 0x1e, 0x4f, 0x12, 0xcb, 0x2c, 0x00, 0x25, 248aada81deSchenhui zhao 0x64, 0xbb, 0xd1, 0xab, 0x08, 0x00, 0x45, 0x00, 249aada81deSchenhui zhao 0x00, 0x5c, 0xdd, 0x22, 0x00, 0x00, 0x80, 0x01, 250aada81deSchenhui zhao 0x1f, 0x71, 0x0a, 0xc1, 0x14, 0x22, 0x0a, 0xc1, 251aada81deSchenhui zhao 0x14, 0x6a, 0x08, 0x00, 0xef, 0x7e, 0x02, 0x00, 252aada81deSchenhui zhao 0x94, 0x05, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 253aada81deSchenhui zhao 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 254aada81deSchenhui zhao 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 255aada81deSchenhui zhao 0x77, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 256aada81deSchenhui zhao 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 257aada81deSchenhui zhao 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 258aada81deSchenhui zhao 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 259aada81deSchenhui zhao 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 260aada81deSchenhui zhao 0x71, 0x72}; 261aada81deSchenhui zhao 262aada81deSchenhui zhao /* Enable promiscuous mode */ 263aada81deSchenhui zhao setbits_be32(®s->rctrl, 0x8); 264aada81deSchenhui zhao /* Enable loopback mode */ 265aada81deSchenhui zhao setbits_be32(®s->maccfg1, MACCFG1_LOOPBACK); 266aada81deSchenhui zhao /* Enable transmit and receive */ 267aada81deSchenhui zhao setbits_be32(®s->maccfg1, MACCFG1_RX_EN | MACCFG1_TX_EN); 268aada81deSchenhui zhao 269aada81deSchenhui zhao /* Tell the DMA it is clear to go */ 270aada81deSchenhui zhao setbits_be32(®s->dmactrl, DMACTRL_INIT_SETTINGS); 271aada81deSchenhui zhao out_be32(®s->tstat, TSTAT_CLEAR_THALT); 272aada81deSchenhui zhao out_be32(®s->rstat, RSTAT_CLEAR_RHALT); 273aada81deSchenhui zhao clrbits_be32(®s->dmactrl, DMACTRL_GRS | DMACTRL_GTS); 27452d00a81SAlison Wang #ifdef CONFIG_LS102XA 27552d00a81SAlison Wang setbits_be32(®s->dmactrl, DMACTRL_LE); 27652d00a81SAlison Wang #endif 277aada81deSchenhui zhao 278aada81deSchenhui zhao do { 2799c9141fdSClaudiu Manoil uint16_t status; 280aada81deSchenhui zhao tsec_send(dev, (void *)pkt, sizeof(pkt)); 281aada81deSchenhui zhao 282aada81deSchenhui zhao /* Wait for buffer to be received */ 2839c9141fdSClaudiu Manoil for (t = 0; in_be16(&rxbd[rx_idx].status) & RXBD_EMPTY; t++) { 284aada81deSchenhui zhao if (t >= 10 * TOUT_LOOP) { 285aada81deSchenhui zhao printf("%s: tsec: rx error\n", dev->name); 286aada81deSchenhui zhao break; 287aada81deSchenhui zhao } 288aada81deSchenhui zhao } 289aada81deSchenhui zhao 290*1fd92db8SJoe Hershberger if (!memcmp(pkt, (void *)net_rx_packets[rx_idx], sizeof(pkt))) 291aada81deSchenhui zhao fail = 0; 292aada81deSchenhui zhao 2939c9141fdSClaudiu Manoil out_be16(&rxbd[rx_idx].length, 0); 2949c9141fdSClaudiu Manoil status = RXBD_EMPTY; 2959c9141fdSClaudiu Manoil if ((rx_idx + 1) == PKTBUFSRX) 2969c9141fdSClaudiu Manoil status |= RXBD_WRAP; 2979c9141fdSClaudiu Manoil out_be16(&rxbd[rx_idx].status, status); 29818b338fbSClaudiu Manoil rx_idx = (rx_idx + 1) % PKTBUFSRX; 299aada81deSchenhui zhao 300aada81deSchenhui zhao if (in_be32(®s->ievent) & IEVENT_BSY) { 301aada81deSchenhui zhao out_be32(®s->ievent, IEVENT_BSY); 302aada81deSchenhui zhao out_be32(®s->rstat, RSTAT_CLEAR_RHALT); 303aada81deSchenhui zhao } 304aada81deSchenhui zhao if (fail) { 305aada81deSchenhui zhao printf("loopback recv packet error!\n"); 306aada81deSchenhui zhao clrbits_be32(®s->maccfg1, MACCFG1_RX_EN); 307aada81deSchenhui zhao udelay(1000); 308aada81deSchenhui zhao setbits_be32(®s->maccfg1, MACCFG1_RX_EN); 309aada81deSchenhui zhao } 310aada81deSchenhui zhao } while ((count++ < 4) && (fail == 1)); 311aada81deSchenhui zhao 312aada81deSchenhui zhao if (fail) 313aada81deSchenhui zhao panic("eTSEC init fail!\n"); 314aada81deSchenhui zhao /* Disable promiscuous mode */ 315aada81deSchenhui zhao clrbits_be32(®s->rctrl, 0x8); 316aada81deSchenhui zhao /* Disable loopback mode */ 317aada81deSchenhui zhao clrbits_be32(®s->maccfg1, MACCFG1_LOOPBACK); 318aada81deSchenhui zhao } 319aada81deSchenhui zhao #endif 320aada81deSchenhui zhao 32190751910SMingkai Hu /* Set up the buffers and their descriptors, and bring up the 32290751910SMingkai Hu * interface 32390751910SMingkai Hu */ 32490751910SMingkai Hu static void startup_tsec(struct eth_device *dev) 32590751910SMingkai Hu { 32690751910SMingkai Hu struct tsec_private *priv = (struct tsec_private *)dev->priv; 327aec84bf6SClaudiu Manoil struct tsec __iomem *regs = priv->regs; 3289c9141fdSClaudiu Manoil uint16_t status; 3299c9141fdSClaudiu Manoil int i; 33090751910SMingkai Hu 331063c1263SAndy Fleming /* reset the indices to zero */ 33218b338fbSClaudiu Manoil rx_idx = 0; 33318b338fbSClaudiu Manoil tx_idx = 0; 334aada81deSchenhui zhao #ifdef CONFIG_SYS_FSL_ERRATUM_NMG_ETSEC129 335aada81deSchenhui zhao uint svr; 336aada81deSchenhui zhao #endif 337063c1263SAndy Fleming 33890751910SMingkai Hu /* Point to the buffer descriptors */ 3399c9141fdSClaudiu Manoil out_be32(®s->tbase, (u32)&txbd[0]); 3409c9141fdSClaudiu Manoil out_be32(®s->rbase, (u32)&rxbd[0]); 34190751910SMingkai Hu 34290751910SMingkai Hu /* Initialize the Rx Buffer descriptors */ 34390751910SMingkai Hu for (i = 0; i < PKTBUFSRX; i++) { 3449c9141fdSClaudiu Manoil out_be16(&rxbd[i].status, RXBD_EMPTY); 3459c9141fdSClaudiu Manoil out_be16(&rxbd[i].length, 0); 346*1fd92db8SJoe Hershberger out_be32(&rxbd[i].bufptr, (u32)net_rx_packets[i]); 34790751910SMingkai Hu } 3489c9141fdSClaudiu Manoil status = in_be16(&rxbd[PKTBUFSRX - 1].status); 3499c9141fdSClaudiu Manoil out_be16(&rxbd[PKTBUFSRX - 1].status, status | RXBD_WRAP); 35090751910SMingkai Hu 35190751910SMingkai Hu /* Initialize the TX Buffer Descriptors */ 35290751910SMingkai Hu for (i = 0; i < TX_BUF_CNT; i++) { 3539c9141fdSClaudiu Manoil out_be16(&txbd[i].status, 0); 3549c9141fdSClaudiu Manoil out_be16(&txbd[i].length, 0); 3559c9141fdSClaudiu Manoil out_be32(&txbd[i].bufptr, 0); 35690751910SMingkai Hu } 3579c9141fdSClaudiu Manoil status = in_be16(&txbd[TX_BUF_CNT - 1].status); 3589c9141fdSClaudiu Manoil out_be16(&txbd[TX_BUF_CNT - 1].status, status | TXBD_WRAP); 35990751910SMingkai Hu 360aada81deSchenhui zhao #ifdef CONFIG_SYS_FSL_ERRATUM_NMG_ETSEC129 361aada81deSchenhui zhao svr = get_svr(); 362aada81deSchenhui zhao if ((SVR_MAJ(svr) == 1) || IS_SVR_REV(svr, 2, 0)) 363aada81deSchenhui zhao redundant_init(dev); 364aada81deSchenhui zhao #endif 36590751910SMingkai Hu /* Enable Transmit and Receive */ 36690751910SMingkai Hu setbits_be32(®s->maccfg1, MACCFG1_RX_EN | MACCFG1_TX_EN); 36790751910SMingkai Hu 36890751910SMingkai Hu /* Tell the DMA it is clear to go */ 36990751910SMingkai Hu setbits_be32(®s->dmactrl, DMACTRL_INIT_SETTINGS); 37090751910SMingkai Hu out_be32(®s->tstat, TSTAT_CLEAR_THALT); 37190751910SMingkai Hu out_be32(®s->rstat, RSTAT_CLEAR_RHALT); 37290751910SMingkai Hu clrbits_be32(®s->dmactrl, DMACTRL_GRS | DMACTRL_GTS); 37352d00a81SAlison Wang #ifdef CONFIG_LS102XA 37452d00a81SAlison Wang setbits_be32(®s->dmactrl, DMACTRL_LE); 37552d00a81SAlison Wang #endif 37690751910SMingkai Hu } 37790751910SMingkai Hu 37890751910SMingkai Hu /* This returns the status bits of the device. The return value 37990751910SMingkai Hu * is never checked, and this is what the 8260 driver did, so we 38090751910SMingkai Hu * do the same. Presumably, this would be zero if there were no 38190751910SMingkai Hu * errors 38290751910SMingkai Hu */ 383c8a60b53SJoe Hershberger static int tsec_send(struct eth_device *dev, void *packet, int length) 38490751910SMingkai Hu { 38590751910SMingkai Hu struct tsec_private *priv = (struct tsec_private *)dev->priv; 386aec84bf6SClaudiu Manoil struct tsec __iomem *regs = priv->regs; 3879c9141fdSClaudiu Manoil uint16_t status; 3889c9141fdSClaudiu Manoil int result = 0; 3899c9141fdSClaudiu Manoil int i; 39090751910SMingkai Hu 39190751910SMingkai Hu /* Find an empty buffer descriptor */ 3929c9141fdSClaudiu Manoil for (i = 0; in_be16(&txbd[tx_idx].status) & TXBD_READY; i++) { 39390751910SMingkai Hu if (i >= TOUT_LOOP) { 39490751910SMingkai Hu debug("%s: tsec: tx buffers full\n", dev->name); 39590751910SMingkai Hu return result; 39690751910SMingkai Hu } 39790751910SMingkai Hu } 39890751910SMingkai Hu 3999c9141fdSClaudiu Manoil out_be32(&txbd[tx_idx].bufptr, (u32)packet); 4009c9141fdSClaudiu Manoil out_be16(&txbd[tx_idx].length, length); 4019c9141fdSClaudiu Manoil status = in_be16(&txbd[tx_idx].status); 4029c9141fdSClaudiu Manoil out_be16(&txbd[tx_idx].status, status | 4039c9141fdSClaudiu Manoil (TXBD_READY | TXBD_LAST | TXBD_CRC | TXBD_INTERRUPT)); 40490751910SMingkai Hu 40590751910SMingkai Hu /* Tell the DMA to go */ 40690751910SMingkai Hu out_be32(®s->tstat, TSTAT_CLEAR_THALT); 40790751910SMingkai Hu 40890751910SMingkai Hu /* Wait for buffer to be transmitted */ 4099c9141fdSClaudiu Manoil for (i = 0; in_be16(&txbd[tx_idx].status) & TXBD_READY; i++) { 41090751910SMingkai Hu if (i >= TOUT_LOOP) { 41190751910SMingkai Hu debug("%s: tsec: tx error\n", dev->name); 41290751910SMingkai Hu return result; 41390751910SMingkai Hu } 41490751910SMingkai Hu } 41590751910SMingkai Hu 41618b338fbSClaudiu Manoil tx_idx = (tx_idx + 1) % TX_BUF_CNT; 4179c9141fdSClaudiu Manoil result = in_be16(&txbd[tx_idx].status) & TXBD_STATS; 41890751910SMingkai Hu 41990751910SMingkai Hu return result; 42090751910SMingkai Hu } 42190751910SMingkai Hu 42290751910SMingkai Hu static int tsec_recv(struct eth_device *dev) 42390751910SMingkai Hu { 42490751910SMingkai Hu struct tsec_private *priv = (struct tsec_private *)dev->priv; 425aec84bf6SClaudiu Manoil struct tsec __iomem *regs = priv->regs; 42690751910SMingkai Hu 4279c9141fdSClaudiu Manoil while (!(in_be16(&rxbd[rx_idx].status) & RXBD_EMPTY)) { 4289c9141fdSClaudiu Manoil int length = in_be16(&rxbd[rx_idx].length); 4299c9141fdSClaudiu Manoil uint16_t status = in_be16(&rxbd[rx_idx].status); 43090751910SMingkai Hu 43190751910SMingkai Hu /* Send the packet up if there were no errors */ 4329c9141fdSClaudiu Manoil if (!(status & RXBD_STATS)) 433*1fd92db8SJoe Hershberger net_process_received_packet(net_rx_packets[rx_idx], 434*1fd92db8SJoe Hershberger length - 4); 4359c9141fdSClaudiu Manoil else 4369c9141fdSClaudiu Manoil printf("Got error %x\n", (status & RXBD_STATS)); 43790751910SMingkai Hu 4389c9141fdSClaudiu Manoil out_be16(&rxbd[rx_idx].length, 0); 43990751910SMingkai Hu 4409c9141fdSClaudiu Manoil status = RXBD_EMPTY; 44190751910SMingkai Hu /* Set the wrap bit if this is the last element in the list */ 4429c9141fdSClaudiu Manoil if ((rx_idx + 1) == PKTBUFSRX) 4439c9141fdSClaudiu Manoil status |= RXBD_WRAP; 4449c9141fdSClaudiu Manoil out_be16(&rxbd[rx_idx].status, status); 44590751910SMingkai Hu 44618b338fbSClaudiu Manoil rx_idx = (rx_idx + 1) % PKTBUFSRX; 44790751910SMingkai Hu } 44890751910SMingkai Hu 44990751910SMingkai Hu if (in_be32(®s->ievent) & IEVENT_BSY) { 45090751910SMingkai Hu out_be32(®s->ievent, IEVENT_BSY); 45190751910SMingkai Hu out_be32(®s->rstat, RSTAT_CLEAR_RHALT); 45290751910SMingkai Hu } 45390751910SMingkai Hu 45490751910SMingkai Hu return -1; 45590751910SMingkai Hu 45690751910SMingkai Hu } 45790751910SMingkai Hu 45890751910SMingkai Hu /* Stop the interface */ 45990751910SMingkai Hu static void tsec_halt(struct eth_device *dev) 46090751910SMingkai Hu { 46190751910SMingkai Hu struct tsec_private *priv = (struct tsec_private *)dev->priv; 462aec84bf6SClaudiu Manoil struct tsec __iomem *regs = priv->regs; 46390751910SMingkai Hu 46490751910SMingkai Hu clrbits_be32(®s->dmactrl, DMACTRL_GRS | DMACTRL_GTS); 46590751910SMingkai Hu setbits_be32(®s->dmactrl, DMACTRL_GRS | DMACTRL_GTS); 46690751910SMingkai Hu 46790751910SMingkai Hu while ((in_be32(®s->ievent) & (IEVENT_GRSC | IEVENT_GTSC)) 46890751910SMingkai Hu != (IEVENT_GRSC | IEVENT_GTSC)) 46990751910SMingkai Hu ; 47090751910SMingkai Hu 47190751910SMingkai Hu clrbits_be32(®s->maccfg1, MACCFG1_TX_EN | MACCFG1_RX_EN); 47290751910SMingkai Hu 47390751910SMingkai Hu /* Shut down the PHY, as needed */ 474063c1263SAndy Fleming phy_shutdown(priv->phydev); 47590751910SMingkai Hu } 47690751910SMingkai Hu 47790751910SMingkai Hu /* Initializes data structures and registers for the controller, 47890751910SMingkai Hu * and brings the interface up. Returns the link status, meaning 47990751910SMingkai Hu * that it returns success if the link is up, failure otherwise. 48090751910SMingkai Hu * This allows u-boot to find the first active controller. 48190751910SMingkai Hu */ 48290751910SMingkai Hu static int tsec_init(struct eth_device *dev, bd_t * bd) 48390751910SMingkai Hu { 48490751910SMingkai Hu struct tsec_private *priv = (struct tsec_private *)dev->priv; 485aec84bf6SClaudiu Manoil struct tsec __iomem *regs = priv->regs; 486b1690bc3SClaudiu Manoil u32 tempval; 48711af8d65STimur Tabi int ret; 48890751910SMingkai Hu 48990751910SMingkai Hu /* Make sure the controller is stopped */ 49090751910SMingkai Hu tsec_halt(dev); 49190751910SMingkai Hu 49290751910SMingkai Hu /* Init MACCFG2. Defaults to GMII */ 49390751910SMingkai Hu out_be32(®s->maccfg2, MACCFG2_INIT_SETTINGS); 49490751910SMingkai Hu 49590751910SMingkai Hu /* Init ECNTRL */ 49690751910SMingkai Hu out_be32(®s->ecntrl, ECNTRL_INIT_SETTINGS); 49790751910SMingkai Hu 49890751910SMingkai Hu /* Copy the station address into the address registers. 499b1690bc3SClaudiu Manoil * For a station address of 0x12345678ABCD in transmission 500b1690bc3SClaudiu Manoil * order (BE), MACnADDR1 is set to 0xCDAB7856 and 501b1690bc3SClaudiu Manoil * MACnADDR2 is set to 0x34120000. 502b1690bc3SClaudiu Manoil */ 503b1690bc3SClaudiu Manoil tempval = (dev->enetaddr[5] << 24) | (dev->enetaddr[4] << 16) | 504b1690bc3SClaudiu Manoil (dev->enetaddr[3] << 8) | dev->enetaddr[2]; 50590751910SMingkai Hu 50690751910SMingkai Hu out_be32(®s->macstnaddr1, tempval); 50790751910SMingkai Hu 508b1690bc3SClaudiu Manoil tempval = (dev->enetaddr[1] << 24) | (dev->enetaddr[0] << 16); 50990751910SMingkai Hu 51090751910SMingkai Hu out_be32(®s->macstnaddr2, tempval); 51190751910SMingkai Hu 51290751910SMingkai Hu /* Clear out (for the most part) the other registers */ 51390751910SMingkai Hu init_registers(regs); 51490751910SMingkai Hu 51590751910SMingkai Hu /* Ready the device for tx/rx */ 51690751910SMingkai Hu startup_tsec(dev); 51790751910SMingkai Hu 518063c1263SAndy Fleming /* Start up the PHY */ 51911af8d65STimur Tabi ret = phy_startup(priv->phydev); 52011af8d65STimur Tabi if (ret) { 52111af8d65STimur Tabi printf("Could not initialize PHY %s\n", 52211af8d65STimur Tabi priv->phydev->dev->name); 52311af8d65STimur Tabi return ret; 52411af8d65STimur Tabi } 525063c1263SAndy Fleming 526063c1263SAndy Fleming adjust_link(priv, priv->phydev); 527063c1263SAndy Fleming 52890751910SMingkai Hu /* If there's no link, fail */ 529063c1263SAndy Fleming return priv->phydev->link ? 0 : -1; 53090751910SMingkai Hu } 53190751910SMingkai Hu 532063c1263SAndy Fleming static phy_interface_t tsec_get_interface(struct tsec_private *priv) 533063c1263SAndy Fleming { 534aec84bf6SClaudiu Manoil struct tsec __iomem *regs = priv->regs; 535063c1263SAndy Fleming u32 ecntrl; 536063c1263SAndy Fleming 537063c1263SAndy Fleming ecntrl = in_be32(®s->ecntrl); 538063c1263SAndy Fleming 539063c1263SAndy Fleming if (ecntrl & ECNTRL_SGMII_MODE) 540063c1263SAndy Fleming return PHY_INTERFACE_MODE_SGMII; 541063c1263SAndy Fleming 542063c1263SAndy Fleming if (ecntrl & ECNTRL_TBI_MODE) { 543063c1263SAndy Fleming if (ecntrl & ECNTRL_REDUCED_MODE) 544063c1263SAndy Fleming return PHY_INTERFACE_MODE_RTBI; 545063c1263SAndy Fleming else 546063c1263SAndy Fleming return PHY_INTERFACE_MODE_TBI; 547063c1263SAndy Fleming } 548063c1263SAndy Fleming 549063c1263SAndy Fleming if (ecntrl & ECNTRL_REDUCED_MODE) { 550063c1263SAndy Fleming if (ecntrl & ECNTRL_REDUCED_MII_MODE) 551063c1263SAndy Fleming return PHY_INTERFACE_MODE_RMII; 552063c1263SAndy Fleming else { 553063c1263SAndy Fleming phy_interface_t interface = priv->interface; 554063c1263SAndy Fleming 555063c1263SAndy Fleming /* 556063c1263SAndy Fleming * This isn't autodetected, so it must 557063c1263SAndy Fleming * be set by the platform code. 558063c1263SAndy Fleming */ 559063c1263SAndy Fleming if ((interface == PHY_INTERFACE_MODE_RGMII_ID) || 560063c1263SAndy Fleming (interface == PHY_INTERFACE_MODE_RGMII_TXID) || 561063c1263SAndy Fleming (interface == PHY_INTERFACE_MODE_RGMII_RXID)) 562063c1263SAndy Fleming return interface; 563063c1263SAndy Fleming 564063c1263SAndy Fleming return PHY_INTERFACE_MODE_RGMII; 565063c1263SAndy Fleming } 566063c1263SAndy Fleming } 567063c1263SAndy Fleming 568063c1263SAndy Fleming if (priv->flags & TSEC_GIGABIT) 569063c1263SAndy Fleming return PHY_INTERFACE_MODE_GMII; 570063c1263SAndy Fleming 571063c1263SAndy Fleming return PHY_INTERFACE_MODE_MII; 572063c1263SAndy Fleming } 573063c1263SAndy Fleming 574063c1263SAndy Fleming 57590751910SMingkai Hu /* Discover which PHY is attached to the device, and configure it 57690751910SMingkai Hu * properly. If the PHY is not recognized, then return 0 57790751910SMingkai Hu * (failure). Otherwise, return 1 57890751910SMingkai Hu */ 57990751910SMingkai Hu static int init_phy(struct eth_device *dev) 58090751910SMingkai Hu { 58190751910SMingkai Hu struct tsec_private *priv = (struct tsec_private *)dev->priv; 582063c1263SAndy Fleming struct phy_device *phydev; 583aec84bf6SClaudiu Manoil struct tsec __iomem *regs = priv->regs; 584063c1263SAndy Fleming u32 supported = (SUPPORTED_10baseT_Half | 585063c1263SAndy Fleming SUPPORTED_10baseT_Full | 586063c1263SAndy Fleming SUPPORTED_100baseT_Half | 587063c1263SAndy Fleming SUPPORTED_100baseT_Full); 588063c1263SAndy Fleming 589063c1263SAndy Fleming if (priv->flags & TSEC_GIGABIT) 590063c1263SAndy Fleming supported |= SUPPORTED_1000baseT_Full; 59190751910SMingkai Hu 59290751910SMingkai Hu /* Assign a Physical address to the TBI */ 59390751910SMingkai Hu out_be32(®s->tbipa, CONFIG_SYS_TBIPA_VALUE); 59490751910SMingkai Hu 595063c1263SAndy Fleming priv->interface = tsec_get_interface(priv); 59690751910SMingkai Hu 597063c1263SAndy Fleming if (priv->interface == PHY_INTERFACE_MODE_SGMII) 59890751910SMingkai Hu tsec_configure_serdes(priv); 59990751910SMingkai Hu 600063c1263SAndy Fleming phydev = phy_connect(priv->bus, priv->phyaddr, dev, priv->interface); 6017f233c05SClaudiu Manoil if (!phydev) 6027f233c05SClaudiu Manoil return 0; 60390751910SMingkai Hu 604063c1263SAndy Fleming phydev->supported &= supported; 605063c1263SAndy Fleming phydev->advertising = phydev->supported; 606063c1263SAndy Fleming 607063c1263SAndy Fleming priv->phydev = phydev; 608063c1263SAndy Fleming 609063c1263SAndy Fleming phy_config(phydev); 61090751910SMingkai Hu 61190751910SMingkai Hu return 1; 61290751910SMingkai Hu } 61390751910SMingkai Hu 61490751910SMingkai Hu /* Initialize device structure. Returns success if PHY 61590751910SMingkai Hu * initialization succeeded (i.e. if it recognizes the PHY) 61690751910SMingkai Hu */ 61790751910SMingkai Hu static int tsec_initialize(bd_t *bis, struct tsec_info_struct *tsec_info) 61890751910SMingkai Hu { 61990751910SMingkai Hu struct eth_device *dev; 62090751910SMingkai Hu int i; 62190751910SMingkai Hu struct tsec_private *priv; 62290751910SMingkai Hu 62390751910SMingkai Hu dev = (struct eth_device *)malloc(sizeof *dev); 62490751910SMingkai Hu 62590751910SMingkai Hu if (NULL == dev) 62690751910SMingkai Hu return 0; 62790751910SMingkai Hu 62890751910SMingkai Hu memset(dev, 0, sizeof *dev); 62990751910SMingkai Hu 63090751910SMingkai Hu priv = (struct tsec_private *)malloc(sizeof(*priv)); 63190751910SMingkai Hu 63290751910SMingkai Hu if (NULL == priv) 63390751910SMingkai Hu return 0; 63490751910SMingkai Hu 63590751910SMingkai Hu priv->regs = tsec_info->regs; 63690751910SMingkai Hu priv->phyregs_sgmii = tsec_info->miiregs_sgmii; 63790751910SMingkai Hu 63890751910SMingkai Hu priv->phyaddr = tsec_info->phyaddr; 63990751910SMingkai Hu priv->flags = tsec_info->flags; 64090751910SMingkai Hu 64190751910SMingkai Hu sprintf(dev->name, tsec_info->devname); 642063c1263SAndy Fleming priv->interface = tsec_info->interface; 643063c1263SAndy Fleming priv->bus = miiphy_get_dev_by_name(tsec_info->mii_devname); 64490751910SMingkai Hu dev->iobase = 0; 64590751910SMingkai Hu dev->priv = priv; 64690751910SMingkai Hu dev->init = tsec_init; 64790751910SMingkai Hu dev->halt = tsec_halt; 64890751910SMingkai Hu dev->send = tsec_send; 64990751910SMingkai Hu dev->recv = tsec_recv; 65090751910SMingkai Hu #ifdef CONFIG_MCAST_TFTP 65190751910SMingkai Hu dev->mcast = tsec_mcast_addr; 65290751910SMingkai Hu #endif 65390751910SMingkai Hu 65490751910SMingkai Hu /* Tell u-boot to get the addr from the env */ 65590751910SMingkai Hu for (i = 0; i < 6; i++) 65690751910SMingkai Hu dev->enetaddr[i] = 0; 65790751910SMingkai Hu 65890751910SMingkai Hu eth_register(dev); 65990751910SMingkai Hu 66090751910SMingkai Hu /* Reset the MAC */ 66190751910SMingkai Hu setbits_be32(&priv->regs->maccfg1, MACCFG1_SOFT_RESET); 66290751910SMingkai Hu udelay(2); /* Soft Reset must be asserted for 3 TX clocks */ 66390751910SMingkai Hu clrbits_be32(&priv->regs->maccfg1, MACCFG1_SOFT_RESET); 66490751910SMingkai Hu 66590751910SMingkai Hu /* Try to initialize PHY here, and return */ 66690751910SMingkai Hu return init_phy(dev); 66790751910SMingkai Hu } 66890751910SMingkai Hu 66990751910SMingkai Hu /* 67090751910SMingkai Hu * Initialize all the TSEC devices 67190751910SMingkai Hu * 67290751910SMingkai Hu * Returns the number of TSEC devices that were initialized 67390751910SMingkai Hu */ 67490751910SMingkai Hu int tsec_eth_init(bd_t *bis, struct tsec_info_struct *tsecs, int num) 67590751910SMingkai Hu { 67690751910SMingkai Hu int i; 67790751910SMingkai Hu int ret, count = 0; 67890751910SMingkai Hu 67990751910SMingkai Hu for (i = 0; i < num; i++) { 68090751910SMingkai Hu ret = tsec_initialize(bis, &tsecs[i]); 68190751910SMingkai Hu if (ret > 0) 68290751910SMingkai Hu count += ret; 68390751910SMingkai Hu } 68490751910SMingkai Hu 68590751910SMingkai Hu return count; 68690751910SMingkai Hu } 68790751910SMingkai Hu 68890751910SMingkai Hu int tsec_standard_init(bd_t *bis) 68990751910SMingkai Hu { 690063c1263SAndy Fleming struct fsl_pq_mdio_info info; 691063c1263SAndy Fleming 692aec84bf6SClaudiu Manoil info.regs = TSEC_GET_MDIO_REGS_BASE(1); 693063c1263SAndy Fleming info.name = DEFAULT_MII_NAME; 694063c1263SAndy Fleming 695063c1263SAndy Fleming fsl_pq_mdio_init(bis, &info); 696063c1263SAndy Fleming 69790751910SMingkai Hu return tsec_eth_init(bis, tsec_info, ARRAY_SIZE(tsec_info)); 69890751910SMingkai Hu } 699